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
package/src/esc-abort-gate.ts
CHANGED
|
@@ -34,6 +34,9 @@ import type { KeyEvent } from './display/types.js';
|
|
|
34
34
|
import type { ThemeTokens } from './theme/tokens.js';
|
|
35
35
|
import { debug } from './debug/log.js';
|
|
36
36
|
import { abortTurnOnly } from './turn-abort-scope.js';
|
|
37
|
+
import { SELF_IMPLEMENT_TOOL_NAMES } from './boot/daemon-tools/self-implement-names.js';
|
|
38
|
+
|
|
39
|
+
export const DASHBOARD_CLARIFICATION_REQUEST = Symbol.for('elanous.dashboard.clarification-request');
|
|
37
40
|
|
|
38
41
|
export interface EscAbortGateDeps {
|
|
39
42
|
abortCtrl: AbortController;
|
|
@@ -87,8 +90,14 @@ export async function routeStreamingEscapeKey(
|
|
|
87
90
|
gate: Pick<EscAbortGate, 'handleEscape' | 'handleKey' | 'isGateOpen'>,
|
|
88
91
|
gateEvent: KeyEvent,
|
|
89
92
|
consumeDragEscape: () => Promise<boolean>,
|
|
93
|
+
consumeTopModalEscape: () => boolean | 'passthrough' = () => false,
|
|
90
94
|
): Promise<boolean> {
|
|
91
95
|
if (key.kind && key.kind !== 'press') return false;
|
|
96
|
+
if (key.name === 'escape') {
|
|
97
|
+
const modalResult = consumeTopModalEscape();
|
|
98
|
+
if (modalResult === true) return true;
|
|
99
|
+
if (modalResult === 'passthrough') return false;
|
|
100
|
+
}
|
|
92
101
|
if (gate.isGateOpen()) {
|
|
93
102
|
gate.handleKey(gateEvent);
|
|
94
103
|
return true;
|
|
@@ -99,6 +108,41 @@ export async function routeStreamingEscapeKey(
|
|
|
99
108
|
return true;
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
export function consumeStreamingTopModalEscape(input: {
|
|
112
|
+
modal: Pick<ModalSurface, 'id' | 'onKey'> | null;
|
|
113
|
+
abortGateModalId: string | null;
|
|
114
|
+
event: KeyEvent;
|
|
115
|
+
question?: { id: string; dispose(cancelled: boolean): void; isClarification: boolean };
|
|
116
|
+
onClarificationClosed(): void;
|
|
117
|
+
topModalId(): string | null;
|
|
118
|
+
redraw(): void;
|
|
119
|
+
}): boolean | 'passthrough' {
|
|
120
|
+
const { modal, question } = input;
|
|
121
|
+
if (!modal || modal.id === input.abortGateModalId) return false;
|
|
122
|
+
if (modal.id === question?.id) {
|
|
123
|
+
question.dispose(true);
|
|
124
|
+
if (question.isClarification) input.onClarificationClosed();
|
|
125
|
+
input.redraw();
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (!modal.onKey) return 'passthrough';
|
|
129
|
+
modal.onKey(input.event);
|
|
130
|
+
input.redraw();
|
|
131
|
+
return input.topModalId() === modal.id ? 'passthrough' : true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function createHarnessEscHint(pushLine: (line: string) => void): (targets: readonly string[]) => boolean {
|
|
135
|
+
let shown = false;
|
|
136
|
+
return (targets) => {
|
|
137
|
+
if (!targets.some(name => (SELF_IMPLEMENT_TOOL_NAMES as readonly string[]).includes(name))) return false;
|
|
138
|
+
if (!shown) {
|
|
139
|
+
pushLine('하니스 런은 따로 계속 돈다 — 멈추려면 /harness stop <space-id> · 목록은 /harness runs');
|
|
140
|
+
shown = true;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
102
146
|
export function createEscAbortGate(deps: EscAbortGateDeps): EscAbortGate {
|
|
103
147
|
let current: ApprovalModalHandle | null = null;
|
|
104
148
|
let currentDispose: (() => void) | null = null;
|
|
@@ -35,7 +35,11 @@ export interface GraphRunState {
|
|
|
35
35
|
stoppedAt?: string;
|
|
36
36
|
status: 'running' | 'done' | 'failed' | 'budget-exceeded' | 'awaiting-approval';
|
|
37
37
|
path: string[];
|
|
38
|
-
|
|
38
|
+
/** startedAt/endedAt (ISO) and seconds are written when the node runs; ledgers before GRAPH-NODE-TIMES (0.2.19) have none. */
|
|
39
|
+
nodes: Array<{ nodeId: string; ok: boolean; exit: number | null; executed: boolean; output?: unknown; error?: string; decidedBy?: string; decidedAt?: string;
|
|
40
|
+
startedAt?: string; endedAt?: string; seconds?: number }>;
|
|
41
|
+
/** The node now running and when it started; cleared when its record is written. */
|
|
42
|
+
currentNode?: { nodeId: string; startedAt: string };
|
|
39
43
|
input?: unknown;
|
|
40
44
|
pending?: { nodeId: string; message: string; since: string; notifiedAt?: string; decision?: 'approved' | 'rejected'; decidedBy?: string; decidedAt?: string };
|
|
41
45
|
approvalSourceHash?: string;
|
|
@@ -658,6 +662,8 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
|
|
|
658
662
|
}
|
|
659
663
|
state.status = 'running';
|
|
660
664
|
const startedAt = performance.now();
|
|
665
|
+
const nodeStartedAt = new Date().toISOString();
|
|
666
|
+
if (!resumingCompleted) state.currentNode = { nodeId: current, startedAt: nodeStartedAt };
|
|
661
667
|
console.error(`[graph] ${current} start (0.00s)`);
|
|
662
668
|
debug.log('graph.run', 'node', { graphId, runId, nodeId: current, phase: 'start', dryRun: state.dryRun });
|
|
663
669
|
publishInsideEvent({ kind: 'node', graphId, runId, nodeId: current, phase: 'start' });
|
|
@@ -723,6 +729,10 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
|
|
|
723
729
|
error = result.error ? redactCredentials(result.error) : undefined;
|
|
724
730
|
state.executed++;
|
|
725
731
|
}
|
|
732
|
+
const seconds = Number(((performance.now() - startedAt) / 1000).toFixed(2));
|
|
733
|
+
// A wall clock stepped back mid-node must not record an end before the start.
|
|
734
|
+
const nodeEndedAt = new Date(Math.max(Date.now(), Date.parse(nodeStartedAt))).toISOString();
|
|
735
|
+
delete state.currentNode;
|
|
726
736
|
if (resumingCompleted && completed) {
|
|
727
737
|
ok = completed.ok;
|
|
728
738
|
exit = completed.exit;
|
|
@@ -734,7 +744,8 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
|
|
|
734
744
|
output = JSON.stringify({ outcome: ok ? 'approved' : 'rejected', ...(state.pending?.decidedBy === undefined ? {} : { decidedBy: state.pending.decidedBy }), decidedAt: state.pending?.decidedAt ?? null });
|
|
735
745
|
}
|
|
736
746
|
state.nodes.push({ nodeId: current, ok, exit, executed: !!command && (!state.dryRun || !!command.dry_run_command), ...((command || approval) && (!state.dryRun || !!command?.dry_run_command) && output !== undefined ? { output } : {}), ...(error ? { error } : {}),
|
|
737
|
-
...(approval && state.pending ? { ...(state.pending.decidedBy === undefined ? {} : { decidedBy: state.pending.decidedBy }), decidedAt: state.pending.decidedAt } : {})
|
|
747
|
+
...(approval && state.pending ? { ...(state.pending.decidedBy === undefined ? {} : { decidedBy: state.pending.decidedBy }), decidedAt: state.pending.decidedAt } : {}),
|
|
748
|
+
startedAt: nodeStartedAt, endedAt: nodeEndedAt, seconds });
|
|
738
749
|
}
|
|
739
750
|
if (approval) {
|
|
740
751
|
delete state.pending;
|
|
@@ -742,7 +753,6 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
|
|
|
742
753
|
}
|
|
743
754
|
const reported = command && (!state.dryRun || command.dry_run_command) ? lastJsonObject(resumingCompleted ? completed?.output : output)?.outcome : undefined;
|
|
744
755
|
const namedOutcome = typeof reported === 'string' ? reported : undefined;
|
|
745
|
-
const seconds = Number(((performance.now() - startedAt) / 1000).toFixed(2));
|
|
746
756
|
console.error(`[graph] ${current} ${ok ? 'ok' : 'fail'} (${seconds.toFixed(2)}s)`);
|
|
747
757
|
debug.log('graph.run', 'node', { graphId, runId, nodeId: current, phase: ok ? 'ok' : 'fail', seconds, exit });
|
|
748
758
|
publishInsideEvent({ kind: 'node', graphId, runId, nodeId: current, phase: ok ? 'ok' : 'fail', seconds });
|
|
@@ -892,11 +902,21 @@ export function manageGraphRun(graphId: string, runId: string, action: 'stop' |
|
|
|
892
902
|
catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error; }
|
|
893
903
|
}
|
|
894
904
|
}
|
|
905
|
+
const current = state.currentNode;
|
|
906
|
+
const running = current && state.path.length === state.nodes.length + 1 && current.nodeId === state.path.at(-1) &&
|
|
907
|
+
Number.isFinite(Date.parse(current.startedAt)) ? current.startedAt : undefined;
|
|
908
|
+
// One stop instant for the node end, finishedAt and stoppedAt — never before the running node's start.
|
|
909
|
+
const stopMs = running === undefined ? Date.now() : Math.max(Date.now(), Date.parse(running));
|
|
895
910
|
if (state.path.length === state.nodes.length + 1) {
|
|
896
|
-
state.nodes.push({ nodeId: state.path.at(-1)!, ok: false, exit: null, executed: false, error: 'stopped before node completed'
|
|
911
|
+
state.nodes.push({ nodeId: state.path.at(-1)!, ok: false, exit: null, executed: false, error: 'stopped before node completed',
|
|
912
|
+
// The stop instant is always the node end; a start (and so seconds) exists only when the ledger named the running
|
|
913
|
+
// node — a run begun by a runner before GRAPH-NODE-TIMES did not, and a guessed start would be a false time.
|
|
914
|
+
endedAt: new Date(stopMs).toISOString(),
|
|
915
|
+
...(running === undefined ? {} : { startedAt: running, seconds: Number(((stopMs - Date.parse(running)) / 1000).toFixed(2)) }) });
|
|
897
916
|
}
|
|
917
|
+
delete state.currentNode;
|
|
898
918
|
state.status = 'failed';
|
|
899
|
-
state.finishedAt = new Date().toISOString();
|
|
919
|
+
state.finishedAt = new Date(stopMs).toISOString();
|
|
900
920
|
state.stoppedAt = state.finishedAt;
|
|
901
921
|
delete state.activeNode;
|
|
902
922
|
persistGraphRun(state);
|
|
@@ -23,6 +23,7 @@ import { queryRunningRuns } from '../self-implement/running-runs.js';
|
|
|
23
23
|
import { DevPipelineError } from '../self-dev/dev-pipeline.js';
|
|
24
24
|
import { runDraftSweep, sweepFailureReason, type DraftSweepAdapters, type DraftSweepResult, type SweepDraft, type SweepMergedPr, type SweepReviewGate } from '../self-dev/draft-sweep.js';
|
|
25
25
|
import { debug } from '../debug/log.js';
|
|
26
|
+
import { installHarnessSalvageCommand } from './harness-salvage-cli.js';
|
|
26
27
|
import { decideNestedElanousLaunch, readNestedElanousDepth } from './nested-elanous-policy.js';
|
|
27
28
|
import { dispatchTask, type DispatchTaskInput, type DispatchTaskDeps } from '../execution-loop/dispatch-task.js';
|
|
28
29
|
import { launchRequestId, preLaunchGate, type PreLaunchGateDeps } from '../execution-loop/launch-gate.js';
|
|
@@ -2511,6 +2512,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2511
2512
|
installDeliverableVerifyCliCommand(harnessCmd, deps.deliverableVerify);
|
|
2512
2513
|
installHarnessProcessObservationCommand(harnessCmd, deps.processObservation);
|
|
2513
2514
|
installHarnessBudgetCommand(harnessCmd);
|
|
2515
|
+
installHarnessSalvageCommand(harnessCmd);
|
|
2514
2516
|
installHarnessGoalCommand(harnessCmd, deps.goalLookup, deps.goalArchive);
|
|
2515
2517
|
installHarnessDraftSweepCommand(harnessCmd, deps.draftSweep);
|
|
2516
2518
|
const queue = harnessCmd.command('queue').description('자리별 영속 발사 대기열');
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `elanous harness salvage <runId...> [--json]` — 런마다 «PR #n | 수확 가지 <branch> (+a/-b · N files) | 없음 | 모름(<이유>)».
|
|
3
|
+
* SALVAGE-VISIBLE(0.2.19) — 판정은 `src/self-implement/salvage-branches.ts`, 여기는 배선·출력·관측만.
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from 'commander';
|
|
6
|
+
import { debug } from '../debug/log.js';
|
|
7
|
+
import { normalizeRunId } from './harness-space.js';
|
|
8
|
+
import { loadFederatedRunLedger } from '../self-implement/run-ledger.js';
|
|
9
|
+
import {
|
|
10
|
+
decideRunSalvage,
|
|
11
|
+
findRunSalvageBranches,
|
|
12
|
+
gitSalvageRunner,
|
|
13
|
+
listRemoteSalvageRefs,
|
|
14
|
+
prStateFromLedger,
|
|
15
|
+
type RunPrState,
|
|
16
|
+
type RunSalvageVerdict,
|
|
17
|
+
type SalvageGitRunner,
|
|
18
|
+
} from '../self-implement/salvage-branches.js';
|
|
19
|
+
|
|
20
|
+
export interface HarnessSalvageDeps {
|
|
21
|
+
git?: SalvageGitRunner;
|
|
22
|
+
readPr?: (runId: string) => RunPrState;
|
|
23
|
+
print?: (line: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function defaultReadPr(runId: string): RunPrState {
|
|
27
|
+
try {
|
|
28
|
+
return prStateFromLedger(loadFederatedRunLedger(runId, { includeTest: true }));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return { status: 'unknown', reason: `원장 읽기 실패 · ${error instanceof Error ? error.message : String(error)}` };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 여러 런을 ls-remote «한 번»으로 판정한다. PR 이 있는 런은 git 을 더 부르지 않는다. */
|
|
35
|
+
export function runHarnessSalvage(runIds: readonly string[], deps: HarnessSalvageDeps = {}): RunSalvageVerdict[] {
|
|
36
|
+
const git = deps.git ?? gitSalvageRunner(process.cwd());
|
|
37
|
+
const readPr = deps.readPr ?? defaultReadPr;
|
|
38
|
+
let listing: ReturnType<typeof listRemoteSalvageRefs> | undefined;
|
|
39
|
+
const verdicts: RunSalvageVerdict[] = [];
|
|
40
|
+
for (const raw of runIds) {
|
|
41
|
+
const runId = normalizeRunId(raw);
|
|
42
|
+
const pr = readPr(runId);
|
|
43
|
+
let verdict: RunSalvageVerdict;
|
|
44
|
+
if (pr.status === 'pr') {
|
|
45
|
+
verdict = decideRunSalvage(runId, pr, { status: 'not-checked' });
|
|
46
|
+
} else {
|
|
47
|
+
listing ??= listRemoteSalvageRefs(git);
|
|
48
|
+
verdict = decideRunSalvage(runId, pr, findRunSalvageBranches(runId, git, { listing }));
|
|
49
|
+
}
|
|
50
|
+
const top = verdict.salvage.status === 'found' ? verdict.salvage.branches[0] : undefined;
|
|
51
|
+
debug.log('harness.salvage', 'visible', {
|
|
52
|
+
runId,
|
|
53
|
+
outcome: verdict.outcome,
|
|
54
|
+
branch: top?.branch ?? null,
|
|
55
|
+
files: top?.diffstat.files ?? null,
|
|
56
|
+
...(verdict.pr.status === 'pr' ? { prNumber: verdict.pr.number } : {}),
|
|
57
|
+
...(verdict.salvage.status === 'unknown' ? { reason: verdict.salvage.reason } : {}),
|
|
58
|
+
...(verdict.pr.status === 'unknown' ? { prReason: verdict.pr.reason } : {}),
|
|
59
|
+
});
|
|
60
|
+
verdicts.push(verdict);
|
|
61
|
+
}
|
|
62
|
+
return verdicts;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function installHarnessSalvageCommand(harnessCmd: Command, deps: HarnessSalvageDeps = {}): Command {
|
|
66
|
+
return harnessCmd
|
|
67
|
+
.command('salvage')
|
|
68
|
+
.description('런 → PR | 수확 가지(salvage/*) | 없음 | 모름 — Pod 런이 멈추며 남긴 가지를 보인다')
|
|
69
|
+
.argument('<runIds...>', '런 id (run-xxxxxxxx-…)')
|
|
70
|
+
.option('--json', '런마다 { runId, outcome, pr, salvage } 를 JSON 배열로')
|
|
71
|
+
.action((runIds: string[], opts: { json?: boolean }) => {
|
|
72
|
+
const print = deps.print ?? ((line: string) => console.log(line));
|
|
73
|
+
const verdicts = runHarnessSalvage(runIds, deps);
|
|
74
|
+
if (opts.json) print(JSON.stringify(verdicts.map(({ line: _line, ...rest }) => rest)));
|
|
75
|
+
else for (const verdict of verdicts) print(verdict.line);
|
|
76
|
+
if (verdicts.some((verdict) => verdict.outcome === 'unknown')) process.exitCode = 1;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -2,6 +2,7 @@ import { createWorktree, type CreateWorktreeResult } from '../git-fs/worktree.js
|
|
|
2
2
|
import { runGitCommand } from '../git-fs/runner.js';
|
|
3
3
|
import { configuredWorktreeRoot } from '../user-config.js';
|
|
4
4
|
import { debug } from '../debug/log.js';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
5
6
|
|
|
6
7
|
const OWNER_CONFIG_KEY = 'elanous.harness.owner';
|
|
7
8
|
const COMMAND_CONFIG_KEY = 'elanous.harness.command';
|
|
@@ -87,8 +88,75 @@ function restoreWorktreeProvenance(worktreePath: string, snapshot: WorktreeConfi
|
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
/** Keys that must leave the shared config once `extensions.worktreeConfig` is on (`git help worktree` §CONFIGURATION FILE).
|
|
92
|
+
* `core.bare=false` is harmless when shared (linked trees default to non-bare), so only a true value moves. */
|
|
93
|
+
const MAIN_TREE_ONLY_CONFIG_KEYS = ['core.bare', 'core.worktree'] as const;
|
|
94
|
+
|
|
95
|
+
/** Moves `core.bare=true` / `core.worktree` from `$GIT_COMMON_DIR/config` to `$GIT_COMMON_DIR/config.worktree`.
|
|
96
|
+
* Runs every time (also when the extension is already on) and throws before the caller enables the extension.
|
|
97
|
+
* Incident 10-07 (HQ-WORKTREE-CONFIG): a shared `core.bare=true` made every linked worktree of a bare repo unusable. */
|
|
98
|
+
/** Values are moved byte-for-byte (a `core.worktree` path may carry edge whitespace), so read them NUL-terminated. */
|
|
99
|
+
function nulTerminatedValue(stdout: unknown, key: string): string {
|
|
100
|
+
const text = String(stdout ?? '');
|
|
101
|
+
if (!text.endsWith('\0')) throw new Error(`harness worktree ${key} read failed — git config emitted an unterminated value`);
|
|
102
|
+
return text.slice(0, -1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function moveMainTreeOnlyConfig(worktreePath: string): void {
|
|
106
|
+
const common = gitAt(worktreePath, ['rev-parse', '--git-common-dir']);
|
|
107
|
+
const commonOut = String(common.stdout ?? '').trim();
|
|
108
|
+
if (common.status !== 0 || !commonOut) {
|
|
109
|
+
throw new Error(`harness worktree common git dir lookup failed — ${gitConfigFailure(common)}`);
|
|
110
|
+
}
|
|
111
|
+
const commonDir = resolve(worktreePath, commonOut);
|
|
112
|
+
const shared = join(commonDir, 'config');
|
|
113
|
+
const perTree = join(commonDir, 'config.worktree');
|
|
114
|
+
// `null` = absent. Typed reads judge meaning (`yes`/`TRUE` are true); raw reads carry the bytes that move.
|
|
115
|
+
const readValue = (file: string, key: string, typed: boolean): string | null => {
|
|
116
|
+
const read = gitAt(worktreePath, ['config', '--file', file, ...(typed ? ['--type=bool'] : []), '--null', '--get', key]);
|
|
117
|
+
if (read.status === 1) return null;
|
|
118
|
+
if (read.status !== 0) throw new Error(`harness worktree ${key} read failed (${file}) — ${gitConfigFailure(read)}`);
|
|
119
|
+
return nulTerminatedValue(read.stdout, key);
|
|
120
|
+
};
|
|
121
|
+
for (const key of MAIN_TREE_ONLY_CONFIG_KEYS) {
|
|
122
|
+
const typed = key === 'core.bare';
|
|
123
|
+
const meaning = readValue(shared, key, typed);
|
|
124
|
+
if (meaning === null) continue;
|
|
125
|
+
if (typed && meaning !== 'true') continue;
|
|
126
|
+
const raw = typed ? readValue(shared, key, false) : meaning;
|
|
127
|
+
if (raw === null) throw new Error(`harness worktree shared ${key} vanished during the move`);
|
|
128
|
+
// A valueless `bare` means true; writing its empty raw form would mean false.
|
|
129
|
+
const value = typed && raw === '' ? 'true' : raw;
|
|
130
|
+
// A conflicting per-tree value would flip the main tree once the extension is on — refuse instead of guessing.
|
|
131
|
+
// Every per-tree value must agree (not just the last one), so a mixed list also fails closed.
|
|
132
|
+
const existingRead = gitAt(worktreePath, ['config', '--file', perTree, ...(typed ? ['--type=bool'] : []), '--null', '--get-all', key]);
|
|
133
|
+
if (existingRead.status !== 0 && existingRead.status !== 1) {
|
|
134
|
+
throw new Error(`harness worktree ${key} read failed (${perTree}) — ${gitConfigFailure(existingRead)}`);
|
|
135
|
+
}
|
|
136
|
+
const existingValues = existingRead.status === 0 ? nulTerminatedValue(existingRead.stdout, key).split('\0') : [];
|
|
137
|
+
if (existingValues.some((existing) => existing !== meaning)) {
|
|
138
|
+
throw new Error(`harness worktree ${key} conflict — ${shared} has ${JSON.stringify(meaning)} but ${perTree} has ${JSON.stringify(existingValues)}; resolve by hand before enabling extensions.worktreeConfig`);
|
|
139
|
+
}
|
|
140
|
+
const existingMeaning = existingValues.length > 0 ? meaning : null;
|
|
141
|
+
if (existingMeaning === null) {
|
|
142
|
+
const write = gitAt(worktreePath, ['config', '--file', perTree, key, value]);
|
|
143
|
+
if (write.status !== 0) throw new Error(`harness worktree ${key} move failed — ${gitConfigFailure(write)}`);
|
|
144
|
+
}
|
|
145
|
+
const unset = gitAt(worktreePath, ['config', '--file', shared, '--unset-all', key]);
|
|
146
|
+
if (unset.status !== 0) throw new Error(`harness worktree shared ${key} unset failed — ${gitConfigFailure(unset)}`);
|
|
147
|
+
debug.log('harness.worktree', 'core-bare-moved', {
|
|
148
|
+
key,
|
|
149
|
+
value,
|
|
150
|
+
commonDir,
|
|
151
|
+
perTreeHadValue: existingMeaning !== null,
|
|
152
|
+
worktreePath,
|
|
153
|
+
}, { level: 'warn' });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
90
157
|
/** Records the shared worktree-scoped provenance used by both manual and self-implement creation paths. */
|
|
91
158
|
export function recordHarnessWorktreeProvenance(worktreePath: string, provenance: HarnessWorktreeProvenance): void {
|
|
159
|
+
moveMainTreeOnlyConfig(worktreePath);
|
|
92
160
|
const enable = gitAt(worktreePath, ['config', 'extensions.worktreeConfig', 'true']);
|
|
93
161
|
if (enable.status !== 0) {
|
|
94
162
|
throw new Error(`harness worktree owner declaration failed — ${gitConfigFailure(enable)}`);
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
|
|
1
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
3
2
|
import { debug } from '../debug/log.js';
|
|
4
3
|
import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
|
|
5
|
-
|
|
6
|
-
function physicalPath(path: string): string {
|
|
7
|
-
const absolute = resolve(path);
|
|
8
|
-
try {
|
|
9
|
-
return realpathSync(absolute);
|
|
10
|
-
} catch (error) {
|
|
11
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
12
|
-
const parent = dirname(absolute);
|
|
13
|
-
if (parent === absolute) throw error;
|
|
14
|
-
return resolve(physicalPath(parent), relative(parent, absolute));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
4
|
+
import { isInsideOpsRoot, physicalPath, testProcessSignal } from '../instance/test-write-guard.js';
|
|
17
5
|
|
|
18
6
|
/** Refuse a test's write to the production instance, including an explicitly supplied ledger directory. */
|
|
19
7
|
export function refuseProductionLedgerWriteInTest(
|
|
@@ -23,11 +11,13 @@ export function refuseProductionLedgerWriteInTest(
|
|
|
23
11
|
productionRoot = prodInstanceRoot(),
|
|
24
12
|
instanceRoot = effectiveInstanceRoot(),
|
|
25
13
|
): boolean {
|
|
26
|
-
if (env.
|
|
14
|
+
if (!testProcessSignal(env, env === process.env ? undefined : '')) return false;
|
|
27
15
|
const target = physicalPath(root);
|
|
28
16
|
const production = physicalPath(productionRoot);
|
|
29
17
|
const withinProduction = relative(production, target);
|
|
30
|
-
|
|
18
|
+
const outsideHomeRoot = withinProduction === '..' || withinProduction.startsWith(`..${sep}`) || isAbsolute(withinProduction);
|
|
19
|
+
// The account's real ~/.elanous is production too when a runner redirected HOME (TEST-PROD-LEAK).
|
|
20
|
+
if (outsideHomeRoot && !isInsideOpsRoot(root)) return false;
|
|
31
21
|
try {
|
|
32
22
|
debug.log('harness.incidents', 'write-refused', { store, root: target, effectiveInstanceRoot: instanceRoot });
|
|
33
23
|
} catch { /* Observation cannot reopen a closed write boundary. */ }
|
package/src/hq/hq.ts
CHANGED
|
@@ -108,7 +108,7 @@ function resolve(deps: HqDeps = {}): Resolved {
|
|
|
108
108
|
ssh,
|
|
109
109
|
probe: deps.probe ?? tailnetProbe(config),
|
|
110
110
|
localPath: deps.localPath ?? join(getElanousConfigDir(), 'hq', 'local.json'),
|
|
111
|
-
seenPath: deps.seenPath ??
|
|
111
|
+
seenPath: deps.seenPath ?? (deps.localPath && !config.seenGenerationFile ? `${deps.localPath}.seen-generation` : hqSeenGenerationPath(config)),
|
|
112
112
|
now: deps.now ?? (() => Math.floor(Date.now() / 1000)),
|
|
113
113
|
log,
|
|
114
114
|
};
|
|
@@ -161,6 +161,11 @@ function writeLocal(path: string, state: LocalHqState): void {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/** Highest lease generation this host ever observed (null = never). */
|
|
164
|
+
/** The seen-generation marker this host keeps (hq.seenGenerationFile · default ~/.elanous-hq/seen-generation). */
|
|
165
|
+
export function hqSeenGenerationPath(config: Pick<HqConfig, 'seenGenerationFile'>): string {
|
|
166
|
+
return config.seenGenerationFile ?? join(homedir(), '.elanous-hq', 'seen-generation');
|
|
167
|
+
}
|
|
168
|
+
|
|
164
169
|
export function readSeenGeneration(path: string): number | null {
|
|
165
170
|
try {
|
|
166
171
|
if (!existsSync(path)) return null;
|
package/src/index.ts
CHANGED
|
@@ -51,6 +51,7 @@ import { registerRoleCommands } from './cli/role-cli.js';
|
|
|
51
51
|
import { registerMachineCommands } from './cli/machine-cli.js';
|
|
52
52
|
import { registerAgentEnvCommands } from './cli/agent-env-cli.js';
|
|
53
53
|
import { registerScheduleCommands } from './cli/schedule-cli.js';
|
|
54
|
+
import { registerGuardianCommands } from './cli/guardian-cli.js';
|
|
54
55
|
export { runSchedule, scheduleCreatePlan } from './cli/schedule-cli.js';
|
|
55
56
|
export type { ScheduleDispatch } from './cli/schedule-cli.js';
|
|
56
57
|
import { registerReviewLoopOptions, buildReviewLoopOpts } from './agent-mission/review-loop-cli.js';
|
|
@@ -75,6 +76,7 @@ import { registerIntakeCommands } from './cli/intake-cli.js';
|
|
|
75
76
|
import { registerTasksCommands } from './cli/tasks-cli.js';
|
|
76
77
|
import { registerBriefCommands } from './cli/brief-cli.js';
|
|
77
78
|
import { registerNotifyCommand } from './cli/notify-cli.js';
|
|
79
|
+
import { registerAwayCommand } from './cli/away-cli.js';
|
|
78
80
|
import { registerLabelsCommands } from './cli/labels-cli.js';
|
|
79
81
|
import { registerMsgCommands } from './cli/msg-cli.js';
|
|
80
82
|
import { registerDoctorCommand } from './cli/doctor-cli.js';
|
|
@@ -215,6 +217,23 @@ export { cliVersion, setInstallMetadataRootForTesting };
|
|
|
215
217
|
export const program = new Command();
|
|
216
218
|
program.enablePositionalOptions();
|
|
217
219
|
|
|
220
|
+
program.command('preview <target>')
|
|
221
|
+
.description('Isolated PR/branch-head TUI + PWA preview; publish the TUI-COMFORT friction table to a PR')
|
|
222
|
+
.option('--scenario <id>', 'TUI-COMFORT scenario (default S2)', 'S2')
|
|
223
|
+
.option('--flag <path>', 'Enable an existing config feature flag in main-based preview (repeatable)', (value: string, all: string[]) => [...all, value], [] as string[])
|
|
224
|
+
.option('--comment-pr <number>', 'PR to receive a branch/main preview report', (value: string) => Number(value))
|
|
225
|
+
.action(async (target: string, opts: { scenario: string; flag: string[]; commentPr?: number }) => {
|
|
226
|
+
try {
|
|
227
|
+
const { runPrPreview } = await import('./self-dev/pr-preview.js');
|
|
228
|
+
const result = await runPrPreview({ target, repoRoot: process.cwd(), scenario: opts.scenario, flags: opts.flag, ...(opts.commentPr === undefined ? {} : { commentPr: opts.commentPr }) });
|
|
229
|
+
console.log(`preview ${result.status} · ${result.head} · PR #${result.prNumber} · comment posted`);
|
|
230
|
+
if (result.status !== 'passed') process.exitCode = 1;
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
233
|
+
process.exitCode = 1;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
218
237
|
export { SELF_SEND_RECENT_FRAME_WINDOW_MS, SELF_SEND_STALE_HEARTBEAT_MS, formatSelfSendCandidateDisplay } from './harness/self-send-decide.js';
|
|
219
238
|
export type { SelfSendCandidate, SelfSendCandidateDisplay } from './harness/self-send-decide.js';
|
|
220
239
|
import { decideSelfSend, type SelfSendCandidate } from './harness/self-send-decide.js';
|
|
@@ -891,6 +910,7 @@ registerResearchCommand(program);
|
|
|
891
910
|
registerReleaseCommands(program);
|
|
892
911
|
registerKnowCommand(program);
|
|
893
912
|
registerNotifyCommand(program);
|
|
913
|
+
registerAwayCommand(program);
|
|
894
914
|
registerFreezeCommands(program);
|
|
895
915
|
registerFlowCommands(program);
|
|
896
916
|
// HQ-HB · HQ-FENCE (10-04): one writer across mbp · node-b · cloud-vm — lease on the arbiter, 2-of-3 quorum, generation fencing.
|
|
@@ -5979,6 +5999,7 @@ program
|
|
|
5979
5999
|
});
|
|
5980
6000
|
|
|
5981
6001
|
registerScheduleCommands(program);
|
|
6002
|
+
registerGuardianCommands(program);
|
|
5982
6003
|
|
|
5983
6004
|
/** `elanous decide*` 공통 — 보낼 곳과 자격을 정한다(설정 decide.endpoint > ELANOUS_JEV_ENDPOINT > Typesafe). 없으면 안내하고 rc 2. */
|
|
5984
6005
|
async function loadJevAccessOrExit(): Promise<import('./decide/jev.js').JevAccess> {
|
|
@@ -7173,7 +7194,7 @@ const selfDevCmd = program
|
|
|
7173
7194
|
const members = parsePodPool(devAskSubstrate.pool!);
|
|
7174
7195
|
const host = podPoolHostLease(members);
|
|
7175
7196
|
while (!authoringLease) {
|
|
7176
|
-
const status = recommendConcurrency(measurePoolLease(members), { capacity: members.reduce((n, m) => n + m.capacity, 0), accounts: 0, perAccount: 0 });
|
|
7197
|
+
const status = recommendConcurrency(measurePoolLease(members, { measureUsage: true }), { capacity: members.reduce((n, m) => n + m.capacity, 0), accounts: 0, perAccount: 0 });
|
|
7177
7198
|
if (status.recommended !== null && status.recommended > 0) {
|
|
7178
7199
|
const { leaseHasPendingPod } = await import('./pod-lease/host-lease.js');
|
|
7179
7200
|
const pendingJobs = status.pendingJobs ?? [];
|
|
@@ -7328,7 +7349,23 @@ const selfDevCmd = program
|
|
|
7328
7349
|
if (hasExplicitReviewerContext && loaded.failed.length > 0) throw new DevPipelineError(contextStatus);
|
|
7329
7350
|
if (loaded.items.length > 0) spec = { ...spec, reviewerContext: loaded.items };
|
|
7330
7351
|
}
|
|
7331
|
-
|
|
7352
|
+
// ⭐ TUI-ONE-WORD-LAUNCH — 명시 격리 우주에서 `--cwd`·`--worktree` 둘 다 없으면 «자동» 갈래로
|
|
7353
|
+
// 같은 `prepareDevWorktree` 를 탄다(새 생성 경로 없음). 명시 `--cwd` 는 그대로 이긴다.
|
|
7354
|
+
const autoWorktreeDecision = await (async () => {
|
|
7355
|
+
if (!devOpts.elanous || devOpts.worktree === true || devOpts.cwd !== undefined) {
|
|
7356
|
+
return devCli.decideAutoWorktree({ explicitlyIsolated: false, ...devOpts });
|
|
7357
|
+
}
|
|
7358
|
+
const [{ resolveCurrentInstance }, { isExplicitlyIsolated }] = await Promise.all([
|
|
7359
|
+
import('./instance/current.js'),
|
|
7360
|
+
import('./cli/pty-drive-cli.js'),
|
|
7361
|
+
]);
|
|
7362
|
+
return devCli.decideAutoWorktree({
|
|
7363
|
+
explicitlyIsolated: isExplicitlyIsolated(resolveCurrentInstance(), devOpts.isolatedRoot),
|
|
7364
|
+
...devOpts,
|
|
7365
|
+
});
|
|
7366
|
+
})();
|
|
7367
|
+
debug.log('dev-pipeline', 'auto-worktree-decision', { runId: devRunId, decision: autoWorktreeDecision });
|
|
7368
|
+
if (autoWorktreeDecision === 'requested' || autoWorktreeDecision === 'auto') {
|
|
7332
7369
|
const { prepareDevWorktree, renderPreparedDevWorktree } = await import('./harness/harness-worktree-auto.js');
|
|
7333
7370
|
const goal = 'file' in input
|
|
7334
7371
|
? await (async () => {
|
|
@@ -7338,13 +7375,25 @@ const selfDevCmd = program
|
|
|
7338
7375
|
return { id: goalId, file: input.file };
|
|
7339
7376
|
})()
|
|
7340
7377
|
: undefined;
|
|
7341
|
-
const prepared =
|
|
7378
|
+
const prepared = (() => {
|
|
7379
|
+
try {
|
|
7380
|
+
return prepareDevWorktree(process.cwd(), devRunId, invokedAsDrive ? 'drive' : 'dev', goal);
|
|
7381
|
+
} catch (error) {
|
|
7382
|
+
if (autoWorktreeDecision !== 'auto') throw error;
|
|
7383
|
+
debug.log('dev-pipeline', 'auto-worktree-failed', { runId: devRunId, cwd: process.cwd(), msg: error instanceof Error ? error.message : String(error) }, { level: 'warn' });
|
|
7384
|
+
throw new DevPipelineError(devCli.formatAutoWorktreeFailure(error));
|
|
7385
|
+
}
|
|
7386
|
+
})();
|
|
7342
7387
|
preparedWorktree = prepared;
|
|
7343
7388
|
if (spec.elanous) spec = { ...spec, elanous: { ...spec.elanous, cwd: prepared.worktree.path } };
|
|
7344
7389
|
else if (spec.drive) spec = { ...spec, drive: { ...spec.drive, cwd: prepared.worktree.path } };
|
|
7345
7390
|
else throw new DevPipelineError('--worktree 는 elanous 또는 셸 drive child에만 유효');
|
|
7346
7391
|
if (!opts.json) console.log(renderPreparedDevWorktree(prepared).join('\n'));
|
|
7347
7392
|
debug.log('dev-pipeline', 'auto-worktree-prepared', { runId: devRunId, ...prepared.environment, worktree: prepared.worktree });
|
|
7393
|
+
if (autoWorktreeDecision === 'auto') {
|
|
7394
|
+
if (!opts.json) console.log(devCli.formatAutoWorktreeNotice(prepared.worktree.path));
|
|
7395
|
+
debug.log('dev-pipeline', 'auto-worktree-implied', { runId: devRunId, worktree: prepared.worktree.path });
|
|
7396
|
+
}
|
|
7348
7397
|
}
|
|
7349
7398
|
// ⛔ 종전의 `const plan = planDevPipeline(spec)` 를 지운다(무인 리뷰 must-fix) — 쓰이지 않는
|
|
7350
7399
|
// 데다 **잔여 조회보다 먼저 던질 수 있어** 관측 자체를 건너뛰게 만든다. 계획은 어차피
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Child fixture for test-write-guard.test.ts: a bare spy installed BEFORE outbound-alert is imported must not
|
|
2
|
+
// make the captured «real» curl look like a fake. Prints {refused, curlCalls}.
|
|
3
|
+
import { spyOn } from 'bun:test';
|
|
4
|
+
import * as childProcess from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
const bare = spyOn(childProcess, 'execFileSync');
|
|
7
|
+
const { sendTelegramDirect } = await import('../domains/outbound-alert.js');
|
|
8
|
+
const { getUserConfig } = await import('../user-config.js');
|
|
9
|
+
const base = getUserConfig();
|
|
10
|
+
const config = { ...base, telegram: { ...base.telegram, channels: undefined, botToken: '2:fake', homeChannel: 2 } } as typeof base;
|
|
11
|
+
let refused = '';
|
|
12
|
+
try { sendTelegramDirect('private-alert-body', 'ops-alert', { config }); } catch (e) { refused = e instanceof Error ? e.name : String(e); }
|
|
13
|
+
console.log(JSON.stringify({ refused, curlCalls: bare.mock.calls.length }));
|