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
|
@@ -25,6 +25,8 @@ import { classifyPodExitStop, recordRunStop, runStopRecorded, RUN_STOP_EVENT } f
|
|
|
25
25
|
import { ensureOpenRouterChildModelLive, resolveChildLlmEffort, resolveImplementationChildModel } from '../self-dev/dev-cli.js';
|
|
26
26
|
import { resolveHarnessTarget } from '../self-implement/harness-target-options.js';
|
|
27
27
|
import { buildRunProgressRows, isPartialRunningRuns, queryRunningRuns, renderRunProgressTable } from '../self-implement/running-runs.js';
|
|
28
|
+
import { launchBindingRunIds, readLaunchBinding } from './launch-registry.js';
|
|
29
|
+
import { psProcessStartMs } from './harness-stop.js';
|
|
28
30
|
import { DevPipelineError } from '../self-dev/dev-pipeline.js';
|
|
29
31
|
import { collectDraftMetrics, collectOverlapMetrics, DRAFT_SWEEP_CONCURRENCY, mapBounded, resolveDraftSweepCloseCap, runDraftSweep, sweepFailureReason, type DraftSweepAdapters, type DraftSweepResult, type OverlapMetricAdapters, type SweepDraft, type SweepMergedPr, type SweepReviewGate } from '../self-dev/draft-sweep.js';
|
|
30
32
|
import { readAskPreflightRowsSince, readSalvagedRowsSince } from '../self-dev/ask-launch-io.js';
|
|
@@ -303,6 +305,7 @@ function registerHarnessAskSayOptions(command: Command): Command {
|
|
|
303
305
|
.addOption(new Option('--pod-memory <tier>', 'pod: 메모리 등급 — lite(2Gi · 문서·조사·네트워크 스킬 골 · OOM 이면 high 로 한 번 재시도) | standard(16Gi) | high(32Gi) · 없으면 골 문면 `Pod 메모리: <등급>` 한 줄 · 그것도 없으면 골이 apps/pwa/ 를 담을 때 high').choices(['lite', 'standard', 'high']))
|
|
304
306
|
.option('--after <goal-or-pr>', 'pod: 선행 — 이 골 ID(16자) 또는 PR(#N) 이 병합될 때까지 Pod 발사가 큐에서 이유와 함께 기다린다(병합 없이 닫히면 blocked) · 골 문면 `선행: #N` 한 줄과 같다 · 대상 파일만 겹치면 선행이 아니다(경고만)')
|
|
305
307
|
.option('--source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · `--substrate pod` 와 함께')
|
|
308
|
+
.option('--repair-commit-only <expected-head>', 'pod: 기존 PR head에서 수리한 커밋을 bundle로 반환(PR 생성 없음)')
|
|
306
309
|
.option('--bench <id[:sha]>', '벤치 팔 — base 를 bench/<id>/base 로 고정(없으면 sha·생략 시 origin/main 으로 만든다 · 있으면 sha 일치 확인 · 불일치 거부) · 팔 가지 bench/<id>/<arm> · PR 라벨 elanous:bench · PR 직전 main 동기화 생략 · 원장 elanous bench ls <id>');
|
|
307
310
|
}
|
|
308
311
|
|
|
@@ -395,7 +398,7 @@ function assertHarnessChildLlmModel(opts: HarnessAskSayChildLlmOptions): void {
|
|
|
395
398
|
}
|
|
396
399
|
|
|
397
400
|
/** Shared post-parse gate: validate child model before any ask/say early return (including `--dry-run`). */
|
|
398
|
-
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: 'lite' | 'standard' | 'high'; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; seat?: QueueSeat };
|
|
401
|
+
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: 'lite' | 'standard' | 'high'; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; repairCommitOnly?: string; seat?: QueueSeat };
|
|
399
402
|
function resolveLaunchSubstrate(opts: HarnessSubstrateOpts): ResolvedHarnessSubstrate {
|
|
400
403
|
const resolved = resolveHarnessSubstrate({ flag: opts, config: getUserConfig(), env: process.env });
|
|
401
404
|
debug.log('harness.substrate', 'resolved', resolved);
|
|
@@ -691,7 +694,7 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
|
|
|
691
694
|
const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(authorOnPod && entrance === 'cli-harness-say' ? { authorOnPod: true } : {}),
|
|
692
695
|
...(child.childLlmProvider?.trim() ? { childLlmProvider: child.childLlmProvider.trim() } : {}),
|
|
693
696
|
...(child.childLlmModel?.trim() ? { childLlmModel: child.childLlmModel.trim() } : {}),
|
|
694
|
-
...(child.childLlmEffort?.trim() ? { childLlmEffort: child.childLlmEffort.trim() } : {}), ...(authorOnPod && podAuthorGrade ? { authorGrade: podAuthorGrade.grade, authorGradeSource: podAuthorGrade.source } : {}), ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...((opts as HarnessAskSayChildLlmOptions).goalType ? { goalType: (opts as HarnessAskSayChildLlmOptions).goalType } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.seat ? { seat: o.seat } : {}) },
|
|
697
|
+
...(child.childLlmEffort?.trim() ? { childLlmEffort: child.childLlmEffort.trim() } : {}), ...(authorOnPod && podAuthorGrade ? { authorGrade: podAuthorGrade.grade, authorGradeSource: podAuthorGrade.source } : {}), ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...((opts as HarnessAskSayChildLlmOptions).goalType ? { goalType: (opts as HarnessAskSayChildLlmOptions).goalType } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.repairCommitOnly ? { repairCommitOnly: o.repairCommitOnly } : {}), ...(o.seat ? { seat: o.seat } : {}) },
|
|
695
698
|
{ onOutput: (text) => {
|
|
696
699
|
runId ??= harnessPodRunId(output + text);
|
|
697
700
|
output = (output + text).slice(-16_000);
|
|
@@ -892,6 +895,8 @@ async function dispatchHarnessAskSay(
|
|
|
892
895
|
if (isHarnessDryRun(opts)) {
|
|
893
896
|
resolveLaunchSubstrate(opts);
|
|
894
897
|
printHarnessLaunchDryRun(dryRunPreview);
|
|
898
|
+
const repair = opts as HarnessSubstrateOpts;
|
|
899
|
+
if (repair.repairCommitOnly) console.log(`[dry-run] repair forwarding: --pod-source ${repair.source} --repair-commit-only ${repair.repairCommitOnly} --no-auto-merge`);
|
|
895
900
|
return;
|
|
896
901
|
}
|
|
897
902
|
ensureJourneyKey();
|
|
@@ -937,7 +942,7 @@ async function dispatchHarnessAskSay(
|
|
|
937
942
|
['--goal-type', opts.goalType], ...(dryRunPreview.entrance === 'cli-harness-say' ? [['--author-grade', opts.authorGradeSource === 'flag' ? opts.authorGrade : undefined] as [string, string | undefined]] : []), ['--child-llm-provider', opts.childLlmProvider],
|
|
938
943
|
['--child-llm-model', opts.childLlmModel], ['--child-llm-effort', opts.childLlmEffort],
|
|
939
944
|
['--pod-pool', (opts as HarnessSubstrateOpts).podPool], ['--pod-memory', (opts as HarnessSubstrateOpts).podMemory],
|
|
940
|
-
['--after', (opts as HarnessSubstrateOpts).after], ['--source', (opts as HarnessSubstrateOpts).source],
|
|
945
|
+
['--after', (opts as HarnessSubstrateOpts).after], ['--source', (opts as HarnessSubstrateOpts).source], ['--repair-commit-only', (opts as HarnessSubstrateOpts).repairCommitOnly],
|
|
941
946
|
];
|
|
942
947
|
for (const [flag, value] of values) if (value !== undefined) flags.push(flag, value);
|
|
943
948
|
if ((opts as HarnessSubstrateOpts).source !== undefined && resolved.substrate !== 'pod') {
|
|
@@ -1011,8 +1016,9 @@ async function dispatchHarnessAskSay(
|
|
|
1011
1016
|
const previous = process.env.ELANOUS_HARNESS_SEAT;
|
|
1012
1017
|
if (stampedSeat) process.env.ELANOUS_HARNESS_SEAT = stampedSeat;
|
|
1013
1018
|
else delete process.env.ELANOUS_HARNESS_SEAT;
|
|
1014
|
-
//
|
|
1015
|
-
passJourneyNode('dispatch', { ...journey, outcome:
|
|
1019
|
+
// The source label selects the declared author or same-PR rework edge; substrate remains data for decompose.
|
|
1020
|
+
passJourneyNode('dispatch', { ...journey, outcome: (stampedOpts as HarnessSubstrateOpts).repairCommitOnly ? 'pr-source' : 'fresh',
|
|
1021
|
+
data: { substrate: resolved.substrate } });
|
|
1016
1022
|
const benchRow = bench ? recordBenchLaunch(bench, stampedOpts, resolved.substrate, dryRunPreview.entrance, benchDeps) : undefined;
|
|
1017
1023
|
try { await dispatch(resolved, stampedOpts); }
|
|
1018
1024
|
finally {
|
|
@@ -2391,6 +2397,7 @@ const defaultDraftSweepStopRun: DraftSweepStopRun = async (runId) => {
|
|
|
2391
2397
|
export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: DraftSweepGitExecute = runGitCommand, cwd = process.cwd(),
|
|
2392
2398
|
executeAsync: (args: string[]) => Promise<string> = execute === executeGh ? executeGhAsync : async (args) => execute(args),
|
|
2393
2399
|
stopRun: DraftSweepStopRun = defaultDraftSweepStopRun): GithubDraftSweepAdapters {
|
|
2400
|
+
const ensuredSweepLabels = new Set<string>();
|
|
2394
2401
|
const inventory = async (repository: string, state: 'open' | 'closed'): Promise<GithubPull[]> => {
|
|
2395
2402
|
// ⛔ A large repository has tens of thousands of closed PRs (2026-09-28: 21k → «exceeded pagination limit», no sweep at all).
|
|
2396
2403
|
// Merged twins only matter after the oldest open draft was opened, so the closed listing stops at that time.
|
|
@@ -2642,11 +2649,19 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
|
|
|
2642
2649
|
.map((line) => line.slice('branch refs/heads/'.length).trim()));
|
|
2643
2650
|
},
|
|
2644
2651
|
setLabels: async (repository, number, change) => {
|
|
2652
|
+
if (change.add.startsWith('elanous:swept:')) {
|
|
2653
|
+
const key = `${repository}:${change.add}`;
|
|
2654
|
+
if (!ensuredSweepLabels.has(key)) {
|
|
2655
|
+
execute(['label', 'create', change.add, '--repo', repository, '--color', '6A737D',
|
|
2656
|
+
'--description', 'Draft sweep close reason; reopen this PR to restore it', '--force']);
|
|
2657
|
+
ensuredSweepLabels.add(key);
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2645
2660
|
execute(['pr', 'edit', String(number), '--repo', repository, '--add-label', change.add,
|
|
2646
2661
|
...change.remove.flatMap((name) => ['--remove-label', name])]);
|
|
2647
2662
|
},
|
|
2648
|
-
closeDraft: async (repository, number
|
|
2649
|
-
execute(['pr', 'close', String(number), '--repo', repository
|
|
2663
|
+
closeDraft: async (repository, number) => {
|
|
2664
|
+
execute(['pr', 'close', String(number), '--repo', repository]);
|
|
2650
2665
|
},
|
|
2651
2666
|
getClaimOwner: async (repository, number) => claimCommentOwner(repository, number, execute),
|
|
2652
2667
|
getActiveClaimOwner: async (repository, number) => activeClaimOwnerFromBodies(await claimCommentsFor(repository, number)),
|
|
@@ -3137,7 +3152,13 @@ export interface HarnessCliCommandDeps {
|
|
|
3137
3152
|
mission?: HarnessMissionHandler;
|
|
3138
3153
|
missionLoop?: HarnessMissionLoopHandler;
|
|
3139
3154
|
/** `harness progress` 가 도는 런 관측을 읽는 자리(시험 주입). 기본은 queryRunningRuns. */
|
|
3140
|
-
progress?: {
|
|
3155
|
+
progress?: {
|
|
3156
|
+
query?: typeof queryRunningRuns;
|
|
3157
|
+
nowMs?: () => number;
|
|
3158
|
+
bindingRunIds?: typeof launchBindingRunIds;
|
|
3159
|
+
readBinding?: typeof readLaunchBinding;
|
|
3160
|
+
processStartMs?: typeof psProcessStartMs;
|
|
3161
|
+
};
|
|
3141
3162
|
}
|
|
3142
3163
|
|
|
3143
3164
|
export function installHarnessCliCommand(program: Command, deps: HarnessCliCommandDeps): Command {
|
|
@@ -3198,8 +3219,33 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3198
3219
|
});
|
|
3199
3220
|
harnessCmd.command('progress').description('도는 골마다 진도를 한 표로 읽는다 — 단계 · 진입 시각 · 마지막 진전 · pty (읽기 전용)')
|
|
3200
3221
|
.option('--json', '같은 행 배열을 JSON 으로 출력')
|
|
3201
|
-
.
|
|
3222
|
+
.option('--pid <number>', '기록된 로컬 PID 에 연결된 런 한 건만 조회')
|
|
3223
|
+
.action((opts: { json?: boolean; pid?: string }) => {
|
|
3202
3224
|
try {
|
|
3225
|
+
if (opts.pid !== undefined) {
|
|
3226
|
+
const pid = Number(opts.pid);
|
|
3227
|
+
if (!Number.isSafeInteger(pid) || pid <= 1) {
|
|
3228
|
+
console.error('❌ --pid 는 2 이상의 정수여야 합니다');
|
|
3229
|
+
process.exitCode = 2;
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
const bindings = (deps.progress?.bindingRunIds ?? launchBindingRunIds)()
|
|
3233
|
+
.map((runId) => ({ runId, binding: (deps.progress?.readBinding ?? readLaunchBinding)(runId) }))
|
|
3234
|
+
.filter(({ binding }) => binding?.pid === pid);
|
|
3235
|
+
const binding = bindings.length === 1 && !bindings[0]!.binding?.podName ? bindings[0] : undefined;
|
|
3236
|
+
const startedAt = binding ? (deps.progress?.processStartMs ?? psProcessStartMs)(pid) : null;
|
|
3237
|
+
// ps lstart has second precision. A wider stop-oriented tolerance would attribute a reused PID to this run.
|
|
3238
|
+
const observed = binding && startedAt !== null
|
|
3239
|
+
&& startedAt === Math.floor(binding.binding!.startedAt / 1_000) * 1_000;
|
|
3240
|
+
const result = observed
|
|
3241
|
+
? (deps.progress?.query ?? queryRunningRuns)({ runIds: [binding.runId], caller: 'harness.progress.pid' })
|
|
3242
|
+
: null;
|
|
3243
|
+
const row = result ? buildRunProgressRows(result, (deps.progress?.nowMs ?? Date.now)())
|
|
3244
|
+
.find((item) => item.runId === binding!.runId && item.status !== 'ended-unclosed' && item.status !== 'unknown') : undefined;
|
|
3245
|
+
if (opts.json) console.log(JSON.stringify({ pid, observation: row ? 'observed' : 'unobserved', runId: row?.runId ?? null, progress: row ?? null }));
|
|
3246
|
+
else console.log(row ? `pid ${pid} · ${renderRunProgressTable({ ...result!, entries: result!.entries.filter((item) => item.runId === row.runId) }, (deps.progress?.nowMs ?? Date.now)()).split('\n').slice(1).join('\n')}` : `pid ${pid} · 미관측`);
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
3203
3249
|
const result = (deps.progress?.query ?? queryRunningRuns)({ caller: 'harness.progress' });
|
|
3204
3250
|
const nowMs = (deps.progress?.nowMs ?? Date.now)();
|
|
3205
3251
|
if (opts.json) {
|
|
@@ -3300,6 +3346,11 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3300
3346
|
if (ask) {
|
|
3301
3347
|
registerHarnessAskSayOptions(harnessCmd.command('ask <goal-path>').description('골 문서 경로를 받아 구동한다'))
|
|
3302
3348
|
.action(async (goalPath: string, opts: HarnessAskSayChildLlmOptions & HarnessDryRunOpts) => {
|
|
3349
|
+
if ((opts as HarnessSubstrateOpts).repairCommitOnly !== undefined) {
|
|
3350
|
+
console.error('--repair-commit-only is supported only by harness say');
|
|
3351
|
+
process.exitCode = 2;
|
|
3352
|
+
return;
|
|
3353
|
+
}
|
|
3303
3354
|
await dispatchHarnessAskSay(
|
|
3304
3355
|
opts,
|
|
3305
3356
|
{
|
|
@@ -3328,6 +3379,13 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3328
3379
|
registerHarnessAskSayOptions(harnessCmd.command('say <sentence...>').description('문장을 받아 구동한다'))
|
|
3329
3380
|
.addOption(new Option('--author-grade <grade>', 'say 저작 등급 (full|lite)').choices(['full', 'lite']))
|
|
3330
3381
|
.action(async (sentence: string[], opts: HarnessAskSayChildLlmOptions & HarnessDryRunOpts) => {
|
|
3382
|
+
const repair = opts as HarnessSubstrateOpts;
|
|
3383
|
+
if (repair.repairCommitOnly !== undefined && (repair.substrate !== 'pod' || !/^pr:[1-9]\d*$/.test(repair.source ?? '')
|
|
3384
|
+
|| !/^[0-9a-f]{40}$/.test(repair.repairCommitOnly) || repair.autoMerge !== false || repair.target !== undefined)) {
|
|
3385
|
+
console.error('--repair-commit-only requires --substrate pod --source pr:N --no-auto-merge and a 40-hex expected head');
|
|
3386
|
+
process.exitCode = 2;
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3331
3389
|
const grade = resolveGoalAuthorGrade(opts.authorGrade, getUserConfig().harness?.authorGrade);
|
|
3332
3390
|
const podSource = process.env.ELANOUS_POD_AUTHOR_ON_POD === '1' && process.env.ELANOUS_POD_AUTHOR_GRADE === grade.grade
|
|
3333
3391
|
? process.env.ELANOUS_POD_AUTHOR_GRADE_SOURCE : undefined;
|
|
@@ -3348,7 +3406,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
3348
3406
|
return Promise.resolve();
|
|
3349
3407
|
}
|
|
3350
3408
|
return resolved.substrate === 'pod'
|
|
3351
|
-
? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask, harnessAuthorOnPod())
|
|
3409
|
+
? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask, !(opts as HarnessSubstrateOpts).repairCommitOnly && harnessAuthorOnPod())
|
|
3352
3410
|
: (announceLocalChildProvider(stampedOpts), say(sentence, normalizeHarnessAskSayOptions(stampedOpts)));
|
|
3353
3411
|
},
|
|
3354
3412
|
deps.launchGate, queueDeps, immediateLaunch, queueDeps.launch ? undefined : immediateExit, deps.bench,
|
|
@@ -43,6 +43,8 @@ export interface HarnessPodDispatchInput {
|
|
|
43
43
|
readonly json?: boolean;
|
|
44
44
|
/** 사람이 고른 원천 spec — `commit:` · `pr:` · `worktree:` · `files:`. 검증은 발사 전. */
|
|
45
45
|
readonly source?: string;
|
|
46
|
+
/** Existing PR head for a commit-only repair. Requires source pr:N. */
|
|
47
|
+
readonly repairCommitOnly?: string;
|
|
46
48
|
/** `--child-llm-provider/--child-llm-model/--child-llm-effort` — carried to `self orchestrate` so the Pod child uses them (10-05 PODPROVIDER). */
|
|
47
49
|
readonly childLlmProvider?: string;
|
|
48
50
|
readonly childLlmModel?: string;
|
|
@@ -59,10 +61,11 @@ export function podOrchestrateArgs(input: HarnessPodDispatchInput, goalFile: str
|
|
|
59
61
|
'--substrate', 'pod',
|
|
60
62
|
...(input.podPool ? ['--pod-pool', input.podPool] : []),
|
|
61
63
|
// 하니스 기본(자동 병합)을 따른다 · 끄면 PR 까지 — 어느 쪽이든 Pod 가 사라져도 결과가 남는다.
|
|
62
|
-
...(input.autoMerge === false ? ['--open-pr'] : ['--auto-merge']),
|
|
63
|
-
...(input.base ? ['--base', input.base] : []),
|
|
64
|
+
...(input.repairCommitOnly ? [] : input.autoMerge === false ? ['--open-pr'] : ['--auto-merge']),
|
|
65
|
+
...(input.repairCommitOnly && input.source ? ['--base', `pr-${input.source.slice(3)}`] : input.base ? ['--base', input.base] : []),
|
|
64
66
|
...(input.json ? ['--json'] : []),
|
|
65
67
|
...(input.source ? ['--pod-source', input.source] : []),
|
|
68
|
+
...(input.repairCommitOnly ? ['--repair-commit-only', input.repairCommitOnly] : []),
|
|
66
69
|
...(input.childLlmProvider?.trim() ? ['--child-llm-provider', input.childLlmProvider.trim()] : []),
|
|
67
70
|
...(input.childLlmModel?.trim() ? ['--child-llm-model', input.childLlmModel.trim()] : []),
|
|
68
71
|
...(input.childLlmEffort?.trim() ? ['--child-llm-effort', input.childLlmEffort.trim()] : []),
|
|
@@ -85,6 +88,10 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
85
88
|
return 2;
|
|
86
89
|
}
|
|
87
90
|
}
|
|
91
|
+
if (input.repairCommitOnly && (!/^pr:[1-9]\d*$/.test(input.source ?? '') || !/^[0-9a-f]{40}$/.test(input.repairCommitOnly) || input.autoMerge === true)) {
|
|
92
|
+
debug.log('harness.substrate', 'repair-refused', { entrance: input.entrance, reason: 'requires pr source, 40-hex head, and no auto-merge' });
|
|
93
|
+
return 2;
|
|
94
|
+
}
|
|
88
95
|
const env = { ...process.env, ...oldDoorInternalEnv('self-orchestrate') };
|
|
89
96
|
// POD-OBS(10-06): 자식 orchestrate 는 트리 파생 우주에서 돈다 — Pod 원장 재방출을 «발사한 집»의 logs.db 에도 남기게 경로를 넘긴다.
|
|
90
97
|
env[POD_REEMIT_LOGS_DB_ENV] = logsDbPath();
|
|
@@ -146,7 +153,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
146
153
|
memoryLimit: podMemoryLimitFor(goalText, env).limit });
|
|
147
154
|
delete env.ELANOUS_POD_AFTER;
|
|
148
155
|
if (input.after) env.ELANOUS_POD_AFTER = input.after;
|
|
149
|
-
if (input.authorOnPod) env.ELANOUS_POD_AUTHOR_ON_POD = '1';
|
|
156
|
+
if (input.authorOnPod && !input.repairCommitOnly) env.ELANOUS_POD_AUTHOR_ON_POD = '1';
|
|
150
157
|
else delete env.ELANOUS_POD_AUTHOR_ON_POD;
|
|
151
158
|
if (input.authorOnPod && input.authorGrade) {
|
|
152
159
|
env.ELANOUS_POD_AUTHOR_GRADE = input.authorGrade;
|
|
@@ -157,7 +164,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
157
164
|
delete env.ELANOUS_POD_AUTHOR_GRADE;
|
|
158
165
|
delete env.ELANOUS_POD_AUTHOR_GRADE_SOURCE;
|
|
159
166
|
}
|
|
160
|
-
if (input.entrance === 'cli-harness-ask') {
|
|
167
|
+
if (input.entrance === 'cli-harness-ask' && !input.repairCommitOnly) {
|
|
161
168
|
const root = findGitDir(cwd)?.root;
|
|
162
169
|
const path = resolve(cwd, input.input);
|
|
163
170
|
const relativePath = root ? relative(realpathSync(root), realpathSync(path)) : '';
|
|
@@ -81,7 +81,7 @@ export function discoverStopProcesses(runId: string, goalPath: string | null, ta
|
|
|
81
81
|
const match = /^\s*(\d+)\s+((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+\w+\s+\d+\s+\d\d:\d\d:\d\d\s+\d{4})\s+(.+)$/.exec(line);
|
|
82
82
|
if (!match) return { status: 'failed', reason: 'unparseable process table row' };
|
|
83
83
|
const pid = Number(match[1]);
|
|
84
|
-
const startedAt = Date.parse(match[2]!);
|
|
84
|
+
const startedAt = Date.parse(`${match[2]!} GMT`);
|
|
85
85
|
if (!Number.isSafeInteger(pid) || !Number.isFinite(startedAt)) return { status: 'failed', reason: 'invalid process table row' };
|
|
86
86
|
if (pid <= 1) continue;
|
|
87
87
|
const args = match[3]!.match(/"[^"]*"|'[^']*'|\S+/g)?.map((part) => part.replace(/^(['"])(.*)\1$/, '$2')) ?? [];
|
|
@@ -132,7 +132,9 @@ function stopProcessCwd(pid: number): string | null {
|
|
|
132
132
|
|
|
133
133
|
function scanStopProcessTable(runId: string, goalPath: string | null): StopProcessScan {
|
|
134
134
|
let r: ReturnType<typeof spawnSync>;
|
|
135
|
-
try { r = spawnSync('ps', ['-eo', 'pid=,lstart=,args='], {
|
|
135
|
+
try { r = spawnSync('ps', ['-eo', 'pid=,lstart=,args='], {
|
|
136
|
+
encoding: 'utf8', timeout: 5_000, maxBuffer: 16 * 1024 * 1024, env: { ...process.env, TZ: 'UTC' },
|
|
137
|
+
}); }
|
|
136
138
|
catch (error) { return { status: 'failed', reason: String(error) }; }
|
|
137
139
|
if (r.error || r.status !== 0 || typeof r.stdout !== 'string') return { status: 'failed', reason: String(r.error ?? r.stderr ?? `ps status ${r.status}`) };
|
|
138
140
|
return discoverStopProcesses(runId, goalPath, r.stdout, stopProcessCwd);
|
|
@@ -201,13 +203,15 @@ export function pidRecordFromLaunchBinding(runId: string, registryDir = launchRe
|
|
|
201
203
|
return { pid: binding.pid, startedAt: binding.startedAt, ...(binding.argv0 ? { argv0: binding.argv0 } : {}) };
|
|
202
204
|
}
|
|
203
205
|
|
|
204
|
-
/** macOS·Linux 공통 —
|
|
206
|
+
/** macOS·Linux 공통 — UTC 시작 시각과 상태를 같은 ps 관측에서 읽는다. */
|
|
205
207
|
export function psProcessStartMs(pid: number): number | null {
|
|
206
|
-
const r = spawnSync('ps', ['-o', 'lstart=', '-p', String(pid)], {
|
|
208
|
+
const r = spawnSync('ps', ['-o', 'lstart=,stat=', '-p', String(pid)], {
|
|
209
|
+
encoding: 'utf8', timeout: 5_000, env: { ...process.env, TZ: 'UTC' },
|
|
210
|
+
});
|
|
207
211
|
if (r.status !== 0) return null;
|
|
208
|
-
const
|
|
209
|
-
if (!
|
|
210
|
-
const ms = Date.parse(
|
|
212
|
+
const match = /^\s*((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+\w+\s+\d+\s+\d\d:\d\d:\d\d\s+\d{4})\s+(\S+)\s*$/.exec(r.stdout);
|
|
213
|
+
if (!match || match[2]!.startsWith('Z')) return null;
|
|
214
|
+
const ms = Date.parse(`${match[1]!} GMT`);
|
|
211
215
|
return Number.isFinite(ms) ? ms : null;
|
|
212
216
|
}
|
|
213
217
|
|
package/src/hq/seats.ts
CHANGED
|
@@ -278,6 +278,18 @@ export function hqInit(options: { root?: string; home?: string } = {}): { root:
|
|
|
278
278
|
return { root, created, cron };
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
// A skipped refresh leaves the seat looking idle to every other surface: one observation line carries the
|
|
282
|
+
// reason and how far the kept HEAD trails the fetched origin/main. Observation never changes the verdict
|
|
283
|
+
// (same rule as judgeLandedTip).
|
|
284
|
+
function observeRefreshSkipped(path: string, role: HqSeatRole, reason: 'dirty' | 'unlanded-head', head?: string): void {
|
|
285
|
+
try {
|
|
286
|
+
const tip = head ?? git(path, 'rev-parse', 'HEAD');
|
|
287
|
+
const behind = runGitCommand(path, ['rev-list', '--count', 'HEAD..refs/remotes/origin/main'], { encoding: 'utf8' });
|
|
288
|
+
const count = behind.status === 0 && /^\d+$/.test(behind.stdout.trim()) ? Number(behind.stdout.trim()) : null;
|
|
289
|
+
debug.log('hq.seat', 'refresh-skipped', { role, path, reason, head: tip, behind: count });
|
|
290
|
+
} catch { /* observation must not change the verdict */ }
|
|
291
|
+
}
|
|
292
|
+
|
|
281
293
|
export function hqSeat(value: string, options: { root?: string; refresh?: boolean } = {}): { path: string; outcome: 'created' | 'unchanged' | 'refreshed' | 'dirty' } {
|
|
282
294
|
const role = roleOf(value);
|
|
283
295
|
const root = resolve(options.root ?? hqRoot());
|
|
@@ -301,16 +313,18 @@ export function hqSeat(value: string, options: { root?: string; refresh?: boolea
|
|
|
301
313
|
const onBranch = runGitCommand(path, ['symbolic-ref', '--quiet', '--short', 'HEAD'], { encoding: 'utf8' });
|
|
302
314
|
if (onBranch.status === 0) throw new Error(`not a seat: ${path} is on branch ${onBranch.stdout.trim()}; refusing to touch it`);
|
|
303
315
|
// A dirty seat must be byte-for-byte untouched, including its detached HEAD.
|
|
304
|
-
|
|
316
|
+
// The cron line fetches the mirror before refreshing, so `behind` counts against the fetched origin/main.
|
|
317
|
+
if (options.refresh && !clean(path)) { observeRefreshSkipped(path, role, 'dirty'); return { path, outcome: 'dirty' }; }
|
|
305
318
|
if (!options.refresh) return { path, outcome: 'unchanged' };
|
|
306
319
|
git(repo, 'fetch', 'origin');
|
|
307
320
|
// Concurrent refreshes of one seat (cron and a person) serialize on the house lock; each re-checks first.
|
|
308
321
|
return withLedgerLock(root, () => {
|
|
309
322
|
assertRegisteredWorktree(repo, path);
|
|
310
323
|
if (runGitCommand(path, ['symbolic-ref', '--quiet', 'HEAD'], { encoding: 'utf8' }).status === 0) throw new Error(`not a seat: ${path} is on a branch; refusing to touch it`);
|
|
311
|
-
if (!clean(path)) return { path, outcome: 'dirty' as const };
|
|
324
|
+
if (!clean(path)) { observeRefreshSkipped(path, role, 'dirty'); return { path, outcome: 'dirty' as const }; }
|
|
312
325
|
// Commits made on the detached seat are not on origin/main; moving HEAD would orphan them. Treat as dirty.
|
|
313
|
-
|
|
326
|
+
const head = git(path, 'rev-parse', 'HEAD');
|
|
327
|
+
if (!mergedIntoMain(repo, head)) { observeRefreshSkipped(path, role, 'unlanded-head', head); return { path, outcome: 'dirty' as const }; }
|
|
314
328
|
git(path, 'checkout', '--detach', 'refs/remotes/origin/main');
|
|
315
329
|
return { path, outcome: 'refreshed' as const };
|
|
316
330
|
});
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { DEV_PIPELINE_SINK_SURFACE } from './self-implement/self-cli-sink-surfac
|
|
|
38
38
|
import { registerPrivateLedgerCommands } from './cli/private-ledger-commands.js';
|
|
39
39
|
import { registerKnowCommand } from './cli/know-cli.js';
|
|
40
40
|
import { registerSeatRequestsCommands } from './cli/seat-requests-cli.js';
|
|
41
|
+
import { registerSeatBootCommands } from './cli/seat-cli.js';
|
|
41
42
|
import { applyTestStateDirFlagFromArgv } from './cli/test-state-dir-flag.js';
|
|
42
43
|
import { applyTestFlagFromArgv, observeTestFlagOwnership, uncoveredTestFlagPaths, staleTestFlagPaths } from './cli/test-flag.js';
|
|
43
44
|
import { registerPtyTakeoverCommands } from './cli/pty-takeover-cli.js';
|
|
@@ -1118,6 +1119,7 @@ hqCmd.command('fence').description('이 호스트가 임대를 쥐었을 때만
|
|
|
1118
1119
|
process.exitCode = hqFenceRun(opts.role as 'cron', command);
|
|
1119
1120
|
});
|
|
1120
1121
|
const seatCmd = program.command('seat').description('분배된 자리의 하루 루프와 보고');
|
|
1122
|
+
registerSeatBootCommands(seatCmd);
|
|
1121
1123
|
registerSeatRequestsCommands(seatCmd);
|
|
1122
1124
|
seatCmd.command('asks').description('최근 CTO 되묻기 왕복과 10분 판정')
|
|
1123
1125
|
.option('--since <duration>', '조회 창 (예: 24h)', '24h')
|
|
@@ -2394,18 +2396,20 @@ harnessCmd
|
|
|
2394
2396
|
.description('하니스 disposable worktree + 브랜치 정리(기본 접두는 만드는 쪽 상수에서 온다). ⚠️ 열린 PR 은 항상 보존. 기본 dry-run(계획만·--yes 로 실제 제거).')
|
|
2395
2397
|
.option('--abandoned', 'PR 이력 없는 것(escalated/방치) 제거 [기본]')
|
|
2396
2398
|
.option('--merged', 'PR 머지된 것 제거')
|
|
2399
|
+
.option('--include-unowned-merged-clean', '미소유 merged-clean worktree 회수 허용(merged 모드 전용)')
|
|
2397
2400
|
.option('--all', '열린 PR 외 전부 제거')
|
|
2398
2401
|
.option('--force', '열린 PR 브랜치도 제거(위험)')
|
|
2399
2402
|
.option('--yes', '실제 제거(생략 시 dry-run)')
|
|
2400
2403
|
.option('--prefix <p>', `브랜치 prefix(기본 ${WORKTREE_BRANCH_PREFIX_HELP})`)
|
|
2401
2404
|
.option('--repo <repo>', 'gh repo(기본 origin 추론)')
|
|
2402
2405
|
.option('--json', '구조화 출력')
|
|
2403
|
-
.action(async (opts: { abandoned?: boolean; merged?: boolean; all?: boolean; force?: boolean; yes?: boolean; prefix?: string; repo?: string; json?: boolean }) => {
|
|
2406
|
+
.action(async (opts: { abandoned?: boolean; merged?: boolean; all?: boolean; force?: boolean; includeUnownedMergedClean?: boolean; yes?: boolean; prefix?: string; repo?: string; json?: boolean }) => {
|
|
2404
2407
|
const { execHarnessClean } = await import('./harness/harness-clean.js');
|
|
2405
2408
|
const mode = opts.all ? 'all' : opts.merged ? 'merged' : 'abandoned';
|
|
2406
2409
|
const res = execHarnessClean({
|
|
2407
2410
|
mode, dryRun: !opts.yes,
|
|
2408
2411
|
...(opts.force ? { force: true } : {}),
|
|
2412
|
+
...(opts.includeUnownedMergedClean ? { includeUnownedMergedClean: true } : {}),
|
|
2409
2413
|
...(opts.prefix ? { branchPrefix: opts.prefix } : {}),
|
|
2410
2414
|
...(opts.repo ? { repo: opts.repo } : {}),
|
|
2411
2415
|
});
|
|
@@ -3352,6 +3356,20 @@ coordCmd.command('events')
|
|
|
3352
3356
|
});
|
|
3353
3357
|
|
|
3354
3358
|
const selfCmd = program.command('self').description('Self-awareness memory — 외부 도구(Claude Code/Codex)가 구현/변경 이력을 elanous 기억에 주입·회상');
|
|
3359
|
+
selfCmd.command('repair-commit-export <pr> <base-head> <child-output> <repo> <outbox>')
|
|
3360
|
+
.description('Pod commit-only repair artifact exporter (installed CLI)')
|
|
3361
|
+
.action(async (pr: string, baseHead: string, outputPath: string, repo: string, outbox: string) => {
|
|
3362
|
+
const { readFileSync } = await import('node:fs');
|
|
3363
|
+
const { writePodRepairCommit } = await import('./task-orchestrator/surfaces/pod-repair-commit.js');
|
|
3364
|
+
try {
|
|
3365
|
+
const result = writePodRepairCommit({ pr: Number(pr), baseHead, runId: process.env.ELANOUS_PARENT_RUN_ID ?? '', output: readFileSync(outputPath, 'utf8'), repo, outbox });
|
|
3366
|
+
console.log(`ELANOUS_POD_REPAIR_COMMIT ${result.pr} ${result.baseHead} ${result.commit}`);
|
|
3367
|
+
} catch (error) {
|
|
3368
|
+
console.error(`ELANOUS_POD_REPAIR_FAILED ${error instanceof Error ? error.message : String(error)}`);
|
|
3369
|
+
process.exitCode = 1;
|
|
3370
|
+
}
|
|
3371
|
+
});
|
|
3372
|
+
{ const { registerSelfUtterancesCommand } = await import('./cli/self-utterances-cli.js'); registerSelfUtterancesCommand(selfCmd); }
|
|
3355
3373
|
|
|
3356
3374
|
// M12 Claude Code 의존도 계기판 — `elanous self dependence [--since] [--until] [--json]`(읽기만).
|
|
3357
3375
|
{ const { registerDependenceCommand } = await import('./cli/dependence-gauge.js'); registerDependenceCommand(selfCmd); }
|
|
@@ -4377,6 +4395,7 @@ selfCmd
|
|
|
4377
4395
|
.option('--base <branch>', 'PR base 브랜치(생략 시 provider 기본)')
|
|
4378
4396
|
.option('--no-draft', 'non-draft PR (기본 draft)')
|
|
4379
4397
|
.option('--open-pr', 'gate 통과 후 push + draft PR open (기본: PR 안 열고 worktree 보존·fail-closed). 이 플래그가 HITL 명시 승인.')
|
|
4398
|
+
.addOption(new Option('--no-open-pr', '수리 실행: PR 개설 없이 worktree-only로 종료').default(undefined))
|
|
4380
4399
|
.option('--auto-merge', '★ 내부 리뷰가 clean(실제 리뷰 완료·verdict≠fail)이면 자동 병합(squash). must-fix 있으면 무시(hold·rework). outward-facing(main 병합)이라 명시 opt-in. 미지정=리뷰 후 HITL/draft.')
|
|
4381
4400
|
.option('--merge-by-host', 'Pod 자식: 병합 직전 merge-ready 로 끝내 호스트가 재게이트한 뒤 병합')
|
|
4382
4401
|
.option('--child-llm-provider <id>', '구현 자식 LLM provider(--child-llm-model 과 함께 · Pod 의 grok 폴백이 쓴다)')
|
|
@@ -4562,6 +4581,13 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4562
4581
|
ui.error(refused.message);
|
|
4563
4582
|
process.exit(refused.exitCode);
|
|
4564
4583
|
}
|
|
4584
|
+
const repairRequested = (opts as { repairCommitOnly?: string }).repairCommitOnly;
|
|
4585
|
+
if (repairRequested !== undefined && ((opts as { substrate?: string }).substrate !== 'pod'
|
|
4586
|
+
|| !/^pr:[1-9]\d*$/.test((opts as { podSource?: string }).podSource ?? '')
|
|
4587
|
+
|| !/^[0-9a-f]{40}$/.test(repairRequested) || opts.openPr || opts.autoMerge)) {
|
|
4588
|
+
ui.error('--repair-commit-only: --substrate pod, --pod-source pr:N, 40-hex expected head, PR/자동 병합 없음이 필요합니다');
|
|
4589
|
+
process.exit(2);
|
|
4590
|
+
}
|
|
4565
4591
|
// 위치 인자는 종전처럼 분리하고 파일 입력은 파일당 한 골이다.
|
|
4566
4592
|
let inputGoals: ReturnType<typeof readSelfOrchestrateGoals>;
|
|
4567
4593
|
try { inputGoals = readSelfOrchestrateGoals(parts, opts.goalFile); }
|
|
@@ -5011,6 +5037,10 @@ const selfOrchestrateCmd = selfCmd
|
|
|
5011
5037
|
}
|
|
5012
5038
|
const passEnv = podProvider === 'grok' ? requestedPassEnv.filter((key) => !grokKeyNames.includes(key)) : podProvider === 'openrouter' ? [...new Set([...requestedPassEnv, 'OPENROUTER_API_KEY'])] : podProvider === 'anthropic' ? [...new Set([...requestedPassEnv, 'ANTHROPIC_API_KEY'])] : requestedPassEnv;
|
|
5013
5039
|
const podSourceSpec = (opts as { podSource?: string }).podSource;
|
|
5040
|
+
const repairBaseHead = (opts as { repairCommitOnly?: string }).repairCommitOnly;
|
|
5041
|
+
if (repairBaseHead && (!/^pr:[1-9]\d*$/.test(podSourceSpec ?? '') || !/^[0-9a-f]{40}$/.test(repairBaseHead) || opts.autoMerge || opts.openPr || goalTexts.length !== 1)) {
|
|
5042
|
+
ui.error('--repair-commit-only: --pod-source pr:N, 40-hex expected head, 골 1개, PR/자동 병합 없음이 필요합니다'); process.exit(2);
|
|
5043
|
+
}
|
|
5014
5044
|
let podSource: import('./task-orchestrator/surfaces/pod-source-receive.js').PodSource | undefined;
|
|
5015
5045
|
if (podSourceSpec) {
|
|
5016
5046
|
const { parsePodSourceSpec, resolvePodSource } = await import('./task-orchestrator/surfaces/pod-source-spec.js');
|
|
@@ -5033,7 +5063,7 @@ const selfOrchestrateCmd = selfCmd
|
|
|
5033
5063
|
if (childFlags.childLlmProvider?.trim()) debug.log('self-implement.pod', 'child-provider-named', { provider: childFlags.childLlmProvider.trim(), model: childFlags.childLlmModel ?? null, podProvider });
|
|
5034
5064
|
// BEDROCK-POD-PROVIDER-DROP — provider·account 는 한 곳(podLaunchProviderOptions)에서 — 손 나열이 bedrock 을 떨궈 codex(team)로 돌았다(10-11).
|
|
5035
5065
|
const podProviderOptions = (await import('./task-orchestrator/surfaces/pod-child-providers.js')).podLaunchProviderOptions(podProvider, { explicitPodAccount, grokApiKeyOptIn });
|
|
5036
|
-
const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), ...podProviderOptions, ...(accountBroker ? { accountBroker, rotationAccounts } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}) };
|
|
5066
|
+
const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), ...podProviderOptions, ...(accountBroker ? { accountBroker, rotationAccounts } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}), ...(repairBaseHead && podSource?.kind === 'pr' ? { repairCommitOnly: { pr: podSource.number, baseHead: repairBaseHead } } : {}) };
|
|
5037
5067
|
if (benchArms) {
|
|
5038
5068
|
const { benchPodSpawn } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
|
|
5039
5069
|
podSpawn = benchPodSpawn(benchArms, podBase);
|
|
@@ -5143,7 +5173,8 @@ selfOrchestrateCmd
|
|
|
5143
5173
|
.addOption(new Option('--no-supervise', '⛔ 런 슈퍼바이저를 «끈다»(대표 2026-08-22 ***기본 ON***) — 켜져 있으면 런이 끝나면 실패를 «트리아지»해서 다시 걸 것이 있으면 «스스로» 재개한다(골루프처럼 끝까지). 정지 사유는 converged|needs-human|max-rounds|no-progress 로 각각 «다른 값»으로 말한다. 관측=elanous logs --category self-dev.supervisor').hideHelp())
|
|
5144
5174
|
.addOption(new Option('--supervise-rounds <n>', '슈퍼바이저 재개 라운드 상한 (기본 3 · 끄려면 --no-supervise)').hideHelp())
|
|
5145
5175
|
.addOption(new Option('--json', '구조화 출력 [{taskId, feature, status, stage?, prUrl?, merged?, error?}]').hideHelp())
|
|
5146
|
-
.addOption(new Option('--pod-source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · 없으면 기본 clone').hideHelp())
|
|
5176
|
+
.addOption(new Option('--pod-source <spec>', 'pod: 원천 — commit:<40자 sha> | pr:<정수> | worktree:<경로> | files:<경로>[,<경로>…] · 없으면 기본 clone').hideHelp())
|
|
5177
|
+
.addOption(new Option('--repair-commit-only <expected-head>', 'pod: 기존 PR head에서 재작업하고 PR 생성 없이 커밋 bundle을 돌려준다').hideHelp());
|
|
5147
5178
|
|
|
5148
5179
|
function formatRelativeAge(updatedAt: number, now = Date.now()): string {
|
|
5149
5180
|
const seconds = Math.floor(Math.max(0, now - updatedAt) / 1000);
|
|
@@ -5646,7 +5677,8 @@ selfCmd
|
|
|
5646
5677
|
.option('--context <path>', '리뷰어가 함께 판단할 레포 상대 파일 경로(반복 가능)', (value: string, previous: string[] = []) => [...previous, value])
|
|
5647
5678
|
.option('--context-text <text>', '리뷰어가 함께 판단할 텍스트(반복 가능)', (value: string, previous: string[] = []) => [...previous, value])
|
|
5648
5679
|
.option('--json', '구조화 출력 {pr, verdict, mustFix, shouldFix, reviewed}')
|
|
5649
|
-
.
|
|
5680
|
+
.option('--save <name>', '리뷰 결과를 상태 디렉터리의 review-results/<name>-<PR>-<head12>.json에 저장')
|
|
5681
|
+
.action(async (prParts: string[], opts: { intent?: string; model?: string; acp?: boolean; acpModel?: string; acpBackend?: string; acpTimeout?: string; context?: string[]; contextText?: string[]; json?: boolean; save?: string }) => {
|
|
5650
5682
|
const prArgs = prParts.flatMap((p) => String(p).split(/[,\s]+/).filter(Boolean)); // 번호/#번호/URL·콤마목록.
|
|
5651
5683
|
if (!prArgs.length) { ui.error('PR 필요: elanous self review <번호|URL> [..]'); process.exit(2); }
|
|
5652
5684
|
// ⭐ 본문은 seam(`runSelfReviewCliCommand`)에 있다 — 이 액션은 **의존 배선만** 한다.
|
|
@@ -5744,6 +5776,19 @@ selfCmd
|
|
|
5744
5776
|
envModel: () => process.env.ELANOUS_PR_REVIEW_MODEL,
|
|
5745
5777
|
});
|
|
5746
5778
|
if (opts.json) await writeStdoutJson(selfReviewJsonLine(results));
|
|
5779
|
+
// Detached TA review: stdout is now complete in its result file. Resume only the bound card.
|
|
5780
|
+
try {
|
|
5781
|
+
const { rejudgeCompletedTaskReview, TA_REVIEW_COMPLETION_CARD_ENV, TA_REVIEW_COMPLETION_STATE_ENV, TA_REVIEW_COMPLETION_RESULT_ENV } = await import('./task-agent/review-result-capture.js');
|
|
5782
|
+
const completionEnv: Record<string, string | undefined> = {};
|
|
5783
|
+
for (const key of [TA_REVIEW_COMPLETION_CARD_ENV, TA_REVIEW_COMPLETION_STATE_ENV, TA_REVIEW_COMPLETION_RESULT_ENV]) {
|
|
5784
|
+
const value = process.env[key];
|
|
5785
|
+
if (value) completionEnv[key] = value;
|
|
5786
|
+
delete process.env[key];
|
|
5787
|
+
}
|
|
5788
|
+
await rejudgeCompletedTaskReview(completionEnv);
|
|
5789
|
+
} catch (error) {
|
|
5790
|
+
try { debug.log('task-agent', 'review-completion-rejudge-failed', { reason: String(error).slice(-300) }, { level: 'warn' }); } catch { /* fail-soft */ }
|
|
5791
|
+
}
|
|
5747
5792
|
if (failed >= 1) process.exitCode = 1;
|
|
5748
5793
|
});
|
|
5749
5794
|
|
|
@@ -5822,22 +5867,25 @@ selfCmd
|
|
|
5822
5867
|
.description('외부 도구 발화를 elanous 기억에 주입 — origin/git/branch/cwd/시간 태그(회상이 "누가 언제 어디서" 구분). text=--text 또는 stdin')
|
|
5823
5868
|
.option('-s, --text <text>', '발화 원문(생략 시 stdin)')
|
|
5824
5869
|
.option('--source <origin>', 'claude-code|codex|gemini|…', 'claude-code')
|
|
5870
|
+
.option('--origin <origin>', '발화 주체: human|agent (기본 agent)')
|
|
5825
5871
|
.option('--session <id>', '세션 id')
|
|
5826
5872
|
.option('--git-hash <hash>', '발화 시점 git HEAD(short)')
|
|
5827
5873
|
.option('--branch <name>', 'git 브랜치')
|
|
5828
5874
|
.option('--cwd <dir>', '작업 디렉토리')
|
|
5829
5875
|
.option('--ts <iso>', 'ISO 시간(기본 now)')
|
|
5830
5876
|
.option('-i, --importance <n>', '0-10 현저성', '5')
|
|
5831
|
-
.action(async (opts: { text?: string; source: string; session?: string; gitHash?: string; branch?: string; cwd?: string; ts?: string; importance: string }) => {
|
|
5877
|
+
.action(async (opts: { text?: string; source: string; origin?: string; session?: string; gitHash?: string; branch?: string; cwd?: string; ts?: string; importance: string }) => {
|
|
5878
|
+
if (opts.origin !== undefined && opts.origin !== 'human' && opts.origin !== 'agent') { ui.error('utterance: --origin must be human or agent'); process.exitCode = 1; return; }
|
|
5832
5879
|
let text = opts.text;
|
|
5833
5880
|
if (!text) text = await readPipedStdin(); // ★ OBS-T3
|
|
5834
5881
|
if (!text || !text.trim()) { ui.error('utterance: --text 또는 stdin 필요'); process.exit(1); }
|
|
5835
5882
|
// 독립 CLI 프로세스 — 데몬 StoreSink 를 상속 안 하므로 logs.db 싱크를 붙여야
|
|
5836
5883
|
// injectUtterance 의 `debug.log('memory.utterance','ingress')` 가 logs.db 에 닿음(제1원칙 관측).
|
|
5837
|
-
const {
|
|
5838
|
-
const r =
|
|
5884
|
+
const { recordSelfUtterance } = await import('./cli/self-utterances-cli.js');
|
|
5885
|
+
const r = recordSelfUtterance({
|
|
5839
5886
|
text: text.trim(),
|
|
5840
5887
|
origin: opts.source,
|
|
5888
|
+
utteranceOrigin: opts.origin === 'human' ? 'human' : 'agent',
|
|
5841
5889
|
...(opts.session ? { sessionId: opts.session } : {}),
|
|
5842
5890
|
...(opts.gitHash ? { gitHash: opts.gitHash } : {}),
|
|
5843
5891
|
...(opts.branch ? { branch: opts.branch } : {}),
|
|
@@ -7704,7 +7752,7 @@ configCmd
|
|
|
7704
7752
|
.action(async (path: string | undefined, opts: { reveal?: boolean }) => {
|
|
7705
7753
|
const { resolveCurrentInstance } = await import('./instance/current.js');
|
|
7706
7754
|
const instance = resolveCurrentInstance();
|
|
7707
|
-
if (instance.kind === 'test' && instance.layer === 'tree-derived') {
|
|
7755
|
+
if (instance.kind === 'test' && String(instance.layer) === 'tree-derived') {
|
|
7708
7756
|
console.error('⚠️ test 우주의 config를 읽습니다 — 운영 값은 --config-dir ~/.elanous');
|
|
7709
7757
|
}
|
|
7710
7758
|
const cfg = getUserConfig() as unknown as Record<string, unknown>;
|
|
@@ -11722,7 +11770,10 @@ async function main(): Promise<void> {
|
|
|
11722
11770
|
// 한다. 인터랙티브 TUI 는 데몬 sink 를 상속 안 하므로 안 붙이면 debug.log 가 no-op
|
|
11723
11771
|
// (제1원칙 관측 갭 · tui-sim 드라이브에서 agent.source 0건으로 실측 2026-07-19).
|
|
11724
11772
|
// PR#4622(self utterance CLI)·session-cli 미러. fail-open·비블로킹.
|
|
11773
|
+
const bootTimer = (await import('./dashboard/boot-timing.js')).createBootTimer();
|
|
11774
|
+
bootTimer.begin();
|
|
11725
11775
|
try { await (await import('./domains/standalone-log-sink.js')).registerStandaloneLogSink('tui'); } catch { /* fail-open */ }
|
|
11776
|
+
bootTimer.phase('log-sink');
|
|
11726
11777
|
// P3(대표 2026-07-26) — footgun 관측을 logs.db 에 도달시킨다. 초반(arg 파싱 前) warnProdSpawnFootgun 은
|
|
11727
11778
|
// StoreSink 등록 前이라 debug.log 가 logs.db 미도달이었다(순서 갭). sink 등록 직후 관측만 재발행(stderr 중복 X).
|
|
11728
11779
|
try { (await import('./instance-root-coherence.js')).warnProdSpawnFootgun({ emit: 'log' }); } catch { /* fail-open */ }
|
|
@@ -11732,7 +11783,9 @@ async function main(): Promise<void> {
|
|
|
11732
11783
|
// so `elanous self screen` / `/v1/terminals` / (P2) PWA can see the
|
|
11733
11784
|
// dashboard the user is actually looking at. Off unless this boots
|
|
11734
11785
|
// (no producer in headless/daemon paths). fail-soft·비블로킹.
|
|
11786
|
+
bootTimer.begin();
|
|
11735
11787
|
try { (await import('./capture/tui-self-report.js')).startTuiSelfReport(); } catch { /* fail-soft */ }
|
|
11788
|
+
bootTimer.phase('self-report');
|
|
11736
11789
|
|
|
11737
11790
|
// Dashboard handles sync inline — only returns on quit
|
|
11738
11791
|
// ⛔ stdin 이 TTY 가 아니면 «뜨지 않는다» — 뜨면 readKey 가 엔터를 지어내 초당 수백 프레임을
|
|
@@ -11745,7 +11798,14 @@ async function main(): Promise<void> {
|
|
|
11745
11798
|
return;
|
|
11746
11799
|
}
|
|
11747
11800
|
}
|
|
11748
|
-
|
|
11801
|
+
bootTimer.begin();
|
|
11802
|
+
await showDashboard({
|
|
11803
|
+
...dashboardOpts,
|
|
11804
|
+
onFirstFrameRendered: () => {
|
|
11805
|
+
bootTimer.phase('show-dashboard');
|
|
11806
|
+
bootTimer.done();
|
|
11807
|
+
},
|
|
11808
|
+
});
|
|
11749
11809
|
closeTui();
|
|
11750
11810
|
// Force exit: the dashboard starts background timers (clipboard
|
|
11751
11811
|
// poller, shimmer/blink animations) that keep the Bun event loop
|
package/src/instance/current.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { join } from 'node:path';
|
|
2
1
|
import { debug } from '../debug/log.js';
|
|
3
2
|
import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
|
|
4
3
|
import { getTestStateRoot } from '../nexus/paths.js';
|
|
5
|
-
import {
|
|
6
|
-
import { isInstalledCopyScript
|
|
4
|
+
import { getAppliedGlobalTestRoot } from '../cli/test-flag.js';
|
|
5
|
+
import { isInstalledCopyScript } from './leader.js';
|
|
7
6
|
import { prodInstanceRoot, resolveInstance, type InstanceResolution } from './resolve.js';
|
|
8
7
|
|
|
9
8
|
interface ResolveCurrentInstanceDeps {
|
|
@@ -16,15 +15,12 @@ interface ResolveCurrentInstanceDeps {
|
|
|
16
15
|
|
|
17
16
|
/** 현재 프로세스의 4층 판정 입력을 모아 순수 리졸버에 전달한다. */
|
|
18
17
|
export function resolveCurrentInstance(deps: ResolveCurrentInstanceDeps = {}): InstanceResolution {
|
|
19
|
-
const cwd = (deps.cwd ?? (() => process.cwd()))();
|
|
20
18
|
const explicitFlagRoot = (deps.explicitFlagRoot ?? (() =>
|
|
21
19
|
getAppliedGlobalTestRoot() ?? getTestStateRoot() ?? getElanousConfigDirOverride()))();
|
|
22
|
-
const treeRoot = (process.argv[1] ? treeFromScriptPath(process.argv[1]) : null) ?? findTreeRoot(cwd);
|
|
23
20
|
const resolution = resolveInstance({
|
|
24
21
|
explicitFlagRoot,
|
|
25
22
|
stampedStateDir: (deps.stampedStateDir ?? (() => process.env.ELANOUS_STATE_DIR))(),
|
|
26
23
|
installedCopy: isInstalledCopyScript(),
|
|
27
|
-
treeTestRoot: treeRoot ? join(treeRoot, '.elanous-test') : null,
|
|
28
24
|
prodRoot: prodInstanceRoot(),
|
|
29
25
|
});
|
|
30
26
|
debug.log('instance.current', 'resolved', { layer: resolution.layer, kind: resolution.kind });
|
package/src/instance/resolve.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// 인스턴스 우주: 명시 루트 → 부모 스탬프 →
|
|
1
|
+
// 인스턴스 우주: 명시 루트 → 부모 스탬프 → 운영 집. 트리 위치는 우주를 고르지 않는다.
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
|
|
5
5
|
export type InstanceKind = 'prod' | 'test';
|
|
6
|
-
export type ResolutionLayer = 'explicit-flag' | 'parent-stamp' | 'installed' | '
|
|
6
|
+
export type ResolutionLayer = 'explicit-flag' | 'parent-stamp' | 'installed' | 'default';
|
|
7
7
|
|
|
8
8
|
export interface InstanceResolution {
|
|
9
9
|
kind: InstanceKind;
|
|
@@ -50,10 +50,9 @@ export function resolveInstance(deps: ResolveDeps = {}): InstanceResolution {
|
|
|
50
50
|
}
|
|
51
51
|
const installed = deps.installedCopy ?? isInstalledExecution();
|
|
52
52
|
if (installed) return { kind: 'prod', root: prodRoot, layer: 'installed', why: '설치본으로 실행' };
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return { kind: 'test', root: normRoot(join(process.cwd(), '.elanous-test')), layer: 'default', why: '소스 트리 밖 실행(격리)' };
|
|
53
|
+
// Explicit --test selects a test root before this resolver runs. A checkout,
|
|
54
|
+
// worktree, or arbitrary cwd alone never changes the operating house.
|
|
55
|
+
return { kind: 'prod', root: prodRoot, layer: 'default', why: '명시 시험 우주가 없는 운영 집' };
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
/** 부모가 도장으로 물려준 우주와 자식이 실제로 쓰는 우주가 다른가. 비어 있는 쪽은 비교하지 않는다. */
|