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/dashboard/index.ts
CHANGED
|
@@ -11,280 +11,26 @@ import { spawn, spawnSync } from 'node:child_process';
|
|
|
11
11
|
import { $ } from 'bun';
|
|
12
12
|
import { LOCAL_SKILLS_DIR, SERVICE_NAMES, DATA_DIR, OBSIDIAN_VAULT } from '../config.js';
|
|
13
13
|
import { dispatchDashboardSessionRuntimeTool } from './session-runtime-dispatch.js';
|
|
14
|
-
import { buildAdRunSetup } from '../ad-pipeline/ad-run-setup.js';
|
|
15
14
|
import { nextChatScrollOffset } from '../chat/log-scroll-key.js';
|
|
16
|
-
import type { CommandRunner } from '../ad-pipeline/higgsfield-backend.js';
|
|
17
|
-
import type { ShootRunOptions } from '../ad-pipeline/shoot-run.js';
|
|
18
|
-
import type { QcThresholds } from '../ad-pipeline/qc.js';
|
|
19
|
-
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
20
15
|
import { suggestProjectForFolder } from '../project/project-store.js';
|
|
21
16
|
import { createProjectSuggester } from '../project/project-suggestion.js';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
'captionFontPath',
|
|
40
|
-
'musicBedPath',
|
|
41
|
-
'qcThresholds',
|
|
42
|
-
'voiceover',
|
|
43
|
-
'soundtrack',
|
|
44
|
-
'referenceAssets',
|
|
45
|
-
'shootRunOptions',
|
|
46
|
-
'ground',
|
|
47
|
-
'invariants',
|
|
48
|
-
] as const;
|
|
49
|
-
|
|
50
|
-
export interface DashboardAdAssetPreset {
|
|
51
|
-
readonly captionFontPath?: string;
|
|
52
|
-
readonly musicBedPath?: string;
|
|
53
|
-
readonly referenceAssets?: Readonly<Record<string, string[]>>;
|
|
54
|
-
readonly shootRunOptions?: ShootRunOptions;
|
|
55
|
-
readonly qcThresholds?: QcThresholds;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Operator-owned, instance-scoped optional asset preset; never a repository asset path. */
|
|
59
|
-
export function dashboardAdAssetPresetPath(stateRoot = elanousStateRoot()): string {
|
|
60
|
-
return join(stateRoot, 'ad-assets.json');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Reads optional operator-owned asset paths without inventing local defaults. */
|
|
64
|
-
export function loadDashboardAdAssetPreset(path: string): DashboardAdAssetPreset {
|
|
65
|
-
let raw: string;
|
|
66
|
-
try {
|
|
67
|
-
raw = readFileSync(path, 'utf8');
|
|
68
|
-
} catch (error) {
|
|
69
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};
|
|
70
|
-
throw new Error(`dashboard ad asset preset unreadable at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let parsed: unknown;
|
|
74
|
-
try {
|
|
75
|
-
parsed = JSON.parse(raw);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
78
|
-
}
|
|
79
|
-
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
80
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: expected an object`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const preset = parsed as Record<string, unknown>;
|
|
84
|
-
for (const key of ['captionFontPath', 'musicBedPath'] as const) {
|
|
85
|
-
if (preset[key] !== undefined && typeof preset[key] !== 'string') {
|
|
86
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: ${key} must be a string`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (preset.referenceAssets !== undefined && (
|
|
90
|
-
preset.referenceAssets === null
|
|
91
|
-
|| typeof preset.referenceAssets !== 'object'
|
|
92
|
-
|| Array.isArray(preset.referenceAssets)
|
|
93
|
-
|| Object.values(preset.referenceAssets).some((value) => !Array.isArray(value) || value.some((entry) => typeof entry !== 'string'))
|
|
94
|
-
)) {
|
|
95
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: referenceAssets must be a record of string arrays`);
|
|
96
|
-
}
|
|
97
|
-
if (preset.shootRunOptions !== undefined && (
|
|
98
|
-
preset.shootRunOptions === null
|
|
99
|
-
|| typeof preset.shootRunOptions !== 'object'
|
|
100
|
-
|| Array.isArray(preset.shootRunOptions)
|
|
101
|
-
)) {
|
|
102
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: shootRunOptions must be an object`);
|
|
103
|
-
}
|
|
104
|
-
const shootRunOptions = preset.shootRunOptions as Record<string, unknown> | undefined;
|
|
105
|
-
for (const key of ['pollIntervalMs', 'maxPollsPerJob', 'maxPollElapsedMs', 'submitStaggerMs', 'submitRetries'] as const) {
|
|
106
|
-
if (shootRunOptions?.[key] !== undefined && (typeof shootRunOptions[key] !== 'number' || !Number.isFinite(shootRunOptions[key]))) {
|
|
107
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: shootRunOptions.${key} must be a finite number`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (preset.qcThresholds !== undefined && (
|
|
111
|
-
preset.qcThresholds === null
|
|
112
|
-
|| typeof preset.qcThresholds !== 'object'
|
|
113
|
-
|| Array.isArray(preset.qcThresholds)
|
|
114
|
-
)) {
|
|
115
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds must be an object`);
|
|
116
|
-
}
|
|
117
|
-
const qcThresholds = preset.qcThresholds as Record<string, unknown> | undefined;
|
|
118
|
-
for (const key of ['dialogueLufsTolerance', 'colorDistance', 'frameDiffVariance'] as const) {
|
|
119
|
-
if (qcThresholds?.[key] !== undefined && (typeof qcThresholds[key] !== 'number' || !Number.isFinite(qcThresholds[key]))) {
|
|
120
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.${key} must be a finite number`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (qcThresholds?.durationRanges !== undefined && (
|
|
124
|
-
qcThresholds.durationRanges === null
|
|
125
|
-
|| typeof qcThresholds.durationRanges !== 'object'
|
|
126
|
-
|| Array.isArray(qcThresholds.durationRanges)
|
|
127
|
-
)) {
|
|
128
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.durationRanges must be an object`);
|
|
129
|
-
}
|
|
130
|
-
const durationRanges = qcThresholds?.durationRanges as Record<string, unknown> | undefined;
|
|
131
|
-
for (const scope of ['cut', 'master'] as const) {
|
|
132
|
-
if (durationRanges?.[scope] !== undefined && (
|
|
133
|
-
durationRanges[scope] === null
|
|
134
|
-
|| typeof durationRanges[scope] !== 'object'
|
|
135
|
-
|| Array.isArray(durationRanges[scope])
|
|
136
|
-
)) {
|
|
137
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.durationRanges.${scope} must be an object`);
|
|
138
|
-
}
|
|
139
|
-
const range = durationRanges?.[scope] as Record<string, unknown> | undefined;
|
|
140
|
-
if (range !== undefined) {
|
|
141
|
-
const minimumSeconds = range.minimumSeconds;
|
|
142
|
-
const maximumSeconds = range.maximumSeconds;
|
|
143
|
-
if (typeof minimumSeconds !== 'number' || !Number.isFinite(minimumSeconds)) {
|
|
144
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.durationRanges.${scope}.minimumSeconds must be a finite number`);
|
|
145
|
-
}
|
|
146
|
-
if (typeof maximumSeconds !== 'number' || !Number.isFinite(maximumSeconds)) {
|
|
147
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.durationRanges.${scope}.maximumSeconds must be a finite number`);
|
|
148
|
-
}
|
|
149
|
-
if (minimumSeconds > maximumSeconds) {
|
|
150
|
-
throw new Error(`dashboard ad asset preset malformed at ${path}: qcThresholds.durationRanges.${scope}.minimumSeconds must be less than or equal to maximumSeconds`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
...(typeof preset.captionFontPath === 'string' ? { captionFontPath: preset.captionFontPath } : {}),
|
|
156
|
-
...(typeof preset.musicBedPath === 'string' ? { musicBedPath: preset.musicBedPath } : {}),
|
|
157
|
-
...(preset.referenceAssets === undefined ? {} : { referenceAssets: preset.referenceAssets as Record<string, string[]> }),
|
|
158
|
-
...(shootRunOptions === undefined ? {} : { shootRunOptions: shootRunOptions as ShootRunOptions }),
|
|
159
|
-
...(qcThresholds === undefined ? {} : { qcThresholds: qcThresholds as QcThresholds }),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export const dashboardAdCommandRunner: CommandRunner = {
|
|
164
|
-
async run(argv, options) {
|
|
165
|
-
const process = Bun.spawn([...argv], {
|
|
166
|
-
stdout: 'pipe',
|
|
167
|
-
stderr: 'pipe',
|
|
168
|
-
...(options?.timeoutMs ? { timeout: options.timeoutMs } : {}),
|
|
169
|
-
});
|
|
170
|
-
const [raw, stderr, exitCode] = await Promise.all([
|
|
171
|
-
new Response(process.stdout).bytes(),
|
|
172
|
-
new Response(process.stderr).text(),
|
|
173
|
-
process.exited,
|
|
174
|
-
]);
|
|
175
|
-
return { stdout: new TextDecoder().decode(raw), stderr, exitCode, raw };
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export function createDashboardAdRunSetupFactory(input: {
|
|
180
|
-
readonly home: string;
|
|
181
|
-
readonly date: string;
|
|
182
|
-
readonly contractsJson: string;
|
|
183
|
-
readonly runner: CommandRunner;
|
|
184
|
-
readonly assetPresetPath?: string;
|
|
185
|
-
}): (allowSpend: boolean) => ReturnType<typeof buildAdRunSetup> {
|
|
186
|
-
let runSequence = 0;
|
|
187
|
-
let activeRunSlug: string | undefined;
|
|
188
|
-
|
|
189
|
-
return (allowSpend) => {
|
|
190
|
-
if (!allowSpend) {
|
|
191
|
-
const runStart = new Date();
|
|
192
|
-
const time = [runStart.getHours(), runStart.getMinutes(), runStart.getSeconds()]
|
|
193
|
-
.map((part) => String(part).padStart(2, '0'))
|
|
194
|
-
.join('');
|
|
195
|
-
activeRunSlug = `dashboard-ad-${time}-${++runSequence}`;
|
|
196
|
-
}
|
|
197
|
-
const slug = activeRunSlug ?? (() => {
|
|
198
|
-
const runStart = new Date();
|
|
199
|
-
const time = [runStart.getHours(), runStart.getMinutes(), runStart.getSeconds()]
|
|
200
|
-
.map((part) => String(part).padStart(2, '0'))
|
|
201
|
-
.join('');
|
|
202
|
-
return `dashboard-ad-${time}-${++runSequence}`;
|
|
203
|
-
})();
|
|
204
|
-
const assetPreset = input.assetPresetPath === undefined ? {} : loadDashboardAdAssetPreset(input.assetPresetPath);
|
|
205
|
-
let setup = buildAdRunSetup({
|
|
206
|
-
home: input.home,
|
|
207
|
-
slug,
|
|
208
|
-
date: input.date,
|
|
209
|
-
version: 1,
|
|
210
|
-
aspect: '9x16',
|
|
211
|
-
contractsJson: input.contractsJson,
|
|
212
|
-
runner: input.runner,
|
|
213
|
-
...assetPreset,
|
|
214
|
-
referenceAssets: assetPreset.referenceAssets ?? {},
|
|
215
|
-
shootRunOptions: { ...dashboardDefaultShootRunOptions, ...assetPreset.shootRunOptions },
|
|
216
|
-
soundtrack: input.runner,
|
|
217
|
-
voiceover: { runner: input.runner, lines: [] },
|
|
218
|
-
allowSpend,
|
|
219
|
-
});
|
|
220
|
-
if (!('error' in setup) && setup.production) {
|
|
221
|
-
const production = {
|
|
222
|
-
...setup.production,
|
|
223
|
-
assemblyMaterials: { options: { workDir: setup.workDir, outputName: setup.outputName } },
|
|
224
|
-
};
|
|
225
|
-
setup = {
|
|
226
|
-
...setup,
|
|
227
|
-
production,
|
|
228
|
-
missingProductionInputs: dashboardOptionalProductionInputs.filter((key) => production[key] === undefined),
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
return setup;
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** Builds the /ad runtime bindings used by showDashboard for each invocation's spend intent. */
|
|
236
|
-
export function createDashboardAdRunSetupBindings(
|
|
237
|
-
buildDashboardAdRunSetup: ReturnType<typeof createDashboardAdRunSetupFactory>,
|
|
238
|
-
) {
|
|
239
|
-
let adRunSetup: ReturnType<typeof buildAdRunSetup> | undefined;
|
|
240
|
-
let outputSetupError: string | undefined;
|
|
241
|
-
try {
|
|
242
|
-
adRunSetup = buildDashboardAdRunSetup(false);
|
|
243
|
-
outputSetupError = 'error' in adRunSetup ? adRunSetup.error : undefined;
|
|
244
|
-
} catch (error) {
|
|
245
|
-
outputSetupError = error instanceof Error ? error.message : String(error);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return {
|
|
249
|
-
production: adRunSetup && !('error' in adRunSetup) ? adRunSetup.production : undefined,
|
|
250
|
-
productionForSpend: (allowSpend: boolean) => {
|
|
251
|
-
try {
|
|
252
|
-
const setup = buildDashboardAdRunSetup(allowSpend);
|
|
253
|
-
if ('error' in setup) {
|
|
254
|
-
outputSetupError = setup.error;
|
|
255
|
-
return undefined;
|
|
256
|
-
}
|
|
257
|
-
return setup.production;
|
|
258
|
-
} catch (error) {
|
|
259
|
-
outputSetupError = error instanceof Error ? error.message : String(error);
|
|
260
|
-
return undefined;
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
missingProductionInputs: adRunSetup && !('error' in adRunSetup) ? adRunSetup.missingProductionInputs : undefined,
|
|
264
|
-
get outputSetupError() {
|
|
265
|
-
return outputSetupError;
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/** Connects the dashboard's setup state to the actual /ad runtime. */
|
|
271
|
-
export function createDashboardAdSlashRuntime(
|
|
272
|
-
input: Omit<DashboardAdSlashRuntimeDeps, 'production' | 'productionForSpend' | 'missingProductionInputs' | 'outputSetupError'> & {
|
|
273
|
-
readonly adRunSetupBindings?: ReturnType<typeof createDashboardAdRunSetupBindings>;
|
|
274
|
-
readonly adRunSetupError?: string;
|
|
275
|
-
},
|
|
276
|
-
): DashboardAdSlashRuntime {
|
|
277
|
-
const { adRunSetupBindings, adRunSetupError, ...deps } = input;
|
|
278
|
-
return createAdSlashRuntime({
|
|
279
|
-
...deps,
|
|
280
|
-
production: adRunSetupBindings?.production,
|
|
281
|
-
productionForSpend: adRunSetupBindings?.productionForSpend,
|
|
282
|
-
missingProductionInputs: adRunSetupBindings?.missingProductionInputs,
|
|
283
|
-
get outputSetupError() {
|
|
284
|
-
return adRunSetupBindings?.outputSetupError ?? adRunSetupError;
|
|
285
|
-
},
|
|
286
|
-
});
|
|
287
|
-
}
|
|
17
|
+
import {
|
|
18
|
+
createDashboardAdRunSetupBindings,
|
|
19
|
+
createDashboardAdRunSetupFactory,
|
|
20
|
+
createDashboardAdSlashRuntime,
|
|
21
|
+
dashboardAdAssetPresetPath,
|
|
22
|
+
dashboardAdCommandRunner,
|
|
23
|
+
} from './ad-run-setup-bindings.js';
|
|
24
|
+
export {
|
|
25
|
+
dashboardOptionalProductionInputs,
|
|
26
|
+
type DashboardAdAssetPreset,
|
|
27
|
+
dashboardAdAssetPresetPath,
|
|
28
|
+
loadDashboardAdAssetPreset,
|
|
29
|
+
dashboardAdCommandRunner,
|
|
30
|
+
createDashboardAdRunSetupFactory,
|
|
31
|
+
createDashboardAdRunSetupBindings,
|
|
32
|
+
createDashboardAdSlashRuntime,
|
|
33
|
+
} from './ad-run-setup-bindings.js';
|
|
288
34
|
|
|
289
35
|
export interface DashboardGlobalKeyRegistration {
|
|
290
36
|
id: string;
|
|
@@ -1005,11 +751,7 @@ import { createDashboardControlSignalSlashRuntime } from './control-signal-slash
|
|
|
1005
751
|
import { createDashboardBrowserCdpSlashRuntime } from './browser-cdp-slash-runtime.js';
|
|
1006
752
|
import { collectGroundingFactsViaCdp } from '../product-grounding/cdp-collect.js';
|
|
1007
753
|
import { createDashboardSimSlashRuntime } from './sim-slash-runtime.js';
|
|
1008
|
-
import {
|
|
1009
|
-
createDashboardAdSlashRuntime as createAdSlashRuntime,
|
|
1010
|
-
type DashboardAdSlashRuntime,
|
|
1011
|
-
type DashboardAdSlashRuntimeDeps,
|
|
1012
|
-
} from './ad-slash-runtime.js';
|
|
754
|
+
import type { DashboardAdSlashRuntime } from './ad-slash-runtime.js';
|
|
1013
755
|
import { openDashboardLocalSimulationWebCockpit } from './sim-web-cockpit-runtime.js';
|
|
1014
756
|
import { createDashboardCompanionFeedbackRuntime } from './companion-feedback-runtime.js';
|
|
1015
757
|
import { resolveDashboardMediaSlash } from './media-slash-runtime.js';
|
|
@@ -12,6 +12,17 @@ export type StaleInstallResult = {
|
|
|
12
12
|
|
|
13
13
|
export const STALE_INSTALL_CHECK_INTERVAL_MS = 60_000;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Builds the command that relaunches the TUI on the same daemon session: `elanous --resume <id>` boots the dashboard,
|
|
17
|
+
* loads that session (ACP session/load) and replays its turns (src/index.ts resumeSessionId · dashboard acp-boot).
|
|
18
|
+
* The user-facing hint and its key binding land with the dashboard wiring slice (`r` is the render toggle today).
|
|
19
|
+
* Intentional wiring boundary: the dashboard owns the key binding and executes this command;
|
|
20
|
+
* this scoped helper only constructs it and does not spawn a child process.
|
|
21
|
+
*/
|
|
22
|
+
export function buildStaleInstallRelaunchCommand(sessionId: string): string {
|
|
23
|
+
return `elanous --resume ${JSON.stringify(sessionId)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export function formatStaleInstallNotice(result: StaleInstallResult, notifiedCount: number): string {
|
|
16
27
|
const message = `새 판이 깔렸습니다 (부팅 판 ${result.bootCommit!.slice(0, 7)} → 지금 ${result.installedCommit!.slice(0, 7)}) · TUI 를 다시 띄우면 새 판으로 돕니다`;
|
|
17
28
|
return notifiedCount >= 2 ? `${message} · 이 TUI 가 뜬 뒤 ${notifiedCount}번째 새 판` : message;
|
package/src/debug/log-diet.ts
CHANGED
|
@@ -2,6 +2,13 @@ import type { DebugEvent } from './log.js';
|
|
|
2
2
|
|
|
3
3
|
export const LOG_DIET_WINDOW_MS = 60_000;
|
|
4
4
|
|
|
5
|
+
/** LOG-DIET-2 — minimum spacing between two `log.diet/suppressed` summary releases.
|
|
6
|
+
* One diet window: a folded stream costs at most one summary row per window instead of one per flush. */
|
|
7
|
+
export const LOG_DIET_SUMMARY_MIN_INTERVAL_MS = LOG_DIET_WINDOW_MS;
|
|
8
|
+
|
|
9
|
+
/** LOG-DIET-2 — pending-stream pressure that releases summaries before the interval elapses. */
|
|
10
|
+
export const LOG_DIET_SUMMARY_MAX_PENDING = 256;
|
|
11
|
+
|
|
5
12
|
export const LOG_DIET_KEYS: Readonly<Record<string, 'repeat' | 'consecutive'>> = {
|
|
6
13
|
'watchdog/activity': 'consecutive',
|
|
7
14
|
'user-config.llm/provider-resolved': 'repeat',
|
|
@@ -9,6 +16,11 @@ export const LOG_DIET_KEYS: Readonly<Record<string, 'repeat' | 'consecutive'>> =
|
|
|
9
16
|
'input.cursor.claim/chat-main': 'repeat',
|
|
10
17
|
'tox.loop/waiting-capacity': 'repeat',
|
|
11
18
|
'tox.loop/tick': 'repeat',
|
|
19
|
+
'llm.credential/provider-key-missing': 'repeat',
|
|
20
|
+
'llm.credential/provider-key-resolved': 'repeat',
|
|
21
|
+
'pty.manifest/output-bytes-flushed': 'repeat',
|
|
22
|
+
// `pod-lease/admit-by-usage` is NOT folded: dispatch backpressure and the TA parent-host admission
|
|
23
|
+
// read it back from logs and count rows (`admissionCounts`) — it is a judgment-path event.
|
|
12
24
|
};
|
|
13
25
|
|
|
14
26
|
export interface LogDietSummary {
|
|
@@ -57,14 +69,20 @@ export class LogDietGuard {
|
|
|
57
69
|
private readonly now: () => number;
|
|
58
70
|
private readonly keys: Readonly<Record<string, Policy>>;
|
|
59
71
|
private readonly maxStreams: number;
|
|
72
|
+
private readonly summaryMinIntervalMs: number;
|
|
73
|
+
private readonly summaryMaxPending: number;
|
|
60
74
|
private readonly disabled: boolean;
|
|
61
75
|
private readonly streams = new Map<string, Stream>();
|
|
76
|
+
private lastSummaryReleaseAt = Number.NEGATIVE_INFINITY;
|
|
77
|
+
private pendingStreams = 0;
|
|
62
78
|
|
|
63
|
-
constructor(opts: { windowMs?: number; now?: () => number; keys?: Readonly<Record<string, Policy>>; maxStreams?: number } = {}) {
|
|
79
|
+
constructor(opts: { windowMs?: number; now?: () => number; keys?: Readonly<Record<string, Policy>>; maxStreams?: number; summaryMinIntervalMs?: number; summaryMaxPending?: number } = {}) {
|
|
64
80
|
this.windowMs = opts.windowMs ?? LOG_DIET_WINDOW_MS;
|
|
65
81
|
this.now = opts.now ?? Date.now;
|
|
66
82
|
this.keys = opts.keys ?? LOG_DIET_KEYS;
|
|
67
83
|
this.maxStreams = Math.max(1, opts.maxStreams ?? 2000);
|
|
84
|
+
this.summaryMinIntervalMs = Math.max(0, opts.summaryMinIntervalMs ?? LOG_DIET_SUMMARY_MIN_INTERVAL_MS);
|
|
85
|
+
this.summaryMaxPending = Math.max(1, opts.summaryMaxPending ?? LOG_DIET_SUMMARY_MAX_PENDING);
|
|
68
86
|
this.disabled = process.env.ELANOUS_LOG_DIET === 'off';
|
|
69
87
|
}
|
|
70
88
|
|
|
@@ -84,8 +102,9 @@ export class LogDietGuard {
|
|
|
84
102
|
|
|
85
103
|
admit(rec: DietRecord): { pass: boolean; summaries: LogDietSummary[] } {
|
|
86
104
|
const policy = this.keys[`${rec.category}/${rec.event}`];
|
|
105
|
+
// LOG-DIET-2 — a registered key folds at warn too; unregistered warn/error/critical alarms never fold.
|
|
87
106
|
if (this.disabled || !policy || rec.category === 'log.diet'
|
|
88
|
-
|| rec.level === '
|
|
107
|
+
|| rec.level === 'error' || rec.level === 'critical') {
|
|
89
108
|
return { pass: true, summaries: [] };
|
|
90
109
|
}
|
|
91
110
|
|
|
@@ -108,6 +127,7 @@ export class LogDietGuard {
|
|
|
108
127
|
this.streams.delete(key); // Evict the least recently observed flow.
|
|
109
128
|
this.streams.set(key, stream);
|
|
110
129
|
if ((policy === 'repeat' || stream.value === value) && time - stream.lastEmittedAt < this.windowMs) {
|
|
130
|
+
if (stream.count === 0) this.pendingStreams++;
|
|
111
131
|
stream.count++;
|
|
112
132
|
const at = new Date(time).toISOString();
|
|
113
133
|
stream.firstSuppressedAt ??= at;
|
|
@@ -115,7 +135,7 @@ export class LogDietGuard {
|
|
|
115
135
|
return { pass: false, summaries };
|
|
116
136
|
}
|
|
117
137
|
const pending = this.summary(stream);
|
|
118
|
-
if (pending) summaries.push(pending);
|
|
138
|
+
if (pending) { summaries.push(pending); this.pendingStreams--; }
|
|
119
139
|
stream.count = 0;
|
|
120
140
|
stream.firstSuppressedAt = undefined;
|
|
121
141
|
stream.lastSuppressedAt = undefined;
|
|
@@ -128,7 +148,7 @@ export class LogDietGuard {
|
|
|
128
148
|
const oldestKey = this.streams.keys().next().value!;
|
|
129
149
|
const oldest = this.streams.get(oldestKey)!;
|
|
130
150
|
const pending = this.summary(oldest);
|
|
131
|
-
if (pending) summaries.push(pending);
|
|
151
|
+
if (pending) { summaries.push(pending); this.pendingStreams--; }
|
|
132
152
|
this.streams.delete(oldestKey);
|
|
133
153
|
}
|
|
134
154
|
this.streams.set(key, { category: rec.category, event: rec.event,
|
|
@@ -138,8 +158,12 @@ export class LogDietGuard {
|
|
|
138
158
|
return { pass: true, summaries };
|
|
139
159
|
}
|
|
140
160
|
|
|
141
|
-
/** Emit pending counts without reopening the current sample windows.
|
|
142
|
-
|
|
161
|
+
/** Emit pending counts without reopening the current sample windows.
|
|
162
|
+
* LOG-DIET-2 — releases are spaced by `summaryMinIntervalMs` unless forced (drain)
|
|
163
|
+
* or the pending-stream pressure cap is hit. Deferred counts stay accumulated on
|
|
164
|
+
* their streams, so a held-back release never drops a suppressed event. */
|
|
165
|
+
flushPending(force = false): LogDietSummary[] {
|
|
166
|
+
if (!force && !this.summaryReleaseDue()) return [];
|
|
143
167
|
const summaries: LogDietSummary[] = [];
|
|
144
168
|
for (const stream of this.streams.values()) {
|
|
145
169
|
const pending = this.summary(stream);
|
|
@@ -148,11 +172,18 @@ export class LogDietGuard {
|
|
|
148
172
|
stream.firstSuppressedAt = undefined;
|
|
149
173
|
stream.lastSuppressedAt = undefined;
|
|
150
174
|
}
|
|
175
|
+
this.pendingStreams = 0;
|
|
176
|
+
this.lastSummaryReleaseAt = this.now();
|
|
151
177
|
return summaries;
|
|
152
178
|
}
|
|
153
179
|
|
|
180
|
+
private summaryReleaseDue(): boolean {
|
|
181
|
+
if (this.pendingStreams >= this.summaryMaxPending) return true;
|
|
182
|
+
return this.now() - this.lastSummaryReleaseAt >= this.summaryMinIntervalMs;
|
|
183
|
+
}
|
|
184
|
+
|
|
154
185
|
drain(): LogDietSummary[] {
|
|
155
|
-
const summaries = this.flushPending();
|
|
186
|
+
const summaries = this.flushPending(true);
|
|
156
187
|
this.streams.clear();
|
|
157
188
|
return summaries;
|
|
158
189
|
}
|
package/src/debug/log.ts
CHANGED
|
@@ -561,6 +561,24 @@ class DebugLog {
|
|
|
561
561
|
for (const summary of summaries) this.log('log.diet', 'suppressed', summary);
|
|
562
562
|
}
|
|
563
563
|
|
|
564
|
+
/** LOG-DIET-2 — summaries are now spaced by the diet window, so a short-lived process could exit
|
|
565
|
+
* holding folded counts. On the first suppression we arm one exit drain that force-releases them
|
|
566
|
+
* (and flushes the sinks synchronously) so a held-back release never drops a count at shutdown. */
|
|
567
|
+
private _logDietExitArmed = false;
|
|
568
|
+
private armLogDietExitDrain(): void {
|
|
569
|
+
if (this._logDietExitArmed) return;
|
|
570
|
+
this._logDietExitArmed = true;
|
|
571
|
+
const drain = (): void => { try { this.drainLogDietPending(); } catch { /* exit path must not throw */ } };
|
|
572
|
+
process.once('beforeExit', drain);
|
|
573
|
+
process.once('exit', drain);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/** Force-release every pending diet summary (ignores the summary interval) and flush sinks. */
|
|
577
|
+
drainLogDietPending(): void {
|
|
578
|
+
if (this._logDietGuard) this.emitLogDietSummaries(this._logDietGuard.flushPending(true));
|
|
579
|
+
this.flush();
|
|
580
|
+
}
|
|
581
|
+
|
|
564
582
|
/** Force any buffered events to disk immediately. */
|
|
565
583
|
flush(): void {
|
|
566
584
|
if (this._logDietGuard) this.emitLogDietSummaries(this._logDietGuard.flushPending());
|
|
@@ -615,7 +633,7 @@ class DebugLog {
|
|
|
615
633
|
if (this._logDietGuard) {
|
|
616
634
|
const decision = this._logDietGuard.admit(rec);
|
|
617
635
|
this.emitLogDietSummaries(decision.summaries);
|
|
618
|
-
if (!decision.pass) return;
|
|
636
|
+
if (!decision.pass) { this.armLogDietExitDrain(); return; }
|
|
619
637
|
}
|
|
620
638
|
|
|
621
639
|
// Ring buffer — always populated when at least one sink is live so
|
|
@@ -9,6 +9,7 @@ import { requestConfirmation, type ConfirmOpts, type ConfirmResult } from '../hi
|
|
|
9
9
|
import { devVersion, checklistDevVersion, listChecklist, summarizeChecklist, type Checklist, type ChecklistItem } from '../release-loop/checklist.js';
|
|
10
10
|
import { add, move, validateVersion } from '../release-loop/feature-store.js';
|
|
11
11
|
import { formatKst, formatSchedule, getSchedule, listSchedules, setSchedule, type ReleaseSchedule } from '../release-loop/release-schedule.js';
|
|
12
|
+
import { mergedPrsLast24h as countMergedPrsLast24h } from '../release-loop/placement.js';
|
|
12
13
|
import { latestGraphRun, type GraphRunState } from '../graph-runner/runner.js';
|
|
13
14
|
import { formatElanousCard, type ElanousCard } from './elanous-card.js';
|
|
14
15
|
|
|
@@ -24,6 +25,7 @@ export const RELEASE_STATUS_SPEC: LLMToolSpec = {
|
|
|
24
25
|
parameters: { type: 'object', properties: {
|
|
25
26
|
version: { type: 'string', description: '조회할 판. 생략하면 개발 판과 다음 판.' },
|
|
26
27
|
topic: { type: 'string', enum: ['status', 'features', 'cell', 'schedule', 'ops'], description: '읽을 대상(기본 status).' },
|
|
28
|
+
action: { type: 'string', enum: ['schedule', 'blocked', 'landed'], description: '짧은 읽기 요약: 다음 컷 일정·막힌 칸·최근 24시간 병합 PR.' },
|
|
27
29
|
id: { type: 'string', description: 'topic=cell 때 찾을 칸 id(필수).' },
|
|
28
30
|
}, required: [] },
|
|
29
31
|
};
|
|
@@ -57,6 +59,7 @@ export interface ReleaseToolDeps {
|
|
|
57
59
|
add?: typeof add;
|
|
58
60
|
move?: typeof move;
|
|
59
61
|
setSchedule?: typeof setSchedule;
|
|
62
|
+
mergedPrsLast24h?: (now?: Date) => number;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
function nextVersion(version: string): string {
|
|
@@ -129,6 +132,42 @@ export function dispatchReleaseStatus(args: Record<string, unknown>, deps: Relea
|
|
|
129
132
|
return { text: facts.length ? facts.map(fact => JSON.stringify(fact)).join('\n') : '운영 개관: 관측된 사실 없음', structured: { facts } };
|
|
130
133
|
}
|
|
131
134
|
const dev = checklistDevVersion(deps.devVersion?.() ?? devVersion());
|
|
135
|
+
if (args.action !== undefined) {
|
|
136
|
+
const action = args.action;
|
|
137
|
+
if (typeof action !== 'string' || !['schedule', 'blocked', 'landed'].includes(action)) {
|
|
138
|
+
throw new Error('action 은 schedule, blocked, landed 중 하나여야 합니다');
|
|
139
|
+
}
|
|
140
|
+
if (action === 'schedule') {
|
|
141
|
+
const released = checklist(dev).released;
|
|
142
|
+
const schedules = (deps.schedules ?? listSchedules)()
|
|
143
|
+
.filter(row => requested ? row.version === requested : !released || versionOrder(row.version, released) > 0)
|
|
144
|
+
.sort((a, b) => versionOrder(a.version, b.version));
|
|
145
|
+
const text = schedules.length ? `다음 컷 시각:\n${schedules.map(formatSchedule).join('\n')}` : '다음 컷 시각: 일정 없음';
|
|
146
|
+
debug.log('release.tool', 'status', { action, version: requested ?? dev });
|
|
147
|
+
return { text, structured: { schedules: schedules.map(row => ({ version: row.version, cutAt: row.cutAt, landBy: row.landBy,
|
|
148
|
+
publishAt: row.publishAt ?? null, freezeFrom: row.freezeFrom ?? null, freezeUntil: row.freezeUntil ?? null })) } };
|
|
149
|
+
}
|
|
150
|
+
if (action === 'blocked') {
|
|
151
|
+
const versions = requested ? [requested as string] : [dev, nextVersion(dev)];
|
|
152
|
+
const blocked = versions.flatMap(version => {
|
|
153
|
+
validateVersion(version);
|
|
154
|
+
return checklist(version).items
|
|
155
|
+
.filter(item => item.status === 'red' || (item.status === 'yellow' && item.disposition === 'block'))
|
|
156
|
+
.map(item => ({ version, id: item.id, title: firstLine(item.title), status: item.status, disposition: item.disposition ?? null, owner: item.owner ?? null }));
|
|
157
|
+
});
|
|
158
|
+
const text = blocked.length ? `막힌 칸 ${blocked.length}개:\n${blocked.map(item => `${item.version} · ${item.id} ${item.title} · ${item.status === 'red' ? '빨강' : '보류'}${item.owner ? ` · 담당 ${item.owner}` : ''}`).join('\n')}` : '막힌 칸 없음';
|
|
159
|
+
debug.log('release.tool', 'status', { action, version: requested ?? versions.join(',') });
|
|
160
|
+
return { text, structured: { blocked } };
|
|
161
|
+
}
|
|
162
|
+
const now = deps.now ?? new Date();
|
|
163
|
+
const merged = (deps.mergedPrsLast24h ?? countMergedPrsLast24h)(now);
|
|
164
|
+
debug.log('release.tool', 'status', { action, since: new Date(now.getTime() - 86_400_000).toISOString(), until: now.toISOString(), merged });
|
|
165
|
+
return { text: `어제 착지: 최근 24시간 병합 PR ${merged}건`, structured: {
|
|
166
|
+
mergedPrsLast24h: merged,
|
|
167
|
+
since: new Date(now.getTime() - 86_400_000).toISOString(),
|
|
168
|
+
until: now.toISOString(),
|
|
169
|
+
} };
|
|
170
|
+
}
|
|
132
171
|
if (topic === 'features' || topic === 'cell' || topic === 'schedule') {
|
|
133
172
|
let result: { text: string; structured: Record<string, unknown> };
|
|
134
173
|
if (topic === 'features') {
|
|
@@ -31,7 +31,7 @@ export interface ErrorReport {
|
|
|
31
31
|
at: string; consent: true;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export interface ErrorReportSettings { enabled: boolean; identity: boolean; email?: string; telegramUser?: string }
|
|
34
|
+
export interface ErrorReportSettings { enabled: boolean; identity: boolean; consented?: boolean; email?: string; telegramUser?: string }
|
|
35
35
|
|
|
36
36
|
export interface ErrorReportDeps {
|
|
37
37
|
configDir?: () => string;
|
|
@@ -100,10 +100,18 @@ export function buildErrorReport(input: ErrorReportInput, ctx: { installId: stri
|
|
|
100
100
|
return report;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
/** First-run notice: says what is actually sent — identity fields go along only when errorReports.identity is on. */
|
|
104
|
+
export function errorReportNoticeLine(config: { identity?: boolean; email?: string; telegramUser?: string } | undefined): string {
|
|
105
|
+
const fields = [config?.email ? '이메일' : '', config?.telegramUser ? '텔레그램 사용자' : ''].filter(Boolean).join('·');
|
|
106
|
+
// Mirrors buildErrorReport: a field goes along only when identity is on AND the field is set.
|
|
107
|
+
const who = config?.identity === true && fields ? `진단과 함께 설정된 신원(${fields})을` : '익명 진단을';
|
|
108
|
+
return `오류 보고 안내: 오류 발생 시 ${who} 운영팀에 전송합니다. 끄려면 \`elanous config set errorReports.enabled false\`.`;
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
function defaultSettings(): ErrorReportSettings {
|
|
104
112
|
try {
|
|
105
113
|
const er = getUserConfig().errorReports;
|
|
106
|
-
return { enabled: er?.enabled !== false, identity: er?.identity === true, ...(er?.email ? { email: er.email } : {}), ...(er?.telegramUser ? { telegramUser: er.telegramUser } : {}) };
|
|
114
|
+
return { enabled: er?.enabled !== false, consented: er?.noticeShown === true, identity: er?.identity === true, ...(er?.email ? { email: er.email } : {}), ...(er?.telegramUser ? { telegramUser: er.telegramUser } : {}) };
|
|
107
115
|
} catch { return { enabled: false, identity: false }; }
|
|
108
116
|
}
|
|
109
117
|
|
|
@@ -137,10 +145,17 @@ export async function reportError(input: ErrorReportInput, deps: ErrorReportDeps
|
|
|
137
145
|
if (!settings.enabled) return { sent: false, reason: 'disabled' };
|
|
138
146
|
const now = (deps.now ?? Date.now)();
|
|
139
147
|
const key = `${input.code}\u0000${input.message.slice(0, 200)}`;
|
|
148
|
+
const configDir = (deps.configDir ?? getElanousConfigDir)();
|
|
149
|
+
if (settings.consented !== true) {
|
|
150
|
+
const report = buildErrorReport(input, {
|
|
151
|
+
installId: installId(configDir), settings, nexus: { alive: false }, at: new Date(now).toISOString(),
|
|
152
|
+
});
|
|
153
|
+
keepPending(report, configDir, deps);
|
|
154
|
+
return { sent: false, reason: 'awaiting-notice' };
|
|
155
|
+
}
|
|
140
156
|
const previous = lastSent.get(key);
|
|
141
157
|
if (previous !== undefined && now - previous < SAME_ERROR_GAP_MS) return { sent: false, reason: 'recently-sent' };
|
|
142
158
|
lastSent.set(key, now);
|
|
143
|
-
const configDir = (deps.configDir ?? getElanousConfigDir)();
|
|
144
159
|
const report = buildErrorReport(input, {
|
|
145
160
|
installId: installId(configDir), settings, nexus: await (deps.nexusMeta ?? defaultNexusMeta)(), at: new Date(now).toISOString(),
|
|
146
161
|
});
|
|
@@ -186,7 +201,9 @@ function keepPending(report: ErrorReport, configDir: string, deps: ErrorReportDe
|
|
|
186
201
|
export async function retryPendingErrorReport(deps: ErrorReportDeps = {}): Promise<ReportOutcome> {
|
|
187
202
|
try {
|
|
188
203
|
if (!(deps.enabledByEnvironment ?? defaultEnabledByEnvironment)()) return { sent: false, reason: 'environment' };
|
|
189
|
-
|
|
204
|
+
const settings = (deps.settings ?? defaultSettings)();
|
|
205
|
+
if (!settings.enabled) return { sent: false, reason: 'disabled' };
|
|
206
|
+
if (settings.consented !== true) return { sent: false, reason: 'awaiting-notice' };
|
|
190
207
|
const configDir = (deps.configDir ?? getElanousConfigDir)();
|
|
191
208
|
const file = pendingFile(configDir);
|
|
192
209
|
if (!existsSync(file)) return { sent: false, reason: 'none' };
|
package/src/github/pr-labels.ts
CHANGED
|
@@ -32,6 +32,7 @@ export const PR_LABELS = [
|
|
|
32
32
|
{ name: 'elanous:release-hold', axis: 'addon', color: 'D4C5F9', description: 'Exclude from release notes until verified in production', appliedBy: ['launcher', 'session', 'human'], sweep: { action: 'none' } },
|
|
33
33
|
{ name: 'elanous:idea-stale', axis: 'addon', color: 'FBCA04', description: 'Approval pending beyond the notification threshold', appliedBy: ['sweeper'], sweep: { action: 'notify', afterDays: IDEA_STALE_DAYS } },
|
|
34
34
|
{ name: 'elanous:needs-rebase', axis: 'addon', color: 'E99695', description: 'Approval blocked by conflicts or failing checks', appliedBy: ['sweeper'], sweep: { action: 'block-approval' } },
|
|
35
|
+
{ name: 'elanous:bench', axis: 'addon', color: 'C5DEF5', description: 'Bench arm output: never landed or swept; the owner harvests the winner onto main', appliedBy: ['harness'], sweep: { action: 'none' } },
|
|
35
36
|
{ name: 'elanous:harvestable', axis: 'addon', color: 'FBCA04', description: 'Pod terminal marked this PR for harvest', appliedBy: ['harness'], sweep: { action: 'close', afterHours: STALLED_DRAFT_HOURS } },
|
|
36
37
|
{ name: 'elanous:from-harness', axis: 'origin', color: 'C5DEF5', description: 'Launched from a harness goal', appliedBy: ['harness'], sweep: { action: 'none' } },
|
|
37
38
|
{ name: 'elanous:from-intake', axis: 'origin', color: 'C5DEF5', description: 'Launched from an absorbed idea', appliedBy: ['launcher'], sweep: { action: 'none' } },
|