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/cli/release-cli.ts
CHANGED
|
@@ -47,6 +47,7 @@ import { runReleaseIfReady } from './release-run-if-ready.js';
|
|
|
47
47
|
import { formatPreflight, releasePreflight } from '../../scripts/release-loop/preflight.js';
|
|
48
48
|
import { autoStartScheduledRelease, type AutoStartDeferral } from '../release-loop/auto-start.js';
|
|
49
49
|
import { landingFreezeMessage, LandingFrozenError, readLandingFreeze } from '../release-loop/landing-freeze.js';
|
|
50
|
+
import { formatLightRc, runLightRc, type LightRcDeps } from '../release-loop/light-rc.js';
|
|
50
51
|
|
|
51
52
|
export const DEFAULT_PUBLIC_REPO = 'ElanvitalAI/elanous';
|
|
52
53
|
const SEMVER = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
|
|
@@ -594,7 +595,7 @@ function compareReleaseVersions(a: string, b: string): number {
|
|
|
594
595
|
return 0;
|
|
595
596
|
}
|
|
596
597
|
|
|
597
|
-
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}, landedDeps: LandedButYellowDeps = {}, hqDeps: HqDeps = {}): void {
|
|
598
|
+
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}, landedDeps: LandedButYellowDeps = {}, hqDeps: HqDeps = {}, lightRcDeps: LightRcDeps = {}): void {
|
|
598
599
|
const release = program.command('release').description('공개 배포 한 판 — prepare(로컬) → publish(--yes) → verify (docs/manual/MANUAL-versioning-and-release-2026-09-25.md)');
|
|
599
600
|
const schedule = release.command('schedule').description('판별 컷·착지 마감 조회·갱신');
|
|
600
601
|
const scheduleLedgerRoot = () => releaseRunDeps.ledgerRoot ?? releaseLedgerRoot();
|
|
@@ -793,17 +794,17 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
793
794
|
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
794
795
|
.option('--status <status>', 'green|yellow|red|done').option('--evidence <evidence>', '근거').option('--owner <owner>', '담당')
|
|
795
796
|
.option('--disposition <disposition>', 'move|known-issue|block').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄')
|
|
796
|
-
.option('--priority <priority>', 'P0|P1|P2').option('--deadline-version <v>', '마감 판').option('--predecessor <id...>', '선행 칸 id')
|
|
797
|
+
.option('--priority <priority>', 'P0|P1|P2').option('--deadline-version <v>', '마감 판').option('--predecessor <id...>', '선행 칸 id').option('--no-predecessor', '선행 칸 비우기(진짜 의존이 아니면 · CHECKLIST-PRED-CLEAR)')
|
|
797
798
|
.option('--ceo-minutes <minutes>', '대표 손 분량(분)').option('--ceo-date <date>', '대표 손 날짜 YYYY-MM-DD')
|
|
798
799
|
.option('--accelerator', '가속 등급 부여').option('--no-accelerator', '가속 등급 해제(기본은 없음)')
|
|
799
800
|
.option('--ref <path...>', '근거 문서 더하기 — 저장소 상대 경로[#절] (반복 가능 · 중복 제거)')
|
|
800
|
-
.action((id: string, opts: { ref?: string[]; status?: string; evidence?: string; owner?: string; disposition?: string; kind?: string; priority?: string; deadlineVersion?: string; predecessor?: string[]; ceoMinutes?: string; ceoDate?: string; accelerator?: boolean }, cmd: Command) => {
|
|
801
|
+
.action((id: string, opts: { ref?: string[]; status?: string; evidence?: string; owner?: string; disposition?: string; kind?: string; priority?: string; deadlineVersion?: string; predecessor?: string[] | false; ceoMinutes?: string; ceoDate?: string; accelerator?: boolean }, cmd: Command) => {
|
|
801
802
|
const { version, json } = context(cmd);
|
|
802
803
|
if (opts.status !== undefined && !['green', 'yellow', 'red', 'done'].includes(opts.status)) throw new CliUserError(`잘못된 상태: ${opts.status}`, 'green|yellow|red|done');
|
|
803
804
|
if (opts.disposition !== undefined && !['move', 'known-issue', 'block'].includes(opts.disposition)) throw new CliUserError(`잘못된 처분: ${opts.disposition}`, 'move|known-issue|block');
|
|
804
805
|
if (opts.status === undefined && opts.evidence === undefined && opts.owner === undefined && opts.disposition === undefined && opts.kind === undefined && opts.priority === undefined && opts.deadlineVersion === undefined && opts.predecessor === undefined && opts.ceoMinutes === undefined && opts.ceoDate === undefined && opts.accelerator === undefined && opts.ref === undefined) throw new CliUserError('갱신할 칸을 지정하라', '--ref · --status · --evidence · --owner · --disposition · --kind · --priority · --deadline-version · --predecessor · --ceo-minutes · --ceo-date · --accelerator · --no-accelerator 중 하나');
|
|
805
806
|
if (!mayWrite(cmd)) return;
|
|
806
|
-
const data = setItem(version, id, { ...(opts.ref !== undefined ? { refs: opts.ref } : {}), ...(opts.status !== undefined ? { status: opts.status as ChecklistStatus } : {}), ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.disposition !== undefined ? { disposition: opts.disposition as ChecklistDisposition } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}), ...(opts.priority !== undefined ? { priority: opts.priority as PlacementPriority } : {}), ...(opts.deadlineVersion !== undefined ? { deadlineVersion: opts.deadlineVersion } : {}), ...(opts.predecessor !== undefined ? { predecessors: opts.predecessor } : {}), ...(opts.ceoMinutes !== undefined ? { ceoMinutes: ceoMinutes(opts.ceoMinutes) } : {}), ...(opts.ceoDate !== undefined ? { ceoDate: opts.ceoDate } : {}), ...(opts.accelerator !== undefined ? { accelerator: opts.accelerator ? true : null } : {}) }, process.env.ELANOUS_TRACK || 'cli');
|
|
807
|
+
const data = setItem(version, id, { ...(opts.ref !== undefined ? { refs: opts.ref } : {}), ...(opts.status !== undefined ? { status: opts.status as ChecklistStatus } : {}), ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.disposition !== undefined ? { disposition: opts.disposition as ChecklistDisposition } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}), ...(opts.priority !== undefined ? { priority: opts.priority as PlacementPriority } : {}), ...(opts.deadlineVersion !== undefined ? { deadlineVersion: opts.deadlineVersion } : {}), ...(opts.predecessor !== undefined ? { predecessors: opts.predecessor === false ? [] : opts.predecessor } : {}), ...(opts.ceoMinutes !== undefined ? { ceoMinutes: ceoMinutes(opts.ceoMinutes) } : {}), ...(opts.ceoDate !== undefined ? { ceoDate: opts.ceoDate } : {}), ...(opts.accelerator !== undefined ? { accelerator: opts.accelerator ? true : null } : {}) }, process.env.ELANOUS_TRACK || 'cli');
|
|
807
808
|
const item = data.items.find((entry) => entry.id === id);
|
|
808
809
|
const why = item?.kind === 'screen' && item.status === 'green' ? parityGap(item.evidence) : null;
|
|
809
810
|
if (why) {
|
|
@@ -1054,16 +1055,40 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1054
1055
|
process.exitCode = 1;
|
|
1055
1056
|
}
|
|
1056
1057
|
});
|
|
1058
|
+
// LIGHT-RC (0.2.19) — read-only for the ledger · never touches the landing freeze or launches Pods.
|
|
1059
|
+
release.command('light-rc')
|
|
1060
|
+
.description('가벼운 RC 점검 — 직전 판 컷(또는 --base) 이후 변경 범위 self gate ⊕ 상시 목록(release/light-rc-always.txt)을 원격 게이트 호스트에서 · 새 회귀(introduced>0)면 exit 1')
|
|
1061
|
+
.requiredOption('--version <v>', '점검할 판(x.y.z)')
|
|
1062
|
+
.option('--base <ref>', '비교 기준(기본: git merge-base origin/main origin/release/<원장 직전 판>)')
|
|
1063
|
+
.option('--remote <host>', '게이트 호스트(기본 config gateRemote.host)')
|
|
1064
|
+
.option('--local', '원격 대신 이 기계에서 돌린다(원격 자식이 이것으로 다시 불린다)')
|
|
1065
|
+
.option('--shards <n>', '시험 분할 수', '4')
|
|
1066
|
+
.option('--json', '결과 한 줄 JSON(stdout) · 사람 줄은 stderr')
|
|
1067
|
+
.action(async (o: { version: string; base?: string; remote?: string; local?: boolean; shards: string; json?: boolean }) => {
|
|
1068
|
+
// The root strips `--local` from argv (remote-bookmark attach) before Commander sees it — same read as `self gate`.
|
|
1069
|
+
const local = !!o.local || process.argv.slice(2).includes('--local');
|
|
1070
|
+
await jsonAction(o.json, async (log) => {
|
|
1071
|
+
if (o.remote !== undefined && local) throw new Error('release light-rc: --remote and --local cannot be combined');
|
|
1072
|
+
const shards = Number(o.shards);
|
|
1073
|
+
const result = await runLightRc(o.version, { base: o.base, remote: o.remote, local, shards, ledgerRoot: releaseRunDeps.ledgerRoot, log: (l) => console.error(l) }, lightRcDeps);
|
|
1074
|
+
for (const line of formatLightRc(result)) log(line);
|
|
1075
|
+
return result;
|
|
1076
|
+
}, (r) => r.ok);
|
|
1077
|
+
});
|
|
1057
1078
|
release.command('resume')
|
|
1058
1079
|
.description('실패한 릴리스 런을 이어 달린다 — cut-branch --append 로 고친 release/<v> 새 끝을 version-release 기록에 반영(빨리감기만·상태 백업) 뒤 --from 노드부터')
|
|
1059
1080
|
.requiredOption('--run <runId>', '실패한 release-loop 런 ID')
|
|
1060
1081
|
.requiredOption('--from <node>', '다시 시작할 노드(예: gate)')
|
|
1082
|
+
.option('--partial', 'GATE-PARTIAL — --from gate 에서 앞 게이트 뒤 바뀐 시험 파일 ⊕ 앞 실패 파일만 다시 돈다(시험·문서만 바뀐 경우 · 아니면 전체 게이트로)')
|
|
1061
1083
|
.option('--json', '결과 한 줄 JSON(stdout)')
|
|
1062
|
-
.action(async (o: { run: string; from: string; json?: boolean }) => {
|
|
1084
|
+
.action(async (o: { run: string; from: string; partial?: boolean; json?: boolean }) => {
|
|
1063
1085
|
await jsonAction(o.json, async (log) => {
|
|
1064
|
-
const result = await resumeReleaseRun({ runId: o.run, from: o.from });
|
|
1086
|
+
const result = await resumeReleaseRun({ runId: o.run, from: o.from, partial: o.partial });
|
|
1087
|
+
if (result.partial.requested) log(result.partial.applied
|
|
1088
|
+
? `◐ 부분 재검: ${result.partial.files}파일 · 나머지는 앞 게이트(${result.partial.priorCommit.slice(0, 12)}) 결과를 잇는다`
|
|
1089
|
+
: `● 전체 게이트로: ${result.partial.reason}`);
|
|
1065
1090
|
log(`${result.tip.changed ? `↻ ${result.tip.branch} ${result.tip.from.slice(0, 12)} → ${result.tip.to.slice(0, 12)} (백업 ${result.tip.backup})` : `· ${result.tip.branch} 끝 그대로 ${result.tip.to.slice(0, 12)}`} · ${o.from} 부터 → ${result.state.status}`);
|
|
1066
|
-
return { tip: result.tip, status: result.state.status, runId: result.state.runId };
|
|
1091
|
+
return { tip: result.tip, partial: result.partial, status: result.state.status, runId: result.state.runId };
|
|
1067
1092
|
}, (r) => r.status === 'done' || r.status === 'awaiting-approval');
|
|
1068
1093
|
});
|
|
1069
1094
|
release.command('auto-start')
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { addSource, listSources } from '../intake-plane/intake-sources.js';
|
|
6
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
4
7
|
import { Command } from 'commander';
|
|
5
8
|
import { formatDoctorReport, registerDoctorCommand, runDoctor, type DoctorOptions, type DoctorReport } from './doctor-cli.js';
|
|
6
9
|
import { applyClaudePluginSetup, planClaudePluginSetup } from './claude-plugin-setup.js';
|
|
7
10
|
import { recommendedSetup } from './setup-recommend.js';
|
|
8
11
|
import { detectSkillCliAuth, type CliAuthStatus } from '../onboarding/cli-auth-status.js';
|
|
9
12
|
import { debug } from '../debug/log.js';
|
|
10
|
-
import { getUserConfig, saveUserConfig, type UserConfig } from '../user-config.js';
|
|
13
|
+
import { getUserConfig, saveUserConfig, userConfigPath, type UserConfig } from '../user-config.js';
|
|
11
14
|
|
|
12
15
|
const ELANOUS_LOGIN_COMMAND = 'elanous login openai-codex';
|
|
13
16
|
const PROVIDER_COMMAND = 'elanous config set llm.provider openai-codex';
|
|
@@ -29,6 +32,9 @@ export interface SetupCliDeps extends DoctorOptions {
|
|
|
29
32
|
homeDir?: () => string;
|
|
30
33
|
getUserConfig?: () => UserConfig;
|
|
31
34
|
saveUserConfig?: (config: UserConfig) => void;
|
|
35
|
+
watchRoot?: string;
|
|
36
|
+
/** Test seam: injected configs are treated as already provisioned unless explicitly first-run. */
|
|
37
|
+
firstRunTopics?: boolean;
|
|
32
38
|
planClaudePluginSetup?: typeof planClaudePluginSetup;
|
|
33
39
|
applyClaudePluginSetup?: typeof applyClaudePluginSetup;
|
|
34
40
|
prompt?: (message: string) => Promise<string | undefined>;
|
|
@@ -209,6 +215,7 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
209
215
|
setExitCode(1);
|
|
210
216
|
return;
|
|
211
217
|
}
|
|
218
|
+
const isFirstRun = deps.firstRunTopics ?? (!deps.getUserConfig && !existsSync(userConfigPath()));
|
|
212
219
|
let steps = setupSteps(deps);
|
|
213
220
|
const provider = steps[1]!;
|
|
214
221
|
if (!provider.complete) {
|
|
@@ -224,6 +231,29 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
224
231
|
out.log(formatSetupReport(doctor, steps, false));
|
|
225
232
|
showCliSkills(false);
|
|
226
233
|
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
234
|
+
let configured = (deps.getUserConfig ?? getUserConfig)();
|
|
235
|
+
if (!configured.starter?.topics && configured.watch?.enabled !== false
|
|
236
|
+
&& isFirstRun
|
|
237
|
+
&& isStdinTty() && !opts.yes) {
|
|
238
|
+
const answer = (await prompt('관심 주제는 무엇인가요? (쉼표로 구분 · 건너뛰려면 Enter) '))?.trim();
|
|
239
|
+
if (answer) {
|
|
240
|
+
configured = { ...configured, starter: { topics: answer.split(',').map((topic) => topic.trim()).filter(Boolean) } };
|
|
241
|
+
(deps.saveUserConfig ?? saveUserConfig)(configured);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const starter = configured.starter;
|
|
245
|
+
if (Array.isArray(starter?.topics) && configured.watch?.enabled !== false) {
|
|
246
|
+
const root = deps.watchRoot ?? effectiveInstanceRoot();
|
|
247
|
+
const existing = listSources({ seat: 'user' }, root);
|
|
248
|
+
for (const rawTopic of starter.topics) {
|
|
249
|
+
if (typeof rawTopic !== 'string' || !rawTopic.trim()) continue;
|
|
250
|
+
const topic = rawTopic.trim();
|
|
251
|
+
if (existing.some((source) => source.kind === 'github-query' && source.spec === topic)) continue;
|
|
252
|
+
const id = `watch-${createHash('sha256').update(topic).digest('hex').slice(0, 12)}`;
|
|
253
|
+
if (listSources({}, root).some((source) => source.id === id)) continue;
|
|
254
|
+
existing.push(addSource({ id, seat: 'user', kind: 'github-query', spec: topic, every: '1d', why: 'starter.topics' }, root));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
227
257
|
const accepted = opts.yes || (isStdinTty() && /^(?:y|yes)?$/i.test((await prompt('추천대로 켤까요? [Y/n] '))?.trim() ?? 'n'));
|
|
228
258
|
if (accepted) {
|
|
229
259
|
const runDoctorFix = deps.runDoctorFix ?? (async (args: readonly string[]) => {
|
package/src/cli/tasks-cli.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
3
|
import { InvalidArgumentError, Option, type Command } from 'commander';
|
|
4
4
|
import { debug } from '../debug/log.js';
|
|
5
5
|
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
6
6
|
import { readNexusRuntime } from '../nexus/runtime.js';
|
|
7
|
+
import { checklistDevVersion } from '../release-loop/checklist.js';
|
|
8
|
+
import { cardsBoard, countBoardTasks, INTERNAL_PACK_PROJECT, mergeBoards, releasePackBoard, type BoardNode } from '../task-agent/board.js';
|
|
7
9
|
import type { Task } from '../task-orchestrator/types.js';
|
|
8
|
-
import { handTask, nextMoveFor, readTaskAgentState, readTaskCard, taskAgentStatePath as taskStatePathDefault, shellQuote, TASK_CARD_PREFIX, TASK_SEATS, type TaskCard, type TaskLauncher, type TaskSeat } from '../task-agent/task-hand.js';
|
|
10
|
+
import { cardPrNumber, COMPLETION_KINDS, handTask, nextMoveFor, readTaskAgentState, readTaskCard, taskAgentStatePath as taskStatePathDefault, shellQuote, TASK_CARD_PREFIX, TASK_SEATS, type CompletionKind, type TaskCard, type TaskLaunchContext, type TaskLaunchReceipt, type TaskLauncher, type TaskSeat } from '../task-agent/task-hand.js';
|
|
11
|
+
import { refreshCardRunBinding, type CardRunEvidenceDeps } from '../task-agent/card-evidence.js';
|
|
9
12
|
import { advanceMission, handMission, MissionAdvanceError, openMissionIds, recordPieceRef, type AdvanceMissionResult, type MissionDecompose, type PieceEvidenceReader } from '../task-agent/mission.js';
|
|
10
13
|
|
|
11
14
|
type TaskRow = Pick<Task, 'id' | 'title' | 'priority' | 'status' | 'createdAt' | 'approval' | 'generatedBy'>;
|
|
@@ -25,6 +28,10 @@ export interface TasksCliDeps {
|
|
|
25
28
|
missionDecompose?: MissionDecompose;
|
|
26
29
|
/** `task advance` 의 착지 근거 읽기(시험 주입). 기본 = `predecessorState`(gh · 런 원장). */
|
|
27
30
|
pieceEvidence?: PieceEvidenceReader;
|
|
31
|
+
/** `task board` 의 내부 팩 어댑터(시험 주입). 기본 = 현재 판(`checklistDevVersion()`)의 `releasePackBoard` — 읽기만. */
|
|
32
|
+
releaseBoard?: () => BoardNode[];
|
|
33
|
+
/** `tasks show`·`advance` 의 런 근거 읽기(시험 주입) — 기본 = 런 원장(이 우주 ⊕ 연합) ⊕ 호스트 logs 의 Pod job-finished. */
|
|
34
|
+
cardRunEvidence?: CardRunEvidenceDeps;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
/** `<조각id>=<값>` 반복 인자. */
|
|
@@ -65,16 +72,28 @@ export async function registerTaskAgentSink(register?: (surface: string) => Prom
|
|
|
65
72
|
* config-dir 은 명시(`--config-dir`/`--test`)가 있으면 그것, 없으면 운영 루트(`prodInstanceRoot()`)다.
|
|
66
73
|
* (작업 트리에서 그냥 띄우면 test 우주로 가서 동결·몫·풀 상한 밖에서 돈다.)
|
|
67
74
|
*/
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
/** This package's CLI entry — never `process.argv[1]`, which is whatever script started this process
|
|
76
|
+
* (ORCH-LIVE-1008: the orchestrator tick runs `bun …/tick.ts delegate`, so the hand launched `tick.ts --config-dir …
|
|
77
|
+
* harness say …`, which exited 2 with stdio ignored — the card said `launched` and no run ever started). */
|
|
78
|
+
export const ELANOUS_CLI_ENTRY = resolve(import.meta.dir, '../../bin/elanous.mjs');
|
|
79
|
+
|
|
80
|
+
/** argv for a detached `elanous` child that runs `args` in `configDir`. */
|
|
81
|
+
export function taskLauncherArgv(configDir: string, args: readonly string[]): string[] {
|
|
82
|
+
return [ELANOUS_CLI_ENTRY, '--config-dir', configDir, ...args];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function defaultTaskLauncher(args: string[], cwd?: string, context?: TaskLaunchContext, deps: { spawn?: DetachedSpawn } = {}): Promise<void | TaskLaunchReceipt> {
|
|
86
|
+
const spawn = deps.spawn ?? ((await import('node:child_process')).spawn as unknown as DetachedSpawn);
|
|
70
87
|
const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
|
|
71
88
|
const { prodInstanceRoot } = await import('../instance/resolve.js');
|
|
72
89
|
const configDir = getElanousConfigDirOverride() ?? prodInstanceRoot();
|
|
73
|
-
|
|
90
|
+
// TA-CARD-RUN-LINK: 런 id 를 자식 환경에 얹는다 — `harness say` 의 런(호스트 orchestrate)이 그 id 를 상속한다.
|
|
91
|
+
await spawnDetachedConfirmed(spawn, process.execPath, taskLauncherArgv(configDir, args), SPAWN_CONFIRM_TIMEOUT_MS, cwd, context?.env);
|
|
92
|
+
return context ? { runId: context.runId } : undefined;
|
|
74
93
|
}
|
|
75
94
|
|
|
76
95
|
/** `spawn` 의 필요한 면만(시험 주입). */
|
|
77
|
-
export type DetachedSpawn = (command: string, args: string[], options: { detached: true; stdio: 'ignore' }) => {
|
|
96
|
+
export type DetachedSpawn = (command: string, args: string[], options: { detached: true; stdio: 'ignore'; cwd?: string; env?: NodeJS.ProcessEnv }) => {
|
|
78
97
|
pid?: number;
|
|
79
98
|
once(event: 'spawn', listener: () => void): unknown;
|
|
80
99
|
once(event: 'error', listener: (error: Error) => void): unknown;
|
|
@@ -89,10 +108,10 @@ export const SPAWN_CONFIRM_TIMEOUT_MS = 2_000;
|
|
|
89
108
|
* 떼어 띄우고 «떴는지» 확인한다 — 'spawn' 이면 성공, 'error'(ENOENT·EACCES 등)면 던진다.
|
|
90
109
|
* 확인 없이 돌려주면 비동기 error 가 처리되지 않고 카드가 `launched` 로 남는다(사후 리뷰 must-fix).
|
|
91
110
|
*/
|
|
92
|
-
export function spawnDetachedConfirmed(spawnFn: DetachedSpawn, command: string, args: string[], timeoutMs = SPAWN_CONFIRM_TIMEOUT_MS): Promise<void> {
|
|
111
|
+
export function spawnDetachedConfirmed(spawnFn: DetachedSpawn, command: string, args: string[], timeoutMs = SPAWN_CONFIRM_TIMEOUT_MS, cwd?: string, env?: Record<string, string>): Promise<void> {
|
|
93
112
|
return new Promise<void>((resolve, reject) => {
|
|
94
113
|
let child: ReturnType<DetachedSpawn>;
|
|
95
|
-
try { child = spawnFn(command, args, { detached: true, stdio: 'ignore' }); } catch (error) { reject(error); return; }
|
|
114
|
+
try { child = spawnFn(command, args, { detached: true, stdio: 'ignore', ...(cwd ? { cwd } : {}), ...(env ? { env: { ...process.env, ...env } } : {}) }); } catch (error) { reject(error); return; }
|
|
96
115
|
let settled = false;
|
|
97
116
|
const finish = (error?: Error) => {
|
|
98
117
|
if (settled) return;
|
|
@@ -122,10 +141,20 @@ function headLine(text: string): string {
|
|
|
122
141
|
return first.length > 100 ? `${first.slice(0, 100)}…` : first;
|
|
123
142
|
}
|
|
124
143
|
|
|
144
|
+
/** 런 연결 한 줄 — 런 id 가 없으면 없다(옛 카드 · shadow). */
|
|
145
|
+
function runLinkLine(card: TaskCard): string[] {
|
|
146
|
+
if (!card.runId) return [];
|
|
147
|
+
const number = cardPrNumber(card);
|
|
148
|
+
const url = typeof card.pr === 'object' ? card.pr.url : undefined;
|
|
149
|
+
const pr = number !== undefined ? `#${number}${url ? ` ${url}` : ''}` : '-';
|
|
150
|
+
return [`런: ${card.runId} · 골: ${card.goalId ?? '-'} · PR: ${pr}${card.runChildId ? ` · 자식 런: ${card.runChildId}` : ''}`];
|
|
151
|
+
}
|
|
152
|
+
|
|
125
153
|
function taskCardLines(card: TaskCard): string[] {
|
|
126
154
|
return [
|
|
127
155
|
[card.id, card.status, card.seat ?? '-', card.checklistId ?? '-', card.createdAt, card.text].join('\t'),
|
|
128
156
|
...(card.mission ? [`미션: ${card.mission} · after: ${card.after?.length ? card.after.join(', ') : '-'}`] : []),
|
|
157
|
+
...runLinkLine(card),
|
|
129
158
|
`다음 수: ${moveLine(card)}`,
|
|
130
159
|
];
|
|
131
160
|
}
|
|
@@ -135,7 +164,8 @@ function missionLines(mission: TaskCard, pieces: TaskCard[]): string[] {
|
|
|
135
164
|
const edges = pieces.flatMap((piece) => (piece.after ?? []).map((before) => `간선: ${before} -> ${piece.id}`));
|
|
136
165
|
return [
|
|
137
166
|
[mission.id, 'mission', mission.seat ?? '-', mission.checklistId ?? '-', mission.createdAt, `조각 ${pieces.length} · 간선 ${edges.length} · 출처 ${mission.splitSource ?? '-'}`, headLine(mission.text)].join('\t'),
|
|
138
|
-
...pieces.map((piece) => [`조각: ${piece.id}`, piece.status, nextMoveFor(piece).kind, `after: ${piece.after?.length ? piece.after.join(',') : '-'}`, headLine(piece.text)
|
|
167
|
+
...pieces.map((piece) => [`조각: ${piece.id}`, piece.status, nextMoveFor(piece).kind, `after: ${piece.after?.length ? piece.after.join(',') : '-'}`, headLine(piece.text),
|
|
168
|
+
...(piece.runId ? [`런: ${piece.runId}${cardPrNumber(piece) !== undefined ? ` · PR #${cardPrNumber(piece)}` : ''}`] : [])].join('\t')),
|
|
139
169
|
...edges,
|
|
140
170
|
...(mission.greenProposal ? [`green 제안: ${mission.greenProposal.at} · 칸 ${mission.greenProposal.checklistId ?? '-'} · 근거 ${Object.entries(mission.greenProposal.evidence).map(([id, ref]) => `${id}=${ref}`).join(', ')}`] : []),
|
|
141
171
|
];
|
|
@@ -255,16 +285,31 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
255
285
|
.description('TASK-AGENT 에 과제 한 줄을 넘긴다 — 카드를 적고 첫 수(harness say --substrate pod --merge-by-host)를 고른다 · 기본 shadow(발사 0) · `--mission` 이면 조각 카드 ⊕ 선후로 쪼개 선행 없는 조각만 넘긴다')
|
|
256
286
|
.addOption(new Option('--seat <seat>', `과제 자리 (${TASK_SEATS.join('|')})`).choices([...TASK_SEATS]))
|
|
257
287
|
.option('--checklist <cellId>', '릴리스 체크리스트 칸 id')
|
|
288
|
+
.addOption(new Option('--completion <kind>', `종결 종류 (${COMPLETION_KINDS.join('|')} · 기본 code-pr = PR 병합)`).choices([...COMPLETION_KINDS]))
|
|
258
289
|
.option('--mission <text>', '미션 문면 — 조각(`- …`·`① …`·`1. …` ⊕ `after: 1`)으로 나열돼 있으면 결정론, 아니면 분해기로 쪼갠다')
|
|
290
|
+
.option('--project <id>', '프로젝트 id — --target 과 함께')
|
|
291
|
+
.option('--goal <id>', '보드 소속 목표 id (task board)')
|
|
292
|
+
.option('--milestone <id>', '보드 소속 이정표 id (task board)')
|
|
293
|
+
.option('--target <dir>', '프로젝트 대상 디렉터리(있어야 한다 · 상대 경로는 절대로 · git 이 아니면 --completion 이 code-pr 밖이어야 한다) — 발사기를 이 디렉터리에서 띄운다')
|
|
259
294
|
.option('--live', '실제로 발사한다(기본은 shadow — 명령만 출력)')
|
|
260
295
|
.option('--json', 'JSON 출력')
|
|
261
|
-
.action(async (text: string | undefined, opts: { seat?: TaskSeat; checklist?: string; mission?: string; live?: boolean; json?: boolean }) => {
|
|
296
|
+
.action(async (text: string | undefined, opts: { seat?: TaskSeat; checklist?: string; completion?: CompletionKind; mission?: string; project?: string; target?: string; goal?: string; milestone?: string; live?: boolean; json?: boolean }) => {
|
|
262
297
|
await registerTaskAgentSink(deps.registerSink);
|
|
263
298
|
if ((text === undefined) === (opts.mission === undefined)) {
|
|
264
299
|
out('과제 한 줄 «또는» --mission <문면> 중 하나만 준다');
|
|
265
300
|
process.exitCode = 1;
|
|
266
301
|
return;
|
|
267
302
|
}
|
|
303
|
+
if ((opts.project === undefined) !== (opts.target === undefined)) {
|
|
304
|
+
out('--project <id> 와 --target <dir> 를 함께 줘야 한다');
|
|
305
|
+
process.exitCode = 1;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (opts.mission !== undefined && (opts.completion !== undefined || opts.project !== undefined || opts.goal !== undefined || opts.milestone !== undefined)) {
|
|
309
|
+
out('--completion/--project/--target/--goal/--milestone 은 과제 한 줄에만 준다 — --mission 조각은 종전처럼 code-pr 이다');
|
|
310
|
+
process.exitCode = 1;
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
268
313
|
if (opts.mission !== undefined) {
|
|
269
314
|
try {
|
|
270
315
|
const result = await handMission({
|
|
@@ -297,8 +342,12 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
297
342
|
try {
|
|
298
343
|
const result = await handTask({
|
|
299
344
|
text: text!,
|
|
345
|
+
...(opts.project !== undefined && opts.target !== undefined ? { project: { id: opts.project, target: opts.target } } : {}),
|
|
346
|
+
...(opts.goal !== undefined ? { goal: opts.goal } : {}),
|
|
347
|
+
...(opts.milestone !== undefined ? { milestone: opts.milestone } : {}),
|
|
300
348
|
...(opts.seat ? { seat: opts.seat } : {}),
|
|
301
349
|
...(opts.checklist ? { checklistId: opts.checklist } : {}),
|
|
350
|
+
...(opts.completion ? { completion: opts.completion } : {}),
|
|
302
351
|
live: opts.live === true,
|
|
303
352
|
...(deps.taskStatePath ? { statePath: deps.taskStatePath } : {}),
|
|
304
353
|
launcher: deps.taskLauncher ?? defaultTaskLauncher,
|
|
@@ -307,6 +356,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
307
356
|
else {
|
|
308
357
|
out(`${result.card.id}\t${result.mode}\t${result.launched ? 'launched' : 'not launched'}`);
|
|
309
358
|
out(`elanous ${result.move.command!.map(shellQuote).join(' ')}`);
|
|
359
|
+
if (result.cwd) out(`(cwd: ${result.cwd})`);
|
|
310
360
|
if (!result.launched) out('(shadow — 띄우지 않았다 · 띄우려면 --live)');
|
|
311
361
|
}
|
|
312
362
|
} catch (error) {
|
|
@@ -315,6 +365,37 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
315
365
|
}
|
|
316
366
|
});
|
|
317
367
|
|
|
368
|
+
tasks.command('board')
|
|
369
|
+
.description('보드 — 프로젝트 › 목표 › 이정표 › 과제. 과제 카드(project·goal·milestone)와 내부 팩(릴리스 체크리스트 = elanous › 판 › 칸)을 합쳐 읽는다(쓰지 않는다)')
|
|
370
|
+
.option('--project <id>', '이 프로젝트만')
|
|
371
|
+
.option('--json', 'JSON 출력')
|
|
372
|
+
.action(async (opts: { project?: string; json?: boolean }) => {
|
|
373
|
+
await registerTaskAgentSink(deps.registerSink);
|
|
374
|
+
try {
|
|
375
|
+
// 내부 팩은 elanous 프로젝트만 낸다 — 다른 프로젝트로 거르면 릴리스 원장을 열지 않는다(그 원장의 오류가 카드 보드를 막지 않게).
|
|
376
|
+
const wantsPack = opts.project === undefined || opts.project === INTERNAL_PACK_PROJECT;
|
|
377
|
+
const board = mergeBoards(
|
|
378
|
+
cardsBoard(deps.taskStatePath ?? taskStatePathDefault()),
|
|
379
|
+
wantsPack ? (deps.releaseBoard ?? (() => releasePackBoard(checklistDevVersion())))() : [],
|
|
380
|
+
);
|
|
381
|
+
// 무소속(unassigned: true)은 어떤 --project 로도 고르지 않는다 — 실제 프로젝트 id 와 겹치지 않게.
|
|
382
|
+
const selected = opts.project !== undefined ? board.filter((project) => project.unassigned !== true && project.id === opts.project) : board;
|
|
383
|
+
try { debug.log('task-agent', 'board', { projects: selected.length, tasks: countBoardTasks(selected), project: opts.project ?? null }); } catch { /* fail-soft */ }
|
|
384
|
+
if (opts.json) out(JSON.stringify(selected));
|
|
385
|
+
else {
|
|
386
|
+
const show = (node: BoardNode, depth: number): void => {
|
|
387
|
+
out(`${' '.repeat(depth)}${node.level}\t${node.id}\t${node.status}\t${headLine(node.title)}`);
|
|
388
|
+
for (const next of node.children ?? []) show(next, depth + 1);
|
|
389
|
+
};
|
|
390
|
+
if (selected.length === 0) out(opts.project !== undefined ? `프로젝트 없음: ${opts.project}` : '보드가 비어 있다');
|
|
391
|
+
for (const project of selected) show(project, 0);
|
|
392
|
+
}
|
|
393
|
+
} catch (error) {
|
|
394
|
+
out(error instanceof Error ? error.message : '보드 읽기 실패');
|
|
395
|
+
process.exitCode = 1;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
318
399
|
tasks.command('advance [missionId]')
|
|
319
400
|
.description('TASK-AGENT 미션 ② — 조각의 PR 병합(근거: `--pr`/`--goal` 로 카드에 적은 PR 번호·골 id)으로 착지를 가르고 새로 준비된 조각만 한 번 넘긴다 · 모두 착지면 green «제안»만 적는다 · 기본 shadow(발사 0)')
|
|
320
401
|
.option('--all', 'green 제안이 아직 없는 미션 전부')
|
|
@@ -366,6 +447,7 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
366
447
|
...(statePath ? { statePath } : {}),
|
|
367
448
|
launcher: deps.taskLauncher ?? defaultTaskLauncher,
|
|
368
449
|
...(deps.pieceEvidence ? { readEvidence: deps.pieceEvidence } : {}),
|
|
450
|
+
...(deps.cardRunEvidence ? { runEvidence: deps.cardRunEvidence } : {}),
|
|
369
451
|
}));
|
|
370
452
|
} catch (error) {
|
|
371
453
|
// 미션 id 하나면 그대로 실패 · --all 이면 그 미션만 실패로 적고 다음 미션으로 간다(크론이 한 미션에 막히지 않게).
|
|
@@ -405,7 +487,18 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
|
|
|
405
487
|
if (id.startsWith(TASK_CARD_PREFIX)) {
|
|
406
488
|
await registerTaskAgentSink(deps.registerSink);
|
|
407
489
|
let card: TaskCard | undefined;
|
|
408
|
-
try {
|
|
490
|
+
try {
|
|
491
|
+
card = readTaskCard(id, deps.taskStatePath);
|
|
492
|
+
// 런 id 가 있으면 원장에서 골 id · PR 을 묶는다(찾았을 때만 적는다 · 실패는 그대로 보인다).
|
|
493
|
+
const bindable = card?.pieces ? card.pieces : card ? [card.id] : [];
|
|
494
|
+
for (const cardId of bindable) {
|
|
495
|
+
try { await refreshCardRunBinding(cardId, deps.taskStatePath ?? taskStatePathDefault(), deps.cardRunEvidence ?? {}); } catch (error) {
|
|
496
|
+
// 근거 없음으로 보인다 — 원장 부재와 갈리게 실패는 남긴다.
|
|
497
|
+
try { debug.log('task-agent', 'card-bind-failed', { card: cardId, via: 'show', error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (card) card = readTaskCard(id, deps.taskStatePath);
|
|
501
|
+
} catch (error) {
|
|
409
502
|
out(error instanceof Error ? error.message : '과제 카드 읽기 실패');
|
|
410
503
|
process.exitCode = 1;
|
|
411
504
|
return;
|
|
@@ -72,7 +72,7 @@ export function filterPublicDemoContext(answer: ContextNowAnswer, brandCheck: ty
|
|
|
72
72
|
id: fact.id ? (rulesMissing || privateIds.has(fact.id) ? '내부 항목' : safe(fact.id, '공개 항목')) : null,
|
|
73
73
|
title: fact.title === null ? null : rulesMissing ? internalItem(1) : privateIds.has(fact.id ?? '') ? '내부 항목' : safe(fact.title, '공개 항목'),
|
|
74
74
|
source: source(fact.source) });
|
|
75
|
-
} else facts.push({ ...fact, version: safe(fact.version, '공개 판'), source: source(fact.source) });
|
|
75
|
+
} else if (fact.kind === 'version') facts.push({ ...fact, version: safe(fact.version, '공개 판'), source: source(fact.source) });
|
|
76
76
|
}
|
|
77
77
|
for (const kind of ['cell', 'decision'] as const) {
|
|
78
78
|
if (!collapsed[kind]) continue;
|
|
@@ -34,6 +34,9 @@ function factText(fact: ContextFact): string {
|
|
|
34
34
|
case 'cell': return `${fact.id} ${fact.title} (${fact.status})`;
|
|
35
35
|
case 'decision': return `${fact.id} ${fact.title} (${fact.status})`;
|
|
36
36
|
case 'seat': return `${fact.seat} ${fact.id ?? ''} ${fact.title ?? ''} (${fact.status})`.trim();
|
|
37
|
+
case 'run': return fact.unreadable ? `못 읽음 · ${fact.unreadable}` : `${fact.goal} · ${fact.phase} · ${fact.elapsed}`;
|
|
38
|
+
case 'release': return fact.unreadable ? `못 읽음 · ${fact.unreadable}` : `${fact.version} · ${fact.node} · ${fact.status}`;
|
|
39
|
+
case 'schedule-late': return fact.unreadable ? `못 읽음 · ${fact.unreadable}` : `${fact.count}개 · ${fact.names.join(', ') || '없음'}`;
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -61,20 +64,27 @@ export function renderTuiNow(input: ContextNowAnswer, audience: ContextNowAudien
|
|
|
61
64
|
if (source.startsWith('elanous://release/')) return '원장';
|
|
62
65
|
return Array.from(source).slice(0, 40).join('');
|
|
63
66
|
};
|
|
64
|
-
const factLabels = { version: '판', cell: '칸', decision: '결정', seat: '자리' } as const;
|
|
67
|
+
const factLabels = { run: '도는 런', release: '발행 런', 'schedule-late': '지연 스케줄', version: '판', cell: '칸', decision: '결정', seat: '자리' } as const;
|
|
65
68
|
const eventLabels: Record<string, string> = { report: '보고', dispatch: '발사', decision: '결정' };
|
|
66
69
|
const events = answer.events.slice().sort((a, b) => Date.parse(b.at) - Date.parse(a.at));
|
|
67
70
|
const rows = [
|
|
68
|
-
...answer.facts.
|
|
71
|
+
...answer.facts.slice().sort((a, b) => {
|
|
72
|
+
const priority = (kind: ContextFact['kind']) => ({ run: 0, release: 1, 'schedule-late': 2 } as Partial<Record<ContextFact['kind'], number>>)[kind] ?? 3;
|
|
73
|
+
return priority(a.kind) - priority(b.kind);
|
|
74
|
+
}).map(f => [factLabels[f.kind], shortText(factText(f)), shortSource(f.source)]),
|
|
69
75
|
...events.slice(0, 8).map(e => [eventLabels[e.kind] ?? '소식', shortText(e.summary), shortSource(e.source)]),
|
|
70
76
|
...answer.guide.map(guide => ['안내', guide, '']),
|
|
71
77
|
...(events.length > 8 ? [['안내', `… 사건 ${events.length - 8}개 더(/now <주제> 로 좁히기)`, '']] : []),
|
|
72
78
|
];
|
|
79
|
+
const clean = (text: string) => text.replaceAll('|', ' ').replaceAll(/\r?\n/g, ' ');
|
|
80
|
+
const width = (text: string) => Array.from(text).reduce((total, char) => total + (/[\u1100-\u115f\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe10-\ufe6f\uff01-\uff60\uffe0-\uffe6]/u.test(char) ? 2 : 1), 0);
|
|
81
|
+
const data = [['종류', '사실', '출처'], ...rows].map(row => row.map(clean));
|
|
82
|
+
const widths = [0, 1].map(i => Math.max(...data.map(row => width(row[i] ?? ''))));
|
|
83
|
+
const format = (row: string[]) => `${row[0]}${' '.repeat(widths[0]! - width(row[0]!) + 2)}${row[1]}${' '.repeat(widths[1]! - width(row[1]!) + 2)}${row[2]}`;
|
|
84
|
+
const time = new Intl.DateTimeFormat('en-GB', { timeZone: 'Asia/Seoul', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }).format(new Date(answer.at));
|
|
73
85
|
return [
|
|
74
|
-
`지금${answer.topic ? ` · ${answer.topic}` : ''} (${
|
|
75
|
-
|
|
76
|
-
'| --- | --- | --- |',
|
|
77
|
-
...rows.map(row => `| ${row.map(cell => cell.replaceAll('|', '\\|').replaceAll(/\r?\n/g, ' ')).join(' | ')} |`),
|
|
86
|
+
`지금${answer.topic ? ` · ${answer.topic}` : ''} (${time} KST)`,
|
|
87
|
+
...data.map(format),
|
|
78
88
|
];
|
|
79
89
|
}
|
|
80
90
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { queryRunningRuns, type QueriedRunningRunsResult } from '../self-implement/running-runs.js';
|
|
4
|
+
import { loadRunLedger } from '../self-implement/run-ledger.js';
|
|
5
|
+
import { localLoopRows } from '../dashboard/slash-runtime/loops-table.js';
|
|
2
6
|
import { checkBrand } from '../../scripts/brand/check.js';
|
|
3
7
|
import { debug, redactSecretText } from '../debug/log.js';
|
|
4
8
|
import { DecisionLedger, type DecisionEntry } from '../decisions/decision-ledger.js';
|
|
@@ -12,7 +16,10 @@ export type ContextFact =
|
|
|
12
16
|
| { kind: 'version'; version: string; source: string }
|
|
13
17
|
| { kind: 'cell'; version: string; id: string; title: string; status: string; owner: string | null; source: string }
|
|
14
18
|
| { kind: 'decision'; id: string; title: string; status: string; dueAt: string | null; source: string }
|
|
15
|
-
| { kind: 'seat'; seat: string; at: string; status: string; id: string | null; title: string | null; source: string }
|
|
19
|
+
| { kind: 'seat'; seat: string; at: string; status: string; id: string | null; title: string | null; source: string }
|
|
20
|
+
| { kind: 'run'; goal: string; phase: string; elapsed: string; source: string; unreadable?: string }
|
|
21
|
+
| { kind: 'release'; version: string; node: string; status: string; source: string; unreadable?: string }
|
|
22
|
+
| { kind: 'schedule-late'; count: number | null; names: string[]; source: string; unreadable?: string };
|
|
16
23
|
export type ContextEvent = { at: string; kind: string; summary: string; source: string };
|
|
17
24
|
export type ContextNowAnswer = { at: string; topic: string | null; facts: ContextFact[]; events: ContextEvent[]; guide: string[]; hiddenCount?: number };
|
|
18
25
|
|
|
@@ -23,6 +30,10 @@ export interface ContextNowDeps {
|
|
|
23
30
|
decisions?: () => DecisionEntry[];
|
|
24
31
|
seatEntries?: (now: Date) => Array<{ entry: SeatEntry; source: string }>;
|
|
25
32
|
events?: (since: string) => CoordEvent[];
|
|
33
|
+
runningRuns?: (now: Date) => Extract<ContextFact, { kind: 'run' }>[];
|
|
34
|
+
queryRuns?: () => QueriedRunningRunsResult;
|
|
35
|
+
releaseRun?: () => Extract<ContextFact, { kind: 'release' }> | null;
|
|
36
|
+
lateSchedules?: (now: Date) => Extract<ContextFact, { kind: 'schedule-late' }> | null;
|
|
26
37
|
brandCheck?: typeof checkBrand;
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -39,6 +50,75 @@ function todaySeatEntries(now: Date): Array<{ entry: SeatEntry; source: string }
|
|
|
39
50
|
});
|
|
40
51
|
}
|
|
41
52
|
|
|
53
|
+
const runSource = 'elanous://self-implement/running-runs';
|
|
54
|
+
const releaseSource = 'elanous://graph-runs/release-loop';
|
|
55
|
+
const scheduleSource = 'elanous://schedules';
|
|
56
|
+
const oneLine = (text: string) => redactSecretText(text.split(/\r?\n/, 1)[0] ?? '').slice(0, 120);
|
|
57
|
+
|
|
58
|
+
function runningRunFacts(now: Date, queryRuns: () => QueriedRunningRunsResult = () => queryRunningRuns({ includeTest: false, caller: 'context-now' })): Extract<ContextFact, { kind: 'run' }>[] {
|
|
59
|
+
const observed = queryRuns();
|
|
60
|
+
const unreadable = observed.completeness === 'partial' || observed.pty.unreadable.length || !!observed.phases?.unreadableTargetCount;
|
|
61
|
+
const facts = observed.entries.filter(entry => observed.countedStatuses.includes(entry.status)).slice(0, 8).flatMap(entry => {
|
|
62
|
+
let ledgerReadFailure = false;
|
|
63
|
+
const starts = entry.ledgerDirectories.flatMap(directory => {
|
|
64
|
+
try { return loadRunLedger(entry.runId, directory)?.filter(record => record.event === 'start') ?? []; }
|
|
65
|
+
catch { ledgerReadFailure = true; return []; }
|
|
66
|
+
});
|
|
67
|
+
const goalRecord = starts.find(record => typeof record.data.feature === 'string' && record.data.feature.trim());
|
|
68
|
+
const goal = typeof goalRecord?.data.feature === 'string' ? goalRecord.data.feature : ledgerReadFailure ? '골 관측 불가' : '골 미기록';
|
|
69
|
+
const started = starts.map(record => record.timestamp ? Date.parse(record.timestamp) : NaN).find(Number.isFinite) ?? NaN;
|
|
70
|
+
const minutes = Number.isFinite(started)
|
|
71
|
+
? Math.max(0, Math.floor((now.getTime() - started) / 60_000)) : null;
|
|
72
|
+
const fact = { kind: 'run' as const, goal: oneLine(goal),
|
|
73
|
+
phase: entry.lastPhase ?? '단계 미관측', elapsed: minutes === null ? ledgerReadFailure ? '경과 관측 불가' : '경과 미관측' : `${minutes}분`,
|
|
74
|
+
source: `${runSource}/${encodeURIComponent(entry.runId)}` };
|
|
75
|
+
return ledgerReadFailure
|
|
76
|
+
? [
|
|
77
|
+
...(goalRecord || minutes !== null ? [fact] : []),
|
|
78
|
+
{ kind: 'run' as const, goal: '', phase: '', elapsed: '', source: fact.source, unreadable: '런 원장 일부 관측 불가' },
|
|
79
|
+
] : [fact];
|
|
80
|
+
});
|
|
81
|
+
return unreadable ? [...facts, { kind: 'run', goal: '', phase: '', elapsed: '', source: runSource, unreadable: '런 원장 또는 관측 대상 일부' }] : facts;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function latestReleaseRun(): Extract<ContextFact, { kind: 'release' }> | null {
|
|
85
|
+
const dir = join(effectiveInstanceRoot(), 'graph-runs', 'release-loop');
|
|
86
|
+
let filenames: string[];
|
|
87
|
+
try { filenames = readdirSync(dir).filter(name => /^[A-Za-z0-9-]+\.json$/.test(name)); }
|
|
88
|
+
catch (error) {
|
|
89
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
const runs = filenames.flatMap(filename => {
|
|
93
|
+
const path = join(dir, filename);
|
|
94
|
+
let run: { startedAt?: unknown; status?: unknown; input?: { version?: unknown }; path?: unknown; nodes?: unknown };
|
|
95
|
+
try {
|
|
96
|
+
if (!lstatSync(path).isFile()) return [];
|
|
97
|
+
run = JSON.parse(readFileSync(path, 'utf8'));
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT' || error instanceof SyntaxError) return [];
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
if (typeof run.startedAt !== 'string' || typeof run.status !== 'string' || !Array.isArray(run.path) || !Array.isArray(run.nodes)) return [];
|
|
103
|
+
const steps = run.path.filter((step): step is string => typeof step === 'string');
|
|
104
|
+
const nodes = run.nodes.filter((node): node is { nodeId: string } => !!node && typeof node.nodeId === 'string');
|
|
105
|
+
const version = typeof run.input?.version === 'string' && /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/.test(run.input.version) ? run.input.version : '판 미기록';
|
|
106
|
+
const index = Math.min(steps.length, nodes.length + (run.status === 'running' || run.status === 'awaiting-approval' ? 1 : 0));
|
|
107
|
+
return [{ startedAt: run.startedAt, fact: { kind: 'release' as const, version, node: `${index}/${steps.length}${steps[index - 1] ? ` ${oneLine(steps[index - 1]!)}` : ''}`,
|
|
108
|
+
status: oneLine(run.status), source: `${releaseSource}/${encodeURIComponent(filename.slice(0, -5))}` } }];
|
|
109
|
+
});
|
|
110
|
+
return runs.sort((a, b) => b.startedAt.localeCompare(a.startedAt))[0]?.fact ?? null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function lateScheduleFact(now: Date): Extract<ContextFact, { kind: 'schedule-late' }> {
|
|
114
|
+
const names = localLoopRows(now).filter(row => row.verdict === 'late').map(row => oneLine(row.name));
|
|
115
|
+
return { kind: 'schedule-late', count: names.length, names, source: scheduleSource };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function unreadableReason(error: unknown): string {
|
|
119
|
+
return oneLine(error instanceof Error ? error.message : String(error)) || '원천 조회 실패';
|
|
120
|
+
}
|
|
121
|
+
|
|
42
122
|
/** Read a bounded, source-labelled view of current ledgers, never a transcript or decision body. */
|
|
43
123
|
export function contextNow(options: { topic?: string; limit?: number; audience?: 'operator' | 'user' | 'public-demo' } = {}, deps: ContextNowDeps = {}): ContextNowAnswer {
|
|
44
124
|
const now = (deps.now ?? (() => new Date()))();
|
|
@@ -71,6 +151,20 @@ export function contextNow(options: { topic?: string; limit?: number; audience?:
|
|
|
71
151
|
const rawEvents = (deps.events ?? (since => listCoordEvents({ since })))(new Date(now.getTime() - 7 * 86_400_000).toISOString());
|
|
72
152
|
const chronologicalEvents = rawEvents.slice().sort((a, b) => a.at.localeCompare(b.at));
|
|
73
153
|
const matches = (text: string) => !topic || text.toLocaleLowerCase().includes(topic.toLocaleLowerCase());
|
|
154
|
+
const operational: ContextFact[] = [];
|
|
155
|
+
if (options.audience !== 'public-demo') {
|
|
156
|
+
try { operational.push(...(deps.runningRuns ?? (date => runningRunFacts(date, deps.queryRuns)))(now)); }
|
|
157
|
+
catch (error) { operational.push({ kind: 'run', goal: '', phase: '', elapsed: '', source: runSource, unreadable: unreadableReason(error) }); }
|
|
158
|
+
try {
|
|
159
|
+
const release = (deps.releaseRun ?? latestReleaseRun)();
|
|
160
|
+
if (release) operational.push(release);
|
|
161
|
+
} catch (error) { operational.push({ kind: 'release', version: '', node: '', status: '', source: releaseSource, unreadable: unreadableReason(error) }); }
|
|
162
|
+
try { const schedules = (deps.lateSchedules ?? lateScheduleFact)(now); if (schedules) operational.push(schedules); }
|
|
163
|
+
catch (error) { operational.push({ kind: 'schedule-late', count: null, names: [], source: scheduleSource, unreadable: unreadableReason(error) }); }
|
|
164
|
+
}
|
|
165
|
+
const selectedOperational = operational.filter(f => !topic || ('unreadable' in f && !!f.unreadable) || (f.kind === 'run' && matches(`${f.goal} ${f.phase}`))
|
|
166
|
+
|| (f.kind === 'release' && matches(`${f.version} ${f.node} ${f.status}`))
|
|
167
|
+
|| (f.kind === 'schedule-late' && matches(f.names.join(' '))));
|
|
74
168
|
const selectedFacts = facts.filter(f => !topic || (f.kind === 'cell' && matches(`${f.id} ${f.title}`))
|
|
75
169
|
|| (f.kind === 'seat' && matches(`${f.id ?? ''} ${f.title ?? ''}`)));
|
|
76
170
|
const groups = (['version', 'cell', 'decision', 'seat'] as const).map(kind => selectedFacts.filter(f => f.kind === kind));
|
|
@@ -92,7 +186,7 @@ export function contextNow(options: { topic?: string; limit?: number; audience?:
|
|
|
92
186
|
chosen[index]!.push(...extra);
|
|
93
187
|
remaining -= extra.length;
|
|
94
188
|
}
|
|
95
|
-
const boundedFacts = chosen.flat();
|
|
189
|
+
const boundedFacts = [...selectedOperational.slice(0, limit), ...chosen.flat()];
|
|
96
190
|
const summaries = chronologicalEvents.map(event => ({
|
|
97
191
|
at: event.at, kind: event.kind, summary: redactSecretText(event.summary.split(/\r?\n/, 1)[0] ?? '').slice(0, 120),
|
|
98
192
|
source: event.refs.source ?? event.refs.url ?? `elanous://context/event/${encodeURIComponent(event.id)}`,
|