elanous 0.2.25 → 0.2.28
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/chunks/{1454-37fd16f479f5554a.js → 1454-29d1d773d5996a49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{599-a914cc0468f56143.js → 599-56f2c0a5cc4a7295.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-b12149c51f7d04b1.js → page-fa46d4588e8442c2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/{page-305cd294e754906e.js → page-256ffd365d32e100.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-dea4b795741126fd.js → page-e0de78ae7b99f01c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-45889e7070d11126.js → page-4c741eb760f2f77c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-16a2e893f83ae4d0.js → page-e9ba98f5f1440a21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-56888bc744e08dac.js → page-2f6f303fa114ec24.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-952c6ceec6d9de38.js → page-ced0bcfc6542b3fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-6d0202af568f4c63.js → page-bb1f05cd51c38944.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-4fb6fc34e20c07b7.js → page-f736324afa2117c1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-e9502921f4f01b1f.js → page-6f131b51193a36f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-b6169ea2f09cf287.js → not-found-435f5e2faf02bc01.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/{page-6a14333d1b1b3967.js → page-497e0eedf20e7890.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-8c91a9a66c9ec90a.js → page-a8d28fdf995e16ea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/{page-3d3fc73dd187ed52.js → page-66a67eb19ebd976b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-9c04dac0831c2bbb.js → page-c71267e7681da982.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-04de9ca6d52a3893.js → page-cb249e81ed339318.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-62527677bbc2fdc4.js → page-781cfc5114e097da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-9a2e09c4a311764c.js → page-478157214db6a023.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-bfeb35d69e8b24bb.js → page-86141f12cf090b7f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-89cb33bced824e4a.js → page-7256c73bb1c36751.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/{page-6445ac4cbb8dd869.js → page-979d318a534e92da.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-20162174b77f96cf.js → page-601fb77340e63c9a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/{page-05a4b2c9b91034aa.js → page-11bf9e5725a72c22.js} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +13 -13
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +13 -13
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +13 -13
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +13 -13
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +13 -13
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +13 -13
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +13 -13
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +13 -13
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +13 -13
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +13 -13
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +13 -13
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +13 -13
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +13 -13
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +13 -13
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +13 -13
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +13 -13
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +13 -13
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +13 -13
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +13 -13
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +13 -13
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +13 -13
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +13 -13
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +13 -13
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +13 -13
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +13 -13
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +13 -13
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +13 -13
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +13 -13
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +14 -14
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +13 -13
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +13 -13
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +13 -13
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +13 -13
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +13 -13
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +13 -13
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +13 -13
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +13 -13
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +13 -13
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +13 -13
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +13 -13
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +13 -13
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +13 -13
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +13 -13
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +13 -13
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +13 -13
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +13 -13
- package/graphs/implement-loop.yaml +38 -1
- package/graphs/steward/recipes.yaml +6 -0
- package/graphs/steward/release-day.yaml +23 -0
- package/graphs/steward/steward.yaml +9 -1
- package/graphs/work/code-pr.yaml +23 -0
- package/package.json +1 -1
- package/scripts/browser-observe-cycle.ts +76 -2
- package/scripts/ci-typecheck-changed.ts +119 -7
- package/scripts/coord-msg-bridge.ts +209 -0
- package/scripts/coord-post.sh +40 -7
- package/scripts/coord-requests-bridge.ts +10 -5
- package/scripts/detect-test-interference.ts +31 -1
- package/scripts/expose-rubric-suggest.ts +1 -1
- package/scripts/measure-tsc-affected-roots.ts +10 -1
- package/scripts/release-loop/docs-node.ts +51 -22
- package/scripts/release-loop/export-check-node.ts +8 -5
- package/scripts/release-loop/gate-node.ts +37 -4
- package/scripts/release-loop/node-verdict.ts +10 -3
- package/scripts/release-loop/publish-node.ts +3 -0
- package/scripts/release-loop/tui-node-checks.ts +5 -2
- package/scripts/skills/public-check.ts +5 -2
- package/scripts/test-deterministic.ts +520 -37
- package/scripts/ux-sim.ts +7 -1
- package/scripts/verify-kpack6-live.ts +230 -0
- package/src/acp/codex-plugins.ts +17 -0
- package/src/agent/task-notification.ts +32 -2
- package/src/agent-mission/in-agent-plugin.ts +8 -3
- package/src/agent-substrate/review-observation.ts +9 -2
- package/src/agent-substrate/self-review-cli.ts +62 -16
- package/src/boot/daemon-tools/self-implement.ts +72 -4
- package/src/briefing/brief-items.ts +151 -35
- package/src/budget/llm-cost.ts +30 -3
- package/src/budget/usage-outcomes.ts +32 -0
- package/src/claims/claims-ledger.ts +23 -0
- package/src/claims/claims-render.ts +22 -2
- package/src/cli/brief-cli.ts +131 -10
- package/src/cli/claims-cli.ts +24 -4
- package/src/cli/control-cli.ts +29 -0
- package/src/cli/doctor-cli.ts +90 -8
- package/src/cli/msg-cli.ts +177 -11
- package/src/cli/plugin-cli.ts +11 -3
- package/src/cli/pr-cli.ts +133 -18
- package/src/cli/pr-land-overlap-evidence.ts +18 -10
- package/src/cli/pr-land-refusal.ts +20 -0
- package/src/cli/release-cli.ts +34 -5
- package/src/cli/rfc-cli.ts +24 -0
- package/src/cli/seat-cli.ts +121 -0
- package/src/cli/self-utterances-cli.ts +140 -0
- package/src/cli/tailscale-serve.ts +5 -8
- package/src/cli/tasks-cli.ts +528 -31
- package/src/cli/usage-cli.ts +9 -4
- package/src/context-card/cell.ts +40 -0
- package/src/dashboard/boot-timing.ts +35 -0
- package/src/dashboard/first-screen-band.ts +63 -13
- package/src/dashboard/index.ts +94 -27
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +26 -0
- package/src/dashboard/skill-detection-runtime.ts +24 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +6 -0
- package/src/debug/log.ts +1 -1
- package/src/domains/morning-report.ts +3 -1
- package/src/domains/release-tool.ts +29 -12
- package/src/domains/surface-events.ts +16 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/fleet/host-doctor.ts +73 -2
- package/src/github/pr-labels.ts +10 -4
- package/src/graph-runner/runner.ts +104 -15
- package/src/harness/harness-clean.ts +21 -3
- package/src/harness/harness-cli-command.ts +68 -10
- package/src/harness/harness-pod-dispatch.ts +11 -4
- package/src/harness/harness-stop.ts +11 -7
- package/src/hq/seats.ts +17 -3
- package/src/index.ts +69 -9
- package/src/instance/current.ts +2 -6
- package/src/instance/resolve.ts +5 -6
- package/src/intelligence-map/model-bench-scores.ts +102 -0
- package/src/llm/openai-sampling-fields.ts +89 -0
- package/src/llm/runtime-model-family.ts +61 -0
- package/src/llm/zai-coding-plan.ts +27 -1
- package/src/llm.ts +13 -89
- package/src/loops/orchestrator/inbox.ts +73 -0
- package/src/loops/orchestrator/resync-shadow.ts +100 -12
- package/src/loops/orchestrator/tick.ts +73 -2
- package/src/machines/machine-ledger.ts +31 -3
- package/src/maturity/cli-maturity.ts +13 -3
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/msg/msg-sse-server.ts +141 -0
- package/src/msg/msg-store.ts +149 -17
- package/src/ops/overview-collect.ts +3 -2
- package/src/ops/overview-owner.ts +29 -0
- package/src/patents/ledger.ts +128 -0
- package/src/plugin-hooks/shell-hook.ts +17 -2
- package/src/plugin-missions/evaluator-runner.ts +18 -2
- package/src/plugins/install/market-fetch.ts +32 -1
- package/src/plugins/install/plugin-install.ts +11 -1
- package/src/pod-lease/admission.ts +116 -41
- package/src/prompt-enhance/enhance.ts +11 -0
- package/src/release-loop/checklist.ts +52 -4
- package/src/release-loop/feature-store.ts +10 -9
- package/src/release-loop/merged-pr-checklist.ts +24 -5
- package/src/release-loop/rubric.ts +70 -0
- package/src/rfc-registry/registry.ts +88 -0
- package/src/seat-dispatch/seat-request-ledger.ts +4 -0
- package/src/seat-loop/knowhow-lint.ts +233 -0
- package/src/seat-loop/seat-loop.ts +5 -1
- package/src/seat-loop/seat-pack.ts +16 -4
- package/src/seat-loop/traffic-signal.ts +7 -0
- package/src/self-dev/ask-launch-flow.ts +48 -8
- package/src/self-dev/ask-path-candidates.ts +69 -14
- package/src/self-dev/decompose-proposal.ts +43 -1
- package/src/self-dev/draft-sweep.ts +23 -14
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/launch-preflight-text.ts +5 -1
- package/src/self-dev/launch-preflight.ts +143 -10
- package/src/self-dev/orchestrate.ts +6 -2
- package/src/self-dev/run-supervisor.ts +35 -1
- package/src/self-implement/gate-cli.ts +6 -2
- package/src/self-implement/goal-author.ts +5 -28
- package/src/self-implement/goal-command-execution.ts +26 -0
- package/src/self-implement/goal-new-paths.ts +4 -5
- package/src/self-implement/graph-authority.ts +17 -3
- package/src/self-implement/graph-yaml.ts +15 -7
- package/src/self-implement/headless-elanous-driver.ts +16 -1
- package/src/self-implement/host-regate.ts +44 -9
- package/src/self-implement/orchestrator.ts +5 -11
- package/src/self-implement/pwa-import-graph.ts +194 -7
- package/src/self-implement/rework-policy.ts +80 -2
- package/src/self-implement/self-implement-runtime.ts +126 -21
- package/src/self-implement/speed-claims.ts +145 -6
- package/src/session/index.ts +14 -4
- package/src/session-runtime/index.ts +55 -11
- package/src/skills/tools/persistent-grounding.ts +59 -4
- package/src/skills/tools/shell.ts +79 -1
- package/src/steward/rejudge-tick.ts +12 -1
- package/src/steward/release-day.ts +158 -0
- package/src/steward/resync-tick.ts +123 -0
- package/src/task-agent/actions.ts +1 -0
- package/src/task-agent/adopt-pr.ts +140 -0
- package/src/task-agent/board.ts +11 -1
- package/src/task-agent/card-evidence.ts +37 -5
- package/src/task-agent/cover.ts +105 -19
- package/src/task-agent/failure-notify.ts +61 -0
- package/src/task-agent/green-sweep.ts +170 -0
- package/src/task-agent/land-worktree.ts +52 -5
- package/src/task-agent/live-move-history.ts +1 -0
- package/src/task-agent/live-moves.ts +56 -17
- package/src/task-agent/parent-host.ts +1 -1
- package/src/task-agent/postland-card.ts +139 -0
- package/src/task-agent/rejudge-on-head.ts +321 -25
- package/src/task-agent/remote-rejudge-bind.ts +62 -0
- package/src/task-agent/repair-branch-cas.ts +182 -0
- package/src/task-agent/repair-cycle.ts +275 -0
- package/src/task-agent/repair-next-move.ts +31 -0
- package/src/task-agent/repair-review.ts +24 -0
- package/src/task-agent/repair-worker.ts +87 -0
- package/src/task-agent/review-result-capture.ts +66 -2
- package/src/task-agent/shadow.ts +150 -29
- package/src/task-agent/task-hand.ts +133 -8
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +96 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +71 -12
- package/src/telegram.ts +30 -1
- package/src/tool-runtime/tool-search-runtime.ts +25 -0
- package/src/tui.ts +20 -1
- package/src/user-config.ts +11 -60
- package/src/ux-sim/fault-sqlite-busy.ts +50 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4e634c5b98fd4e93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b9cc8a10bc6078b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +0 -1
- /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_ssgManifest.js +0 -0
package/src/cli/brief-cli.ts
CHANGED
|
@@ -1,9 +1,97 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { BRIEF_DOMAINS, BRIEF_PRIORITIES, BRIEF_REACTIONS, BRIEF_SLOTS, BriefItemsInputError, BriefItemsLedger, type BriefDomain, type BriefPriority, type BriefReaction, type BriefSendSlot } from '../briefing/brief-items.js';
|
|
3
3
|
import { kindRouteTarget } from '../domains/telegram-kind-route.js';
|
|
4
|
-
import {
|
|
4
|
+
import { sendTelegramButtonsTo, type TgButton } from '../autopilot/mission-notify.js';
|
|
5
5
|
import { getUserConfig } from '../user-config.js';
|
|
6
6
|
|
|
7
|
+
export function briefFeedbackButtons(ids: readonly number[]): TgButton[][] {
|
|
8
|
+
return ids.map(id => [
|
|
9
|
+
{ text: `👀 ${id} 읽음`, data: `brief-item:${id}:read` },
|
|
10
|
+
{ text: `✅ ${id} 움직임`, data: `brief-item:${id}:button` },
|
|
11
|
+
{ text: `➖ ${id} 넘김`, data: `brief-item:${id}:ignore` },
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BriefTelegramUpdate {
|
|
16
|
+
botId: string;
|
|
17
|
+
chatId: number;
|
|
18
|
+
messageId: number;
|
|
19
|
+
updateId: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
callbackData?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function recordBriefTelegramUpdate(ledger: BriefItemsLedger, update: BriefTelegramUpdate): boolean {
|
|
25
|
+
if (update.callbackData !== undefined) {
|
|
26
|
+
const match = /^brief-item:([1-9]\d*):(read|button|ignore)$/.exec(update.callbackData);
|
|
27
|
+
if (!match) return false;
|
|
28
|
+
return ledger.recordTelegramFeedback({ botId: update.botId, chatId: update.chatId,
|
|
29
|
+
messageId: update.messageId, updateId: update.updateId, itemId: Number(match[1]),
|
|
30
|
+
reaction: match[2] === 'read' ? '열람' : match[2] === 'ignore' ? '무시' : '버튼' });
|
|
31
|
+
}
|
|
32
|
+
if (!update.text?.trim()) return false;
|
|
33
|
+
const text = update.text.trim();
|
|
34
|
+
const itemId = /^(?:#|항목\s*)([1-9]\d*)(?=\s|[::]|$)/.exec(text)?.[1];
|
|
35
|
+
return ledger.recordTelegramFeedback({ botId: update.botId, chatId: update.chatId,
|
|
36
|
+
messageId: update.messageId, updateId: update.updateId,
|
|
37
|
+
...(itemId ? { itemId: Number(itemId) } : {}),
|
|
38
|
+
reaction: /그게 아니라|(?:^|\s)정정\s*[::]/.test(text) ? '정정' : '답장' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Prefix each item line with `#<id>` so the 대표 can name the reply target ("#12 답장", "#12 그게 아니라 …"). */
|
|
42
|
+
function withItemNumbers(text: string, itemLines: ReadonlyMap<string, readonly number[]>): string {
|
|
43
|
+
const linePositions = new Map<string, number>();
|
|
44
|
+
return text.split('\n').map(line => {
|
|
45
|
+
const ids = itemLines.get(line);
|
|
46
|
+
if (!ids) return line;
|
|
47
|
+
const position = linePositions.get(line) ?? 0;
|
|
48
|
+
linePositions.set(line, position + 1);
|
|
49
|
+
const itemId = ids[position];
|
|
50
|
+
return itemId === undefined ? line : `#${itemId} ${line}`;
|
|
51
|
+
}).join('\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Split only feedback-enabled pages; each Telegram message gets its own real item coordinate.
|
|
55
|
+
* Item lines carry their `#<id>` so a plain text reply can name its target item.
|
|
56
|
+
*/
|
|
57
|
+
function briefDeliveryParts(markdown: string, itemLines: ReadonlyMap<string, readonly number[]>): Array<{ text: string; itemId: number }> {
|
|
58
|
+
const parts: Array<{ text: string; itemId: number }> = [];
|
|
59
|
+
const linePositions = new Map<string, number>();
|
|
60
|
+
let pending = '';
|
|
61
|
+
for (const line of markdown.trimEnd().split('\n')) {
|
|
62
|
+
const ids = itemLines.get(line);
|
|
63
|
+
const position = linePositions.get(line) ?? 0;
|
|
64
|
+
const itemId = ids?.[position];
|
|
65
|
+
if (itemId === undefined) {
|
|
66
|
+
pending += `${line}\n`;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
linePositions.set(line, position + 1);
|
|
70
|
+
const numbered = `#${itemId} ${line}`;
|
|
71
|
+
// Leave room for the Telegram sender's newline and keep a button on every fragment.
|
|
72
|
+
while (pending.length >= 3800) {
|
|
73
|
+
parts.push({ text: pending.slice(0, 3800), itemId });
|
|
74
|
+
pending = pending.slice(3800);
|
|
75
|
+
}
|
|
76
|
+
let remainder = pending + numbered;
|
|
77
|
+
do {
|
|
78
|
+
parts.push({ text: remainder.slice(0, 3800), itemId });
|
|
79
|
+
remainder = remainder.slice(3800);
|
|
80
|
+
} while (remainder.length);
|
|
81
|
+
pending = '';
|
|
82
|
+
}
|
|
83
|
+
if (pending && parts.length) {
|
|
84
|
+
const last = parts[parts.length - 1]!;
|
|
85
|
+
if (last.text.length + pending.length <= 3800) last.text += pending;
|
|
86
|
+
else {
|
|
87
|
+
const room = 3800 - last.text.length;
|
|
88
|
+
last.text += pending.slice(0, room);
|
|
89
|
+
for (let i = room; i < pending.length; i += 3800) parts.push({ text: pending.slice(i, i + 3800), itemId: last.itemId });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return parts;
|
|
93
|
+
}
|
|
94
|
+
|
|
7
95
|
export interface BriefCliDeps {
|
|
8
96
|
ledger?: BriefItemsLedger;
|
|
9
97
|
stateDir?: string;
|
|
@@ -11,6 +99,10 @@ export interface BriefCliDeps {
|
|
|
11
99
|
output?: (line: string) => void;
|
|
12
100
|
error?: (line: string) => void;
|
|
13
101
|
send?: (markdown: string) => number | null;
|
|
102
|
+
/** Test seam for the Telegram button sender (one actual message per invocation). */
|
|
103
|
+
sendWithButtons?: (text: string, buttons: TgButton[][]) => number | null;
|
|
104
|
+
/** Allows an injected sender to exercise the same Telegram attribution as the real sender. */
|
|
105
|
+
telegramTarget?: { botToken: string; chatId: number };
|
|
14
106
|
}
|
|
15
107
|
|
|
16
108
|
export function registerBriefCommands(program: Command, deps: BriefCliDeps = {}): void {
|
|
@@ -31,18 +123,47 @@ export function registerBriefCommands(program: Command, deps: BriefCliDeps = {})
|
|
|
31
123
|
output(`이번 주 브리핑 중 대표가 움직인 것 ${acted}/${total}`);
|
|
32
124
|
} catch (cause) { fail('', cause); }
|
|
33
125
|
});
|
|
34
|
-
const deliver = (slot: BriefSendSlot): string => ledger().withSendLock(slot, ({ markdown, ids }, markSent) => {
|
|
126
|
+
const deliver = (slot: BriefSendSlot): string => ledger().withSendLock(slot, ({ markdown, ids, itemLines }, markSent) => {
|
|
35
127
|
if (ids.length === 0) return '(보낼 항목 없음)';
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
128
|
+
const target = deps.telegramTarget ?? (deps.send ? null : kindRouteTarget(getUserConfig(), 'ops-report'));
|
|
129
|
+
const numberedMarkdown = withItemNumbers(markdown, itemLines);
|
|
130
|
+
const oneMessage = numberedMarkdown.length + numberedMarkdown.split('\n').length <= 3900 && ids.length <= 30;
|
|
131
|
+
const send = (text: string, itemIds: readonly number[]) => deps.sendWithButtons
|
|
132
|
+
? deps.sendWithButtons(text, briefFeedbackButtons(itemIds))
|
|
133
|
+
: deps.send ? deps.send(text)
|
|
134
|
+
: target ? sendTelegramButtonsTo(target.botToken, target.chatId, text, briefFeedbackButtons(itemIds)) : null;
|
|
135
|
+
const botId = target ? target.botToken.split(':')[0]! : '';
|
|
136
|
+
if (target && !oneMessage) {
|
|
137
|
+
// A sent fragment is not a completed item. Persist only items whose every fragment
|
|
138
|
+
// succeeded; an incomplete item must remain available to the next send.
|
|
139
|
+
const parts = briefDeliveryParts(markdown, itemLines);
|
|
140
|
+
const remainingParts = new Map<number, number>();
|
|
141
|
+
for (const part of parts) remainingParts.set(part.itemId, (remainingParts.get(part.itemId) ?? 0) + 1);
|
|
142
|
+
const coordinates: Array<{ botId: string; chatId: number; messageId: number; itemId: number }> = [];
|
|
143
|
+
let sendThrew = false;
|
|
144
|
+
let sendCause: unknown;
|
|
145
|
+
for (const part of parts) {
|
|
146
|
+
let partMessageId: number | null;
|
|
147
|
+
try { partMessageId = send(part.text, [part.itemId]); }
|
|
148
|
+
catch (cause) { sendThrew = true; sendCause = cause; break; }
|
|
149
|
+
if (typeof partMessageId !== 'number' || !Number.isSafeInteger(partMessageId) || partMessageId <= 0) break;
|
|
150
|
+
coordinates.push({ botId, chatId: target.chatId, messageId: partMessageId, itemId: part.itemId });
|
|
151
|
+
remainingParts.set(part.itemId, remainingParts.get(part.itemId)! - 1);
|
|
152
|
+
}
|
|
153
|
+
const deliveredIds = [...new Set(coordinates.map(row => row.itemId))].filter(id => remainingParts.get(id) === 0);
|
|
154
|
+
if (deliveredIds.length > 0) markSent(deliveredIds, slot, coordinates.filter(row => deliveredIds.includes(row.itemId)));
|
|
155
|
+
if (coordinates.length < parts.length) {
|
|
156
|
+
if (sendThrew) throw sendCause;
|
|
157
|
+
throw new Error(`발송 실패: ${deliveredIds.length}/${ids.length} 항목 전송 후 중단 — 나머지는 다음 발송에서 이어진다`);
|
|
158
|
+
}
|
|
159
|
+
const lastMessageId = coordinates[coordinates.length - 1]!.messageId;
|
|
160
|
+
return `sent ${lastMessageId} (${ids.length} items)`;
|
|
161
|
+
}
|
|
162
|
+
const messageId = target ? send(numberedMarkdown, ids) : send(markdown, ids);
|
|
163
|
+
if (typeof messageId !== 'number' || !Number.isSafeInteger(messageId) || messageId <= 0) {
|
|
43
164
|
throw new Error('발송 실패: 양수 메시지 id 없음');
|
|
44
165
|
}
|
|
45
|
-
markSent(ids, slot);
|
|
166
|
+
markSent(ids, slot, target ? { botId, chatId: target.chatId, messageId } : undefined);
|
|
46
167
|
return `sent ${messageId} (${ids.length} items)`;
|
|
47
168
|
});
|
|
48
169
|
|
package/src/cli/claims-cli.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { ClaimsInputError, ClaimsLedger, type ClaimsLedgerOptions, type ClaimRow, type ClaimDetail } from '../claims/claims-ledger.js';
|
|
3
3
|
import { renderClaims, queueStaleRechecks, type ClaimSurface } from '../claims/claims-render.js';
|
|
4
|
+
import { PatentLedger, PatentsInputError, type PatentStatus, type PatentTrack } from '../patents/ledger.js';
|
|
4
5
|
|
|
5
6
|
function actor(explicit?: string): string {
|
|
6
7
|
const by = explicit?.trim() || process.env.AI_AGENT?.trim();
|
|
@@ -19,7 +20,7 @@ function handle<Args extends unknown[]>(command: string, action: (...args: Args)
|
|
|
19
20
|
return (...args) => {
|
|
20
21
|
try { action(...args); }
|
|
21
22
|
catch (error) {
|
|
22
|
-
if (!(error instanceof ClaimsInputError)) throw error;
|
|
23
|
+
if (!(error instanceof ClaimsInputError) && !(error instanceof PatentsInputError)) throw error;
|
|
23
24
|
const message = error.message.replace(/\r/g, '\\r').replace(/\n/g, '\\n')
|
|
24
25
|
.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
|
|
25
26
|
process.stderr.write(`claims ${command}: ${message}\n`);
|
|
@@ -41,7 +42,19 @@ function detail(row: ClaimDetail): string {
|
|
|
41
42
|
export function registerClaimsCommands(program: Command, options: ClaimsLedgerOptions & { instanceRoot?: string } = {}, out: Pick<Console, 'log'> = console): void {
|
|
42
43
|
const root = program.command('claims').description('소구점 · 실측 근거 원장');
|
|
43
44
|
const ledger = () => new ClaimsLedger(options);
|
|
45
|
+
const patentLedger = () => new PatentLedger(options);
|
|
44
46
|
const emit = (value: unknown, json: boolean | undefined, text: string) => out.log(json ? JSON.stringify(value) : text);
|
|
47
|
+
const patents = root.command('patents').description('비공개 특허 후보 원장');
|
|
48
|
+
patents.command('add <id>').requiredOption('--title <title>').requiredOption('--track <track>')
|
|
49
|
+
.option('--deadline <YYYY-MM-DD>').action(handle('patents add', (id: string, o: { title: string; track: PatentTrack; deadline?: string }) => {
|
|
50
|
+
const row = patentLedger().add({ id, title: o.title, track: o.track, ...(o.deadline ? { deadline: o.deadline } : {}) });
|
|
51
|
+
emit(row, false, `${row.id} · ${row.status}`);
|
|
52
|
+
}));
|
|
53
|
+
patents.command('status <id>').requiredOption('--status <status>')
|
|
54
|
+
.action(handle('patents status', (id: string, o: { status: PatentStatus }) => {
|
|
55
|
+
const row = patentLedger().setStatus(id, o.status);
|
|
56
|
+
emit(row, false, `${row.id} · ${row.status}`);
|
|
57
|
+
}));
|
|
45
58
|
root.command('add <id>').requiredOption('--claim <text>').requiredOption('--audience <list>').requiredOption('--owner <seat>')
|
|
46
59
|
.option('--contrast <text>').action(handle('add', (id: string, o: { claim: string; audience: string; owner: string; contrast?: string }) => {
|
|
47
60
|
const row = ledger().add({ id, claim: o.claim, audience: o.audience, owner: o.owner, ...(o.contrast ? { contrast: o.contrast } : {}) });
|
|
@@ -79,9 +92,16 @@ export function registerClaimsCommands(program: Command, options: ClaimsLedgerOp
|
|
|
79
92
|
emit(row, o.json, detail(row));
|
|
80
93
|
}));
|
|
81
94
|
root.command('render').requiredOption('--surface <surface>', 'deck | site | notice')
|
|
82
|
-
.option('--audience <audience>').option('--
|
|
83
|
-
.
|
|
84
|
-
|
|
95
|
+
.option('--audience <audience>').option('--include-patents', '명시적으로 공개 허용 특허 후보를 포함')
|
|
96
|
+
.option('--patent-owner <owner>', '특허 후보의 확인된 담당').option('--json')
|
|
97
|
+
.action(handle('render', (o: { surface: ClaimSurface; audience?: string; includePatents?: boolean; patentOwner?: string; json?: boolean }) => {
|
|
98
|
+
if (o.includePatents && (!o.patentOwner?.trim() || !o.audience?.trim())) {
|
|
99
|
+
throw new ClaimsInputError('--include-patents requires --patent-owner and --audience');
|
|
100
|
+
}
|
|
101
|
+
if (!o.includePatents && o.patentOwner) throw new ClaimsInputError('--patent-owner requires --include-patents');
|
|
102
|
+
const patents = o.includePatents
|
|
103
|
+
? { ledger: patentLedger(), owner: o.patentOwner!, audience: o.audience! } : undefined;
|
|
104
|
+
const result = renderClaims(ledger(), { surface: o.surface, ...(o.audience ? { audience: o.audience } : {}), ...(patents ? { patents } : {}) });
|
|
85
105
|
// Review follow-up: rendering is where stale claims surface — queue their re-measurement in the same act.
|
|
86
106
|
const rechecks = result.excluded.some(item => item.reason === 'stale')
|
|
87
107
|
? queueStaleRechecks(ledger(), { root: options.instanceRoot, now: options.now?.() }) : 0;
|
package/src/cli/control-cli.ts
CHANGED
|
@@ -31,6 +31,35 @@ function reasonFor(error: unknown, token?: string): string {
|
|
|
31
31
|
return token ? message.replaceAll(token, '[redacted]') : message;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/** Doctor's read-only live source. One malformed Nexus machine row invalidates the whole
|
|
35
|
+
* reading: doctor reports unmeasured rather than treating a partial registry as complete. */
|
|
36
|
+
export async function listMachineResources(options: { primaryUrl?: string; queryToken?: string; port?: string; root?: string; fetch?: (input: URL | RequestInfo, init?: RequestInit) => Promise<Response> } = {}): Promise<ResourceView[]> {
|
|
37
|
+
const portOverride = options.port ?? (process.env.ELANOUS_CONTROL_PORT?.trim() || undefined);
|
|
38
|
+
const primary = await resolvePrimary({
|
|
39
|
+
role: 'query',
|
|
40
|
+
...(options.root ? { root: options.root } : {}),
|
|
41
|
+
config: { url: options.primaryUrl, tokens: options.queryToken ? { query: options.queryToken } : undefined },
|
|
42
|
+
...(portOverride !== undefined ? { port: Number(portOverride) } : {}),
|
|
43
|
+
});
|
|
44
|
+
const token = primary.token;
|
|
45
|
+
if (!token) throw new Error('control query token unavailable');
|
|
46
|
+
const url = new URL('/v1/resources', primary.url);
|
|
47
|
+
url.searchParams.set('kind', 'machine');
|
|
48
|
+
const response = await (options.fetch ?? globalThis.fetch)(url, {
|
|
49
|
+
headers: { authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(5000),
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) throw new Error(`control HTTP ${response.status}`);
|
|
52
|
+
const body: unknown = await response.json();
|
|
53
|
+
if (!body || typeof body !== 'object' || !('resources' in body) || !Array.isArray(body.resources) ||
|
|
54
|
+
body.resources.some((row: unknown) => !row || typeof row !== 'object' ||
|
|
55
|
+
(row as ResourceView).kind !== 'machine' || typeof (row as ResourceView).machine !== 'string' ||
|
|
56
|
+
typeof (row as ResourceView).name !== 'string' || typeof (row as ResourceView).expired !== 'boolean' ||
|
|
57
|
+
!((row as ResourceView).attrs && typeof (row as ResourceView).attrs === 'object'))) {
|
|
58
|
+
throw new Error('invalid machine resource response');
|
|
59
|
+
}
|
|
60
|
+
return body.resources as ResourceView[];
|
|
61
|
+
}
|
|
62
|
+
|
|
34
63
|
export async function runResourcesQuery(options: { where?: string; kind?: string; port?: string; primaryUrl?: string; queryToken?: string; json?: boolean }): Promise<number> {
|
|
35
64
|
let base = '';
|
|
36
65
|
let token: string | undefined;
|
package/src/cli/doctor-cli.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
type ReadinessReport,
|
|
28
28
|
type SubstrateSignals,
|
|
29
29
|
} from './doctor-readiness.js';
|
|
30
|
-
import { debug } from '../debug/log.js';
|
|
30
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
31
31
|
import { resolveDaemonEndpoint, type ResolveDaemonEndpointOpts } from '../nexus/daemon-endpoint.js';
|
|
32
32
|
import { applyDoctorFixes, applyGitInstall, applyServiceRestart, applySudoFixes, planDoctorFixes, type DoctorFixDeps, type DoctorFixItem } from './doctor-fix.js';
|
|
33
33
|
import { ADVISABLE_DOCTOR_FIX_IDS, adviseDoctorFixes, type DoctorAdvice } from './doctor-llm-assist.js';
|
|
@@ -40,7 +40,10 @@ import type { LlmInventory } from '../llm/local-manager/types.js';
|
|
|
40
40
|
import { buildDoctorBundle } from './doctor-bundle.js';
|
|
41
41
|
import { uploadDoctorBundle } from './doctor-bundle-upload.js';
|
|
42
42
|
import { checkNodeModules, formatNodeModulesCheck, nodeModulesTrees } from './doctor-node-modules.js';
|
|
43
|
-
import { formatHostDoctorLines, runHostDoctor, type HostDoctorExpected, type HostDoctorRemote } from '../fleet/host-doctor.js';
|
|
43
|
+
import { formatHostDoctorLines, runHostDoctor, type HostDoctorExpected, type HostDoctorOptions, type HostDoctorRemote } from '../fleet/host-doctor.js';
|
|
44
|
+
import { listMachineResources } from './control-cli.js';
|
|
45
|
+
import type { ResourceView } from '../control-plane/ledger.js';
|
|
46
|
+
import { loadMachineLedger } from '../machines/machine-ledger.js';
|
|
44
47
|
|
|
45
48
|
function defaultCheckPythonEnv(): { status: 'ok' | 'fixable' | 'manual'; evidence: string; remedy?: string } {
|
|
46
49
|
const c = checkPythonEnv(false);
|
|
@@ -203,9 +206,14 @@ export interface DoctorCliDeps extends DoctorOptions, Pick<DoctorFixDeps, 'home'
|
|
|
203
206
|
hostDoctorRemote?: HostDoctorRemote;
|
|
204
207
|
/** `doctor host` 가 대조할 HQ 실측값(설치 판 · 이미지 핀) — 없으면 해당 점검은 unmeasured. */
|
|
205
208
|
hostDoctorExpected?: HostDoctorExpected;
|
|
209
|
+
/** HQ membership readings; injected tests need no live Nexus. */
|
|
210
|
+
hostDoctorMembership?: () => Promise<NonNullable<HostDoctorOptions['membership']>>;
|
|
211
|
+
/** Nexus machine query seam; tests can exercise the default assembly without contacting a live service. */
|
|
212
|
+
hostDoctorMachineResources?: () => Promise<ResourceView[]>;
|
|
206
213
|
}
|
|
207
214
|
|
|
208
215
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
216
|
+
const observationError = (error: unknown): string => redactSecretText(error instanceof Error ? error.message : String(error)).slice(0, 200);
|
|
209
217
|
const tavilyNames = new Set(['TAVILY_API_KEY', 'TAVILY_KEY']);
|
|
210
218
|
|
|
211
219
|
function defaultCodeRevision(): string | undefined {
|
|
@@ -1211,6 +1219,52 @@ function formatDoctorAdvice(advice: DoctorAdvice): string {
|
|
|
1211
1219
|
].join('\n');
|
|
1212
1220
|
}
|
|
1213
1221
|
|
|
1222
|
+
function formatDoctorAdviceProposal(advice: DoctorAdvice, report: DoctorReport): { text: string; itemId: string; observedValue: string } | null {
|
|
1223
|
+
const proposal = advice.ok ? advice.order[0] : undefined;
|
|
1224
|
+
if (!proposal) return null;
|
|
1225
|
+
const observation = report.readiness?.items.find((item) => item.id === proposal.readinessId);
|
|
1226
|
+
if (!observation) return null;
|
|
1227
|
+
const observedValue = `${observation.status}: ${observation.evidence}`;
|
|
1228
|
+
return {
|
|
1229
|
+
itemId: proposal.readinessId,
|
|
1230
|
+
observedValue,
|
|
1231
|
+
text: [
|
|
1232
|
+
`LLM 제안: ${proposal.why}`,
|
|
1233
|
+
`운영 팩 항목 id: ${proposal.readinessId}`,
|
|
1234
|
+
`현재 관측값: ${observedValue}`,
|
|
1235
|
+
].join('\n'),
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
async function recordDoctorAdviceResponse(
|
|
1240
|
+
proposal: { itemId: string; observedValue: string },
|
|
1241
|
+
accepted: boolean,
|
|
1242
|
+
): Promise<void> {
|
|
1243
|
+
debug.log('doctor.advise', accepted ? 'accepted' : 'rejected', {
|
|
1244
|
+
itemId: proposal.itemId,
|
|
1245
|
+
observedValue: proposal.observedValue,
|
|
1246
|
+
applied: 0,
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
async function presentDoctorAdviceProposal(
|
|
1251
|
+
advice: DoctorAdvice,
|
|
1252
|
+
report: DoctorReport,
|
|
1253
|
+
deps: DoctorCliDeps,
|
|
1254
|
+
json: boolean,
|
|
1255
|
+
announce: (text: string) => void,
|
|
1256
|
+
): Promise<{ proposal: { itemId: string; observedValue: string }; response: boolean | null; text: string } | null> {
|
|
1257
|
+
const formatted = formatDoctorAdviceProposal(advice, report);
|
|
1258
|
+
if (!formatted) return null;
|
|
1259
|
+
const proposal = { itemId: formatted.itemId, observedValue: formatted.observedValue };
|
|
1260
|
+
const interactive = deps.adviceInteractive ?? (process.stdin.isTTY === true && (json ? process.stderr.isTTY === true : process.stdout.isTTY === true));
|
|
1261
|
+
if (!interactive) return { proposal, response: null, text: formatted.text };
|
|
1262
|
+
announce(formatted.text);
|
|
1263
|
+
const accepted = await (deps.confirmAdvice ?? ((message) => confirmDoctorAdvice(message, json)))('이 제안을 수락할까요? [y/N] ');
|
|
1264
|
+
await recordDoctorAdviceResponse(proposal, accepted);
|
|
1265
|
+
return { proposal, response: accepted, text: `${formatted.text}\n응답: ${accepted ? '수락' : '거절'}` };
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1214
1268
|
async function confirmDoctorAdvice(message: string, json: boolean): Promise<boolean> {
|
|
1215
1269
|
const prompt = createInterface({ input: process.stdin, output: json ? process.stderr : process.stdout });
|
|
1216
1270
|
try { return /^(y|yes)$/i.test((await prompt.question(message)).trim()); }
|
|
@@ -1246,18 +1300,39 @@ export function registerDoctorCommand(program: Command, deps: DoctorCliDeps = {}
|
|
|
1246
1300
|
if (checks.some((check) => check.status !== 'ok')) setExitCode(1);
|
|
1247
1301
|
});
|
|
1248
1302
|
doctor.command('host')
|
|
1249
|
-
.description('Check whether a fleet host stands ready
|
|
1250
|
-
.argument('<host>', "
|
|
1303
|
+
.description('Check whether a fleet host stands ready (read-only; membership needs a repository checkout and a named remote worker)')
|
|
1304
|
+
.argument('<host>', "SSH name in fleet intent; an unknown name fails membership; 'local' checks readiness without membership")
|
|
1251
1305
|
.option('--role <role>', 'host role: worker or hq', 'worker')
|
|
1252
1306
|
.option('--json', 'structured output')
|
|
1253
|
-
.action((host: string, opts: { role: string; json?: boolean }, command: Command) => {
|
|
1307
|
+
.action(async (host: string, opts: { role: string; json?: boolean }, command: Command) => {
|
|
1254
1308
|
if (opts.role !== 'worker' && opts.role !== 'hq') {
|
|
1255
1309
|
err.error('--role must be worker or hq');
|
|
1256
1310
|
setExitCode(1);
|
|
1257
1311
|
return;
|
|
1258
1312
|
}
|
|
1259
1313
|
const json = opts.json === true || command.parent?.opts().json === true;
|
|
1260
|
-
|
|
1314
|
+
let membership: HostDoctorOptions['membership'];
|
|
1315
|
+
if (opts.role === 'worker' && host !== 'local') {
|
|
1316
|
+
if (deps.hostDoctorMembership) membership = await deps.hostDoctorMembership();
|
|
1317
|
+
else {
|
|
1318
|
+
let intent: NonNullable<HostDoctorOptions['membership']>['intent'] = null;
|
|
1319
|
+
let machines: NonNullable<HostDoctorOptions['membership']>['machines'] = null;
|
|
1320
|
+
let parentHosts: NonNullable<HostDoctorOptions['membership']>['parentHosts'] = null;
|
|
1321
|
+
let intentError: string | undefined;
|
|
1322
|
+
let machinesError: string | undefined;
|
|
1323
|
+
let parentHostsError: string | undefined;
|
|
1324
|
+
try { intent = loadMachineLedger(deps.repositoryRoot ?? repositoryRoot); } catch (error) { intentError = observationError(error); }
|
|
1325
|
+
try { machines = await (deps.hostDoctorMachineResources ?? listMachineResources)(); } catch (error) { machinesError = observationError(error); }
|
|
1326
|
+
try {
|
|
1327
|
+
// UserConfig permits one parent object or an array of parent objects, never a bare host string.
|
|
1328
|
+
const configured = (deps.userConfig ?? (deps.getUserConfig ?? getUserConfig)()).taskAgent?.parentHost;
|
|
1329
|
+
if (configured === null) parentHostsError = 'taskAgent.parentHost is null';
|
|
1330
|
+
else parentHosts = configured === undefined ? [] : Array.isArray(configured) ? configured : [configured];
|
|
1331
|
+
} catch (error) { parentHostsError = observationError(error); }
|
|
1332
|
+
membership = { intent, machines, parentHosts, intentError, machinesError, parentHostsError };
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
const report = runHostDoctor({ host, role: opts.role, remote: deps.hostDoctorRemote, expected: deps.hostDoctorExpected, membership });
|
|
1261
1336
|
out.log(json ? JSON.stringify(report, null, 2) : formatHostDoctorLines(report).join('\n'));
|
|
1262
1337
|
if (!report.ok) setExitCode(1);
|
|
1263
1338
|
});
|
|
@@ -1404,10 +1479,17 @@ export function registerDoctorCommand(program: Command, deps: DoctorCliDeps = {}
|
|
|
1404
1479
|
// Planning never writes; existing repairs require --yes, while git alone can use affirmative TTY consent.
|
|
1405
1480
|
const plan = planDoctorFixes(fixes);
|
|
1406
1481
|
const advice = opts.advise ? await requestDoctorAdvice(report, plan, deps) : undefined;
|
|
1482
|
+
const proposal = advice && !opts.fix ? await presentDoctorAdviceProposal(advice, report, deps, opts.json === true, (text) => {
|
|
1483
|
+
if (opts.json) err.error(text);
|
|
1484
|
+
else out.log(text);
|
|
1485
|
+
}) : null;
|
|
1407
1486
|
if (!opts.fix) {
|
|
1408
1487
|
out.log(opts.json
|
|
1409
|
-
? JSON.stringify({ ...report, advise: advice }, null, 2)
|
|
1410
|
-
: [
|
|
1488
|
+
? JSON.stringify({ ...report, advise: advice, ...(proposal ? { adviceProposal: { itemId: proposal.proposal.itemId, observedValue: proposal.proposal.observedValue, response: proposal.response } } : {}) }, null, 2)
|
|
1489
|
+
: [
|
|
1490
|
+
formatDoctorReport(report, { credentials: opts.credentials }),
|
|
1491
|
+
proposal?.response === null ? proposal.text : proposal ? `응답: ${proposal.response ? '수락' : '거절'}` : formatDoctorAdvice(advice!),
|
|
1492
|
+
].join('\n'));
|
|
1411
1493
|
if (report.requiredMissing?.length) setExitCode(1);
|
|
1412
1494
|
return;
|
|
1413
1495
|
}
|