elanous 0.2.23 → 0.2.24
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/{272-b23d2e92161d11fd.js → 272-0eed0fb0aab716b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3961-fbef064c213b2b18.js → 3961-aaae04ed1d32622f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-d5341ac96203a983.js → page-3b9fc39362473ae7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/{page-55c631c032dcc47e.js → page-d7602d489edf5f37.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ad3bd8084048bee4.js → page-24282bf9f90031a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/{page-5c5d0e370f495ef6.js → page-4eb84d454f8c3415.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-c325e21543cd48a8.js → page-b2e494bdad57fcb5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-6168a7c43e6ef8f5.js → page-c0ab229673a8b0eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-25bb425afdb27541.js → page-bf88c0f558d8ef54.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-32d72fdef1afe11a.js → page-52fec523e5b5d3ad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/{page-2bd9ce9c020d02d4.js → page-22725e2570f1126b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-a34096245e63b9f2.js → page-1891335950d68b70.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-4cc66d22ca4ec502.js → page-c314b75c11234998.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-83b14c729fcea837.js → page-9f9c85415f61782b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-ccdb83ed40c8d724.js → page-8526c17ae38e6a50.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-7ad3de8fa06fdea9.js → page-f998637a8402115c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-786111f30b6f0969.js → page-6f23159fedb41f67.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-48fb31810693c357.js → page-1d809a87139dd024.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-4e17cce5e2ed0fee.js → page-da9e570234d481fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-cb154acadb025414.js → page-b92caddb5c715f30.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-c2dd2b19c93f90ab.js → page-57ffeeb6019440fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-d3c007c8a0ddd7ee.js → page-2c2b3f29cec1efa4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-7837ce2aacb97b04.js → page-9369279f72fc7b51.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-119be9a0444d2482.js → page-b5c0c996f329371e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-fa806c018833e332.js → page-89881ccbcf728978.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/{page-d431fbdea6ad93dd.js → page-58d4e5cb30ef4871.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-847c3de6ca8a4416.js → page-acf868c64d77f950.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-74e69ba2c8e970d4.js → page-bc79f0833533fa84.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/{page-70038f41ae7cf931.js → page-d5c4398eea03d8f3.js} +1 -1
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +14 -14
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +14 -14
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +14 -14
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +14 -14
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +14 -14
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/package.json +1 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/ci-typecheck-changed.ts +71 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-node.ts +262 -26
- package/scripts/release-loop/resume-release.ts +9 -3
- package/scripts/release-loop/resume.ts +41 -0
- package/scripts/release-loop/unattended-release.ts +22 -7
- package/scripts/tsc-baseline-cache.ts +147 -0
- package/scripts/usage-rollup.ts +58 -6
- package/src/agent/run-context.ts +10 -0
- package/src/agent-mission/driver.ts +18 -3
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +8 -2
- package/src/agent-substrate/acp-implementer.ts +139 -0
- package/src/agent-substrate/pr-reviewer.ts +31 -4
- package/src/agent-substrate/self-review-cli.ts +48 -9
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/types.ts +8 -2
- package/src/budget/unified-usage.ts +88 -6
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/log-event-names.ts +4 -0
- package/src/cli/pr-cli.ts +62 -5
- package/src/cli/pr-land-overlap-evidence.ts +160 -12
- package/src/cli/release-cli.ts +18 -9
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/self-update.ts +104 -0
- package/src/cli/tasks-cli.ts +109 -4
- package/src/cli/usage-cli.ts +91 -8
- package/src/core-turn/run-goal-loop.ts +5 -4
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/index.ts +18 -276
- package/src/dashboard/stale-install-check.ts +11 -0
- package/src/debug/log-diet.ts +38 -7
- package/src/debug/log.ts +19 -1
- package/src/domains/release-tool.ts +39 -0
- package/src/error-report/report.ts +21 -4
- package/src/github/pr-labels.ts +1 -0
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +167 -6
- package/src/grok/usage.ts +23 -2
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +10 -2
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +122 -7
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-stop.ts +4 -2
- package/src/harness/harness-substrate-default.ts +142 -7
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/seats.ts +38 -22
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +93 -11
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intelligence-map/model-catalog.ts +72 -0
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +114 -41
- package/src/llm/bedrock.ts +174 -28
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +87 -16
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/maturity/feature-maturity.ts +2 -2
- package/src/model-tier/llm-tier-map.ts +9 -5
- package/src/models/prompts.ts +2 -1
- package/src/mss/logging/log-store.ts +58 -11
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/index.ts +7 -75
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +39 -2
- package/src/oauth/codex-account-store.ts +323 -24
- package/src/oauth/fallback-chain.ts +53 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/prompt-cache/openai.ts +3 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +23 -0
- package/src/release-loop/placement.ts +16 -1
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +5 -5
- package/src/seat-loop/seat-loop.ts +32 -10
- package/src/self-dev/dev-cli.ts +44 -10
- package/src/self-dev/dev-pipeline.ts +7 -2
- package/src/self-dev/draft-residue.ts +14 -2
- package/src/self-dev/draft-sweep.ts +103 -0
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/orchestrate-cli.ts +25 -3
- package/src/self-dev/orchestrate.ts +41 -6
- package/src/self-dev/run-supervisor.ts +188 -15
- package/src/self-dev/run-types.ts +13 -0
- package/src/self-dev/supervisor-verdict-edges.ts +1 -0
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +24 -9
- package/src/self-implement/graph-overlay-condition.ts +28 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/orchestrator.ts +144 -15
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/seams.ts +47 -1
- package/src/self-implement/self-implement-cli.ts +9 -4
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/steward/launch.ts +5 -4
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +83 -22
- package/src/task-agent/actions.ts +62 -5
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +101 -3
- package/src/task-agent/judge.ts +16 -0
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/live-move-history.ts +87 -1
- package/src/task-agent/live-moves.ts +350 -20
- package/src/task-agent/rejudge-on-head.ts +75 -20
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +53 -9
- package/src/task-agent/task-hand.ts +54 -7
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
- package/src/task-orchestrator/surfaces/pod-pool.ts +20 -4
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +213 -23
- package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +51 -11
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
- /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
package/src/self-dev/dev-cli.ts
CHANGED
|
@@ -65,6 +65,7 @@ import { findGrokModel, GROK_MODELS } from '../grok/models.js';
|
|
|
65
65
|
import { resolveModelAlias } from '../intelligence-map/model-alias.js';
|
|
66
66
|
import { BUILTIN_CATALOG } from '../intelligence-map/model-catalog.js';
|
|
67
67
|
import { BEDROCK_DEFAULT_MODEL, BEDROCK_MODELS, findBedrockModel, resolveBedrockModelId } from '../llm/bedrock.js';
|
|
68
|
+
import { ZAI_CODING_DEFAULT_MODEL, ZAI_CODING_MODELS } from '../llm/zai-coding-plan.js';
|
|
68
69
|
|
|
69
70
|
/** `dev --plan` 도움말이 가리키는 대응 문. ⛔ 도움말에 이 문자열을 리터럴로 다시 적지 마라. */
|
|
70
71
|
export const DEV_PLAN_REPLACEMENT = 'elanous harness say';
|
|
@@ -1097,6 +1098,9 @@ export async function executeDevSelfRun(
|
|
|
1097
1098
|
retainConfirmedMerge(result);
|
|
1098
1099
|
await superviseRun({
|
|
1099
1100
|
initial: [initialJob],
|
|
1101
|
+
// A review-oscillation repair goal runs through the existing piece executor (fragment re-execution with the
|
|
1102
|
+
// authored goal as its feature). Without that executor the rerun could only replay the same goal — declare false.
|
|
1103
|
+
repairGoalExecution: supervise.executePiece !== undefined,
|
|
1100
1104
|
enrich: (results) => hydrateDevGoalCauseObserved(
|
|
1101
1105
|
hydrateDevDecomposeProposals(results, supervise.readProposals ?? readDecomposeProposals),
|
|
1102
1106
|
),
|
|
@@ -1157,7 +1161,24 @@ export async function executeDevSelfRun(
|
|
|
1157
1161
|
}) + orderingNote,
|
|
1158
1162
|
};
|
|
1159
1163
|
},
|
|
1160
|
-
rerun: async (previous, { relaunch }) => {
|
|
1164
|
+
rerun: async (previous, { relaunch, repairGoals }) => {
|
|
1165
|
+
const repairJobs = previous.flatMap((job) => repairGoals?.[job.taskId] === undefined ? [] : [{ job, goal: repairGoals[job.taskId]! }]);
|
|
1166
|
+
if (repairJobs.length > 0 && supervise.executePiece !== undefined) {
|
|
1167
|
+
if (recordRestart('relaunch', previous.at(-1)!)) return [];
|
|
1168
|
+
executedRounds += 1;
|
|
1169
|
+
// Every authored repair goal runs (one per oscillating task), each keeping its task's goal feature so a
|
|
1170
|
+
// second oscillation is recognised as «already repaired».
|
|
1171
|
+
const repaired: ReturnType<typeof asSupervisorJobResult>[] = [];
|
|
1172
|
+
for (const { job, goal } of repairJobs) {
|
|
1173
|
+
try { debug.log('self-dev.supervisor', 'oscillation-repair.executed', { surface: 'dev', taskId: job.taskId, chars: goal.length }); } catch { /* fail-open */ }
|
|
1174
|
+
const repairResult = recordResult(await supervise.executePiece(goal));
|
|
1175
|
+
retainConfirmedMerge(repairResult);
|
|
1176
|
+
if (shardResults === undefined) result = repairResult;
|
|
1177
|
+
repaired.push({ ...asSupervisorJobResult(job.feature, repairResult), oscillationRepairOf: job.taskId });
|
|
1178
|
+
}
|
|
1179
|
+
// Jobs without a repair goal are not dropped: their last result stays in the round for the next decision.
|
|
1180
|
+
return [...repaired, ...previous.filter((job) => repairGoals?.[job.taskId] === undefined)];
|
|
1181
|
+
}
|
|
1161
1182
|
if (promotedPieces !== undefined) {
|
|
1162
1183
|
const pieces = promotedPieces;
|
|
1163
1184
|
promotedPieces = undefined;
|
|
@@ -1340,12 +1361,19 @@ export function normalizeChildLlmProvider(provider: string): string {
|
|
|
1340
1361
|
: p;
|
|
1341
1362
|
}
|
|
1342
1363
|
|
|
1364
|
+
/** CLAUDE-IMPL-LANE — claude-acp = Claude 구독 ACP 구현 레인(src/agent-substrate/acp-implementer.ts). 모델 카탈로그·사다리는 anthropic 과 같다. */
|
|
1365
|
+
function childModelCatalogProvider(provider: string): string {
|
|
1366
|
+
const normalized = normalizeChildLlmProvider(provider);
|
|
1367
|
+
return normalized === 'claude-acp' ? 'anthropic' : normalized;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1343
1370
|
function isKnownChildLlmProvider(provider: string): boolean {
|
|
1344
|
-
|
|
1371
|
+
// ZAI-POD-CHILD (0.2.24) — glm = Z.ai GLM Coding Plan 직결(`ZAI_API_KEY` · src/llm/zai-coding-plan.ts). Pod 자식이 `--child-llm-provider glm` 으로 뜬다.
|
|
1372
|
+
return ['grok', 'anthropic', 'claude-acp', 'gemini', 'openai', 'openai-codex', 'local', 'openrouter', 'bedrock', 'glm'].includes(normalizeChildLlmProvider(provider));
|
|
1345
1373
|
}
|
|
1346
1374
|
|
|
1347
1375
|
function findPickerCatalogModel(provider: string, id: string): CatalogModelView | undefined {
|
|
1348
|
-
switch (
|
|
1376
|
+
switch (childModelCatalogProvider(provider)) {
|
|
1349
1377
|
case 'grok': return findGrokModel(id);
|
|
1350
1378
|
case 'anthropic': return findClaudeModel(id);
|
|
1351
1379
|
case 'gemini': return findGeminiModel(id);
|
|
@@ -1353,12 +1381,15 @@ function findPickerCatalogModel(provider: string, id: string): CatalogModelView
|
|
|
1353
1381
|
case 'openai-codex': return findCodexModel(id);
|
|
1354
1382
|
case 'openrouter': return findOpenRouterChildModel(id);
|
|
1355
1383
|
case 'bedrock': return findBedrockChildModel(id);
|
|
1384
|
+
case 'glm': return (ZAI_CODING_MODELS as readonly string[]).includes(id)
|
|
1385
|
+
? { id, tier: /flash/i.test(id) ? 'budget' : 'balanced', supportsThinking: true, recommended: id === ZAI_CODING_DEFAULT_MODEL }
|
|
1386
|
+
: undefined;
|
|
1356
1387
|
default: return undefined;
|
|
1357
1388
|
}
|
|
1358
1389
|
}
|
|
1359
1390
|
|
|
1360
1391
|
/** BEDROCK-PROVIDER — `anthropic.claude-sonnet-5-5` · `bedrock/claude-sonnet-5-5` · (provider=bedrock 일 때) `claude-sonnet-5-5`
|
|
1361
|
-
* 를 받아 와이어 id(`anthropic
|
|
1392
|
+
* 를 받아 와이어 id 로 해석한다(5.5 = 전역 추론 프로필 `global.anthropic.…` · BEDROCK-RUNTIME-PATH). 표 밖은 «모른다» → 거부(다른 provider 와 같은 규율). */
|
|
1362
1393
|
function findBedrockChildModel(id: string): CatalogModelView | undefined {
|
|
1363
1394
|
const entry = findBedrockModel(id);
|
|
1364
1395
|
if (!entry) return undefined;
|
|
@@ -1394,7 +1425,7 @@ function tierFromBuiltin(tags: readonly string[] | undefined): string {
|
|
|
1394
1425
|
}
|
|
1395
1426
|
|
|
1396
1427
|
function findBuiltinCatalogModel(provider: string, id: string): CatalogModelView | undefined {
|
|
1397
|
-
const expected =
|
|
1428
|
+
const expected = childModelCatalogProvider(provider);
|
|
1398
1429
|
const entry = BUILTIN_CATALOG.models.find((model) => (
|
|
1399
1430
|
model.id === id && normalizeChildLlmProvider(model.provider) === expected
|
|
1400
1431
|
));
|
|
@@ -1408,7 +1439,7 @@ function findBuiltinCatalogModel(provider: string, id: string): CatalogModelView
|
|
|
1408
1439
|
}
|
|
1409
1440
|
|
|
1410
1441
|
function listImplementationChildModelCandidates(provider: string): string[] {
|
|
1411
|
-
const expected =
|
|
1442
|
+
const expected = childModelCatalogProvider(provider);
|
|
1412
1443
|
const picker = (() => {
|
|
1413
1444
|
switch (expected) {
|
|
1414
1445
|
case 'grok': return GROK_MODELS.map((model) => model.id);
|
|
@@ -1418,6 +1449,7 @@ function listImplementationChildModelCandidates(provider: string): string[] {
|
|
|
1418
1449
|
case 'openai-codex': return CODEX_MODELS.map((model) => model.id);
|
|
1419
1450
|
case 'openrouter': return [...new Set(MODEL_TIERS.map((t) => LLM_TIER_MAP_BY_PROVIDER.openrouter[t].model))];
|
|
1420
1451
|
case 'bedrock': return BEDROCK_MODELS.map((model) => model.id);
|
|
1452
|
+
case 'glm': return [...ZAI_CODING_MODELS];
|
|
1421
1453
|
default: return [];
|
|
1422
1454
|
}
|
|
1423
1455
|
})();
|
|
@@ -1576,10 +1608,12 @@ export function grokWeeklyUsedPctFromUsageJson(stdout: string): number | undefin
|
|
|
1576
1608
|
/** `elanous usage --json` 의 grok 행 → 잔량 판정. 한 행이라도 100% 미만이면 usable, 모두 100% 이상이면 exhausted. */
|
|
1577
1609
|
export function grokQuotaFromUsageJson(stdout: string): 'usable' | 'exhausted' | 'unknown' {
|
|
1578
1610
|
try {
|
|
1579
|
-
const parsed = JSON.parse(stdout) as { rows?: Array<{ provider?: string; credits?: { status?: string;
|
|
1611
|
+
const parsed = JSON.parse(stdout) as { rows?: Array<{ provider?: string; credits?: { status?: string; periodType?: string | null; usedPercent?: unknown } }> };
|
|
1580
1612
|
const percents = (parsed.rows ?? [])
|
|
1581
|
-
.filter((row) => row.provider === 'grok' && row.credits?.status === 'ok'
|
|
1582
|
-
|
|
1613
|
+
.filter((row) => row.provider === 'grok' && row.credits?.status === 'ok'
|
|
1614
|
+
&& row.credits.periodType === 'USAGE_PERIOD_TYPE_WEEKLY')
|
|
1615
|
+
.map((row) => row.credits?.usedPercent)
|
|
1616
|
+
.filter((pct): pct is number => typeof pct === 'number' && Number.isFinite(pct) && pct >= 0 && pct <= 100);
|
|
1583
1617
|
if (percents.length === 0) return 'unknown';
|
|
1584
1618
|
return percents.some((p) => p < 100) ? 'usable' : 'exhausted';
|
|
1585
1619
|
} catch {
|
|
@@ -1722,7 +1756,7 @@ function announceChildLlmInterpretation(
|
|
|
1722
1756
|
export const CHILD_LLM_DEFAULT_TIER = 'better' as const;
|
|
1723
1757
|
|
|
1724
1758
|
export function defaultChildLlmModel(provider: string): string {
|
|
1725
|
-
return tierModel(CHILD_LLM_DEFAULT_TIER, provider as never);
|
|
1759
|
+
return tierModel(CHILD_LLM_DEFAULT_TIER, childModelCatalogProvider(provider) as never);
|
|
1726
1760
|
}
|
|
1727
1761
|
|
|
1728
1762
|
export type ChildLlmConfigSnapshot = { provider?: string; model?: string };
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
// self 는 backend 리스트 항목이 아니라 transport 축을 붕괴시키는 특수 갈래. 감독 축도 self=turn 레벨.
|
|
16
16
|
|
|
17
17
|
import { execFileSync } from 'node:child_process';
|
|
18
|
-
import { createHash } from 'node:crypto';
|
|
18
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
19
|
+
import { benchArmBranchForBase } from '../bench/bench.js';
|
|
19
20
|
import { readFileSync } from 'node:fs';
|
|
20
21
|
import { dispatchTask, type DispatchTaskDeps } from '../execution-loop/dispatch-task.js';
|
|
21
22
|
import { getNestDepth } from '../agent/nest-depth.js';
|
|
@@ -609,7 +610,11 @@ export function toSelfImplementOptions(text: string, plan: ResolvedDevPlan, seam
|
|
|
609
610
|
...(s.naturalLanguageDispatch ? { naturalLanguageDispatch: true } : {}),
|
|
610
611
|
...(s.childLlm ? { childLlm: s.childLlm } : {}),
|
|
611
612
|
...(s.correlationId !== undefined ? { correlationId: s.correlationId } : {}),
|
|
612
|
-
|
|
613
|
+
// BENCH-ISOLATED-ARMS ② — base 가 `bench/<id>/base` 면 팔 가지 `bench/<id>/<arm>` (명시 branchName 이 이긴다).
|
|
614
|
+
...(() => {
|
|
615
|
+
const branchName = s.branchName ?? benchArmBranchForBase(plan.base, s.childLlm?.model, process.env.ELANOUS_RUN_ID?.trim() || randomUUID());
|
|
616
|
+
return branchName ? { branchName } : {};
|
|
617
|
+
})(),
|
|
613
618
|
...(s.maxReworkRounds !== undefined ? { maxReworkRounds: s.maxReworkRounds } : {}),
|
|
614
619
|
launch: resolveLaunchStamp({ entrance: plan.entrance, queueId: process.env.ELANOUS_HARNESS_QUEUE_LAUNCH }),
|
|
615
620
|
};
|
|
@@ -23,11 +23,14 @@ export interface PrTerminalRecord {
|
|
|
23
23
|
ownerSource: 'seat' | 'card' | 'unknown';
|
|
24
24
|
card: string | null;
|
|
25
25
|
at: string;
|
|
26
|
+
/** Which host-regate gate failed and why — null for every other terminal. */
|
|
27
|
+
hostRegateFailure: { step: string; detail: string; os: string } | null;
|
|
26
28
|
}
|
|
27
29
|
export interface PodTerminalInput {
|
|
28
30
|
childRunId: string;
|
|
29
31
|
state: 'complete' | 'failed' | 'aborted';
|
|
30
|
-
disposition?: { prNumber?: number | null; prUrl?: string | null; checkedHeadCommit?: string | null; stage?: string; merged?: boolean; ok?: boolean
|
|
32
|
+
disposition?: { prNumber?: number | null; prUrl?: string | null; checkedHeadCommit?: string | null; stage?: string; merged?: boolean; ok?: boolean;
|
|
33
|
+
hostRegate?: { passed: boolean; failures: Array<{ step: string; detail: string }>; os: string } | null } | null;
|
|
31
34
|
env?: Readonly<Record<string, string | undefined>>;
|
|
32
35
|
prBody?: string;
|
|
33
36
|
goalText?: string;
|
|
@@ -47,13 +50,22 @@ export function classifyPodTerminal(input: PodTerminalInput): PrTerminalRecord {
|
|
|
47
50
|
const card = cardOf(input.prBody) ?? cardOf(input.goalText);
|
|
48
51
|
const seat = input.env?.ELANOUS_HARNESS_SEAT;
|
|
49
52
|
const ownerSource = seat === 'OP' || seat === 'TC' || seat === 'MK' || seat === 'UX' ? 'seat' : card ? 'card' : 'unknown';
|
|
53
|
+
const hostRegate = d?.hostRegate;
|
|
54
|
+
const firstFailure = hostRegate?.passed === false && Array.isArray(hostRegate.failures) ? hostRegate.failures[0] : undefined;
|
|
55
|
+
const hostRegateFailure = d?.stage === 'host-regate-failed' && hostRegate?.passed === false
|
|
56
|
+
? { step: typeof firstFailure?.step === 'string' && firstFailure.step ? firstFailure.step : 'unknown',
|
|
57
|
+
detail: typeof firstFailure?.detail === 'string' && firstFailure.detail
|
|
58
|
+
? firstFailure.detail.split(/\s+/).filter(Boolean).join(' ').slice(0, 300)
|
|
59
|
+
: 'failures empty',
|
|
60
|
+
os: hostRegate.os }
|
|
61
|
+
: null;
|
|
50
62
|
return {
|
|
51
63
|
childRunId: input.childRunId, prNumber, prUrl, repository,
|
|
52
64
|
headSha: typeof d?.checkedHeadCommit === 'string' && /^[a-f0-9]{40}$/i.test(d.checkedHeadCommit) ? d.checkedHeadCommit : null,
|
|
53
65
|
terminalClass: !d ? 'failed-pr-unobserved' : d.merged === true ? 'landed'
|
|
54
66
|
: prNumber === null ? 'failed-no-pr'
|
|
55
67
|
: input.state === 'complete' && d.ok !== false ? 'merge-ready-not-merged' : 'failed-with-pr',
|
|
56
|
-
stage: d?.stage ?? null,
|
|
68
|
+
stage: d?.stage ?? null, hostRegateFailure,
|
|
57
69
|
owner: ownerSource === 'seat' ? seat! : ownerSource === 'card' ? card! : 'unknown',
|
|
58
70
|
ownerSource, card, at: input.at ?? new Date().toISOString(),
|
|
59
71
|
};
|
|
@@ -4,6 +4,7 @@ import { decideDraft, draftClaimComment, draftClaimState, draftReleaseComment, l
|
|
|
4
4
|
import { cardPrNumber, draftTaskOwner, type TaskCard } from '../task-agent/task-hand.js';
|
|
5
5
|
import type { PrTerminalRecord } from './draft-residue.js';
|
|
6
6
|
import { branchLineageSlug } from '../cli/pr-lineage.js';
|
|
7
|
+
import { branchLineageKey } from '../harness/worktree-branch-prefix.js';
|
|
7
8
|
|
|
8
9
|
export interface SweepDraft extends DraftTriagePr {
|
|
9
10
|
readonly title: string;
|
|
@@ -60,6 +61,12 @@ export interface DraftSweepAdapters {
|
|
|
60
61
|
getReviewGate?(draft: SweepDraft, repository: string): Promise<SweepReviewGate | undefined>;
|
|
61
62
|
/** One PR by number (any state); undefined means it could not be read. Only overlap metrics need it. */
|
|
62
63
|
getPr?(repository: string, number: number): Promise<SweepMergedPr | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* Stops the still-live run behind a draft that a newer, also live, same-lineage run supersedes (`--apply` only).
|
|
66
|
+
* Must reject when the run could not be stopped — the draft is then neither labelled nor closed.
|
|
67
|
+
* Absent ⇒ a live duplicate is kept, never closed.
|
|
68
|
+
*/
|
|
69
|
+
supersedeRun?(draft: SweepDraft, repository: string, newer: SweepDraft): Promise<void>;
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
/** Review PASS and gate posture used only by the daily old-draft count. */
|
|
@@ -138,6 +145,19 @@ export interface DraftMetrics {
|
|
|
138
145
|
readonly conversion48h: number | null;
|
|
139
146
|
}
|
|
140
147
|
|
|
148
|
+
/** Default maximum unclaimed open harness drafts for one seat. */
|
|
149
|
+
export const DRAFT_NEEDS_OWNER_SEAT_CAP = 15;
|
|
150
|
+
|
|
151
|
+
/** Compare one seat's observed needsOwner count; the caller supplies counts of open drafts by seat. */
|
|
152
|
+
export function isSeatDraftNeedsOwnerOverCap(
|
|
153
|
+
seat: string,
|
|
154
|
+
needsOwnerBySeat: Readonly<Record<string, number>>,
|
|
155
|
+
cap = DRAFT_NEEDS_OWNER_SEAT_CAP,
|
|
156
|
+
): boolean {
|
|
157
|
+
const count = Object.hasOwn(needsOwnerBySeat, seat) ? needsOwnerBySeat[seat] : undefined;
|
|
158
|
+
return typeof count === 'number' && Number.isFinite(count) && count > cap;
|
|
159
|
+
}
|
|
160
|
+
|
|
141
161
|
export async function collectDraftMetrics(repository: string, adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listRecentClosed' | 'getActiveClaimOwner'>, now: Date): Promise<DraftMetrics> {
|
|
142
162
|
const clock = now.getTime();
|
|
143
163
|
if (!Number.isFinite(clock)) throw new Error('Invalid draft metric clock');
|
|
@@ -444,6 +464,7 @@ const stalledLabel = label('close', 'stalled');
|
|
|
444
464
|
const supersededLabel = label('close', 'superseded');
|
|
445
465
|
const approvalLabel = PR_LABELS.find((entry) => entry.axis === 'state' && entry.sweep.action === 'none')?.name;
|
|
446
466
|
const keepLabel = PR_LABELS.find((entry) => entry.sweep.action === 'exclude')?.name;
|
|
467
|
+
const benchLabel = PR_LABELS.find((entry) => entry.name === 'elanous:bench')!.name;
|
|
447
468
|
const releaseHoldLabel = PR_LABELS.find((entry) => entry.axis === 'addon' && entry.sweep.action === 'none')?.name;
|
|
448
469
|
const harvestableLabel = PR_LABELS.find((entry) => entry.name === 'elanous:harvestable')!.name;
|
|
449
470
|
const PAGE_SIZE = 100;
|
|
@@ -596,9 +617,26 @@ export async function mapBounded<T, R>(items: readonly T[], limit: number, work:
|
|
|
596
617
|
}
|
|
597
618
|
|
|
598
619
|
function harnessDraft(draft: SweepDraft): boolean {
|
|
620
|
+
// BENCH-ISOLATED-ARMS — a bench arm PR is comparison material: the sweep never marks, supersedes or closes it.
|
|
621
|
+
if (draft.labels.includes(benchLabel)) return false;
|
|
599
622
|
return draft.branch.startsWith('self-impl/') || draft.labels.some((name) => name.startsWith('elanous:'));
|
|
600
623
|
}
|
|
601
624
|
|
|
625
|
+
/**
|
|
626
|
+
* The newest open draft of the same goal lineage that was created strictly after `draft` — a rerun
|
|
627
|
+
* (e.g. a forced requeue) of the same goal. Reads only the branch, so a draft with no task card still has a lineage.
|
|
628
|
+
* ⛔ A branch without a goal id has no lineage key and never matches.
|
|
629
|
+
*/
|
|
630
|
+
export function newerLineageDraft(draft: SweepDraft, openDrafts: readonly SweepDraft[]): SweepDraft | undefined {
|
|
631
|
+
const key = branchLineageKey(draft.branch);
|
|
632
|
+
const created = Date.parse(draft.createdAt);
|
|
633
|
+
if (key === null || !Number.isFinite(created)) return undefined;
|
|
634
|
+
return openDrafts
|
|
635
|
+
.filter((pr) => pr.number !== draft.number && branchLineageKey(pr.branch) === key
|
|
636
|
+
&& Number.isFinite(Date.parse(pr.createdAt)) && Date.parse(pr.createdAt) > created)
|
|
637
|
+
.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt) || b.number - a.number)[0];
|
|
638
|
+
}
|
|
639
|
+
|
|
602
640
|
/**
|
|
603
641
|
* Census of harness drafts older than 24h. Same-goal landing uses `sameGoalPr` unchanged.
|
|
604
642
|
* A draft counts as closable when a same-goal merged PR exists, harvestable when review PASS and the gate passed,
|
|
@@ -842,6 +880,71 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
|
|
|
842
880
|
const ageHours = (now.getTime() - Date.parse(draft.createdAt)) / 3_600_000;
|
|
843
881
|
const idleHours = typeof draft.updatedAt === 'string' && Number.isFinite(Date.parse(draft.updatedAt))
|
|
844
882
|
? (now.getTime() - Date.parse(draft.updatedAt)) / 3_600_000 : NaN;
|
|
883
|
+
// A newer open draft of the same goal lineage (a rerun, e.g. a forced requeue) supersedes this one even when
|
|
884
|
+
// its running claim is fresh or its run is still live. Holds, merged twins and the title-based duplicate rule keep their priority.
|
|
885
|
+
const lineageNewer = contradiction || draft.labels.includes(harvestableLabel) ? undefined : newerLineageDraft(draft, drafts);
|
|
886
|
+
if (lineageNewer) {
|
|
887
|
+
const base = decideDraft({ draft, runStatus, mergedTwins: merged, openDrafts: drafts, liveBranches,
|
|
888
|
+
finalRunResult, ageHours: runStatus ? ageHours : idleHours });
|
|
889
|
+
if (!base.reason.startsWith('label:') && !base.reason.startsWith('superseded-by #') && !base.reason.startsWith('duplicate-of-open #')) {
|
|
890
|
+
const live = (status: string | undefined, branch: string) => status === 'running' || status === 'probable-running'
|
|
891
|
+
|| (status !== 'self-implement.result final' && liveBranches.has(branch));
|
|
892
|
+
const runLive = live(runStatus, draft.branch);
|
|
893
|
+
const lineageKey = branchLineageKey(draft.branch);
|
|
894
|
+
const reason = `duplicate-of-open #${lineageNewer.number} (lineage ${lineageKey})${runLive ? ` · stop run ${draft.runId ?? 'unknown'}` : ''}`;
|
|
895
|
+
// Every lineage outcome that does not close falls through to the existing rules (preservation contract):
|
|
896
|
+
// a duplicate this rule cannot settle is decided exactly as it was before this rule existed.
|
|
897
|
+
const fallThrough = (why: string) => {
|
|
898
|
+
try { debug.log('self-dev.draft-sweep', 'lineage-fall-through', { number: draft.number, newer: lineageNewer.number, lineageKey, why }); } catch { /* fail-soft */ }
|
|
899
|
+
};
|
|
900
|
+
if (runLive && !adapters.supersedeRun) fallThrough('lineage-duplicate-run-live');
|
|
901
|
+
// Safety (OP 10-11): a live run is stopped only when the newer run of the same lineage is itself live —
|
|
902
|
+
// never trade a running attempt for one that already ended or was never observed running.
|
|
903
|
+
else if (runLive && !live(statuses.get(lineageNewer.number), lineageNewer.branch)) fallThrough('lineage-newer-run-not-live');
|
|
904
|
+
else if (closes >= closeCap) {
|
|
905
|
+
record({ number: draft.number, action: 'keep', reason: 'close-cap', applied: false });
|
|
906
|
+
continue;
|
|
907
|
+
} else {
|
|
908
|
+
let stopFailed = false;
|
|
909
|
+
// --apply only: the run is stopped before anything is written; a stop that cannot be confirmed writes nothing.
|
|
910
|
+
if (apply && runLive) {
|
|
911
|
+
const observed = { number: draft.number, newer: lineageNewer.number, runId: draft.runId ?? null, newerRunId: lineageNewer.runId ?? null, lineageKey };
|
|
912
|
+
try {
|
|
913
|
+
await adapters.supersedeRun!(draft, repository, lineageNewer);
|
|
914
|
+
try { debug.log('self-dev.draft-sweep', 'supersede-run', observed); } catch { /* fail-soft */ }
|
|
915
|
+
} catch (error) {
|
|
916
|
+
stopFailed = true;
|
|
917
|
+
try { debug.log('self-dev.draft-sweep', 'supersede-run-failed', { ...observed, reason: sweepFailureReason(error) }, { level: 'warn' }); } catch { /* fail-soft */ }
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (stopFailed) fallThrough('supersede-run-failed');
|
|
921
|
+
else {
|
|
922
|
+
// A close is counted against the cap only once it is decided here; a failed write gives the slot back.
|
|
923
|
+
closes += 1;
|
|
924
|
+
const entry: DraftSweepEntry = { number: draft.number, action: 'close', reason, statusLabel: supersededLabel, applied: false };
|
|
925
|
+
record(entry);
|
|
926
|
+
if (!apply) continue;
|
|
927
|
+
let labelsChanged = false;
|
|
928
|
+
try {
|
|
929
|
+
if (!draft.labels.includes(supersededLabel)) {
|
|
930
|
+
await adapters.setLabels(repository, draft.number, {
|
|
931
|
+
add: supersededLabel, remove: states.map((state) => state.name).filter((name) => name !== supersededLabel),
|
|
932
|
+
});
|
|
933
|
+
labelsChanged = true;
|
|
934
|
+
}
|
|
935
|
+
await adapters.closeDraft(repository, draft.number,
|
|
936
|
+
`Draft sweep: ${reason} (https://github.com/${repository}/pull/${lineageNewer.number}). Branch preserved.`);
|
|
937
|
+
entry.applied = true;
|
|
938
|
+
} catch (error) {
|
|
939
|
+
if (labelsChanged) entry.partialApplied = true;
|
|
940
|
+
else closes -= 1;
|
|
941
|
+
entry.error = String(error);
|
|
942
|
+
}
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
845
948
|
// An unobserved claim may still have a merged twin: liveness/holds retain their priority,
|
|
846
949
|
// but a superseded draft must not be hidden by the six-hour claim window.
|
|
847
950
|
const mergedDecision = isClaimed ? decideDraft({ draft, runStatus, mergedTwins: merged, openDrafts: drafts, liveBranches,
|
|
@@ -103,3 +103,9 @@ export function intakeTakesQueue(label: 'queued' | 'direct', route: Pick<Journey
|
|
|
103
103
|
const graphQueues = route.source === 'graph' ? route.to === 'queue' : label === 'queued';
|
|
104
104
|
return graphQueues && eligible;
|
|
105
105
|
}
|
|
106
|
+
|
|
107
|
+
/** 병합 직전 동결 검사의 «승인 요구» — 동결이 아닌(open) 병합을 그래프가 hold 로 보내면 true.
|
|
108
|
+
* ⛔ 그래프가 답을 못 내면(code-default) false — 오늘의 입장 판정 그대로. 동결·선점(frozen·taken)은 이미 코드가 정했다. */
|
|
109
|
+
export function freezeCheckHolds(label: 'open' | 'frozen' | 'taken', route: Pick<JourneyRoute, 'source' | 'to'>): boolean {
|
|
110
|
+
return label === 'open' && route.source === 'graph' && route.to === 'hold';
|
|
111
|
+
}
|
|
@@ -421,6 +421,9 @@ export async function runSelfOrchestrateCliCommand(
|
|
|
421
421
|
await recordRoundPrs(results);
|
|
422
422
|
results = await superviseRun({
|
|
423
423
|
initial: results,
|
|
424
|
+
// The add-repair-task branch below runs each authored review-oscillation repair goal as that goal's new
|
|
425
|
+
// feature (a fresh piece, same goal id) — the supervisor records the repair text, so a second oscillation stops.
|
|
426
|
+
repairGoalExecution: true,
|
|
424
427
|
limits,
|
|
425
428
|
enrich: (rs) => backfillDecomposeProposals([...rs], deps),
|
|
426
429
|
onDecision: (decision) => {
|
|
@@ -431,9 +434,28 @@ export async function runSelfOrchestrateCliCommand(
|
|
|
431
434
|
onRound: (rs) => { try { baseRuntime.checkpoint?.([...rs]); } catch { /* fail-open */ } },
|
|
432
435
|
// ⭐ 방금 끝난 결과를 넘긴다 — orchestrateSelfDev 가 classifyResumeDisposition 으로
|
|
433
436
|
// skip/rerun 을 갈라준다(재발명 0 · 착지한 조각은 다시 안 돈다).
|
|
434
|
-
rerun: async (previous) => {
|
|
437
|
+
rerun: async (previous, invocation) => {
|
|
435
438
|
let addedRepairIds: string[] = [];
|
|
436
|
-
|
|
439
|
+
// A requested repair that cannot be bound to exactly one goal is held (not relaunched with the old strategy).
|
|
440
|
+
const unrepairedHold: string[] = [];
|
|
441
|
+
if (invocation.repairGoals) {
|
|
442
|
+
const replacements = new Map<SelfDevGoal, string>();
|
|
443
|
+
for (const [taskId, repairGoal] of Object.entries(invocation.repairGoals)) {
|
|
444
|
+
const source = previous.find((result) => result.taskId === taskId);
|
|
445
|
+
const matches = source ? currentGoals.filter((goal) => resumeKey(goal.feature) === resumeKey(source.feature)) : [];
|
|
446
|
+
if (matches.length === 1 && !replacements.has(matches[0]!)) replacements.set(matches[0]!, repairGoal);
|
|
447
|
+
else unrepairedHold.push(taskId);
|
|
448
|
+
}
|
|
449
|
+
currentGoals = currentGoals.map((goal) => replacements.has(goal) ? { ...goal, feature: replacements.get(goal)! } : goal);
|
|
450
|
+
spec = buildSelfOrchestrateDevSpec(currentGoals, input.concurrency);
|
|
451
|
+
try {
|
|
452
|
+
debug.log('self-dev.supervisor', 'oscillation-repair.executed', {
|
|
453
|
+
surface: 'orchestrate', replaced: replacements.size, requested: Object.keys(invocation.repairGoals).length, held: unrepairedHold,
|
|
454
|
+
});
|
|
455
|
+
} catch { /* fail-open */ }
|
|
456
|
+
}
|
|
457
|
+
// A review-oscillation decision attaches only its authored repair goals (above) — never deliverable fragments too.
|
|
458
|
+
if (currentDecision?.action === 'add-repair-task' && !currentDecision.oscillation) {
|
|
437
459
|
const appended = appendRepairFragments(currentGoals, currentDecision.classifications, {
|
|
438
460
|
seenFingerprints: repairFingerprints,
|
|
439
461
|
addedCount: repairFragmentsAdded,
|
|
@@ -487,7 +509,7 @@ export async function runSelfOrchestrateCliCommand(
|
|
|
487
509
|
baseRuntime = runtimeWithParentRequest();
|
|
488
510
|
// ⛔⭐ 판정이 「사람이 볼 것」이라 한 조각은 집행이 다시 돌리지 않는다 — 판정과 집행이 갈리면
|
|
489
511
|
// `pr-opened` 조각이 duplicate-risk 로 재실행돼 PR 이 겹친다(2026-09-25 실측).
|
|
490
|
-
const resumeHold = currentDecision?.needsHuman ?? [];
|
|
512
|
+
const resumeHold = [...new Set([...(currentDecision?.needsHuman ?? []), ...unrepairedHold])];
|
|
491
513
|
// The engine's resume lookup is last-result-wins for each normalized feature.
|
|
492
514
|
// Use that exact predecessor, not any earlier task sharing the same feature.
|
|
493
515
|
const selectedPrior = new Map(previous.map((result) => [resumeKey(result.feature), result.taskId]));
|
|
@@ -23,6 +23,7 @@ import { parentUnlandedProgressLine } from './run-supervisor.js';
|
|
|
23
23
|
import { mkdirSync, openSync, writeFileSync, closeSync, renameSync, unlinkSync } from 'node:fs';
|
|
24
24
|
import { join, resolve } from 'node:path';
|
|
25
25
|
import { goalPathFromArgv, launchRegistryDir, removeLaunchBinding, writeLaunchBinding } from '../harness/launch-registry.js';
|
|
26
|
+
import { adoptRunCard } from '../task-agent/run-adopt.js';
|
|
26
27
|
import { availableParallelism, cpus } from 'node:os';
|
|
27
28
|
import { selfDevRunsDir } from './run-store.js';
|
|
28
29
|
import { HARNESS_RUN_ID_ENV, normalizeRunId } from '../harness/harness-space.js';
|
|
@@ -369,6 +370,11 @@ export type TriageAction =
|
|
|
369
370
|
| 'decompose-and-retry'
|
|
370
371
|
/** 기존 조각을 치환하거나 재실행하지 않고 수리 조각을 추가한다. */
|
|
371
372
|
| 'add-repair-task'
|
|
373
|
+
/**
|
|
374
|
+
* main 정합(LLM 충돌 해결)이 막힌 조각을 «조각당 한 번» 최신 main 위에서 다시 건다.
|
|
375
|
+
* 보존 가지는 지우지 않고 재발사 골의 참고로만 쓴다. 두 번째부터는 `needs-human`.
|
|
376
|
+
*/
|
|
377
|
+
| 'relaunch-on-main'
|
|
372
378
|
/** 실패가 아니었다(전송 불일치) — 건드리지 않는다. */
|
|
373
379
|
| 'no-action'
|
|
374
380
|
/** 모른다 — 사람이 본다. */
|
|
@@ -386,7 +392,11 @@ export interface FailureClassification {
|
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
/** 순수: 분류 → 다음 행동. ⛔ 한 자리에서만 정한다(소비자가 각자 매핑하면 갈린다). */
|
|
389
|
-
export function triageActionFor(
|
|
395
|
+
export function triageActionFor(
|
|
396
|
+
kind: FailureKind,
|
|
397
|
+
/** `main-sync-blocked` 만 읽는다 — 이 조각의 재발사 한 번을 이미 썼으면 true. */
|
|
398
|
+
options: { mainSyncRelaunchSpent?: boolean } = {},
|
|
399
|
+
): TriageAction {
|
|
390
400
|
switch (kind) {
|
|
391
401
|
case 'transient': return 'rerun';
|
|
392
402
|
case 'blocked-upstream': return 'rerun-after-upstream';
|
|
@@ -396,14 +406,22 @@ export function triageActionFor(kind: FailureKind): TriageAction {
|
|
|
396
406
|
case 'deliverable-broken':
|
|
397
407
|
case 'oversized-goal': return 'add-repair-task';
|
|
398
408
|
case 'false-failure': return 'no-action';
|
|
409
|
+
case 'main-sync-blocked': return options.mainSyncRelaunchSpent === true ? 'needs-human' : 'relaunch-on-main';
|
|
399
410
|
case 'awaiting-human':
|
|
400
411
|
case 'parent-unlanded':
|
|
401
|
-
case 'main-sync-blocked':
|
|
402
412
|
case 'provider-rejected': return 'needs-human';
|
|
403
413
|
default: return 'needs-human';
|
|
404
414
|
}
|
|
405
415
|
}
|
|
406
416
|
|
|
417
|
+
/**
|
|
418
|
+
* main 정합 충돌로 멈춘 결과만 «최신 main 위 재발사» 후보다. harvestable 이라도 다른 단계(timed-out 등)에서
|
|
419
|
+
* 멈춘 결과는 후보가 아니다 — 지금처럼 사람이 수확한다.
|
|
420
|
+
*/
|
|
421
|
+
export function isMainSyncRelaunchCandidate(result: Pick<SelfDevJobResult, 'stage'>): boolean {
|
|
422
|
+
return result.stage === 'merge-conflict';
|
|
423
|
+
}
|
|
424
|
+
|
|
407
425
|
const LEDGER_FAILURE_KIND: Partial<Record<AbandonedClassification, FailureKind>> = {
|
|
408
426
|
'implementation-deficit': 'unconverged',
|
|
409
427
|
'report-deficit': 'unconverged',
|
|
@@ -588,6 +606,8 @@ export function failureFromDeployFindings(
|
|
|
588
606
|
export function classifyFailures(
|
|
589
607
|
results: SelfDevJobResult[],
|
|
590
608
|
queryPreflight?: PreflightLogQuery,
|
|
609
|
+
/** 이 조각이 main 정합 재발사 한 번을 이미 썼나 — 생략은 «감독 없음» 이라 종전대로 needs-human. */
|
|
610
|
+
mainSyncRelaunchSpent?: (result: SelfDevJobResult) => boolean,
|
|
591
611
|
): FailureClassification[] {
|
|
592
612
|
return results.flatMap((result) => {
|
|
593
613
|
const preflightIdentifiers = [...new Set([result.runId, result.taskId].filter((id): id is string => Boolean(id)))];
|
|
@@ -603,7 +623,10 @@ export function classifyFailures(
|
|
|
603
623
|
taskId: result.taskId,
|
|
604
624
|
stage: result.stage ?? null,
|
|
605
625
|
kind,
|
|
606
|
-
action: triageActionFor(kind
|
|
626
|
+
action: triageActionFor(kind, {
|
|
627
|
+
// 생략 = 감독 없이 도는 경로(재발사할 주체가 없다) — 종전대로 needs-human. 재발사는 감독이 이력으로 셀 때만.
|
|
628
|
+
mainSyncRelaunchSpent: !isMainSyncRelaunchCandidate(result) || !mainSyncRelaunchSpent || mainSyncRelaunchSpent(result) === true,
|
|
629
|
+
}),
|
|
607
630
|
...(awaitingHuman ?? failureObservationFields(error?.code ?? 'UNKNOWN', error?.message ?? '')),
|
|
608
631
|
}];
|
|
609
632
|
});
|
|
@@ -651,8 +674,12 @@ export function triageRun(
|
|
|
651
674
|
hasUnmeasuredDeliverables = false,
|
|
652
675
|
/** Optional injected lookup of launch preflight observations; absence remains unknown. */
|
|
653
676
|
queryPreflight?: PreflightLogQuery,
|
|
677
|
+
/** 이 조각이 main 정합 재발사 한 번을 이미 썼나 — 생략은 «감독 없음» 이라 종전대로 needs-human. */
|
|
678
|
+
mainSyncRelaunchSpent?: (result: SelfDevJobResult) => boolean,
|
|
654
679
|
): {
|
|
655
680
|
classifications: FailureClassification[];
|
|
681
|
+
/** ⭐ main 정합이 막힌 조각 중 «첫 번» — 사람 수확 대신 최신 main 위에서 다시 건다. */
|
|
682
|
+
relaunchOnMain: string[];
|
|
656
683
|
/** 그대로 다시 걸면 되는 조각(일시적·상류대기). */
|
|
657
684
|
rerunnable: string[];
|
|
658
685
|
/** 다시 걸 수는 있으나 같은 결과일 수 있는 조각(수렴 실패). */
|
|
@@ -678,21 +705,23 @@ export function triageRun(
|
|
|
678
705
|
failureFromDeployFindings(taskId, observation.target, observation.findings));
|
|
679
706
|
const classifications = [
|
|
680
707
|
...deployClassifications,
|
|
681
|
-
...classifyFailures(results, queryPreflight),
|
|
708
|
+
...classifyFailures(results, queryPreflight, mainSyncRelaunchSpent),
|
|
682
709
|
];
|
|
683
710
|
const pick = (a: TriageAction) => classifications.filter((c) => c.action === a).map((c) => c.taskId);
|
|
684
711
|
const rerunnable = [...pick('rerun'), ...pick('rerun-after-upstream')];
|
|
685
712
|
const reworkable = pick('rework');
|
|
686
713
|
const decomposable = pick('decompose-and-retry');
|
|
687
714
|
const repairable = [...new Set(pick('add-repair-task'))]; // ⛔ finding 이 여럿이면 같은 taskId 가 겹친다
|
|
715
|
+
const relaunchOnMain = [...new Set(pick('relaunch-on-main'))];
|
|
688
716
|
return {
|
|
689
717
|
classifications,
|
|
718
|
+
relaunchOnMain,
|
|
690
719
|
rerunnable,
|
|
691
720
|
reworkable,
|
|
692
721
|
decomposable,
|
|
693
722
|
repairable,
|
|
694
723
|
needsHuman: pick('needs-human'),
|
|
695
|
-
actionable: rerunnable.length + reworkable.length + decomposable.length + repairable.length > 0,
|
|
724
|
+
actionable: rerunnable.length + reworkable.length + decomposable.length + repairable.length + relaunchOnMain.length > 0,
|
|
696
725
|
deliverableUnmeasured,
|
|
697
726
|
};
|
|
698
727
|
}
|
|
@@ -897,7 +926,11 @@ export function writeRunPidRecord(runId: string, runsDir: string = selfDevRunsDi
|
|
|
897
926
|
const cwd = process.cwd();
|
|
898
927
|
const goalPath = goalPathFromArgv(process.argv, cwd);
|
|
899
928
|
writeLaunchBinding(runId, { pid: process.pid, startedAt: Date.now() - Math.floor(process.uptime() * 1000), argv0: process.argv0,
|
|
900
|
-
cwd, ...(goalPath ? { goalPath } : {}), runsDir: resolve(runsDir)
|
|
929
|
+
cwd, ...(goalPath ? { goalPath } : {}), runsDir: resolve(runsDir),
|
|
930
|
+
...(process.env.ELANOUS_POD_NAME ? { podName: process.env.ELANOUS_POD_NAME } : {}),
|
|
931
|
+
...(process.env.ELANOUS_TASK_CARD_ID ? { taskCardId: process.env.ELANOUS_TASK_CARD_ID } : {}) }, registryDir);
|
|
932
|
+
try { adoptRunCard({ runId, cwd, goalPath, runsDir, env: process.env }); }
|
|
933
|
+
catch (error) { try { debug.log('task-agent', 'run-adopt-failed', { runId, error: String(error) }); } catch { /* launch must continue */ } }
|
|
901
934
|
}
|
|
902
935
|
return pidPath;
|
|
903
936
|
}
|
|
@@ -1381,6 +1414,8 @@ export function orchestrateSelfDev(opts: OrchestrateSelfDevOptions): Promise<Sel
|
|
|
1381
1414
|
...(disp?.completionDisposition ? { completionDisposition: disp.completionDisposition } : {}),
|
|
1382
1415
|
...(disp?.failureClassification ? { failureClassification: disp.failureClassification } : {}),
|
|
1383
1416
|
...(disp?.providerErrors ? { providerErrors: disp.providerErrors } : {}),
|
|
1417
|
+
...(disp?.rework ? { rework: disp.rework } : {}),
|
|
1418
|
+
...(disp?.mustFix ? { reviewMustFix: disp.mustFix } : {}),
|
|
1384
1419
|
...(goalCauseObservedFromFailureClassification(disp?.failureClassification) === true
|
|
1385
1420
|
? { goalCauseObserved: true } : {}),
|
|
1386
1421
|
...(disp?.runId ? { runId: disp.runId } : {}),
|