elanous 0.2.17 → 0.2.19
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/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{726.83532d69452ee24b.js → 1470.98a6ab61ccb4131c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9247-269e4464cc4b491c.js → 2375-e061bb24cd2b5cde.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{211-9c9090c59e2c5907.js → 2977-e38442e86289f1d3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → 2ea96958.e8c7e112de50b067.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +2 -0
- package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +1 -0
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 4323.c5dfb6f503304775.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 4847.56f5bc454fbcc827.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 6062-73e68343a9814f6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{935.4ddaa99fc1d1126c.js → 7647.2fcd30d894d5ee30.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6231284-45726550aba08fca.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +25 -0
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-b70cd005d9169e25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +1 -0
- package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
- package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +1 -0
- package/apps/pwa/out/_next/static/css/d3427996da11e480.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -0
- package/apps/pwa/out/decisions/index.txt +30 -0
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +25 -24
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +24 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +28 -27
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/ops/guardian.yaml +26 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/package.json +2 -1
- package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
- package/samples/workflows/templates/chat-driven-research.yaml +35 -0
- package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
- package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
- package/samples/workflows/templates/manual-quickstart.yaml +21 -0
- package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
- package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
- package/scripts/ci-public-export-import-gate.ts +7 -2
- package/scripts/ci-typecheck-changed.ts +21 -6
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +6 -3
- package/scripts/docs/generate-cli-anatomy.ts +162 -0
- package/scripts/goals/authoring-metrics.ts +73 -0
- package/scripts/landing-heal/must-fix-match.ts +7 -7
- package/scripts/landing-heal/run-mission.ts +3 -2
- package/scripts/lib/pch-regress-map.ts +23 -0
- package/scripts/morning-report.ts +18 -4
- package/scripts/pch-regress.ts +88 -0
- package/scripts/public-export-test-run.ts +37 -2
- package/scripts/release-loop/checklist-gate-node.ts +13 -11
- package/scripts/release-loop/cut-branch.ts +2 -1
- package/scripts/release-loop/cutoff.ts +4 -2
- package/scripts/release-loop/docs-land-node.ts +8 -1
- package/scripts/release-loop/docs-node.ts +1 -1
- package/scripts/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +436 -59
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +120 -0
- package/scripts/release-loop/node-verdict.ts +2 -1
- package/scripts/release-loop/npm-publish-node.ts +11 -7
- package/scripts/release-loop/ops-upgrade-node.ts +8 -1
- package/scripts/release-loop/preflight.ts +246 -0
- package/scripts/release-loop/publish-node.ts +8 -1
- package/scripts/release-loop/release-readiness.ts +11 -6
- package/scripts/release-loop/release-version.ts +48 -0
- package/scripts/release-loop/resume-release.ts +174 -0
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +45 -7
- package/scripts/release-loop/version-node.ts +145 -40
- package/scripts/rhythm/daily.ts +25 -4
- package/scripts/skills/public-check.ts +62 -12
- package/scripts/test-deterministic.ts +51 -33
- package/scripts/test-diet/effectiveness.ts +62 -1
- package/scripts/test-diet/lib.ts +1 -1
- package/scripts/test-diet/node.ts +8 -1
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/agent-mission/review-loop.ts +4 -3
- package/src/agent-substrate/pr-comment-meta.ts +20 -0
- package/src/autopilot/build/llm-conflict-merge.ts +28 -8
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +255 -0
- package/src/briefing/brief-items.ts +86 -17
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/autopilot-cli.ts +30 -11
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/brief-cli.ts +36 -2
- package/src/cli/freeze-cli.ts +3 -2
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +85 -7
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/notify-cli.ts +75 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/provider-cli.ts +12 -2
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +128 -19
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +403 -4
- package/src/context-bus/condense.ts +19 -3
- package/src/context-bus/context-day.ts +77 -24
- package/src/context-bus/context-first.ts +33 -0
- package/src/context-bus/context-now-public.ts +1 -1
- package/src/context-bus/context-now-surfaces.ts +16 -6
- package/src/context-bus/context-now.ts +97 -3
- package/src/core-turn/short-question.ts +100 -0
- package/src/dashboard/dashboard-status-lines.ts +24 -4
- package/src/dashboard/index.ts +50 -5
- package/src/dashboard/input/slash-executor.ts +6 -2
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +63 -36
- package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +21 -8
- package/src/dashboard/slash-runtime/help-groups.ts +44 -0
- package/src/dashboard/slash-runtime/model-choices.ts +125 -0
- package/src/discord-self-message.ts +20 -2
- package/src/discord-slash-wire.ts +1 -0
- package/src/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +244 -40
- package/src/domains/outbound-log-probe.ts +16 -1
- package/src/domains/release-tool.ts +2 -2
- package/src/domains/schedule-registry.ts +23 -0
- package/src/domains/telegram-kind-route.ts +39 -0
- package/src/domains/watch-default-scheduler.ts +95 -0
- package/src/esc-abort-gate.ts +44 -0
- package/src/execution-loop/gates.ts +11 -2
- package/src/flow-loop/split.ts +8 -4
- package/src/git-fs/worktree.ts +23 -3
- package/src/graph-runner/runner.ts +25 -5
- package/src/harness/harness-cli-command.ts +12 -2
- package/src/harness/harness-queue.ts +388 -33
- package/src/harness/harness-salvage-cli.ts +78 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/helper-scan.ts +10 -3
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/hq.ts +6 -1
- package/src/hq/seats.ts +369 -0
- package/src/index.ts +185 -18
- package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
- package/src/instance/test-write-guard.ts +200 -0
- package/src/intake-plane/adopt-gate.ts +49 -0
- package/src/intake-plane/check.ts +3 -0
- package/src/intake-plane/collect-github.ts +57 -25
- package/src/intake-plane/digest.ts +39 -15
- package/src/intake-plane/discord-seat-work.ts +8 -2
- package/src/intake-plane/harness-target.ts +4 -3
- package/src/intake-plane/intake-sources.ts +1 -0
- package/src/intake-plane/items.ts +1 -0
- package/src/intake-plane/requirement-funnel.ts +316 -0
- package/src/knowledge/know-find.ts +10 -1
- package/src/loops/budget.ts +36 -0
- package/src/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +106 -4
- package/src/loops/orchestrator/grid-place.ts +11 -0
- package/src/loops/orchestrator/tick.ts +450 -54
- package/src/maturity/feature-maturity.ts +8 -5
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/decisions-route.ts +11 -1
- package/src/nexus/api/http-server.ts +16 -5
- package/src/nexus/api/loop-edges.ts +352 -23
- package/src/nexus/api/ops-api.ts +96 -28
- package/src/nexus/api/ops-seats-sources.ts +2 -2
- package/src/nexus/api/workflow-templates.ts +3 -0
- package/src/nexus/index.ts +7 -0
- package/src/oauth/codex.ts +38 -0
- package/src/onboarding/first-chat-gate.ts +29 -0
- package/src/release-loop/checklist.ts +106 -6
- package/src/release-loop/feature-store.ts +64 -16
- package/src/release-loop/landing-freeze.ts +6 -4
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +64 -20
- package/src/release-loop/rubric.ts +136 -0
- package/src/seat-dispatch/seat-ask.ts +79 -16
- package/src/seat-loop/seat-loop.ts +12 -6
- package/src/self-dev/ask-launch-flow.ts +24 -3
- package/src/self-dev/ask-path-candidates.ts +68 -0
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/dev-pipeline.ts +4 -0
- package/src/self-dev/draft-triage-rules.ts +1 -1
- package/src/self-dev/orchestrate-cli.ts +22 -0
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +179 -0
- package/src/self-dev/round-pr-supersede.ts +244 -0
- package/src/self-dev/run-supervisor.ts +14 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/follow-up-goals.ts +2 -2
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/gate-remote.ts +427 -0
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-author.ts +8 -3
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/l8-merge-queue.ts +29 -5
- package/src/self-implement/orchestrator.ts +61 -13
- package/src/self-implement/prior-draft-findings.ts +4 -3
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/skills/skill-feedback.ts +76 -0
- package/src/task-agent/actions.ts +101 -7
- package/src/task-agent/board.ts +132 -0
- package/src/task-agent/card-evidence.ts +203 -0
- package/src/task-agent/completion-evidence.ts +126 -0
- package/src/task-agent/judge.ts +49 -5
- package/src/task-agent/live-moves.ts +176 -0
- package/src/task-agent/mission.ts +449 -0
- package/src/task-agent/shadow.ts +258 -0
- package/src/task-agent/task-hand.ts +337 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +64 -4
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +10 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +142 -13
- package/src/task-orchestrator/surfaces/pod-pool.ts +13 -5
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +88 -20
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +11 -0
- package/src/telegram-loops-command.ts +1 -1
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/telegram.ts +5 -20
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +196 -4
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-aac7332576c4d6fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6877-fe94e76a5841ee9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3143b07a817d1da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-17ba086ef82d339b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-6e5c3a867557298b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9a41d65355fc25b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-41afec0b255ed2bb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4187666132fc98c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-09328d499162bae4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-29ff3a8f84f03b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-80ec7401bc83f511.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-fc7d86467291ae38.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-de43a186e5ba5683.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-043a9111e74f6b24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-23a4601ceb7f452e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-10d958605a77b3bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a04260b8ccc968d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-12916918988ac97e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-5a64cb5208c6a8fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1407ec83ea64c1f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7f49fe645d5132f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-424659bacfb8cdd7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-fc2df261f8a2c7df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d4fef9ccd7d406b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +0 -1
- package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
- package/apps/pwa/out/_next/static/yRA5ur6DcPl0YHSRheH2O/_buildManifest.js +0 -1
- /package/apps/pwa/out/_next/static/{yRA5ur6DcPl0YHSRheH2O → J5H7BvqgSI8DUjtRRcA_S}/_ssgManifest.js +0 -0
|
@@ -5,12 +5,17 @@ import { tmpdir } from 'node:os';
|
|
|
5
5
|
import { join, resolve } from 'node:path';
|
|
6
6
|
import { emitNodeResult } from './node-verdict.js';
|
|
7
7
|
import { debug } from '../../src/debug/log.js';
|
|
8
|
+
import { effectiveInstanceRoot, prodInstanceRoot } from '../../src/instance/resolve.js';
|
|
9
|
+
import { landingFreezeMessage, readLandingFreeze, type LandingFreeze } from '../../src/release-loop/landing-freeze.js';
|
|
10
|
+
import { baseVersion, isReleaseVersion, isStableVersion, prereleaseKind } from './release-version.js';
|
|
8
11
|
|
|
9
12
|
type Kind = 'release' | 'dev-bump';
|
|
10
|
-
type Output = { outcome: 'ok' | 'error'; kind: Kind | null; version: string | null; commit: string | null; pr: number | null; files?: string[]; worktree?: string; error?: string
|
|
13
|
+
type Output = { outcome: 'ok' | 'error'; kind: Kind | null; version: string | null; commit: string | null; pr: number | null; files?: string[]; worktree?: string; error?: string;
|
|
14
|
+
/** RELEASE-BRANCH: the release branch the cut lives on and the main commit it was cut from. */
|
|
15
|
+
branch?: string; base?: string; existing?: boolean; skipped?: string };
|
|
11
16
|
|
|
12
17
|
export function nextDevVersion(version: string): string {
|
|
13
|
-
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(version);
|
|
18
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(isReleaseVersion(version) ? baseVersion(version) : version);
|
|
14
19
|
if (!match) throw new Error(`invalid release version: ${version}`);
|
|
15
20
|
return `${match[1]}.${match[2]}.${BigInt(match[3]!) + 1n}-dev.0`;
|
|
16
21
|
}
|
|
@@ -64,9 +69,136 @@ function shippedNextMdLines(repo: string, cut: string | undefined): { lines: Set
|
|
|
64
69
|
return { lines: new Set(shown.stdout.split('\n').map((line) => line.trim()).filter((line) => line.startsWith('- '))) };
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
/** Rewrite the version in package.json, server.json, the ACP agent card and the bun.lock root; returns the files touched. */
|
|
73
|
+
function writeVersionBump(worktree: string, current: string, target: string): string[] {
|
|
74
|
+
const path = join(worktree, 'package.json');
|
|
75
|
+
const text = readFileSync(path, 'utf8');
|
|
76
|
+
const old = `"version": "${current}"`;
|
|
77
|
+
if (!text.includes(old)) throw new Error(`package.json version field not found: ${current}`);
|
|
78
|
+
writeFileSync(path, text.replace(old, `"version": "${target}"`));
|
|
79
|
+
const files = ['package.json'];
|
|
80
|
+
const serverPath = join(worktree, 'server.json');
|
|
81
|
+
if (existsSync(serverPath)) {
|
|
82
|
+
const server = JSON.parse(readFileSync(serverPath, 'utf8')) as { version: string; packages: Array<{ version: string }> };
|
|
83
|
+
server.version = target;
|
|
84
|
+
server.packages[0]!.version = target;
|
|
85
|
+
writeFileSync(serverPath, `${JSON.stringify(server, null, 2)}\n`);
|
|
86
|
+
files.push('server.json');
|
|
87
|
+
}
|
|
88
|
+
const agentPath = join(worktree, 'integrations', 'acp-registry', 'elanous', 'agent.json');
|
|
89
|
+
if (existsSync(agentPath)) {
|
|
90
|
+
const agent = JSON.parse(readFileSync(agentPath, 'utf8')) as { version: string; distribution: { npx: { package: string } } };
|
|
91
|
+
agent.version = target;
|
|
92
|
+
agent.distribution.npx.package = `elanous@${target}`;
|
|
93
|
+
writeFileSync(agentPath, `${JSON.stringify(agent, null, 2)}\n`);
|
|
94
|
+
files.push('agent.json');
|
|
95
|
+
}
|
|
96
|
+
const lockPath = join(worktree, 'bun.lock');
|
|
97
|
+
const lock = readFileSync(lockPath, 'utf8');
|
|
98
|
+
const root = /"workspaces"\s*:\s*\{\s*""\s*:\s*\{([\s\S]*?)(?=\s*"(?:dependencies|devDependencies|optionalDependencies)"\s*:)/.exec(lock);
|
|
99
|
+
if (!root) throw new Error('bun.lock root workspace not found');
|
|
100
|
+
const lockedVersion = /"version"\s*:\s*"([^"]+)"/.exec(root[1]!);
|
|
101
|
+
if (lockedVersion) {
|
|
102
|
+
if (lockedVersion[1] !== current) throw new Error(`bun.lock root version ${lockedVersion[1]} is not ${current}`);
|
|
103
|
+
writeFileSync(lockPath, lock.replace(root[0], root[0].replace(lockedVersion[0], `"version": "${target}"`)));
|
|
104
|
+
}
|
|
105
|
+
return files;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface BranchCutDeps {
|
|
109
|
+
/** Runs `bun install --frozen-lockfile` in the bump worktree (the lock must accept the new version). */
|
|
110
|
+
install?: (worktree: string) => void;
|
|
111
|
+
/** The landing freeze in force (production root first, like a merge). */
|
|
112
|
+
freeze?: () => LandingFreeze | null;
|
|
113
|
+
/** `--force-freeze`: cut while a freeze is on (recorded). */
|
|
114
|
+
forceFreeze?: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function currentFreeze(): LandingFreeze | null {
|
|
118
|
+
const prod = prodInstanceRoot();
|
|
119
|
+
const root = effectiveInstanceRoot();
|
|
120
|
+
return readLandingFreeze(prod) ?? (root === prod ? null : readLandingFreeze(root));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* RELEASE-BRANCH (대표 10-06 20:0x «0.2.18부터 브랜치 방식»): the release commit lives on `release/<v>`, never on main.
|
|
125
|
+
* An existing branch is reused as is (a resumed run, or a branch a repair appended to) — its tip is the release commit.
|
|
126
|
+
* Otherwise the branch is cut from origin/main and the version bump is committed on it; main keeps its -dev.N version
|
|
127
|
+
* until the post-publish dev bump.
|
|
128
|
+
*/
|
|
129
|
+
export function cutReleaseBranchForRun(repo: string, version: string, deps: BranchCutDeps = {}): Output {
|
|
130
|
+
if (!isReleaseVersion(version)) throw new Error(`invalid release version: ${version}`);
|
|
131
|
+
// The run does not need a freeze, but one that is on is the emergency stop: neither a new nor a reused cut passes it.
|
|
132
|
+
const frozen = (deps.freeze ?? currentFreeze)();
|
|
133
|
+
if (frozen) {
|
|
134
|
+
debug.log('release.run', deps.forceFreeze ? 'freeze-forced' : 'frozen', { version, reason: frozen.reason, until: frozen.until, node: 'version-release' });
|
|
135
|
+
if (!deps.forceFreeze) throw new Error(landingFreezeMessage(frozen));
|
|
136
|
+
}
|
|
137
|
+
fetchMain(repo);
|
|
138
|
+
const branch = `release/${version}`;
|
|
139
|
+
const advertised = git(repo, 'ls-remote', '--heads', 'origin', `refs/heads/${branch}`).split(/\s+/)[0] ?? '';
|
|
140
|
+
if (advertised) {
|
|
141
|
+
// A prerelease number is used once: an existing rc branch is another run's cut, never this run's.
|
|
142
|
+
if (prereleaseKind(version) !== null) throw new Error(`${branch} already exists — ${version} was cut by another run; run again for the next free number`);
|
|
143
|
+
if (!/^[0-9a-f]{40}$/i.test(advertised)) throw new Error(`${branch} remote tip is not a commit SHA`);
|
|
144
|
+
git(repo, 'fetch', 'origin', `+refs/heads/${branch}:refs/remotes/origin/${branch}`);
|
|
145
|
+
const tip = git(repo, 'rev-parse', '--verify', `refs/remotes/origin/${branch}^{commit}`);
|
|
146
|
+
if (tip !== advertised) throw new Error(`${branch} moved while it was read (${advertised} → ${tip})`);
|
|
147
|
+
const current = versionAt(repo, tip);
|
|
148
|
+
if (current !== version) throw new Error(`${branch} tip ${tip} package.json version ${current} is not ${version}`);
|
|
149
|
+
// The branch must be a cut of this release line: its fork point on main still carries <base>-dev.N (or <v>).
|
|
150
|
+
const fork = git(repo, 'merge-base', 'origin/main', tip);
|
|
151
|
+
const forkVersion = versionAt(repo, fork);
|
|
152
|
+
const stableLine = baseVersion(version);
|
|
153
|
+
if (forkVersion !== version && !new RegExp(`^${stableLine.replaceAll('.', '\\.')}-dev\\.(0|[1-9][0-9]*)$`).test(forkVersion)) {
|
|
154
|
+
throw new Error(`${branch} forks from main at ${fork} (version ${forkVersion}) — not a cut of ${stableLine}-dev.N`);
|
|
155
|
+
}
|
|
156
|
+
debug.log('release-loop.cut', 'chosen', { version, source: 'release-branch', commit: tip, branch, existing: true });
|
|
157
|
+
return { outcome: 'ok', kind: 'release', version, commit: tip, pr: null, branch, existing: true };
|
|
158
|
+
}
|
|
159
|
+
const base = git(repo, 'rev-parse', 'origin/main');
|
|
160
|
+
const current = versionAt(repo, base);
|
|
161
|
+
const stable = baseVersion(version);
|
|
162
|
+
const devOfStable = new RegExp(`^${stable.replaceAll('.', '\\.')}-dev\\.(0|[1-9][0-9]*)$`);
|
|
163
|
+
if (current !== version && !devOfStable.test(current)) throw new Error(`origin/main version ${current} is not ${stable}-dev.N (release ${version})`);
|
|
164
|
+
const temp = mkdtempSync(join(tmpdir(), 'release-branch-cut-'));
|
|
165
|
+
const worktree = join(temp, 'tree');
|
|
166
|
+
let added = false;
|
|
167
|
+
try {
|
|
168
|
+
git(repo, 'worktree', 'add', '--detach', worktree, base);
|
|
169
|
+
added = true;
|
|
170
|
+
const files = current === version ? [] : writeVersionBump(worktree, current, version);
|
|
171
|
+
if (files.length) {
|
|
172
|
+
(deps.install ?? ((tree: string) => { run('bun', ['install', '--frozen-lockfile'], tree); }))(worktree);
|
|
173
|
+
git(worktree, 'add', '-A');
|
|
174
|
+
git(worktree, 'commit', '-m', `release: ${version}`, '-m', `Cut from main ${base}.`);
|
|
175
|
+
}
|
|
176
|
+
const commit = git(worktree, 'rev-parse', 'HEAD');
|
|
177
|
+
// Create-only: an empty lease refuses to overwrite a branch someone else made meanwhile.
|
|
178
|
+
const push = git(repo, 'push', '--porcelain', `--force-with-lease=refs/heads/${branch}:`, 'origin', `${commit}:refs/heads/${branch}`);
|
|
179
|
+
const created = push.split('\n').some((line) => {
|
|
180
|
+
const [flag, ref, summary] = line.split('\t');
|
|
181
|
+
return flag === '*' && !!ref?.endsWith(`:refs/heads/${branch}`) && summary === '[new branch]';
|
|
182
|
+
});
|
|
183
|
+
if (!created) throw new Error(`${branch} was not created (push: ${push.replace(/\s+/g, ' ').trim() || 'no output'})`);
|
|
184
|
+
debug.log('release-loop.cut', 'chosen', { version, source: 'release-branch', commit, branch, base, existing: false });
|
|
185
|
+
return { outcome: 'ok', kind: 'release', version, commit, pr: null, branch, base, files };
|
|
186
|
+
} finally {
|
|
187
|
+
try { if (added) git(repo, 'worktree', 'remove', '--force', worktree); }
|
|
188
|
+
finally { rmSync(temp, { recursive: true, force: true }); }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function landing(repo: string, kind: Kind, releaseVersion: string, cut?: string, cutCommit?: string, forceFreeze = false, branchCut = false): Output {
|
|
193
|
+
if (kind === 'release' && branchCut && cutCommit === undefined) return cutReleaseBranchForRun(repo, releaseVersion, { forceFreeze });
|
|
194
|
+
if (kind === 'dev-bump' && prereleaseKind(releaseVersion) !== null) {
|
|
195
|
+
// A prerelease (rehearsal) never moves main: the next stable release still owns this -dev line.
|
|
196
|
+
debug.log('release-loop.version-dev-bump', 'skipped', { version: releaseVersion, reason: 'prerelease' });
|
|
197
|
+
return { outcome: 'ok', kind, version: releaseVersion, commit: null, pr: null, skipped: 'prerelease' };
|
|
198
|
+
}
|
|
68
199
|
const target = kind === 'release' ? releaseVersion : nextDevVersion(releaseVersion);
|
|
69
|
-
|
|
200
|
+
// With the release on its branch, main still carries <v>-dev.N when the dev bump runs.
|
|
201
|
+
const source = kind === 'release' ? `${releaseVersion}-dev.N` : branchCut ? `${releaseVersion}-dev.N` : releaseVersion;
|
|
70
202
|
fetchMain(repo);
|
|
71
203
|
if (kind === 'release' && cutCommit !== undefined) {
|
|
72
204
|
if (!/^[0-9a-f]{7,40}$/i.test(cutCommit)) throw new Error(`invalid cut commit SHA: ${cutCommit}`);
|
|
@@ -107,7 +239,8 @@ function landing(repo: string, kind: Kind, releaseVersion: string, cut?: string,
|
|
|
107
239
|
return { outcome: 'ok', kind, version: current, commit: before, pr: null };
|
|
108
240
|
}
|
|
109
241
|
}
|
|
110
|
-
|
|
242
|
+
const devOfRelease = new RegExp(`^${releaseVersion.replaceAll('.', '\\.')}\\-dev\\.(0|[1-9][0-9]*)$`);
|
|
243
|
+
if (kind === 'release' || branchCut ? !devOfRelease.test(current) && !(kind === 'dev-bump' && current === releaseVersion) : current !== source) {
|
|
111
244
|
throw new Error(`origin/main version ${current} is not ${source} (target ${target})`);
|
|
112
245
|
}
|
|
113
246
|
|
|
@@ -115,37 +248,7 @@ function landing(repo: string, kind: Kind, releaseVersion: string, cut?: string,
|
|
|
115
248
|
const worktree = join(temp, 'tree');
|
|
116
249
|
try {
|
|
117
250
|
git(repo, 'worktree', 'add', '-b', `release-version-${kind}-${Date.now()}-${process.pid}`, worktree, 'origin/main');
|
|
118
|
-
const
|
|
119
|
-
const text = readFileSync(path, 'utf8');
|
|
120
|
-
const old = `"version": "${current}"`;
|
|
121
|
-
if (!text.includes(old)) throw new Error(`package.json version field not found: ${current}`);
|
|
122
|
-
writeFileSync(path, text.replace(old, `"version": "${target}"`));
|
|
123
|
-
const files = ['package.json'];
|
|
124
|
-
const serverPath = join(worktree, 'server.json');
|
|
125
|
-
if (existsSync(serverPath)) {
|
|
126
|
-
const server = JSON.parse(readFileSync(serverPath, 'utf8')) as { version: string; packages: Array<{ version: string }> };
|
|
127
|
-
server.version = target;
|
|
128
|
-
server.packages[0]!.version = target;
|
|
129
|
-
writeFileSync(serverPath, `${JSON.stringify(server, null, 2)}\n`);
|
|
130
|
-
files.push('server.json');
|
|
131
|
-
}
|
|
132
|
-
const agentPath = join(worktree, 'integrations', 'acp-registry', 'elanous', 'agent.json');
|
|
133
|
-
if (existsSync(agentPath)) {
|
|
134
|
-
const agent = JSON.parse(readFileSync(agentPath, 'utf8')) as { version: string; distribution: { npx: { package: string } } };
|
|
135
|
-
agent.version = target;
|
|
136
|
-
agent.distribution.npx.package = `elanous@${target}`;
|
|
137
|
-
writeFileSync(agentPath, `${JSON.stringify(agent, null, 2)}\n`);
|
|
138
|
-
files.push('agent.json');
|
|
139
|
-
}
|
|
140
|
-
const lockPath = join(worktree, 'bun.lock');
|
|
141
|
-
const lock = readFileSync(lockPath, 'utf8');
|
|
142
|
-
const root = /"workspaces"\s*:\s*\{\s*""\s*:\s*\{([\s\S]*?)(?=\s*"(?:dependencies|devDependencies|optionalDependencies)"\s*:)/.exec(lock);
|
|
143
|
-
if (!root) throw new Error('bun.lock root workspace not found');
|
|
144
|
-
const lockedVersion = /"version"\s*:\s*"([^"]+)"/.exec(root[1]!);
|
|
145
|
-
if (lockedVersion) {
|
|
146
|
-
if (lockedVersion[1] !== current) throw new Error(`bun.lock root version ${lockedVersion[1]} is not ${current}`);
|
|
147
|
-
writeFileSync(lockPath, lock.replace(root[0], root[0].replace(lockedVersion[0], `"version": "${target}"`)));
|
|
148
|
-
}
|
|
251
|
+
const files = writeVersionBump(worktree, current, target);
|
|
149
252
|
run('bun', ['install', '--frozen-lockfile'], worktree);
|
|
150
253
|
if (kind === 'dev-bump') {
|
|
151
254
|
const nextPath = join(worktree, 'release', 'next.md');
|
|
@@ -207,12 +310,13 @@ function landing(repo: string, kind: Kind, releaseVersion: string, cut?: string,
|
|
|
207
310
|
}
|
|
208
311
|
}
|
|
209
312
|
|
|
210
|
-
function main(args: string[] = process.argv.slice(2), repo = process.cwd()): Output {
|
|
313
|
+
export function main(args: string[] = process.argv.slice(2), repo = process.cwd()): Output {
|
|
211
314
|
let kind: Kind | null = null;
|
|
212
315
|
let version: string | null = null;
|
|
213
316
|
let cut: string | undefined;
|
|
214
317
|
let cutCommit: string | undefined;
|
|
215
318
|
let forceFreeze = false;
|
|
319
|
+
let branchCut = false;
|
|
216
320
|
try {
|
|
217
321
|
if (args[0] !== 'release' && args[0] !== 'dev-bump') throw new Error('usage: version-node.ts <release|dev-bump> [--version <v>] [--cut <sha>] [--cut-commit <sha>] --json');
|
|
218
322
|
kind = args[0];
|
|
@@ -226,9 +330,10 @@ function main(args: string[] = process.argv.slice(2), repo = process.cwd()): Out
|
|
|
226
330
|
if (process.env.ELANOUS_GRAPH_CONTEXT) {
|
|
227
331
|
const location = process.env.ELANOUS_GRAPH_CONTEXT;
|
|
228
332
|
const context = JSON.parse(location.trimStart().startsWith('{') ? location : readFileSync(location, 'utf8')) as {
|
|
229
|
-
input?: { version?: unknown; cutCommit?: unknown; forceFreeze?: unknown }; outputs?: Record<string, { commit?: unknown } | undefined> };
|
|
333
|
+
input?: { version?: unknown; cutCommit?: unknown; forceFreeze?: unknown; branchCut?: unknown }; outputs?: Record<string, { commit?: unknown } | undefined> };
|
|
230
334
|
if (!version && typeof context.input?.version === 'string') version = context.input.version;
|
|
231
335
|
forceFreeze = context.input?.forceFreeze === true;
|
|
336
|
+
branchCut = context.input?.branchCut === true;
|
|
232
337
|
if (kind === 'release' && cutCommit === undefined && context.input?.cutCommit !== undefined) {
|
|
233
338
|
if (typeof context.input.cutCommit !== 'string') throw new Error('cutCommit must be a commit SHA');
|
|
234
339
|
cutCommit = context.input.cutCommit;
|
|
@@ -240,11 +345,11 @@ function main(args: string[] = process.argv.slice(2), repo = process.cwd()): Out
|
|
|
240
345
|
if (!version) throw new Error('version required (--version or ELANOUS_GRAPH_CONTEXT.input.version)');
|
|
241
346
|
nextDevVersion(version);
|
|
242
347
|
if (kind === 'dev-bump' && cutCommit !== undefined) throw new Error('--cut-commit is only valid for release');
|
|
243
|
-
return landing(resolve(repo), kind, version, cut, cutCommit, forceFreeze);
|
|
348
|
+
return landing(resolve(repo), kind, version, cut, cutCommit, forceFreeze, branchCut);
|
|
244
349
|
} catch (error) {
|
|
245
350
|
const message = error instanceof Error ? error.message : String(error);
|
|
246
351
|
const worktree = /\[worktree: ([^\]]+)\]$/.exec(message)?.[1];
|
|
247
|
-
const outputVersion = kind === 'dev-bump' && version &&
|
|
352
|
+
const outputVersion = kind === 'dev-bump' && version && isStableVersion(version)
|
|
248
353
|
? nextDevVersion(version) : version;
|
|
249
354
|
return { outcome: 'error', kind, version: outputVersion,
|
|
250
355
|
commit: null, pr: null, ...(worktree ? { worktree } : {}), error: message };
|
package/scripts/rhythm/daily.ts
CHANGED
|
@@ -301,8 +301,9 @@ function recipient(deps: DailyDeps): { chatId: number; botToken: string } | null
|
|
|
301
301
|
function sendReview(file: string, text: string, target: { chatId: number; botToken: string },
|
|
302
302
|
send: (request: DailySendRequest) => DailySendConfirmation | null,
|
|
303
303
|
receipt: (key: string) => DeliveryReceipt,
|
|
304
|
-
recordDelivery?: (text: string, kind: 'ops-report') => void
|
|
305
|
-
|
|
304
|
+
recordDelivery?: (text: string, kind: 'ops-report') => void,
|
|
305
|
+
keySuffix = ''): DeliveryResult {
|
|
306
|
+
const key = file.slice(file.lastIndexOf('/') + 1).replace(/\.md$/, '') + keySuffix;
|
|
306
307
|
const label = `telegram:${target.chatId}`;
|
|
307
308
|
const db = new Database(join(dirname(file), 'delivery.sqlite'));
|
|
308
309
|
try {
|
|
@@ -346,6 +347,21 @@ function sendReview(file: string, text: string, target: { chatId: number; botTok
|
|
|
346
347
|
finally { db.close(); }
|
|
347
348
|
}
|
|
348
349
|
|
|
350
|
+
function newsMessage(markdown: string): string | null {
|
|
351
|
+
const section = markdown.split('## ⑦ 외부 동향\n')[1]?.split('\n\n## ')[0];
|
|
352
|
+
if (!section || section.startsWith('못 읽음 ·')) return null;
|
|
353
|
+
const articles = [...section.matchAll(/^- (.+) — (https?:\/\/\S+)\n 시사점: (.*)$/gm)].slice(0, 3);
|
|
354
|
+
return articles.length ? `## 외부 동향\n${articles.map(article => article[0]).join('\n')}` : null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function sendNewsAfterReview(delivery: DeliveryResult, file: string, markdown: string,
|
|
358
|
+
target: { chatId: number; botToken: string }, deps: DailyDeps): string | null {
|
|
359
|
+
if (!['sent', 'already-sent', 'receipt-sent'].includes(delivery.deliveryState)) return null;
|
|
360
|
+
const text = newsMessage(markdown);
|
|
361
|
+
if (!text) return null;
|
|
362
|
+
return sendReview(file, text, target, deps.send ?? sendTelegram, deps.receipt ?? (() => 'unknown'), deps.recordDelivery, '-news').deliveryState;
|
|
363
|
+
}
|
|
364
|
+
|
|
349
365
|
export type DailyDeps = { now?: () => Date; root?: string; vaultRoot?: string | null; sendEnabled?: boolean; repoRoot?: string; repoName?: string;
|
|
350
366
|
landings?: (now: Date) => Promise<Landing[]>; release?: () => Promise<Release>; loops?: () => Promise<Loop[]>;
|
|
351
367
|
grid?: () => Promise<Seat[]>; decisions?: () => Promise<Pending[]>; news?: () => Promise<News[]>;
|
|
@@ -402,6 +418,7 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
|
|
|
402
418
|
let target = 'unknown';
|
|
403
419
|
let sendError: string | null = null;
|
|
404
420
|
let recordError: string | null = null;
|
|
421
|
+
let newsState: string | null = null;
|
|
405
422
|
let enabled = deps.sendEnabled === true;
|
|
406
423
|
if (deps.sendEnabled === undefined && options.stage === 'deliver' && !options.dryRun) {
|
|
407
424
|
try { enabled = record(record(record(getUserConfig().raw.loops).rhythm).daily).send === true; }
|
|
@@ -420,12 +437,13 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
|
|
|
420
437
|
sendError = sendError ?? delivery.sendError;
|
|
421
438
|
recordError = delivery.recordError ?? null;
|
|
422
439
|
deliveryState = delivery.deliveryState;
|
|
440
|
+
if (resolved) newsState = sendNewsAfterReview(delivery, file, markdown, resolved, deps);
|
|
423
441
|
}
|
|
424
442
|
tick.sent = sent;
|
|
425
443
|
const status = vault.vaultFatal || Object.values(sections).includes('unreadable') ? 'degraded'
|
|
426
444
|
: deliveryState === 'pending' ? 'pending'
|
|
427
445
|
: ['sent', 'already-sent', 'receipt-sent'].includes(deliveryState) ? 'ok' : 'degraded';
|
|
428
|
-
const deliveryLine = `${options.stage} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}`;
|
|
446
|
+
const deliveryLine = `${options.stage} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}${newsState ? ` · news=${newsState}` : ''}`;
|
|
429
447
|
if (options.stage === 'deliver') {
|
|
430
448
|
Object.assign(tick, { status, deliveryState, target, chars, receiptKey, deliveryLine, recordError });
|
|
431
449
|
if (!options.dryRun) {
|
|
@@ -526,6 +544,7 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
|
|
|
526
544
|
}
|
|
527
545
|
let sent = false;
|
|
528
546
|
let recordError: string | null = null;
|
|
547
|
+
let newsState: string | null = null;
|
|
529
548
|
let chars = 0;
|
|
530
549
|
let target = 'unknown';
|
|
531
550
|
if (!options.dryRun && options.stage !== 'collect' && enabled) {
|
|
@@ -541,11 +560,13 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
|
|
|
541
560
|
sendError = sendError ?? delivery.sendError;
|
|
542
561
|
recordError = delivery.recordError ?? null;
|
|
543
562
|
deliveryState = delivery.deliveryState;
|
|
563
|
+
if (resolved && parts.news.status === 'ok' && parts.news.value.length > 0)
|
|
564
|
+
newsState = sendNewsAfterReview(delivery, file, review.markdown, resolved, deps);
|
|
544
565
|
}
|
|
545
566
|
const status = vaultFatal || Object.values(review.sections).includes('unreadable') ? 'degraded'
|
|
546
567
|
: deliveryState === 'pending' ? 'pending'
|
|
547
568
|
: ['sent', 'already-sent', 'receipt-sent'].includes(deliveryState) ? 'ok' : 'degraded';
|
|
548
|
-
const deliveryLine = `${options.stage === 'collect' ? 'collect' : 'deliver'} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}`;
|
|
569
|
+
const deliveryLine = `${options.stage === 'collect' ? 'collect' : 'deliver'} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}${newsState ? ` · news=${newsState}` : ''}`;
|
|
549
570
|
if (options.stage !== 'collect') {
|
|
550
571
|
const tick = { sections: review.sections, risks: review.risks.length, sent, status, deliveryState, target, chars, receiptKey, deliveryLine, recordError };
|
|
551
572
|
if (!options.dryRun) {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
import { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs';
|
|
4
|
-
import {
|
|
2
|
+
/** Public (core) skill readiness inventory; optional builds never execute a skill. */
|
|
3
|
+
import { cpSync, existsSync, lstatSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { basename, isAbsolute, join, relative, sep, win32 } from 'node:path';
|
|
5
6
|
import { computeSkillBoundaries, type SkillBoundaryReport } from '../skill-boundary.js';
|
|
6
7
|
|
|
7
8
|
export type PublicCheckKey = 'header' | 'entry' | 'free' | 'portable' | 'install';
|
|
8
9
|
export interface PublicSkillRow {
|
|
9
10
|
readonly skill: string;
|
|
10
|
-
readonly checks: Readonly<Record<PublicCheckKey, boolean | 'N/A'
|
|
11
|
+
readonly checks: Readonly<Record<PublicCheckKey, boolean | 'N/A'> & { build?: SkillBuildResult }>;
|
|
11
12
|
readonly violations: readonly string[];
|
|
12
13
|
}
|
|
13
14
|
export interface PublicCheckReport {
|
|
@@ -68,6 +69,44 @@ function executableEntries(files: readonly string[], dir: string, docs: string):
|
|
|
68
69
|
&& (commanded.has(file) || file.startsWith('bin/') || ENTRY_NAME.test(file)));
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
export type SkillBuildResult = 'OK' | 'FAIL' | 'N/A';
|
|
73
|
+
|
|
74
|
+
/** Build only selected TS/JS entries from an isolated skill copy, never from the repository. */
|
|
75
|
+
export function buildSkillEntries(
|
|
76
|
+
dir: string,
|
|
77
|
+
entries: readonly string[],
|
|
78
|
+
run: (args: string[], cwd: string) => boolean = (args, cwd) => Bun.spawnSync(args, {
|
|
79
|
+
cwd, stdout: 'ignore', stderr: 'ignore',
|
|
80
|
+
}).exitCode === 0,
|
|
81
|
+
): SkillBuildResult {
|
|
82
|
+
const buildable = entries.filter((entry) => /\.(?:ts|tsx|js|mjs|cjs)$/iu.test(entry));
|
|
83
|
+
if (buildable.length === 0) return 'N/A';
|
|
84
|
+
if (buildable.some((entry) => isAbsolute(entry) || win32.isAbsolute(entry) || entry.split(/[\\/]/u).includes('..'))) return 'FAIL';
|
|
85
|
+
const temp = mkdtempSync(join(tmpdir(), 'skill-public-build-'));
|
|
86
|
+
try {
|
|
87
|
+
const skill = join(temp, 'skill');
|
|
88
|
+
cpSync(dir, skill, {
|
|
89
|
+
recursive: true,
|
|
90
|
+
filter: (source) => source === dir || !['.git', 'node_modules', '__pycache__'].includes(basename(source)) && !lstatSync(source).isSymbolicLink(),
|
|
91
|
+
});
|
|
92
|
+
const copiedRoot = realpathSync(skill);
|
|
93
|
+
for (const entry of buildable) {
|
|
94
|
+
const target = realpathSync(join(skill, entry));
|
|
95
|
+
const inside = relative(copiedRoot, target);
|
|
96
|
+
if (inside === '..' || inside.startsWith(`..${sep}`) || isAbsolute(inside) || !lstatSync(target).isFile()) return 'FAIL';
|
|
97
|
+
}
|
|
98
|
+
if (existsSync(join(skill, 'package.json')) && !run(['bun', 'install', '--ignore-scripts'], skill)) return 'FAIL';
|
|
99
|
+
for (const [index, entry] of buildable.entries()) {
|
|
100
|
+
if (!run(['bun', 'build', entry, '--target=bun', '--outfile', join(temp, `entry-${index}.js`)], skill)) return 'FAIL';
|
|
101
|
+
}
|
|
102
|
+
return 'OK';
|
|
103
|
+
} catch {
|
|
104
|
+
return 'FAIL';
|
|
105
|
+
} finally {
|
|
106
|
+
rmSync(temp, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
71
110
|
function freeValid(doc: string, entries: ReadonlySet<string>): boolean {
|
|
72
111
|
const section = /(?:^|\n)#{1,4}\s*[^\n]*(?:무료|free)[^\n]*\n([\s\S]*?)(?=\n#{1,4}\s|$)/giu;
|
|
73
112
|
for (const match of doc.matchAll(section)) {
|
|
@@ -97,7 +136,7 @@ function installValid(doc: string, dir: string): boolean {
|
|
|
97
136
|
}
|
|
98
137
|
|
|
99
138
|
/** `boundary` is injectable for pure fixture tests; production always derives it from the repository. */
|
|
100
|
-
export function checkPublicSkills(root: string, boundary: SkillBoundaryReport = computeSkillBoundaries(root)): PublicCheckReport {
|
|
139
|
+
export function checkPublicSkills(root: string, boundary: SkillBoundaryReport = computeSkillBoundaries(root), build = false): PublicCheckReport {
|
|
101
140
|
const errors = [...boundary.errors];
|
|
102
141
|
const skills: PublicSkillRow[] = [];
|
|
103
142
|
const skillsDir = join(root, 'skills');
|
|
@@ -133,6 +172,7 @@ export function checkPublicSkills(root: string, boundary: SkillBoundaryReport =
|
|
|
133
172
|
free: freeValid(docs, entries),
|
|
134
173
|
portable: matches.length === 0,
|
|
135
174
|
install: installValid(docs, dir),
|
|
175
|
+
...(build ? { build: buildSkillEntries(dir, [...entries]) } : {}),
|
|
136
176
|
};
|
|
137
177
|
const violations = [
|
|
138
178
|
...(!checks.header ? ['SKILL.md 머리(name·description) 없음/불일치'] : []),
|
|
@@ -140,6 +180,7 @@ export function checkPublicSkills(root: string, boundary: SkillBoundaryReport =
|
|
|
140
180
|
...(!checks.free ? ['키/.env 없이 쓰는 무료 경로가 문서에 없음'] : []),
|
|
141
181
|
...matches.map((file) => `${file}: 개인 경로/내부 표지 문자열`),
|
|
142
182
|
...(!checks.install ? ['의존 manifest와 문서의 한 줄 설치 명령이 없음'] : []),
|
|
183
|
+
...(checks.build === 'FAIL' ? ['스킬 실행 파일 빌드 실패'] : []),
|
|
143
184
|
];
|
|
144
185
|
skills.push({ skill, checks, violations });
|
|
145
186
|
}
|
|
@@ -147,23 +188,32 @@ export function checkPublicSkills(root: string, boundary: SkillBoundaryReport =
|
|
|
147
188
|
}
|
|
148
189
|
|
|
149
190
|
export function formatPublicCheck(report: PublicCheckReport): string {
|
|
150
|
-
const columns: PublicCheckKey[] = ['header', 'entry', 'free', 'portable', 'install'];
|
|
191
|
+
const columns: (PublicCheckKey | 'build')[] = ['header', 'entry', 'free', 'portable', 'install'];
|
|
192
|
+
if (report.skills.some((row) => row.checks.build !== undefined)) columns.push('build');
|
|
151
193
|
return [
|
|
152
194
|
`skill ${columns.map((key) => key.padEnd(9)).join(' ')} result`,
|
|
153
|
-
...report.skills.map((row) => `${row.skill.padEnd(34)} ${columns.map((key) =>
|
|
195
|
+
...report.skills.map((row) => `${row.skill.padEnd(34)} ${columns.map((key) => { const value = row.checks[key]; return (typeof value === 'string' ? value : value ? 'OK' : 'FAIL').padEnd(9); }).join(' ')} ${row.violations.length ? row.violations.join('; ') : 'OK'}`),
|
|
154
196
|
...report.errors.map((error) => `ERROR ${error}`),
|
|
155
197
|
`PUBLIC-CHECK ${report.ok ? 'PASS' : 'FAIL'} (${report.skills.length} public skills)`,
|
|
156
198
|
].join('\n');
|
|
157
199
|
}
|
|
158
200
|
|
|
201
|
+
export function runPublicCheck(root: string, args: readonly string[], boundary?: SkillBoundaryReport): { output: string; exitCode: number } {
|
|
202
|
+
const report = checkPublicSkills(root, boundary, args.includes('--build'));
|
|
203
|
+
return {
|
|
204
|
+
output: args.includes('--json') ? JSON.stringify(report, null, 2) : formatPublicCheck(report),
|
|
205
|
+
exitCode: report.ok ? 0 : 1,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
159
209
|
if (import.meta.main) {
|
|
160
210
|
const args = process.argv.slice(2);
|
|
161
|
-
if (args.some((arg) => arg !== '--json')) {
|
|
162
|
-
console.error('Usage: bun scripts/skills/public-check.ts [--json]');
|
|
211
|
+
if (args.some((arg) => arg !== '--json' && arg !== '--build')) {
|
|
212
|
+
console.error('Usage: bun scripts/skills/public-check.ts [--json] [--build]');
|
|
163
213
|
process.exitCode = 2;
|
|
164
214
|
} else {
|
|
165
|
-
const
|
|
166
|
-
console.log(
|
|
167
|
-
|
|
215
|
+
const result = runPublicCheck(join(import.meta.dir, '..', '..'), args);
|
|
216
|
+
console.log(result.output);
|
|
217
|
+
process.exitCode = result.exitCode;
|
|
168
218
|
}
|
|
169
219
|
}
|
|
@@ -57,7 +57,10 @@ const HARNESS_TEST_ENV_KEYS = [
|
|
|
57
57
|
// Discovery: rg -n "process\.env\.ELANOUS_(HOST|RUN|ORIGIN|SUPERVISOR|PARENT)" src
|
|
58
58
|
// These are ambient execution identities, not inputs to a deterministic test.
|
|
59
59
|
// debug.log also attributes SUBSTRATE and ARM_ID to every plain-object record.
|
|
60
|
-
const GIT_LOCATION_ENV_KEYS = [
|
|
60
|
+
export const GIT_LOCATION_ENV_KEYS = [
|
|
61
|
+
'GIT_DIR', 'GIT_WORK_TREE', 'GIT_COMMON_DIR', 'GIT_INDEX_FILE',
|
|
62
|
+
'GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
|
63
|
+
] as const;
|
|
61
64
|
|
|
62
65
|
const EXECUTION_ORIGIN_ENV_KEYS = [
|
|
63
66
|
'ELANOUS_HOST_ID',
|
|
@@ -123,7 +126,7 @@ export type DeterministicRunnerDeps = {
|
|
|
123
126
|
childGraceMs?: number;
|
|
124
127
|
killProcessGroup?: KillProcessGroup;
|
|
125
128
|
getProcessGroupId?: GetProcessGroupId;
|
|
126
|
-
gitConfig?: (cwd: string, args: string[]) => string;
|
|
129
|
+
gitConfig?: (cwd: string, args: string[]) => string | undefined;
|
|
127
130
|
};
|
|
128
131
|
|
|
129
132
|
export function isLivePid(pid: number): boolean {
|
|
@@ -273,14 +276,17 @@ export async function terminateDirectChild(
|
|
|
273
276
|
reportVisible(`failed to terminate child pid=${pid}`, report);
|
|
274
277
|
}
|
|
275
278
|
|
|
276
|
-
function gitConfig(cwd: string, args: string[]): string {
|
|
279
|
+
function gitConfig(cwd: string, args: string[]): string | undefined {
|
|
277
280
|
const env = { ...process.env };
|
|
278
281
|
for (const key of GIT_LOCATION_ENV_KEYS) delete env[key];
|
|
279
282
|
const result = spawnSync('git', args, { cwd, env, encoding: 'utf8' });
|
|
280
283
|
if (result.error || (result.status !== 0 && !(result.status === 1 && args.includes('--get-all') && !result.stderr))) {
|
|
281
284
|
throw new Error(`git ${args.join(' ')} failed: ${result.error?.message ?? result.stderr}`);
|
|
282
285
|
}
|
|
283
|
-
|
|
286
|
+
if (result.status === 1) return undefined;
|
|
287
|
+
// --null --get-all terminates each complete value with NUL, even when
|
|
288
|
+
// a value itself contains newlines or is empty.
|
|
289
|
+
return args.includes('--get-all') ? result.stdout : result.stdout.trim();
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
export function prepareIsolatedTestEnv(sourceEnv: NodeJS.ProcessEnv, testRoot: string): NodeJS.ProcessEnv {
|
|
@@ -406,33 +412,45 @@ export async function runDeterministicTests(deps: DeterministicRunnerDeps = {}):
|
|
|
406
412
|
const cwd = deps.cwd ?? process.cwd();
|
|
407
413
|
const config = deps.gitConfig ?? gitConfig;
|
|
408
414
|
const commonDir = config(cwd, ['rev-parse', '--path-format=absolute', '--git-common-dir']);
|
|
415
|
+
if (commonDir === undefined) throw new Error('git common directory is unset');
|
|
409
416
|
const configFile = join(resolve(cwd, commonDir), 'config');
|
|
410
|
-
const
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
417
|
+
const configArgs = ['config', '--file', configFile];
|
|
418
|
+
const watchedKeys = ['core.bare', 'user.name', 'user.email'] as const;
|
|
419
|
+
// Legacy injected gitConfig fixtures supply newline-delimited results and
|
|
420
|
+
// return '' for an absent key. Real Git uses NUL-delimited complete values.
|
|
421
|
+
const readConfig = (key: string): string[] => {
|
|
422
|
+
const value = config(cwd, [...configArgs, '--null', '--get-all', key]);
|
|
423
|
+
if (value === undefined || (deps.gitConfig && value === '')) return [];
|
|
424
|
+
if (deps.gitConfig && !value.includes('\0')) return value.split('\n');
|
|
425
|
+
if (!value.endsWith('\0')) throw new Error(`unterminated git config value for ${key}`);
|
|
426
|
+
return value.slice(0, -1).split('\0');
|
|
427
|
+
};
|
|
428
|
+
const before = new Map(watchedKeys.map((key) => [key, readConfig(key)]));
|
|
429
|
+
let configChanged = false;
|
|
430
|
+
let configChecked = false;
|
|
431
|
+
const checkConfig = (): void => {
|
|
432
|
+
configChecked = true;
|
|
433
|
+
const visible = (values: string[]) => values.length === 0 ? '<unset>' : values.map((value) => value === '' ? '<empty>' : value.replaceAll('\n', ',')).join(',');
|
|
434
|
+
for (const key of watchedKeys) {
|
|
435
|
+
const original = before.get(key)!;
|
|
436
|
+
let after: string[] = ['<unreadable>'];
|
|
437
|
+
try {
|
|
438
|
+
after = readConfig(key);
|
|
439
|
+
if (JSON.stringify(after) === JSON.stringify(original)) continue;
|
|
440
|
+
configChanged = true;
|
|
441
|
+
if (original.length > 0) {
|
|
442
|
+
config(cwd, [...configArgs, '--replace-all', key, original[0]!]);
|
|
443
|
+
for (const value of original.slice(1)) config(cwd, [...configArgs, '--add', key, value]);
|
|
444
|
+
} else {
|
|
445
|
+
config(cwd, [...configArgs, '--unset-all', key]);
|
|
446
|
+
}
|
|
447
|
+
const restored = readConfig(key);
|
|
448
|
+
if (JSON.stringify(restored) !== JSON.stringify(original)) throw new Error(`expected ${visible(original)}, got ${visible(restored)}`);
|
|
449
|
+
report(`[test-deterministic] ${key} changed ${visible(original)} -> ${visible(after)}; restored ${visible(original)}; failing run`);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
configChanged = true;
|
|
452
|
+
report(`[test-deterministic] ${key} changed ${visible(original)} -> ${visible(after)}; restore failed: ${formatError(error)}`);
|
|
429
453
|
}
|
|
430
|
-
const restored = readBare();
|
|
431
|
-
if (restored !== bareBefore) throw new Error(`expected ${visible(bareBefore)}, got ${visible(restored)}`);
|
|
432
|
-
report(`[test-deterministic] core.bare changed ${visible(bareBefore)} -> ${visible(bareAfter)}; restored ${visible(bareBefore)}; failing run`);
|
|
433
|
-
} catch (error) {
|
|
434
|
-
bareChanged = true;
|
|
435
|
-
report(`[test-deterministic] core.bare changed ${visible(bareBefore)} -> ${visible(bareAfter)}; restore failed: ${formatError(error)}`);
|
|
436
454
|
}
|
|
437
455
|
};
|
|
438
456
|
// ⛔ 사람이 «경로»를 직접 준 창에서는 아무것도 빼지 않는다 — 그 창은 「이것만 돌려라」다.
|
|
@@ -494,7 +512,7 @@ export async function runDeterministicTests(deps: DeterministicRunnerDeps = {}):
|
|
|
494
512
|
});
|
|
495
513
|
cleanupTemporaryRoot(testRoot, { rmSync: deps.rmSync, report });
|
|
496
514
|
rootCleanupAttempted = true;
|
|
497
|
-
|
|
515
|
+
checkConfig();
|
|
498
516
|
gate?.dispose();
|
|
499
517
|
gate = undefined;
|
|
500
518
|
if (deps.killSelf) {
|
|
@@ -509,8 +527,8 @@ export async function runDeterministicTests(deps: DeterministicRunnerDeps = {}):
|
|
|
509
527
|
}
|
|
510
528
|
|
|
511
529
|
cleanupRoot();
|
|
512
|
-
|
|
513
|
-
return
|
|
530
|
+
checkConfig();
|
|
531
|
+
return configChanged ? 1 : (outcome.code ?? 1);
|
|
514
532
|
} catch (error) {
|
|
515
533
|
if (child) {
|
|
516
534
|
try {
|
|
@@ -529,7 +547,7 @@ export async function runDeterministicTests(deps: DeterministicRunnerDeps = {}):
|
|
|
529
547
|
} finally {
|
|
530
548
|
gate?.dispose();
|
|
531
549
|
cleanupRoot();
|
|
532
|
-
if (!
|
|
550
|
+
if (!configChecked) checkConfig();
|
|
533
551
|
}
|
|
534
552
|
}
|
|
535
553
|
|