Files
zemion 2ffdb23f69
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s
feat(devkit): add resumable workspace automation and UI review tooling
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:17 +02:00

91 lines
3.2 KiB
Python
Executable File

"""Small read-only context bundles; no automatic source/credential dumping."""
from __future__ import annotations
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from .common import META_ROOT, now, read_json
from .workspace import inspect_repository, load_project, selected_repositories
def build_context(
workspace_root: Path, project_file: Path | None, names: list[str], changed: bool
) -> dict:
project = load_project(workspace_root, project_file)
repos = selected_repositories(project, names)
with ThreadPoolExecutor(max_workers=8) as pool:
states = list(pool.map(inspect_repository, repos))
if changed:
states = [
state
for state in states
if state["errors"]
or state["dirty_entries"]
or state["ahead"]
or (state["head"] and not state["upstream"])
]
inventory = {}
if not project_file:
path = META_ROOT / "docs/project/ui-review-issue-inventory.json"
if path.is_file():
payload = read_json(path)
for item in payload.get("issues", []) if isinstance(payload, dict) else []:
if isinstance(item, dict):
inventory[item.get("repository")] = item
for state in states:
root = Path(state["path"])
state["instructions"] = [
str(path) for path in (root / "AGENTS.md",) if path.is_file()
]
state["documentation"] = [
str(path)
for path in (
root / "README.md",
root / "docs/README.md",
root / "docs/MODULE_ARCHITECTURE.md",
)
if path.is_file()
]
state["change_entry_count"] = len(state["dirty_entries"])
state["review_issue"] = inventory.get(state["name"], {}).get("url")
state["suggested_check"] = (
f"./devkit check --repo {state['name']} --profile quick --dry-run"
)
summary = [
f"{project.name}: {len(states)} repositories selected (offline; upstream counts may be stale)."
]
for state in states:
errors = f" ERROR: {'; '.join(state['errors'])}" if state["errors"] else ""
summary.append(
f"{state['name']}: {state['branch'] or '(detached/unborn)'}; {state['change_entry_count']} change entries; ahead={state['ahead']} behind={state['behind']}{errors}"
)
return {
"schema_version": 1,
"generated_at": now(),
"workspace_root": str(workspace_root),
"project": project.name,
"remote_checked": False,
"repositories": states,
"summary": summary,
"_exit_code": 1 if any(state["errors"] for state in states) else 0,
}
def register(subparsers):
parser = subparsers.add_parser(
"context",
help="Offline repository changes, ownership and relevant instruction paths",
)
parser.add_argument("--repo", action="append", default=[])
parser.add_argument(
"--changed",
action="store_true",
help="Show dirty or locally ahead repositories, retaining inspection errors",
)
parser.set_defaults(
handler=lambda args: build_context(
args.workspace_root, args.project, args.repo, args.changed
)
)