elanous 0.2.18 → 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/{P6YTVgzuZz5oTZhY4Din_ → J5H7BvqgSI8DUjtRRcA_S}/_buildManifest.js +1 -1
- 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 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- 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 +1 -1
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +3 -1
- 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/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +338 -46
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +120 -0
- package/scripts/release-loop/resume-release.ts +64 -5
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +2 -0
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +255 -0
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +13 -7
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +32 -7
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +104 -11
- 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/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +44 -13
- 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/graph-runner/runner.ts +25 -5
- package/src/harness/harness-cli-command.ts +2 -0
- package/src/harness/harness-salvage-cli.ts +78 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/hq.ts +6 -1
- package/src/index.ts +52 -3
- 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/digest.ts +39 -15
- 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/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +33 -3
- package/src/loops/orchestrator/tick.ts +166 -45
- package/src/maturity/feature-maturity.ts +6 -4
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/http-server.ts +16 -5
- package/src/nexus/api/loop-edges.ts +290 -17
- package/src/nexus/api/ops-api.ts +96 -28
- package/src/nexus/index.ts +7 -0
- package/src/release-loop/checklist.ts +2 -0
- package/src/release-loop/feature-store.ts +54 -7
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +51 -17
- package/src/release-loop/rubric.ts +57 -1
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +179 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/orchestrator.ts +2 -1
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/task-agent/actions.ts +63 -2
- 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 +18 -0
- package/src/task-agent/live-moves.ts +176 -0
- package/src/task-agent/mission.ts +32 -6
- package/src/task-agent/shadow.ts +183 -15
- package/src/task-agent/task-hand.ts +117 -15
- package/src/task-orchestrator/surfaces/pod-command-job.ts +64 -4
- 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 +2 -2
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +11 -0
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +134 -2
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-30dff22c9e1f3073.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/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- 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/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.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/3857-4f936cdb30322aa6.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-5761612531d0146b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6158.af2e93b7adff709b.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.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-8615a660c84cdb03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- 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-d92f7ee3994e84c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-4733c967b56a4277.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d22fd849cc22f104.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-bb742f995c6769e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-02b073a2ac793b83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-8a9b3594bc23289b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-308111abadf35670.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-5d97b2901e0d1ea6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c39554c321576982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-8c3d8e63ae2e1c98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-9b72a07d424701c6.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-bd5d586429167fea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a572f58cd3ca5864.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-be5ea965a07fbc41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-fa244bd146a00ae8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-44d56d6391965a6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-83a700d4c754d802.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-7b3170f374f77b9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a3c58f5c72a5f3f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1467047104141297.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-102310930791197a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-6ed0b73bae8351d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-44d5f767491692bf.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-43336055451f6e37.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-3cc47dca0922ab9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a77ee355a2304ff0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-b17cd46cf0e9b8cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-61553851aa606146.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-a1f585e154e61c59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-7bf54c9bb9274af8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-5150ef17b5383a57.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-134da468538baf48.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.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-c2782b330447ffb6.js +0 -1
- package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +0 -1
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → J5H7BvqgSI8DUjtRRcA_S}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdtempSync, rmSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
export interface PreviewOptions {
|
|
6
|
+
target: string;
|
|
7
|
+
repoRoot: string;
|
|
8
|
+
scenario?: string;
|
|
9
|
+
/** Main-based combined preview: only existing config paths may be enabled. */
|
|
10
|
+
flags?: readonly string[];
|
|
11
|
+
commentPr?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface PreviewResult {
|
|
14
|
+
target: string;
|
|
15
|
+
head: string;
|
|
16
|
+
scenario: string;
|
|
17
|
+
status: 'passed' | 'friction';
|
|
18
|
+
report: string;
|
|
19
|
+
prNumber?: number;
|
|
20
|
+
commented: boolean;
|
|
21
|
+
}
|
|
22
|
+
export function readPreviewResult(directory: string): PreviewResult | null {
|
|
23
|
+
try {
|
|
24
|
+
const value = JSON.parse(readFileSync(join(directory, 'preview-result.json'), 'utf8')) as PreviewResult;
|
|
25
|
+
return value && (value.status === 'passed' || value.status === 'friction') && typeof value.head === 'string' ? value : null;
|
|
26
|
+
} catch { return null; }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface PreviewDeps {
|
|
30
|
+
run?: (command: string, args: readonly string[], cwd: string, timeoutMs?: number) => { status: number | null; stdout: string; stderr: string };
|
|
31
|
+
makeDir?: () => string;
|
|
32
|
+
dispose?: (directory: string) => void;
|
|
33
|
+
wait?: (ms: number) => Promise<void>;
|
|
34
|
+
/** Probe a test-mode daemon without injecting a global HTTP client into the command runner. */
|
|
35
|
+
probePwa?: (url: string) => Promise<boolean>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const SCENARIOS: Record<string, string> = {
|
|
39
|
+
S2: '/help', S3: '/status', S6: '/now', S7: '/term list', S8: '/model', S9: '/harness',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function previewScenarioInput(scenario: string): string {
|
|
43
|
+
const text = Object.hasOwn(SCENARIOS, scenario) ? SCENARIOS[scenario] : undefined;
|
|
44
|
+
if (!text) throw new Error(`TUI-COMFORT §4: unsupported scenario ${scenario}; available: ${Object.keys(SCENARIOS).join(', ')}`);
|
|
45
|
+
return text;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const defaultRun: NonNullable<PreviewDeps['run']> = (command, args, cwd, timeoutMs = 120_000) => {
|
|
49
|
+
const r = spawnSync(command, [...args], { cwd, encoding: 'utf8', timeout: timeoutMs, maxBuffer: 4 * 1024 * 1024 });
|
|
50
|
+
return { status: r.status, stdout: r.stdout ?? '', stderr: r.stderr ?? String(r.error ?? '') };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Build and exercise a detached head, never the caller's checkout. The report is posted only after measurement. */
|
|
54
|
+
export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps = {}): Promise<PreviewResult> {
|
|
55
|
+
const run = deps.run ?? defaultRun;
|
|
56
|
+
const root = resolve(options.repoRoot);
|
|
57
|
+
const target = options.target.trim();
|
|
58
|
+
if (!target || target.startsWith('-') || /[\s\x00-\x1f]/u.test(target)) throw new Error('preview: invalid PR number or branch');
|
|
59
|
+
const isPr = /^[1-9]\d*$/u.test(target);
|
|
60
|
+
if (isPr && !Number.isSafeInteger(Number(target))) throw new Error('preview: invalid PR number');
|
|
61
|
+
if (/^\d+$/u.test(target) && !isPr) throw new Error('preview: invalid PR number');
|
|
62
|
+
if (options.commentPr !== undefined && (!Number.isSafeInteger(options.commentPr) || options.commentPr <= 0)) throw new Error('preview: invalid --comment-pr');
|
|
63
|
+
if (target === 'main' && options.commentPr === undefined) throw new Error('preview: main ⊕ flags requires --comment-pr <PR number> to publish the result');
|
|
64
|
+
if (isPr && options.commentPr !== undefined && options.commentPr !== Number(target)) throw new Error('preview: --comment-pr must match the target PR');
|
|
65
|
+
const flags = options.flags ?? [];
|
|
66
|
+
if (flags.length && target !== 'main') throw new Error('preview: --flag requires main (main ⊕ feature flags)');
|
|
67
|
+
if (flags.some((flag) => !/^[a-zA-Z][\w-]*(?:\.[a-zA-Z][\w-]*)+$/u.test(flag))) throw new Error('preview: --flag expects an existing dotted config path');
|
|
68
|
+
const scenario = options.scenario ?? 'S2';
|
|
69
|
+
const input = previewScenarioInput(scenario);
|
|
70
|
+
const check = (command: string, args: readonly string[], cwd: string, timeout?: number): string => {
|
|
71
|
+
const r = run(command, args, cwd, timeout);
|
|
72
|
+
if (r.status !== 0) throw new Error(`preview: ${command} ${args.join(' ')} failed: ${(r.stdout + '\n' + r.stderr).slice(-600)}`);
|
|
73
|
+
return r.stdout.trim();
|
|
74
|
+
};
|
|
75
|
+
let prNumber = isPr ? Number(target) : options.commentPr;
|
|
76
|
+
let branchPrHead: string | undefined;
|
|
77
|
+
let ref = target;
|
|
78
|
+
if (isPr) {
|
|
79
|
+
const pr = JSON.parse(check('gh', ['pr', 'view', target, '--json', 'number,headRefOid'], root)) as { number?: number; headRefOid?: string };
|
|
80
|
+
if (pr.number !== Number(target) || !/^[0-9a-f]{40}$/iu.test(pr.headRefOid ?? '')) throw new Error('preview: PR head is unavailable');
|
|
81
|
+
ref = pr.headRefOid!;
|
|
82
|
+
} else if (target !== 'main') {
|
|
83
|
+
check('git', ['check-ref-format', '--branch', target], root);
|
|
84
|
+
if (options.commentPr === undefined) {
|
|
85
|
+
const matching = JSON.parse(check('gh', ['pr', 'list', '--head', target, '--state', 'open', '--json', 'number,headRefOid'], root)) as Array<{ number?: number; headRefOid?: string }>;
|
|
86
|
+
if (matching.length !== 1 || !Number.isSafeInteger(matching[0]?.number)) throw new Error('preview: branch has no unique open PR; use --comment-pr <PR number>');
|
|
87
|
+
prNumber = matching[0]!.number;
|
|
88
|
+
branchPrHead = matching[0]!.headRefOid;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (isPr && run('git', ['cat-file', '-e', `${ref}^{commit}`], root).status !== 0) {
|
|
92
|
+
check('git', ['fetch', '--no-tags', 'origin', `pull/${target}/head`], root, 120_000);
|
|
93
|
+
const fetched = check('git', ['rev-parse', '--verify', 'FETCH_HEAD^{commit}'], root);
|
|
94
|
+
if (fetched !== ref) throw new Error('preview: PR head changed while fetching; retry');
|
|
95
|
+
}
|
|
96
|
+
const head = check('git', ['rev-parse', '--verify', `${ref}^{commit}`], root);
|
|
97
|
+
if (!/^[0-9a-f]{40}$/iu.test(head)) throw new Error('preview: unresolved commit');
|
|
98
|
+
if (target !== 'main' && !isPr) {
|
|
99
|
+
const pr = JSON.parse(check('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,headRefName'], root)) as { headRefOid?: string; headRefName?: string };
|
|
100
|
+
if (pr.headRefName !== target || pr.headRefOid !== head || (branchPrHead !== undefined && branchPrHead !== head)) throw new Error('preview: branch does not match the target PR head; use the PR number');
|
|
101
|
+
}
|
|
102
|
+
const directory = (deps.makeDir ?? (() => {
|
|
103
|
+
const previews = join(root, '.elanous-test', 'previews');
|
|
104
|
+
mkdirSync(previews, { recursive: true });
|
|
105
|
+
return mkdtempSync(join(previews, 'preview-'));
|
|
106
|
+
}))();
|
|
107
|
+
const worktree = join(directory, 'checkout');
|
|
108
|
+
let added = false;
|
|
109
|
+
let heldPty: string | undefined;
|
|
110
|
+
let report = '';
|
|
111
|
+
const wait = deps.wait ?? ((ms: number) => new Promise<void>((done) => setTimeout(done, ms)));
|
|
112
|
+
try {
|
|
113
|
+
check('git', ['worktree', 'add', '--detach', worktree, head], root);
|
|
114
|
+
added = true;
|
|
115
|
+
check('bun', ['install', '--frozen-lockfile'], worktree, 300_000);
|
|
116
|
+
check('bun', ['install', '--frozen-lockfile'], join(worktree, 'apps/pwa'), 300_000);
|
|
117
|
+
for (const flag of flags) {
|
|
118
|
+
const existing = check('bun', ['bin/elanous.mjs', '--test', 'config', 'get', flag], worktree);
|
|
119
|
+
if (existing !== 'true' && existing !== 'false') throw new Error(`preview: ${flag} is not a boolean feature flag`);
|
|
120
|
+
check('bun', ['bin/elanous.mjs', '--test', 'config', 'set', flag, 'true'], worktree);
|
|
121
|
+
}
|
|
122
|
+
check('bun', ['bin/elanous.mjs', '--test', 'nexus', 'build', '--cwd', join(worktree, 'apps/pwa')], worktree, 300_000);
|
|
123
|
+
const pwa = check('bun', ['bin/elanous.mjs', '--test', 'nexus', 'run', '--test', '--tool-cwd', worktree], worktree, 120_000);
|
|
124
|
+
const port = /\bnexus\s+:(314[5-9]\d)\b/u.exec(pwa)?.[1];
|
|
125
|
+
const endpoint = port ? `http://127.0.0.1:${port}` : undefined;
|
|
126
|
+
if (!endpoint) throw new Error('preview: P-1 has no local test endpoint');
|
|
127
|
+
const probeOnce = deps.probePwa ?? (async (url: string) => {
|
|
128
|
+
try {
|
|
129
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
130
|
+
return response.ok && (await response.text()).includes('<');
|
|
131
|
+
} catch { return false; }
|
|
132
|
+
});
|
|
133
|
+
// `nexus run` detaches and returns before the daemon listens — its exit is not readiness. Poll.
|
|
134
|
+
let probe = false;
|
|
135
|
+
for (let attempt = 0; attempt < 60 && !probe; attempt++) {
|
|
136
|
+
probe = await probeOnce(`${endpoint}/app/`);
|
|
137
|
+
if (!probe) await wait(1000);
|
|
138
|
+
}
|
|
139
|
+
if (!probe) throw new Error('preview: P-1 did not serve the built PWA');
|
|
140
|
+
const version = check('bun', ['bin/elanous.mjs', '--version'], worktree);
|
|
141
|
+
if (!version) throw new Error('preview: B-1 version probe returned no output');
|
|
142
|
+
const held = check('bun', ['bin/elanous.mjs', '--test', 'dev', '--elanous', '--hold', '--cwd', worktree, '--isolated-root', join(directory, 'tui'), '--json'], worktree, 120_000);
|
|
143
|
+
const last = held.split('\n').reverse().find((line: string) => line.trim().startsWith('{'));
|
|
144
|
+
const pty = last ? JSON.parse(last) as { held?: boolean; ptyId?: string } : {};
|
|
145
|
+
if (pty.held !== true || !/^pty_[\w-]+$/u.test(pty.ptyId ?? '')) throw new Error('preview: B-1 held TUI did not return a PTY reference');
|
|
146
|
+
heldPty = pty.ptyId;
|
|
147
|
+
const snapshotArgs = ['bin/elanous.mjs', '--test', 'pty', 'snapshot', pty.ptyId!] as const;
|
|
148
|
+
const before = check('bun', snapshotArgs, worktree);
|
|
149
|
+
check('bun', ['bin/elanous.mjs', '--test', 'pty', 'text', pty.ptyId!, input, '--enter'], worktree);
|
|
150
|
+
// A constant sleep misses slow frames under load — poll until the screen answers (≤ 20s).
|
|
151
|
+
let snapshot = '';
|
|
152
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
153
|
+
await wait(1000);
|
|
154
|
+
snapshot = check('bun', snapshotArgs, worktree);
|
|
155
|
+
if (snapshot && snapshot !== 'ok' && snapshot !== before) break;
|
|
156
|
+
}
|
|
157
|
+
if (!snapshot || snapshot === 'ok' || snapshot === before) throw new Error('preview: inner PTY did not show a response to the scenario input within 20s');
|
|
158
|
+
report = `| Check | Observation |\n|---|---|\n| head | \`${head}\` |\n| B-1 version | ${version.slice(0, 120)} |\n| P-1 PWA | \`${endpoint}/app/\` served the built PWA |\n| TUI-COMFORT §4 ${scenario} | \`${input}\` → snapshot captured |\n\n<details><summary>Inner PTY snapshot</summary>\n\n\`\`\`text\n${snapshot.slice(-3000).replaceAll('```', "'''")}\n\`\`\`\n</details>`;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
report = `| Check | Friction |\n|---|---|\n| head | \`${head}\` |\n| TUI-COMFORT §4 ${scenario} | ${String(error).replaceAll('|', '\\|').slice(0, 700)} |`;
|
|
161
|
+
} finally {
|
|
162
|
+
if (added) {
|
|
163
|
+
if (heldPty) run('bun', ['bin/elanous.mjs', '--test', 'pty', 'key', heldPty, 'ctrl+c'], worktree, 30_000);
|
|
164
|
+
run('bun', ['bin/elanous.mjs', '--test', 'nexus', 'run', '--test', '--stop'], worktree, 30_000);
|
|
165
|
+
const removed = run('git', ['worktree', 'remove', '--force', worktree], root, 30_000);
|
|
166
|
+
if (removed.status !== 0) throw new Error(`preview: failed to remove isolated worktree: ${removed.stderr}`);
|
|
167
|
+
}
|
|
168
|
+
(deps.dispose ?? ((dir) => rmSync(dir, { recursive: true, force: true })))(directory);
|
|
169
|
+
}
|
|
170
|
+
const status = report.includes('| Friction |') ? 'friction' : 'passed';
|
|
171
|
+
const body = `## PR preview — ${target} (${status})\n\n${report}`;
|
|
172
|
+
if (prNumber === undefined) throw new Error('preview: cannot comment without a PR number');
|
|
173
|
+
check('gh', ['pr', 'comment', String(prNumber), '--body', body], root);
|
|
174
|
+
const result: PreviewResult = { target, head, scenario, status, report: body, prNumber, commented: true };
|
|
175
|
+
const resultDir = join(root, '.elanous-test');
|
|
176
|
+
mkdirSync(resultDir, { recursive: true });
|
|
177
|
+
writeFileSync(join(resultDir, 'preview-result.json'), JSON.stringify(result), { mode: 0o600 });
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
@@ -11,6 +11,7 @@ export interface ShardRunResult {
|
|
|
11
11
|
shards: GateTestShard[];
|
|
12
12
|
attempts: GateShardAttempt[];
|
|
13
13
|
reason?: string;
|
|
14
|
+
measurementFailures?: number;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type ShardProcess = (cwd: string, files: readonly string[]) => {
|
|
@@ -34,24 +35,39 @@ export function runShardedGateTests(
|
|
|
34
35
|
if (!Number.isSafeInteger(count) || count < 1) throw new Error('invalid --shards count');
|
|
35
36
|
const rss = new Map<string, number>();
|
|
36
37
|
const seconds = new Map<string, number>();
|
|
38
|
+
const failedMeasurements: string[] = [];
|
|
37
39
|
for (const file of [...new Set(files)]) {
|
|
38
40
|
let sample: ReturnType<ShardProcess>;
|
|
39
41
|
try {
|
|
40
42
|
sample = run(cwd, [file]);
|
|
41
|
-
} catch
|
|
42
|
-
|
|
43
|
+
} catch {
|
|
44
|
+
failedMeasurements.push(file);
|
|
45
|
+
continue;
|
|
43
46
|
}
|
|
44
|
-
if (![0, 1].includes(sample.exitCode ?? -1) || sample.signal || !sample.junit
|
|
45
|
-
|
|
47
|
+
if (![0, 1].includes(sample.exitCode ?? -1) || sample.signal || !sample.junit
|
|
48
|
+
|| !Number.isFinite(sample.rssMb) || sample.rssMb! <= 0
|
|
49
|
+
|| !Number.isFinite(sample.seconds) || sample.seconds! < 0) {
|
|
50
|
+
failedMeasurements.push(file);
|
|
51
|
+
continue;
|
|
46
52
|
}
|
|
47
53
|
rss.set(file, sample.rssMb!);
|
|
48
54
|
seconds.set(file, sample.seconds!);
|
|
49
55
|
}
|
|
56
|
+
if (failedMeasurements.length) {
|
|
57
|
+
if (!rss.size) return { aggregate: { status: 'unmeasured', retryShardIds: [] }, shards: [], attempts: [], reason: 'no valid file measurements', measurementFailures: failedMeasurements.length };
|
|
58
|
+
const averageRss = [...rss.values()].reduce((sum, value) => sum + value, 0) / rss.size;
|
|
59
|
+
const averageSeconds = [...seconds.values()].reduce((sum, value) => sum + value, 0) / seconds.size;
|
|
60
|
+
for (const file of failedMeasurements) {
|
|
61
|
+
rss.set(file, averageRss);
|
|
62
|
+
seconds.set(file, averageSeconds);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const measurementFailures = failedMeasurements.length || undefined;
|
|
50
66
|
let shards: GateTestShard[];
|
|
51
67
|
try {
|
|
52
68
|
shards = planGateTestShards(files, rss, seconds, budgetGiB, count);
|
|
53
69
|
} catch (error) {
|
|
54
|
-
return { aggregate: { status: 'unmeasured', retryShardIds: [] }, shards: [], attempts: [], reason: String(error) };
|
|
70
|
+
return { aggregate: { status: 'unmeasured', retryShardIds: [] }, shards: [], attempts: [], reason: String(error), ...(measurementFailures ? { measurementFailures } : {}) };
|
|
55
71
|
}
|
|
56
72
|
const attempts: GateShardAttempt[] = [];
|
|
57
73
|
const baseline = baselineWorktree(cwd, baseRef, (dir) => {
|
|
@@ -76,8 +92,8 @@ export function runShardedGateTests(
|
|
|
76
92
|
}
|
|
77
93
|
return aggregateGateTestShards(shards, attempts);
|
|
78
94
|
});
|
|
79
|
-
if ('retryShardIds' in baseline) return { aggregate: baseline, shards, attempts };
|
|
80
|
-
return { aggregate: { status: 'unmeasured', retryShardIds: shards.map((shard) => shard.id) }, shards, attempts, reason: baseline.log };
|
|
95
|
+
if ('retryShardIds' in baseline) return { aggregate: baseline, shards, attempts, ...(measurementFailures ? { measurementFailures } : {}) };
|
|
96
|
+
return { aggregate: { status: 'unmeasured', retryShardIds: shards.map((shard) => shard.id) }, shards, attempts, reason: baseline.log, ...(measurementFailures ? { measurementFailures } : {}) };
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
export function runBunShard(cwd: string, files: readonly string[]): ReturnType<ShardProcess> {
|
|
@@ -26,10 +26,13 @@ import {
|
|
|
26
26
|
import { listWorktrees } from '../git-fs/worktree.js';
|
|
27
27
|
import { runShardedGateTests } from '../self-dev/shard-run.js';
|
|
28
28
|
|
|
29
|
-
interface SelfGateCliOptions {
|
|
29
|
+
export interface SelfGateCliOptions {
|
|
30
30
|
base?: string;
|
|
31
31
|
pr?: string;
|
|
32
32
|
shards?: number;
|
|
33
|
+
/** LIGHT-RC (0.2.19) — repository-relative test paths run on every call, whatever changed. Existing ones join the
|
|
34
|
+
* run (deduplicated, same introduced/preexisting baseline as the rest); missing ones go to `alwaysIncludeMissing`. */
|
|
35
|
+
alwaysInclude?: readonly string[];
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
interface ProcessResult {
|
|
@@ -102,7 +105,7 @@ interface GateOutput {
|
|
|
102
105
|
error: (message: string) => void;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
interface SelfGateCliResult {
|
|
108
|
+
export interface SelfGateCliResult {
|
|
106
109
|
exitCode: number;
|
|
107
110
|
lines: string[];
|
|
108
111
|
changedFiles: string[];
|
|
@@ -110,6 +113,11 @@ interface SelfGateCliResult {
|
|
|
110
113
|
unverified: readonly string[];
|
|
111
114
|
documentPaths: readonly string[];
|
|
112
115
|
documentsWithoutDerivedTests: readonly string[];
|
|
116
|
+
/** `alwaysInclude` paths that do not exist in the tree (empty when none were given). */
|
|
117
|
+
alwaysIncludeMissing: readonly string[];
|
|
118
|
+
/** New vs. already-present failures (unknown/preconditionUnmet = failures it could not classify). Absent = the test
|
|
119
|
+
* step did not produce a measurement (e.g. shards unmeasured). */
|
|
120
|
+
baseline?: { introduced: number; preexisting: number; unknown: number; preconditionUnmet: number };
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
/** 시험 단계와 독립인 정책 관문 넷. skipTestStep 이든 시험 통과든 같은 함수를 부른다. */
|
|
@@ -590,7 +598,12 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
590
598
|
const expose = publicExposureFiles(selection.files).length > 0
|
|
591
599
|
? runExposeGate(cwd, selection.files, getUserConfig().harness?.exposeGate === 'strict' ? 'strict' : 'warn', deps.runCommand)
|
|
592
600
|
: { passed: true, log: '' };
|
|
593
|
-
const
|
|
601
|
+
const alwaysInclude = [...new Set((options.alwaysInclude ?? []).map(normalizeGatePath).filter(Boolean))];
|
|
602
|
+
const alwaysIncludeMissing = alwaysInclude.filter((path) => !exists(path));
|
|
603
|
+
const scopedTests = scope.testArgs ?? [];
|
|
604
|
+
const alwaysIncludeExtra = alwaysInclude.filter((path) => exists(path) && !scopedTests.includes(path));
|
|
605
|
+
const testFiles = [...scopedTests, ...alwaysIncludeExtra];
|
|
606
|
+
const skipTestStep = scope.skipTestStep && alwaysIncludeExtra.length === 0;
|
|
594
607
|
const unrunImporterTotal = lookupFailed ? null : (scope.importerTestsNotRun?.total ?? 0);
|
|
595
608
|
const importerLookupFailed = Boolean(lookupFailed);
|
|
596
609
|
const lines = [
|
|
@@ -619,6 +632,10 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
619
632
|
...(routeIndex?.lookupFailures.length ? [`⚠️ caller route base lookup failed — unmeasured: ${routeIndex.lookupFailures.map(({ source, reason }) => `${source} (${reason})`).join(', ')}`] : []),
|
|
620
633
|
...(scope.callerTestsOverflow.length ? [`⚠️ caller test cap exceeded — not run: ${scope.callerTestsOverflow.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ')}`] : []),
|
|
621
634
|
changedTestCountNote(cwd, selection.files, selection.baseRef, deps.runCommand, deps.readFile),
|
|
635
|
+
// Only printed when the caller asked for always-include paths — the plain `self gate` output is unchanged.
|
|
636
|
+
...(options.alwaysInclude !== undefined
|
|
637
|
+
? [`always include: ${alwaysInclude.length - alwaysIncludeMissing.length}/${alwaysInclude.length} (added ${alwaysIncludeExtra.length}${alwaysIncludeMissing.length ? ` · missing: ${alwaysIncludeMissing.join(', ')}` : ''})`]
|
|
638
|
+
: []),
|
|
622
639
|
];
|
|
623
640
|
if (expose.log) lines.push(expose.log);
|
|
624
641
|
if (options.pr) {
|
|
@@ -641,17 +658,18 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
641
658
|
const iosPassed = runAdditionalGate('ios-gate', deps.runIosGate ?? runIosUnitTestGate, selection.files, cwd, lines);
|
|
642
659
|
const pwaPassed = runAdditionalGate('pwa-gate', deps.runPwaGate ?? runPwaBuildGate, selection.files, cwd, lines);
|
|
643
660
|
|
|
644
|
-
if (
|
|
661
|
+
if (skipTestStep) {
|
|
645
662
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
646
663
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
647
|
-
return { exitCode: androidPassed && iosPassed && pwaPassed && policyPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests };
|
|
664
|
+
return { exitCode: androidPassed && iosPassed && pwaPassed && policyPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
|
|
648
665
|
}
|
|
649
666
|
|
|
650
667
|
if (options.shards !== undefined) {
|
|
651
668
|
const sharded = (deps.runShards ?? runShardedGateTests)(cwd, testFiles, selection.baseRef, options.shards);
|
|
652
|
-
lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})`);
|
|
669
|
+
lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})${sharded.measurementFailures ? ` · 측정 실패 ${sharded.measurementFailures}` : ''}`);
|
|
653
670
|
for (const attempt of sharded.attempts) lines.push(`shard attempt: ${attempt.shardId} #${attempt.attempt}`);
|
|
654
671
|
const { aggregate } = sharded;
|
|
672
|
+
let shardBaseline: SelfGateCliResult['baseline'];
|
|
655
673
|
if (aggregate.status === 'unmeasured') lines.push(`shards: unmeasured (${aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit'})`);
|
|
656
674
|
else if (aggregate.report) {
|
|
657
675
|
const report = aggregate.report;
|
|
@@ -662,15 +680,18 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
662
680
|
baselineFiles: report.files, baselineStatus: report.baselineStatus, unrunImporterTotal, lookupFailed: importerLookupFailed,
|
|
663
681
|
});
|
|
664
682
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
|
|
683
|
+
shardBaseline = { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet };
|
|
665
684
|
} else {
|
|
666
685
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
667
686
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
687
|
+
shardBaseline = { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 };
|
|
668
688
|
}
|
|
669
689
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
670
690
|
return {
|
|
671
691
|
exitCode: aggregate.status !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed || !expose.passed ? 1 : 0,
|
|
672
692
|
lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
|
|
673
693
|
documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
|
|
694
|
+
alwaysIncludeMissing, ...(shardBaseline ? { baseline: shardBaseline } : {}),
|
|
674
695
|
};
|
|
675
696
|
}
|
|
676
697
|
|
|
@@ -680,7 +701,7 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
680
701
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
681
702
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
682
703
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
683
|
-
return { exitCode: policyPassed && androidPassed && iosPassed && pwaPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests };
|
|
704
|
+
return { exitCode: policyPassed && androidPassed && iosPassed && pwaPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
|
|
684
705
|
}
|
|
685
706
|
|
|
686
707
|
if (worktreeLog.includes('deterministic environment setup failed')) lines.push(worktreeLog);
|
|
@@ -702,5 +723,5 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
702
723
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
|
|
703
724
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
704
725
|
const exitCode = !androidPassed || !iosPassed || !pwaPassed || !policyPassed || !expose.passed || report.introduced > 0 || report.unknown > 0 || report.preconditionUnmet > 0 ? 1 : 0;
|
|
705
|
-
return { exitCode, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests };
|
|
726
|
+
return { exitCode, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, baseline: { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet } };
|
|
706
727
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { resolve, relative, isAbsolute } from 'node:path';
|
|
3
|
+
import ts from 'typescript';
|
|
1
4
|
import { tierModel } from '../llm/model-defaults.js';
|
|
2
5
|
import { debug } from '../debug/log.js';
|
|
3
6
|
import type { LLMUsage } from '../prompt-cache/types.js';
|
|
@@ -42,7 +45,7 @@ export function parseGoalAuthorParent(document: string): GoalAuthorParent | null
|
|
|
42
45
|
return matches.length === 1 ? matches[0] : null;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
export type GoalAuthorClarificationAnswerSource = 'injected' | 'recommended' | 'self-authored';
|
|
48
|
+
export type GoalAuthorClarificationAnswerSource = 'injected' | 'recommended' | 'self-authored' | 'default';
|
|
46
49
|
|
|
47
50
|
export interface GoalAuthorClarificationProvenance {
|
|
48
51
|
source: GoalAuthorClarificationAnswerSource;
|
|
@@ -78,8 +81,8 @@ export interface GoalAuthorSelfResolutionContext {
|
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
export type GoalAuthorSelfResolution =
|
|
81
|
-
| { answer: string; evidence: readonly string[] }
|
|
82
|
-
| { answer?: undefined; evidence?: undefined };
|
|
84
|
+
| { answer: string; evidence: readonly string[]; declined?: undefined }
|
|
85
|
+
| { answer?: undefined; evidence?: undefined; declined?: boolean };
|
|
83
86
|
|
|
84
87
|
export interface GoalAuthorClarificationResolutionDeps {
|
|
85
88
|
/** Elanousic authoring seam; it must return no answer when the available evidence is insufficient. */
|
|
@@ -189,7 +192,7 @@ export async function defaultGoalAuthorSelfResolve(
|
|
|
189
192
|
const usages: LLMUsage[] = [];
|
|
190
193
|
if (context.evidence.length === 0) {
|
|
191
194
|
observeSelfResolve('self-resolve-no-evidence', context, startedAt, { usage: deriveUsage(usages) });
|
|
192
|
-
return {};
|
|
195
|
+
return context.questionId === 'preservation_contract' ? { declined: true } : {};
|
|
193
196
|
}
|
|
194
197
|
const controller = new AbortController();
|
|
195
198
|
const timeout = setTimeout(
|
|
@@ -230,7 +233,7 @@ export async function defaultGoalAuthorSelfResolve(
|
|
|
230
233
|
evidenceCount: context.evidence.length,
|
|
231
234
|
usage: deriveUsage(usages),
|
|
232
235
|
});
|
|
233
|
-
return {};
|
|
236
|
+
return answer === null && context.questionId === 'preservation_contract' ? { declined: true } : {};
|
|
234
237
|
} catch (error) {
|
|
235
238
|
observeSelfResolve(
|
|
236
239
|
isSelfResolutionTimeout(error, controller.signal) ? 'self-resolve-timeout' : 'self-resolve-error',
|
|
@@ -471,6 +474,57 @@ interface GoalAuthorClarificationSeed {
|
|
|
471
474
|
parent: GoalAuthorParent;
|
|
472
475
|
}
|
|
473
476
|
|
|
477
|
+
const PRESERVATION_DEFAULT = '대상 경로의 기존 공개 동작(내보내는 함수 시그니처 · CLI 인자·출력·종료 코드)은 그대로 유지한다 · 바뀌는 것은 골이 명시한 동작뿐';
|
|
478
|
+
|
|
479
|
+
function preservationDefault(ask: string): { answer: string; exportCount: number } {
|
|
480
|
+
const request = /Original ask \(verbatim, unmodified\):\s*```\r?\n([\s\S]*?)\r?\n```/.exec(ask)?.[1] ?? ask;
|
|
481
|
+
// Every `대상 경로:` line counts, plain or as a Markdown list item; backticks around a path are cosmetic.
|
|
482
|
+
const paths = [...new Set(request.split(/\r?\n/).flatMap((line) => {
|
|
483
|
+
const match = /^\s*(?:(?:[-*+]|\d+[.)])\s+)?대상 경로:\s*(.*)$/.exec(line);
|
|
484
|
+
return match ? match[1].split(/\s*[,·]\s*/).map((path) => path.trim().replace(/^`|`$/g, '')) : [];
|
|
485
|
+
}))];
|
|
486
|
+
const exports: string[] = [];
|
|
487
|
+
for (const path of paths) {
|
|
488
|
+
if (!/^[\w./-]+\.[cm]?[jt]sx?$/.test(path) || path.startsWith('/') || path.split('/').includes('..')) continue;
|
|
489
|
+
const absolute = resolve(process.cwd(), path);
|
|
490
|
+
try {
|
|
491
|
+
const actual = realpathSync(absolute);
|
|
492
|
+
const withinRepo = relative(realpathSync(process.cwd()), actual);
|
|
493
|
+
if (withinRepo === '..' || withinRepo.startsWith('../') || isAbsolute(withinRepo)) continue;
|
|
494
|
+
const source = ts.createSourceFile(path, readFileSync(actual, 'utf8'), ts.ScriptTarget.Latest, true);
|
|
495
|
+
for (const statement of source.statements) {
|
|
496
|
+
if (ts.isExportDeclaration(statement)) {
|
|
497
|
+
if (statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
498
|
+
for (const element of statement.exportClause.elements) exports.push(`${path}: ${element.name.text}`);
|
|
499
|
+
} else if (statement.exportClause && ts.isNamespaceExport(statement.exportClause)) {
|
|
500
|
+
exports.push(`${path}: ${statement.exportClause.name.text}`);
|
|
501
|
+
} else if (!statement.exportClause && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
502
|
+
// Names re-exported by `export *` are not resolved here; record the re-export itself so the preserved surface is explicit.
|
|
503
|
+
exports.push(`${path}: * from ${statement.moduleSpecifier.text}`);
|
|
504
|
+
}
|
|
505
|
+
} else if (ts.isExportAssignment(statement)) {
|
|
506
|
+
exports.push(`${path}: ${statement.isExportEquals ? 'export =' : 'default'}`);
|
|
507
|
+
} else if (ts.canHaveModifiers(statement) && ts.getModifiers(statement)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
508
|
+
if (ts.getModifiers(statement)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) {
|
|
509
|
+
exports.push(`${path}: default`);
|
|
510
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
511
|
+
const bindingNames = (name: ts.BindingName): string[] => ts.isIdentifier(name)
|
|
512
|
+
? [name.text]
|
|
513
|
+
: name.elements.flatMap((element) => ts.isOmittedExpression(element) ? [] : bindingNames(element.name));
|
|
514
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
515
|
+
for (const exported of bindingNames(declaration.name)) exports.push(`${path}: ${exported}`);
|
|
516
|
+
}
|
|
517
|
+
} else if ('name' in statement && statement.name && ts.isIdentifier(statement.name as ts.Node)) {
|
|
518
|
+
exports.push(`${path}: ${(statement.name as ts.Identifier).text}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
} catch { /* An unavailable target cannot supply verified export names. */ }
|
|
523
|
+
}
|
|
524
|
+
const names = [...new Set(exports)];
|
|
525
|
+
return { answer: names.length ? `${PRESERVATION_DEFAULT} · export 이름: ${names.join(', ')}` : PRESERVATION_DEFAULT, exportCount: names.length };
|
|
526
|
+
}
|
|
527
|
+
|
|
474
528
|
const DEFERRED_ANSWER = 'DEFERRED-UNTIL: ';
|
|
475
529
|
const DEFERRED_ANSWER_PREFIX = 'DEFERRED-UNTIL';
|
|
476
530
|
|
|
@@ -515,7 +569,7 @@ export function parseGoalDocumentClarifications(document: string): GoalDocumentC
|
|
|
515
569
|
readingOptions = false;
|
|
516
570
|
continue;
|
|
517
571
|
}
|
|
518
|
-
const provenanceSource = /^ - provenance\.source: (injected|recommended|self-authored)$/.exec(line);
|
|
572
|
+
const provenanceSource = /^ - provenance\.source: (injected|recommended|self-authored|default)$/.exec(line);
|
|
519
573
|
if (provenanceSource) {
|
|
520
574
|
fields.set('provenanceSource', provenanceSource[1]);
|
|
521
575
|
provenanceLines.push(index);
|
|
@@ -692,6 +746,7 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
692
746
|
ask?: string;
|
|
693
747
|
evidence?: readonly string[];
|
|
694
748
|
resolver?: GoalClarificationSelfResolver;
|
|
749
|
+
runId?: string;
|
|
695
750
|
},
|
|
696
751
|
): Promise<{ document: string; asked: number; answered: number; unanswered: number; newlyAnswered: number }> {
|
|
697
752
|
const clarifications = parseGoalDocumentClarifications(document);
|
|
@@ -699,7 +754,7 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
699
754
|
// The first say pass may already have self-answered some questions while authoring: count those,
|
|
700
755
|
// never re-ask them, and still attempt every question that is left unanswered.
|
|
701
756
|
const alreadySelfAnswered = options.path === 'say-first'
|
|
702
|
-
? clarifications.filter((item) => item.answered && item.provenanceSource === 'self-authored').length
|
|
757
|
+
? clarifications.filter((item) => item.answered && (item.provenanceSource === 'self-authored' || item.provenanceSource === 'default')).length
|
|
703
758
|
: 0;
|
|
704
759
|
let updated = document;
|
|
705
760
|
let answered = 0;
|
|
@@ -709,6 +764,7 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
709
764
|
for (const item of pending) {
|
|
710
765
|
if (parseGoalDocumentClarifications(updated).filter((entry) => entry.questionId === item.questionId).length !== 1) continue;
|
|
711
766
|
let response: Awaited<ReturnType<typeof resolveGoalAuthorClarification>>;
|
|
767
|
+
let declined = false;
|
|
712
768
|
try { response = await resolveGoalAuthorClarification({
|
|
713
769
|
questionId: item.questionId,
|
|
714
770
|
kind: 'scope',
|
|
@@ -717,7 +773,11 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
717
773
|
options: item.options.map((option) => ({ label: option.label, description: option.description })),
|
|
718
774
|
blocking: false,
|
|
719
775
|
}, {
|
|
720
|
-
selfResolve:
|
|
776
|
+
selfResolve: async (context) => {
|
|
777
|
+
const resolution = await (options.resolver ?? defaultGoalAuthorSelfResolve)(context);
|
|
778
|
+
declined = resolution.declined === true;
|
|
779
|
+
return resolution;
|
|
780
|
+
},
|
|
721
781
|
evidence,
|
|
722
782
|
ask: options.ask,
|
|
723
783
|
selfResolutionSelected: true,
|
|
@@ -725,11 +785,19 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
725
785
|
// A resolver failure leaves this question unanswered; the remaining questions are still attempted.
|
|
726
786
|
continue;
|
|
727
787
|
}
|
|
728
|
-
|
|
788
|
+
let defaultExportCount: number | undefined;
|
|
789
|
+
if (response.answer === null && item.questionId === 'preservation_contract'
|
|
790
|
+
&& declined) {
|
|
791
|
+
const fallback = preservationDefault(options.ask ?? document);
|
|
792
|
+
response = { ...response, answer: fallback.answer, status: 'ANSWERED', provenance: { source: 'default' } };
|
|
793
|
+
defaultExportCount = fallback.exportCount;
|
|
794
|
+
}
|
|
795
|
+
if (response.answer === null || (response.provenance?.source !== 'self-authored' && response.provenance?.source !== 'default')
|
|
729
796
|
|| response.answer.startsWith(DEFERRED_ANSWER_PREFIX)) continue;
|
|
797
|
+
const answerSource = response.provenance.source;
|
|
730
798
|
try {
|
|
731
799
|
if (!response.answer.trim() || /[\r\n]/.test(response.answer)
|
|
732
|
-
|| (!item.includeOther && !item.options.some((option) => option.label === response.answer))) continue;
|
|
800
|
+
|| (answerSource !== 'default' && !item.includeOther && !item.options.some((option) => option.label === response.answer))) continue;
|
|
733
801
|
const current = findUnansweredGoalDocumentClarification(updated, item.questionId);
|
|
734
802
|
const lines = updated.split(/\r?\n/);
|
|
735
803
|
const provenanceLines = current.provenanceLines ?? [];
|
|
@@ -737,15 +805,22 @@ export async function selfAnswerGoalDocumentClarifications(
|
|
|
737
805
|
const answerLine = current.answerLine - provenanceLines.filter((line) => line < current.answerLine).length;
|
|
738
806
|
lines[answerLine] = ` - answer: ${response.answer}`;
|
|
739
807
|
lines.splice(answerLine + 1, 0,
|
|
740
|
-
|
|
741
|
-
...response.provenance.evidence
|
|
808
|
+
` - provenance.source: ${answerSource}`,
|
|
809
|
+
...(response.provenance.evidence ?? []).map((entry) => ` - evidence: ${entry.replace(/[\r\n]/g, ' ')}`));
|
|
742
810
|
updateWhatToBuildRenderAnswers(lines, item.questionId, response.answer);
|
|
743
811
|
if (hasWhatToBuildUnansweredRenderAnswer(lines, item.questionId)) continue;
|
|
744
812
|
const candidate = lines.join(document.includes('\r\n') ? '\r\n' : '\n');
|
|
745
813
|
if (!parseGoalDocumentClarifications(candidate).some((entry) => entry.questionId === item.questionId
|
|
746
|
-
&& entry.answered && entry.answer === response.answer && entry.provenanceSource ===
|
|
814
|
+
&& entry.answered && entry.answer === response.answer && entry.provenanceSource === answerSource)) continue;
|
|
747
815
|
updated = candidate;
|
|
748
816
|
answered += 1;
|
|
817
|
+
if (defaultExportCount !== undefined) {
|
|
818
|
+
observeGoalAuthor('goal-author', 'self-answer-default-applied', {
|
|
819
|
+
runId: options.runId ?? process.env.ELANOUS_RUN_ID,
|
|
820
|
+
questionId: item.questionId,
|
|
821
|
+
exportCount: defaultExportCount,
|
|
822
|
+
});
|
|
823
|
+
}
|
|
749
824
|
} catch {
|
|
750
825
|
// Leave malformed or disallowed answers deferred.
|
|
751
826
|
}
|
|
@@ -39,6 +39,7 @@ type GoalClarificationAnsweredBy = 'human' | 'agent' | 'none' | 'mixed';
|
|
|
39
39
|
|
|
40
40
|
export interface GoalClarificationEscalationInput {
|
|
41
41
|
goalFile: string;
|
|
42
|
+
runId?: string;
|
|
42
43
|
/** Explicit provenance for isolated test fixtures; never inferred from goalFile. */
|
|
43
44
|
testOrigin?: true;
|
|
44
45
|
delivery?: GoalClarificationDelivery;
|
|
@@ -443,6 +444,7 @@ export async function escalateGoalDocumentClarifications(
|
|
|
443
444
|
path: input.selfAnswerPath,
|
|
444
445
|
ask: document,
|
|
445
446
|
resolver: input.selfResolveClarification,
|
|
447
|
+
runId: input.runId ?? process.env.ELANOUS_RUN_ID,
|
|
446
448
|
});
|
|
447
449
|
if (resolution.newlyAnswered > 0) {
|
|
448
450
|
writeGoalDocumentAtomic(input.goalFile, resolution.document);
|
|
@@ -5381,6 +5381,7 @@ async function runSelfImplementInner(
|
|
|
5381
5381
|
const { listSubscribers } = await import('../session/index.js');
|
|
5382
5382
|
clarificationEscalation = await escalateGoalDocumentClarifications({
|
|
5383
5383
|
goalFile: resolvedGoalFile,
|
|
5384
|
+
runId,
|
|
5384
5385
|
dispatchContext: clarificationDispatchContext,
|
|
5385
5386
|
resolveOriginDelivery: (sessionId) => originHitlDelivery(listSubscribers(sessionId)),
|
|
5386
5387
|
// ⛔ seam 이 주입되면 전역 리졸버는 «불리지 않는다» — 그때 'terminal' 이라 적으면
|
|
@@ -6231,7 +6232,7 @@ async function runSelfImplementInner(
|
|
|
6231
6232
|
const source = readFileSync(opts.goalFile, 'utf8');
|
|
6232
6233
|
// Always run the shared self-answer so every rework pass leaves one observation, even with nothing pending.
|
|
6233
6234
|
const resolved = await selfAnswerGoalDocumentClarifications(source, {
|
|
6234
|
-
path: 'rework', ask: source, resolver: s.selfResolveClarification,
|
|
6235
|
+
path: 'rework', ask: source, resolver: s.selfResolveClarification, runId,
|
|
6235
6236
|
});
|
|
6236
6237
|
if (resolved.newlyAnswered > 0) writeGoalDocumentAtomic(opts.goalFile, resolved.document);
|
|
6237
6238
|
} catch (error) {
|