Files
2026-07-13 12:35:03 +08:00

239 lines
7.8 KiB
Python

#!/usr/bin/env python3
"""
List all ArcKit projects with status indicators.
Usage:
python3 list-projects.py [OPTIONS]
Options:
--json Output in JSON format
--verbose, -v Show detailed artifact status
--help, -h Show help message
"""
import argparse
import json
import os
import sys
from pathlib import Path
# Add parent directory to path for common imports
sys.path.insert(0, os.path.dirname(__file__))
from common import (
find_repo_root, get_projects_dir, get_project_number_from_dir,
log_warning,
)
def check_artifact(project_dir, artifact):
"""Check if an artifact exists (file or non-empty directory)."""
if artifact.endswith("/"):
d = os.path.join(project_dir, artifact.rstrip("/"))
return os.path.isdir(d) and bool(os.listdir(d))
return os.path.isfile(os.path.join(project_dir, artifact))
def count_vendors(project_dir):
"""Count vendor proposal directories."""
vendors_dir = os.path.join(project_dir, "vendors")
if not os.path.isdir(vendors_dir):
return 0
return sum(1 for d in os.listdir(vendors_dir)
if os.path.isdir(os.path.join(vendors_dir, d)))
def count_external_docs(project_dir):
"""Count external documents (excluding README.md)."""
external_dir = os.path.join(project_dir, "external")
if not os.path.isdir(external_dir):
return 0
extensions = {".pdf", ".docx", ".md", ".csv", ".sql", ".png", ".jpg"}
count = 0
for fname in os.listdir(external_dir):
if fname == "README.md":
continue
fpath = os.path.join(external_dir, fname)
if os.path.isfile(fpath) and Path(fname).suffix.lower() in extensions:
count += 1
return count
def calculate_completion(project_dir):
"""Calculate completion percentage based on standard artifacts."""
total = 10
completed = 0
artifacts = [
"stakeholder-drivers.md", "risk-register.md", "sobc.md",
"requirements.md", "data-model.md", "research-findings.md",
"sow.md", "evaluation-criteria.md",
]
for artifact in artifacts:
if os.path.isfile(os.path.join(project_dir, artifact)):
completed += 1
# Wardley maps
wm_dir = os.path.join(project_dir, "wardley-maps")
if os.path.isdir(wm_dir) and os.listdir(wm_dir):
completed += 1
# Vendors
vendors_dir = os.path.join(project_dir, "vendors")
if os.path.isdir(vendors_dir) and os.listdir(vendors_dir):
completed += 1
return completed * 100 // total
def get_status_emoji(percentage):
"""Get status indicator based on completion."""
if percentage == 100:
return "\u2705"
elif percentage >= 75:
return "\U0001f7e2"
elif percentage >= 50:
return "\U0001f7e1"
elif percentage >= 25:
return "\U0001f7e0"
else:
return "\U0001f534"
def main():
parser = argparse.ArgumentParser(description="List all ArcKit projects with status indicators")
parser.add_argument("--json", dest="json_mode", action="store_true", help="Output in JSON format")
parser.add_argument("--verbose", "-v", action="store_true", help="Show detailed artifact status")
args = parser.parse_args()
repo_root = find_repo_root()
projects_dir = get_projects_dir(repo_root)
if not os.path.isdir(projects_dir):
if args.json_mode:
print('{"projects": []}')
else:
log_warning("No projects directory found")
print()
print("Run: /arckit:init to initialize an ArcKit repository")
sys.exit(0)
# Get sorted project directories
project_dirs = sorted(
d for d in Path(projects_dir).iterdir() if d.is_dir()
)
project_count = len(project_dirs)
if project_count == 0:
if args.json_mode:
print('{"projects": []}')
else:
print("No projects found")
print()
print("Run: /arckit:create to create a new project")
sys.exit(0)
# JSON output mode
if args.json_mode:
projects = []
for pd in project_dirs:
pdir = str(pd)
project_name = pd.name
project_number = get_project_number_from_dir(pdir) or ""
vendor_count = count_vendors(pdir)
external_doc_count = count_external_docs(pdir)
completion = calculate_completion(pdir)
projects.append({
"name": project_name,
"number": project_number,
"path": pdir,
"completion_percentage": completion,
"vendor_count": vendor_count,
"external_doc_count": external_doc_count,
"artifacts": {
"stakeholder_drivers": check_artifact(pdir, "stakeholder-drivers.md"),
"risk_register": check_artifact(pdir, "risk-register.md"),
"sobc": check_artifact(pdir, "sobc.md"),
"requirements": check_artifact(pdir, "requirements.md"),
"data_model": check_artifact(pdir, "data-model.md"),
"research_findings": check_artifact(pdir, "research-findings.md"),
"wardley_maps": check_artifact(pdir, "wardley-maps/"),
"sow": check_artifact(pdir, "sow.md"),
"evaluation_criteria": check_artifact(pdir, "evaluation-criteria.md"),
"vendors": check_artifact(pdir, "vendors/"),
},
})
output = {
"repository_root": repo_root,
"projects_dir": projects_dir,
"project_count": project_count,
"projects": projects,
}
print(json.dumps(output, indent=2))
sys.exit(0)
# Text output mode
print("ArcKit Projects")
print("===============")
print()
print(f"Repository: {repo_root}")
print(f"Projects found: {project_count}")
print()
for pd in project_dirs:
pdir = str(pd)
project_name = pd.name
project_number = get_project_number_from_dir(pdir) or ""
vendor_count = count_vendors(pdir)
external_doc_count = count_external_docs(pdir)
completion = calculate_completion(pdir)
status = get_status_emoji(completion)
print(f"{status} [{project_number}] {project_name} ({completion}% complete)")
if args.verbose:
print(f" Path: {pdir}")
print(" Artifacts:")
checks = [
("stakeholder-drivers.md", "Stakeholder Drivers"),
("risk-register.md", "Risk Register"),
("sobc.md", "Strategic Outline Business Case"),
("requirements.md", "Requirements"),
("data-model.md", "Data Model"),
("research-findings.md", "Research Findings"),
("wardley-maps/", "Wardley Maps"),
("sow.md", "Statement of Work"),
("evaluation-criteria.md", "Evaluation Criteria"),
]
for artifact, label in checks:
mark = "\u2713" if check_artifact(pdir, artifact) else "\u2717"
print(f" {mark} {label}")
if vendor_count > 0:
print(f" \u2713 Vendor Proposals ({vendor_count})")
else:
print(" \u2717 Vendor Proposals")
if external_doc_count > 0:
print(f" \u2713 External Documents ({external_doc_count})")
else:
print(" \u2717 External Documents")
print()
print()
print("Legend:")
print(" \u2705 Complete (100%)")
print(" \U0001f7e2 Mostly complete (75-99%)")
print(" \U0001f7e1 In progress (50-74%)")
print(" \U0001f7e0 Started (25-49%)")
print(" \U0001f534 Not started (0-24%)")
if __name__ == "__main__":
main()