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
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { debug } from '../src/debug/log.js';
|
|
6
|
+
import { parseTypecheckErrors, tscEnv } from '../src/typecheck-ratchet.js';
|
|
7
|
+
import { compareDiagnostics, normalizeDiagnostics, type NormalizedDiagnostic } from './tsc-baseline-comparison.js';
|
|
8
|
+
|
|
9
|
+
export interface CommandResult {
|
|
10
|
+
status: number | null;
|
|
11
|
+
signal?: NodeJS.Signals | null;
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
error?: Error;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
}
|
|
17
|
+
export type Runner = (command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv) => Promise<CommandResult>;
|
|
18
|
+
export interface Metrics { durationMs: number | null; rssMb: number | null; }
|
|
19
|
+
export interface PrMeasurement {
|
|
20
|
+
pr: number;
|
|
21
|
+
head: string;
|
|
22
|
+
base: string;
|
|
23
|
+
verdict: 'missed' | 'same' | 'stricter' | 'unmeasured';
|
|
24
|
+
missedDiagnostics: NormalizedDiagnostic[];
|
|
25
|
+
addedDiagnostics: NormalizedDiagnostic[];
|
|
26
|
+
fullBase: Metrics;
|
|
27
|
+
fullHead: Metrics;
|
|
28
|
+
narrowed: Metrics;
|
|
29
|
+
gateExitCode: number | null;
|
|
30
|
+
reason?: string;
|
|
31
|
+
worktree: string;
|
|
32
|
+
}
|
|
33
|
+
export interface MeasurementReport {
|
|
34
|
+
prs: PrMeasurement[];
|
|
35
|
+
summary: { missed: number; same: number; stricter: number; unmeasured: number; of: number };
|
|
36
|
+
exitCode: number;
|
|
37
|
+
}
|
|
38
|
+
export interface Options { run?: Runner; platform?: NodeJS.Platform; makeTemp?: () => string; removeTemp?: (path: string) => void; }
|
|
39
|
+
interface Pr { number: number; mergeCommit: { oid: string } | null; files: { path: string }[]; mergedAt?: string; changedFiles?: number; }
|
|
40
|
+
const emptyMetrics = (): Metrics => ({ durationMs: null, rssMb: null });
|
|
41
|
+
const hash = (text: string): boolean => /^[0-9a-f]{40}$/i.test(text);
|
|
42
|
+
const reason = (result: CommandResult): string => result.error?.message ?? (result.stderr.trim() || result.stdout.trim() || `exit ${result.status}`);
|
|
43
|
+
|
|
44
|
+
export const spawnRunner: Runner = (command, args, cwd, extraEnv) => new Promise((done) => {
|
|
45
|
+
const started = performance.now();
|
|
46
|
+
const env = tscEnv({ ...process.env, ...extraEnv });
|
|
47
|
+
delete env.GIT_DIR;
|
|
48
|
+
delete env.GIT_WORK_TREE;
|
|
49
|
+
delete env.GIT_COMMON_DIR;
|
|
50
|
+
let child;
|
|
51
|
+
try { child = spawn(command, args, { cwd, env, stdio: ['ignore', 'pipe', 'pipe'] }); }
|
|
52
|
+
catch (cause) {
|
|
53
|
+
done({ status: null, stdout: '', stderr: '', error: cause instanceof Error ? cause : new Error(String(cause)), durationMs: performance.now() - started });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const stdout: Buffer[] = [];
|
|
57
|
+
const stderr: Buffer[] = [];
|
|
58
|
+
child.stdout.on('data', (chunk: Buffer) => stdout.push(chunk));
|
|
59
|
+
child.stderr.on('data', (chunk: Buffer) => stderr.push(chunk));
|
|
60
|
+
let error: Error | undefined;
|
|
61
|
+
child.on('error', (cause: Error) => { error = cause; });
|
|
62
|
+
child.on('close', (status, signal) => done({ status, signal, stdout: Buffer.concat(stdout).toString(), stderr: Buffer.concat(stderr).toString(), error, durationMs: performance.now() - started }));
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export function parseRss(output: string, platform: NodeJS.Platform): number | null {
|
|
66
|
+
const mac = output.match(/^\s*(\d+)\s+maximum resident set size\s*$/im);
|
|
67
|
+
const linux = output.match(/^\s*Maximum resident set size \(kbytes\):\s*(\d+)\s*$/im);
|
|
68
|
+
const value = platform === 'darwin' ? mac : platform === 'linux' ? linux : null;
|
|
69
|
+
if (!value) return null;
|
|
70
|
+
const bytes = Number(value[1]) * (platform === 'linux' ? 1024 : 1);
|
|
71
|
+
return Number.isSafeInteger(bytes) ? bytes / 1048576 : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function optionsFromArgs(argv: readonly string[]): { numbers: number[] | null; recent: number; keep: boolean } {
|
|
75
|
+
let numbers: number[] | null = null;
|
|
76
|
+
let recent = 10;
|
|
77
|
+
let explicitRecent = false;
|
|
78
|
+
let keep = false;
|
|
79
|
+
for (let i = 0; i < argv.length; i++) {
|
|
80
|
+
const arg = argv[i];
|
|
81
|
+
if (arg === '--prs' || arg === '--recent') {
|
|
82
|
+
const value = argv[++i];
|
|
83
|
+
if (!value) throw new Error(`${arg} requires a value`);
|
|
84
|
+
if (arg === '--prs') {
|
|
85
|
+
if (numbers || explicitRecent || !/^\d+(,\d+)*$/.test(value)) throw new Error('invalid --prs list');
|
|
86
|
+
numbers = value.split(',').map(Number);
|
|
87
|
+
if (numbers.some((n) => !Number.isSafeInteger(n) || n < 1) || new Set(numbers).size !== numbers.length) throw new Error('invalid --prs list');
|
|
88
|
+
} else {
|
|
89
|
+
if (numbers || explicitRecent || !/^\d+$/.test(value)) throw new Error('invalid --recent count');
|
|
90
|
+
recent = Number(value);
|
|
91
|
+
if (!Number.isSafeInteger(recent) || recent < 1) throw new Error('invalid --recent count');
|
|
92
|
+
explicitRecent = true;
|
|
93
|
+
}
|
|
94
|
+
} else if (arg === '--json') continue;
|
|
95
|
+
else if (arg === '--keep') keep = true;
|
|
96
|
+
else throw new Error(`unknown option: ${arg}`);
|
|
97
|
+
}
|
|
98
|
+
return { numbers, recent, keep };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function required(run: Runner, command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<CommandResult> {
|
|
102
|
+
const result = await run(command, args, cwd, env);
|
|
103
|
+
if (result.error || result.signal || result.status !== 0) throw new Error(`${command} ${args.join(' ')}: ${reason(result)}`);
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
function parsePr(value: unknown): Pr {
|
|
107
|
+
if (!value || typeof value !== 'object') throw new Error('invalid PR response');
|
|
108
|
+
const pr = value as Pr;
|
|
109
|
+
if (!Number.isSafeInteger(pr.number) || pr.number < 1 || !pr.mergeCommit || !hash(pr.mergeCommit.oid) || !Array.isArray(pr.files) || !pr.files.every((file) => typeof file?.path === 'string')) throw new Error(`invalid merged PR response: ${JSON.stringify(value)}`);
|
|
110
|
+
return pr;
|
|
111
|
+
}
|
|
112
|
+
const typeScriptFile = (path: string): boolean => /\.[cm]?tsx?$/.test(path);
|
|
113
|
+
/** The list API truncates `files`; when the listed files are fewer than `changedFiles`, read the full paginated list. */
|
|
114
|
+
async function touchesTypeScript(run: Runner, repo: string, pr: Pr): Promise<boolean> {
|
|
115
|
+
if (pr.files.some((file) => typeScriptFile(file.path))) return true;
|
|
116
|
+
if (typeof pr.changedFiles === 'number' && pr.changedFiles <= pr.files.length) return false;
|
|
117
|
+
const all = (await required(run, 'gh', ['api', '--paginate', `repos/{owner}/{repo}/pulls/${pr.number}/files`, '--jq', '.[].filename'], repo)).stdout.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
118
|
+
if (typeof pr.changedFiles === 'number' && all.length < pr.changedFiles) throw new Error(`PR #${pr.number}: file list incomplete (${all.length} of ${pr.changedFiles})`);
|
|
119
|
+
return all.some(typeScriptFile);
|
|
120
|
+
}
|
|
121
|
+
async function selectPrs(repo: string, opts: ReturnType<typeof optionsFromArgs>, run: Runner): Promise<Pr[]> {
|
|
122
|
+
if (opts.numbers) {
|
|
123
|
+
const prs: Pr[] = [];
|
|
124
|
+
for (const n of opts.numbers) {
|
|
125
|
+
const pr = parsePr(JSON.parse((await required(run, 'gh', ['pr', 'view', String(n), '--json', 'number,mergeCommit,files'], repo)).stdout));
|
|
126
|
+
if (pr.number !== n) throw new Error(`requested PR #${n} but received #${pr.number}`);
|
|
127
|
+
prs.push(pr);
|
|
128
|
+
}
|
|
129
|
+
return prs;
|
|
130
|
+
}
|
|
131
|
+
let limit = Math.max(100, opts.recent);
|
|
132
|
+
let previousCount = -1;
|
|
133
|
+
for (;;) {
|
|
134
|
+
const result = await required(run, 'gh', ['pr', 'list', '--state', 'merged', '--base', 'main', '--search', 'sort:merged-desc', '--limit', String(limit), '--json', 'number,mergeCommit,files,mergedAt,changedFiles'], repo);
|
|
135
|
+
const raw: unknown = JSON.parse(result.stdout);
|
|
136
|
+
if (!Array.isArray(raw)) throw new Error('invalid merged PR list');
|
|
137
|
+
if (raw.some((item) => typeof item?.mergedAt !== 'string')) throw new Error('merged PR list has no merge dates');
|
|
138
|
+
const prs: Pr[] = [];
|
|
139
|
+
for (const pr of raw.map(parsePr)) if (await touchesTypeScript(run, repo, pr)) prs.push(pr);
|
|
140
|
+
if (prs.length >= opts.recent || raw.length < limit || raw.length === previousCount) return prs.sort((a, b) => b.mergedAt!.localeCompare(a.mergedAt!)).slice(0, opts.recent);
|
|
141
|
+
previousCount = raw.length;
|
|
142
|
+
limit += 100;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function elapsed(result: CommandResult, platform: NodeJS.Platform): Metrics {
|
|
147
|
+
return { durationMs: Number.isFinite(result.durationMs) ? result.durationMs : null, rssMb: parseRss(result.stderr, platform) };
|
|
148
|
+
}
|
|
149
|
+
function checked(result: CommandResult, label: string, output: string): void {
|
|
150
|
+
if (result.error || result.signal || ![0, 1, 2].includes(result.status ?? -1) || /error TS(?:2688|5083|6053)\b|heap out of memory|Ineffective mark-compacts near heap limit/i.test(output)) throw new Error(`${label}: tsc not measured: ${reason(result)}`);
|
|
151
|
+
const diagnostics = parseTypecheckErrors(output);
|
|
152
|
+
if (result.status !== 0 && diagnostics.length === 0) throw new Error(`${label}: nonzero exit without parseable diagnostics: ${reason(result)}`);
|
|
153
|
+
if ((/error TS\d+/.test(output) && diagnostics.length === 0) || (result.status === 0 && diagnostics.length > 0 && label === 'full')) throw new Error(`${label}: inconsistent tsc diagnostics and exit status`);
|
|
154
|
+
}
|
|
155
|
+
function fullDiagnostics(result: CommandResult, root: string): NormalizedDiagnostic[] {
|
|
156
|
+
const output = `${result.stdout}\n${result.stderr}`;
|
|
157
|
+
checked(result, 'full', output);
|
|
158
|
+
return normalizeDiagnostics(parseTypecheckErrors(output), root);
|
|
159
|
+
}
|
|
160
|
+
function gateDiagnostics(result: CommandResult, root: string): NormalizedDiagnostic[] {
|
|
161
|
+
const output = `${result.stdout}\n${result.stderr}`;
|
|
162
|
+
const diagnosticOutput = output.split('\n').map((line) => line.replace(/^ /, '')).join('\n');
|
|
163
|
+
checked(result, 'narrowed', diagnosticOutput);
|
|
164
|
+
if (/tsc 를 «못 쟀다»|tsc 가 정상 실행됐음을 확인할 수 없다|변경 파일 없음|변경 파일 수집 실패/i.test(output)
|
|
165
|
+
|| (result.status === 0 && !/\[tsc-gate\] PASS —/.test(output))
|
|
166
|
+
|| (result.status !== 0 && !/\[tsc-gate\] FAIL —/.test(output))) throw new Error('narrowed gate did not measure tsc');
|
|
167
|
+
return normalizeDiagnostics(parseTypecheckErrors(diagnosticOutput), root);
|
|
168
|
+
}
|
|
169
|
+
async function timed(run: Runner, platform: NodeJS.Platform, command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<CommandResult> {
|
|
170
|
+
if (platform === 'darwin' || platform === 'linux') return run('/usr/bin/time', [platform === 'darwin' ? '-l' : '-v', command, ...args], cwd, env);
|
|
171
|
+
return run(command, args, cwd, env);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The pre-merge base of the whole PR. Merge commit → first parent. Single-parent merge commit: the PR's complete
|
|
176
|
+
* commit count comes from REST (`pulls/N .commits`) for every PR — never from the possibly truncated listed commits.
|
|
177
|
+
* One commit → `head^1`. k > 1 commits → squash (one commit on main) or rebase-merge (k rewritten commits); the
|
|
178
|
+
* method is decided by GitHub's commit↔PR association of `head~1 … head~(k-1)` (all ours → rebase → `head~k`,
|
|
179
|
+
* none ours → squash → `head^1`), never by commit subjects. Anything else is ambiguous and the PR is unmeasured,
|
|
180
|
+
* so an error introduced by an earlier rebased commit is never hidden behind a wrong baseline.
|
|
181
|
+
*/
|
|
182
|
+
async function preMergeRevision(run: Runner, repo: string, pr: Pr, head: string): Promise<string> {
|
|
183
|
+
const parents = (await required(run, 'git', ['rev-list', '--parents', '-n', '1', head], repo)).stdout.trim().split(/\s+/).filter(Boolean);
|
|
184
|
+
if (parents.length > 2) return `${head}^1`;
|
|
185
|
+
const totalText = (await required(run, 'gh', ['api', `repos/{owner}/{repo}/pulls/${pr.number}`, '--jq', '.commits'], repo)).stdout.trim();
|
|
186
|
+
const total = Number(totalText);
|
|
187
|
+
if (!/^\d+$/.test(totalText) || !Number.isSafeInteger(total) || total < 1) throw new Error(`PR #${pr.number}: commit count unreadable (${totalText || 'empty'}) — pre-merge base not determinable`);
|
|
188
|
+
if (total === 1) return `${head}^1`;
|
|
189
|
+
const ours: boolean[] = [];
|
|
190
|
+
for (let back = 1; back < total; back += 1) {
|
|
191
|
+
const sha = (await required(run, 'git', ['rev-parse', `${head}~${back}`], repo)).stdout.trim();
|
|
192
|
+
if (!hash(sha)) throw new Error(`PR #${pr.number}: ${head}~${back} unresolvable — pre-merge base not determinable`);
|
|
193
|
+
const numbers = (await required(run, 'gh', ['api', `repos/{owner}/{repo}/commits/${sha}/pulls`, '--jq', '.[].number'], repo)).stdout.split(/\s+/).filter(Boolean);
|
|
194
|
+
ours.push(numbers.includes(String(pr.number)));
|
|
195
|
+
}
|
|
196
|
+
if (ours.every(Boolean)) return `${head}~${total}`;
|
|
197
|
+
if (ours.every((owned) => !owned)) return `${head}^1`;
|
|
198
|
+
throw new Error(`PR #${pr.number}: merge method ambiguous (${ours.filter(Boolean).length}/${ours.length} of the preceding commits belong to the PR) — pre-merge base not determinable`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function measurePr(repo: string, pr: Pr, run: Runner, platform: NodeJS.Platform, keep: boolean, makeTemp: () => string, removeTemp: (path: string) => void): Promise<PrMeasurement> {
|
|
202
|
+
const head = pr.mergeCommit!.oid;
|
|
203
|
+
const workspace = makeTemp();
|
|
204
|
+
const worktree = join(workspace, 'pr');
|
|
205
|
+
const result: PrMeasurement = { pr: pr.number, head, base: '', worktree, verdict: 'unmeasured', missedDiagnostics: [], addedDiagnostics: [], fullBase: emptyMetrics(), fullHead: emptyMetrics(), narrowed: emptyMetrics(), gateExitCode: null };
|
|
206
|
+
let attempted = false;
|
|
207
|
+
try {
|
|
208
|
+
const base = (await required(run, 'git', ['rev-parse', await preMergeRevision(run, repo, pr, head)], repo)).stdout.trim();
|
|
209
|
+
if (!hash(base)) throw new Error(`invalid first parent of ${head}: ${base}`);
|
|
210
|
+
result.base = base;
|
|
211
|
+
attempted = true;
|
|
212
|
+
await required(run, 'git', ['worktree', 'add', '--detach', worktree, head], repo);
|
|
213
|
+
await required(run, 'git', ['checkout', '--detach', base], worktree);
|
|
214
|
+
await required(run, 'bun', ['install', '--frozen-lockfile'], worktree);
|
|
215
|
+
const baseRun = await timed(run, platform, './node_modules/.bin/tsc', ['--noEmit', '-p', 'tsconfig.gate.json'], worktree);
|
|
216
|
+
result.fullBase = elapsed(baseRun, platform);
|
|
217
|
+
const baseline = fullDiagnostics(baseRun, worktree);
|
|
218
|
+
await required(run, 'git', ['checkout', '--detach', head], worktree);
|
|
219
|
+
await required(run, 'bun', ['install', '--frozen-lockfile'], worktree);
|
|
220
|
+
const headRun = await timed(run, platform, './node_modules/.bin/tsc', ['--noEmit', '-p', 'tsconfig.gate.json'], worktree);
|
|
221
|
+
result.fullHead = elapsed(headRun, platform);
|
|
222
|
+
const current = fullDiagnostics(headRun, worktree);
|
|
223
|
+
const added = compareDiagnostics(current, baseline);
|
|
224
|
+
if (added.kind === 'unavailable') throw new Error(added.reason);
|
|
225
|
+
result.addedDiagnostics = added.added;
|
|
226
|
+
const gateRun = await timed(run, platform, 'bun', ['scripts/ci-typecheck-changed.ts', '--local'], worktree, { ...process.env, TSC_BASE_REF: base });
|
|
227
|
+
result.narrowed = elapsed(gateRun, platform);
|
|
228
|
+
result.gateExitCode = gateRun.status;
|
|
229
|
+
const seen = gateDiagnostics(gateRun, worktree);
|
|
230
|
+
const unseen = compareDiagnostics(added.added, seen);
|
|
231
|
+
result.missedDiagnostics = unseen.kind === 'added' ? unseen.added : [];
|
|
232
|
+
result.verdict = added.added.length > 0
|
|
233
|
+
? gateRun.status === 0 || result.missedDiagnostics.length > 0 ? 'missed' : 'same'
|
|
234
|
+
: gateRun.status === 0 ? 'same' : 'stricter';
|
|
235
|
+
} catch (error) {
|
|
236
|
+
result.reason = error instanceof Error ? error.message : String(error);
|
|
237
|
+
result.verdict = 'unmeasured';
|
|
238
|
+
} finally {
|
|
239
|
+
if (!keep) {
|
|
240
|
+
try {
|
|
241
|
+
if (attempted) {
|
|
242
|
+
const removed = await run('git', ['worktree', 'remove', '--force', worktree], repo);
|
|
243
|
+
if (removed.error || removed.signal || (removed.status !== 0 && !/is not a working tree|is not a worktree/i.test(removed.stderr))) throw new Error(`git worktree remove: ${reason(removed)}`);
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (result.verdict !== 'missed') result.verdict = 'unmeasured';
|
|
247
|
+
result.reason = `${result.reason ? `${result.reason}; ` : ''}cleanup failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
248
|
+
}
|
|
249
|
+
try { removeTemp(workspace); }
|
|
250
|
+
catch (error) {
|
|
251
|
+
if (result.verdict !== 'missed') result.verdict = 'unmeasured';
|
|
252
|
+
result.reason = `${result.reason ? `${result.reason}; ` : ''}workspace cleanup failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
debug.log('tsc.affected-roots', 'measure-pr', { pr: result.pr, head, base: result.base, verdict: result.verdict, missedDiagnostics: result.missedDiagnostics.length, fullBase: result.fullBase, fullHead: result.fullHead, narrowed: result.narrowed, reason: result.reason });
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export async function measureAffectedRoots(repo: string, argv: readonly string[] = [], options: Options = {}): Promise<MeasurementReport> {
|
|
261
|
+
const opts = optionsFromArgs(argv);
|
|
262
|
+
const run = options.run ?? spawnRunner;
|
|
263
|
+
const prs = await selectPrs(repo, opts, run);
|
|
264
|
+
if (prs.length === 0) throw new Error('no merged TypeScript PRs to measure');
|
|
265
|
+
const rows: PrMeasurement[] = [];
|
|
266
|
+
for (const pr of prs) rows.push(await measurePr(repo, pr, run, options.platform ?? process.platform, opts.keep, options.makeTemp ?? (() => mkdtempSync(join(tmpdir(), 'tsc-affected-roots-'))), options.removeTemp ?? ((path) => rmSync(path, { recursive: true, force: true }))));
|
|
267
|
+
const summary = { missed: rows.filter((row) => row.verdict === 'missed').length, same: rows.filter((row) => row.verdict === 'same').length, stricter: rows.filter((row) => row.verdict === 'stricter').length, unmeasured: rows.filter((row) => row.verdict === 'unmeasured').length, of: rows.length };
|
|
268
|
+
return { prs: rows, summary, exitCode: summary.missed ? 1 : summary.unmeasured ? 2 : 0 };
|
|
269
|
+
}
|
|
270
|
+
export function formatReport(report: MeasurementReport, json = false): string {
|
|
271
|
+
if (json) return JSON.stringify(report);
|
|
272
|
+
const metric = (m: Metrics) => `${m.durationMs === null ? '—' : Math.round(m.durationMs)} / ${m.rssMb === null ? '—' : m.rssMb}`;
|
|
273
|
+
return [
|
|
274
|
+
'PR | verdict | missed diagnostics | full base ms/RSS MB | full head ms/RSS MB | narrowed ms/RSS MB',
|
|
275
|
+
...report.prs.map((row) => `#${row.pr} | ${row.verdict} | ${row.missedDiagnostics.length} | ${metric(row.fullBase)} | ${metric(row.fullHead)} | ${metric(row.narrowed)}${row.reason ? ` | ${row.reason}` : ''}`),
|
|
276
|
+
`missed=${report.summary.missed} same=${report.summary.same} stricter=${report.summary.stricter} unmeasured=${report.summary.unmeasured} of ${report.summary.of}`,
|
|
277
|
+
].join('\n');
|
|
278
|
+
}
|
|
279
|
+
if (import.meta.main) {
|
|
280
|
+
try {
|
|
281
|
+
const argv = process.argv.slice(2);
|
|
282
|
+
const report = await measureAffectedRoots(resolve(process.cwd()), argv);
|
|
283
|
+
console.log(formatReport(report, argv.includes('--json')));
|
|
284
|
+
process.exitCode = report.exitCode;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error(`tsc affected roots measurement unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
287
|
+
process.exitCode = 2;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// GATE-HOST-EXECUTOR (0.2.24): the release `gate` node has two executors for the SAME verdict.
|
|
2
|
+
// `pod` (default) sweeps in k8s shard Pods; `host` sweeps in a clean clone on an SSH host (`gateRemote`).
|
|
3
|
+
// The host executor is not a waiver: attribution (introduced/preexisting/baseline) and blocking stay identical —
|
|
4
|
+
// it only lets an operator measure when the Pod infrastructure cannot (10-10: node-b containerd DeadlineExceeded × 4).
|
|
5
|
+
|
|
6
|
+
export type GateExecutor = 'pod' | 'host';
|
|
7
|
+
|
|
8
|
+
export const GATE_EXECUTORS: readonly GateExecutor[] = ['pod', 'host'];
|
|
9
|
+
|
|
10
|
+
/** Same shape `judgeGate` accepts for `gateRemote` (`[user@]host`). */
|
|
11
|
+
export const GATE_HOST_PATTERN = /^(?:[\w.-]+@)?[\w.-]+$/;
|
|
12
|
+
|
|
13
|
+
export function isGateExecutor(value: unknown): value is GateExecutor {
|
|
14
|
+
return typeof value === 'string' && (GATE_EXECUTORS as readonly string[]).includes(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Validate an operator-supplied executor/host pair. Host is required for (and only for) the host executor. */
|
|
18
|
+
export function checkGateExecutorChoice(executor: unknown, host: unknown): { executor: GateExecutor; host?: string } {
|
|
19
|
+
if (!isGateExecutor(executor)) throw new Error(`gate executor must be pod or host: ${String(executor)}`);
|
|
20
|
+
if (executor === 'host') {
|
|
21
|
+
if (typeof host !== 'string' || !host.trim()) throw new Error('gate executor host requires a gate host (--gate-host <ssh-host> or release.loop.gateRemote)');
|
|
22
|
+
const trimmed = host.trim();
|
|
23
|
+
if (!GATE_HOST_PATTERN.test(trimmed)) throw new Error(`invalid gate host: ${trimmed}`);
|
|
24
|
+
return { executor, host: trimmed };
|
|
25
|
+
}
|
|
26
|
+
if (host !== undefined) throw new Error('--gate-host applies only to --gate-executor host');
|
|
27
|
+
return { executor };
|
|
28
|
+
}
|