elanous 0.2.15 → 0.2.17
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/chunks/{1307-33ffcc49ab45123b.js → 1307-aac7332576c4d6fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6877-7c6208705c284124.js → 6877-fe94e76a5841ee9b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9103-7a3ae7f60af3b99f.js → 9103-60fbef33e66f0a46.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-0e2c57fe6add4b2a.js → page-3143b07a817d1da9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-e05a77df7e005b04.js → page-17ba086ef82d339b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-b8c49f6b4fa2df91.js → page-6e5c3a867557298b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-976813c91d7394ea.js → page-9a41d65355fc25b9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-1d4901eb7c2d8822.js → page-41afec0b255ed2bb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-72d3e7ff35a8c954.js → page-4187666132fc98c4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-60c7a8e1a4fe62ce.js → page-09328d499162bae4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-2a52b316cb143d9c.js → page-29ff3a8f84f03b6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-c3ce483c8d5db370.js → page-80ec7401bc83f511.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-96f074f6538e8a2c.js → page-fc7d86467291ae38.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{layout-e97be5334d83a9f5.js → layout-de43a186e5ba5683.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-c1343f9499d86f3f.js → page-043a9111e74f6b24.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-8739a2e0ae793130.js → not-found-23a4601ceb7f452e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-d23b12bb92242558.js → page-10d958605a77b3bd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-c7fea475488201a8.js → page-a04260b8ccc968d4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-5efbf81124c474ae.js → page-12916918988ac97e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-06ee266953d9c879.js → page-5a64cb5208c6a8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-153c2b3bcc89e8de.js → page-1407ec83ea64c1f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/{page-0d6d23b40263a7ea.js → page-7f49fe645d5132f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-73735b64bfe1ae67.js → page-424659bacfb8cdd7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-f7e631e9b4daf66e.js → page-fc2df261f8a2c7df.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-9817c7f9007466cc.js → page-5d4fef9ccd7d406b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +1 -0
- package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +1 -0
- package/apps/pwa/out/_next/static/css/{04dabcbcc4bfa6db.css → 085673d826b98b62.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +15 -15
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +15 -15
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +15 -15
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +15 -15
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +15 -15
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +15 -15
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +15 -15
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +15 -15
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +15 -15
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +15 -15
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +15 -15
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +15 -15
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +15 -15
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +15 -15
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +15 -15
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +15 -15
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +15 -15
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +15 -15
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +15 -15
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +15 -15
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +15 -15
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +15 -15
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +15 -15
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +15 -15
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +15 -15
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +15 -15
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +16 -16
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +15 -15
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +15 -15
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +15 -15
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +15 -15
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +15 -15
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +15 -15
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +15 -15
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +15 -15
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +15 -15
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +15 -15
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +15 -15
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +15 -15
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +15 -15
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +15 -15
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +15 -15
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +15 -15
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +15 -15
- package/graphs/doc-gen/doc-gen.yaml +24 -0
- package/graphs/doc-gen/recipes.yaml +3 -0
- package/graphs/intake/intake-daily.yaml +9 -2
- package/graphs/intake/news-sources.yaml +4 -0
- package/graphs/intake/recipes.yaml +6 -1
- package/graphs/orchestrator/orchestrator.yaml +7 -0
- package/graphs/orchestrator/recipes.yaml +3 -0
- package/graphs/steward/recipes.yaml +2 -1
- package/package.json +1 -1
- package/scripts/__fixtures__/intake-news.xml +7 -0
- package/scripts/ci-public-export-import-gate.ts +154 -0
- package/scripts/ci-test-interference-gate.ts +5 -1
- package/scripts/ci-typecheck-changed.ts +34 -15
- package/scripts/docs/doc-rot.ts +164 -0
- package/scripts/docs/generate-graph-anatomy.ts +131 -9
- package/scripts/docs-cli-check.ts +4 -4
- package/scripts/goals/goal-census.ts +343 -0
- package/scripts/intake-news.ts +169 -0
- package/scripts/measure/author-section-contribution.ts +84 -0
- package/scripts/release-loop/cut-branch.ts +43 -13
- package/scripts/release-loop/docs-land-node.ts +69 -10
- package/scripts/release-loop/gate-node.ts +3 -1
- package/scripts/release-loop/publish-node.ts +2 -2
- package/scripts/release-loop/release-docs.ts +134 -0
- package/scripts/release-loop/vault-note-node.ts +19 -2
- package/scripts/release-loop/version-node.ts +7 -4
- package/scripts/release-story/draft.ts +42 -14
- package/scripts/rhythm/monthly.ts +97 -0
- package/src/acp/client.ts +17 -2
- package/src/agent-mission/driver.ts +104 -11
- package/src/agent-mission/supervisor-metrics-cli.ts +40 -0
- package/src/agent-mission/supervisor-metrics.ts +218 -0
- package/src/autopilot/track-agent-shadow.ts +2 -1
- package/src/autopilot/track-agent.ts +5 -3
- package/src/briefing/brief-items.ts +191 -36
- package/src/budget/usage-outcomes.ts +204 -0
- package/src/cli/autopilot-cli.ts +66 -0
- package/src/cli/brief-cli.ts +73 -0
- package/src/cli/decisions-cli.ts +4 -1
- package/src/cli/intake-cli.ts +1 -1
- package/src/cli/know-cli.ts +20 -0
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/logs-cli.ts +43 -1
- package/src/cli/pr-cli.ts +92 -13
- package/src/cli/provider-cli.ts +14 -0
- package/src/cli/release-cli.ts +11 -8
- package/src/cli/self-update-canary.ts +46 -0
- package/src/cli/self-update.ts +399 -1
- package/src/cli/usage-cli.ts +26 -0
- package/src/context-card/index.ts +45 -0
- package/src/context-card/task.ts +76 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
- package/src/decisions/decision-ledger.ts +10 -1
- package/src/discord-self-message.ts +9 -0
- package/src/flow-loop/split.ts +24 -0
- package/src/harness/harness-cli-command.ts +178 -12
- package/src/harness/harness-pod-dispatch.ts +36 -55
- package/src/harness/harness-queue.ts +86 -7
- package/src/harness/harness-seams.ts +13 -3
- package/src/harness/helper-repair.ts +139 -8
- package/src/harness/helper-scan.ts +13 -2
- package/src/harness/nested-elanous-policy.ts +133 -0
- package/src/hq/fence-wrapper.ts +123 -0
- package/src/hq/hq.ts +16 -2
- package/src/hq/lease.ts +5 -3
- package/src/hq/transfer.ts +185 -0
- package/src/index.ts +168 -13
- package/src/intake-plane/digest.ts +85 -28
- package/src/knowledge/know-find.ts +105 -0
- package/src/llm.ts +75 -19
- package/src/loops/orchestrator/finish-rate.ts +14 -3
- package/src/loops/orchestrator/tick.ts +96 -25
- package/src/maturity/bot-slash-catalog.ts +11 -2
- package/src/maturity/feature-maturity.ts +2 -2
- package/src/maturity/tui-slash-availability.ts +9 -0
- package/src/nexus/api/grid.ts +61 -0
- package/src/nexus/api/http-server.ts +19 -1
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/oauth/codex.ts +82 -2
- package/src/oauth/overload-failover-launch.ts +75 -0
- package/src/oauth/overload-failover.ts +137 -0
- package/src/release-loop/checklist.ts +10 -5
- package/src/release-loop/feature-store.ts +10 -9
- package/src/release-loop/landing-freeze.ts +18 -10
- package/src/release-loop/placement.ts +17 -8
- package/src/seat-dispatch/seat-ask.ts +33 -6
- package/src/seat-loop/seat-loop.ts +172 -21
- package/src/self-dev/ask-launch-flow.ts +48 -8
- package/src/self-dev/authored-goal-trace.ts +64 -0
- package/src/self-dev/dev-cli.ts +19 -1
- package/src/self-dev/dev-pipeline.ts +6 -5
- package/src/self-dev/entrance-registry.ts +10 -6
- package/src/self-dev/old-door.ts +73 -0
- package/src/self-dev/run-store.ts +5 -1
- package/src/self-dev/run-supervisor.ts +7 -1
- package/src/self-dev/supervisor-verdict-edges.ts +46 -0
- package/src/self-implement/app-api-budget.ts +166 -0
- package/src/self-implement/budget-gate.ts +7 -5
- package/src/self-implement/follow-up-goals.ts +289 -0
- package/src/self-implement/frozen-merges.ts +25 -20
- package/src/self-implement/goal-author-clarification.ts +81 -0
- package/src/self-implement/goal-author-cli.ts +33 -5
- package/src/self-implement/goal-author.ts +107 -25
- package/src/self-implement/goal-clarification-escalation.ts +37 -1
- package/src/self-implement/goal-document-write.ts +28 -0
- package/src/self-implement/heal-intake.ts +4 -0
- package/src/self-implement/heal-triage.ts +44 -0
- package/src/self-implement/host-regate.ts +3 -1
- package/src/self-implement/orchestrator.ts +157 -8
- package/src/self-implement/run-ledger.ts +4 -0
- package/src/self-implement/seams.ts +44 -15
- package/src/session-runtime/index.ts +2 -0
- package/src/session-runtime/retry-api.ts +87 -0
- package/src/session-runtime/retry-policy.ts +107 -6
- package/src/steward/working-backwards.ts +16 -1
- package/src/task-agent/actions.ts +118 -0
- package/src/task-agent/judge.ts +96 -0
- package/src/task-cards/card-cli.ts +25 -0
- package/src/task-cards/card-store.ts +9 -4
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +33 -4
- package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +4 -3
- package/src/task-orchestrator/surfaces/pod-ledger-prod-sink.ts +75 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +95 -18
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +37 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +168 -37
- package/src/task-orchestrator/surfaces/self-implement.ts +2 -0
- package/src/telegram-commands.ts +6 -1
- package/src/telegram-loops-command.ts +21 -14
- package/src/telegram.ts +47 -0
- package/src/user-config.ts +59 -4
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-29d889b809288e65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-f5597e894c02cd33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +0 -1
- package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +0 -1
- package/src/launch-head/seat-goal-queue-lock.fixture.ts +0 -15
- package/src/launch-head/seat-goal-queue.ts +0 -198
- /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_ssgManifest.js +0 -0
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// ⛔ 종료(`process.exit`)는 여기가 «안» 한다 — 호출자가 자기 표면에 맞게 끝낸다.
|
|
12
12
|
// 그래서 결과를 «세 값»으로 낸다: 발사 / 저작 전 중단 / 전제 검사 중단.
|
|
13
13
|
import { linesOutsideFencedCode } from '../self-implement/goal-author.js';
|
|
14
|
+
import { recordAuthoredGoal } from './authored-goal-trace.js';
|
|
14
15
|
import { retiredEntranceNotice, type EntranceDeclaration } from './entrance-registry.js';
|
|
15
16
|
import {
|
|
16
17
|
classifyConcurrentAuthoring,
|
|
@@ -34,6 +35,8 @@ import { dirname, isAbsolute as isAbsolutePath, relative as relativePath, resolv
|
|
|
34
35
|
import {
|
|
35
36
|
applyClarificationReply,
|
|
36
37
|
planClarificationIntake,
|
|
38
|
+
selfAnswerGoalDocumentClarifications,
|
|
39
|
+
type GoalClarificationSelfResolver,
|
|
37
40
|
} from '../self-implement/goal-author-clarification.js';
|
|
38
41
|
import { classifyReauthoredAsk, countMissingAuthoredConstraintMarkers, askGoalTypeDeclaration, declaredGoalType, parseGoalId } from '../self-implement/goal-author.js';
|
|
39
42
|
import { observeFrontNodeEntry } from './graph-front-nodes.js';
|
|
@@ -58,7 +61,7 @@ function resolveSelfResolveClarifications(explicit: boolean | undefined): Resolv
|
|
|
58
61
|
/** 저작기 산출 — `runGoalAuthorCli` 의 반환에서 이 흐름이 «실제로 쓰는» 것만. */
|
|
59
62
|
export interface AskAuthoredGoal {
|
|
60
63
|
readonly path: string;
|
|
61
|
-
readonly authored?: { readonly document?: string; readonly grounded?: boolean | null } | null;
|
|
64
|
+
readonly authored?: { readonly document?: string; readonly grounded?: boolean | null; readonly authorRunId?: string } | null;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
export type LaunchingTreeProbe =
|
|
@@ -142,6 +145,9 @@ export interface AskLaunchFlowDeps {
|
|
|
142
145
|
/** Optional structured clarification adapter. Omitted callers retain the
|
|
143
146
|
* existing CLI line-input contract exactly. */
|
|
144
147
|
readClarification?(clarification: GoalDocumentClarification): Promise<string>;
|
|
148
|
+
selfResolveClarification?: GoalClarificationSelfResolver;
|
|
149
|
+
/** Replaces the goal document after a self-answer; production entrances pass an atomic writer. */
|
|
150
|
+
writeGoalDocument?(path: string, document: string): void;
|
|
145
151
|
readFile(path: string): string;
|
|
146
152
|
writeFile(path: string, data: string): void;
|
|
147
153
|
cwd(): string;
|
|
@@ -158,6 +164,8 @@ export interface AskLaunchFlowDeps {
|
|
|
158
164
|
/** ⛔ 못 얻으면 `null` — 같은 이유. */
|
|
159
165
|
recentAuthoringSamples(): RecentAuthoringSample[] | null;
|
|
160
166
|
authorGoal(args: readonly string[], options: Record<string, unknown>): Promise<AskAuthoredGoal>;
|
|
167
|
+
/** AUTHOR-TRACE seam (tests). */
|
|
168
|
+
recordAuthoredGoal?: typeof recordAuthoredGoal;
|
|
161
169
|
/** Pod launches reserve a host slot before goal authoring begins. */
|
|
162
170
|
beforeAuthoring?(): Promise<void>;
|
|
163
171
|
/** 발사 전 권고용 분해 seam. 생략하면 전용 관측명을 준 기존 분해기를 쓴다. */
|
|
@@ -185,6 +193,7 @@ export interface AskLaunchFlowInput {
|
|
|
185
193
|
readonly askFile?: string;
|
|
186
194
|
/** Optional repository root used only for code grounding during goal authoring. */
|
|
187
195
|
readonly groundingCwd?: string;
|
|
196
|
+
readonly authorGrade?: import('../self-implement/goal-author.js').GoalAuthorGradeSelection;
|
|
188
197
|
readonly liveRunWindowMinutes: number;
|
|
189
198
|
readonly recentChangeWindowDays: number;
|
|
190
199
|
readonly forceRequested: boolean;
|
|
@@ -721,16 +730,27 @@ async function intakeClarifications(
|
|
|
721
730
|
return effectiveGoalFile;
|
|
722
731
|
}
|
|
723
732
|
if (mode === 'deferred-noninteractive') {
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
733
|
+
// The resolver comes in through deps (I/O seam): production entrances pass the author
|
|
734
|
+
// self-resolver; a caller that injects none keeps the previous deferred behaviour.
|
|
735
|
+
if (selfResolveClarifications.value && deps.selfResolveClarification) try {
|
|
736
|
+
const resolution = await selfAnswerGoalDocumentClarifications(document, {
|
|
737
|
+
path: 'ask', ask: input.askText, resolver: deps.selfResolveClarification,
|
|
738
|
+
});
|
|
739
|
+
if (resolution.newlyAnswered > 0) {
|
|
740
|
+
(deps.writeGoalDocument ?? deps.writeFile)(effectiveGoalFile, resolution.document);
|
|
741
|
+
document = resolution.document;
|
|
742
|
+
}
|
|
743
|
+
} catch (error) {
|
|
744
|
+
deps.log('ask-clarify', { goalFile: effectiveGoalFile, reason: 'self-answer-failed', error: error instanceof Error ? error.message : String(error) }, 'warn');
|
|
745
|
+
}
|
|
746
|
+
const remaining = planClarificationIntake(document, false).pending;
|
|
747
|
+
// 미답으로 남은 문항만 기존 답변 창구를 안내한다.
|
|
748
|
+
deps.print(`[ask] ⑴b ⚠️ 미답 되묻기 ${remaining.length}건 — 저작은 그대로 간다 · 구현 전에 LLM 릴레이가 먼저 답하고, 못 하면 미답으로 진행한다 (사람을 기다리지 않는다)`);
|
|
749
|
+
for (const item of remaining) {
|
|
730
750
|
deps.print(`[ask] ❓ [${item.questionId}] ${item.question}`);
|
|
731
751
|
item.options.forEach((option, index) => deps.print(`[ask] ${index}) ${option.label}`));
|
|
732
752
|
}
|
|
733
|
-
if (
|
|
753
|
+
if (remaining.length > 0) {
|
|
734
754
|
const goalArg = deps.relativeToCwd(effectiveGoalFile);
|
|
735
755
|
deps.print(`[ask] ▶ 답하려면: elanous self clarify answer ${goalArg} <questionId> <옵션번호> (자유 답은 --other "<문장>")`);
|
|
736
756
|
deps.print(`[ask] ▶ 답한 뒤 재저작: elanous self author --supersedes ${goalArg}`);
|
|
@@ -768,6 +788,7 @@ async function intakeClarifications(
|
|
|
768
788
|
const reauthored = await deps.authorGoal([], {
|
|
769
789
|
cwd: deps.cwd(),
|
|
770
790
|
...(input.groundingCwd === undefined ? {} : { groundingCwd: input.groundingCwd }),
|
|
791
|
+
...(input.authorGrade === undefined ? {} : { authorGrade: input.authorGrade }),
|
|
771
792
|
fromClarification: `${deps.relativeToCwd(effectiveGoalFile)}#${seedQuestionId}`,
|
|
772
793
|
reauthorFromAnsweredClarification: true,
|
|
773
794
|
selfResolveClarifications: selfResolveClarifications.value,
|
|
@@ -850,6 +871,7 @@ export async function runAskLaunchFlow(
|
|
|
850
871
|
const authored = await deps.authorGoal([input.askText], {
|
|
851
872
|
cwd: deps.cwd(),
|
|
852
873
|
...(input.groundingCwd === undefined ? {} : { groundingCwd: input.groundingCwd }),
|
|
874
|
+
...(input.authorGrade === undefined ? {} : { authorGrade: input.authorGrade }),
|
|
853
875
|
...(goalType === null ? {} : { goalType }),
|
|
854
876
|
// ⛔ 인라인 ask(`harness say`)는 askFile 이 없다 — 그 칸을 넘기면 저작기가 빈 줄을 쓴다.
|
|
855
877
|
...(() => {
|
|
@@ -861,6 +883,24 @@ export async function runAskLaunchFlow(
|
|
|
861
883
|
selfResolveClarifications: selfResolveClarifications.value,
|
|
862
884
|
});
|
|
863
885
|
deps.print(`[ask] 저작됨: ${authored.path}`);
|
|
886
|
+
// AUTHOR-TRACE: the authored goal file can be cleaned up later — keep path ⊕ sha256 ⊕ size in the run ledger and
|
|
887
|
+
// archive the body, so authoring length is measurable after the fact (GOAL-BENCH · AUTHOR-LITE).
|
|
888
|
+
const traceIds = {
|
|
889
|
+
...(input.runId === undefined ? {} : { runId: input.runId }),
|
|
890
|
+
...(authored.authored?.authorRunId === undefined ? {} : { authorRunId: authored.authored.authorRunId }),
|
|
891
|
+
};
|
|
892
|
+
if (authored.authored?.document !== undefined && (traceIds.runId !== undefined || traceIds.authorRunId !== undefined)) {
|
|
893
|
+
try {
|
|
894
|
+
const trace = (deps.recordAuthoredGoal ?? recordAuthoredGoal)(traceIds, authored.path, authored.authored.document);
|
|
895
|
+
deps.log('goal-authored-trace', { ...traceIds, ...trace }, 'info');
|
|
896
|
+
} catch (error) {
|
|
897
|
+
deps.log('goal-authored-trace-failed', { ...traceIds, error: error instanceof Error ? error.message : String(error) }, 'warn');
|
|
898
|
+
}
|
|
899
|
+
} else {
|
|
900
|
+
deps.log('goal-authored-trace-skipped', {
|
|
901
|
+
reason: authored.authored?.document === undefined ? 'no-authored-document' : 'no-run-or-author-id', path: authored.path,
|
|
902
|
+
}, 'warn');
|
|
903
|
+
}
|
|
864
904
|
const markerCounts = authored.authored?.document === undefined
|
|
865
905
|
? null
|
|
866
906
|
: countMissingAuthoredConstraintMarkers(input.askText, authored.authored.document);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { appendRunLedgerEntry, runLedgerDir } from '../self-implement/run-ledger.js';
|
|
5
|
+
import { debug } from '../debug/log.js';
|
|
6
|
+
|
|
7
|
+
/** AUTHOR-TRACE: what `harness say`/`ask` authored, kept with the run — the goal file itself may be cleaned up later,
|
|
8
|
+
* so the ledger carries path ⊕ sha256 ⊕ size and the body is archived next to the ledger. */
|
|
9
|
+
export interface AuthoredGoalTrace {
|
|
10
|
+
path: string;
|
|
11
|
+
sha256: string;
|
|
12
|
+
chars: number;
|
|
13
|
+
sections: number;
|
|
14
|
+
archivedAt: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** `## ` headings outside fenced code (a fence closes only on the same marker, at least as long). */
|
|
18
|
+
function countSections(document: string): number {
|
|
19
|
+
let fence: { char: string; length: number } | null = null;
|
|
20
|
+
let count = 0;
|
|
21
|
+
for (const line of document.split('\n')) {
|
|
22
|
+
const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line);
|
|
23
|
+
if (fence) {
|
|
24
|
+
if (marker && marker[1]![0] === fence.char && marker[1]!.length >= fence.length && line.trim() === marker[1]) fence = null;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (marker) { fence = { char: marker[1]![0]!, length: marker[1]!.length }; continue; }
|
|
28
|
+
if (/^ {0,3}##\s/.test(line)) count += 1;
|
|
29
|
+
}
|
|
30
|
+
return count;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function authoredGoalTrace(path: string, document: string, archivedAt: string): AuthoredGoalTrace {
|
|
34
|
+
return {
|
|
35
|
+
path,
|
|
36
|
+
sha256: createHash('sha256').update(document).digest('hex'),
|
|
37
|
+
chars: [...document].length,
|
|
38
|
+
sections: countSections(document),
|
|
39
|
+
archivedAt,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Archive the body, emit one `goal-author`/`goal-authored` observation and — when the run id is already known —
|
|
44
|
+
* append a `goal-authored` run-ledger event. At `harness say` authoring time the run id usually does not exist yet;
|
|
45
|
+
* the authoring run id (`authorRunId`, joined to the goal by `goal-id-assigned`) keys the record then. */
|
|
46
|
+
export function recordAuthoredGoal(
|
|
47
|
+
ids: { runId?: string; authorRunId?: string },
|
|
48
|
+
path: string,
|
|
49
|
+
document: string,
|
|
50
|
+
options: { ledgerDir?: string; archiveDir?: string } = {},
|
|
51
|
+
): AuthoredGoalTrace {
|
|
52
|
+
const key = ids.runId ?? ids.authorRunId;
|
|
53
|
+
if (!key) throw new Error('recordAuthoredGoal needs a runId or an authorRunId');
|
|
54
|
+
const ledgerDir = options.ledgerDir ?? runLedgerDir();
|
|
55
|
+
const archiveDir = options.archiveDir ?? join(dirname(ledgerDir), 'authored-goals');
|
|
56
|
+
const digest = createHash('sha256').update(document).digest('hex');
|
|
57
|
+
const archived = join(archiveDir, `${key}-${digest.slice(0, 12)}.md`);
|
|
58
|
+
if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
|
|
59
|
+
writeFileSync(archived, document, 'utf8');
|
|
60
|
+
const trace = authoredGoalTrace(path, document, archived);
|
|
61
|
+
debug.log('goal-author', 'goal-authored', { ...ids, ...trace });
|
|
62
|
+
if (ids.runId) appendRunLedgerEntry({ runId: ids.runId, event: 'goal-authored', data: { ...trace, ...(ids.authorRunId ? { authorRunId: ids.authorRunId } : {}) } }, ledgerDir);
|
|
63
|
+
return trace;
|
|
64
|
+
}
|
package/src/self-dev/dev-cli.ts
CHANGED
|
@@ -43,6 +43,7 @@ import { observeDeliverables, type DeliverableObservationResult, type Deliverabl
|
|
|
43
43
|
import { debug } from '../debug/log.js';
|
|
44
44
|
import { getUserConfig, type UserConfig } from '../user-config.js';
|
|
45
45
|
import { resolveChildLlmPreference, type ChildLlmPreferenceInput, type ResolvedChildLlmPreference } from '../self-implement/child-llm-preference.js';
|
|
46
|
+
import { applyLaunchOverloadFailover, codexProviderNamed } from '../oauth/overload-failover-launch.js';
|
|
46
47
|
import { readCachedGrokQuota } from '../oauth/codex-account-store.js';
|
|
47
48
|
import { queryAbandonedDraftPrs, type AbandonedDraftPr } from '../cli/logs-abandoned-draft-prs.js';
|
|
48
49
|
import { branchLineageSlug } from '../cli/pr-lineage.js';
|
|
@@ -1631,6 +1632,18 @@ function resolveChildLlmFromParts(
|
|
|
1631
1632
|
return undefined;
|
|
1632
1633
|
}
|
|
1633
1634
|
|
|
1635
|
+
/** Pinned `tools.selfImplement.childLlm` naming codex. Fallback-chain codex is not pinned. */
|
|
1636
|
+
function childLlmCodexPinned(flagProvider: string | undefined): boolean {
|
|
1637
|
+
if (flagProvider !== undefined) return false;
|
|
1638
|
+
try {
|
|
1639
|
+
const preference = resolveChildLlmPreference(getUserConfig());
|
|
1640
|
+
const provider = preference.chain[0]?.provider;
|
|
1641
|
+
return preference.mode === 'pinned' && preference.source.chain === 'pinned' && codexProviderNamed(provider);
|
|
1642
|
+
} catch {
|
|
1643
|
+
return false;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1634
1647
|
export function buildChildLlmSelection(
|
|
1635
1648
|
opts: Pick<DevCliOpts, 'childLlmProvider' | 'childLlmModel' | 'childLlmEffort'> & {
|
|
1636
1649
|
/** 발사 인자가 있을 때 관측용 선호를 읽는다. 없으면 getUserConfig. 기존 두 인자 시그니처는 그대로다. */
|
|
@@ -1967,7 +1980,12 @@ export function buildDevCliSpec(
|
|
|
1967
1980
|
}
|
|
1968
1981
|
|
|
1969
1982
|
if (path === 'self-mission') {
|
|
1970
|
-
const
|
|
1983
|
+
const builtChild = buildChildLlmSelection({ ...opts, readPreference: () => getUserConfig() });
|
|
1984
|
+
const childLlm = applyLaunchOverloadFailover(builtChild, {
|
|
1985
|
+
provider: opts.childLlmProvider,
|
|
1986
|
+
model: opts.childLlmModel,
|
|
1987
|
+
codexPinned: childLlmCodexPinned(opts.childLlmProvider),
|
|
1988
|
+
});
|
|
1971
1989
|
// 잔량 조회(약 3초)는 한 발사에 한 번만 — 자식·부모가 같은 값을 쓴다.
|
|
1972
1990
|
let grokQuotaOnce: ReturnType<typeof readCachedGrokQuota> | undefined;
|
|
1973
1991
|
const readGrokQuotaOnce = () => (grokQuotaOnce ??= readGrokQuota());
|
|
@@ -1863,9 +1863,9 @@ async function observeDevTaskDispatch(spec: DevPipelineSpec, plan: ResolvedDevPl
|
|
|
1863
1863
|
}
|
|
1864
1864
|
}
|
|
1865
1865
|
|
|
1866
|
-
async function inspectReleasePathBeforeMerge(seams: SelfImplementSeams, number: number, cwd: string): Promise<string | undefined> {
|
|
1866
|
+
async function inspectReleasePathBeforeMerge(seams: SelfImplementSeams, number: number, cwd: string, base?: string): Promise<string | undefined> {
|
|
1867
1867
|
if (!seams.readPrFiles) throw new Error('release-path inspection unavailable — automatic merge refused');
|
|
1868
|
-
const files = await seams.readPrFiles({ number, cwd });
|
|
1868
|
+
const files = await seams.readPrFiles({ number, cwd, ...(base ? { base } : {}) });
|
|
1869
1869
|
if (!Array.isArray(files) || !files.every((path) => typeof path === 'string')) throw new Error('invalid PR file list — automatic merge refused');
|
|
1870
1870
|
const path = releasePathHold(files);
|
|
1871
1871
|
if (!path) return undefined;
|
|
@@ -2107,10 +2107,11 @@ async function runDevPipelineDispatch(
|
|
|
2107
2107
|
...assembledSeams,
|
|
2108
2108
|
...(assembledSeams.mergePr ? { mergePr: async (input) => {
|
|
2109
2109
|
let path: string | undefined;
|
|
2110
|
-
try { path = await inspectReleasePathBeforeMerge(assembledSeams, input.number, input.cwd); }
|
|
2110
|
+
try { path = await inspectReleasePathBeforeMerge(assembledSeams, input.number, input.cwd, plan.base); }
|
|
2111
2111
|
catch (error) {
|
|
2112
|
-
|
|
2113
|
-
|
|
2112
|
+
const rateLimited = error instanceof Error && (error as { rateLimited?: boolean }).rateLimited === true;
|
|
2113
|
+
debug.log('self-dev.merge', 'release-path-inspection-failed', { number: input.number, error: String(error), ...(rateLimited ? { rateLimit: true } : {}) });
|
|
2114
|
+
return { merged: false, detail: rateLimited ? `automatic merge refused: rate-limit: ${String(error)}` : `automatic merge refused: ${String(error)}` };
|
|
2114
2115
|
}
|
|
2115
2116
|
if (path) return { merged: false, detail: `OP approval required: ${path}` };
|
|
2116
2117
|
return assembledSeams.mergePr!(input);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findNativeTool, isNativeToolModelExposed } from '../native-tool-catalog.js';
|
|
2
2
|
|
|
3
|
-
export type EntranceStatus = 'live' | 'retired';
|
|
3
|
+
export type EntranceStatus = 'live' | 'retired' | 'closed';
|
|
4
4
|
|
|
5
5
|
export type EntranceStampability = 'stampable' | 'structurally-unstampable' | 'unknown';
|
|
6
6
|
|
|
@@ -181,12 +181,14 @@ const ENTRANCE_DECLARATIONS = [
|
|
|
181
181
|
// `dev --ask` 와 ***같은*** `runAskLaunchFlow` 를 탄다. 두 문의 차이는 `entrance` 태그뿐이다.
|
|
182
182
|
// ⇒ 판정값이 `'verified' | 'unknown'` 둘뿐이라 「구조적 부재」를 적을 칸이 없다. `unknown` 으로 둔다.
|
|
183
183
|
// ⛔ 그러니 이 `unknown` 을 「미완」으로 읽지 마라 — 그 구분은 이 주석이 canonical 이다.
|
|
184
|
-
|
|
184
|
+
// OLD-DOOR-CLOSE — a direct `dev --ask` from a terminal or seat session refuses.
|
|
185
|
+
// Harness-internal calls still pass, marked with the ONEDOOR-1 entrance stamp.
|
|
186
|
+
{ id: 'cli-dev-ask', surface: 'cli', status: 'closed', verification: { actualMission: 'verified', legacyParity: 'unknown' } },
|
|
185
187
|
// `elanous drive` 는 `elanous dev` 의 Commander alias 로 살아 있고, buildDriveAliasDevSpec 이 entrance 를
|
|
186
188
|
// `cli-drive` 로 넘기며 completion 을 `worktree-only` 로 못 박는다. 그래서 별도 무인 권한 축이 아니다.
|
|
187
189
|
{ id: 'cli-drive', surface: 'cli', status: 'live' },
|
|
188
|
-
{ id: 'cli-self-implement', surface: 'cli', status: '
|
|
189
|
-
{ id: 'cli-self-orchestrate', surface: 'cli', status: '
|
|
190
|
+
{ id: 'cli-self-implement', surface: 'cli', status: 'closed' },
|
|
191
|
+
{ id: 'cli-self-orchestrate', surface: 'cli', status: 'closed' },
|
|
190
192
|
// ⭐ 2026-08-22 · 🅣 — ***사람이 «돌려 보고» 적은 판정***이다(⛔ 도구가 추측한 값이 아니다).
|
|
191
193
|
// actualMission: 그 입구로 실제 골을 «끝까지» 돌렸다 — 17발 · 자동 병합 5 · 회수 착지 7.
|
|
192
194
|
// 📏 원장 각인이 그것을 말한다: `"entrance":"cli-harness-ask"` (아침엔 0건이었다).
|
|
@@ -331,6 +333,7 @@ export function summarizeEntrances(registry: readonly EntranceDeclaration[] = EN
|
|
|
331
333
|
readonly total: number;
|
|
332
334
|
readonly live: number;
|
|
333
335
|
readonly retired: number;
|
|
336
|
+
readonly closed: number;
|
|
334
337
|
readonly bySurface: ReadonlyArray<{ surface: EntranceSurface; total: number; retired: number }>;
|
|
335
338
|
} {
|
|
336
339
|
const surfaces = [...new Set(registry.map((e) => e.surface))];
|
|
@@ -338,6 +341,7 @@ export function summarizeEntrances(registry: readonly EntranceDeclaration[] = EN
|
|
|
338
341
|
total: registry.length,
|
|
339
342
|
live: registry.filter((e) => e.status === 'live').length,
|
|
340
343
|
retired: registry.filter((e) => e.status === 'retired').length,
|
|
344
|
+
closed: registry.filter((e) => e.status === 'closed').length,
|
|
341
345
|
bySurface: surfaces.map((surface) => ({
|
|
342
346
|
surface,
|
|
343
347
|
total: registry.filter((e) => e.surface === surface).length,
|
|
@@ -350,12 +354,12 @@ export function summarizeEntrances(registry: readonly EntranceDeclaration[] = EN
|
|
|
350
354
|
export function renderLaunchEntrances(registry: readonly EntranceDeclaration[] = ENTRANCE_REGISTRY): string {
|
|
351
355
|
const summary = summarizeEntrances(registry);
|
|
352
356
|
const rows = listEntrancesWithModelExposure(registry)
|
|
353
|
-
.map((e) => ` ${e.status === 'retired' ? '🪦' : '✅'} ${e.surface.padEnd(7)} ${e.id} (${e.stampability}) verification=actualMission:${e.verification.actualMission},legacyParity:${e.verification.legacyParity} imprintEvidence=${e.imprintEvidence} evidenceSource=${e.stampabilityEvidenceSource} evidenceSourceFilePath=${e.evidenceSourceFilePath ?? 'missing'} modelExposed=${e.modelExposed ?? 'missing'}`);
|
|
357
|
+
.map((e) => ` ${e.status === 'retired' ? '🪦' : e.status === 'closed' ? '닫힘' : '✅'} ${e.surface.padEnd(7)} ${e.id} (${e.stampability}) verification=actualMission:${e.verification.actualMission},legacyParity:${e.verification.legacyParity} imprintEvidence=${e.imprintEvidence} evidenceSource=${e.stampabilityEvidenceSource} evidenceSourceFilePath=${e.evidenceSourceFilePath ?? 'missing'} modelExposed=${e.modelExposed ?? 'missing'}`);
|
|
354
358
|
const surfaces = summary.bySurface
|
|
355
359
|
.map((s) => `${s.surface}=${s.total}${s.retired > 0 ? `(은퇴 ${s.retired})` : ''}`)
|
|
356
360
|
.join(' · ');
|
|
357
361
|
return [
|
|
358
|
-
`launch entrances: ${summary.total} (live ${summary.live} · retired ${summary.retired})`,
|
|
362
|
+
`launch entrances: ${summary.total} (live ${summary.live} · retired ${summary.retired} · closed ${summary.closed})`,
|
|
359
363
|
` 표면별: ${surfaces}`,
|
|
360
364
|
...rows,
|
|
361
365
|
].join('\n');
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OLD-DOOR-CLOSE — the three outside doors refuse a direct call.
|
|
3
|
+
*
|
|
4
|
+
* `elanous dev --ask`, `elanous self implement`, and `elanous self orchestrate`
|
|
5
|
+
* stay callable from inside the harness. The harness marks those calls with
|
|
6
|
+
* the same stamp ONEDOOR-1 uses for a door (`ELANOUS_HARNESS_ENTRANCE`) or with
|
|
7
|
+
* the explicit internal flag `--harness-internal`. A terminal or seat session
|
|
8
|
+
* carries neither, so it exits non-zero and is told where to go.
|
|
9
|
+
*/
|
|
10
|
+
import type { LaunchDoor } from '../harness/launch-stamp.js';
|
|
11
|
+
|
|
12
|
+
export const OLD_DOORS = ['dev-ask', 'self-implement', 'self-orchestrate'] as const;
|
|
13
|
+
export type OldDoor = (typeof OLD_DOORS)[number];
|
|
14
|
+
|
|
15
|
+
/** Same env ONEDOOR-1 already stamps onto a harness launch. */
|
|
16
|
+
export const OLD_DOOR_STAMP_ENV = 'ELANOUS_HARNESS_ENTRANCE';
|
|
17
|
+
/** Same meaning as the env, for a caller that can pass an argument but not an env. */
|
|
18
|
+
export const OLD_DOOR_STAMP_FLAG = '--harness-internal';
|
|
19
|
+
|
|
20
|
+
const STAMP_BY_DOOR: Readonly<Record<OldDoor, readonly string[]>> = {
|
|
21
|
+
'dev-ask': ['dev-ask', 'cli-dev-ask', 'cli-drive', 'harness-say', 'cli-harness-say', 'harness-ask', 'cli-harness-ask', 'queue-tick', 'agent-mission', 'daemon-tool'],
|
|
22
|
+
'self-implement': ['self-implement', 'cli-self-implement', 'nl-self-implement', 'daemon-self-implement', 'daemon-tool', 'harness-say', 'cli-harness-say', 'harness-ask', 'cli-harness-ask', 'queue-tick', 'agent-mission'],
|
|
23
|
+
'self-orchestrate': ['self-orchestrate', 'cli-self-orchestrate', 'nl-self-orchestrate', 'cli-harness-orchestrate', 'harness-say', 'cli-harness-say', 'harness-ask', 'cli-harness-ask', 'queue-tick', 'agent-mission', 'daemon-tool'],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export interface OldDoorRefusal {
|
|
27
|
+
readonly door: OldDoor;
|
|
28
|
+
readonly caller: 'outside';
|
|
29
|
+
readonly exitCode: 1;
|
|
30
|
+
readonly message: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function oldDoorStampAccepted(door: OldDoor, stamp: string | undefined | null): boolean {
|
|
34
|
+
const value = stamp?.trim();
|
|
35
|
+
if (!value) return false;
|
|
36
|
+
return (STAMP_BY_DOOR[door] as readonly string[]).includes(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A harness-internal call carries the stamp in the environment or on the argv. Anything else is outside. */
|
|
40
|
+
export function isOldDoorInternalCall(
|
|
41
|
+
door: OldDoor,
|
|
42
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
43
|
+
argv: readonly string[] = process.argv,
|
|
44
|
+
): boolean {
|
|
45
|
+
if (argv.includes(OLD_DOOR_STAMP_FLAG)) return true;
|
|
46
|
+
return oldDoorStampAccepted(door, env[OLD_DOOR_STAMP_ENV]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Env a harness parent sets so the child door stays open. */
|
|
50
|
+
export function oldDoorInternalEnv(door: LaunchDoor | OldDoor): Record<string, string> {
|
|
51
|
+
return { [OLD_DOOR_STAMP_ENV]: door };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const REPLACEMENT: Readonly<Record<OldDoor, string>> = {
|
|
55
|
+
'dev-ask': 'elanous harness ask <goal.md>',
|
|
56
|
+
'self-implement': 'elanous harness say "<sentence>"',
|
|
57
|
+
'self-orchestrate': 'elanous harness say "<sentence>"',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const DOOR_LABEL: Readonly<Record<OldDoor, string>> = {
|
|
61
|
+
'dev-ask': 'elanous dev --ask',
|
|
62
|
+
'self-implement': 'elanous self implement',
|
|
63
|
+
'self-orchestrate': 'elanous self orchestrate',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** One line: the closed door, the harness door to use, and a command of the same meaning. */
|
|
67
|
+
export function oldDoorRefusalMessage(door: OldDoor): string {
|
|
68
|
+
return `${DOOR_LABEL[door]} 는 닫혔습니다 — harness say / harness ask 로. 예: ${REPLACEMENT[door]}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function refuseOldDoor(door: OldDoor): OldDoorRefusal {
|
|
72
|
+
return { door, caller: 'outside', exitCode: 1, message: oldDoorRefusalMessage(door) };
|
|
73
|
+
}
|
|
@@ -28,6 +28,7 @@ import type { RunIdSource } from '../harness/harness-space.js';
|
|
|
28
28
|
import { withFileLockSync } from '../storage/file-lock.js';
|
|
29
29
|
import type { SelfDevJobResult, SelfDevGoal } from './orchestrate.js';
|
|
30
30
|
import type { SupervisorStopReason } from './run-supervisor.js';
|
|
31
|
+
import type { SupervisorNext } from './supervisor-verdict-edges.js';
|
|
31
32
|
import { loadMirroredRunRecord, mirrorRunRecord } from './run-record-mirror.js';
|
|
32
33
|
|
|
33
34
|
export interface SelfDevRunParticipant {
|
|
@@ -92,6 +93,8 @@ export interface SelfDevRunState {
|
|
|
92
93
|
parkedResolution?: SelfDevRunResolution;
|
|
93
94
|
/** The closed supervisor termination reason, persisted independently from per-goal results. */
|
|
94
95
|
supervisorStopReason?: SupervisorStopReason;
|
|
96
|
+
/** Named next step at supervisor termination; legacy checkpoints omit it. */
|
|
97
|
+
next?: SupervisorNext;
|
|
95
98
|
/** ★ C(2026-07-21·HITL 정황 품질) — 이 run 을 구동하는 오케스트레이터 프로세스 pid. 살아있으면
|
|
96
99
|
* non-terminal goal 은 **실행중(running)** 이지 막힌(interrupted) 게 아니다. 죽었으면(오케스트레이터
|
|
97
100
|
* killed) 진짜 interrupted. isPidAlive 로 구분해 라이브 잡을 parked/repair-signals 에서 제외. */
|
|
@@ -311,13 +314,14 @@ export function recordSelfDevRunSupervisorStop(
|
|
|
311
314
|
runId: string,
|
|
312
315
|
supervisorStopReason: SupervisorStopReason,
|
|
313
316
|
dir = selfDevRunsDir(),
|
|
317
|
+
next?: SupervisorNext,
|
|
314
318
|
): SupervisorStopPersistenceOutcome {
|
|
315
319
|
try {
|
|
316
320
|
if (!existsSync(dir)) return { outcome: 'missing-directory' };
|
|
317
321
|
return withFileLockSync(join(dir, `${runId}.lock`), () => {
|
|
318
322
|
const state = loadSelfDevRunFromPath(runPath(runId, dir));
|
|
319
323
|
if (!state) return { outcome: 'missing-record' };
|
|
320
|
-
writeSelfDevRun({ ...state, updatedAt: Date.now(), supervisorStopReason }, dir);
|
|
324
|
+
writeSelfDevRun({ ...state, updatedAt: Date.now(), supervisorStopReason, ...(next === undefined ? {} : { next }) }, dir);
|
|
321
325
|
return { outcome: 'persisted' };
|
|
322
326
|
});
|
|
323
327
|
} catch {
|
|
@@ -6,6 +6,7 @@ import type { SelfDevJobResult } from './orchestrate.js';
|
|
|
6
6
|
import { recordSelfDevRunSupervisorStop, selfDevRunsDir } from './run-store.js';
|
|
7
7
|
import { debug } from '../debug/log.js';
|
|
8
8
|
import { sweepFrozenMerges } from '../self-implement/frozen-merges.js';
|
|
9
|
+
import { routeSupervisorVerdict, type SupervisorNext } from './supervisor-verdict-edges.js';
|
|
9
10
|
|
|
10
11
|
export interface SupervisorRound {
|
|
11
12
|
round: number;
|
|
@@ -186,6 +187,7 @@ function formatGoalPlanRevisionObservation(results: readonly SelfDevJobResult[])
|
|
|
186
187
|
export type SupervisorJobResult = SelfDevJobResult & {
|
|
187
188
|
reviewReason?: string;
|
|
188
189
|
salvage?: 'launched' | 'parked';
|
|
190
|
+
next?: SupervisorNext;
|
|
189
191
|
};
|
|
190
192
|
|
|
191
193
|
export function decideNextRun(input: {
|
|
@@ -592,9 +594,13 @@ export async function superviseRun(opts: SuperviseRunOptions): Promise<Superviso
|
|
|
592
594
|
} catch { /* fail-open */ }
|
|
593
595
|
|
|
594
596
|
if (decision.action === 'stop') {
|
|
597
|
+
const reason = decision.stopReason ?? 'unregistered-stop';
|
|
598
|
+
const next = routeSupervisorVerdict(reason, results).next;
|
|
599
|
+
try { debug.log('self-dev.supervisor', 'verdict-edge', { runId, reason, next }); } catch { /* observation must not interrupt supervision */ }
|
|
600
|
+
results = results.map((result) => ({ ...result, next }));
|
|
595
601
|
if (runId && decision.stopReason) {
|
|
596
602
|
const storage = resolveSupervisorStopStorage(opts.runStore);
|
|
597
|
-
const persistence = recordSelfDevRunSupervisorStop(runId, decision.stopReason, storage.path);
|
|
603
|
+
const persistence = recordSelfDevRunSupervisorStop(runId, decision.stopReason, storage.path, next);
|
|
598
604
|
const storageObservation = {
|
|
599
605
|
storagePath: storage.path,
|
|
600
606
|
storageSource: storage.source,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SelfDevJobResult } from './orchestrate.js';
|
|
2
|
+
import type { SupervisorStopReason } from './run-supervisor.js';
|
|
3
|
+
|
|
4
|
+
export type SupervisorNext = 'harvest' | 'scope-decompose' | 'self-review' | 'human-gate' | 'proposal';
|
|
5
|
+
export type SupervisorVerdictEdge = { readonly meaning: string; readonly next: SupervisorNext };
|
|
6
|
+
|
|
7
|
+
// 목표 규칙: 사람 관문은 결제·공개·자격·비가역 결정에만. 지금 max-rounds·provider-exhausted·step-timeout 이 human-gate 인 것은
|
|
8
|
+
// 그 규칙의 예외로 «그대로» 둔 값이다(시험에 고정 — 바꾸면 보인다).
|
|
9
|
+
export const SUPERVISOR_VERDICT_EDGES = {
|
|
10
|
+
converged: { meaning: 'run converged', next: 'harvest' },
|
|
11
|
+
'human-stopped': { meaning: 'human stopped the run', next: 'human-gate' },
|
|
12
|
+
'parent-signals-red': { meaning: 'parent decision signals are red', next: 'human-gate' },
|
|
13
|
+
'needs-human': { meaning: 'unresolved human or harvest decision', next: 'human-gate' },
|
|
14
|
+
'no-actionable-work': { meaning: 'no actionable work remains', next: 'self-review' },
|
|
15
|
+
'harvestable-awaiting-human': { meaning: 'implementation awaits harvest', next: 'harvest' },
|
|
16
|
+
'handed-off-to-salvage': { meaning: 'salvage already owns the work', next: 'harvest' },
|
|
17
|
+
'max-rounds': { meaning: 'round budget exhausted', next: 'human-gate' },
|
|
18
|
+
'no-progress': { meaning: 'run stalled', next: 'scope-decompose' },
|
|
19
|
+
'provider-exhausted': { meaning: 'provider quota exhausted', next: 'human-gate' },
|
|
20
|
+
'step-timeout': { meaning: 'step budget exhausted', next: 'human-gate' },
|
|
21
|
+
'decomposable-no-progress': { meaning: 'stalled with a decomposition proposal', next: 'scope-decompose' },
|
|
22
|
+
'review-unobserved': { meaning: 'review was not observed', next: 'self-review' },
|
|
23
|
+
'deliverable-unobserved': { meaning: 'deliverable was not observed', next: 'self-review' },
|
|
24
|
+
'deliverable-merged': { meaning: 'deliverable is merged', next: 'harvest' },
|
|
25
|
+
} as const satisfies Record<SupervisorStopReason, SupervisorVerdictEdge>;
|
|
26
|
+
|
|
27
|
+
const HUMAN_GATE_MERGE_REASONS: ReadonlySet<string> = new Set(['decision-signal-red', 'signal-incomplete', 'parent-unlanded', 'human-gate']);
|
|
28
|
+
|
|
29
|
+
/** Unknown stop vocabularies are proposals, never silently treated as approved edges. */
|
|
30
|
+
export function routeSupervisorVerdict(
|
|
31
|
+
reason: string,
|
|
32
|
+
results: readonly Partial<Pick<SelfDevJobResult, 'status' | 'stage' | 'merged' | 'prNumber' | 'prUrl' | 'blockReason' | 'mergeReason'>>[] = [],
|
|
33
|
+
): SupervisorVerdictEdge {
|
|
34
|
+
const edge = Object.hasOwn(SUPERVISOR_VERDICT_EDGES, reason)
|
|
35
|
+
? SUPERVISOR_VERDICT_EDGES[reason as SupervisorStopReason]
|
|
36
|
+
: undefined;
|
|
37
|
+
if (!edge) return { meaning: 'unregistered supervisor stop reason', next: 'proposal' };
|
|
38
|
+
if (reason !== 'needs-human') return edge;
|
|
39
|
+
if (results.some((result) => result.blockReason === 'parent-unlanded')) return edge;
|
|
40
|
+
// A human-gate reason on ANY result in the run keeps the whole run at the human gate.
|
|
41
|
+
if (results.some((result) => HUMAN_GATE_MERGE_REASONS.has(String(result.mergeReason)))) return edge;
|
|
42
|
+
const openPrs = results.filter((result) => result.status === 'done' && result.stage === 'pr-opened'
|
|
43
|
+
&& result.merged !== true && (result.prNumber !== undefined || Boolean(result.prUrl)));
|
|
44
|
+
if (openPrs.length === 0) return edge;
|
|
45
|
+
return { meaning: 'open PR ready for harvest', next: 'harvest' };
|
|
46
|
+
}
|