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
|
@@ -34,6 +34,7 @@ import { isWorktreeInUse, listActiveTerminalDirectories } from '../harness/harne
|
|
|
34
34
|
import { readWorktreePorcelain } from './abandoned-classification.js';
|
|
35
35
|
import { recordHarnessWorktreeGoalMetadata, recordHarnessWorktreeProvenance, type HarnessWorktreeGoalMetadata } from '../harness/harness-worktree-add.js';
|
|
36
36
|
import { runGitCommand } from '../git-fs/runner.js';
|
|
37
|
+
import { BENCH_LABEL, BENCH_LOG_CATEGORY, benchIdFromBase, parseBenchArmBranch } from '../bench/bench.js';
|
|
37
38
|
import { provisionDerivedUniverse } from '../instance/provision.js';
|
|
38
39
|
import { DEFAULT_GATE_STEPS, runIntegrityGate, type GateResult, type GateStepName } from '../autopilot/build/integrity-gate.js';
|
|
39
40
|
import { androidFilesIn, runAndroidUnitTestGate } from '../../scripts/ci-android-unit-tests.js';
|
|
@@ -94,6 +95,7 @@ import { isSupervisorDecisionSection, splitGoalSections, supervisorGoalDigest }
|
|
|
94
95
|
import type { SupervisionReworkSource } from './supervision-vocabulary.js';
|
|
95
96
|
import type { ReworkBudgetVerdict } from './run-outcome.js';
|
|
96
97
|
import { pickImplementRoleForGoal, runHeadlessGoalLoopPty } from './headless-elanous-driver.js';
|
|
98
|
+
import { isClaudeAcpChild, runClaudeAcpImplement } from './claude-acp-implement.js';
|
|
97
99
|
import { childLlmSelectionEnv } from '../agent/run-context.js';
|
|
98
100
|
import { observeExternalEvent } from '../context-bus/external-events.js';
|
|
99
101
|
import { buildLlmHitlRelay, SIDE_EFFECT_RE } from '../harness/llm-hitl-relay.js';
|
|
@@ -1067,6 +1069,8 @@ export interface DefaultSeamsOptions {
|
|
|
1067
1069
|
buildLlmHitlRelay?: typeof buildLlmHitlRelay;
|
|
1068
1070
|
/** 테스트용 PTY executor 주입. */
|
|
1069
1071
|
runHeadlessGoalLoopPty?: typeof runHeadlessGoalLoopPty;
|
|
1072
|
+
/** CLAUDE-IMPL-LANE 시험 주입 — claude-acp 자식의 구독 ACP 구현 실행. */
|
|
1073
|
+
runClaudeAcpImplement?: typeof runClaudeAcpImplement;
|
|
1070
1074
|
/** 테스트용 PTY 가용성 주입. */
|
|
1071
1075
|
ptyAvailable?: () => boolean;
|
|
1072
1076
|
/** Tests may inject the shared provenance writer to exercise the self-implement failure contract. */
|
|
@@ -1367,6 +1371,8 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
|
|
|
1367
1371
|
const removeCleanupWorktree = o.removeWorktree ?? removeWorktree;
|
|
1368
1372
|
const runCleanupGitCommand = o.runGitCommand ?? runGitCommand;
|
|
1369
1373
|
const baselineRefs = new Map<string, string>();
|
|
1374
|
+
// BENCH-ISOLATED-ARMS — 벤치 base(`bench/<id>/base`) 위에서 만든 작업 트리 → bench id.
|
|
1375
|
+
const benchWorktrees = new Map<string, string>();
|
|
1370
1376
|
const gateVerifyOrdinals = new Map<string, number>();
|
|
1371
1377
|
const gateVerifyIdentity = (runId: string | undefined) => {
|
|
1372
1378
|
if (!runId?.trim()) return { runId: runId === undefined ? null : runId, ordinal: null };
|
|
@@ -1535,6 +1541,18 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
|
|
|
1535
1541
|
defaultBranchRef,
|
|
1536
1542
|
// ★ G2(2026-07-21) — 호출부가 해석한 대상만 PR 직전에 정합한다.
|
|
1537
1543
|
mergeMain: async (worktreePath, mergeTarget) => {
|
|
1544
|
+
// BENCH-ISOLATED-ARMS ③ — 벤치 팔은 main 에 정합하지 않는다: 판정은 고정 base 위 게이트·시험·리뷰.
|
|
1545
|
+
// ⭐ 표지는 둘 중 하나 — 이 프로세스가 벤치 base 로 만든 트리이거나, 트리 가지가 `bench/<id>/<arm>` 이다
|
|
1546
|
+
// (재개 프로세스는 앞의 Map 이 비어 있으므로 가지 이름으로 다시 안다).
|
|
1547
|
+
const benchArm = benchWorktrees.has(worktreePath) ? undefined : (() => {
|
|
1548
|
+
const head = runGitCommand(worktreePath, ['rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf8', timeout: GIT_TIMEOUT });
|
|
1549
|
+
return head.status === 0 ? parseBenchArmBranch(String(head.stdout).trim()) : null;
|
|
1550
|
+
})();
|
|
1551
|
+
const benchId = benchWorktrees.get(worktreePath) ?? benchArm?.id;
|
|
1552
|
+
if (benchId) {
|
|
1553
|
+
debug.log(BENCH_LOG_CATEGORY, 'main-sync-skipped', { benchId, worktreePath, mergeTarget, source: benchWorktrees.has(worktreePath) ? 'base' : 'branch' });
|
|
1554
|
+
return { status: 'up-to-date' as const };
|
|
1555
|
+
}
|
|
1538
1556
|
const { mergeMainIntoWorktreeWithLlm } = await import('../autopilot/build/llm-conflict-merge.js');
|
|
1539
1557
|
return mergeMainIntoWorktreeWithLlm(worktreePath, mergeTarget);
|
|
1540
1558
|
},
|
|
@@ -1586,6 +1604,8 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
|
|
|
1586
1604
|
...(runId ? { currentOwner: `dev:${runId}` } : {}),
|
|
1587
1605
|
});
|
|
1588
1606
|
if (r.resolvedBase) baselineRefs.set(r.path, r.resolvedBase);
|
|
1607
|
+
const benchId = benchIdFromBase(base);
|
|
1608
|
+
if (benchId) benchWorktrees.set(r.path, benchId);
|
|
1589
1609
|
const provenance = runId ? {
|
|
1590
1610
|
owner: `dev:${runId}`,
|
|
1591
1611
|
command: 'elanous dev',
|
|
@@ -1686,6 +1706,28 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
|
|
|
1686
1706
|
...(runId ? { runId } : {}),
|
|
1687
1707
|
});
|
|
1688
1708
|
const prompt = featurePrompt(feature, cwd, o.reviewerContext);
|
|
1709
|
+
// CLAUDE-IMPL-LANE — claude-acp 는 PTY 자식(`elanous chat` → getProvider)으로 보내지 않는다:
|
|
1710
|
+
// 거기서는 모델 이름(claude-…)이 anthropic(API 키 provider)으로 풀려 «구독» 런이 API 로 과금된다(#26277 보류 판독).
|
|
1711
|
+
// 구독 ACP 구현기만 쓰고, 구독 확인이 안 되면 실패로 끝낸다(다른 공급자로 조용히 새지 않는다).
|
|
1712
|
+
if (isClaudeAcpChild(childLlm)) {
|
|
1713
|
+
const outcome = await (o.runClaudeAcpImplement ?? runClaudeAcpImplement)({
|
|
1714
|
+
cwd, prompt, ...(childLlm?.model ? { model: childLlm.model } : {}), ...(runId ? { runId } : {}),
|
|
1715
|
+
});
|
|
1716
|
+
if (outcome.kind === 'refused') {
|
|
1717
|
+
debug.log('self-implement', 'implement.result', { reached: false, changed: false, transport: 'claude-acp', refused: outcome.reason, ...(runId ? { runId } : {}) });
|
|
1718
|
+
return { ok: false, summary: `claude-acp 구현 레인 거부: ${outcome.reason}` };
|
|
1719
|
+
}
|
|
1720
|
+
const changed = worktreeHasChanges(cwd, harnessSeededPaths ?? []);
|
|
1721
|
+
// 도구 호출 수 = 허가를 요청한 호출(허가 ⊕ 거부) — ACP 는 읽기 전용 호출 일부를 묻지 않으니 하한이다.
|
|
1722
|
+
const toolCalls = outcome.result.allowed + outcome.result.denied;
|
|
1723
|
+
debug.log('self-implement', 'implement.result', { reached: true, changed, toolCalls, transport: 'claude-acp', allowed: outcome.result.allowed, denied: outcome.result.denied, ...(runId ? { runId } : {}) });
|
|
1724
|
+
return {
|
|
1725
|
+
ok: changed,
|
|
1726
|
+
...buildImplementReport(outcome.result.text, { changed, toolCalls, reached: true, timedOut: false }),
|
|
1727
|
+
toolCalls,
|
|
1728
|
+
terminalStatus: { reached: true, changed, toolCalls, timedOut: false },
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1689
1731
|
// S4 P2b/P3: input은 관측만 하며, done만 config와 stall 확증을 모두 만족할 때 부모 대기를 끝낸다.
|
|
1690
1732
|
// 이 종료-보고 규칙은 self-implement child에만 적용한다. 범용 brain의 기본 프롬프트를 바꾸지 않는다.
|
|
1691
1733
|
const brain = createSelfImplementControlBrain({ goal: feature });
|
|
@@ -2436,7 +2478,11 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
|
|
|
2436
2478
|
commitMessage: title,
|
|
2437
2479
|
...(resolvedBase ? { base: resolvedBase } : {}),
|
|
2438
2480
|
...(draft !== undefined ? { draft } : {}),
|
|
2439
|
-
|
|
2481
|
+
// BENCH-ISOLATED-ARMS ② — base 가 `bench/<id>/base` 면 라벨 `elanous:bench` 를 더한다.
|
|
2482
|
+
...(() => {
|
|
2483
|
+
const all = benchIdFromBase(resolvedBase) && !labels?.includes(BENCH_LABEL) ? [...(labels ?? []), BENCH_LABEL] : labels;
|
|
2484
|
+
return all?.length ? { labels: all } : {};
|
|
2485
|
+
})(),
|
|
2440
2486
|
});
|
|
2441
2487
|
if (!outcome.ok) throw new Error(`self-implement PR ${outcome.reason} 실패: ${outcome.detail}`);
|
|
2442
2488
|
const number = Number.parseInt(outcome.url.match(/\/pull\/(\d+)/)?.[1] ?? '', 10);
|
|
@@ -120,6 +120,8 @@ export function singleRunAsJobResult(feature: string, r: SelfImplementResultWith
|
|
|
120
120
|
...(r.abandonedClassification?.classification
|
|
121
121
|
? { failureClassification: r.abandonedClassification.classification } : {}),
|
|
122
122
|
...(r.decomposeProposal ? { decomposeProposal: r.decomposeProposal } : {}),
|
|
123
|
+
...(r.rework ? { rework: r.rework } : {}),
|
|
124
|
+
...(r.review?.reviewed && r.review.mustFix?.length ? { reviewMustFix: r.review.mustFix } : {}),
|
|
123
125
|
...(r.goalPlanRevision ? { goalPlanRevision: r.goalPlanRevision } : {}),
|
|
124
126
|
...(r.salvage !== undefined ? { salvage: r.salvage } : {}),
|
|
125
127
|
...(r.review?.reviewed === true && r.review.verdict === 'pass'
|
|
@@ -240,8 +242,10 @@ export async function runSelfImplementCliCommand(
|
|
|
240
242
|
}
|
|
241
243
|
: undefined;
|
|
242
244
|
|
|
245
|
+
const initialJob = singleRunAsJobResult(feature, result);
|
|
243
246
|
await superviseRun({
|
|
244
|
-
initial: [
|
|
247
|
+
initial: [initialJob],
|
|
248
|
+
repairGoalExecution: true,
|
|
245
249
|
limits,
|
|
246
250
|
...(deliverableEye ? { observeDeliverables: deliverableEye } : {}),
|
|
247
251
|
...(opts.supervise.onDecision ? { onDecision: opts.supervise.onDecision } : {}),
|
|
@@ -250,11 +254,12 @@ export async function runSelfImplementCliCommand(
|
|
|
250
254
|
},
|
|
251
255
|
// ⛔ 단일의 「다시 걸기」는 «같은 골을 다시»다 — 연합의 resumeFrom 과 다르다.
|
|
252
256
|
// ⇒ 그래서 판정은 «같고» 집행만 여기서 안다(superviseRun 은 그것을 모른다).
|
|
253
|
-
rerun: async () => {
|
|
254
|
-
const
|
|
257
|
+
rerun: async (_, invocation) => {
|
|
258
|
+
const repairGoal = invocation.repairGoals?.[initialJob.taskId];
|
|
259
|
+
const next = await exec(repairGoal ? { ...spec, input: { ...spec.input, text: repairGoal } } : spec, pipelineDeps ? { pipelineDeps } : undefined);
|
|
255
260
|
result = next.result;
|
|
256
261
|
exitCode = next.exitCode;
|
|
257
|
-
return [singleRunAsJobResult(feature, next.result)];
|
|
262
|
+
return [{ ...singleRunAsJobResult(feature, next.result), taskId: initialJob.taskId }];
|
|
258
263
|
},
|
|
259
264
|
});
|
|
260
265
|
}
|
|
@@ -15,12 +15,19 @@
|
|
|
15
15
|
* evidence-uncovered → derive-evidence-rejudge 런 출력·시험·배선에서 증거를 끌어내 1회 재판정
|
|
16
16
|
* review-repeat · review-out-of-scope · fabric · launch-failed · unclassified → needs-owner(새 라운드 없음)
|
|
17
17
|
*
|
|
18
|
+
* 사다리의 «출처»: `graphs/overlays/stop-heal-ladder.yaml` 이 갈래마다 처방 노드(id = 처방 이름)를 선언한다.
|
|
19
|
+
* 그 갈래에 얹힌 오버레이가 더한 노드 id 가 처방이다(source='graph'). 선언이 없거나 못 읽으면
|
|
20
|
+
* 위 표(`AUTOHEAL_ACTION_BY_CLASS`)로 간다(source='code-default'). 둘이 같은 답을 내는지는 시험이 문다.
|
|
21
|
+
*
|
|
18
22
|
* 모드 `tools.selfImplement.autoheal.mode` = `shadow`(기본: 할 일을 원장에만 적고 손대지 않는다) | `live`.
|
|
19
23
|
* ⛔ live 에서도 행동은 주입 seam 으로만 한다 — seam 이 없는 행동은 `needs-owner`(action-unwired)로 떨어진다.
|
|
20
24
|
* «안 이어진 손»을 「고쳤다」로 읽지 않게.
|
|
21
25
|
* 관측 = `debug.log('self-implement.autoheal', …)` ⊕ 원장 `event='autoheal'`.
|
|
22
26
|
*/
|
|
23
27
|
import { debug } from '../debug/log.js';
|
|
28
|
+
import { applyGraphOverlays, defaultOverlaysDir, loadGraphOverlays, selectOverlays, type GraphOverlaySpec } from './graph-overlay-yaml.js';
|
|
29
|
+
import type { GraphTemplateSpec } from './graph-yaml.js';
|
|
30
|
+
import { GRAPH_SPECS } from './graph-templates.js';
|
|
24
31
|
import { appendRunLedgerEntry, loadRunLedger, type RunLedgerEntry, type RunLedgerWriter } from './run-ledger.js';
|
|
25
32
|
import type { RunStopClass, RunStopRecord } from './run-stop.js';
|
|
26
33
|
|
|
@@ -48,6 +55,58 @@ export const AUTOHEAL_ACTION_BY_CLASS: Readonly<Record<RunStopClass, AutohealAct
|
|
|
48
55
|
unclassified: 'needs-owner',
|
|
49
56
|
};
|
|
50
57
|
|
|
58
|
+
/** 처방 노드 id 로 인정하는 이름 — 오버레이가 더한 노드 중 이 넷만 처방으로 읽는다. */
|
|
59
|
+
const HEAL_ACTION_NODE_IDS: ReadonlySet<string> = new Set<Exclude<AutohealAction, 'needs-owner'>>([
|
|
60
|
+
'clean-workspace-regate', 'rebase-regate', 'resume-from-salvage', 'derive-evidence-rejudge',
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
/** 처방이 «어디서» 왔나 — `graph` = 그 갈래에 얹힌 오버레이가 더한 노드 · `code-default` = 위 표. */
|
|
64
|
+
export type AutohealActionSource = 'graph' | 'code-default';
|
|
65
|
+
|
|
66
|
+
export interface AutohealPick {
|
|
67
|
+
action: AutohealAction;
|
|
68
|
+
source: AutohealActionSource;
|
|
69
|
+
/** source='graph' 일 때 그 처방 노드를 더한 오버레이. */
|
|
70
|
+
overlayId?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 사다리를 읽어 오는 자리 — 활성 템플릿 선언 ⊕ 오버레이 목록. 시험이 갈아 끼운다. */
|
|
74
|
+
export interface AutohealLadder {
|
|
75
|
+
template: GraphTemplateSpec | undefined;
|
|
76
|
+
overlays: readonly GraphOverlaySpec[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function loadDefaultLadder(): AutohealLadder {
|
|
80
|
+
return { template: GRAPH_SPECS['self-implement'], overlays: loadGraphOverlays(defaultOverlaysDir()).overlays };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 갈래 → 처방. 그 `stop_class` 에 얹힌 오버레이가 활성 템플릿에 더한 처방 노드 id 를 고른다.
|
|
85
|
+
* ⛔ 오버레이가 없거나 · 조건 키가 없거나 · 로드·적용이 실패하거나 · 처방 노드가 정확히 하나가 아니면
|
|
86
|
+
* «조용히» 코드 표로 간다 — 그 사실은 `source` 가 말한다. 던지지 않는다.
|
|
87
|
+
*/
|
|
88
|
+
export function pickAutohealAction(cls: RunStopClass, loadLadder: () => AutohealLadder = loadDefaultLadder): AutohealPick {
|
|
89
|
+
const codeDefault: AutohealPick = { action: AUTOHEAL_ACTION_BY_CLASS[cls] ?? 'needs-owner', source: 'code-default' };
|
|
90
|
+
try {
|
|
91
|
+
const { template, overlays } = loadLadder();
|
|
92
|
+
if (!template) return codeDefault;
|
|
93
|
+
const { applied } = selectOverlays(overlays, { graphId: template.graphId, stage: 'heal', state: { stop_class: cls } });
|
|
94
|
+
const declared = new Set(template.nodes.map((node) => node.nodeId));
|
|
95
|
+
for (const overlay of applied) {
|
|
96
|
+
const result = applyGraphOverlays(template, [overlay]);
|
|
97
|
+
if (!result.ok) {
|
|
98
|
+
observe('overlay-rejected', { stopClass: cls, overlayId: overlay.overlayId, rejections: result.rejections.map((r) => r.kind) });
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const added = result.template.nodes.map((node) => node.nodeId).filter((id) => !declared.has(id) && HEAL_ACTION_NODE_IDS.has(id));
|
|
102
|
+
if (added.length === 1) return { action: added[0] as AutohealAction, source: 'graph', overlayId: overlay.overlayId };
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
observe('ladder-unreadable', { stopClass: cls, error: error instanceof Error ? error.message : String(error) });
|
|
106
|
+
}
|
|
107
|
+
return codeDefault;
|
|
108
|
+
}
|
|
109
|
+
|
|
51
110
|
/** 설정 원값 → 모드. 모르는 값은 «좁은 쪽»(shadow). */
|
|
52
111
|
export function parseAutohealMode(raw: unknown): AutohealMode {
|
|
53
112
|
return raw === 'live' ? 'live' : 'shadow';
|
|
@@ -84,6 +143,10 @@ export interface AutohealResult {
|
|
|
84
143
|
runId: string;
|
|
85
144
|
class: RunStopClass;
|
|
86
145
|
action: AutohealAction;
|
|
146
|
+
/** 처방을 «어디서» 골랐나 — 그래프 선언 또는 코드 표. */
|
|
147
|
+
source: AutohealActionSource;
|
|
148
|
+
/** source='graph' 일 때 처방 노드를 더한 오버레이. */
|
|
149
|
+
overlayId?: string;
|
|
87
150
|
mode: AutohealMode;
|
|
88
151
|
outcome: AutohealOutcome;
|
|
89
152
|
/** needs-owner 일 때 사람이 볼 이유(멈춘 원인 그대로 또는 행동 실패). */
|
|
@@ -98,6 +161,8 @@ export interface AutohealDeps {
|
|
|
98
161
|
/** 가드용 원장 읽기 — 기본 `loadRunLedger(runId)`. null = 원장 없음(첫 시도). */
|
|
99
162
|
loadLedger?: (runId: string) => readonly RunLedgerEntry[] | null;
|
|
100
163
|
writeLedger?: RunLedgerWriter;
|
|
164
|
+
/** 사다리 선언 읽기 — 기본은 활성 템플릿 ⊕ `graphs/overlays`. 던지면 코드 표로 간다. */
|
|
165
|
+
loadLadder?: () => AutohealLadder;
|
|
101
166
|
}
|
|
102
167
|
|
|
103
168
|
/**
|
|
@@ -128,8 +193,8 @@ function observe(event: string, data: Record<string, unknown>): void {
|
|
|
128
193
|
export async function autohealFromStop(ctx: AutohealContext, deps: AutohealDeps = {}): Promise<AutohealResult> {
|
|
129
194
|
const mode = deps.mode ?? DEFAULT_AUTOHEAL_MODE;
|
|
130
195
|
const cls = ctx.record.class;
|
|
131
|
-
const action =
|
|
132
|
-
const base = { runId: ctx.runId, class: cls, action, mode };
|
|
196
|
+
const { action, source, overlayId } = pickAutohealAction(cls, deps.loadLadder);
|
|
197
|
+
const base = { runId: ctx.runId, class: cls, action, source, ...(overlayId ? { overlayId } : {}), mode };
|
|
133
198
|
|
|
134
199
|
let ledger: readonly RunLedgerEntry[] | null = null;
|
|
135
200
|
try {
|
|
@@ -145,6 +210,8 @@ export async function autohealFromStop(ctx: AutohealContext, deps: AutohealDeps
|
|
|
145
210
|
return { ...base, outcome: 'already-attempted' };
|
|
146
211
|
}
|
|
147
212
|
|
|
213
|
+
observe('action-source', { stopClass: cls, action, source, overlayId: overlayId ?? null });
|
|
214
|
+
|
|
148
215
|
let outcome: AutohealOutcome;
|
|
149
216
|
let reason: string | undefined;
|
|
150
217
|
let detail: string | undefined;
|
|
@@ -225,7 +225,8 @@ export function providerNamesFromFallbackChain(chain: readonly string[]): string
|
|
|
225
225
|
const out: string[] = [];
|
|
226
226
|
const seen = new Set<string>();
|
|
227
227
|
for (const step of chain) {
|
|
228
|
-
|
|
228
|
+
// `codex-credits`(체인 마지막 칸 · 크레딧)도 provider 는 openai-codex 다 — 이미 앞에 있으면 중복이라 빠진다.
|
|
229
|
+
const name = step === 'grok' ? 'grok' : step === 'codex-rotate' || step === 'codex-credits' ? 'openai-codex' : undefined;
|
|
229
230
|
if (!name || seen.has(name)) continue;
|
|
230
231
|
seen.add(name);
|
|
231
232
|
out.push(name);
|
package/src/steward/launch.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { closeSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { join
|
|
3
|
+
import { join } from 'node:path';
|
|
4
4
|
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
5
|
-
import { resolveHqLaunchSeat } from '../hq/seats.js';
|
|
5
|
+
import { installedCliArgv, resolveHqLaunchSeat } from '../hq/seats.js';
|
|
6
6
|
import { debug } from '../debug/log.js';
|
|
7
7
|
import { publishInsideEvent } from '../nexus/api/inside-events.js';
|
|
8
8
|
import { redactSecrets } from '../task-cards/card-store.js';
|
|
@@ -56,7 +56,7 @@ const DEFAULT_POOL = 'pool-node-b@node-b:8';
|
|
|
56
56
|
// `harness budget --json` outcomes: proceed | next-provider | wait-reset | stop. next-provider still runs (the harness switches provider itself).
|
|
57
57
|
const BUDGET_PROCEED: readonly string[] = ['proceed', 'next-provider'];
|
|
58
58
|
const launchMode = (settings: StewardSettings): 'off' | 'shadow' | 'live' => launchModeOf(settings.mode ?? settings.launch ?? 'shadow');
|
|
59
|
-
const cli = (args: string[]) => [
|
|
59
|
+
const cli = (args: string[]) => installedCliArgv([...(process.env.NODE_ENV === 'test' ? ['--test'] : []), ...args]);
|
|
60
60
|
const sourceOf = (issue: TriageIssue): string => /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1] ?? `linear:${issue.identifier}`;
|
|
61
61
|
const promptOf = (issue: TriageIssue): string => `${issue.title}\n${issue.body.slice(0, 1500)}`;
|
|
62
62
|
const argvFor = (issue: TriageIssue, settings: StewardSettings): string[] =>
|
|
@@ -108,7 +108,8 @@ function stewardLaunchSeat(): string {
|
|
|
108
108
|
return resolveHqLaunchSeat('OP', getElanousConfigDir());
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
/** Read commands run in the registered OP seat as well: the tree this module was loaded from may be a stale clone. */
|
|
112
|
+
function runCommand(args: string[], cwd = stewardLaunchSeat()): { exitCode: number; stdout: string; stderr: string } {
|
|
112
113
|
const result = Bun.spawnSync(args, { cwd, stdout: 'pipe', stderr: 'pipe' });
|
|
113
114
|
return { exitCode: result.exitCode, stdout: result.stdout.toString(), stderr: result.stderr.toString() };
|
|
114
115
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { debug } from '../debug/log.js';
|
|
3
3
|
import type { TriageDecision, TriageIssue } from './triage.js';
|
|
4
|
+
import { InvalidWorkingBackwardsDraft } from './working-backwards.js';
|
|
4
5
|
|
|
5
6
|
export interface HashedTriageDecision extends TriageDecision {
|
|
6
7
|
inputHash: string;
|
|
@@ -125,3 +126,64 @@ export async function triageWithinBudget({ issues, previous, judge, tracks, conc
|
|
|
125
126
|
debug.log('steward.triage', 'budget', stats);
|
|
126
127
|
return { decisions, stats };
|
|
127
128
|
}
|
|
129
|
+
|
|
130
|
+
export interface CarriedDraft<T> {
|
|
131
|
+
wish: T;
|
|
132
|
+
/** `deadline` = never started before the stage deadline; `timeout` = per-item or stage deadline hit mid-draft. */
|
|
133
|
+
reason: 'timeout' | 'deadline' | 'error';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type DraftOutcome<T> = { kind: 'drafted' } | { kind: 'invalid' } | { kind: 'carried'; reason: CarriedDraft<T>['reason'] };
|
|
137
|
+
|
|
138
|
+
export async function draftWithinBudget<T>({ wishes, draft, concurrency = 4, perItemMs = 120_000, deadlineMs = 240_000, now = Date.now }: {
|
|
139
|
+
wishes: T[];
|
|
140
|
+
/** `expired` rejects once this item's own deadline passes; drafts should race their slow calls against it. */
|
|
141
|
+
draft: (wish: T, expired: Promise<never>) => Promise<void>;
|
|
142
|
+
concurrency?: number;
|
|
143
|
+
perItemMs?: number;
|
|
144
|
+
deadlineMs?: number;
|
|
145
|
+
now?: () => number;
|
|
146
|
+
}): Promise<{ drafted: T[]; carried: Array<CarriedDraft<T>>; invalid: T[]; stats: { drafted: number; carried: number; invalid: number } }> {
|
|
147
|
+
const end = now() + deadlineMs;
|
|
148
|
+
const slots = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 4;
|
|
149
|
+
const outcomes: Array<DraftOutcome<T> | undefined> = new Array(wishes.length);
|
|
150
|
+
let stageTimer: ReturnType<typeof setTimeout> | undefined;
|
|
151
|
+
const stageExpired = new Promise<void>(resolve => { stageTimer = setTimeout(resolve, Math.max(0, end - now())); });
|
|
152
|
+
const timedOut = Symbol('draft-timeout');
|
|
153
|
+
let cursor = 0;
|
|
154
|
+
const worker = async (): Promise<void> => {
|
|
155
|
+
while (cursor < wishes.length) {
|
|
156
|
+
const remaining = end - now();
|
|
157
|
+
if (remaining <= 0) return;
|
|
158
|
+
const index = cursor++;
|
|
159
|
+
let itemTimer: ReturnType<typeof setTimeout> | undefined;
|
|
160
|
+
const expired = new Promise<never>((_, reject) => { itemTimer = setTimeout(() => reject(timedOut), Math.min(perItemMs, remaining)); });
|
|
161
|
+
// The draft may finish without ever racing this promise — never leave its rejection unhandled.
|
|
162
|
+
expired.catch(() => undefined);
|
|
163
|
+
const work = Promise.resolve().then(() => draft(wishes[index]!, expired));
|
|
164
|
+
const settled = work.then(() => undefined, () => undefined);
|
|
165
|
+
try {
|
|
166
|
+
await Promise.race([work, expired]);
|
|
167
|
+
outcomes[index] = { kind: 'drafted' };
|
|
168
|
+
} catch (error) {
|
|
169
|
+
outcomes[index] = error instanceof InvalidWorkingBackwardsDraft ? { kind: 'invalid' }
|
|
170
|
+
: { kind: 'carried', reason: error === timedOut ? 'timeout' : 'error' };
|
|
171
|
+
// A timed-out draft keeps its concurrency slot until the underlying call settles or the stage ends.
|
|
172
|
+
await Promise.race([settled, stageExpired]);
|
|
173
|
+
} finally { if (itemTimer) clearTimeout(itemTimer); }
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
try {
|
|
177
|
+
await Promise.all(Array.from({ length: Math.min(slots, wishes.length) }, () => worker()));
|
|
178
|
+
} finally { if (stageTimer) clearTimeout(stageTimer); }
|
|
179
|
+
const result = { drafted: [] as T[], carried: [] as Array<CarriedDraft<T>>, invalid: [] as T[] };
|
|
180
|
+
for (const [index, wish] of wishes.entries()) {
|
|
181
|
+
const outcome = outcomes[index];
|
|
182
|
+
if (outcome?.kind === 'drafted') result.drafted.push(wish);
|
|
183
|
+
else if (outcome?.kind === 'invalid') result.invalid.push(wish);
|
|
184
|
+
else result.carried.push({ wish, reason: outcome?.kind === 'carried' ? outcome.reason : 'deadline' });
|
|
185
|
+
}
|
|
186
|
+
const stats = { drafted: result.drafted.length, carried: result.carried.length, invalid: result.invalid.length };
|
|
187
|
+
debug.log('steward.triage', 'draft-budget', stats);
|
|
188
|
+
return { ...result, stats };
|
|
189
|
+
}
|
package/src/steward/triage.ts
CHANGED
|
@@ -8,6 +8,10 @@ import { getUserConfig } from '../user-config.js';
|
|
|
8
8
|
import { emitDecision } from '../live/detail-switch.js';
|
|
9
9
|
import { debug, redactSecretText } from '../debug/log.js';
|
|
10
10
|
import { loopEvent } from '../loops/observe.js';
|
|
11
|
+
import { checkLoops, daemonScheduleEntries, entriesFromRegistry, extendHealthyLauncher, launcherEvidence, notifyOwners, scheduleFindings, versionEvidence, type CheckEntry } from '../loops/checker.js';
|
|
12
|
+
import { listSchedules, schedulesDbPath, type ScheduleRow } from '../domains/schedule-registry.js';
|
|
13
|
+
import { Database } from 'bun:sqlite';
|
|
14
|
+
import { defaultLoopRoot, listAllLoops, listLoops } from '../loops/registry.js';
|
|
11
15
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
12
16
|
import { redactSecrets } from '../task-cards/card-store.js';
|
|
13
17
|
import { directiveHash } from './directive.js';
|
|
@@ -17,7 +21,7 @@ import { planLaunches, launch, collectOutcomes, raiseHitl, readLaunchLedger, sav
|
|
|
17
21
|
import { listFabricExecutionCandidates } from '../self-dev/fabric-plan-core.js';
|
|
18
22
|
import { InvalidWorkingBackwardsDraft, recordWorkingBackwardsOnCards } from './working-backwards.js';
|
|
19
23
|
import { CardStore } from '../task-cards/card-store.js';
|
|
20
|
-
import { triageWithinBudget } from './triage-budget.js';
|
|
24
|
+
import { draftWithinBudget, triageWithinBudget } from './triage-budget.js';
|
|
21
25
|
import { askSteward, classifyIssue, installedCapabilities, planIssues, ruleJudgment, unsafeReason, type ClassifiedIssue, type StewardAsk } from './triage-plan.js';
|
|
22
26
|
import { failureAlertText, markStageStart, markStageEnd, readFailureStreak, shouldAlert, writeFailureStreak, type FailureStreak, type StewardStage } from './failure-streak.js';
|
|
23
27
|
|
|
@@ -59,6 +63,8 @@ export interface StewardDeps {
|
|
|
59
63
|
ask?: StewardAsk;
|
|
60
64
|
/** Maximum time for each working-backwards wish draft in schedule (milliseconds). */
|
|
61
65
|
draftItemMs?: number;
|
|
66
|
+
/** Maximum time for the whole wish-drafting phase in schedule (milliseconds); wishes still undrafted are carried. */
|
|
67
|
+
draftDeadlineMs?: number;
|
|
62
68
|
launchSettings?: Pick<StewardSettings, 'mode' | 'launch' | 'maxParallel' | 'podPool'>;
|
|
63
69
|
launchCommand?: LaunchDeps['command'];
|
|
64
70
|
spawnLaunch?: LaunchDeps['spawn'];
|
|
@@ -68,6 +74,9 @@ export interface StewardDeps {
|
|
|
68
74
|
outcomeNotify?: Pick<OutcomeNotifyDeps, 'document' | 'message' | 'worktreeCommand' | 'loadOrigin' | 'loadOrigins'>;
|
|
69
75
|
/** Internal command boundary: the current sync has already claimed this pid. */
|
|
70
76
|
stageOwnedByCommand?: boolean;
|
|
77
|
+
/** Isolated scheduler inventory for this tick; production reads the unified registry. */
|
|
78
|
+
scheduleInventory?: () => CheckEntry[];
|
|
79
|
+
daemonSchedules?: () => ScheduleRow[];
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
/** rescue launches/harvests like live (HQ-SEAT). */
|
|
@@ -314,6 +323,61 @@ function logStageFailure(root: string, stage: StewardStage, reason: string): voi
|
|
|
314
323
|
if (runId) try { rmSync(tickDecisionPath(root, runId), { force: true }); } catch { /* Observation must not change the failure. */ }
|
|
315
324
|
logTickDecision(root, 'failed', `${stage}: ${reason}`);
|
|
316
325
|
}
|
|
326
|
+
const SCHEDULE_CHECK_MS = 15 * 60_000;
|
|
327
|
+
|
|
328
|
+
/** Called by runStewardStage(sync) under its stage slot, never from the checker CLI. */
|
|
329
|
+
async function checkStewardSchedules(root: string, settings: StewardSettings, deps: StewardDeps): Promise<void> {
|
|
330
|
+
const now = (deps.now ?? (() => new Date()))();
|
|
331
|
+
const marker = join(root, 'steward', 'schedule-check.json');
|
|
332
|
+
let previous: { at?: string } = {};
|
|
333
|
+
try { previous = JSON.parse(readFileSync(marker, 'utf8')) as typeof previous; }
|
|
334
|
+
catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
|
|
335
|
+
const elapsed = now.getTime() - Date.parse(previous.at ?? '');
|
|
336
|
+
if (Number.isFinite(elapsed) && elapsed >= 0 && elapsed < SCHEDULE_CHECK_MS) return;
|
|
337
|
+
const inventory = deps.scheduleInventory ?? (() => {
|
|
338
|
+
const repo = deps.root ? process.cwd() : defaultLoopRoot();
|
|
339
|
+
const registryOptions = { now, root: repo, stateRoot: root,
|
|
340
|
+
...(deps.root ? { schedules: [] } : {}) };
|
|
341
|
+
const { entries } = entriesFromRegistry({ now, listAllLoops: () => listAllLoops(registryOptions) });
|
|
342
|
+
const graphs = listLoops(registryOptions);
|
|
343
|
+
const byId = new Map(graphs.map(graph => [graph.id, graph.file]));
|
|
344
|
+
return versionEvidence(launcherEvidence(entries.map(entry => byId.has(entry.id)
|
|
345
|
+
? { ...entry, file: byId.get(entry.id) } : entry), root), repo, root);
|
|
346
|
+
});
|
|
347
|
+
const daemonRows = deps.daemonSchedules ?? (() => {
|
|
348
|
+
const path = deps.root ? join(root, 'schedules.db') : schedulesDbPath();
|
|
349
|
+
if (!existsSync(path)) return [];
|
|
350
|
+
try {
|
|
351
|
+
const db = new Database(path, { readonly: true });
|
|
352
|
+
try { return listSchedules(db); } finally { db.close(); }
|
|
353
|
+
} catch (error) {
|
|
354
|
+
debug.log('steward.schedule-check', 'daemon-inventory-unavailable', { reason: redactSecretText(String(error)) });
|
|
355
|
+
return [];
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
const entries = inventory();
|
|
359
|
+
const seen = new Set(entries.map(entry => entry.id));
|
|
360
|
+
const checked = checkLoops([...entries, ...daemonScheduleEntries(daemonRows(), now).filter(row => !seen.has(row.id))], now);
|
|
361
|
+
const findings = scheduleFindings(checked, now);
|
|
362
|
+
if (settings.mode === 'live') {
|
|
363
|
+
let recovered = 0;
|
|
364
|
+
const unresolved = findings.filter(finding => {
|
|
365
|
+
try {
|
|
366
|
+
if (extendHealthyLauncher(root, finding, now)) { recovered++; return false; }
|
|
367
|
+
} catch (error) {
|
|
368
|
+
debug.log('steward.schedule-check', 'recovery-failed', { id: finding.id, reason: redactSecretText(String(error)) });
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
});
|
|
372
|
+
const remainingChecks = checked.filter(row => unresolved.some(finding => finding.id === row.id && finding.kind === row.state));
|
|
373
|
+
const ownerRequests = notifyOwners(remainingChecks, { root, now }, unresolved);
|
|
374
|
+
const opEscalations = notifyOwners(remainingChecks, { root, now }, unresolved, true);
|
|
375
|
+
debug.log('steward.schedule-check', 'routing', { ownerRequests, opEscalations, recovered });
|
|
376
|
+
}
|
|
377
|
+
debug.log('steward.schedule-check', 'checked', { count: checked.length, findings: findings.length, mode: settings.mode });
|
|
378
|
+
writeFileSync(marker, JSON.stringify({ at: now.toISOString() }));
|
|
379
|
+
}
|
|
380
|
+
|
|
317
381
|
function readState(path: string): { issues: Record<string, string>; digestDay?: string } {
|
|
318
382
|
try { return JSON.parse(readFileSync(path, 'utf8')) as ReturnType<typeof readState>; }
|
|
319
383
|
catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { issues: {} }; throw error; }
|
|
@@ -343,6 +407,11 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
343
407
|
const runId = (graphRunId() ?? process.env.ELANOUS_RUN_ID?.trim()) || `steward-stage-${randomUUID()}`;
|
|
344
408
|
let outcome: 'ok' | 'fail' = 'fail';
|
|
345
409
|
try {
|
|
410
|
+
if (stage === 'sync') {
|
|
411
|
+
// The schedule check is an add-on to sync: its failure is observed, never allowed to stop the Linear sync.
|
|
412
|
+
try { await checkStewardSchedules(root, settings, deps); }
|
|
413
|
+
catch (error) { debug.log('steward.schedule-check', 'failed', { reason: redactSecretText(String(error)) }, { level: 'warn' }); }
|
|
414
|
+
}
|
|
346
415
|
const key = await (deps.getSecret ?? getSecretAsync)('connector.linear.apiKey');
|
|
347
416
|
if (!key) throw new Error('connector.linear.apiKey missing');
|
|
348
417
|
if (stage === 'sync') {
|
|
@@ -420,27 +489,19 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
420
489
|
const carried = new Set<string>();
|
|
421
490
|
if (store) try {
|
|
422
491
|
recordTriageOnCards(wishes, issues, { root, store, now: deps.now });
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (error instanceof InvalidWorkingBackwardsDraft) {
|
|
437
|
-
invalid.add(wish.issue);
|
|
438
|
-
debug.log('steward.stage', 'draft-invalid', { issue: wish.issue });
|
|
439
|
-
} else {
|
|
440
|
-
carried.add(wish.issue);
|
|
441
|
-
debug.log('steward.schedule', 'draft-carried', { issue: wish.issue, reason: error === timedOut ? 'timeout' : 'error' });
|
|
442
|
-
}
|
|
443
|
-
} finally { if (timer) clearTimeout(timer); }
|
|
492
|
+
const outcome = await draftWithinBudget({
|
|
493
|
+
wishes, perItemMs: deps.draftItemMs ?? 120_000, deadlineMs: deps.draftDeadlineMs ?? 240_000,
|
|
494
|
+
// Bound the ask itself so a late answer cannot write to a store closed after this tick.
|
|
495
|
+
draft: (wish, expired) => recordWorkingBackwardsOnCards([wish], issues, store,
|
|
496
|
+
(prompt, role) => Promise.race([(deps.ask ?? askSteward)(prompt, role), expired])),
|
|
497
|
+
});
|
|
498
|
+
for (const wish of outcome.invalid) {
|
|
499
|
+
invalid.add(wish.issue);
|
|
500
|
+
debug.log('steward.stage', 'draft-invalid', { issue: wish.issue });
|
|
501
|
+
}
|
|
502
|
+
for (const { wish, reason } of outcome.carried) {
|
|
503
|
+
carried.add(wish.issue);
|
|
504
|
+
debug.log('steward.schedule', 'draft-carried', { issue: wish.issue, reason });
|
|
444
505
|
}
|
|
445
506
|
} finally { if (!deps.cardStore) store.close(); }
|
|
446
507
|
if (invalid.size || carried.size) rows = rows.map(row => invalid.has(row.issue)
|