elanous 0.2.25 → 0.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{1454-37fd16f479f5554a.js → 1454-29d1d773d5996a49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{599-a914cc0468f56143.js → 599-56f2c0a5cc4a7295.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-b12149c51f7d04b1.js → page-fa46d4588e8442c2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/{page-305cd294e754906e.js → page-256ffd365d32e100.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-dea4b795741126fd.js → page-e0de78ae7b99f01c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-45889e7070d11126.js → page-4c741eb760f2f77c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-16a2e893f83ae4d0.js → page-e9ba98f5f1440a21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-56888bc744e08dac.js → page-2f6f303fa114ec24.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-952c6ceec6d9de38.js → page-ced0bcfc6542b3fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-6d0202af568f4c63.js → page-bb1f05cd51c38944.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-4fb6fc34e20c07b7.js → page-f736324afa2117c1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-e9502921f4f01b1f.js → page-6f131b51193a36f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-b6169ea2f09cf287.js → not-found-435f5e2faf02bc01.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/{page-6a14333d1b1b3967.js → page-497e0eedf20e7890.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-8c91a9a66c9ec90a.js → page-a8d28fdf995e16ea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/{page-3d3fc73dd187ed52.js → page-66a67eb19ebd976b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-9c04dac0831c2bbb.js → page-c71267e7681da982.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-04de9ca6d52a3893.js → page-cb249e81ed339318.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-62527677bbc2fdc4.js → page-781cfc5114e097da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-9a2e09c4a311764c.js → page-478157214db6a023.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-bfeb35d69e8b24bb.js → page-86141f12cf090b7f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-89cb33bced824e4a.js → page-7256c73bb1c36751.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/{page-6445ac4cbb8dd869.js → page-979d318a534e92da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-20162174b77f96cf.js → page-601fb77340e63c9a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/{page-05a4b2c9b91034aa.js → page-11bf9e5725a72c22.js} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +13 -13
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +13 -13
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +13 -13
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +13 -13
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +13 -13
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +13 -13
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +13 -13
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +13 -13
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +13 -13
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +13 -13
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +13 -13
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +13 -13
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +13 -13
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +13 -13
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +13 -13
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +13 -13
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +13 -13
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +13 -13
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +13 -13
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +13 -13
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +13 -13
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +13 -13
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +13 -13
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +13 -13
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +13 -13
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +13 -13
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +13 -13
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +13 -13
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +14 -14
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +13 -13
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +13 -13
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +13 -13
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +13 -13
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +13 -13
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +13 -13
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +13 -13
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +13 -13
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +13 -13
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +13 -13
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +13 -13
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +13 -13
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +13 -13
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +13 -13
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +13 -13
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +13 -13
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +13 -13
- package/graphs/implement-loop.yaml +38 -1
- package/graphs/steward/recipes.yaml +6 -0
- package/graphs/steward/release-day.yaml +23 -0
- package/graphs/steward/steward.yaml +9 -1
- package/graphs/work/code-pr.yaml +23 -0
- package/package.json +1 -1
- package/scripts/browser-observe-cycle.ts +76 -2
- package/scripts/ci-typecheck-changed.ts +119 -7
- package/scripts/coord-msg-bridge.ts +209 -0
- package/scripts/coord-post.sh +40 -7
- package/scripts/coord-requests-bridge.ts +10 -5
- package/scripts/detect-test-interference.ts +31 -1
- package/scripts/expose-rubric-suggest.ts +1 -1
- package/scripts/measure-tsc-affected-roots.ts +10 -1
- package/scripts/release-loop/docs-node.ts +51 -22
- package/scripts/release-loop/export-check-node.ts +8 -5
- package/scripts/release-loop/gate-node.ts +37 -4
- package/scripts/release-loop/node-verdict.ts +10 -3
- package/scripts/release-loop/publish-node.ts +3 -0
- package/scripts/release-loop/tui-node-checks.ts +5 -2
- package/scripts/skills/public-check.ts +5 -2
- package/scripts/test-deterministic.ts +520 -37
- package/scripts/ux-sim.ts +7 -1
- package/scripts/verify-kpack6-live.ts +230 -0
- package/src/acp/codex-plugins.ts +17 -0
- package/src/agent/task-notification.ts +32 -2
- package/src/agent-mission/in-agent-plugin.ts +8 -3
- package/src/agent-substrate/review-observation.ts +9 -2
- package/src/agent-substrate/self-review-cli.ts +62 -16
- package/src/boot/daemon-tools/self-implement.ts +72 -4
- package/src/briefing/brief-items.ts +151 -35
- package/src/budget/llm-cost.ts +30 -3
- package/src/budget/usage-outcomes.ts +32 -0
- package/src/claims/claims-ledger.ts +23 -0
- package/src/claims/claims-render.ts +22 -2
- package/src/cli/brief-cli.ts +131 -10
- package/src/cli/claims-cli.ts +24 -4
- package/src/cli/control-cli.ts +29 -0
- package/src/cli/doctor-cli.ts +90 -8
- package/src/cli/msg-cli.ts +177 -11
- package/src/cli/plugin-cli.ts +11 -3
- package/src/cli/pr-cli.ts +133 -18
- package/src/cli/pr-land-overlap-evidence.ts +18 -10
- package/src/cli/pr-land-refusal.ts +20 -0
- package/src/cli/release-cli.ts +34 -5
- package/src/cli/rfc-cli.ts +24 -0
- package/src/cli/seat-cli.ts +121 -0
- package/src/cli/self-utterances-cli.ts +140 -0
- package/src/cli/tailscale-serve.ts +5 -8
- package/src/cli/tasks-cli.ts +528 -31
- package/src/cli/usage-cli.ts +9 -4
- package/src/context-card/cell.ts +40 -0
- package/src/dashboard/boot-timing.ts +35 -0
- package/src/dashboard/first-screen-band.ts +63 -13
- package/src/dashboard/index.ts +94 -27
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +26 -0
- package/src/dashboard/skill-detection-runtime.ts +24 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +6 -0
- package/src/debug/log.ts +1 -1
- package/src/domains/morning-report.ts +3 -1
- package/src/domains/release-tool.ts +29 -12
- package/src/domains/surface-events.ts +16 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/fleet/host-doctor.ts +73 -2
- package/src/github/pr-labels.ts +10 -4
- package/src/graph-runner/runner.ts +104 -15
- package/src/harness/harness-clean.ts +21 -3
- package/src/harness/harness-cli-command.ts +68 -10
- package/src/harness/harness-pod-dispatch.ts +11 -4
- package/src/harness/harness-stop.ts +11 -7
- package/src/hq/seats.ts +17 -3
- package/src/index.ts +69 -9
- package/src/instance/current.ts +2 -6
- package/src/instance/resolve.ts +5 -6
- package/src/intelligence-map/model-bench-scores.ts +102 -0
- package/src/llm/openai-sampling-fields.ts +89 -0
- package/src/llm/runtime-model-family.ts +61 -0
- package/src/llm/zai-coding-plan.ts +27 -1
- package/src/llm.ts +13 -89
- package/src/loops/orchestrator/inbox.ts +73 -0
- package/src/loops/orchestrator/resync-shadow.ts +100 -12
- package/src/loops/orchestrator/tick.ts +73 -2
- package/src/machines/machine-ledger.ts +31 -3
- package/src/maturity/cli-maturity.ts +13 -3
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/msg/msg-sse-server.ts +141 -0
- package/src/msg/msg-store.ts +149 -17
- package/src/ops/overview-collect.ts +3 -2
- package/src/ops/overview-owner.ts +29 -0
- package/src/patents/ledger.ts +128 -0
- package/src/plugin-hooks/shell-hook.ts +17 -2
- package/src/plugin-missions/evaluator-runner.ts +18 -2
- package/src/plugins/install/market-fetch.ts +32 -1
- package/src/plugins/install/plugin-install.ts +11 -1
- package/src/pod-lease/admission.ts +116 -41
- package/src/prompt-enhance/enhance.ts +11 -0
- package/src/release-loop/checklist.ts +52 -4
- package/src/release-loop/feature-store.ts +10 -9
- package/src/release-loop/merged-pr-checklist.ts +24 -5
- package/src/release-loop/rubric.ts +70 -0
- package/src/rfc-registry/registry.ts +88 -0
- package/src/seat-dispatch/seat-request-ledger.ts +4 -0
- package/src/seat-loop/knowhow-lint.ts +233 -0
- package/src/seat-loop/seat-loop.ts +5 -1
- package/src/seat-loop/seat-pack.ts +16 -4
- package/src/seat-loop/traffic-signal.ts +7 -0
- package/src/self-dev/ask-launch-flow.ts +48 -8
- package/src/self-dev/ask-path-candidates.ts +69 -14
- package/src/self-dev/decompose-proposal.ts +43 -1
- package/src/self-dev/draft-sweep.ts +23 -14
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/launch-preflight-text.ts +5 -1
- package/src/self-dev/launch-preflight.ts +143 -10
- package/src/self-dev/orchestrate.ts +6 -2
- package/src/self-dev/run-supervisor.ts +35 -1
- package/src/self-implement/gate-cli.ts +6 -2
- package/src/self-implement/goal-author.ts +5 -28
- package/src/self-implement/goal-command-execution.ts +26 -0
- package/src/self-implement/goal-new-paths.ts +4 -5
- package/src/self-implement/graph-authority.ts +17 -3
- package/src/self-implement/graph-yaml.ts +15 -7
- package/src/self-implement/headless-elanous-driver.ts +16 -1
- package/src/self-implement/host-regate.ts +44 -9
- package/src/self-implement/orchestrator.ts +5 -11
- package/src/self-implement/pwa-import-graph.ts +194 -7
- package/src/self-implement/rework-policy.ts +80 -2
- package/src/self-implement/self-implement-runtime.ts +126 -21
- package/src/self-implement/speed-claims.ts +145 -6
- package/src/session/index.ts +14 -4
- package/src/session-runtime/index.ts +55 -11
- package/src/skills/tools/persistent-grounding.ts +59 -4
- package/src/skills/tools/shell.ts +79 -1
- package/src/steward/rejudge-tick.ts +12 -1
- package/src/steward/release-day.ts +158 -0
- package/src/steward/resync-tick.ts +123 -0
- package/src/task-agent/actions.ts +1 -0
- package/src/task-agent/adopt-pr.ts +140 -0
- package/src/task-agent/board.ts +11 -1
- package/src/task-agent/card-evidence.ts +37 -5
- package/src/task-agent/cover.ts +105 -19
- package/src/task-agent/failure-notify.ts +61 -0
- package/src/task-agent/green-sweep.ts +170 -0
- package/src/task-agent/land-worktree.ts +52 -5
- package/src/task-agent/live-move-history.ts +1 -0
- package/src/task-agent/live-moves.ts +56 -17
- package/src/task-agent/parent-host.ts +1 -1
- package/src/task-agent/postland-card.ts +139 -0
- package/src/task-agent/rejudge-on-head.ts +321 -25
- package/src/task-agent/remote-rejudge-bind.ts +62 -0
- package/src/task-agent/repair-branch-cas.ts +182 -0
- package/src/task-agent/repair-cycle.ts +275 -0
- package/src/task-agent/repair-next-move.ts +31 -0
- package/src/task-agent/repair-review.ts +24 -0
- package/src/task-agent/repair-worker.ts +87 -0
- package/src/task-agent/review-result-capture.ts +66 -2
- package/src/task-agent/shadow.ts +150 -29
- package/src/task-agent/task-hand.ts +133 -8
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +96 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +71 -12
- package/src/telegram.ts +30 -1
- package/src/tool-runtime/tool-search-runtime.ts +25 -0
- package/src/tui.ts +20 -1
- package/src/user-config.ts +11 -60
- package/src/ux-sim/fault-sqlite-busy.ts +50 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4e634c5b98fd4e93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b9cc8a10bc6078b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +0 -1
- /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_ssgManifest.js +0 -0
|
@@ -7,10 +7,17 @@ import { registerStandaloneLogSink } from '../src/domains/standalone-log-sink.js
|
|
|
7
7
|
import { effectiveInstanceRoot } from '../src/instance/resolve.js';
|
|
8
8
|
import trackData from './coord-tracks.json';
|
|
9
9
|
|
|
10
|
-
type
|
|
10
|
+
export type CoordChannelComment = { id: number; body: string; created_at: string; html_url: string };
|
|
11
11
|
type Options = { seat: string; channel: string; since?: string; dryRun: boolean; json: boolean };
|
|
12
12
|
const seatIds = new Set(trackData.tracks.map((track) => track.id));
|
|
13
13
|
|
|
14
|
+
/** Shared channel retrieval. Callers validate the complete result before changing a ledger. */
|
|
15
|
+
export function fetchCoordChannelComments(channel: string, since?: string): CoordChannelComment[] {
|
|
16
|
+
const endpoint = `repos/{owner}/{repo}/issues/${channel}/comments${since ? `?since=${encodeURIComponent(since)}` : ''}`;
|
|
17
|
+
const output = execFileSync('gh', ['api', endpoint, '--paginate', '--jq', '.[]'], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
18
|
+
return output.split('\n').filter(Boolean).map((line) => JSON.parse(line) as CoordChannelComment);
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
function options(args: string[]): Options {
|
|
15
22
|
let seat = '';
|
|
16
23
|
let channel = '23032';
|
|
@@ -98,15 +105,13 @@ async function run(args: string[]): Promise<void> {
|
|
|
98
105
|
seat = selected.seat;
|
|
99
106
|
const { channel, since, dryRun, json } = selected;
|
|
100
107
|
reason = 'gh';
|
|
101
|
-
const
|
|
102
|
-
const output = execFileSync('gh', ['api', endpoint, '--paginate', '--jq', '.[]'], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
103
|
-
const comments = output.split('\n').filter(Boolean).map((line) => JSON.parse(line) as unknown);
|
|
108
|
+
const comments = fetchCoordChannelComments(channel, since);
|
|
104
109
|
reason = 'ledger';
|
|
105
110
|
const path = join(effectiveInstanceRoot(), 'seat-requests', 'requests.jsonl');
|
|
106
111
|
const seen = existingSeatComments(path);
|
|
107
112
|
let picked = 0, added = 0, existing = 0;
|
|
108
113
|
for (const item of comments) {
|
|
109
|
-
const comment = item as Partial<
|
|
114
|
+
const comment = item as Partial<CoordChannelComment>;
|
|
110
115
|
if (typeof comment.id !== 'number' || !Number.isSafeInteger(comment.id) || typeof comment.body !== 'string'
|
|
111
116
|
|| typeof comment.created_at !== 'string' || typeof comment.html_url !== 'string') throw new Error('gh api 댓글 필드가 잘못됐다');
|
|
112
117
|
if (since && Date.parse(comment.created_at) < Date.parse(since)) continue;
|
|
@@ -26,6 +26,9 @@ export type MeasuredRun = {
|
|
|
26
26
|
fail: number | null;
|
|
27
27
|
status: 'measured' | 'unmeasurable';
|
|
28
28
|
reason?: string;
|
|
29
|
+
/** Names observed in Bun's failed-test output. Absent names must not be inferred from the selected files. */
|
|
30
|
+
failedFiles?: string[];
|
|
31
|
+
failedTests?: string[];
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
export type InterferenceReport = {
|
|
@@ -61,6 +64,32 @@ export function parseFailureCount(output: string): number | null {
|
|
|
61
64
|
return Number(failures[0]![1]);
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
/** Bun prints a file heading before its `(fail) name` lines. Only retain names actually printed by that run. */
|
|
68
|
+
export function parseFailedTestNames(output: string): { files: string[]; tests: string[] } {
|
|
69
|
+
const files = new Set<string>();
|
|
70
|
+
const tests = new Set<string>();
|
|
71
|
+
let currentFile: string | undefined;
|
|
72
|
+
for (const raw of output.replace(/\x1b\[[0-9;]*m/g, '').split(/\r?\n/)) {
|
|
73
|
+
const line = raw.trim();
|
|
74
|
+
if (/^(?:\d+\s+(?:pass|fail|skip)|Ran\s+\d+\s+tests?|Bun test v)/i.test(line)) { currentFile = undefined; continue; }
|
|
75
|
+
const failure = /^\(fail\)\s+(.+?)(?:\s+\[[^\]]+\])?$/.exec(line);
|
|
76
|
+
if (failure) {
|
|
77
|
+
tests.add(failure[1]!.trim());
|
|
78
|
+
if (currentFile) files.add(currentFile);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const heading = /^(.+):$/.exec(line);
|
|
82
|
+
if (heading) currentFile = /\.(?:test|spec)\.[cm]?[jt]sx?$/.test(heading[1]!) ? heading[1] : undefined;
|
|
83
|
+
}
|
|
84
|
+
return { files: [...files], tests: [...tests] };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function failedNamesFromStreams(result: RunnerResult): { files: string[]; tests: string[] } {
|
|
88
|
+
const stdout = parseFailedTestNames(result.stdout);
|
|
89
|
+
const stderr = parseFailedTestNames(result.stderr);
|
|
90
|
+
return { files: [...new Set([...stdout.files, ...stderr.files])], tests: [...new Set([...stdout.tests, ...stderr.tests])] };
|
|
91
|
+
}
|
|
92
|
+
|
|
64
93
|
async function measure(files: readonly string[], runner: TestRunner): Promise<MeasuredRun> {
|
|
65
94
|
try {
|
|
66
95
|
const result = await runner(files);
|
|
@@ -68,9 +97,10 @@ async function measure(files: readonly string[], runner: TestRunner): Promise<Me
|
|
|
68
97
|
return { files: [...files], fail: null, status: 'unmeasurable', reason: result.signal ? `runner terminated by ${result.signal}` : 'runner exit code unavailable' };
|
|
69
98
|
}
|
|
70
99
|
const fail = parseFailureCount(`${result.stdout}${result.stderr}`);
|
|
100
|
+
const names = fail !== null && fail > 0 ? failedNamesFromStreams(result) : undefined;
|
|
71
101
|
return fail === null
|
|
72
102
|
? { files: [...files], fail: null, status: 'unmeasurable', reason: 'test summary unavailable, ambiguous, or ran zero files' }
|
|
73
|
-
: { files: [...files], fail, status: 'measured' };
|
|
103
|
+
: { files: [...files], fail, status: 'measured', ...(names?.files.length ? { failedFiles: names.files } : {}), ...(names?.tests.length ? { failedTests: names.tests } : {}) };
|
|
74
104
|
} catch (error) {
|
|
75
105
|
return { files: [...files], fail: null, status: 'unmeasurable', reason: error instanceof Error ? error.message : String(error) };
|
|
76
106
|
}
|
|
@@ -28,7 +28,7 @@ function measure(run: () => Criterion): Criterion {
|
|
|
28
28
|
export function suggestExposeRubric(root: string, files?: readonly string[], help?: HelpRunner, rulesPath?: string): Suggestion[] {
|
|
29
29
|
const names = files ?? readdirSync(join(root, DOCS)).filter((name) => name.endsWith('.md')).map((name) => `${DOCS}/${name}`);
|
|
30
30
|
const paths = [...new Set(names.map((name) => relative(root, resolve(root, name)).split(sep).join('/')))];
|
|
31
|
-
if (paths.some((path) => !/^release\/public\/docs\/[^/]
|
|
31
|
+
if (paths.some((path) => !/^(?:release\/public\/docs\/[^/]+|docs\/marketing\/BLOG-[^/]+)\.md$/.test(path))) throw new Error('문서 경로는 release/public/docs/*.md 또는 docs/marketing/BLOG-*.md 이어야 합니다');
|
|
32
32
|
type HelpResult = ReturnType<HelpRunner> & { failure?: string };
|
|
33
33
|
let helpRuns = 0;
|
|
34
34
|
const rootHelp: (args: string[]) => HelpResult = help ?? ((args) => {
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Measures the changed-file gate against the whole program on recently merged PRs.
|
|
3
|
+
* The narrowed run is the gate's default root check (changed .ts ∪ direct importers), so `missed` / `same` judge that mode:
|
|
4
|
+
* the run pins TSC_GATE_ROOTS to a non-`full` value and disables the rollback switch
|
|
5
|
+
* even when the caller's shell requests a full run.
|
|
6
|
+
* `missed > 0` is reverted without a code change by running the gate with env `TSC_GATE_ROOTS=full`.
|
|
7
|
+
*/
|
|
1
8
|
import { spawn } from 'node:child_process';
|
|
2
9
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
3
10
|
import { tmpdir } from 'node:os';
|
|
@@ -223,7 +230,9 @@ async function measurePr(repo: string, pr: Pr, run: Runner, platform: NodeJS.Pla
|
|
|
223
230
|
const added = compareDiagnostics(current, baseline);
|
|
224
231
|
if (added.kind === 'unavailable') throw new Error(added.reason);
|
|
225
232
|
result.addedDiagnostics = added.added;
|
|
226
|
-
const gateRun = await timed(run, platform, 'bun', ['scripts/ci-typecheck-changed.ts', '--local'], worktree, {
|
|
233
|
+
const gateRun = await timed(run, platform, 'bun', ['scripts/ci-typecheck-changed.ts', '--local'], worktree, {
|
|
234
|
+
...process.env, TSC_BASE_REF: base, TSC_GATE_ROOTS: 'affected', ELANOUS_TSC_AFFECTED_ROOTS: '1',
|
|
235
|
+
});
|
|
227
236
|
result.narrowed = elapsed(gateRun, platform);
|
|
228
237
|
result.gateExitCode = gateRun.status;
|
|
229
238
|
const seen = gateDiagnostics(gateRun, worktree);
|
|
@@ -130,7 +130,11 @@ export function runDocs(
|
|
|
130
130
|
const SHA = /^[0-9a-f]{40}$/i;
|
|
131
131
|
const PREFETCH_DEADLINE_MS = 15 * 60_000;
|
|
132
132
|
type Cut = { version: string; commit: string; manifestHash: string };
|
|
133
|
-
|
|
133
|
+
// Two separately published cache files: a finished TUI must survive a docs failure or delay,
|
|
134
|
+
// so it never lives inside the same file as the docs result (should-fix ②).
|
|
135
|
+
type TuiCache = Cut & { tui: Record<string, unknown> };
|
|
136
|
+
type DocsCache = Cut & { main: string; tree: string; docs: DocsResult };
|
|
137
|
+
type PrefetchCache = DocsCache & { tui: Record<string, unknown> | null };
|
|
134
138
|
type Runner = (command: string, args: string[], cwd?: string, timeout?: number, env?: NodeJS.ProcessEnv) => string;
|
|
135
139
|
export const commandRunner: Runner = (command, args, cwd, timeout, env) => {
|
|
136
140
|
const output = spawnSync(command, args, { cwd, env: env ?? process.env, timeout: timeout ?? 15 * 60_000, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
@@ -162,11 +166,27 @@ function claimPrefetch(dir: string, owner: 'worker' | 'docs'): boolean {
|
|
|
162
166
|
function cacheFile(dir: string, cut: Cut): string {
|
|
163
167
|
return join(dir, `${cut.commit}-${cut.manifestHash}.json`);
|
|
164
168
|
}
|
|
165
|
-
function
|
|
169
|
+
function tuiCacheFile(dir: string, cut: Cut): string {
|
|
170
|
+
return join(dir, `${cut.commit}-${cut.manifestHash}.tui.json`);
|
|
171
|
+
}
|
|
172
|
+
function loadTuiCache(dir: string, cut: Cut): TuiCache | null {
|
|
173
|
+
try {
|
|
174
|
+
const value = JSON.parse(readFileSync(tuiCacheFile(dir, cut), 'utf8')) as TuiCache;
|
|
175
|
+
if (value.version !== cut.version || value.commit !== cut.commit || value.manifestHash !== cut.manifestHash) return null;
|
|
176
|
+
return value;
|
|
177
|
+
} catch { return null; }
|
|
178
|
+
}
|
|
179
|
+
/** Publish `data` to `path` atomically (temp + rename), so a reader never sees a partial file. */
|
|
180
|
+
function publish(path: string, data: unknown): void {
|
|
181
|
+
const staged = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
182
|
+
writeFileSync(staged, JSON.stringify(data) + '\n');
|
|
183
|
+
try { renameSync(staged, path); } catch (error) { rmSync(staged, { force: true }); throw error; }
|
|
184
|
+
}
|
|
185
|
+
function loadCache(dir: string, cut: Cut): DocsCache | null {
|
|
166
186
|
try {
|
|
167
|
-
const value = JSON.parse(readFileSync(cacheFile(dir, cut), 'utf8')) as
|
|
187
|
+
const value = JSON.parse(readFileSync(cacheFile(dir, cut), 'utf8')) as DocsCache;
|
|
168
188
|
if (value.version !== cut.version || value.commit !== cut.commit || value.manifestHash !== cut.manifestHash
|
|
169
|
-
|| !SHA.test(value.main) || value.tree !==
|
|
189
|
+
|| !SHA.test(value.main) || dirname(value.tree) !== dir || !/^tree-[0-9a-f-]{36}$/.test(basename(value.tree)) || !existsSync(value.tree)
|
|
170
190
|
|| value.docs?.outcome !== 'ok' || value.docs.version !== cut.version
|
|
171
191
|
|| value.docs.notes !== join(value.tree, 'release/public/docs/releases', `${cut.version}.md`)
|
|
172
192
|
|| value.docs.pages !== join(value.tree, 'website/pages.json')
|
|
@@ -191,21 +211,34 @@ export function stagePrefetch(context: GraphContext, env: NodeJS.ProcessEnv = pr
|
|
|
191
211
|
const cut = cutFor(context, stateRoot);
|
|
192
212
|
mkdirSync(dir, { recursive: true });
|
|
193
213
|
const already = loadCache(dir, cut);
|
|
194
|
-
if (already) return already;
|
|
195
|
-
|
|
214
|
+
if (already) return { ...already, tui: loadTuiCache(dir, cut)?.tui ?? null };
|
|
215
|
+
// An attempt gets its own path. A failed add can only remove a tree belonging to this attempt,
|
|
216
|
+
// even when an earlier cut or a concurrent worker has a checkout in the same run directory.
|
|
217
|
+
const tree = join(dir, `tree-${randomUUID()}`);
|
|
196
218
|
let added = false;
|
|
219
|
+
// `git worktree add` can fail AFTER creating the tree directory (e.g. a failed checkout): clean up
|
|
220
|
+
// whenever the add succeeded OR the tree is on disk, so a retry of this run is never blocked (should-fix ①).
|
|
221
|
+
const removeTree = () => {
|
|
222
|
+
if (!(added || existsSync(tree))) return;
|
|
223
|
+
try { runner('git', ['worktree', 'remove', '--force', tree], repo, 60_000); } catch { /* preserve original failure */ }
|
|
224
|
+
// A remove that failed (or could not unregister the tree) must still leave no blocking directory behind.
|
|
225
|
+
if (existsSync(tree)) rmSync(tree, { recursive: true, force: true });
|
|
226
|
+
};
|
|
197
227
|
try {
|
|
198
228
|
const main = run('git', ['rev-parse', '--verify', 'origin/main^{commit}'], repo);
|
|
199
229
|
if (!SHA.test(main)) throw new Error('invalid origin/main commit');
|
|
200
|
-
|
|
230
|
+
const cachedTui = loadTuiCache(dir, cut);
|
|
231
|
+
// TUI runs against the cut, on its own isolated session, before touching the docs checkout.
|
|
201
232
|
// tui-sim-node.ts prints the RAW result (no `outcome`); judge it the way node-verdict.ts tui would before reuse.
|
|
202
|
-
|
|
233
|
+
// Publish the reusable TUI in its OWN file the moment it is confirmed — a later docs failure or
|
|
234
|
+
// delay must not throw away a finished TUI (should-fix ②).
|
|
235
|
+
const tui = cachedTui ? cachedTui.tui : reusableTui(withTuiOutcome(0, deps.tui ? deps.tui(cut.commit) : (() => {
|
|
203
236
|
const tuiRun = spawnSync('bun', ['scripts/release-loop/tui-sim-node.ts', '--commit', cut.commit, '--json'], {
|
|
204
237
|
cwd: repo, timeout: Math.min(6 * 60_000, left()), encoding: 'utf8', maxBuffer: 16 * 1024 * 1024,
|
|
205
238
|
});
|
|
206
239
|
return tuiRun.status === 0 ? lastResult({ status: tuiRun.status, stdout: tuiRun.stdout ?? '', stderr: tuiRun.stderr ?? '' }) ?? null : null;
|
|
207
|
-
})();
|
|
208
|
-
|
|
240
|
+
})()), cut.commit);
|
|
241
|
+
if (tui && !cachedTui) publish(tuiCacheFile(dir, cut), { ...cut, tui });
|
|
209
242
|
run('git', ['worktree', 'add', '--detach', tree, main], repo);
|
|
210
243
|
added = true;
|
|
211
244
|
run('bun', ['install', '--frozen-lockfile'], tree);
|
|
@@ -220,19 +253,14 @@ export function stagePrefetch(context: GraphContext, env: NodeJS.ProcessEnv = pr
|
|
|
220
253
|
const finalCut = cutFor(context, stateRoot);
|
|
221
254
|
if (finalCut.manifestHash !== cut.manifestHash) throw new Error('manifest changed during prefetch');
|
|
222
255
|
const result: PrefetchCache = { ...cut, main, tree, docs, tui };
|
|
223
|
-
const
|
|
224
|
-
const staged = `${final}.${process.pid}.${randomUUID()}.tmp`;
|
|
225
|
-
writeFileSync(staged, JSON.stringify(result) + '\n');
|
|
256
|
+
const docsCache: DocsCache = { ...cut, main, tree, docs };
|
|
226
257
|
// Publication handshake: whoever creates `claim` first (O_EXCL) wins. The docs node claims before it reads,
|
|
227
258
|
// so a worker that loses can never publish a cache that a docs attempt would consume.
|
|
228
|
-
if (!claimPrefetch(dir, 'worker'))
|
|
229
|
-
|
|
230
|
-
throw new Error('docs node already ran; late prefetch is discarded');
|
|
231
|
-
}
|
|
232
|
-
renameSync(staged, final);
|
|
259
|
+
if (!claimPrefetch(dir, 'worker')) throw new Error('docs node already ran; late prefetch is discarded');
|
|
260
|
+
publish(cacheFile(dir, cut), docsCache);
|
|
233
261
|
return result;
|
|
234
262
|
} catch (error) {
|
|
235
|
-
|
|
263
|
+
removeTree();
|
|
236
264
|
throw error;
|
|
237
265
|
}
|
|
238
266
|
}
|
|
@@ -247,9 +275,10 @@ export function joinTui(context: GraphContext, env: NodeJS.ProcessEnv, repo: str
|
|
|
247
275
|
}, stateRoot = effectiveInstanceRoot()): Record<string, unknown> {
|
|
248
276
|
if (context.outputs.upgrade?.outcome !== 'ok') throw new Error('upgrade did not pass');
|
|
249
277
|
// Any failure to key the cache (no manifest, cutoff mismatch, no run dir) is a cache miss → original TUI path.
|
|
278
|
+
// The TUI cache file is independent of docs (should-fix ②): a docs failure or delay never blocks this read.
|
|
250
279
|
let cut: Cut | null = null;
|
|
251
|
-
let cached:
|
|
252
|
-
try { cut = cutFor(context, stateRoot); cached =
|
|
280
|
+
let cached: TuiCache | null = null;
|
|
281
|
+
try { cut = cutFor(context, stateRoot); cached = loadTuiCache(runCacheDir(env), cut); } catch { /* cache miss */ }
|
|
253
282
|
const reused = cut && cached?.tui && reusableTui(cached.tui, cut.commit);
|
|
254
283
|
if (reused) return { ...reused, outcome: 'ok', summary: `tui ${reused.verdict}` };
|
|
255
284
|
// Preserve node-verdict.ts's exit convention and last-JSON output on a cache miss.
|
|
@@ -287,7 +316,7 @@ export function graphDocs(context: GraphContext, env: NodeJS.ProcessEnv, repo: s
|
|
|
287
316
|
try {
|
|
288
317
|
// No fetch (nor any write to remote) until every gate is verified.
|
|
289
318
|
for (const node of ['gate', 'prepare', 'upgrade', 'tui']) if (context.outputs[node]?.outcome !== 'ok') throw new Error(`${node} did not pass`);
|
|
290
|
-
let cached:
|
|
319
|
+
let cached: DocsCache | null = null;
|
|
291
320
|
// A cache key that cannot be computed is a miss — the original fresh-worktree path runs.
|
|
292
321
|
if (mayConsume && cacheDir) { try { const cut = cutFor(context, stateRoot); cached = loadCache(cacheDir, cut); } catch { cached = null; } }
|
|
293
322
|
const branch = `release-docs/${version}`;
|
|
@@ -48,11 +48,14 @@ export function runExportCheck(run: CommandRunner = runCommand, repoRoot = proce
|
|
|
48
48
|
const publicDir = join(out, 'export');
|
|
49
49
|
symlinkSync(join(modulesRoot, 'node_modules'), join(publicDir, 'node_modules'), 'dir');
|
|
50
50
|
const pwaModules = join(modulesRoot, 'apps', 'pwa', 'node_modules');
|
|
51
|
-
if (existsSync(pwaModules)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
if (!existsSync(pwaModules)) result = failed('build', 'PWA dependencies missing; run bun install --cwd apps/pwa in the release-loop repository');
|
|
52
|
+
else {
|
|
53
|
+
if (existsSync(join(publicDir, 'apps', 'pwa'))) symlinkSync(pwaModules, join(publicDir, 'apps', 'pwa', 'node_modules'), 'dir');
|
|
54
|
+
const built = run('bun', ['bin/elanous.mjs', 'nexus', 'build'], publicDir);
|
|
55
|
+
result = built.status === 0 && existsSync(join(publicDir, 'apps', 'pwa', 'out', 'index.html'))
|
|
56
|
+
? { outcome: 'ok', verdict: 'pass', summary: `public export and PWA build ${commit.slice(0, 12)}`, step: 'build', tail: '' }
|
|
57
|
+
: failed('build', 'PWA build or out/index.html missing', built);
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
}
|
|
@@ -117,6 +117,8 @@ export interface GateResult {
|
|
|
117
117
|
const sha = /^[0-9a-f]{7,40}$/i;
|
|
118
118
|
const versionPattern = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
|
|
119
119
|
const failureFile = (root: string, version: string) => join(root, 'release', version, 'gate-failures.json');
|
|
120
|
+
/** Judged identities live beside the machine release ledger; gate-failures.json keeps its raw baseline schema. */
|
|
121
|
+
const verdictFile = (root: string, version: string) => join(root, 'release', version, 'gate-verdict.json');
|
|
120
122
|
const quote = (s: string) => `'${s.replaceAll("'", "'\\''")}'`;
|
|
121
123
|
const defaultRemoteMirror = '~/mirror/elanous-agent.git';
|
|
122
124
|
|
|
@@ -1431,6 +1433,8 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1431
1433
|
};
|
|
1432
1434
|
const repo = resolve(opts.repo ?? process.cwd());
|
|
1433
1435
|
const result: GateResult = { outcome: 'error', commit: opts.commit, introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: 0 };
|
|
1436
|
+
const preexistingIds: string[] = [];
|
|
1437
|
+
let knownEnvIds: string[] = [];
|
|
1434
1438
|
let work: string | undefined;
|
|
1435
1439
|
let baseSnapshot = false;
|
|
1436
1440
|
let cutFailures: SweepFailures | undefined;
|
|
@@ -1598,11 +1602,13 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1598
1602
|
const baselineIds = [...baseline.failures, ...baseline.errors];
|
|
1599
1603
|
const countedCut = splitKnownEnv(cutIds, known);
|
|
1600
1604
|
const countedBaseline = splitKnownEnv(baselineIds, known);
|
|
1601
|
-
|
|
1605
|
+
knownEnvIds = countedCut.knownEnv;
|
|
1606
|
+
result.knownEnv = knownEnvIds.length;
|
|
1602
1607
|
result.knownEnvCleared = [...new Set(cutRun.passedIds ?? [])].filter((id) => known.has(id) && !cutIds.includes(id) && !cutRun.stalledEnv?.some(({ file }) => fileOf(id) === file)).sort();
|
|
1603
1608
|
const diff = diffFailures(countedCut.counted, countedBaseline.counted);
|
|
1604
1609
|
result.fixed = result.baselineDeferred ? null : diff.fixed.length;
|
|
1605
|
-
|
|
1610
|
+
preexistingIds.push(...diff.common);
|
|
1611
|
+
result.preexisting = preexistingIds.length;
|
|
1606
1612
|
// GATE-BASELINE-CACHE — only the files whose new failures reproduce in isolation reach the baseline, and each
|
|
1607
1613
|
// (commit, file, host) is run at most once across gates: this gate's cut results also seed the next gate's baseline.
|
|
1608
1614
|
const cacheHost = opts.remote ?? 'local';
|
|
@@ -1703,10 +1709,11 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1703
1709
|
debug.log('release-loop.gate', 'isolated-rc-nonzero-no-failures', { file, label: 'cut isolated', rc: rcOnly.rc, pass: rcOnly.pass, baseline });
|
|
1704
1710
|
}
|
|
1705
1711
|
for (const id of candidates) {
|
|
1706
|
-
if (oldFailures.has(id))
|
|
1712
|
+
if (oldFailures.has(id)) preexistingIds.push(id);
|
|
1707
1713
|
else result.introduced.push(id);
|
|
1708
1714
|
}
|
|
1709
1715
|
}
|
|
1716
|
+
result.preexisting = preexistingIds.length;
|
|
1710
1717
|
result.baselineCache = cacheStats;
|
|
1711
1718
|
debug.log('release.gate', 'baseline-cache', { hits: cacheStats.hits, misses: cacheStats.misses, commit: baseSha });
|
|
1712
1719
|
result.outcome = result.introduced.length ? 'regression' : 'ok';
|
|
@@ -1751,7 +1758,33 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1751
1758
|
result.error = `baseline persistence: ${String(error)}`;
|
|
1752
1759
|
}
|
|
1753
1760
|
}
|
|
1754
|
-
if (result.outcome !== 'error')
|
|
1761
|
+
if (result.outcome !== 'error') {
|
|
1762
|
+
const ids = {
|
|
1763
|
+
introduced: [...result.introduced].sort(),
|
|
1764
|
+
knownEnv: [...knownEnvIds].sort(),
|
|
1765
|
+
preexisting: [...preexistingIds].sort(),
|
|
1766
|
+
loadFlaky: [...(result.loadFlaky ?? [])].sort(),
|
|
1767
|
+
};
|
|
1768
|
+
try {
|
|
1769
|
+
const path = verdictFile(ledger, opts.version);
|
|
1770
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
1771
|
+
const temp = join(dirname(path), `.gate-verdict-${process.pid}-${randomUUID()}.tmp`);
|
|
1772
|
+
try {
|
|
1773
|
+
writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit, outcome: result.outcome, ...ids }, null, 2) + '\n', { mode: 0o600 });
|
|
1774
|
+
chmodSync(temp, 0o600);
|
|
1775
|
+
renameSync(temp, path);
|
|
1776
|
+
} finally { if (existsSync(temp)) rmSync(temp); }
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
result.outcome = 'error';
|
|
1779
|
+
result.error = `verdict persistence: ${String(error)}`;
|
|
1780
|
+
}
|
|
1781
|
+
if (result.outcome !== 'error') debug.log('release-loop.gate', 'judged', {
|
|
1782
|
+
version: opts.version, commit: opts.commit,
|
|
1783
|
+
introduced: result.introduced.length, preexisting: result.preexisting,
|
|
1784
|
+
knownEnv: result.knownEnv, loadFlaky: ids.loadFlaky.length,
|
|
1785
|
+
introducedIds: ids.introduced, knownEnvIds: ids.knownEnv, preexistingIds: ids.preexisting, loadFlakyIds: ids.loadFlaky,
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1755
1788
|
// GATE-LIVE-OBS-RC-WORDING ⓒ — the shards board says «판정 전» until this lands; then «새 실패 N» only (UX · gate-shards.ts).
|
|
1756
1789
|
// Same ledger as the board's own writes (sweep's shardsFile). A write failure is logged and never changes the verdict.
|
|
1757
1790
|
if (result.outcome !== 'error' && opts.pod) {
|
|
@@ -7,6 +7,7 @@ import { debug } from '../../src/debug/log.js';
|
|
|
7
7
|
export type NodeOutcome = 'ok' | 'fail' | 'error';
|
|
8
8
|
export type NodeVerdict = 'pass' | 'flaky' | 'fail';
|
|
9
9
|
export interface GraphContext {
|
|
10
|
+
nodeId?: string;
|
|
10
11
|
input: { version: string; previousVersion: string; [key: string]: unknown };
|
|
11
12
|
outputs: Record<string, Record<string, unknown>>;
|
|
12
13
|
}
|
|
@@ -20,7 +21,8 @@ export function readGraphContext(env: NodeJS.ProcessEnv = process.env): GraphCon
|
|
|
20
21
|
const input = context.input as Record<string, unknown> | undefined;
|
|
21
22
|
if (!input || typeof input.version !== 'string' || !isReleaseVersion(input.version)
|
|
22
23
|
|| typeof input.previousVersion !== 'string' || !/^\d+\.\d+\.\d+$/.test(input.previousVersion)) throw new Error('version and previousVersion required');
|
|
23
|
-
return {
|
|
24
|
+
return { ...(typeof context.nodeId === 'string' ? { nodeId: context.nodeId } : {}),
|
|
25
|
+
input: input as GraphContext['input'], outputs: context.outputs && typeof context.outputs === 'object' ? context.outputs as GraphContext['outputs'] : {} };
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export function nodeOutput(context: GraphContext, node: string, key: string): string {
|
|
@@ -48,9 +50,14 @@ export function lastResult(run: CommandResult): Record<string, unknown> | undefi
|
|
|
48
50
|
} catch { return undefined; }
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
export function finishNode(node: string, version: string, result: Record<string, unknown> & { outcome: NodeOutcome; verdict: NodeVerdict; summary: string }): number {
|
|
53
|
+
export function finishNode(node: string, version: string, result: Record<string, unknown> & { outcome: NodeOutcome; verdict: NodeVerdict; summary: string; tail?: string }): number {
|
|
52
54
|
debug.log(`release-loop.${node}`, 'result', { version, outcome: result.outcome });
|
|
53
|
-
|
|
55
|
+
if (result.outcome === 'fail') {
|
|
56
|
+
const summary = result.summary.replace(/[\r\n]+/g, ' ').trim();
|
|
57
|
+
const tail = result.tail?.trim() ? result.tail : summary;
|
|
58
|
+
debug.log('release.node', 'failed', { node, summary, tail });
|
|
59
|
+
emitNodeResult({ ...result, summary, tail });
|
|
60
|
+
} else emitNodeResult(result);
|
|
54
61
|
return result.outcome === 'ok' ? 0 : result.outcome === 'fail' ? 1 : 2;
|
|
55
62
|
}
|
|
56
63
|
|
|
@@ -48,6 +48,9 @@ export function waitForAssets(run: CommandRunner, repo: string, tag: string, nam
|
|
|
48
48
|
export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: string,
|
|
49
49
|
clock: { now: () => number; sleep: (ms: number) => void } = { now: Date.now, sleep: Bun.sleepSync }) {
|
|
50
50
|
const context = readGraphContext();
|
|
51
|
+
// A resumed graph once invoked this irreversible node at npm-publish, docs-land, and failed.
|
|
52
|
+
// The runner's context is the authority: only the publish visit may publish.
|
|
53
|
+
if (context.nodeId !== 'publish') throw new Error(`publish node context mismatch: expected publish, got ${context.nodeId ?? 'missing'}`);
|
|
51
54
|
const version = context.input.version;
|
|
52
55
|
// A measured automatic decision or the existing human approval must authorize publication.
|
|
53
56
|
const auto = context.outputs['auto-approve'];
|
|
@@ -11,6 +11,9 @@ export interface TuiScreens {
|
|
|
11
11
|
export interface TuiCheck { id: string; pass: boolean; detail: string }
|
|
12
12
|
|
|
13
13
|
const ERROR_TEXT = /\b(TypeError|ReferenceError|SyntaxError|Unhandled|panic|Segmentation fault)\b|Error: /;
|
|
14
|
+
// The startup band can say "Commands — /help lists every command" (#26954).
|
|
15
|
+
// Only the modal's title proves that the help overlay itself remains on screen.
|
|
16
|
+
const HELP_MODAL_TITLE = 'Dashboard help';
|
|
14
17
|
|
|
15
18
|
export function tuiChecks(s: TuiScreens, readyLimitMs = 60_000): TuiCheck[] {
|
|
16
19
|
const all = [s.first, s.help, s.afterEsc].join('\n');
|
|
@@ -18,8 +21,8 @@ export function tuiChecks(s: TuiScreens, readyLimitMs = 60_000): TuiCheck[] {
|
|
|
18
21
|
{ id: 'boot', pass: s.readyMs !== null && s.readyMs <= readyLimitMs, detail: s.readyMs === null ? 'never ready' : `ready in ${s.readyMs}ms` },
|
|
19
22
|
{ id: 'prompt', pass: s.first.includes('❯'), detail: 'input line (❯) on the first screen' },
|
|
20
23
|
{ id: 'status-bar', pass: /│.*ctx \d+/.test(s.first), detail: 'status bar with model and ctx' },
|
|
21
|
-
{ id: 'help-opens', pass: s.help.includes(
|
|
22
|
-
{ id: 'help-closes', pass: !s.afterEsc.includes(
|
|
24
|
+
{ id: 'help-opens', pass: s.help.includes(HELP_MODAL_TITLE) && s.help.includes('Commands') && s.help.includes('/help'), detail: '/help shows the help overlay' },
|
|
25
|
+
{ id: 'help-closes', pass: !s.afterEsc.includes(HELP_MODAL_TITLE) && s.afterEsc.includes('❯'), detail: 'Esc closes the overlay' },
|
|
23
26
|
{ id: 'no-error-text', pass: !ERROR_TEXT.test(all), detail: 'no error text on any screen' },
|
|
24
27
|
];
|
|
25
28
|
}
|
|
@@ -17,7 +17,9 @@ export interface PublicCheckReport {
|
|
|
17
17
|
readonly ok: boolean;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// 개인 경로(`/Users/`·`~/source`)는 대소문자를 가리고, 내부 표지는 기존처럼 `iu`.
|
|
21
|
+
const PERSONAL_PATH = /\/Users\/|~\/source(?:\/|\b)/u;
|
|
22
|
+
const INTERNAL_MARKER = /\b(?:INTERNAL_ONLY|ELANOUS_INTERNAL|PRIVATE_INTERNAL|internal-only)\b|@internal\b|내부\s*전용/iu;
|
|
21
23
|
const EXECUTABLE = /\.(?:ts|tsx|js|mjs|cjs|py|sh|bash)$/iu;
|
|
22
24
|
const ENTRY_DIR = /^(?:scripts|src|bin)\//u;
|
|
23
25
|
const NON_ENTRY = /(?:\.d\.ts|\.(?:test|spec)\.[^.]+)$/iu;
|
|
@@ -165,7 +167,8 @@ export function checkPublicSkills(root: string, boundary: SkillBoundaryReport =
|
|
|
165
167
|
const bytes = readFileSync(file);
|
|
166
168
|
if (bytes.includes(0)) continue;
|
|
167
169
|
try {
|
|
168
|
-
|
|
170
|
+
const decoded = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
171
|
+
if (PERSONAL_PATH.test(decoded) || INTERNAL_MARKER.test(decoded)) matches.push(relative(root, file));
|
|
169
172
|
} catch {
|
|
170
173
|
// Binary assets are not text; extensionless and dotfiles are checked when decodable.
|
|
171
174
|
}
|