239 lines
7.8 KiB
Python
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()
|