elanous 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/LZcstaO9_NXypPFmujolv/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-33ffcc49ab45123b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-0e2c57fe6add4b2a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e05a77df7e005b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b8c49f6b4fa2df91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-976813c91d7394ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-1d4901eb7c2d8822.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-72d3e7ff35a8c954.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-60c7a8e1a4fe62ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a52b316cb143d9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c3ce483c8d5db370.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-96f074f6538e8a2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e97be5334d83a9f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-c1343f9499d86f3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-8739a2e0ae793130.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-d23b12bb92242558.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c7fea475488201a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-5efbf81124c474ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-06ee266953d9c879.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-153c2b3bcc89e8de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-0d6d23b40263a7ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-f5597e894c02cd33.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-73735b64bfe1ae67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f7e631e9b4daf66e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9817c7f9007466cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
- package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -0
- package/apps/pwa/out/ceo/index.txt +33 -0
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -0
- package/apps/pwa/out/loops/index.txt +30 -0
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/heal/heal-loop.yaml +1 -1
- package/graphs/implement-loop.yaml +1 -1
- package/graphs/orchestrator/orchestrator.yaml +59 -0
- package/graphs/orchestrator/recipes.yaml +18 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +6 -1
- package/graphs/rhythm/daily.yaml +38 -0
- package/graphs/rhythm/recipes.yaml +18 -0
- package/graphs/rhythm/weekly.yaml +39 -0
- package/graphs/video/recipes.yaml +3 -0
- package/graphs/video/youtube-summary.yaml +17 -0
- package/package.json +1 -1
- package/scripts/audit-test-state-writes.ts +72 -17
- package/scripts/brand/check.ts +188 -0
- package/scripts/ci-typecheck-changed.ts +50 -18
- package/scripts/coord-post.sh +11 -1
- package/scripts/docs/generate-graph-anatomy.ts +315 -0
- package/scripts/docs-cli-check.ts +23 -6
- package/scripts/expose-rubric-check.ts +118 -0
- package/scripts/expose-rubric-suggest.ts +169 -0
- package/scripts/heal/run-role.ts +14 -0
- package/scripts/hq/standby-verify.ts +11 -7
- package/scripts/lecture-note/node.ts +31 -11
- package/scripts/lessons/handbook-page.ts +112 -0
- package/scripts/marketing/generate-ax-brief.ts +140 -0
- package/scripts/marketing/generate-feature-map.ts +118 -0
- package/scripts/release-loop/checklist-gate-node.ts +53 -14
- package/scripts/release-loop/gate-node.ts +89 -14
- package/scripts/release-loop/publish-node.ts +14 -1
- package/scripts/release-loop/unattended-release.ts +23 -1
- package/scripts/release-loop/vault-note-node.ts +428 -0
- package/scripts/release-story/draft.ts +220 -0
- package/scripts/rhythm/daily.ts +570 -0
- package/scripts/rhythm/weekly.ts +315 -0
- package/scripts/skills/public-check.ts +169 -0
- package/scripts/smart-merge/resync-shadow.ts +147 -0
- package/scripts/test-deterministic.ts +4 -8
- package/scripts/test-diet/effectiveness.ts +195 -0
- package/scripts/test-diet/lib.ts +16 -8
- package/scripts/test-diet/node.ts +77 -9
- package/scripts/ux/demo-rehearsal.ts +2 -2
- package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
- package/scripts/video/youtube-summary.ts +133 -0
- package/skills/diagram-master/SKILL.md +42 -49
- package/skills/diagram-master/references/pyproject.toml +4 -1
- package/skills/diagram-master/references/routing-guide.md +4 -2
- package/skills/grill-me/SKILL.md +1 -0
- package/skills/youtube-master/SKILL.md +13 -13
- package/skills/youtube-master/package-lock.json +0 -545
- package/skills/youtube-master/package.json +2 -5
- package/skills/youtube-master/scripts/main.ts +2 -2
- package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
- package/skills/youtube-master/src/util.ts +30 -7
- package/src/agent-env/profile.ts +161 -0
- package/src/agent-mission/driver.ts +3 -3
- package/src/agent-substrate/pr-reviewer.ts +2 -0
- package/src/ask-user-question/pending-questions.ts +5 -0
- package/src/auth/github-app-token.ts +112 -13
- package/src/autopilot/build/llm-conflict-merge.ts +73 -10
- package/src/autopilot/build/merge-intent.ts +53 -0
- package/src/briefing/brief-items.ts +121 -0
- package/src/chat/index.ts +2 -0
- package/src/claims/claims-ledger.ts +232 -0
- package/src/claims/claims-render.ts +166 -0
- package/src/cli/agent-env-cli.ts +21 -0
- package/src/cli/claims-cli.ts +94 -0
- package/src/cli/decisions-cli.ts +44 -3
- package/src/cli/docs-cli.ts +2 -0
- package/src/cli/doctor-cli.ts +23 -1
- package/src/cli/doctor-node-modules.ts +147 -0
- package/src/cli/flow-cli.ts +11 -0
- package/src/cli/freeze-cli.ts +45 -0
- package/src/cli/intake-cli.ts +46 -17
- package/src/cli/lesson-cli.ts +108 -0
- package/src/cli/logs-cli.ts +104 -2
- package/src/cli/logs-model-input.ts +131 -0
- package/src/cli/pod-cli.ts +2 -0
- package/src/cli/pr-cli.ts +29 -1
- package/src/cli/private-ledger-commands.ts +54 -4
- package/src/cli/pty-drive-verdict.ts +11 -2
- package/src/cli/release-cli.ts +190 -33
- package/src/cli/rfc-status.ts +91 -0
- package/src/cli/seat-requests-cli.ts +52 -0
- package/src/connectors/linear.ts +5 -3
- package/src/context-bus/condense.ts +15 -20
- package/src/context-bus/context-now-public.ts +96 -0
- package/src/context-bus/context-now-surfaces.ts +55 -2
- package/src/context-bus/context-now.ts +6 -3
- package/src/context-bus/coord-events.ts +6 -4
- package/src/context-bus/long-term-memory.ts +92 -11
- package/src/dashboard/index.ts +75 -22
- package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
- package/src/dashboard/slash-runtime/loops-table.ts +77 -0
- package/src/decisions/decision-cards.ts +33 -7
- package/src/decisions/decision-ledger.ts +40 -1
- package/src/decisions/proact-meter.ts +286 -0
- package/src/decisions/proact1-lite.ts +86 -0
- package/src/decisions/web-push-decision-cards.ts +1 -1
- package/src/discord/sprint21-runtime.ts +16 -0
- package/src/discord-self-message.ts +8 -0
- package/src/discord-slash-wire.ts +31 -2
- package/src/domains/alert-audit.ts +271 -0
- package/src/domains/core-tools.ts +4 -3
- package/src/domains/ops-facts-tool.ts +31 -1
- package/src/domains/outbound-alert.ts +1 -1
- package/src/elanous-config-dir.ts +29 -4
- package/src/execution-loop/launch-gate.ts +29 -14
- package/src/flow/cards.ts +239 -0
- package/src/graph-runner/graph-tick.ts +4 -0
- package/src/graph-runner/runner.ts +30 -5
- package/src/harness/harness-cli-command.ts +259 -38
- package/src/harness/harness-incidents.ts +45 -12
- package/src/harness/harness-pod-dispatch.ts +102 -11
- package/src/harness/harness-queue-child.ts +3 -3
- package/src/harness/harness-queue.ts +583 -65
- package/src/harness/helper-repair.ts +87 -0
- package/src/harness/helper-scan.ts +151 -0
- package/src/harness/launch-stamp.ts +236 -0
- package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
- package/src/harness/ledger-write-guard.ts +35 -0
- package/src/harness/model-input-observation.ts +37 -0
- package/src/harness/pod-memory-policy.ts +15 -0
- package/src/harness/repository-name.ts +55 -0
- package/src/hq/fence-audit.ts +90 -0
- package/src/hq/hq.ts +63 -5
- package/src/hq/lease.ts +4 -4
- package/src/hq/move-plan.ts +126 -0
- package/src/hq/promote.ts +332 -0
- package/src/index.ts +159 -27
- package/src/intake-plane/check.ts +63 -0
- package/src/intake-plane/digest.ts +37 -15
- package/src/intake-plane/front-classifier.ts +6 -0
- package/src/intake-plane/items.ts +3 -2
- package/src/intake-plane/lens.ts +177 -0
- package/src/intake-plane/linear-wish.ts +39 -11
- package/src/intake-plane/route.ts +145 -1
- package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
- package/src/intake-plane/wish-card.ts +53 -2
- package/src/intake-plane/wish-folder.ts +5 -2
- package/src/intake-plane/wish-reply.ts +72 -0
- package/src/launch-head/seat-goal-queue-lock.fixture.ts +15 -0
- package/src/launch-head/seat-goal-queue.ts +198 -0
- package/src/lessons/lesson-import.ts +106 -0
- package/src/lessons/lesson-ledger.ts +206 -0
- package/src/loops/activity.ts +203 -0
- package/src/loops/budget.ts +63 -0
- package/src/loops/checker.ts +5 -3
- package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
- package/src/loops/loop-cli.ts +36 -4
- package/src/loops/neighbors.ts +40 -0
- package/src/loops/observe.ts +10 -0
- package/src/loops/orchestrator/author-depth.ts +220 -0
- package/src/loops/orchestrator/author-input-check.ts +82 -0
- package/src/loops/orchestrator/author-ledger.ts +232 -0
- package/src/loops/orchestrator/finish-rate.ts +175 -0
- package/src/loops/orchestrator/overlap.ts +51 -12
- package/src/loops/orchestrator/resync-shadow.ts +227 -0
- package/src/loops/orchestrator/seat-share.ts +56 -0
- package/src/loops/orchestrator/tick.ts +309 -0
- package/src/loops/orchestrator/traffic.ts +134 -13
- package/src/loops/registry.ts +535 -9
- package/src/loops/status-rows.ts +118 -0
- package/src/loops/verdict.ts +17 -5
- package/src/maturity/bot-slash-catalog.ts +66 -0
- package/src/maturity/feature-maturity.ts +9 -5
- package/src/maturity/tui-slash-availability.ts +31 -0
- package/src/mss/logging/log-store.ts +35 -4
- package/src/nexus/api/dashboard.ts +6 -1
- package/src/nexus/api/http-server.ts +33 -3
- package/src/nexus/api/loop-edges.ts +173 -0
- package/src/nexus/api/merge-approvals-gate.ts +1 -1
- package/src/nexus/api/schedules-read.ts +18 -1
- package/src/nexus/api/seat-requests.ts +79 -56
- package/src/nexus/api/task-cards-api.ts +44 -5
- package/src/nexus/api/workflows.ts +2 -1
- package/src/prompt-enhance/enhance.ts +6 -1
- package/src/release-loop/auto-start.ts +51 -0
- package/src/release-loop/checklist.ts +22 -4
- package/src/release-loop/feature-store.ts +71 -32
- package/src/release-loop/landing-freeze.ts +121 -0
- package/src/release-loop/merged-pr-checklist.ts +125 -0
- package/src/release-loop/placement.ts +302 -0
- package/src/release-loop/release-schedule.ts +3 -1
- package/src/seat-dispatch/ceo-commands.ts +2 -2
- package/src/seat-dispatch/seat-ask.ts +16 -3
- package/src/seat-dispatch/seat-questions.ts +58 -0
- package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
- package/src/seat-dispatch/seat-request-ledger.ts +133 -0
- package/src/seat-loop/seat-loop.ts +531 -40
- package/src/self-dev/dev-pipeline.ts +14 -6
- package/src/self-dev/draft-sweep.ts +162 -6
- package/src/self-dev/draft-triage-rules.ts +25 -8
- package/src/self-dev/orchestrate.ts +15 -1
- package/src/self-dev/review-provider-fallback.ts +6 -1
- package/src/self-dev/run-store.ts +73 -1
- package/src/self-dev/run-supervisor.ts +57 -2
- package/src/self-dev/self-orchestrate-runtime.ts +5 -1
- package/src/self-implement/budget-gate.ts +29 -0
- package/src/self-implement/expose-gate.ts +47 -0
- package/src/self-implement/frozen-merges.ts +295 -0
- package/src/self-implement/gate-cli.ts +10 -4
- package/src/self-implement/gate-scope.ts +46 -9
- package/src/self-implement/goal-archive.ts +222 -0
- package/src/self-implement/goal-author.ts +43 -5
- package/src/self-implement/goal-clarification-escalation.ts +5 -0
- package/src/self-implement/goal-lookup.ts +147 -0
- package/src/self-implement/heal-intake.ts +197 -0
- package/src/self-implement/host-regate.ts +32 -2
- package/src/self-implement/l8-merge-queue.ts +132 -0
- package/src/self-implement/orchestrator.ts +299 -48
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/revert-guard.ts +97 -0
- package/src/self-implement/run-ledger.ts +3 -1
- package/src/self-implement/run-status-mapping.ts +2 -0
- package/src/self-implement/seams.ts +29 -9
- package/src/self-implement/self-implement-cli.ts +1 -0
- package/src/self-implement/speed-claims.ts +338 -0
- package/src/session/index.ts +2 -0
- package/src/steward/triage.ts +74 -3
- package/src/steward/working-backwards.ts +4 -1
- package/src/task-cards/card-cli.ts +10 -2
- package/src/task-cards/card-store.ts +10 -6
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
- package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
- package/src/task-orchestrator/surfaces/pod-pool.ts +60 -8
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +224 -49
- package/src/task-orchestrator/surfaces/self-implement.ts +5 -1
- package/src/telegram-commands.ts +27 -3
- package/src/telegram-loops-command.ts +44 -0
- package/src/telegram.ts +25 -4
- package/src/user-config.ts +146 -18
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/nodes/bash.ts +9 -1
- package/src/workflow-runtime/storage.ts +31 -13
- package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f14987d5850a31e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66c27608f651b866.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-78b40a344ed22f24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
- /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → LZcstaO9_NXypPFmujolv}/_ssgManifest.js +0 -0
|
@@ -35,14 +35,15 @@ import type { DocumentReferenceStatus } from '../self-implement/self-implement-r
|
|
|
35
35
|
import type { SelfDevGoal, OrchestrateSelfDevOptions, SelfDevJobResult } from './orchestrate.js';
|
|
36
36
|
import { launchCapabilityObservation, resolveLaunchCapabilities } from './launch-capabilities.js';
|
|
37
37
|
import { lookupEntrance, type EntranceId } from './entrance-registry.js';
|
|
38
|
+
import { resolveLaunchStamp } from '../harness/launch-stamp.js';
|
|
38
39
|
import type { IngestionEntry } from '../agent-substrate/execution/ingestion-policy.js';
|
|
39
40
|
import type { ReviewerContextItem } from '../agent-substrate/pr-reviewer.js';
|
|
40
41
|
import { resolveRunIdentity, type RunIdSource } from '../harness/harness-space.js';
|
|
41
|
-
import { addSelfDevRunParticipant, saveSelfDevRun } from './run-store.js';
|
|
42
|
+
import { addSelfDevRunParticipant, processBirthId, saveSelfDevRun } from './run-store.js';
|
|
42
43
|
import { getUserConfig, resolveRoleLlm } from '../user-config.js';
|
|
43
44
|
import { reviewReasoningEffort } from '../model-tier/review-effort.js';
|
|
44
45
|
import { getProvider, inferProviderFromModel } from '../llm.js';
|
|
45
|
-
import { buildReviewProviderAttempts, runReviewWithFallback, reviewFallbackModelsFromConfig } from './review-provider-fallback.js';
|
|
46
|
+
import { buildReviewProviderAttempts, defaultReviewFallbackModel, runReviewWithFallback, reviewFallbackModelsFromConfig } from './review-provider-fallback.js';
|
|
46
47
|
import type { DefaultSeamsOptions } from '../self-implement/seams.js';
|
|
47
48
|
import { harnessTargetOptions, resolveHarnessTarget, revalidateHarnessTarget, type HarnessTargetResolution } from '../self-implement/harness-target-options.js';
|
|
48
49
|
import { provisionRepository, type RepoProvisionResult } from '../self-implement/repo-provision.js';
|
|
@@ -609,6 +610,7 @@ export function toSelfImplementOptions(text: string, plan: ResolvedDevPlan, seam
|
|
|
609
610
|
...(s.correlationId !== undefined ? { correlationId: s.correlationId } : {}),
|
|
610
611
|
...(s.branchName ? { branchName: s.branchName } : {}),
|
|
611
612
|
...(s.maxReworkRounds !== undefined ? { maxReworkRounds: s.maxReworkRounds } : {}),
|
|
613
|
+
launch: resolveLaunchStamp({ entrance: plan.entrance, queueId: process.env.ELANOUS_HARNESS_QUEUE_LAUNCH }),
|
|
612
614
|
};
|
|
613
615
|
}
|
|
614
616
|
|
|
@@ -1093,10 +1095,12 @@ export async function buildDefaultSelfImplementSeams(
|
|
|
1093
1095
|
provider: inferProviderFromModel(model) ? getProvider(model) : undefined,
|
|
1094
1096
|
label,
|
|
1095
1097
|
});
|
|
1098
|
+
const primaryReviewAttempt = reviewAttemptForModel(reviewModel, 'primary');
|
|
1096
1099
|
const reviewAttempts = buildReviewProviderAttempts(
|
|
1097
|
-
|
|
1098
|
-
reviewFallbackModels
|
|
1099
|
-
|
|
1100
|
+
primaryReviewAttempt,
|
|
1101
|
+
[...reviewFallbackModels, defaultReviewFallbackModel(primaryReviewAttempt.provider?.name)]
|
|
1102
|
+
.map((model) => reviewAttemptForModel(model, model)),
|
|
1103
|
+
).slice(0, 2);
|
|
1100
1104
|
const defaultApiReview = async (prompt: string): Promise<string> => {
|
|
1101
1105
|
const r = await runReviewWithFallback(
|
|
1102
1106
|
reviewAttempts,
|
|
@@ -1718,7 +1722,11 @@ export async function runDevPipeline(spec: DevPipelineSpec, deps: DevPipelineDep
|
|
|
1718
1722
|
if (spec.runId) {
|
|
1719
1723
|
const runIdSource = spec.runIdSource ?? resolveRunIdentity({ explicit: spec.runId }).source;
|
|
1720
1724
|
const now = Date.now();
|
|
1721
|
-
|
|
1725
|
+
const seat = process.env.ELANOUS_HARNESS_SEAT;
|
|
1726
|
+
const pidStart = processBirthId(process.pid);
|
|
1727
|
+
saveSelfDevRun({ runId: spec.runId, createdAt: now, updatedAt: now, results: [], pid: process.pid,
|
|
1728
|
+
...(pidStart ? { pidStart } : {}),
|
|
1729
|
+
...(seat === 'OP' || seat === 'TC' || seat === 'MK' || seat === 'UX' ? { seat } : {}) });
|
|
1722
1730
|
addSelfDevRunParticipant(spec.runId, {
|
|
1723
1731
|
id: `process:${process.pid}`,
|
|
1724
1732
|
kind: 'process',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CLAIM_IDLE_HOURS, PR_LABELS, STALLED_DRAFT_HOURS } from '../github/pr-labels.js';
|
|
2
2
|
import { debug } from '../debug/log.js';
|
|
3
|
-
import { decideDraft, type DraftTriagePr } from './draft-triage-rules.js';
|
|
3
|
+
import { decideDraft, sameGoalPr, type DraftTriagePr } from './draft-triage-rules.js';
|
|
4
4
|
|
|
5
5
|
export interface SweepDraft extends DraftTriagePr {
|
|
6
6
|
readonly title: string;
|
|
@@ -31,6 +31,20 @@ export interface DraftSweepAdapters {
|
|
|
31
31
|
hasFinalRunResult?(draft: SweepDraft, repository: string): Promise<boolean | undefined>;
|
|
32
32
|
/** Per-file last change on the draft branch; undefined means file coverage is unverified. */
|
|
33
33
|
getLatestFileChanges?(draft: SweepDraft, repository: string): Promise<Readonly<Record<string, string>> | undefined>;
|
|
34
|
+
/** Optional merge-time file inventory for the existing all-files-landed decision. */
|
|
35
|
+
getPrFiles?(repository: string, number: number): Promise<readonly string[] | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Review and gate posture for the daily count. Omitted means unknown — not harvestable and not blocked.
|
|
38
|
+
* `review: 'pass'` is a review PASS; `mustFix` means must-fix remains; `gate: 'pass'` is a green gate.
|
|
39
|
+
*/
|
|
40
|
+
getReviewGate?(draft: SweepDraft, repository: string): Promise<SweepReviewGate | undefined>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Review PASS and gate posture used only by the daily old-draft count. */
|
|
44
|
+
export interface SweepReviewGate {
|
|
45
|
+
readonly review?: 'pass' | 'fail';
|
|
46
|
+
readonly mustFix?: boolean;
|
|
47
|
+
readonly gate?: 'pass' | 'fail';
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
export interface DraftSweepOptions {
|
|
@@ -65,9 +79,23 @@ export interface DraftSweepResult {
|
|
|
65
79
|
claimed?: number;
|
|
66
80
|
/** Running claims older than the idle window, including those kept by liveness. */
|
|
67
81
|
claimExpired?: number;
|
|
82
|
+
/**
|
|
83
|
+
* One line per sweep: harness drafts older than 24h, split into closable (a same-goal landing exists),
|
|
84
|
+
* harvestable (review PASS and gate pass), and blocked (must-fix remains).
|
|
85
|
+
*/
|
|
86
|
+
daily?: DraftSweepDaily;
|
|
68
87
|
error?: string;
|
|
69
88
|
}
|
|
70
89
|
|
|
90
|
+
/** Daily old-draft census. `date` is the sweep clock's UTC calendar day. */
|
|
91
|
+
export interface DraftSweepDaily {
|
|
92
|
+
readonly date: string;
|
|
93
|
+
readonly over24h: number;
|
|
94
|
+
readonly closable: number;
|
|
95
|
+
readonly harvestable: number;
|
|
96
|
+
readonly blocked: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
71
99
|
const stateLabels = PR_LABELS.filter((label) => label.axis === 'state');
|
|
72
100
|
const label = (action: 'mark-stalled' | 'close', name?: string): string => {
|
|
73
101
|
const match = PR_LABELS.find((entry) => entry.axis === 'state' && entry.sweep.action === action && (name === undefined || entry.name.endsWith(name)));
|
|
@@ -84,6 +112,80 @@ const PAGE_SIZE = 100;
|
|
|
84
112
|
/** At most this many closes per tick, so a wrong rule cannot close everything at once. */
|
|
85
113
|
export const DRAFT_SWEEP_CLOSE_CAP = 10;
|
|
86
114
|
|
|
115
|
+
/** Post-merge shortcut: only the existing superseded-by decision can authorize a close. */
|
|
116
|
+
export async function supersedeDraftsOnMerge(input: {
|
|
117
|
+
repository: string;
|
|
118
|
+
merged: SweepMergedPr & { createdAt: string; mergedAt: string };
|
|
119
|
+
adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listLiveBranches' | 'getRunStatus' | 'setLabels' | 'closeDraft'>
|
|
120
|
+
& Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles'>;
|
|
121
|
+
}): Promise<{ closed: number[]; kept: number[] }> {
|
|
122
|
+
const { repository, merged, adapters } = input;
|
|
123
|
+
const closed: number[] = [];
|
|
124
|
+
const kept: number[] = [];
|
|
125
|
+
let drafts: SweepDraft[] = [];
|
|
126
|
+
let error: string | undefined;
|
|
127
|
+
const failed: number[] = [];
|
|
128
|
+
let closeAttempts = 0;
|
|
129
|
+
try {
|
|
130
|
+
const [listedDrafts, liveBranches] = await Promise.all([
|
|
131
|
+
collectPages((page, size) => adapters.listDrafts(page, size, repository)),
|
|
132
|
+
adapters.listLiveBranches(repository),
|
|
133
|
+
]);
|
|
134
|
+
drafts = listedDrafts;
|
|
135
|
+
if (!liveBranches || !Number.isInteger(merged.number) || !merged.branch || !merged.title
|
|
136
|
+
|| !Number.isFinite(Date.parse(merged.createdAt)) || !Number.isFinite(Date.parse(merged.mergedAt))
|
|
137
|
+
|| drafts.some((pr) => !Number.isInteger(pr.number) || !pr.branch || !Array.isArray(pr.labels)
|
|
138
|
+
|| !Number.isFinite(Date.parse(pr.createdAt)))) throw new Error('Incomplete merge draft inventory');
|
|
139
|
+
const statuses = new Map<number, string | undefined>();
|
|
140
|
+
const latestChanges = new Map<number, Readonly<Record<string, string>> | undefined>();
|
|
141
|
+
const mergedFiles = await adapters.getPrFiles?.(repository, merged.number);
|
|
142
|
+
const landed = { ...merged, changedFiles: mergedFiles };
|
|
143
|
+
for (const draft of drafts) {
|
|
144
|
+
if (draft.number !== merged.number && draft.branch.startsWith('self-impl/') && !liveBranches.has(draft.branch)
|
|
145
|
+
&& Date.parse(draft.createdAt) < Date.parse(merged.mergedAt)) {
|
|
146
|
+
statuses.set(draft.number, await adapters.getRunStatus(draft, repository));
|
|
147
|
+
if (draft.changedFiles?.length && adapters.getLatestFileChanges) {
|
|
148
|
+
latestChanges.set(draft.number, await adapters.getLatestFileChanges(draft, repository));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (const listedDraft of drafts) {
|
|
153
|
+
const draft = { ...listedDraft, latestFileChanges: latestChanges.get(listedDraft.number) };
|
|
154
|
+
if (draft.number === merged.number || !draft.branch.startsWith('self-impl/') || liveBranches.has(draft.branch)
|
|
155
|
+
|| Date.parse(draft.createdAt) >= Date.parse(merged.mergedAt)) {
|
|
156
|
+
kept.push(draft.number);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const decision = decideDraft({ draft, runStatus: statuses.get(draft.number),
|
|
160
|
+
mergedTwins: [landed], liveBranches, ageHours: NaN });
|
|
161
|
+
if (decision.action !== 'close' || !decision.reason.startsWith(`superseded-by #${merged.number}`)
|
|
162
|
+
|| PR_LABELS.filter((entry) => entry.axis === 'state' && draft.labels.includes(entry.name)).length > 1
|
|
163
|
+
|| closeAttempts >= DRAFT_SWEEP_CLOSE_CAP) {
|
|
164
|
+
kept.push(draft.number);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
closeAttempts += 1;
|
|
168
|
+
const remove = stateLabels.filter((entry) => draft.labels.includes(entry.name) && entry.name !== supersededLabel).map((entry) => entry.name);
|
|
169
|
+
try {
|
|
170
|
+
// Label first: a failed label write must never strand a closed, unlabelled PR outside open-draft sweeps.
|
|
171
|
+
if (!draft.labels.includes(supersededLabel)) await adapters.setLabels(repository, draft.number, { add: supersededLabel, remove });
|
|
172
|
+
await adapters.closeDraft(repository, draft.number,
|
|
173
|
+
`Draft sweep: superseded-by #${merged.number} (https://github.com/${repository}/pull/${merged.number}). Branch preserved.`);
|
|
174
|
+
closed.push(draft.number);
|
|
175
|
+
} catch (failure) {
|
|
176
|
+
kept.push(draft.number);
|
|
177
|
+
failed.push(draft.number);
|
|
178
|
+
error = String(failure);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch (failure) {
|
|
182
|
+
error = String(failure);
|
|
183
|
+
kept.push(...drafts.map((draft) => draft.number).filter((number) => !closed.includes(number) && !kept.includes(number)));
|
|
184
|
+
}
|
|
185
|
+
debug.log('drafts.cleanup', 'superseded-on-merge', { merged: merged.number, closed, kept, ...(failed.length ? { failed } : {}), ...(error ? { error } : {}) });
|
|
186
|
+
return { closed, kept };
|
|
187
|
+
}
|
|
188
|
+
|
|
87
189
|
async function collectPages<T>(fetch: (page: number, perPage: number) => Promise<readonly T[]>): Promise<T[]> {
|
|
88
190
|
const rows: T[] = [];
|
|
89
191
|
for (let page = 1; page <= 100; page++) {
|
|
@@ -95,6 +197,46 @@ async function collectPages<T>(fetch: (page: number, perPage: number) => Promise
|
|
|
95
197
|
throw new Error('PR listing exceeded pagination limit');
|
|
96
198
|
}
|
|
97
199
|
|
|
200
|
+
/** First line of a failure, with no stack — the draft-cleanup loop log shows this line as-is. */
|
|
201
|
+
export function sweepFailureReason(error: unknown): string {
|
|
202
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
203
|
+
const line = message.split(/\r?\n/).map((part) => part.trim()).find((part) => part.length > 0 && !/^\s*at\s/.test(part));
|
|
204
|
+
return line && line.length > 0 ? line : 'sweep failed';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function harnessDraft(draft: SweepDraft): boolean {
|
|
208
|
+
return draft.branch.startsWith('self-impl/') || draft.labels.some((name) => name.startsWith('elanous:'));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Census of harness drafts older than 24h. Same-goal landing uses `sameGoalPr` unchanged.
|
|
213
|
+
* A draft counts as closable when a same-goal merged PR exists, harvestable when review PASS and the gate passed,
|
|
214
|
+
* and blocked when must-fix remains. Unknown review/gate is neither harvestable nor blocked.
|
|
215
|
+
*/
|
|
216
|
+
export function draftSweepDaily(
|
|
217
|
+
drafts: readonly SweepDraft[],
|
|
218
|
+
merged: readonly SweepMergedPr[],
|
|
219
|
+
now: Date,
|
|
220
|
+
reviewGate: ReadonlyMap<number, SweepReviewGate | undefined>,
|
|
221
|
+
): DraftSweepDaily {
|
|
222
|
+
const cutoff = now.getTime() - STALLED_DRAFT_HOURS * 3_600_000;
|
|
223
|
+
let over24h = 0;
|
|
224
|
+
let closable = 0;
|
|
225
|
+
let harvestable = 0;
|
|
226
|
+
let blocked = 0;
|
|
227
|
+
for (const draft of drafts) {
|
|
228
|
+
if (!harnessDraft(draft)) continue;
|
|
229
|
+
const created = Date.parse(draft.createdAt);
|
|
230
|
+
if (!Number.isFinite(created) || created > cutoff) continue;
|
|
231
|
+
over24h += 1;
|
|
232
|
+
if (merged.some((pr) => pr.number !== draft.number && sameGoalPr(draft, pr))) closable += 1;
|
|
233
|
+
const posture = reviewGate.get(draft.number);
|
|
234
|
+
if (posture?.mustFix === true) blocked += 1;
|
|
235
|
+
else if (posture?.review === 'pass' && posture.gate === 'pass') harvestable += 1;
|
|
236
|
+
}
|
|
237
|
+
return { date: now.toISOString().slice(0, 10), over24h, closable, harvestable, blocked };
|
|
238
|
+
}
|
|
239
|
+
|
|
98
240
|
/** A failed inventory or liveness lookup is never treated as proof that a draft can be closed. */
|
|
99
241
|
export async function runDraftSweep({ repository, adapters, apply = false, now = new Date() }: DraftSweepOptions): Promise<DraftSweepResult> {
|
|
100
242
|
const result: DraftSweepResult = { repository, apply, complete: false, entries: [], counts: {} };
|
|
@@ -105,10 +247,12 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
|
|
|
105
247
|
};
|
|
106
248
|
const finish = (): DraftSweepResult => {
|
|
107
249
|
debug.log('drafts.cleanup', 'summary', result.counts);
|
|
250
|
+
if (result.daily) debug.log('harness.drafts', 'daily', result.daily);
|
|
251
|
+
if (!result.complete && result.error) debug.log('drafts.cleanup', 'failed', { reason: sweepFailureReason(result.error) });
|
|
108
252
|
return result;
|
|
109
253
|
};
|
|
110
|
-
let drafts: SweepDraft[];
|
|
111
|
-
let merged: SweepMergedPr[];
|
|
254
|
+
let drafts: SweepDraft[] = [];
|
|
255
|
+
let merged: SweepMergedPr[] = [];
|
|
112
256
|
let liveBranches: ReadonlySet<string> | undefined;
|
|
113
257
|
try {
|
|
114
258
|
[drafts, merged, liveBranches] = await Promise.all([
|
|
@@ -120,7 +264,8 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
|
|
|
120
264
|
if (drafts.some((pr) => !Number.isInteger(pr.number) || !pr.branch || !Array.isArray(pr.labels) || !Number.isFinite(Date.parse(pr.createdAt)))
|
|
121
265
|
|| merged.some((pr) => !Number.isInteger(pr.number) || !pr.branch)) throw new Error('Invalid PR inventory');
|
|
122
266
|
} catch (error) {
|
|
123
|
-
result.error =
|
|
267
|
+
result.error = sweepFailureReason(error);
|
|
268
|
+
if (drafts.length > 0) result.daily = draftSweepDaily(drafts, merged, now, new Map());
|
|
124
269
|
return finish();
|
|
125
270
|
}
|
|
126
271
|
let statuses: Map<number, string | undefined>;
|
|
@@ -142,9 +287,19 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
|
|
|
142
287
|
}
|
|
143
288
|
}
|
|
144
289
|
} catch (error) {
|
|
145
|
-
result.error =
|
|
290
|
+
result.error = sweepFailureReason(error);
|
|
146
291
|
return finish();
|
|
147
292
|
}
|
|
293
|
+
let reviewGate = new Map<number, SweepReviewGate | undefined>();
|
|
294
|
+
if (adapters.getReviewGate) {
|
|
295
|
+
try {
|
|
296
|
+
for (const draft of drafts) reviewGate.set(draft.number, await adapters.getReviewGate(draft, repository));
|
|
297
|
+
} catch (error) {
|
|
298
|
+
result.error = sweepFailureReason(error);
|
|
299
|
+
return finish();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
result.daily = draftSweepDaily(drafts, merged, now, reviewGate);
|
|
148
303
|
result.complete = true;
|
|
149
304
|
let closes = 0;
|
|
150
305
|
let unobserved = 0;
|
|
@@ -254,7 +409,8 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
|
|
|
254
409
|
if (action === 'close') {
|
|
255
410
|
await adapters.closeDraft(repository, draft.number, decision.reason === 'stale-unobserved'
|
|
256
411
|
? `Draft sweep: run unobserved — no run record reachable here, no host worktree for this branch, idle ≥${STALLED_DRAFT_HOURS}h. Closed as stalled. Branch preserved; reopen to restore.`
|
|
257
|
-
: `Draft sweep: ${decision.reason}.
|
|
412
|
+
: `Draft sweep: ${decision.reason}${decision.reason.startsWith('superseded-by #')
|
|
413
|
+
? ` (https://github.com/${repository}/pull/${decision.reason.slice('superseded-by #'.length).match(/^\d+/)![0]})` : ''}. Branch preserved.`);
|
|
258
414
|
}
|
|
259
415
|
entry.applied = labelsChanged || action === 'close';
|
|
260
416
|
} catch (error) {
|
|
@@ -38,6 +38,21 @@ const PROTECTED_LABELS: ReadonlySet<string> = new Set<string>([...PR_LABELS
|
|
|
38
38
|
const goalId = (branch: string): string | undefined => /(?:^|[-/])goalid-([a-f0-9]+)(?=-|\/|$)/i.exec(branch)?.[1]?.toLowerCase();
|
|
39
39
|
export const branchStem = (branch: string): string | undefined => /^self-impl\/(.+)-[a-f0-9]{8}-r[a-f0-9]+$/i.exec(branch)?.[1];
|
|
40
40
|
const slot = (body?: string): string | undefined => /^칸:\s*(.+?)\s*$/m.exec(body ?? '')?.[1];
|
|
41
|
+
const goalText = (body?: string): string | undefined => /^골:\s*(\S.*?)\s*$/m.exec(body ?? '')?.[1];
|
|
42
|
+
// Auto titles name only files («src/harness: harness-queue.ts») — different goals share them, so they never identify a goal.
|
|
43
|
+
export const isAutoTitle = (title: string): boolean =>
|
|
44
|
+
/^[\w./-]+:\s*[^\s,]+\.[a-z0-9]+(?:\s*,\s*[^\s,]+\.[a-z0-9]+)*$/i.test(title.trim());
|
|
45
|
+
|
|
46
|
+
/** Same goal (TC 10-05): ① both carry a goal identifier → compare it ② otherwise exact title ⊕ both harness drafts ⊕ same branch stem, never an auto title ③ else false. */
|
|
47
|
+
export function sameGoalPr(a: DraftTriagePr, b: DraftTriagePr): boolean {
|
|
48
|
+
const idA = goalId(a.branch), idB = goalId(b.branch);
|
|
49
|
+
if (idA && idB) return idA === idB;
|
|
50
|
+
const textA = goalText(a.body), textB = goalText(b.body);
|
|
51
|
+
if (textA && textB) return textA === textB;
|
|
52
|
+
if (!a.title || a.title !== b.title || isAutoTitle(a.title)) return false;
|
|
53
|
+
const stemA = branchStem(a.branch);
|
|
54
|
+
return Boolean(stemA && a.branch.startsWith('self-impl/') && b.branch.startsWith('self-impl/') && stemA === branchStem(b.branch));
|
|
55
|
+
}
|
|
41
56
|
const referencesDraft = (text: string, number: number): boolean =>
|
|
42
57
|
new RegExp(`(?:\\(수확\\s*#${number}\\s*\\)|\\bsuperseded\\s*#${number}(?!\\d))`, 'i').test(text);
|
|
43
58
|
const landingCommentReferencesDraft = (text: string, number: number): boolean =>
|
|
@@ -55,28 +70,30 @@ export function decideDraft({ draft, runStatus, mergedTwins, openDrafts, ageHour
|
|
|
55
70
|
return { action: 'keep', reason: 'live' };
|
|
56
71
|
}
|
|
57
72
|
const lineage = goalId(draft.branch);
|
|
58
|
-
const
|
|
59
|
-
(draft.title && pr.title === draft.title) || (lineage && goalId(pr.branch) === lineage)
|
|
60
|
-
));
|
|
61
|
-
if (twin) return { action: 'close', reason: `superseded-by #${twin.number}` };
|
|
73
|
+
const draftSlot = slot(draft.body);
|
|
62
74
|
const stem = branchStem(draft.branch);
|
|
75
|
+
const compatible = (pr: DraftTriagePr): boolean =>
|
|
76
|
+
!(lineage && goalId(pr.branch) && goalId(pr.branch) !== lineage)
|
|
77
|
+
&& !(draftSlot && slot(pr.body) && slot(pr.body) !== draftSlot);
|
|
78
|
+
const twin = mergedTwins.find((pr) => pr.number !== draft.number && compatible(pr) && sameGoalPr(draft, pr));
|
|
79
|
+
if (twin) return { action: 'close', reason: `superseded-by #${twin.number}` };
|
|
63
80
|
const createdAt = Date.parse(draft.createdAt ?? '');
|
|
64
81
|
const newer = stem && draft.title && Number.isFinite(createdAt) ? openDrafts
|
|
65
|
-
?.filter((pr) => pr.number !== draft.number && pr.title === draft.title && branchStem(pr.branch) === stem
|
|
82
|
+
?.filter((pr) => pr.number !== draft.number && pr.title === draft.title && branchStem(pr.branch) === stem && sameGoalPr(draft, pr)
|
|
66
83
|
&& Number.isFinite(Date.parse(pr.createdAt ?? '')) && Date.parse(pr.createdAt!) > createdAt)
|
|
67
84
|
.sort((a, b) => Date.parse(b.createdAt!) - Date.parse(a.createdAt!) || b.number - a.number)[0] : undefined;
|
|
68
85
|
if (newer) return { action: 'close', reason: `duplicate-of-open #${newer.number}` };
|
|
69
|
-
const harvest = mergedTwins.find((pr) => pr.number !== draft.number && (
|
|
86
|
+
const harvest = mergedTwins.find((pr) => pr.number !== draft.number && compatible(pr) && (
|
|
70
87
|
[pr.mergeCommitMessage, pr.body].some((text) => text && referencesDraft(text, draft.number))
|
|
71
88
|
|| pr.landingVerifiedComments?.some((text) => landingCommentReferencesDraft(text, draft.number))
|
|
72
89
|
));
|
|
73
90
|
if (harvest) return { action: 'close', reason: `superseded-by #${harvest.number} (harvest #${draft.number})` };
|
|
74
91
|
const created = Date.parse(draft.createdAt ?? '');
|
|
75
92
|
const files = draft.changedFiles;
|
|
76
|
-
const draftSlot = slot(draft.body);
|
|
77
93
|
const later = mergedTwins.filter((pr) => pr.number !== draft.number && Number.isFinite(created)
|
|
78
94
|
&& Number.isFinite(Date.parse(pr.mergedAt ?? '')) && Date.parse(pr.mergedAt!) > created
|
|
79
|
-
&& ((lineage && goalId(pr.branch) === lineage)
|
|
95
|
+
&& compatible(pr) && ((lineage && goalId(pr.branch) === lineage)
|
|
96
|
+
|| (draftSlot && slot(pr.body) === draftSlot) || (stem && branchStem(pr.branch) === stem)));
|
|
80
97
|
if (files?.length && files.every((file) => {
|
|
81
98
|
const changed = Date.parse(draft.latestFileChanges?.[file] ?? '');
|
|
82
99
|
return Number.isFinite(changed) && changed >= created && later.some((pr) =>
|
|
@@ -260,12 +260,23 @@ export interface SelfDevJobResult {
|
|
|
260
260
|
* (merged / pr-opened / gate-failed / review-blocked / pr-declined). */
|
|
261
261
|
stage?: string;
|
|
262
262
|
branch?: string;
|
|
263
|
+
/** Child confirmed the finished implementation was pushed for manual harvest. */
|
|
264
|
+
harvestable?: true;
|
|
263
265
|
worktreePath?: string;
|
|
264
266
|
prUrl?: string;
|
|
265
267
|
prNumber?: number;
|
|
266
268
|
merged?: boolean;
|
|
267
269
|
/** Child commit SHA, when observed by the Pod/host. */
|
|
268
270
|
checkedHeadCommit?: string;
|
|
271
|
+
/**
|
|
272
|
+
* This run's own `--base` (not main). A non-main completion mode
|
|
273
|
+
* (worktree-only, draft, `--base` other than main) lands commits here.
|
|
274
|
+
*/
|
|
275
|
+
base?: string;
|
|
276
|
+
/** Child finished with GOAL-COMPLETE (`ok=true`). Distinct from a main merge. */
|
|
277
|
+
ok?: boolean;
|
|
278
|
+
/** Commits this child added against its own `--base`. 0 is not completion progress. */
|
|
279
|
+
commitsAheadOfBase?: number;
|
|
269
280
|
/** A dependency is done but its result is not on main; no child was launched. */
|
|
270
281
|
blockReason?: 'parent-unlanded';
|
|
271
282
|
parentPrNumber?: number;
|
|
@@ -405,6 +416,7 @@ export type ResumeDisposition = 'skip' | 'rerun' | 'rerun-duplicate-risk';
|
|
|
405
416
|
*/
|
|
406
417
|
export function classifyResumeDisposition(result: SelfDevJobResult): ResumeDisposition {
|
|
407
418
|
if (hasDelivered(result)) return 'skip';
|
|
419
|
+
if (result.harvestable === true && result.branch) return 'skip';
|
|
408
420
|
if (result.stage === 'pr-opened') return 'rerun-duplicate-risk';
|
|
409
421
|
if (result.merged === false) return 'rerun';
|
|
410
422
|
if (result.status !== 'done') return 'rerun';
|
|
@@ -621,6 +633,7 @@ export function classifyFailure(
|
|
|
621
633
|
) {
|
|
622
634
|
return 'awaiting-human';
|
|
623
635
|
}
|
|
636
|
+
if (result.harvestable === true && result.branch) return 'main-sync-blocked';
|
|
624
637
|
if (result.status === 'done' && !hasDelivered(result)) return convergedFailureKind();
|
|
625
638
|
// ⭐ 상류가 죽어 «취소»된 조각 — 종전엔 status 가 failed 도 done 도 아니라 null 로 사라졌다.
|
|
626
639
|
// ⛔ 이것을 못 보면 「무엇이 상류를 기다리는가」를 슈퍼바이저가 영영 모른다.
|
|
@@ -1479,6 +1492,7 @@ export function orchestrateSelfDev(opts: OrchestrateSelfDevOptions): Promise<Sel
|
|
|
1479
1492
|
...(resumeDisposition ? { resumeDisposition } : {}),
|
|
1480
1493
|
...(disp?.stage ? { stage: disp.stage } : {}),
|
|
1481
1494
|
...(disp?.branch ? { branch: disp.branch } : {}),
|
|
1495
|
+
...(disp?.harvestable === true && disp.branch ? { harvestable: true } : {}),
|
|
1482
1496
|
...(disp?.worktreePath ? { worktreePath: disp.worktreePath } : {}),
|
|
1483
1497
|
...(disp?.prUrl ? { prUrl: disp.prUrl } : {}),
|
|
1484
1498
|
...(disp?.prNumber !== undefined ? { prNumber: disp.prNumber } : {}),
|
|
@@ -1526,7 +1540,7 @@ export function orchestrateSelfDev(opts: OrchestrateSelfDevOptions): Promise<Sel
|
|
|
1526
1540
|
const rm = opts.removeWorktree ?? defaultRemoveWorktree;
|
|
1527
1541
|
let removed = 0;
|
|
1528
1542
|
for (const r of out) {
|
|
1529
|
-
if (!r.worktreePath || r.prUrl) continue;
|
|
1543
|
+
if (!r.worktreePath || r.prUrl || r.harvestable) continue;
|
|
1530
1544
|
try { rm(r.worktreePath); removed++; } catch { /* fail-soft */ }
|
|
1531
1545
|
}
|
|
1532
1546
|
if (removed > 0) debug.log('self-dev.orchestrate', 'teardown', { removed });
|
|
@@ -73,13 +73,18 @@ export function buildReviewProviderAttempts(
|
|
|
73
73
|
const out: ReviewProviderAttempt[] = [primary];
|
|
74
74
|
const seen = new Set([primary.model]);
|
|
75
75
|
for (const f of fallbacks) {
|
|
76
|
-
if (!f.model.trim() || seen.has(f.model)) continue;
|
|
76
|
+
if (!f.model.trim() || seen.has(f.model) || (primary.provider && f.provider?.name === primary.provider.name)) continue;
|
|
77
77
|
seen.add(f.model);
|
|
78
78
|
out.push(f);
|
|
79
79
|
}
|
|
80
80
|
return out;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/** A distinct provider is available even when the optional config list is empty. */
|
|
84
|
+
export function defaultReviewFallbackModel(primaryProvider?: string): string {
|
|
85
|
+
return resolveModelAlias(primaryProvider === 'grok' ? 'claude' : 'grok')!;
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
export interface ReviewFallbackObservation {
|
|
84
89
|
readonly attempt: number;
|
|
85
90
|
readonly total: number;
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* Cf. PLAN-parallel-self-dev-orchestrator-2026-07-21 §5 (S3).
|
|
17
17
|
*/
|
|
18
18
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
19
|
+
import { dlopen, FFIType } from 'bun:ffi';
|
|
19
20
|
import { randomUUID } from 'node:crypto';
|
|
20
|
-
import { debug } from '../debug/log.js';
|
|
21
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
21
22
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
22
23
|
import { loadRunLedger, queryInterruptedRunLedgers, runLedgerDir, type RunLedgerEntry } from '../self-implement/run-ledger.js';
|
|
23
24
|
import { join, resolve, sep } from 'node:path';
|
|
@@ -68,6 +69,8 @@ export interface SelfDevRunState {
|
|
|
68
69
|
createdAt: number;
|
|
69
70
|
updatedAt: number;
|
|
70
71
|
results: SelfDevJobResult[];
|
|
72
|
+
/** Redacted, bounded one-line projection for loop readers; legacy checkpoints omit it. */
|
|
73
|
+
summaryLine?: string;
|
|
71
74
|
/** Undefined means a legacy checkpoint has no dependency information; each key is a shard ID and its array lists predecessor shard IDs. */
|
|
72
75
|
dependencies?: Record<string, string[]>;
|
|
73
76
|
/**
|
|
@@ -93,6 +96,10 @@ export interface SelfDevRunState {
|
|
|
93
96
|
* non-terminal goal 은 **실행중(running)** 이지 막힌(interrupted) 게 아니다. 죽었으면(오케스트레이터
|
|
94
97
|
* killed) 진짜 interrupted. isPidAlive 로 구분해 라이브 잡을 parked/repair-signals 에서 제외. */
|
|
95
98
|
pid?: number;
|
|
99
|
+
/** OS process birth identity, paired with pid to reject a recycled pid. */
|
|
100
|
+
pidStart?: string;
|
|
101
|
+
/** Seat fixed at launch; survives removal of the launch worktree. */
|
|
102
|
+
seat?: 'OP' | 'TC' | 'MK' | 'UX';
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
/** `<ELANOUS_STATE_DIR or ~/.elanous>/self-dev-runs`. */
|
|
@@ -103,6 +110,34 @@ export function selfDevRunsDir(stateDir?: string): string {
|
|
|
103
110
|
|
|
104
111
|
const RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
105
112
|
|
|
113
|
+
/** Kernel process birth identity: Linux boot ID + start ticks or Darwin microseconds since epoch. */
|
|
114
|
+
export function processBirthId(pid: number, platform: NodeJS.Platform = process.platform): string | undefined {
|
|
115
|
+
if (!Number.isSafeInteger(pid) || pid < 1) return undefined;
|
|
116
|
+
try {
|
|
117
|
+
if (platform === 'linux') {
|
|
118
|
+
const stat = readFileSync(`/proc/${pid}/stat`, 'utf8');
|
|
119
|
+
const tail = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
|
|
120
|
+
const ticks = tail[19]; // field 22 (starttime), after pid and parenthesized comm
|
|
121
|
+
const bootId = readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim();
|
|
122
|
+
return ticks && /^\d+$/.test(ticks) && /^[0-9a-f-]{36}$/i.test(bootId)
|
|
123
|
+
? `linux:${bootId}:${ticks}` : undefined;
|
|
124
|
+
}
|
|
125
|
+
if (platform === 'darwin') {
|
|
126
|
+
const libproc = dlopen('/usr/lib/libproc.dylib', {
|
|
127
|
+
proc_pidinfo: { args: [FFIType.i32, FFIType.i32, FFIType.u64, FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
|
|
128
|
+
});
|
|
129
|
+
try {
|
|
130
|
+
const buf = new Uint8Array(136);
|
|
131
|
+
if (libproc.symbols.proc_pidinfo(pid, 3, 0n, buf, buf.length) !== buf.length) return undefined;
|
|
132
|
+
const view = new DataView(buf.buffer);
|
|
133
|
+
if (view.getUint32(12, true) !== pid) return undefined;
|
|
134
|
+
return `darwin:${view.getBigUint64(120, true) * 1_000_000n + view.getBigUint64(128, true)}`;
|
|
135
|
+
} finally { libproc.close(); }
|
|
136
|
+
}
|
|
137
|
+
} catch { /* Unreadable birth identity is not evidence of a match. */ }
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
106
141
|
function runPath(runId: string, dir: string): string {
|
|
107
142
|
if (!RUN_ID.test(runId)) throw new Error(`invalid self-dev run ID: ${runId}`);
|
|
108
143
|
const root = resolve(dir);
|
|
@@ -154,6 +189,40 @@ function mergeParticipants(
|
|
|
154
189
|
return [...byId.values()];
|
|
155
190
|
}
|
|
156
191
|
|
|
192
|
+
const SUMMARY_LINE_LIMIT = 120;
|
|
193
|
+
const FINISHED_RESULT_STATUSES = new Set(['done', 'failed', 'cancelled', 'superseded']);
|
|
194
|
+
|
|
195
|
+
function boundedSummaryLine(text: string): string {
|
|
196
|
+
const redacted = redactSecretText(text.replace(/\s+/g, ' ').trim());
|
|
197
|
+
if (redacted.length <= SUMMARY_LINE_LIMIT) return redacted;
|
|
198
|
+
const head = redacted.slice(0, SUMMARY_LINE_LIMIT - 1).replace(/[\uD800-\uDBFF]$/, '');
|
|
199
|
+
return `${head}…`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Read-only projection for loop readers; missing legacy fields are derived in memory. */
|
|
203
|
+
export function runSummaryLine(state: SelfDevRunState): string {
|
|
204
|
+
if (state.summaryLine !== undefined) return boundedSummaryLine(state.summaryLine);
|
|
205
|
+
const feature = state.goals?.[0]?.feature ?? state.results[0]?.feature ?? '';
|
|
206
|
+
const head = feature.split(/\r?\n/, 1)[0]?.trim() ?? '';
|
|
207
|
+
const header = /^「하니스로 구현」\s+(\S+?)\s+—\s*(.*)$/.exec(head);
|
|
208
|
+
const id = state.goals?.[0]?.goalId ?? header?.[1] ?? state.goals?.[0]?.id ?? state.runId;
|
|
209
|
+
const phrase = (header?.[2] ?? head).split(/[.!?。;;]/, 1)[0]?.trim() ?? '';
|
|
210
|
+
const finished = state.results.length > 0
|
|
211
|
+
&& state.results.every((result) => FINISHED_RESULT_STATUSES.has(result.status));
|
|
212
|
+
if (finished) {
|
|
213
|
+
// A completed shard cannot hide a failed one merely by settling later.
|
|
214
|
+
const result = state.results.find(({ status }) => status === 'failed')
|
|
215
|
+
?? state.results.find(({ status }) => status === 'cancelled')
|
|
216
|
+
?? state.results.find(({ status }) => status === 'superseded')
|
|
217
|
+
?? state.results.at(-1)!;
|
|
218
|
+
const stage = result.stage ?? result.status;
|
|
219
|
+
const prNumber = result.prNumber ?? Number(/\/pull\/(\d+)(?:[/?#]|$)/.exec(result.prUrl ?? '')?.[1]);
|
|
220
|
+
const pr = Number.isSafeInteger(prNumber) && prNumber > 0 ? ` · PR #${prNumber}` : '';
|
|
221
|
+
return boundedSummaryLine(`${id} · ${stage}${pr}`);
|
|
222
|
+
}
|
|
223
|
+
return boundedSummaryLine(`「하니스로 구현」 ${id}${phrase ? ` — ${phrase}` : ''}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
157
226
|
/** Persist a run checkpoint (fail-soft — never throws into the caller). */
|
|
158
227
|
export function saveSelfDevRun(state: SelfDevRunState, dir = selfDevRunsDir()): void {
|
|
159
228
|
try {
|
|
@@ -163,7 +232,10 @@ export function saveSelfDevRun(state: SelfDevRunState, dir = selfDevRunsDir()):
|
|
|
163
232
|
const participants = mergeParticipants(current?.participants, state.participants);
|
|
164
233
|
const saved = {
|
|
165
234
|
...state,
|
|
235
|
+
summaryLine: runSummaryLine({ ...state, goals: state.goals ?? current?.goals, summaryLine: undefined }),
|
|
166
236
|
...(participants === undefined ? {} : { participants }),
|
|
237
|
+
...(current?.seat && !state.seat ? { seat: current.seat } : {}),
|
|
238
|
+
...(current?.pidStart && current.pid === state.pid && !state.pidStart ? { pidStart: current.pidStart } : {}),
|
|
167
239
|
...(current?.parkedResolution && !state.parkedResolution ? { parkedResolution: current.parkedResolution } : {}),
|
|
168
240
|
};
|
|
169
241
|
writeSelfDevRun(saved, dir);
|