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.
This commit is contained in:
Executable
+90
@@ -0,0 +1,90 @@
|
||||
"""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
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user