smlflg's picture
Initial public upload from Projekte/AgentProjectMinenraeumer (part 9)
b67a1e9 verified
Raw History Blame Contribute Delete
5.39 kB
#!/usr/bin/env python3
from collections import defaultdict
from datetime import datetime, timezone
from intake_common import *
def row_for(p, rank=None):
action = "Run bounded review handoff"
if p.get("triage_status") == "needs_human":
action = "Owner decision before worker"
elif p.get("triage_status") == "archive_candidate":
action = "Confirm archive/no-action"
elif p.get("triage_status") == "quick_win":
action = "Extract one quick next action"
return f"| {rank or ''} | {md_escape(action)} | `{md_escape(p['name'])}` | `{md_escape(p['path'])}` | {p.get('score',0)} | {md_escape(p.get('triage_status'))} | {md_escape(', '.join(p.get('score_reasons', [])[:3]))} | `{p.get('evidence_file')}` |"
def write_table(path, title, rows):
lines = [f"# {title}", "", "| Rank | Action | Project | Path | Score | Status | Why | Evidence |", "|---:|---|---|---|---:|---|---|---|"]
for i, p in enumerate(rows, 1):
lines.append(row_for(p, i))
if not rows:
lines.append("| - | None | - | - | - | - | - | - |")
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def merge_candidates(projects):
groups = defaultdict(list)
for p in projects:
base = re.sub(r"[-_.]?(old|new|copy|backup|v\d+|test|draft)$", "", p["name"].lower())
parent = str(Path(p["path"]).parent)
groups[(parent, base)].append(p)
out = []
for (_, _), items in groups.items():
if len(items) > 1:
out.extend(sorted(items, key=lambda x: -x.get("score", 0)))
# also group by exact names across roots
by_name = defaultdict(list)
for p in projects:
by_name[p["name"].lower()].append(p)
for items in by_name.values():
if len(items) > 1:
for p in items:
if p not in out:
out.append(p)
return out[:50]
def main():
ensure_dirs()
projects = sorted(load_jsonl(INV / "projects.jsonl"), key=project_sort_key)
backlog = ["# Backlog", "", f"Generated: {now_iso()}", "", "This is a read-only intake map. It recommends decisions; it does not authorize edits in source projects.", ""]
for p in projects:
backlog += [
f"## {p['name']}",
"",
f"- Path: `{p['path']}`",
f"- Status: `{p.get('triage_status')}`",
f"- Score: `{p.get('score')}`",
f"- Risk: `{p.get('risk_level')}`",
f"- Tech: {', '.join(p.get('technologies', []))}",
f"- TODO/FIXME/WIP hints: {p.get('todo_fixme_count', 0)}",
f"- Plan/agent artifacts: {p.get('plan_hit_count', 0)} plans, {p.get('agent_artifact_count', 0)} agent files",
f"- Evidence: `{p.get('evidence_file')}`",
"- Next: see project card and pending job contract if generated.",
"",
]
(TRIAGE / "BACKLOG.md").write_text("\n".join(backlog), encoding="utf-8")
write_table(TRIAGE / "TOP_10_NEXT_ACTIONS.md", "Top 10 Next Actions", projects[:10])
write_table(TRIAGE / "ARCHIVE_CANDIDATES.md", "Archive Candidates", [p for p in projects if p.get("triage_status") == "archive_candidate"][:50])
write_table(TRIAGE / "NEEDS_HUMAN.md", "Needs Human", [p for p in projects if p.get("triage_status") == "needs_human"][:50])
write_table(TRIAGE / "MERGE_CANDIDATES.md", "Merge Candidates", merge_candidates(projects))
counts = {s: len([p for p in projects if p.get("triage_status") == s]) for s in ["needs_human", "active", "quick_win", "review", "archive_candidate"]}
digest = [
"# OWNER DIGEST — READ_ONLY_SYSTEM_INTAKE",
"",
f"Generated: {now_iso()}",
"",
"## One-screen summary",
"",
f"- Projects / artifact clusters found: {len(projects)}",
f"- Needs human: {counts.get('needs_human',0)}",
f"- Active: {counts.get('active',0)}",
f"- Quick wins: {counts.get('quick_win',0)}",
f"- Review/unclear: {counts.get('review',0)}",
f"- Archive candidates: {counts.get('archive_candidate',0)}",
"",
"## Read this first",
"",
"1. `triage/TOP_10_NEXT_ACTIONS.md` — prioritized working map.",
"2. `triage/NEEDS_HUMAN.md` — decisions that should not be delegated blindly.",
"3. `jobs/pending/` — bounded review-only handoff contracts.",
"4. `github/issue_drafts/` — local drafts only; no GitHub issues were created.",
"",
"## Operator stance",
"",
"The Operator coordinates and verifies. Workers get one bounded contract, produce artifacts under ProjectIntakeTower, and stop on credentials, destructive actions, or unclear owner intent. Worker claims are not accepted without artifacts and verifier results.",
"",
"## Top 10 compressed",
"",
]
for i, p in enumerate(projects[:10], 1):
digest.append(f"{i}. {p['name']} — {p.get('triage_status')} — score {p.get('score')} — `{p['path']}`")
digest += ["", "## Safety", "", "No source projects were intentionally modified. Scan skipped secret-like filenames and capped all snippets.", ""]
(ROOT / "OWNER_DIGEST.md").write_text("\n".join(digest), encoding="utf-8")
print(json.dumps({"status": "succeeded", "projects": len(projects), "top10": min(10, len(projects))}, indent=2))
if __name__ == "__main__":
main()