elanous 0.2.17 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{726.83532d69452ee24b.js → 1470.98a6ab61ccb4131c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9247-269e4464cc4b491c.js → 2375-e061bb24cd2b5cde.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{211-9c9090c59e2c5907.js → 2977-e38442e86289f1d3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → 2ea96958.e8c7e112de50b067.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +2 -0
- package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +1 -0
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 4323.c5dfb6f503304775.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 4847.56f5bc454fbcc827.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 6062-73e68343a9814f6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{935.4ddaa99fc1d1126c.js → 7647.2fcd30d894d5ee30.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6231284-45726550aba08fca.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +25 -0
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-b70cd005d9169e25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +1 -0
- package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
- package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +1 -0
- package/apps/pwa/out/_next/static/css/d3427996da11e480.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -0
- package/apps/pwa/out/decisions/index.txt +30 -0
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +25 -24
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +24 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +28 -27
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/ops/guardian.yaml +26 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/package.json +2 -1
- package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
- package/samples/workflows/templates/chat-driven-research.yaml +35 -0
- package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
- package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
- package/samples/workflows/templates/manual-quickstart.yaml +21 -0
- package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
- package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
- package/scripts/ci-public-export-import-gate.ts +7 -2
- package/scripts/ci-typecheck-changed.ts +21 -6
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +6 -3
- package/scripts/docs/generate-cli-anatomy.ts +162 -0
- package/scripts/goals/authoring-metrics.ts +73 -0
- package/scripts/landing-heal/must-fix-match.ts +7 -7
- package/scripts/landing-heal/run-mission.ts +3 -2
- package/scripts/lib/pch-regress-map.ts +23 -0
- package/scripts/morning-report.ts +18 -4
- package/scripts/pch-regress.ts +88 -0
- package/scripts/public-export-test-run.ts +37 -2
- package/scripts/release-loop/checklist-gate-node.ts +13 -11
- package/scripts/release-loop/cut-branch.ts +2 -1
- package/scripts/release-loop/cutoff.ts +4 -2
- package/scripts/release-loop/docs-land-node.ts +8 -1
- package/scripts/release-loop/docs-node.ts +1 -1
- package/scripts/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +436 -59
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +120 -0
- package/scripts/release-loop/node-verdict.ts +2 -1
- package/scripts/release-loop/npm-publish-node.ts +11 -7
- package/scripts/release-loop/ops-upgrade-node.ts +8 -1
- package/scripts/release-loop/preflight.ts +246 -0
- package/scripts/release-loop/publish-node.ts +8 -1
- package/scripts/release-loop/release-readiness.ts +11 -6
- package/scripts/release-loop/release-version.ts +48 -0
- package/scripts/release-loop/resume-release.ts +174 -0
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +45 -7
- package/scripts/release-loop/version-node.ts +145 -40
- package/scripts/rhythm/daily.ts +25 -4
- package/scripts/skills/public-check.ts +62 -12
- package/scripts/test-deterministic.ts +51 -33
- package/scripts/test-diet/effectiveness.ts +62 -1
- package/scripts/test-diet/lib.ts +1 -1
- package/scripts/test-diet/node.ts +8 -1
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/agent-mission/review-loop.ts +4 -3
- package/src/agent-substrate/pr-comment-meta.ts +20 -0
- package/src/autopilot/build/llm-conflict-merge.ts +28 -8
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +255 -0
- package/src/briefing/brief-items.ts +86 -17
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/autopilot-cli.ts +30 -11
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/brief-cli.ts +36 -2
- package/src/cli/freeze-cli.ts +3 -2
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +85 -7
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/notify-cli.ts +75 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/provider-cli.ts +12 -2
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +128 -19
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +403 -4
- package/src/context-bus/condense.ts +19 -3
- package/src/context-bus/context-day.ts +77 -24
- package/src/context-bus/context-first.ts +33 -0
- package/src/context-bus/context-now-public.ts +1 -1
- package/src/context-bus/context-now-surfaces.ts +16 -6
- package/src/context-bus/context-now.ts +97 -3
- package/src/core-turn/short-question.ts +100 -0
- package/src/dashboard/dashboard-status-lines.ts +24 -4
- package/src/dashboard/index.ts +50 -5
- package/src/dashboard/input/slash-executor.ts +6 -2
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +63 -36
- package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +21 -8
- package/src/dashboard/slash-runtime/help-groups.ts +44 -0
- package/src/dashboard/slash-runtime/model-choices.ts +125 -0
- package/src/discord-self-message.ts +20 -2
- package/src/discord-slash-wire.ts +1 -0
- package/src/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +244 -40
- package/src/domains/outbound-log-probe.ts +16 -1
- package/src/domains/release-tool.ts +2 -2
- package/src/domains/schedule-registry.ts +23 -0
- package/src/domains/telegram-kind-route.ts +39 -0
- package/src/domains/watch-default-scheduler.ts +95 -0
- package/src/esc-abort-gate.ts +44 -0
- package/src/execution-loop/gates.ts +11 -2
- package/src/flow-loop/split.ts +8 -4
- package/src/git-fs/worktree.ts +23 -3
- package/src/graph-runner/runner.ts +25 -5
- package/src/harness/harness-cli-command.ts +12 -2
- package/src/harness/harness-queue.ts +388 -33
- package/src/harness/harness-salvage-cli.ts +78 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/helper-scan.ts +10 -3
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/hq.ts +6 -1
- package/src/hq/seats.ts +369 -0
- package/src/index.ts +185 -18
- package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
- package/src/instance/test-write-guard.ts +200 -0
- package/src/intake-plane/adopt-gate.ts +49 -0
- package/src/intake-plane/check.ts +3 -0
- package/src/intake-plane/collect-github.ts +57 -25
- package/src/intake-plane/digest.ts +39 -15
- package/src/intake-plane/discord-seat-work.ts +8 -2
- package/src/intake-plane/harness-target.ts +4 -3
- package/src/intake-plane/intake-sources.ts +1 -0
- package/src/intake-plane/items.ts +1 -0
- package/src/intake-plane/requirement-funnel.ts +316 -0
- package/src/knowledge/know-find.ts +10 -1
- package/src/loops/budget.ts +36 -0
- package/src/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +106 -4
- package/src/loops/orchestrator/grid-place.ts +11 -0
- package/src/loops/orchestrator/tick.ts +450 -54
- package/src/maturity/feature-maturity.ts +8 -5
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/decisions-route.ts +11 -1
- package/src/nexus/api/http-server.ts +16 -5
- package/src/nexus/api/loop-edges.ts +352 -23
- package/src/nexus/api/ops-api.ts +96 -28
- package/src/nexus/api/ops-seats-sources.ts +2 -2
- package/src/nexus/api/workflow-templates.ts +3 -0
- package/src/nexus/index.ts +7 -0
- package/src/oauth/codex.ts +38 -0
- package/src/onboarding/first-chat-gate.ts +29 -0
- package/src/release-loop/checklist.ts +106 -6
- package/src/release-loop/feature-store.ts +64 -16
- package/src/release-loop/landing-freeze.ts +6 -4
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +64 -20
- package/src/release-loop/rubric.ts +136 -0
- package/src/seat-dispatch/seat-ask.ts +79 -16
- package/src/seat-loop/seat-loop.ts +12 -6
- package/src/self-dev/ask-launch-flow.ts +24 -3
- package/src/self-dev/ask-path-candidates.ts +68 -0
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/dev-pipeline.ts +4 -0
- package/src/self-dev/draft-triage-rules.ts +1 -1
- package/src/self-dev/orchestrate-cli.ts +22 -0
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +179 -0
- package/src/self-dev/round-pr-supersede.ts +244 -0
- package/src/self-dev/run-supervisor.ts +14 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/follow-up-goals.ts +2 -2
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/gate-remote.ts +427 -0
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-author.ts +8 -3
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/l8-merge-queue.ts +29 -5
- package/src/self-implement/orchestrator.ts +61 -13
- package/src/self-implement/prior-draft-findings.ts +4 -3
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/skills/skill-feedback.ts +76 -0
- package/src/task-agent/actions.ts +101 -7
- package/src/task-agent/board.ts +132 -0
- package/src/task-agent/card-evidence.ts +203 -0
- package/src/task-agent/completion-evidence.ts +126 -0
- package/src/task-agent/judge.ts +49 -5
- package/src/task-agent/live-moves.ts +176 -0
- package/src/task-agent/mission.ts +449 -0
- package/src/task-agent/shadow.ts +258 -0
- package/src/task-agent/task-hand.ts +337 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +64 -4
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +10 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +142 -13
- package/src/task-orchestrator/surfaces/pod-pool.ts +13 -5
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +88 -20
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +11 -0
- package/src/telegram-loops-command.ts +1 -1
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/telegram.ts +5 -20
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +196 -4
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-aac7332576c4d6fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6877-fe94e76a5841ee9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3143b07a817d1da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-17ba086ef82d339b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-6e5c3a867557298b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9a41d65355fc25b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-41afec0b255ed2bb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4187666132fc98c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-09328d499162bae4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-29ff3a8f84f03b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-80ec7401bc83f511.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-fc7d86467291ae38.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-de43a186e5ba5683.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-043a9111e74f6b24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-23a4601ceb7f452e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-10d958605a77b3bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a04260b8ccc968d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-12916918988ac97e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-5a64cb5208c6a8fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1407ec83ea64c1f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7f49fe645d5132f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-424659bacfb8cdd7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-fc2df261f8a2c7df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d4fef9ccd7d406b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +0 -1
- package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
- package/apps/pwa/out/_next/static/yRA5ur6DcPl0YHSRheH2O/_buildManifest.js +0 -1
- /package/apps/pwa/out/_next/static/{yRA5ur6DcPl0YHSRheH2O → J5H7BvqgSI8DUjtRRcA_S}/_ssgManifest.js +0 -0
|
@@ -18,6 +18,9 @@ import { dirname, join } from 'node:path';
|
|
|
18
18
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
19
19
|
import { prevScheduledFire } from './cron-match.js';
|
|
20
20
|
import { debug } from '../debug/log.js';
|
|
21
|
+
import { listSources } from '../intake-plane/intake-sources.js';
|
|
22
|
+
import { getUserConfig } from '../user-config.js';
|
|
23
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
21
24
|
import { deriveScheduleName, ensureScheduleRunsSchema, recordScheduleRun } from './schedule-runs.js';
|
|
22
25
|
|
|
23
26
|
/** 스케줄 레지스트리 DB 정본 경로 — state-dir 존중(lazy · Phase B). prod(ELANOUS_STATE_DIR
|
|
@@ -490,6 +493,9 @@ export interface InventoryInternalOpts {
|
|
|
490
493
|
discoveryIntervalMs?: number;
|
|
491
494
|
/** 테스트 seam — workflow-runtime schedule 트리거 주입(미지정 시 discoverWorkflows). */
|
|
492
495
|
workflowSchedules?: Array<{ workflowName: string; nodeId: string; cron?: string | null; intervalMs?: number | null }>;
|
|
496
|
+
/** Test seams for the installed instance; production reads the active config and instance root. */
|
|
497
|
+
watchRoot?: string;
|
|
498
|
+
watchEnabled?: boolean;
|
|
493
499
|
}
|
|
494
500
|
|
|
495
501
|
/** 데몬 내부 스케줄을 레지스트리에 upsert(멱등·고정 id). 등록 수 반환. */
|
|
@@ -513,6 +519,23 @@ export function inventoryInternalSchedules(db: Database, opts: InventoryInternal
|
|
|
513
519
|
// 회고(retro loop = retro-aggregate/report/rebalance)와는 별개.
|
|
514
520
|
const hour = opts.reflectionHour ?? (Number.isFinite(Number.parseInt(process.env.ELANOUS_REFLECTION_HOUR ?? '', 10)) ? Number.parseInt(process.env.ELANOUS_REFLECTION_HOUR!, 10) : 21);
|
|
515
521
|
upsert('internal:daily-reflection', 'daily-reflection', 'daily-reflection', `0 ${hour} * * *`, null, 'daemon: elanous 활동 회고(노트/OCR/세션) 스냅샷 푸시', 'report', 'elanous');
|
|
522
|
+
// WATCH-DEFAULT — fail-soft: a broken sources file or config must not stop the other internal rows.
|
|
523
|
+
let watchSources: ReturnType<typeof listSources> = [];
|
|
524
|
+
try {
|
|
525
|
+
const watchEnabled = opts.watchEnabled ?? (getUserConfig().watch?.enabled !== false);
|
|
526
|
+
watchSources = watchEnabled ? listSources({ seat: 'user' }, opts.watchRoot ?? effectiveInstanceRoot()) : [];
|
|
527
|
+
} catch (error) {
|
|
528
|
+
debug.log('watch.default', 'failed', { stage: 'inventory', reason: error instanceof Error ? error.message : String(error) });
|
|
529
|
+
}
|
|
530
|
+
if (watchSources.length > 0) {
|
|
531
|
+
upsert('internal:watch-collect', 'watch-collect', 'watch-default', '0 7 * * *', null,
|
|
532
|
+
'intake source run-due --seat user', 'ingest', 'elanous');
|
|
533
|
+
upsert('internal:watch-brief', 'watch-brief', 'watch-default', '30 8 * * *', null,
|
|
534
|
+
'intake digest --seat user --telegram', 'digest', 'elanous');
|
|
535
|
+
debug.log('watch.default', 'scheduled', { topics: watchSources.length, items: 0, sent: false });
|
|
536
|
+
} else {
|
|
537
|
+
db.run("DELETE FROM schedule_registry WHERE id IN ('internal:watch-collect', 'internal:watch-brief') AND source = 'watch-default'");
|
|
538
|
+
}
|
|
516
539
|
// discovery (env 설정 시에만 가동) — 코어 인프라 → elanous.
|
|
517
540
|
const dm = opts.discoveryIntervalMs ?? Number.parseInt(process.env.ELANOUS_DISCOVERY_CRON_INTERVAL_MS ?? '', 10);
|
|
518
541
|
if (Number.isFinite(dm) && dm > 0) {
|
|
@@ -75,3 +75,42 @@ export function kindRouteTarget(cfg: UserConfig, kind?: string): { botToken: str
|
|
|
75
75
|
if (!ch || !Number.isFinite(ch.chatId)) return null;
|
|
76
76
|
return { botToken: ch.botToken, chatId: ch.chatId };
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
export type ReportRouteReason =
|
|
80
|
+
| 'routed' | 'report-role-missing' | 'no-role-channel'
|
|
81
|
+
| 'no-report-channel' | 'report-bot-not-distinct' | 'report-chat-invalid' | 'no-main-home';
|
|
82
|
+
|
|
83
|
+
/** Why a kind has (or lacks) a delivery target — no logging, no sending. Mirrors
|
|
84
|
+
* `resolveReportTarget` so a skipped send can say *which* rule closed it instead of
|
|
85
|
+
* «no report channel configured» (BRIEF-DELIVERY-1007: a channels table without a
|
|
86
|
+
* `report` role closed the morning brief for four days while reportChannel was set). */
|
|
87
|
+
export function explainReportRoute(cfg: UserConfig, kind?: string): { reason: ReportRouteReason; role: string; hint: string } {
|
|
88
|
+
const role = roleForKind(cfg, kind);
|
|
89
|
+
const trading = isTradingKind(kind);
|
|
90
|
+
if (cfg.telegram.channels?.length) {
|
|
91
|
+
if (kindRouteTarget(cfg, kind)) return { reason: 'routed', role, hint: '' };
|
|
92
|
+
const hasRole = resolveTelegramChannels(cfg.telegram).some(c => c.roles.includes(role));
|
|
93
|
+
if (trading && !hasRole && cfg.telegram.reportChannel) {
|
|
94
|
+
return {
|
|
95
|
+
reason: 'report-role-missing', role,
|
|
96
|
+
hint: `채널 표에 «${role}» 역할 칸이 없다 — telegram.reportChannel 은 채널 표가 있으면 쓰지 않는다. `
|
|
97
|
+
+ `telegram.channels[].roles 에 "${role}" 를 더하거나 telegram.kindRoles.${kind ?? '<kind>'} 로 있는 역할을 고른다`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { reason: 'no-role-channel', role, hint: `채널 표에 «${role}» 역할을 가진 허용된 봇 칸이 없다 — telegram.channels 를 확인` };
|
|
101
|
+
}
|
|
102
|
+
if (!trading) {
|
|
103
|
+
return mainHomeTarget(cfg)
|
|
104
|
+
? { reason: 'routed', role, hint: '' }
|
|
105
|
+
: { reason: 'no-main-home', role, hint: '운영 봇 또는 telegram.homeChannel·allowedUsers 가 없다' };
|
|
106
|
+
}
|
|
107
|
+
const rc = cfg.telegram.reportChannel;
|
|
108
|
+
if (!rc) return { reason: 'no-report-channel', role, hint: 'telegram.reportChannel 이 없다' };
|
|
109
|
+
const mainToken = resolveChannelBotToken('telegram', cfg).token;
|
|
110
|
+
if (!rc.botToken || rc.botToken === mainToken) {
|
|
111
|
+
return { reason: 'report-bot-not-distinct', role, hint: 'telegram.reportChannel 의 봇이 없거나 운영 봇과 같다 — 매매 보고는 별도 봇만 쓴다' };
|
|
112
|
+
}
|
|
113
|
+
return Number.isFinite(rc.chatId)
|
|
114
|
+
? { reason: 'routed', role, hint: '' }
|
|
115
|
+
: { reason: 'report-chat-invalid', role, hint: 'telegram.reportChannel.chatId 가 숫자가 아니다' };
|
|
116
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { getUserConfig } from '../user-config.js';
|
|
5
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
|
+
import { listSources, runDue } from '../intake-plane/intake-sources.js';
|
|
7
|
+
import { runIntakeDigestCli } from '../cli/intake-cli.js';
|
|
8
|
+
import { resolveTimeZone } from '../time/format.js';
|
|
9
|
+
import { inventoryInternalSchedules, openSchedulesDb } from './schedule-registry.js';
|
|
10
|
+
import type { Database } from 'bun:sqlite';
|
|
11
|
+
|
|
12
|
+
export interface WatchDefaultSchedulerOpts {
|
|
13
|
+
root?: string;
|
|
14
|
+
enabled?: () => boolean;
|
|
15
|
+
now?: () => Date;
|
|
16
|
+
timeZone?: string;
|
|
17
|
+
collect?: () => Promise<unknown>;
|
|
18
|
+
brief?: () => Promise<unknown>;
|
|
19
|
+
setInterval?: (tick: () => void, ms: number) => ReturnType<typeof setInterval>;
|
|
20
|
+
openDb?: () => Database;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Daemon-owned watch jobs: the inventory rows describe these two actual timers. */
|
|
24
|
+
export function startWatchDefaultScheduler(opts: WatchDefaultSchedulerOpts = {}): { stop(): void; tickNow(): Promise<void> } {
|
|
25
|
+
const root = opts.root ?? effectiveInstanceRoot();
|
|
26
|
+
const enabled = opts.enabled ?? (() => getUserConfig().watch?.enabled !== false);
|
|
27
|
+
const timeZone = opts.timeZone ?? resolveTimeZone().timeZone;
|
|
28
|
+
const now = opts.now ?? (() => new Date());
|
|
29
|
+
const collect = opts.collect ?? (() => runDue({ seat: 'user', deps: { stateDir: root } }));
|
|
30
|
+
// The CLI sets process.exitCode on an unsent report; inside the daemon that would leak into the daemon's own exit status.
|
|
31
|
+
const brief = opts.brief ?? (async () => {
|
|
32
|
+
const before = process.exitCode;
|
|
33
|
+
try { return await runIntakeDigestCli({ seat: 'user', telegram: true }, { root }); }
|
|
34
|
+
finally { process.exitCode = before; }
|
|
35
|
+
});
|
|
36
|
+
const lastRunFile = join(root, 'intake', 'watch-default-last-run.json');
|
|
37
|
+
const lastRun = new Map<string, string>();
|
|
38
|
+
let lastInventory: string | undefined;
|
|
39
|
+
let lastFailure: string | undefined;
|
|
40
|
+
try {
|
|
41
|
+
if (existsSync(lastRunFile)) {
|
|
42
|
+
const saved = JSON.parse(readFileSync(lastRunFile, 'utf8')) as Record<string, string>;
|
|
43
|
+
for (const [job, day] of Object.entries(saved)) if (typeof day === 'string') lastRun.set(job, day);
|
|
44
|
+
}
|
|
45
|
+
} catch (error) { debug.log('watch.default', 'failed', { reason: `last-run: ${String(error)}` }); }
|
|
46
|
+
let running = false;
|
|
47
|
+
let stopped = false;
|
|
48
|
+
const tickNow = async (): Promise<void> => {
|
|
49
|
+
if (stopped || running) return;
|
|
50
|
+
running = true;
|
|
51
|
+
try {
|
|
52
|
+
const active = enabled() && listSources({ seat: 'user' }, root).length > 0;
|
|
53
|
+
const registryDay = now().toISOString().slice(0, 10);
|
|
54
|
+
const inventoryKey = `${registryDay}:${active}`;
|
|
55
|
+
if (lastInventory !== inventoryKey) {
|
|
56
|
+
// The registry row is a view; a registry failure must not skip the real collect/brief of this minute.
|
|
57
|
+
try {
|
|
58
|
+
const db = (opts.openDb ?? openSchedulesDb)();
|
|
59
|
+
try { inventoryInternalSchedules(db, { watchRoot: root, watchEnabled: active }); lastInventory = inventoryKey; }
|
|
60
|
+
finally { if (!opts.openDb) db.close(); }
|
|
61
|
+
} catch (error) { debug.log('watch.default', 'failed', { stage: 'registry', reason: String(error) }); }
|
|
62
|
+
}
|
|
63
|
+
lastFailure = undefined;
|
|
64
|
+
if (!active) return;
|
|
65
|
+
const parts = new Intl.DateTimeFormat('en-CA', {
|
|
66
|
+
timeZone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hourCycle: 'h23',
|
|
67
|
+
}).formatToParts(now());
|
|
68
|
+
const part = (type: string) => parts.find((entry) => entry.type === type)?.value ?? '';
|
|
69
|
+
const day = `${part('year')}-${part('month')}-${part('day')}`;
|
|
70
|
+
const clock = `${part('hour')}:${part('minute')}`;
|
|
71
|
+
for (const [job, at, fire] of [['watch-collect', '07:00', collect], ['watch-brief', '08:30', brief]] as const) {
|
|
72
|
+
if (clock !== at || lastRun.get(job) === day) continue;
|
|
73
|
+
try {
|
|
74
|
+
const outcome = await fire();
|
|
75
|
+
if (job === 'watch-brief' && (!outcome || (outcome as { sent?: boolean }).sent !== true)) continue;
|
|
76
|
+
if (job === 'watch-collect' && typeof outcome === 'object' && outcome && 'ran' in outcome
|
|
77
|
+
&& (outcome as { ran: Array<{ error?: string }> }).ran.some((row) => row.error)) continue;
|
|
78
|
+
lastRun.set(job, day);
|
|
79
|
+
mkdirSync(join(root, 'intake'), { recursive: true });
|
|
80
|
+
const temp = `${lastRunFile}.${process.pid}.tmp`;
|
|
81
|
+
writeFileSync(temp, JSON.stringify(Object.fromEntries(lastRun)) + '\n');
|
|
82
|
+
renameSync(temp, lastRunFile);
|
|
83
|
+
} catch (error) { debug.log('watch.default', 'failed', { job, reason: String(error) }); }
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const reason = String(error);
|
|
87
|
+
if (reason !== lastFailure) debug.log('watch.default', 'failed', { reason });
|
|
88
|
+
lastFailure = reason;
|
|
89
|
+
} finally { running = false; }
|
|
90
|
+
};
|
|
91
|
+
const timer = (opts.setInterval ?? setInterval)(() => { void tickNow(); }, 60_000);
|
|
92
|
+
if (typeof timer === 'object') timer.unref?.();
|
|
93
|
+
void tickNow();
|
|
94
|
+
return { stop() { stopped = true; clearInterval(timer); }, tickNow };
|
|
95
|
+
}
|
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;
|
|
@@ -3,6 +3,7 @@ import { decideBudget, readBudgetInputsLive, type BudgetDecision, type BudgetInp
|
|
|
3
3
|
import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from '../harness/harness-substrate-default.js';
|
|
4
4
|
import { podMemoryLimitFor } from '../task-orchestrator/surfaces/self-implement-pod.js';
|
|
5
5
|
import { recallMemoryContext } from '../agent-substrate/execution/memory-context.js';
|
|
6
|
+
import { CONTEXT_CARD_SCREEN_CHARS } from '../context-card/index.js';
|
|
6
7
|
|
|
7
8
|
export interface GateResult<T> {
|
|
8
9
|
decision: T;
|
|
@@ -169,6 +170,7 @@ export async function relationGate(
|
|
|
169
170
|
export interface MemoryGateDeps {
|
|
170
171
|
recall: (query: string) => Promise<string>;
|
|
171
172
|
priorAbandonment: (goalId: string) => Promise<string | undefined> | string | undefined;
|
|
173
|
+
priorMustFix?: (goalId: string) => readonly string[];
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
export interface MemoryDecision {
|
|
@@ -183,15 +185,22 @@ export async function memoryGate(
|
|
|
183
185
|
card: Pick<TaskCard, 'goalId' | 'title'>,
|
|
184
186
|
deps: MemoryGateDeps = { recall: recallMemoryContext, priorAbandonment: () => undefined },
|
|
185
187
|
): Promise<GateResult<MemoryDecision>> {
|
|
186
|
-
const [
|
|
188
|
+
const [recall, priorAbandonment] = await Promise.all([
|
|
187
189
|
deps.recall(card.title), deps.priorAbandonment(card.goalId),
|
|
188
190
|
]);
|
|
191
|
+
// must-fix 와 recall 은 서로 독립이다 — recall 이 비어도 앞선 must-fix 는 맥락에 남는다.
|
|
192
|
+
const mustFix = deps.priorMustFix?.(card.goalId) ?? [];
|
|
193
|
+
const mustFixBlock = mustFix.length ? `앞선 must-fix:\n${mustFix.map((item) => `- ${item}`).join('\n')}` : '';
|
|
194
|
+
const combined = [mustFixBlock, recall].filter(Boolean).join('\n');
|
|
195
|
+
const codePoints = [...combined];
|
|
196
|
+
const truncated = codePoints.length > CONTEXT_CARD_SCREEN_CHARS;
|
|
197
|
+
const context = truncated ? codePoints.slice(0, CONTEXT_CARD_SCREEN_CHARS).join('') : combined;
|
|
189
198
|
const decision: MemoryDecision = {
|
|
190
199
|
action: 'record', context, fragmentIds: [],
|
|
191
200
|
...(priorAbandonment === undefined ? {} : { priorAbandonment }),
|
|
192
201
|
};
|
|
193
202
|
return {
|
|
194
203
|
decision,
|
|
195
|
-
explanation: `memory=${
|
|
204
|
+
explanation: `memory=${recall ? 'recalled' : 'none or unavailable'}; prior abandonment=${priorAbandonment ?? 'unknown'}; fragment IDs unavailable from recall API${truncated ? `; truncated; chars=${[...context].length}/${CONTEXT_CARD_SCREEN_CHARS}` : ''}`,
|
|
196
205
|
};
|
|
197
206
|
}
|
package/src/flow-loop/split.ts
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import type { TaskCard } from '../task-cards/card-store.js';
|
|
2
2
|
|
|
3
|
-
export interface SplitCell { id: string; title: string; seat?: string; host?: string }
|
|
3
|
+
export interface SplitCell { id: string; title: string; kind?: string; seat?: string; host?: string }
|
|
4
4
|
|
|
5
5
|
/** FLOW1: only explicitly assigned work may enter a seat's queue. The same proposal is used in shadow and live. */
|
|
6
6
|
export function splitCard(card: TaskCard, _opts: { shadow?: boolean } = {}): SplitCell[] {
|
|
7
7
|
const intake = [...card.sections].reverse().find(section => section.key.startsWith('intake:wish:'));
|
|
8
8
|
let text = card.title;
|
|
9
|
+
let kind: string | undefined;
|
|
9
10
|
if (intake) {
|
|
10
11
|
let body: unknown;
|
|
11
12
|
try { body = JSON.parse(intake.content); } catch { body = intake.content; }
|
|
12
13
|
if (typeof body === 'string') text = body;
|
|
13
|
-
else if (body && typeof body === 'object'
|
|
14
|
+
else if (body && typeof body === 'object') {
|
|
15
|
+
if (typeof (body as { text?: unknown }).text === 'string') text = (body as { text: string }).text;
|
|
16
|
+
if (typeof (body as { kind?: unknown }).kind === 'string') kind = (body as { kind: string }).kind;
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
const lines = text.split(/\r?\n/).map(line => line.trim()).filter(Boolean);
|
|
16
20
|
const cells: SplitCell[] = lines.map((line, index) => {
|
|
17
21
|
const match = /^(?:[-*]|\d+[.)])?\s*\[(OP|MK|TC|UX)\]\s*(.+)$/u.exec(line);
|
|
18
|
-
if (match) return { id: `${card.id}-${index + 1}`, title: match[2]!.trim(), seat: match[1]
|
|
22
|
+
if (match) return { id: `${card.id}-${index + 1}`, title: match[2]!.trim(), seat: match[1]!, ...(kind !== undefined ? { kind } : {}) };
|
|
19
23
|
// 담당 없는 행도 칸으로 남긴다 — seat 가 없으니 대기열엔 못 들어가고 tick 이 unplaced-no-owner 로 센다.
|
|
20
|
-
return { id: `${card.id}-${index + 1}`, title: line.replace(/^(?:[-*]|\d+[.)])\s*/u, '') };
|
|
24
|
+
return { id: `${card.id}-${index + 1}`, title: line.replace(/^(?:[-*]|\d+[.)])\s*/u, ''), ...(kind !== undefined ? { kind } : {}) };
|
|
21
25
|
});
|
|
22
26
|
// 의뢰 본문이 있으면 담당이 하나도 없어도 행마다 칸으로 남긴다. 본문 없이 제목뿐일 때만 카드 한 칸.
|
|
23
27
|
return intake || cells.some(cell => cell.seat) ? cells : [{ id: card.id, title: card.title }];
|
package/src/git-fs/worktree.ts
CHANGED
|
@@ -20,6 +20,9 @@ import { debug } from '../debug/log.js';
|
|
|
20
20
|
import { getUserConfig } from '../user-config.js';
|
|
21
21
|
|
|
22
22
|
const GIT_TIMEOUT_MS = 30_000;
|
|
23
|
+
/** 얕은 클론(Pod `git clone --depth 50` · docker/harness/job.yaml)에서 base 를 가져올 깊이 — 클론과 같은 값.
|
|
24
|
+
* ⛔ 깊이 없이 얕은 저장소로 다른 브랜치를 fetch 하면 그 브랜치의 «전 이력»을 받는다(실측 193s vs 4s · 30s 에 SIGTERM). */
|
|
25
|
+
const SHALLOW_BASE_FETCH_DEPTH = 50;
|
|
23
26
|
const WORKTREE_ADD_TIMEOUT_MS = 5 * 60_000;
|
|
24
27
|
|
|
25
28
|
export interface WorktreeAddDeps {
|
|
@@ -439,14 +442,31 @@ export function syncBaseWithRemote(
|
|
|
439
442
|
// 원격이 "그런 브랜치 없다" 고 답했다 ⇒ 축약 hex 여도 모호하지 않다.
|
|
440
443
|
if (!hasRemote) return asSha(false) ?? { checkout: base, freshness: 'local-only' };
|
|
441
444
|
|
|
445
|
+
// ⭐ 얕은 저장소면 깊이를 묶는다 — 아니면 그 브랜치의 전 이력을 받느라 GIT_TIMEOUT_MS 를 넘긴다
|
|
446
|
+
// (Pod 클론은 `--depth 50` · 비-main base 런이 전부 여기서 SIGTERM 으로 죽었다). 받은 tip 에서 갈리므로
|
|
447
|
+
// 이후 merge-base(HEAD ↔ 그 tip)는 tip 자체라 깊이 50 으로 족하다. 얕지 않으면 종전 인자 그대로다.
|
|
448
|
+
// probe 를 못 읽으면 종전 경로로 간다(값은 'unknown' 으로 관측에 남긴다).
|
|
449
|
+
const shallowProbe = git('rev-parse', '--is-shallow-repository');
|
|
450
|
+
const shallowAnswer = shallowProbe.status === 0 ? (shallowProbe.stdout || '').trim() : '';
|
|
451
|
+
const shallow: boolean | 'unknown' = shallowAnswer === 'true' ? true : shallowAnswer === 'false' ? false : 'unknown';
|
|
452
|
+
const depth = shallow === true ? SHALLOW_BASE_FETCH_DEPTH : null;
|
|
453
|
+
const fetchArgs = depth === null ? ['fetch', 'origin', wanted] : ['fetch', `--depth=${depth}`, 'origin', wanted];
|
|
454
|
+
const fetchStartedAt = Date.now();
|
|
442
455
|
// Only the no-runner fallback joins the shared retry seam; injected runners remain
|
|
443
456
|
// an exact test/caller seam with their prior command count.
|
|
444
457
|
const fetched = runner
|
|
445
|
-
? git(
|
|
446
|
-
: runGitCommand(repoRoot,
|
|
458
|
+
? git(...fetchArgs)
|
|
459
|
+
: runGitCommand(repoRoot, fetchArgs, { encoding: 'utf8', timeout: GIT_TIMEOUT_MS });
|
|
460
|
+
const fetchMs = Date.now() - fetchStartedAt;
|
|
461
|
+
debug.log('git-fs.worktree', 'base.fetch', { base, shallow, depth, ms: fetchMs, ok: fetched.status === 0, signal: fetched.signal ?? null }, fetched.status === 0 ? undefined : { level: 'warn' });
|
|
447
462
|
if (fetched.status !== 0) {
|
|
448
463
|
// origin 에 있는 것을 확인했는데 못 가져왔다 ⇒ 낡은 로컬로 진행하면 조용히 틀린다.
|
|
449
|
-
|
|
464
|
+
// spawnSync 의 timeout 은 SIGTERM 으로 끝난다 — 「실패」와 「시간 초과」를 문면에서 가른다.
|
|
465
|
+
const timedOut = fetched.status === null && fetched.signal === 'SIGTERM';
|
|
466
|
+
const what = timedOut
|
|
467
|
+
? `fetch timed out after ${GIT_TIMEOUT_MS / 1000}s (shallow=${shallow}${depth === null ? '' : `, depth=${depth}`})`
|
|
468
|
+
: 'fetch failed';
|
|
469
|
+
throw new Error(`git worktree base sync failed — origin/${remoteBranch} exists but ${what}: status=${fetched.status}, signal=${fetched.signal ?? 'none'}, stdout=${JSON.stringify((fetched.stdout || '').trim().slice(0, 200))}, stderr=${JSON.stringify((fetched.stderr || '').trim().slice(0, 200))}`);
|
|
450
470
|
}
|
|
451
471
|
// ⭐ **가져온 것**에서 갈린다(리뷰 must-fix ②) — ls-remote 로 먼저 읽은 SHA 를 쓰면 그 사이 원격이
|
|
452
472
|
// 전진했을 때 "원격 tip" 계약이 깨진다. FETCH_HEAD 가 방금 받은 tip 이다.
|
|
@@ -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';
|
|
@@ -33,7 +34,7 @@ import { installDeliverableVerifyCliCommand, type InstallDeliverableVerifyCliDep
|
|
|
33
34
|
import { getUserConfig } from '../user-config.js';
|
|
34
35
|
import { resolveRepositoryName } from './repository-name.js';
|
|
35
36
|
import { installHarnessCliSinkHook } from './harness-cli-sink.js';
|
|
36
|
-
import { addHarnessQueue, HarnessQueueDuplicateError, harnessQueueReceiptPath, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, tickHarnessQueue, type HarnessQueueDeps, type QueueItem, type QueueSeat } from './harness-queue.js';
|
|
37
|
+
import { addHarnessQueue, HarnessQueueDuplicateError, harnessQueueReceiptPath, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, setHarnessQueuePriority, tickHarnessQueue, type HarnessQueueDeps, type QueueItem, type QueueSeat } from './harness-queue.js';
|
|
37
38
|
import { writeHarnessQueueReceipt } from './harness-queue-child.js';
|
|
38
39
|
import { parseDoorSince, queryLaunchDoors, renderLaunchDoors, type DoorTable } from './launch-stamp.js';
|
|
39
40
|
import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from './harness-substrate-default.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('자리별 영속 발사 대기열');
|
|
@@ -2548,12 +2550,20 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2548
2550
|
console.log(`${row.id} ${row.seat} ${row.kind} queued`);
|
|
2549
2551
|
}));
|
|
2550
2552
|
queue.command('list').description('대기·발사 원장 조회').action(() => queueAction(async () => {
|
|
2551
|
-
for (const row of listHarnessQueue(queueDeps)) console.log(`${row.id} ${row.seat} ${row.status} ${row.kind} ${row.input}${row.waitingReason ? ` · ${row.waitingReason}` : ''}`);
|
|
2553
|
+
for (const row of listHarnessQueue(queueDeps)) console.log(`${row.id} ${row.seat} ${row.status} ${row.kind} ${row.input}${row.priority === undefined ? '' : ` · prio ${row.priority}`}${row.waitingReason ? ` · ${row.waitingReason}` : ''}`);
|
|
2552
2554
|
}));
|
|
2553
2555
|
queue.command('remove <id>').description('대기 중 또는 종료 확인된 항목 제거').action((id: string) => queueAction(async () => {
|
|
2554
2556
|
if (!await removeHarnessQueue(id, queueDeps)) throw new Error(`queue item active or not found: ${id}`);
|
|
2555
2557
|
console.log(`${id} removed`);
|
|
2556
2558
|
}));
|
|
2559
|
+
queue.command('prio <id> <n>').description('대기 중 항목의 우선순위 재조정(클수록 먼저 · 다음 tick 부터)').action((id: string, n: string) => queueAction(async () => {
|
|
2560
|
+
const value = Number(n);
|
|
2561
|
+
if (!n.trim() || !Number.isFinite(value)) throw new Error(`harness queue prio: 수가 아니다 — ${n}`);
|
|
2562
|
+
// A CLI call is the actor here; a seat or track that drives it names itself through the environment.
|
|
2563
|
+
const by = process.env.ELANOUS_TRACK || process.env.ELANOUS_HARNESS_SEAT || 'cli';
|
|
2564
|
+
const row = await setHarnessQueuePriority(id, value, by, queueDeps);
|
|
2565
|
+
console.log(`${row.id} prio ${row.priority}`);
|
|
2566
|
+
}));
|
|
2557
2567
|
queue.command('reconcile <id>').description('불확정 발사를 확인하고 종료 또는 미발사 증거가 있으면 예약 해소').action((id: string) => queueAction(async () => {
|
|
2558
2568
|
console.log(`${id} ${await reconcileHarnessQueue(id, queueDeps)}`);
|
|
2559
2569
|
}));
|