elanous 0.2.27 → 0.2.28
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/{1454-a9c338f5bb556f42.js → 1454-29d1d773d5996a49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{599-a914cc0468f56143.js → 599-56f2c0a5cc4a7295.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-07110da72c45e68f.js → page-24453f6a302816b4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-d2d76d4a7eae91bd.js → page-6c131d30bb1cf871.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-fa46d4588e8442c2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-e5a9302c105725a3.js → page-dc0772b11861af51.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/{page-6a16a48d1aa6e91f.js → page-256ffd365d32e100.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-39f82acf619cca23.js → page-4c741eb760f2f77c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-7c2c8f81b185f9c0.js → page-e9ba98f5f1440a21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/{page-ae7aff07e32676bb.js → page-dafc901bb1b72b5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-482c60c1bc540d0a.js → page-2f6f303fa114ec24.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{layout-7cb996c1aa08b6f5.js → layout-1634081c5272006c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live/{page-623e08fe4477d606.js → page-ced0bcfc6542b3fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-db460cd8aecb8490.js → page-bb1f05cd51c38944.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/{page-ff27902d0b11ef4f.js → page-646b50f63b6fe732.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-1917ea87ea71ab6b.js → page-f736324afa2117c1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-25a302273b054fd7.js → page-6f131b51193a36f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-670510eda8b9443f.js → not-found-435f5e2faf02bc01.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-4bb7556e2e97a750.js → page-8966452228753c5e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/{page-4eb96fc7241c2456.js → page-66a67eb19ebd976b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-0d64ff212dc55d03.js → page-c71267e7681da982.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-7f096248993fc2d4.js → page-a21d1e1797172692.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-e47fc72049149a38.js → page-cb249e81ed339318.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-f7d808e31e005895.js → page-781cfc5114e097da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-5c2b24b5496dad73.js → page-478157214db6a023.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-76cdb531668b5191.js → page-86141f12cf090b7f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/{page-dab163b338e3b966.js → page-979d318a534e92da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/{page-0260ffc7eda50db1.js → page-21050928a697ed7a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-99c4e6c7345a9156.js → page-601fb77340e63c9a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +13 -13
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +13 -13
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +13 -13
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +13 -13
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +13 -13
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +13 -13
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +13 -13
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +13 -13
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +13 -13
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +13 -13
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +13 -13
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +13 -13
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +13 -13
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +13 -13
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +13 -13
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +13 -13
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +13 -13
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +13 -13
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +13 -13
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +13 -13
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +13 -13
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +13 -13
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +13 -13
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +13 -13
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +13 -13
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +13 -13
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +13 -13
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +13 -13
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +14 -14
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +13 -13
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +13 -13
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +13 -13
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +13 -13
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +13 -13
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +13 -13
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +13 -13
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +13 -13
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +13 -13
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +13 -13
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +13 -13
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +13 -13
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +13 -13
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +13 -13
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +13 -13
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +13 -13
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +13 -13
- package/graphs/implement-loop.yaml +38 -1
- package/graphs/steward/recipes.yaml +6 -0
- package/graphs/steward/release-day.yaml +23 -0
- package/graphs/steward/steward.yaml +9 -1
- package/graphs/work/code-pr.yaml +23 -0
- package/package.json +1 -1
- package/scripts/browser-observe-cycle.ts +76 -2
- package/scripts/ci-typecheck-changed.ts +50 -17
- package/scripts/detect-test-interference.ts +31 -1
- package/scripts/release-loop/docs-node.ts +51 -22
- package/scripts/release-loop/gate-node.ts +37 -4
- package/scripts/release-loop/node-verdict.ts +3 -1
- package/scripts/release-loop/publish-node.ts +3 -0
- package/scripts/release-loop/tui-node-checks.ts +5 -2
- package/scripts/skills/public-check.ts +5 -2
- package/scripts/test-deterministic.ts +520 -37
- package/scripts/ux-sim.ts +7 -1
- package/scripts/verify-kpack6-live.ts +230 -0
- package/src/acp/codex-plugins.ts +17 -0
- package/src/agent/task-notification.ts +2 -1
- package/src/agent-mission/in-agent-plugin.ts +8 -3
- package/src/agent-substrate/self-review-cli.ts +34 -10
- package/src/briefing/brief-items.ts +151 -35
- package/src/budget/llm-cost.ts +25 -2
- package/src/budget/usage-outcomes.ts +32 -0
- package/src/claims/claims-ledger.ts +23 -0
- package/src/claims/claims-render.ts +22 -2
- package/src/cli/brief-cli.ts +131 -10
- package/src/cli/claims-cli.ts +24 -4
- package/src/cli/msg-cli.ts +165 -9
- package/src/cli/plugin-cli.ts +11 -3
- package/src/cli/pr-cli.ts +80 -18
- package/src/cli/pr-land-refusal.ts +20 -0
- package/src/cli/release-cli.ts +2 -0
- package/src/cli/rfc-cli.ts +24 -0
- package/src/cli/tailscale-serve.ts +5 -8
- package/src/cli/tasks-cli.ts +393 -26
- package/src/cli/usage-cli.ts +9 -4
- package/src/dashboard/first-screen-band.ts +63 -13
- package/src/dashboard/index.ts +8 -3
- package/src/dashboard/skill-detection-runtime.ts +24 -4
- package/src/domains/morning-report.ts +3 -1
- package/src/github/pr-labels.ts +10 -4
- package/src/graph-runner/runner.ts +101 -14
- package/src/harness/harness-clean.ts +21 -3
- package/src/harness/harness-cli-command.ts +22 -6
- package/src/harness/harness-pod-dispatch.ts +11 -4
- package/src/hq/seats.ts +17 -3
- package/src/index.ts +34 -5
- package/src/intelligence-map/model-bench-scores.ts +102 -0
- package/src/loops/orchestrator/inbox.ts +73 -0
- package/src/loops/orchestrator/resync-shadow.ts +100 -12
- package/src/loops/orchestrator/tick.ts +73 -2
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/msg/msg-sse-server.ts +141 -0
- package/src/msg/msg-store.ts +84 -14
- package/src/patents/ledger.ts +128 -0
- package/src/plugins/install/market-fetch.ts +32 -1
- package/src/pod-lease/admission.ts +116 -41
- package/src/release-loop/checklist.ts +11 -0
- package/src/release-loop/merged-pr-checklist.ts +24 -5
- package/src/release-loop/rubric.ts +70 -0
- package/src/rfc-registry/registry.ts +88 -0
- package/src/seat-dispatch/seat-request-ledger.ts +4 -0
- package/src/seat-loop/knowhow-lint.ts +233 -0
- package/src/seat-loop/seat-pack.ts +16 -4
- package/src/seat-loop/traffic-signal.ts +7 -0
- package/src/self-dev/ask-launch-flow.ts +48 -8
- package/src/self-dev/ask-path-candidates.ts +69 -14
- package/src/self-dev/decompose-proposal.ts +43 -1
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/launch-preflight-text.ts +5 -1
- package/src/self-dev/launch-preflight.ts +143 -10
- package/src/self-implement/gate-cli.ts +6 -2
- package/src/self-implement/goal-author.ts +2 -1
- package/src/self-implement/goal-new-paths.ts +4 -5
- package/src/self-implement/graph-authority.ts +17 -3
- package/src/self-implement/graph-yaml.ts +15 -7
- package/src/self-implement/headless-elanous-driver.ts +16 -1
- package/src/self-implement/host-regate.ts +44 -9
- package/src/self-implement/orchestrator.ts +3 -10
- package/src/self-implement/rework-policy.ts +80 -2
- package/src/self-implement/speed-claims.ts +145 -6
- package/src/skills/tools/persistent-grounding.ts +59 -4
- package/src/skills/tools/shell.ts +79 -1
- package/src/steward/rejudge-tick.ts +12 -1
- package/src/steward/release-day.ts +158 -0
- package/src/steward/resync-tick.ts +123 -0
- package/src/task-agent/actions.ts +1 -0
- package/src/task-agent/adopt-pr.ts +140 -0
- package/src/task-agent/board.ts +11 -1
- package/src/task-agent/card-evidence.ts +37 -5
- package/src/task-agent/cover.ts +84 -17
- package/src/task-agent/failure-notify.ts +61 -0
- package/src/task-agent/green-sweep.ts +170 -0
- package/src/task-agent/land-worktree.ts +52 -5
- package/src/task-agent/live-move-history.ts +1 -0
- package/src/task-agent/live-moves.ts +43 -12
- package/src/task-agent/parent-host.ts +1 -1
- package/src/task-agent/postland-card.ts +139 -0
- package/src/task-agent/rejudge-on-head.ts +106 -7
- package/src/task-agent/remote-rejudge-bind.ts +62 -0
- package/src/task-agent/repair-branch-cas.ts +182 -0
- package/src/task-agent/repair-cycle.ts +275 -0
- package/src/task-agent/repair-next-move.ts +31 -0
- package/src/task-agent/repair-review.ts +24 -0
- package/src/task-agent/repair-worker.ts +87 -0
- package/src/task-agent/review-result-capture.ts +2 -1
- package/src/task-agent/shadow.ts +13 -7
- package/src/task-agent/task-hand.ts +115 -6
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +96 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +70 -12
- package/src/telegram.ts +30 -1
- package/src/user-config.ts +8 -1
- package/src/ux-sim/fault-sqlite-busy.ts +50 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-a1ce306364f08da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-30007380f2e2a3c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-b93c04b5311c97ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-718a49e86bf25f9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-20662900d6b4b455.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f707a509515ac50c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-fcb06e305f515527.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-6acf5ec4e6c6d1af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-8397a5c6ca569bf4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d73c3f1e00d93986.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-65caacf54389081e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-77e04b4f8762c666.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-15c0a4095baddfba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-63e272a4cd3b6634.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e2b63345bba1a11f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-d376e0c83edc041a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d6db55fe2c04d128.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-87b88f551f421d8b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-08019efef111ed2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-980ce6fe36ad95eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-0ab42e0f05823013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ad9220422d20ba33.js +0 -1
- /package/apps/pwa/out/_next/static/{Ev2jivDMTSoEc-5rIXdcy → y1ltt7oCZxVpC6zVPhZ2O}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{Ev2jivDMTSoEc-5rIXdcy → y1ltt7oCZxVpC6zVPhZ2O}/_ssgManifest.js +0 -0
|
@@ -305,6 +305,7 @@ function registerHarnessAskSayOptions(command: Command): Command {
|
|
|
305
305
|
.addOption(new Option('--pod-memory <tier>', 'pod: 메모리 등급 — lite(2Gi · 문서·조사·네트워크 스킬 골 · OOM 이면 high 로 한 번 재시도) | standard(16Gi) | high(32Gi) · 없으면 골 문면 `Pod 메모리: <등급>` 한 줄 · 그것도 없으면 골이 apps/pwa/ 를 담을 때 high').choices(['lite', 'standard', 'high']))
|
|
306
306
|
.option('--after <goal-or-pr>', 'pod: 선행 — 이 골 ID(16자) 또는 PR(#N) 이 병합될 때까지 Pod 발사가 큐에서 이유와 함께 기다린다(병합 없이 닫히면 blocked) · 골 문면 `선행: #N` 한 줄과 같다 · 대상 파일만 겹치면 선행이 아니다(경고만)')
|
|
307
307
|
.option('--source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · `--substrate pod` 와 함께')
|
|
308
|
+
.option('--repair-commit-only <expected-head>', 'pod: 기존 PR head에서 수리한 커밋을 bundle로 반환(PR 생성 없음)')
|
|
308
309
|
.option('--bench <id[:sha]>', '벤치 팔 — base 를 bench/<id>/base 로 고정(없으면 sha·생략 시 origin/main 으로 만든다 · 있으면 sha 일치 확인 · 불일치 거부) · 팔 가지 bench/<id>/<arm> · PR 라벨 elanous:bench · PR 직전 main 동기화 생략 · 원장 elanous bench ls <id>');
|
|
309
310
|
}
|
|
310
311
|
|
|
@@ -397,7 +398,7 @@ function assertHarnessChildLlmModel(opts: HarnessAskSayChildLlmOptions): void {
|
|
|
397
398
|
}
|
|
398
399
|
|
|
399
400
|
/** Shared post-parse gate: validate child model before any ask/say early return (including `--dry-run`). */
|
|
400
|
-
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: 'lite' | 'standard' | 'high'; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; seat?: QueueSeat };
|
|
401
|
+
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: 'lite' | 'standard' | 'high'; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; repairCommitOnly?: string; seat?: QueueSeat };
|
|
401
402
|
function resolveLaunchSubstrate(opts: HarnessSubstrateOpts): ResolvedHarnessSubstrate {
|
|
402
403
|
const resolved = resolveHarnessSubstrate({ flag: opts, config: getUserConfig(), env: process.env });
|
|
403
404
|
debug.log('harness.substrate', 'resolved', resolved);
|
|
@@ -693,7 +694,7 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
|
|
|
693
694
|
const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(authorOnPod && entrance === 'cli-harness-say' ? { authorOnPod: true } : {}),
|
|
694
695
|
...(child.childLlmProvider?.trim() ? { childLlmProvider: child.childLlmProvider.trim() } : {}),
|
|
695
696
|
...(child.childLlmModel?.trim() ? { childLlmModel: child.childLlmModel.trim() } : {}),
|
|
696
|
-
...(child.childLlmEffort?.trim() ? { childLlmEffort: child.childLlmEffort.trim() } : {}), ...(authorOnPod && podAuthorGrade ? { authorGrade: podAuthorGrade.grade, authorGradeSource: podAuthorGrade.source } : {}), ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...((opts as HarnessAskSayChildLlmOptions).goalType ? { goalType: (opts as HarnessAskSayChildLlmOptions).goalType } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.seat ? { seat: o.seat } : {}) },
|
|
697
|
+
...(child.childLlmEffort?.trim() ? { childLlmEffort: child.childLlmEffort.trim() } : {}), ...(authorOnPod && podAuthorGrade ? { authorGrade: podAuthorGrade.grade, authorGradeSource: podAuthorGrade.source } : {}), ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...((opts as HarnessAskSayChildLlmOptions).goalType ? { goalType: (opts as HarnessAskSayChildLlmOptions).goalType } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.repairCommitOnly ? { repairCommitOnly: o.repairCommitOnly } : {}), ...(o.seat ? { seat: o.seat } : {}) },
|
|
697
698
|
{ onOutput: (text) => {
|
|
698
699
|
runId ??= harnessPodRunId(output + text);
|
|
699
700
|
output = (output + text).slice(-16_000);
|
|
@@ -894,6 +895,8 @@ async function dispatchHarnessAskSay(
|
|
|
894
895
|
if (isHarnessDryRun(opts)) {
|
|
895
896
|
resolveLaunchSubstrate(opts);
|
|
896
897
|
printHarnessLaunchDryRun(dryRunPreview);
|
|
898
|
+
const repair = opts as HarnessSubstrateOpts;
|
|
899
|
+
if (repair.repairCommitOnly) console.log(`[dry-run] repair forwarding: --pod-source ${repair.source} --repair-commit-only ${repair.repairCommitOnly} --no-auto-merge`);
|
|
897
900
|
return;
|
|
898
901
|
}
|
|
899
902
|
ensureJourneyKey();
|
|
@@ -939,7 +942,7 @@ async function dispatchHarnessAskSay(
|
|
|
939
942
|
['--goal-type', opts.goalType], ...(dryRunPreview.entrance === 'cli-harness-say' ? [['--author-grade', opts.authorGradeSource === 'flag' ? opts.authorGrade : undefined] as [string, string | undefined]] : []), ['--child-llm-provider', opts.childLlmProvider],
|
|
940
943
|
['--child-llm-model', opts.childLlmModel], ['--child-llm-effort', opts.childLlmEffort],
|
|
941
944
|
['--pod-pool', (opts as HarnessSubstrateOpts).podPool], ['--pod-memory', (opts as HarnessSubstrateOpts).podMemory],
|
|
942
|
-
['--after', (opts as HarnessSubstrateOpts).after], ['--source', (opts as HarnessSubstrateOpts).source],
|
|
945
|
+
['--after', (opts as HarnessSubstrateOpts).after], ['--source', (opts as HarnessSubstrateOpts).source], ['--repair-commit-only', (opts as HarnessSubstrateOpts).repairCommitOnly],
|
|
943
946
|
];
|
|
944
947
|
for (const [flag, value] of values) if (value !== undefined) flags.push(flag, value);
|
|
945
948
|
if ((opts as HarnessSubstrateOpts).source !== undefined && resolved.substrate !== 'pod') {
|
|
@@ -1013,8 +1016,9 @@ async function dispatchHarnessAskSay(
|
|
|
1013
1016
|
const previous = process.env.ELANOUS_HARNESS_SEAT;
|
|
1014
1017
|
if (stampedSeat) process.env.ELANOUS_HARNESS_SEAT = stampedSeat;
|
|
1015
1018
|
else delete process.env.ELANOUS_HARNESS_SEAT;
|
|
1016
|
-
//
|
|
1017
|
-
passJourneyNode('dispatch', { ...journey, outcome:
|
|
1019
|
+
// The source label selects the declared author or same-PR rework edge; substrate remains data for decompose.
|
|
1020
|
+
passJourneyNode('dispatch', { ...journey, outcome: (stampedOpts as HarnessSubstrateOpts).repairCommitOnly ? 'pr-source' : 'fresh',
|
|
1021
|
+
data: { substrate: resolved.substrate } });
|
|
1018
1022
|
const benchRow = bench ? recordBenchLaunch(bench, stampedOpts, resolved.substrate, dryRunPreview.entrance, benchDeps) : undefined;
|
|
1019
1023
|
try { await dispatch(resolved, stampedOpts); }
|
|
1020
1024
|
finally {
|
|
@@ -3342,6 +3346,11 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3342
3346
|
if (ask) {
|
|
3343
3347
|
registerHarnessAskSayOptions(harnessCmd.command('ask <goal-path>').description('골 문서 경로를 받아 구동한다'))
|
|
3344
3348
|
.action(async (goalPath: string, opts: HarnessAskSayChildLlmOptions & HarnessDryRunOpts) => {
|
|
3349
|
+
if ((opts as HarnessSubstrateOpts).repairCommitOnly !== undefined) {
|
|
3350
|
+
console.error('--repair-commit-only is supported only by harness say');
|
|
3351
|
+
process.exitCode = 2;
|
|
3352
|
+
return;
|
|
3353
|
+
}
|
|
3345
3354
|
await dispatchHarnessAskSay(
|
|
3346
3355
|
opts,
|
|
3347
3356
|
{
|
|
@@ -3370,6 +3379,13 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3370
3379
|
registerHarnessAskSayOptions(harnessCmd.command('say <sentence...>').description('문장을 받아 구동한다'))
|
|
3371
3380
|
.addOption(new Option('--author-grade <grade>', 'say 저작 등급 (full|lite)').choices(['full', 'lite']))
|
|
3372
3381
|
.action(async (sentence: string[], opts: HarnessAskSayChildLlmOptions & HarnessDryRunOpts) => {
|
|
3382
|
+
const repair = opts as HarnessSubstrateOpts;
|
|
3383
|
+
if (repair.repairCommitOnly !== undefined && (repair.substrate !== 'pod' || !/^pr:[1-9]\d*$/.test(repair.source ?? '')
|
|
3384
|
+
|| !/^[0-9a-f]{40}$/.test(repair.repairCommitOnly) || repair.autoMerge !== false || repair.target !== undefined)) {
|
|
3385
|
+
console.error('--repair-commit-only requires --substrate pod --source pr:N --no-auto-merge and a 40-hex expected head');
|
|
3386
|
+
process.exitCode = 2;
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3373
3389
|
const grade = resolveGoalAuthorGrade(opts.authorGrade, getUserConfig().harness?.authorGrade);
|
|
3374
3390
|
const podSource = process.env.ELANOUS_POD_AUTHOR_ON_POD === '1' && process.env.ELANOUS_POD_AUTHOR_GRADE === grade.grade
|
|
3375
3391
|
? process.env.ELANOUS_POD_AUTHOR_GRADE_SOURCE : undefined;
|
|
@@ -3390,7 +3406,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3390
3406
|
return Promise.resolve();
|
|
3391
3407
|
}
|
|
3392
3408
|
return resolved.substrate === 'pod'
|
|
3393
|
-
? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask, harnessAuthorOnPod())
|
|
3409
|
+
? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask, !(opts as HarnessSubstrateOpts).repairCommitOnly && harnessAuthorOnPod())
|
|
3394
3410
|
: (announceLocalChildProvider(stampedOpts), say(sentence, normalizeHarnessAskSayOptions(stampedOpts)));
|
|
3395
3411
|
},
|
|
3396
3412
|
deps.launchGate, queueDeps, immediateLaunch, queueDeps.launch ? undefined : immediateExit, deps.bench,
|
|
@@ -43,6 +43,8 @@ export interface HarnessPodDispatchInput {
|
|
|
43
43
|
readonly json?: boolean;
|
|
44
44
|
/** 사람이 고른 원천 spec — `commit:` · `pr:` · `worktree:` · `files:`. 검증은 발사 전. */
|
|
45
45
|
readonly source?: string;
|
|
46
|
+
/** Existing PR head for a commit-only repair. Requires source pr:N. */
|
|
47
|
+
readonly repairCommitOnly?: string;
|
|
46
48
|
/** `--child-llm-provider/--child-llm-model/--child-llm-effort` — carried to `self orchestrate` so the Pod child uses them (10-05 PODPROVIDER). */
|
|
47
49
|
readonly childLlmProvider?: string;
|
|
48
50
|
readonly childLlmModel?: string;
|
|
@@ -59,10 +61,11 @@ export function podOrchestrateArgs(input: HarnessPodDispatchInput, goalFile: str
|
|
|
59
61
|
'--substrate', 'pod',
|
|
60
62
|
...(input.podPool ? ['--pod-pool', input.podPool] : []),
|
|
61
63
|
// 하니스 기본(자동 병합)을 따른다 · 끄면 PR 까지 — 어느 쪽이든 Pod 가 사라져도 결과가 남는다.
|
|
62
|
-
...(input.autoMerge === false ? ['--open-pr'] : ['--auto-merge']),
|
|
63
|
-
...(input.base ? ['--base', input.base] : []),
|
|
64
|
+
...(input.repairCommitOnly ? [] : input.autoMerge === false ? ['--open-pr'] : ['--auto-merge']),
|
|
65
|
+
...(input.repairCommitOnly && input.source ? ['--base', `pr-${input.source.slice(3)}`] : input.base ? ['--base', input.base] : []),
|
|
64
66
|
...(input.json ? ['--json'] : []),
|
|
65
67
|
...(input.source ? ['--pod-source', input.source] : []),
|
|
68
|
+
...(input.repairCommitOnly ? ['--repair-commit-only', input.repairCommitOnly] : []),
|
|
66
69
|
...(input.childLlmProvider?.trim() ? ['--child-llm-provider', input.childLlmProvider.trim()] : []),
|
|
67
70
|
...(input.childLlmModel?.trim() ? ['--child-llm-model', input.childLlmModel.trim()] : []),
|
|
68
71
|
...(input.childLlmEffort?.trim() ? ['--child-llm-effort', input.childLlmEffort.trim()] : []),
|
|
@@ -85,6 +88,10 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
85
88
|
return 2;
|
|
86
89
|
}
|
|
87
90
|
}
|
|
91
|
+
if (input.repairCommitOnly && (!/^pr:[1-9]\d*$/.test(input.source ?? '') || !/^[0-9a-f]{40}$/.test(input.repairCommitOnly) || input.autoMerge === true)) {
|
|
92
|
+
debug.log('harness.substrate', 'repair-refused', { entrance: input.entrance, reason: 'requires pr source, 40-hex head, and no auto-merge' });
|
|
93
|
+
return 2;
|
|
94
|
+
}
|
|
88
95
|
const env = { ...process.env, ...oldDoorInternalEnv('self-orchestrate') };
|
|
89
96
|
// POD-OBS(10-06): 자식 orchestrate 는 트리 파생 우주에서 돈다 — Pod 원장 재방출을 «발사한 집»의 logs.db 에도 남기게 경로를 넘긴다.
|
|
90
97
|
env[POD_REEMIT_LOGS_DB_ENV] = logsDbPath();
|
|
@@ -146,7 +153,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
146
153
|
memoryLimit: podMemoryLimitFor(goalText, env).limit });
|
|
147
154
|
delete env.ELANOUS_POD_AFTER;
|
|
148
155
|
if (input.after) env.ELANOUS_POD_AFTER = input.after;
|
|
149
|
-
if (input.authorOnPod) env.ELANOUS_POD_AUTHOR_ON_POD = '1';
|
|
156
|
+
if (input.authorOnPod && !input.repairCommitOnly) env.ELANOUS_POD_AUTHOR_ON_POD = '1';
|
|
150
157
|
else delete env.ELANOUS_POD_AUTHOR_ON_POD;
|
|
151
158
|
if (input.authorOnPod && input.authorGrade) {
|
|
152
159
|
env.ELANOUS_POD_AUTHOR_GRADE = input.authorGrade;
|
|
@@ -157,7 +164,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
157
164
|
delete env.ELANOUS_POD_AUTHOR_GRADE;
|
|
158
165
|
delete env.ELANOUS_POD_AUTHOR_GRADE_SOURCE;
|
|
159
166
|
}
|
|
160
|
-
if (input.entrance === 'cli-harness-ask') {
|
|
167
|
+
if (input.entrance === 'cli-harness-ask' && !input.repairCommitOnly) {
|
|
161
168
|
const root = findGitDir(cwd)?.root;
|
|
162
169
|
const path = resolve(cwd, input.input);
|
|
163
170
|
const relativePath = root ? relative(realpathSync(root), realpathSync(path)) : '';
|
package/src/hq/seats.ts
CHANGED
|
@@ -278,6 +278,18 @@ export function hqInit(options: { root?: string; home?: string } = {}): { root:
|
|
|
278
278
|
return { root, created, cron };
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
// A skipped refresh leaves the seat looking idle to every other surface: one observation line carries the
|
|
282
|
+
// reason and how far the kept HEAD trails the fetched origin/main. Observation never changes the verdict
|
|
283
|
+
// (same rule as judgeLandedTip).
|
|
284
|
+
function observeRefreshSkipped(path: string, role: HqSeatRole, reason: 'dirty' | 'unlanded-head', head?: string): void {
|
|
285
|
+
try {
|
|
286
|
+
const tip = head ?? git(path, 'rev-parse', 'HEAD');
|
|
287
|
+
const behind = runGitCommand(path, ['rev-list', '--count', 'HEAD..refs/remotes/origin/main'], { encoding: 'utf8' });
|
|
288
|
+
const count = behind.status === 0 && /^\d+$/.test(behind.stdout.trim()) ? Number(behind.stdout.trim()) : null;
|
|
289
|
+
debug.log('hq.seat', 'refresh-skipped', { role, path, reason, head: tip, behind: count });
|
|
290
|
+
} catch { /* observation must not change the verdict */ }
|
|
291
|
+
}
|
|
292
|
+
|
|
281
293
|
export function hqSeat(value: string, options: { root?: string; refresh?: boolean } = {}): { path: string; outcome: 'created' | 'unchanged' | 'refreshed' | 'dirty' } {
|
|
282
294
|
const role = roleOf(value);
|
|
283
295
|
const root = resolve(options.root ?? hqRoot());
|
|
@@ -301,16 +313,18 @@ export function hqSeat(value: string, options: { root?: string; refresh?: boolea
|
|
|
301
313
|
const onBranch = runGitCommand(path, ['symbolic-ref', '--quiet', '--short', 'HEAD'], { encoding: 'utf8' });
|
|
302
314
|
if (onBranch.status === 0) throw new Error(`not a seat: ${path} is on branch ${onBranch.stdout.trim()}; refusing to touch it`);
|
|
303
315
|
// A dirty seat must be byte-for-byte untouched, including its detached HEAD.
|
|
304
|
-
|
|
316
|
+
// The cron line fetches the mirror before refreshing, so `behind` counts against the fetched origin/main.
|
|
317
|
+
if (options.refresh && !clean(path)) { observeRefreshSkipped(path, role, 'dirty'); return { path, outcome: 'dirty' }; }
|
|
305
318
|
if (!options.refresh) return { path, outcome: 'unchanged' };
|
|
306
319
|
git(repo, 'fetch', 'origin');
|
|
307
320
|
// Concurrent refreshes of one seat (cron and a person) serialize on the house lock; each re-checks first.
|
|
308
321
|
return withLedgerLock(root, () => {
|
|
309
322
|
assertRegisteredWorktree(repo, path);
|
|
310
323
|
if (runGitCommand(path, ['symbolic-ref', '--quiet', 'HEAD'], { encoding: 'utf8' }).status === 0) throw new Error(`not a seat: ${path} is on a branch; refusing to touch it`);
|
|
311
|
-
if (!clean(path)) return { path, outcome: 'dirty' as const };
|
|
324
|
+
if (!clean(path)) { observeRefreshSkipped(path, role, 'dirty'); return { path, outcome: 'dirty' as const }; }
|
|
312
325
|
// Commits made on the detached seat are not on origin/main; moving HEAD would orphan them. Treat as dirty.
|
|
313
|
-
|
|
326
|
+
const head = git(path, 'rev-parse', 'HEAD');
|
|
327
|
+
if (!mergedIntoMain(repo, head)) { observeRefreshSkipped(path, role, 'unlanded-head', head); return { path, outcome: 'dirty' as const }; }
|
|
314
328
|
git(path, 'checkout', '--detach', 'refs/remotes/origin/main');
|
|
315
329
|
return { path, outcome: 'refreshed' as const };
|
|
316
330
|
});
|
package/src/index.ts
CHANGED
|
@@ -2396,18 +2396,20 @@ harnessCmd
|
|
|
2396
2396
|
.description('하니스 disposable worktree + 브랜치 정리(기본 접두는 만드는 쪽 상수에서 온다). ⚠️ 열린 PR 은 항상 보존. 기본 dry-run(계획만·--yes 로 실제 제거).')
|
|
2397
2397
|
.option('--abandoned', 'PR 이력 없는 것(escalated/방치) 제거 [기본]')
|
|
2398
2398
|
.option('--merged', 'PR 머지된 것 제거')
|
|
2399
|
+
.option('--include-unowned-merged-clean', '미소유 merged-clean worktree 회수 허용(merged 모드 전용)')
|
|
2399
2400
|
.option('--all', '열린 PR 외 전부 제거')
|
|
2400
2401
|
.option('--force', '열린 PR 브랜치도 제거(위험)')
|
|
2401
2402
|
.option('--yes', '실제 제거(생략 시 dry-run)')
|
|
2402
2403
|
.option('--prefix <p>', `브랜치 prefix(기본 ${WORKTREE_BRANCH_PREFIX_HELP})`)
|
|
2403
2404
|
.option('--repo <repo>', 'gh repo(기본 origin 추론)')
|
|
2404
2405
|
.option('--json', '구조화 출력')
|
|
2405
|
-
.action(async (opts: { abandoned?: boolean; merged?: boolean; all?: boolean; force?: boolean; yes?: boolean; prefix?: string; repo?: string; json?: boolean }) => {
|
|
2406
|
+
.action(async (opts: { abandoned?: boolean; merged?: boolean; all?: boolean; force?: boolean; includeUnownedMergedClean?: boolean; yes?: boolean; prefix?: string; repo?: string; json?: boolean }) => {
|
|
2406
2407
|
const { execHarnessClean } = await import('./harness/harness-clean.js');
|
|
2407
2408
|
const mode = opts.all ? 'all' : opts.merged ? 'merged' : 'abandoned';
|
|
2408
2409
|
const res = execHarnessClean({
|
|
2409
2410
|
mode, dryRun: !opts.yes,
|
|
2410
2411
|
...(opts.force ? { force: true } : {}),
|
|
2412
|
+
...(opts.includeUnownedMergedClean ? { includeUnownedMergedClean: true } : {}),
|
|
2411
2413
|
...(opts.prefix ? { branchPrefix: opts.prefix } : {}),
|
|
2412
2414
|
...(opts.repo ? { repo: opts.repo } : {}),
|
|
2413
2415
|
});
|
|
@@ -3354,6 +3356,19 @@ coordCmd.command('events')
|
|
|
3354
3356
|
});
|
|
3355
3357
|
|
|
3356
3358
|
const selfCmd = program.command('self').description('Self-awareness memory — 외부 도구(Claude Code/Codex)가 구현/변경 이력을 elanous 기억에 주입·회상');
|
|
3359
|
+
selfCmd.command('repair-commit-export <pr> <base-head> <child-output> <repo> <outbox>')
|
|
3360
|
+
.description('Pod commit-only repair artifact exporter (installed CLI)')
|
|
3361
|
+
.action(async (pr: string, baseHead: string, outputPath: string, repo: string, outbox: string) => {
|
|
3362
|
+
const { readFileSync } = await import('node:fs');
|
|
3363
|
+
const { writePodRepairCommit } = await import('./task-orchestrator/surfaces/pod-repair-commit.js');
|
|
3364
|
+
try {
|
|
3365
|
+
const result = writePodRepairCommit({ pr: Number(pr), baseHead, runId: process.env.ELANOUS_PARENT_RUN_ID ?? '', output: readFileSync(outputPath, 'utf8'), repo, outbox });
|
|
3366
|
+
console.log(`ELANOUS_POD_REPAIR_COMMIT ${result.pr} ${result.baseHead} ${result.commit}`);
|
|
3367
|
+
} catch (error) {
|
|
3368
|
+
console.error(`ELANOUS_POD_REPAIR_FAILED ${error instanceof Error ? error.message : String(error)}`);
|
|
3369
|
+
process.exitCode = 1;
|
|
3370
|
+
}
|
|
3371
|
+
});
|
|
3357
3372
|
{ const { registerSelfUtterancesCommand } = await import('./cli/self-utterances-cli.js'); registerSelfUtterancesCommand(selfCmd); }
|
|
3358
3373
|
|
|
3359
3374
|
// M12 Claude Code 의존도 계기판 — `elanous self dependence [--since] [--until] [--json]`(읽기만).
|
|
@@ -4380,6 +4395,7 @@ selfCmd
|
|
|
4380
4395
|
.option('--base <branch>', 'PR base 브랜치(생략 시 provider 기본)')
|
|
4381
4396
|
.option('--no-draft', 'non-draft PR (기본 draft)')
|
|
4382
4397
|
.option('--open-pr', 'gate 통과 후 push + draft PR open (기본: PR 안 열고 worktree 보존·fail-closed). 이 플래그가 HITL 명시 승인.')
|
|
4398
|
+
.addOption(new Option('--no-open-pr', '수리 실행: PR 개설 없이 worktree-only로 종료').default(undefined))
|
|
4383
4399
|
.option('--auto-merge', '★ 내부 리뷰가 clean(실제 리뷰 완료·verdict≠fail)이면 자동 병합(squash). must-fix 있으면 무시(hold·rework). outward-facing(main 병합)이라 명시 opt-in. 미지정=리뷰 후 HITL/draft.')
|
|
4384
4400
|
.option('--merge-by-host', 'Pod 자식: 병합 직전 merge-ready 로 끝내 호스트가 재게이트한 뒤 병합')
|
|
4385
4401
|
.option('--child-llm-provider <id>', '구현 자식 LLM provider(--child-llm-model 과 함께 · Pod 의 grok 폴백이 쓴다)')
|
|
@@ -4565,6 +4581,13 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4565
4581
|
ui.error(refused.message);
|
|
4566
4582
|
process.exit(refused.exitCode);
|
|
4567
4583
|
}
|
|
4584
|
+
const repairRequested = (opts as { repairCommitOnly?: string }).repairCommitOnly;
|
|
4585
|
+
if (repairRequested !== undefined && ((opts as { substrate?: string }).substrate !== 'pod'
|
|
4586
|
+
|| !/^pr:[1-9]\d*$/.test((opts as { podSource?: string }).podSource ?? '')
|
|
4587
|
+
|| !/^[0-9a-f]{40}$/.test(repairRequested) || opts.openPr || opts.autoMerge)) {
|
|
4588
|
+
ui.error('--repair-commit-only: --substrate pod, --pod-source pr:N, 40-hex expected head, PR/자동 병합 없음이 필요합니다');
|
|
4589
|
+
process.exit(2);
|
|
4590
|
+
}
|
|
4568
4591
|
// 위치 인자는 종전처럼 분리하고 파일 입력은 파일당 한 골이다.
|
|
4569
4592
|
let inputGoals: ReturnType<typeof readSelfOrchestrateGoals>;
|
|
4570
4593
|
try { inputGoals = readSelfOrchestrateGoals(parts, opts.goalFile); }
|
|
@@ -5014,6 +5037,10 @@ const selfOrchestrateCmd = selfCmd
|
|
|
5014
5037
|
}
|
|
5015
5038
|
const passEnv = podProvider === 'grok' ? requestedPassEnv.filter((key) => !grokKeyNames.includes(key)) : podProvider === 'openrouter' ? [...new Set([...requestedPassEnv, 'OPENROUTER_API_KEY'])] : podProvider === 'anthropic' ? [...new Set([...requestedPassEnv, 'ANTHROPIC_API_KEY'])] : requestedPassEnv;
|
|
5016
5039
|
const podSourceSpec = (opts as { podSource?: string }).podSource;
|
|
5040
|
+
const repairBaseHead = (opts as { repairCommitOnly?: string }).repairCommitOnly;
|
|
5041
|
+
if (repairBaseHead && (!/^pr:[1-9]\d*$/.test(podSourceSpec ?? '') || !/^[0-9a-f]{40}$/.test(repairBaseHead) || opts.autoMerge || opts.openPr || goalTexts.length !== 1)) {
|
|
5042
|
+
ui.error('--repair-commit-only: --pod-source pr:N, 40-hex expected head, 골 1개, PR/자동 병합 없음이 필요합니다'); process.exit(2);
|
|
5043
|
+
}
|
|
5017
5044
|
let podSource: import('./task-orchestrator/surfaces/pod-source-receive.js').PodSource | undefined;
|
|
5018
5045
|
if (podSourceSpec) {
|
|
5019
5046
|
const { parsePodSourceSpec, resolvePodSource } = await import('./task-orchestrator/surfaces/pod-source-spec.js');
|
|
@@ -5036,7 +5063,7 @@ const selfOrchestrateCmd = selfCmd
|
|
|
5036
5063
|
if (childFlags.childLlmProvider?.trim()) debug.log('self-implement.pod', 'child-provider-named', { provider: childFlags.childLlmProvider.trim(), model: childFlags.childLlmModel ?? null, podProvider });
|
|
5037
5064
|
// BEDROCK-POD-PROVIDER-DROP — provider·account 는 한 곳(podLaunchProviderOptions)에서 — 손 나열이 bedrock 을 떨궈 codex(team)로 돌았다(10-11).
|
|
5038
5065
|
const podProviderOptions = (await import('./task-orchestrator/surfaces/pod-child-providers.js')).podLaunchProviderOptions(podProvider, { explicitPodAccount, grokApiKeyOptIn });
|
|
5039
|
-
const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), ...podProviderOptions, ...(accountBroker ? { accountBroker, rotationAccounts } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}) };
|
|
5066
|
+
const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), ...podProviderOptions, ...(accountBroker ? { accountBroker, rotationAccounts } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}), ...(repairBaseHead && podSource?.kind === 'pr' ? { repairCommitOnly: { pr: podSource.number, baseHead: repairBaseHead } } : {}) };
|
|
5040
5067
|
if (benchArms) {
|
|
5041
5068
|
const { benchPodSpawn } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
|
|
5042
5069
|
podSpawn = benchPodSpawn(benchArms, podBase);
|
|
@@ -5146,7 +5173,8 @@ selfOrchestrateCmd
|
|
|
5146
5173
|
.addOption(new Option('--no-supervise', '⛔ 런 슈퍼바이저를 «끈다»(대표 2026-08-22 ***기본 ON***) — 켜져 있으면 런이 끝나면 실패를 «트리아지»해서 다시 걸 것이 있으면 «스스로» 재개한다(골루프처럼 끝까지). 정지 사유는 converged|needs-human|max-rounds|no-progress 로 각각 «다른 값»으로 말한다. 관측=elanous logs --category self-dev.supervisor').hideHelp())
|
|
5147
5174
|
.addOption(new Option('--supervise-rounds <n>', '슈퍼바이저 재개 라운드 상한 (기본 3 · 끄려면 --no-supervise)').hideHelp())
|
|
5148
5175
|
.addOption(new Option('--json', '구조화 출력 [{taskId, feature, status, stage?, prUrl?, merged?, error?}]').hideHelp())
|
|
5149
|
-
.addOption(new Option('--pod-source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · 없으면 기본 clone').hideHelp())
|
|
5176
|
+
.addOption(new Option('--pod-source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · 없으면 기본 clone').hideHelp())
|
|
5177
|
+
.addOption(new Option('--repair-commit-only <expected-head>', 'pod: 기존 PR head에서 재작업하고 PR 생성 없이 커밋 bundle을 돌려준다').hideHelp());
|
|
5150
5178
|
|
|
5151
5179
|
function formatRelativeAge(updatedAt: number, now = Date.now()): string {
|
|
5152
5180
|
const seconds = Math.floor(Math.max(0, now - updatedAt) / 1000);
|
|
@@ -5649,7 +5677,8 @@ selfCmd
|
|
|
5649
5677
|
.option('--context <path>', '리뷰어가 함께 판단할 레포 상대 파일 경로(반복 가능)', (value: string, previous: string[] = []) => [...previous, value])
|
|
5650
5678
|
.option('--context-text <text>', '리뷰어가 함께 판단할 텍스트(반복 가능)', (value: string, previous: string[] = []) => [...previous, value])
|
|
5651
5679
|
.option('--json', '구조화 출력 {pr, verdict, mustFix, shouldFix, reviewed}')
|
|
5652
|
-
.
|
|
5680
|
+
.option('--save <name>', '리뷰 결과를 상태 디렉터리의 review-results/<name>-<PR>-<head12>.json에 저장')
|
|
5681
|
+
.action(async (prParts: string[], opts: { intent?: string; model?: string; acp?: boolean; acpModel?: string; acpBackend?: string; acpTimeout?: string; context?: string[]; contextText?: string[]; json?: boolean; save?: string }) => {
|
|
5653
5682
|
const prArgs = prParts.flatMap((p) => String(p).split(/[,\s]+/).filter(Boolean)); // 번호/#번호/URL·콤마목록.
|
|
5654
5683
|
if (!prArgs.length) { ui.error('PR 필요: elanous self review <번호|URL> [..]'); process.exit(2); }
|
|
5655
5684
|
// ⭐ 본문은 seam(`runSelfReviewCliCommand`)에 있다 — 이 액션은 **의존 배선만** 한다.
|
|
@@ -7723,7 +7752,7 @@ configCmd
|
|
|
7723
7752
|
.action(async (path: string | undefined, opts: { reveal?: boolean }) => {
|
|
7724
7753
|
const { resolveCurrentInstance } = await import('./instance/current.js');
|
|
7725
7754
|
const instance = resolveCurrentInstance();
|
|
7726
|
-
if (instance.kind === 'test' && instance.layer === 'tree-derived') {
|
|
7755
|
+
if (instance.kind === 'test' && String(instance.layer) === 'tree-derived') {
|
|
7727
7756
|
console.error('⚠️ test 우주의 config를 읽습니다 — 운영 값은 --config-dir ~/.elanous');
|
|
7728
7757
|
}
|
|
7729
7758
|
const cfg = getUserConfig() as unknown as Record<string, unknown>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
import type { ModelCatalog, ModelEntry } from './types.js';
|
|
3
|
+
|
|
4
|
+
const NUMERIC_COLUMNS = [
|
|
5
|
+
'ctx', 'in$/1M', 'out$/1M', 'cacheRead$/1M', 'est_run$',
|
|
6
|
+
'AA_intel', 'AA_coding', 'AA_agentic', 'SWE_verified', 'SWE_pro',
|
|
7
|
+
'TerminalBench', 'LiveCodeBench', 'tool_use',
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
export type BenchNumericColumn = typeof NUMERIC_COLUMNS[number];
|
|
11
|
+
export type BenchScore = 'AA_coding' | 'AA_agentic' | 'SWE_verified' | 'TerminalBench';
|
|
12
|
+
|
|
13
|
+
export type BenchRow = {
|
|
14
|
+
id: string;
|
|
15
|
+
provider: string;
|
|
16
|
+
sources: string;
|
|
17
|
+
notes: string;
|
|
18
|
+
raw: Record<string, string>;
|
|
19
|
+
} & Record<BenchNumericColumn, number | null>;
|
|
20
|
+
|
|
21
|
+
export type ComparedBenchRow<T extends BenchRow = BenchRow> = T & {
|
|
22
|
+
value: number | null;
|
|
23
|
+
status: 'scored' | '미확인';
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const UNKNOWN = new Set(['', '미확인', '미표기', '-']);
|
|
27
|
+
const NUMBER = /[-+]?(?:\d+(?:,\d{3})*(?:\.\d+)?|\.\d+)(?:[eE][-+]?\d+)?/g;
|
|
28
|
+
|
|
29
|
+
function parseNumber(raw: string): number | null {
|
|
30
|
+
const trimmed = raw.trim();
|
|
31
|
+
if (UNKNOWN.has(trimmed)) return null;
|
|
32
|
+
// A label may contain a version number ("AA TB4.0 33.3"); the final
|
|
33
|
+
// number is the measured value. Keep the full cell separately in raw.
|
|
34
|
+
const matches = [...trimmed.matchAll(NUMBER)];
|
|
35
|
+
const last = matches.at(-1)?.[0];
|
|
36
|
+
if (!last) return null;
|
|
37
|
+
const parsed = Number(last.replaceAll(',', ''));
|
|
38
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Parse a caller-supplied, offline TSV. Column positions come only from the header. */
|
|
42
|
+
export function parseBenchScoresTsv(text: string): BenchRow[] {
|
|
43
|
+
const lines = text.replace(/^\uFEFF/, '').split(/\r?\n/);
|
|
44
|
+
const headers = (lines.shift() ?? '').split('\t').map((name) => name.trim());
|
|
45
|
+
if (!headers.includes('id')) throw new Error('bench scores TSV missing id header');
|
|
46
|
+
const rows: BenchRow[] = [];
|
|
47
|
+
let unknownCells = 0;
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
if (!line.trim()) continue;
|
|
50
|
+
const cells = line.split('\t');
|
|
51
|
+
const raw: Record<string, string> = {};
|
|
52
|
+
headers.forEach((header, index) => { raw[header] = cells[index] ?? ''; });
|
|
53
|
+
const numbers = {} as Record<BenchNumericColumn, number | null>;
|
|
54
|
+
for (const column of NUMERIC_COLUMNS) {
|
|
55
|
+
numbers[column] = parseNumber(raw[column] ?? '');
|
|
56
|
+
if (numbers[column] === null) unknownCells++;
|
|
57
|
+
}
|
|
58
|
+
rows.push({ id: raw.id?.trim() ?? '', provider: raw.provider ?? '',
|
|
59
|
+
sources: raw.sources ?? '', notes: raw.notes ?? '', raw, ...numbers });
|
|
60
|
+
}
|
|
61
|
+
debug.log('intelligence.bench-scores', 'parsed', { rows, unknownCells });
|
|
62
|
+
return rows;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** An OpenRouter vendor/model id matches a catalog id only under its vendor.
|
|
66
|
+
* The builtin DeepSeek entries are `other`/`deepseek` but have the explicit
|
|
67
|
+
* OpenRouter route `deepseek/<id>` in their notes. */
|
|
68
|
+
function catalogIds(model: ModelEntry): string[] {
|
|
69
|
+
const ids = [model.id];
|
|
70
|
+
const vendor = model.provider === 'openai-codex' ? 'openai'
|
|
71
|
+
: model.provider === 'gemini' ? 'google'
|
|
72
|
+
: model.provider === 'grok' ? 'x-ai'
|
|
73
|
+
: model.provider === 'kimi' ? 'moonshotai'
|
|
74
|
+
: model.provider === 'glm' ? 'z-ai'
|
|
75
|
+
: model.provider === 'other' && model.family === 'deepseek' && model.notes?.includes(`OpenRouter deepseek/${model.id}`) ? 'deepseek'
|
|
76
|
+
: model.provider;
|
|
77
|
+
if (!model.local) ids.push(`${vendor}/${model.id}`, `openrouter/${vendor}/${model.id}`);
|
|
78
|
+
return ids;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function joinWithCatalog<T extends BenchRow>(rows: readonly T[], catalog: ModelCatalog): (T & { inCatalog: boolean })[] {
|
|
82
|
+
const ids = new Set(catalog.models.flatMap(catalogIds));
|
|
83
|
+
return rows.map((row) => ({ ...row, inCatalog: ids.has(row.id) }));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Sort by score per estimated run dollar. Missing scores always come last;
|
|
87
|
+
* a known score without a usable denominator has an unknown value. */
|
|
88
|
+
export function compareRows<T extends BenchRow>(rows: readonly T[], opts: { score: BenchScore }): ComparedBenchRow<T>[] {
|
|
89
|
+
return rows.map((row) => {
|
|
90
|
+
const score = row[opts.score];
|
|
91
|
+
return { ...row,
|
|
92
|
+
value: score !== null && row.est_run$ !== null && row.est_run$ > 0
|
|
93
|
+
? score / row.est_run$ : null,
|
|
94
|
+
status: score === null ? '미확인' as const : 'scored' as const,
|
|
95
|
+
};
|
|
96
|
+
}).sort((a, b) => {
|
|
97
|
+
if (a.status !== b.status) return a.status === '미확인' ? 1 : -1;
|
|
98
|
+
if (a.value === null) return b.value === null ? 0 : 1;
|
|
99
|
+
if (b.value === null) return -1;
|
|
100
|
+
return b.value - a.value;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { openMsgStore, type Message, type MsgStore } from '../../msg/msg-store.js';
|
|
2
|
+
import { classifySeatTrafficProposal } from '../../seat-loop/traffic-signal.js';
|
|
3
|
+
import { debug } from '../../debug/log.js';
|
|
4
|
+
|
|
5
|
+
const RECIPIENT = 'COORDINATOR';
|
|
6
|
+
|
|
7
|
+
export interface CoordinatorInboxResult { replied: number; acknowledged: number }
|
|
8
|
+
|
|
9
|
+
function trafficProposal(request: Message): 'hold' | 'UNHOLD' | null {
|
|
10
|
+
// A question mentioning a signal is not evidence that the signal occurred.
|
|
11
|
+
return request.kind === 'question' || /[??]|되나|됐나|맞나|풀어도|해제해도|확인 요청/.test(request.body)
|
|
12
|
+
? null : classifySeatTrafficProposal(request.body);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** This loop suggests traffic moves; it never changes traffic.json. */
|
|
16
|
+
export function coordinatorReply(request: Message): string {
|
|
17
|
+
const traffic = trafficProposal(request);
|
|
18
|
+
const proposal = traffic === 'hold' ? 'hold 제안' : traffic === 'UNHOLD' ? 'UNHOLD 제안' : '모름 — OP/자리 판단 필요';
|
|
19
|
+
const evidence = traffic === 'hold' ? '자리 메시지에 «손 구현 착수»가 있습니다.'
|
|
20
|
+
: traffic === 'UNHOLD' ? '자리 메시지에 «첫 줄 확정»이 있습니다.'
|
|
21
|
+
: '착수·첫 줄 확정을 확정 진술로 확인하지 못했습니다. 칸·traffic 근거를 사람이 확인해야 합니다.';
|
|
22
|
+
return `re #${request.id}\n제안: ${proposal}\n근거: ${evidence}\n실제 잠금 변경은 수행하지 않았습니다.`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Single reply writer: prefer the durable thread link, while recognizing pre-migration body markers. */
|
|
26
|
+
function writeCoordinatorReply(store: MsgStore, request: Message): { id: number; posted: boolean } {
|
|
27
|
+
const marker = `re #${request.id}`;
|
|
28
|
+
const linked = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
29
|
+
AND reply_to = ? ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
|
|
30
|
+
if (linked) return { id: linked.id, posted: false };
|
|
31
|
+
const legacy = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
32
|
+
AND reply_to IS NULL AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
|
|
33
|
+
.get(RECIPIENT, request.from, marker, marker.length + 1, `${marker}\n`) as { id: number } | null;
|
|
34
|
+
if (legacy) return { id: legacy.id, posted: false };
|
|
35
|
+
const reply = store.post({ from: RECIPIENT, to: request.from,
|
|
36
|
+
body: coordinatorReply(request).slice(marker.length + 1), kind: 'reply', replyTo: request.id });
|
|
37
|
+
return { id: reply.id, posted: true };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One transaction ties a reply to its acknowledgement. A retry finds the durable receipt. */
|
|
41
|
+
export function runCoordinatorInbox(inputStore?: MsgStore, limit = 100, path?: string): CoordinatorInboxResult {
|
|
42
|
+
const store = inputStore ?? openMsgStore(path);
|
|
43
|
+
const ownStore = inputStore === undefined;
|
|
44
|
+
let replied = 0;
|
|
45
|
+
let acknowledged = 0;
|
|
46
|
+
try {
|
|
47
|
+
const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), limit);
|
|
48
|
+
for (const request of requests) {
|
|
49
|
+
// Broadcasts and replies are not new requests. Advancing past them keeps the cursor moving.
|
|
50
|
+
if (request.to !== RECIPIENT || request.from === RECIPIENT ||
|
|
51
|
+
(request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
|
|
52
|
+
store.ack(RECIPIENT, request.id);
|
|
53
|
+
acknowledged++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const key = `coord-inbox:${request.id}:${request.from}`;
|
|
57
|
+
const result = store.db.transaction(() => {
|
|
58
|
+
const existing = store.db.query('SELECT message_id FROM msg_provenance WHERE provenance_key = ?')
|
|
59
|
+
.get(key) as { message_id: number } | null;
|
|
60
|
+
const reply = existing ? { id: existing.message_id, posted: false } : writeCoordinatorReply(store, request);
|
|
61
|
+
if (!existing) store.db.query('INSERT INTO msg_provenance(provenance_key, message_id) VALUES (?, ?)').run(key, reply.id);
|
|
62
|
+
store.ack(RECIPIENT, request.id);
|
|
63
|
+
return { posted: reply.posted };
|
|
64
|
+
}).immediate();
|
|
65
|
+
if (result.posted) replied++;
|
|
66
|
+
acknowledged++;
|
|
67
|
+
debug.log('loop.coordinator-inbox', 'reply', { requestId: request.id, recipient: request.from,
|
|
68
|
+
proposal: trafficProposal(request) ?? 'unknown', duplicate: !result.posted });
|
|
69
|
+
}
|
|
70
|
+
debug.log('loop.coordinator-inbox', 'tick', { replied, acknowledged });
|
|
71
|
+
return { replied, acknowledged };
|
|
72
|
+
} finally { if (ownStore) store.close(); }
|
|
73
|
+
}
|