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/release-cli.ts
CHANGED
|
@@ -28,7 +28,7 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../instance/resolve.js
|
|
|
28
28
|
import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
|
|
29
29
|
import { envLiteral } from '../platform/env-literal.js';
|
|
30
30
|
import { getUserConfig, userConfigPath } from '../user-config.js';
|
|
31
|
-
import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, lintDocRefs, listChecklist, normalizeRefs, ownerMatches, parseOwner, parityGap, refRoots, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
|
|
31
|
+
import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, inspectChecklistTargetPaths, lintDocRefs, listChecklist, normalizeRefs, ownerMatches, parseOwner, parityGap, refRoots, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind, type ChecklistDispatchKind } from '../release-loop/checklist.js';
|
|
32
32
|
import * as features from '../release-loop/feature-store.js';
|
|
33
33
|
import { evidencePlan, landedButYellow, type MergedChecklistPr } from '../release-loop/landed-but-yellow.js';
|
|
34
34
|
import { formatSchedule, getSchedule, listSchedules, setSchedule } from '../release-loop/release-schedule.js';
|
|
@@ -53,6 +53,7 @@ import { autoStartScheduledRelease, type AutoStartDeferral } from '../release-lo
|
|
|
53
53
|
import { runRehearsalTick, type RehearsalDeps } from '../release-loop/rehearsal.js';
|
|
54
54
|
import { landingFreezeMessage, LandingFrozenError, readLandingFreeze } from '../release-loop/landing-freeze.js';
|
|
55
55
|
import { formatLightRc, runLightRc, type LightRcDeps } from '../release-loop/light-rc.js';
|
|
56
|
+
import { registerRfcCommands } from './rfc-cli.js';
|
|
56
57
|
|
|
57
58
|
export const DEFAULT_PUBLIC_REPO = 'ElanvitalAI/elanous';
|
|
58
59
|
const SEMVER = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
|
|
@@ -488,6 +489,28 @@ async function jsonAction<T>(json: boolean | undefined, body: (log: (l: string)
|
|
|
488
489
|
}
|
|
489
490
|
}
|
|
490
491
|
|
|
492
|
+
function warnChecklistTargetPaths(input: { title: string; evidence?: string; refs?: readonly string[]; dispatchKind?: ChecklistDispatchKind }): void {
|
|
493
|
+
const cwd = process.cwd();
|
|
494
|
+
const existsAtMain = (path: string): boolean => {
|
|
495
|
+
if (path.startsWith('/') || path.split('/').includes('..')) return false;
|
|
496
|
+
const result = spawnSync('git', ['cat-file', '-e', `origin/main:${path}`], { cwd, timeout: 5_000, stdio: 'ignore' });
|
|
497
|
+
return result.status === 0;
|
|
498
|
+
};
|
|
499
|
+
const mergedPrFiles = (number: number): string[] => {
|
|
500
|
+
const result = spawnSync('gh', ['pr', 'view', String(number), '--json', 'state,files'], { cwd, encoding: 'utf8', timeout: 10_000 });
|
|
501
|
+
if (result.status !== 0) return [];
|
|
502
|
+
try {
|
|
503
|
+
const pr = JSON.parse(result.stdout) as { state?: string; files?: Array<{ path?: string }> };
|
|
504
|
+
return pr.state === 'MERGED' ? (pr.files ?? []).map((file) => file.path).filter((path): path is string => typeof path === 'string') : [];
|
|
505
|
+
} catch { return []; }
|
|
506
|
+
};
|
|
507
|
+
const report = inspectChecklistTargetPaths(input, { existsAtMain, mergedPrFiles });
|
|
508
|
+
for (const warning of report.warnings) {
|
|
509
|
+
console.error(`⚠ 대상 경로: ${warning}${report.candidates.length ? ` · 후보: ${report.candidates.join(' · ')}` : ''}`);
|
|
510
|
+
debug.log('release.checklist', 'target-path-warning', { warning, candidates: report.candidates });
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
491
514
|
function checklistCodenames(): Record<string, string> {
|
|
492
515
|
const path = getElanousConfigDirOverride() ? join(effectiveInstanceRoot(), 'config.json') : userConfigPath();
|
|
493
516
|
if (!existsSync(path)) return {};
|
|
@@ -601,6 +624,7 @@ function compareReleaseVersions(a: string, b: string): number {
|
|
|
601
624
|
}
|
|
602
625
|
|
|
603
626
|
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}, landedDeps: LandedButYellowDeps = {}, hqDeps: HqDeps = {}, lightRcDeps: LightRcDeps = {}, rehearsalDeps: RehearsalDeps = {}): void {
|
|
627
|
+
registerRfcCommands(program);
|
|
604
628
|
const release = program.command('release').description('공개 배포 한 판 — prepare(로컬) → publish(--yes) → verify (docs/manual/MANUAL-versioning-and-release-2026-09-25.md)');
|
|
605
629
|
const schedule = release.command('schedule').description('판별 컷·착지 마감 조회·갱신');
|
|
606
630
|
const scheduleLedgerRoot = () => releaseRunDeps.ledgerRoot ?? releaseLedgerRoot();
|
|
@@ -815,7 +839,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
815
839
|
process.exitCode = 1;
|
|
816
840
|
}
|
|
817
841
|
});
|
|
818
|
-
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄 · postpub = 발행 뒤 실측 칸 — 판 관문이 발행 전 판정에서 빼고 따로 센다')
|
|
842
|
+
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄 · postpub = 발행 뒤 실측 칸 — 판 관문이 발행 전 판정에서 빼고 따로 센다 · code|ops|measure|decision|umbrella = 발사 분류')
|
|
819
843
|
.option('--priority <priority>', 'P0|P1|P2').option('--deadline-version <v>', '마감 판').option('--predecessor <id...>', '선행 칸 id')
|
|
820
844
|
.option('--ceo-minutes <minutes>', '대표 손 분량(분)').option('--ceo-date <date>', '대표 손 날짜 YYYY-MM-DD (없으면 판 착지일 KST)')
|
|
821
845
|
.option('--accelerator', '가속 등급 — 다른 칸의 처리량을 올리는 칸(자율성·효율성·동시성). 생략하면 등급 없음')
|
|
@@ -824,12 +848,14 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
824
848
|
.action((id: string, title: string, opts: { ref?: string[]; owner?: string; kind?: string; priority?: string; deadlineVersion?: string; predecessor?: string[]; ceoMinutes?: string; ceoDate?: string; accelerator?: boolean; allowDuplicateId?: boolean }, cmd: Command) => {
|
|
825
849
|
const { version, json } = context(cmd);
|
|
826
850
|
if (!mayWrite(cmd)) return;
|
|
827
|
-
const
|
|
851
|
+
const dispatchKind = opts.kind && !['screen', 'postpub'].includes(opts.kind) ? opts.kind as ChecklistDispatchKind : undefined;
|
|
852
|
+
const data = addItem(version, { id, title, ...(opts.ref !== undefined ? { refs: opts.ref } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.kind !== undefined && !dispatchKind ? { kind: opts.kind as ChecklistKind } : {}), ...(dispatchKind ? { dispatchKind } : {}), ...(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 ? { accelerator: true } : {}) }, { allowDuplicateId: opts.allowDuplicateId });
|
|
853
|
+
warnChecklistTargetPaths({ title, refs: opts.ref, dispatchKind });
|
|
828
854
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 추가`);
|
|
829
855
|
});
|
|
830
856
|
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
831
857
|
.option('--status <status>', 'green|yellow|red|done').option('--evidence <evidence>', '근거').option('--owner <owner>', '담당')
|
|
832
|
-
.option('--disposition <disposition>', 'move|known-issue|block').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄 · postpub = 발행 뒤 실측 칸 — 판 관문이 발행 전 판정에서 빼고 따로 센다')
|
|
858
|
+
.option('--disposition <disposition>', 'move|known-issue|block').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄 · postpub = 발행 뒤 실측 칸 — 판 관문이 발행 전 판정에서 빼고 따로 센다 · code|ops|measure|decision|umbrella = 발사 분류')
|
|
833
859
|
.option('--priority <priority>', 'P0|P1|P2').option('--deadline-version <v>', '마감 판').option('--predecessor <id...>', '선행 칸 id').option('--no-predecessor', '선행 칸 비우기(진짜 의존이 아니면 · CHECKLIST-PRED-CLEAR)')
|
|
834
860
|
.option('--ceo-minutes <minutes>', '대표 손 분량(분)').option('--ceo-date <date>', '대표 손 날짜 YYYY-MM-DD')
|
|
835
861
|
.option('--accelerator', '가속 등급 부여').option('--no-accelerator', '가속 등급 해제(기본은 없음)')
|
|
@@ -840,7 +866,8 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
840
866
|
if (opts.disposition !== undefined && !['move', 'known-issue', 'block'].includes(opts.disposition)) throw new CliUserError(`잘못된 처분: ${opts.disposition}`, 'move|known-issue|block');
|
|
841
867
|
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 중 하나');
|
|
842
868
|
if (!mayWrite(cmd)) return;
|
|
843
|
-
const
|
|
869
|
+
const dispatchKind = opts.kind && !['screen', 'postpub'].includes(opts.kind) ? opts.kind as ChecklistDispatchKind : undefined;
|
|
870
|
+
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 && !dispatchKind ? { kind: opts.kind as ChecklistKind } : {}), ...(dispatchKind ? { dispatchKind } : {}), ...(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');
|
|
844
871
|
const item = data.items.find((entry) => entry.id === id);
|
|
845
872
|
const why = item?.kind === 'screen' && item.status === 'green' ? parityGap(item.evidence) : null;
|
|
846
873
|
if (why) {
|
|
@@ -891,6 +918,8 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
891
918
|
if (!mayWrite(cmd)) return;
|
|
892
919
|
const snapshot = listChecklist(version);
|
|
893
920
|
features.retitle(id, title, actor(), snapshot.released, snapshot.dev);
|
|
921
|
+
const item = snapshot.items.find((entry) => entry.id === id);
|
|
922
|
+
warnChecklistTargetPaths({ title, evidence: item?.evidence, refs: item?.refs, dispatchKind: item?.dispatchKind });
|
|
894
923
|
if (json) console.log(JSON.stringify(listChecklist(version))); else console.log(`✅ ${id} 제목 수정`);
|
|
895
924
|
});
|
|
896
925
|
const evidence = checklist.command('evidence').description('칸의 PR·커밋 근거');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { CliUserError } from './cli-user-error.js';
|
|
3
|
+
import { listRfcs, showRfc } from '../rfc-registry/registry.js';
|
|
4
|
+
|
|
5
|
+
/** RFC-REGISTRY first slice: list/show initialize an empty registry if needed, then only read rows. */
|
|
6
|
+
export function registerRfcCommands(program: Command): void {
|
|
7
|
+
const rfc = program.command('rfc').description('RFC registry (list/show initialize the database when absent)');
|
|
8
|
+
rfc.command('list').description('registered RFCs').option('--json', 'JSON rows')
|
|
9
|
+
.action((opts: { json?: boolean }) => {
|
|
10
|
+
const rows = listRfcs();
|
|
11
|
+
if (opts.json) console.log(JSON.stringify(rows));
|
|
12
|
+
else for (const row of rows) console.log(`${row.id} · ${row.status} · ${row.title}`);
|
|
13
|
+
});
|
|
14
|
+
rfc.command('show <id>').description('RFC and its items').option('--json', 'JSON record')
|
|
15
|
+
.action((id: string, opts: { json?: boolean }) => {
|
|
16
|
+
const row = showRfc(id);
|
|
17
|
+
if (!row) throw new CliUserError(`없는 RFC: ${id}`);
|
|
18
|
+
if (opts.json) console.log(JSON.stringify(row));
|
|
19
|
+
else {
|
|
20
|
+
console.log(`${row.id} · ${row.status} · ${row.title}`);
|
|
21
|
+
for (const item of row.items) console.log(` ${item.id} · ${item.status} · ${item.title}${item.links.length ? ` → ${item.links.map((link) => link.target_item_id).join(', ')}` : ''}`);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { existsSync, lstatSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
5
|
+
import { redactSecretText } from '../debug/log.js';
|
|
6
|
+
import { defaultMsgStorePath, readUnreadCount } from '../msg/msg-store.js';
|
|
7
|
+
|
|
8
|
+
export const SEAT_ROLES = ['OP', 'TC', 'MK', 'UX'] as const;
|
|
9
|
+
export type SeatRole = typeof SEAT_ROLES[number];
|
|
10
|
+
|
|
11
|
+
const MAX_FIELD = 160;
|
|
12
|
+
const MAX_ROWS = 12;
|
|
13
|
+
const clean = (value: unknown): string => redactSecretText(String(value ?? '').replace(/[\r\n\t]+/g, ' ').trim()).slice(0, MAX_FIELD);
|
|
14
|
+
const safeObject = (value: unknown, keys: readonly string[]): Record<string, string> => {
|
|
15
|
+
const source = value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
|
16
|
+
return Object.fromEntries(keys.filter(key => source[key] !== undefined && source[key] !== null).map(key => [key, clean(source[key])]));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function isRegularSeatPath(home: string, root: string, path: string): boolean {
|
|
20
|
+
const suffix = relative(root, path);
|
|
21
|
+
if (!suffix || suffix === '..' || suffix.startsWith(`..${sep}`) || suffix.startsWith(sep)) return false;
|
|
22
|
+
if (!lstatSync(home).isDirectory()) return false;
|
|
23
|
+
let parent = home;
|
|
24
|
+
for (const part of relative(home, dirname(path)).split(sep).filter(Boolean)) {
|
|
25
|
+
parent = join(parent, part);
|
|
26
|
+
if (!lstatSync(parent).isDirectory()) return false;
|
|
27
|
+
}
|
|
28
|
+
return lstatSync(path).isFile();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function metadata(home: string, root: string, path: string, kind: 'markdown' | 'tsv' | 'memory'): { source: string; updated: string; rows: string[]; reason?: string } {
|
|
32
|
+
if (!existsSync(path)) return { source: path, updated: '미상', rows: [], reason: '미관측: 파일 없음' };
|
|
33
|
+
try {
|
|
34
|
+
if (!isRegularSeatPath(home, root, path)) return { source: path, updated: '미상', rows: [], reason: '미관측: 일반 경로가 아님' };
|
|
35
|
+
const updated = statSync(path).mtime.toISOString();
|
|
36
|
+
const text = readFileSync(path, 'utf8').slice(0, 256_000);
|
|
37
|
+
let rows: string[] = [];
|
|
38
|
+
if (kind === 'tsv') {
|
|
39
|
+
const headers = (text.split(/\r?\n/, 1)[0] ?? '').split('\t');
|
|
40
|
+
const allowed = kind === 'tsv' && path.endsWith('harvest-claims.tsv') ? ['pr', 'claimer', 'at', 'status'] : ['at', 'what', 'then'];
|
|
41
|
+
const indexes = allowed.map(key => headers.indexOf(key));
|
|
42
|
+
rows = text.split(/\r?\n/).slice(1).filter(Boolean).slice(0, MAX_ROWS).map(line => {
|
|
43
|
+
const cells = line.split('\t');
|
|
44
|
+
return allowed.map((key, i) => indexes[i] < 0 ? '' : `${key}=${clean(cells[indexes[i]])}`).filter(Boolean).join(' · ');
|
|
45
|
+
}).filter(Boolean);
|
|
46
|
+
} else if (kind === 'memory') {
|
|
47
|
+
rows = text.split(/\r?\n/).filter(line => /^#{1,6}\s/.test(line)).slice(0, MAX_ROWS).map(line => clean(line.replace(/^#+\s*/, '')));
|
|
48
|
+
} else {
|
|
49
|
+
rows = text.split(/\r?\n/).filter(line => (/^#{1,6}\s/.test(line) || /^(?:[-*]\s*)?(?:from|발신|시각|at)\s*[::]/i.test(line)) && !/[`$;|<>]/.test(line)).slice(0, MAX_ROWS).map(line => {
|
|
50
|
+
const from = line.match(/^(?:[-*]\s*)?(?:from|발신)\s*[::]\s*(OP|TC|MK|UX)\b/i);
|
|
51
|
+
if (/^(?:[-*]\s*)?(?:from|발신)\s*[::]/i.test(line)) return from ? `From: ${from[1]!.toUpperCase()}` : '';
|
|
52
|
+
return clean(line.replace(/^#{1,6}\s*/, ''));
|
|
53
|
+
}).filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
return { source: path, updated, rows, ...(rows.length ? {} : { reason: '미관측: 허용된 메타데이터 없음' }) };
|
|
56
|
+
} catch {
|
|
57
|
+
return { source: path, updated: '미상', rows: [], reason: '미관측: 읽기 실패' };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function contextFacts(snapshot: unknown): string[] {
|
|
62
|
+
const root = snapshot !== null && typeof snapshot === 'object' && !Array.isArray(snapshot) ? snapshot as Record<string, unknown> : {};
|
|
63
|
+
const facts: string[] = [];
|
|
64
|
+
const sourceFacts = Array.isArray(root.facts) ? root.facts as unknown[] : [];
|
|
65
|
+
for (const item of sourceFacts.slice(0, MAX_ROWS)) {
|
|
66
|
+
const value = item !== null && typeof item === 'object' && !Array.isArray(item) ? item as Record<string, unknown> : {};
|
|
67
|
+
const keys = value.kind === 'cell' ? ['id', 'status', 'owner', 'version', 'source']
|
|
68
|
+
: value.kind === 'seat' ? ['seat', 'at', 'status', 'id', 'source']
|
|
69
|
+
: value.kind === 'run' ? ['phase', 'elapsed', 'source'] : [];
|
|
70
|
+
const values = safeObject(value, keys);
|
|
71
|
+
if (Object.keys(values).length) facts.push(`${clean(value.kind)}: ${Object.entries(values).map(([k, v]) => `${k}=${v}`).join(' · ')}`);
|
|
72
|
+
}
|
|
73
|
+
const sourceEvents = Array.isArray(root.events) ? root.events as unknown[] : [];
|
|
74
|
+
for (const item of sourceEvents.slice(0, MAX_ROWS)) {
|
|
75
|
+
const values = safeObject(item, ['at', 'kind', 'source', 'summary']);
|
|
76
|
+
if (Object.keys(values).length) facts.push(`event: ${Object.entries(values).map(([k, v]) => `${k}=${v}`).join(' · ')}`);
|
|
77
|
+
}
|
|
78
|
+
return facts.slice(0, MAX_ROWS);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function renderSeatBootCard(seat: SeatRole, sections: ReadonlyArray<{ title: string; source: string; updated: string; rows: readonly string[]; reason?: string }>, facts: readonly string[], contextUpdated = '미상'): string {
|
|
82
|
+
const out = [`# ${seat} 자리 부팅 카드`, '', '## 현재 구조화 관측', '출처: elanous://context-now', `갱신: ${clean(contextUpdated)}`, ...(facts.length ? facts.map(row => `- ${clean(row)}`) : ['- 미관측: contextNow 구조화 facts/events 없음'])];
|
|
83
|
+
for (const section of sections) out.push('', `## ${section.title}`, `출처: ${clean(section.source)}`, `갱신: ${clean(section.updated)}`, ...(section.rows.length ? section.rows.map(row => `- ${clean(row)}`) : [`- ${clean(section.reason ?? '미관측')}`]));
|
|
84
|
+
return out.join('\n');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function registerSeatBootCommands(command: Command, options: { home?: () => string; contextNow?: () => unknown; msgPath?: () => string } = {}): void {
|
|
88
|
+
command.command('boot <seat>').description('현재 자리 카드 — 허용된 메타데이터만 읽기 전용 표시')
|
|
89
|
+
.action(async (rawSeat: string) => {
|
|
90
|
+
const seat = rawSeat.toUpperCase();
|
|
91
|
+
if (!(SEAT_ROLES as readonly string[]).includes(seat)) { console.error(`seat boot: unknown seat ${rawSeat} (OP|TC|MK|UX)`); process.exitCode = 2; return; }
|
|
92
|
+
const home = options.home?.() ?? homedir();
|
|
93
|
+
const root = join(home, 'elanous-hq', 'seat-state');
|
|
94
|
+
let facts: string[] = [];
|
|
95
|
+
let contextUpdated = '미상';
|
|
96
|
+
try {
|
|
97
|
+
const snapshot = options.contextNow ? options.contextNow() : await (async () => {
|
|
98
|
+
const mod = await import('../context-bus/context-now.js');
|
|
99
|
+
return (mod.contextNow as unknown as (options: { audience: string }) => unknown)({ audience: 'operator' });
|
|
100
|
+
})();
|
|
101
|
+
const context = snapshot !== null && typeof snapshot === 'object' ? snapshot as Record<string, unknown> : {};
|
|
102
|
+
contextUpdated = typeof context.at === 'string' ? clean(context.at) : '시각 미관측';
|
|
103
|
+
facts = contextFacts(snapshot);
|
|
104
|
+
} catch { facts = []; contextUpdated = '미관측: contextNow 조회 실패'; }
|
|
105
|
+
const seatDir = join(root, seat);
|
|
106
|
+
const msgPath = options.msgPath?.() ?? defaultMsgStorePath();
|
|
107
|
+
let unread: number | null = null;
|
|
108
|
+
try { unread = readUnreadCount(seat, msgPath); }
|
|
109
|
+
catch { /* unavailable is not a measured zero */ }
|
|
110
|
+
const sections = [
|
|
111
|
+
{ title: 'msg 원장', source: msgPath, updated: unread === null ? '미상' : new Date().toISOString(), rows: [`안 읽은 msg ${unread ?? '미관측'} (${seat})`] },
|
|
112
|
+
{ title: 'HANDOFF', ...metadata(home, root, join(seatDir, 'HANDOFF.md'), 'markdown') },
|
|
113
|
+
{ title: 'inbox', ...metadata(home, root, join(seatDir, 'inbox.md'), 'markdown') },
|
|
114
|
+
{ title: '수확 주장', ...metadata(home, root, join(seatDir, 'harvest-claims.tsv'), 'tsv') },
|
|
115
|
+
{ title: '예약', ...metadata(home, root, join(seatDir, 'scheduled.tsv'), 'tsv') },
|
|
116
|
+
{ title: '공통 메모리 색인', ...metadata(home, root, join(root, 'memory', 'MEMORY.md'), 'memory') },
|
|
117
|
+
];
|
|
118
|
+
console.log(renderSeatBootCard(seat as SeatRole, sections, facts, contextUpdated));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { Database } from 'bun:sqlite';
|
|
3
|
+
import { redactSecretText } from '../debug/log.js';
|
|
4
|
+
import { openSurfaceEventsDb, querySurfaceUtterances, surfaceEventsDbPath, type SurfaceEventRow } from '../domains/surface-events.js';
|
|
5
|
+
import { injectUtterance, type UtteranceInput } from '../domains/self-awareness.js';
|
|
6
|
+
import { writeStdoutJson } from './stdout-json.js';
|
|
7
|
+
|
|
8
|
+
const PAGE_SIZE = 50;
|
|
9
|
+
type UtteranceOrigin = 'human' | 'agent' | 'unknown';
|
|
10
|
+
|
|
11
|
+
function refsOf(raw: string | null): Record<string, unknown> {
|
|
12
|
+
if (!raw) return {};
|
|
13
|
+
try {
|
|
14
|
+
const value: unknown = JSON.parse(raw);
|
|
15
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
|
16
|
+
} catch { return {}; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function redact(value: string): string {
|
|
20
|
+
return redactSecretText(value)
|
|
21
|
+
.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[REDACTED_EMAIL]')
|
|
22
|
+
.replace(/(https?:\/\/[^\s?#]+)\?[^\s#]*/gi, '$1?[REDACTED_QUERY]');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isAutomatic(row: SurfaceEventRow): boolean {
|
|
26
|
+
const refs = refsOf(row.refs);
|
|
27
|
+
if (row.surface === 'coord:channel' || row.surface === 'coord:seat' || refs.origin === 'coord:channel') return true;
|
|
28
|
+
const seatSource = typeof refs.origin === 'string' && /^(?:seat|seat-notice|notification|wake|coord:seat)$/i.test(refs.origin);
|
|
29
|
+
if (seatSource) return true;
|
|
30
|
+
if (refs.origin === 'observer' || refs.origin === 'observer-generated' || /observer-generated/i.test(row.tags ?? '')) return true;
|
|
31
|
+
if (row.kind === 'qna' && /^(?:telegram|discord)$/i.test(row.surface)) return false;
|
|
32
|
+
if (refs.origin === 'human' || refs.origin === 'user') return false;
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function originOf(row: SurfaceEventRow): UtteranceOrigin {
|
|
37
|
+
if (row.direction !== 'inbound') return 'unknown';
|
|
38
|
+
const refs = refsOf(row.refs);
|
|
39
|
+
if (refs.utteranceOrigin === 'human' || refs.utteranceOrigin === 'agent') return refs.utteranceOrigin;
|
|
40
|
+
const explicit = refs.origin;
|
|
41
|
+
if (typeof explicit === 'string') {
|
|
42
|
+
if (/^(?:human|user|tui|pwa|telegram|discord|cli)$/i.test(explicit)) return 'human';
|
|
43
|
+
if (/^(?:claude-code|codex|gemini|agent|external:)/i.test(explicit)) return 'agent';
|
|
44
|
+
}
|
|
45
|
+
// recordInboundTurn marks its recorder as elanous-self; on chat Q&A the speaker is the human.
|
|
46
|
+
if (row.kind === 'qna' && /^(?:telegram|discord)$/i.test(row.surface)) return 'human';
|
|
47
|
+
if (explicit === 'elanous-self') return 'agent';
|
|
48
|
+
if (/^ext:/i.test(row.surface)) return 'agent';
|
|
49
|
+
if (/^(?:cli|tui|pwa|telegram|discord|ipad|watch)$/i.test(row.surface)) return 'human';
|
|
50
|
+
return 'unknown';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function utteranceText(row: SurfaceEventRow): { text: string; extract: 'direct' | 'qna' | 'ambiguous' | 'summary'; truncated: boolean; truncationEvidence: 'cap-reached' | 'over-cap' | null; possibleLoss: boolean } {
|
|
54
|
+
if (row.kind !== 'qna') return { text: row.text, extract: 'direct', truncated: false, truncationEvidence: null, possibleLoss: false };
|
|
55
|
+
const firstAnswer = row.text.startsWith('Q: ') ? row.text.indexOf('\nA: ', 3) : -1;
|
|
56
|
+
if (firstAnswer >= 0) {
|
|
57
|
+
const ambiguous = row.text.indexOf('\nQ: ', 3) >= 0 || row.text.indexOf('\nA: ', firstAnswer + 4) >= 0;
|
|
58
|
+
return { text: row.text.slice(3, firstAnswer), extract: ambiguous ? 'ambiguous' : 'qna', truncated: false, truncationEvidence: null, possibleLoss: ambiguous };
|
|
59
|
+
}
|
|
60
|
+
const summary = row.summary ?? '';
|
|
61
|
+
return { text: summary.slice(0, 150), extract: 'summary', truncated: summary.length > 150, truncationEvidence: summary.length > 150 ? 'over-cap' : summary.length === 150 ? 'cap-reached' : null, possibleLoss: false };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function validDate(value: string, name: string): string {
|
|
65
|
+
const date = new Date(value);
|
|
66
|
+
if (!value || !Number.isFinite(date.getTime()) || !/^\d{4}-\d\d-\d\d(?:T.*)?$/.test(value)) throw new Error(`--${name} must be a valid ISO date/time`);
|
|
67
|
+
return date.toISOString();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface SelfUtterancesOptions {
|
|
71
|
+
from: string; to: string; surface?: string; origin?: UtteranceOrigin; page?: string; json?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function collectSelfUtterances(opts: SelfUtterancesOptions, db: ReturnType<typeof openSurfaceEventsDb>) {
|
|
75
|
+
const from = validDate(opts.from, 'from');
|
|
76
|
+
const to = validDate(opts.to, 'to');
|
|
77
|
+
if (from >= to) throw new Error('--from must be earlier than --to');
|
|
78
|
+
const page = opts.page === undefined ? 1 : Number(opts.page);
|
|
79
|
+
if (!Number.isSafeInteger(page) || page < 1) throw new Error('--page must be a positive integer');
|
|
80
|
+
const rows = querySurfaceUtterances(db, { from, to, ...(opts.surface ? { surface: opts.surface } : {}) });
|
|
81
|
+
let excludedAutomatic = 0;
|
|
82
|
+
let excludedByOrigin = 0;
|
|
83
|
+
let ambiguous = 0;
|
|
84
|
+
let truncated = 0;
|
|
85
|
+
let capReached = 0;
|
|
86
|
+
let possibleLoss = 0;
|
|
87
|
+
let excludedUnextractable = 0;
|
|
88
|
+
const utterances = rows.flatMap((row) => {
|
|
89
|
+
if (isAutomatic(row)) { excludedAutomatic += 1; return []; }
|
|
90
|
+
const origin = originOf(row);
|
|
91
|
+
if (opts.origin && origin !== opts.origin) { excludedByOrigin += 1; return []; }
|
|
92
|
+
const refs = refsOf(row.refs);
|
|
93
|
+
const cwd = typeof refs.cwd === 'string' && refs.cwd.length > 0 && !/[\u0000-\u001f\u007f]/.test(refs.cwd) ? redact(refs.cwd) : null;
|
|
94
|
+
const extracted = utteranceText(row);
|
|
95
|
+
if (row.kind === 'qna' && extracted.text.trim() === '') { excludedUnextractable += 1; return []; }
|
|
96
|
+
if (extracted.extract === 'ambiguous') ambiguous += 1;
|
|
97
|
+
if (extracted.truncated) truncated += 1;
|
|
98
|
+
if (extracted.truncationEvidence === 'cap-reached') capReached += 1;
|
|
99
|
+
if (extracted.possibleLoss) possibleLoss += 1;
|
|
100
|
+
return [{ id: redact(row.id), ts: redact(row.ts), surface: redact(row.surface), session: row.session_id ? redact(row.session_id) : null, cwd, origin, source: typeof refs.origin === 'string' ? redact(refs.origin) : 'unrecorded', text: redact(extracted.text), extract: extracted.extract, truncated: extracted.truncated, truncationEvidence: extracted.truncationEvidence, possibleLoss: extracted.possibleLoss }];
|
|
101
|
+
});
|
|
102
|
+
const total = utterances.length;
|
|
103
|
+
const start = (page - 1) * PAGE_SIZE;
|
|
104
|
+
return { source: 'surface_events.events (read-only)', filters: { from, to, surface: opts.surface ?? null, origin: opts.origin ?? null, automatic: 'excluded' }, counts: { matched: total, excludedAutomatic, excludedByOrigin, excludedUnextractable, ambiguous, truncated, capReached, possibleLoss }, page: { number: page, size: PAGE_SIZE, total, hasNext: start + PAGE_SIZE < total }, utterances: utterances.slice(start, start + PAGE_SIZE) };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function recordSelfUtterance(input: UtteranceInput & { utteranceOrigin?: 'human' | 'agent' }, db?: Database): { eventId: string } {
|
|
108
|
+
const store = db ?? openSurfaceEventsDb();
|
|
109
|
+
try {
|
|
110
|
+
const result = injectUtterance(input, store);
|
|
111
|
+
if (input.utteranceOrigin === 'human') {
|
|
112
|
+
store.prepare("UPDATE events SET refs = json_set(refs, '$.utteranceOrigin', 'human') WHERE id = ?").run(result.eventId);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
} finally { if (!db) store.close(); }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function registerSelfUtterancesCommand(selfCmd: Command): void {
|
|
119
|
+
selfCmd.command('utterances').description('Read paginated original utterances from surface_events (read-only)')
|
|
120
|
+
.requiredOption('--from <ISO>', 'Inclusive ISO date/time')
|
|
121
|
+
.requiredOption('--to <ISO>', 'Exclusive ISO date/time')
|
|
122
|
+
.option('--surface <surface>', 'Filter by surface')
|
|
123
|
+
.option('--origin <origin>', 'Filter by known origin: human|agent')
|
|
124
|
+
.option('--page <page>', 'One-based page number', '1')
|
|
125
|
+
.option('--json', 'Emit JSON')
|
|
126
|
+
.action(async (opts: SelfUtterancesOptions) => {
|
|
127
|
+
if (opts.origin && opts.origin !== 'human' && opts.origin !== 'agent') throw new Error('--origin must be human or agent');
|
|
128
|
+
const db = new Database(surfaceEventsDbPath(), { readonly: true });
|
|
129
|
+
try {
|
|
130
|
+
const result = collectSelfUtterances(opts, db);
|
|
131
|
+
if (opts.json) { await writeStdoutJson(JSON.stringify(result, null, 2) + '\n'); return; }
|
|
132
|
+
console.log(`source=${result.source} matched=${result.counts.matched} excludedAutomatic=${result.counts.excludedAutomatic} excludedByOrigin=${result.counts.excludedByOrigin} excludedUnextractable=${result.counts.excludedUnextractable} page=${result.page.number} size=${result.page.size} hasNext=${result.page.hasNext}`);
|
|
133
|
+
console.log(`filters=${JSON.stringify(result.filters)}`);
|
|
134
|
+
for (const item of result.utterances) console.log(JSON.stringify(item));
|
|
135
|
+
console.log(`ambiguous=${result.counts.ambiguous} truncated=${result.counts.truncated} cap-reached=${result.counts.capReached} possibleLoss=${result.counts.possibleLoss}`);
|
|
136
|
+
} finally { db.close(); }
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { PAGE_SIZE };
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
// Unified Tailscale Serve helper — single source of truth for the
|
|
2
2
|
// two transport modes monad-agent uses on macOS:
|
|
3
3
|
//
|
|
4
|
-
// - `https-443` —
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// `pwa-start`). HTTP/2 forwarder · NOT WebSocket-
|
|
8
|
-
// friendly (Upgrade returns 502).
|
|
4
|
+
// - `https-443` — explicit legacy mode on the host's standard HTTPS:443.
|
|
5
|
+
// HTTP/2 forwarding does not preserve WebSocket Upgrade
|
|
6
|
+
// (the daily PWA sharing path no longer selects it).
|
|
9
7
|
//
|
|
10
8
|
// - `tls-tcp` — per-port TLS terminator forwarding plaintext TCP
|
|
11
9
|
// (HTTP/1.1) to a backend on `localhost:<port>`.
|
|
12
|
-
// Used by `pwa
|
|
13
|
-
//
|
|
14
|
-
// (the iPad-side multi-LLM dispatch needs this).
|
|
10
|
+
// Used by `pwa share enable`, `pwa-start` auto-share and
|
|
11
|
+
// `pwa test --https`. WebSocket Upgrade returns 101.
|
|
15
12
|
//
|
|
16
13
|
// Why unify? Before this lift, `defaultServe` (https-443) and
|
|
17
14
|
// `mountTailscaleTestServe` (tls-tcp) duplicated:
|