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/usage-cli.ts
CHANGED
|
@@ -78,6 +78,8 @@ type AxisUsageRow = {
|
|
|
78
78
|
unknownCostCalls: number;
|
|
79
79
|
includedCalls: number;
|
|
80
80
|
apiEquivalentUsd: number;
|
|
81
|
+
/** 비용 순위 = usdKnown + apiEquivalentUsd — 구독 호출의 목록가 «그림자 비용»까지 더한 값. */
|
|
82
|
+
rankUsd: number;
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
function usageData(row: LogStoreRow, unwrapPod = false): ExtendedRunUsageInput | null {
|
|
@@ -115,6 +117,8 @@ function rollupByAxis(inputs: readonly ExtendedRunUsageInput[], axis: UsageAxis)
|
|
|
115
117
|
}
|
|
116
118
|
return [...groups].map(([value, group]) => {
|
|
117
119
|
const rows = rollupRunUsage(group);
|
|
120
|
+
const usdKnown = rows.reduce((sum, row) => sum + row.usdKnown, 0);
|
|
121
|
+
const apiEquivalentUsd = rows.reduce((sum, row) => sum + row.apiEquivalentUsd, 0);
|
|
118
122
|
const result: AxisUsageRow = {
|
|
119
123
|
[axis]: value,
|
|
120
124
|
hostIds: [...new Set(rows.flatMap((row) => row.hostIds))],
|
|
@@ -124,13 +128,14 @@ function rollupByAxis(inputs: readonly ExtendedRunUsageInput[], axis: UsageAxis)
|
|
|
124
128
|
cacheReadInputTokens: rows.reduce((sum, row) => sum + row.cacheReadInputTokens, 0),
|
|
125
129
|
cacheCreationInputTokens: rows.reduce((sum, row) => sum + row.cacheCreationInputTokens, 0),
|
|
126
130
|
reasoningOutputTokens: rows.reduce((sum, row) => sum + row.reasoningOutputTokens, 0),
|
|
127
|
-
usdKnown
|
|
131
|
+
usdKnown,
|
|
128
132
|
unknownCostCalls: rows.reduce((sum, row) => sum + row.unknownCostCalls, 0),
|
|
129
133
|
includedCalls: rows.reduce((sum, row) => sum + row.includedCalls, 0),
|
|
130
|
-
apiEquivalentUsd
|
|
134
|
+
apiEquivalentUsd,
|
|
135
|
+
rankUsd: usdKnown + apiEquivalentUsd,
|
|
131
136
|
};
|
|
132
137
|
return result;
|
|
133
|
-
}).sort((a, b) => b.calls - a.calls);
|
|
138
|
+
}).sort((a, b) => (b.rankUsd - a.rankUsd) || (b.calls - a.calls));
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
function isUsageAxis(value: string): value is 'run' | 'role' | UsageAxis {
|
|
@@ -139,7 +144,7 @@ function isUsageAxis(value: string): value is 'run' | 'role' | UsageAxis {
|
|
|
139
144
|
|
|
140
145
|
function formatAxisUsage(row: AxisUsageRow, axis: UsageAxis): string {
|
|
141
146
|
const value = row[axis] ?? '(none)';
|
|
142
|
-
return `${axis}=${value} hosts=${row.hostIds.join(',') || '(none)'} calls=${row.calls} input=${row.inputTokens} output=${row.outputTokens} cacheRead=${row.cacheReadInputTokens} cacheCreation=${row.cacheCreationInputTokens} reasoning=${row.reasoningOutputTokens} usdKnown=${row.usdKnown} unknownCostCalls=${row.unknownCostCalls} includedCalls=${row.includedCalls} apiEquivalentUsd=${row.apiEquivalentUsd}`;
|
|
147
|
+
return `${axis}=${value} hosts=${row.hostIds.join(',') || '(none)'} calls=${row.calls} input=${row.inputTokens} output=${row.outputTokens} cacheRead=${row.cacheReadInputTokens} cacheCreation=${row.cacheCreationInputTokens} reasoning=${row.reasoningOutputTokens} usdKnown=${row.usdKnown} unknownCostCalls=${row.unknownCostCalls} includedCalls=${row.includedCalls} apiEquivalentUsd=${row.apiEquivalentUsd} rankUsd=${row.rankUsd}`;
|
|
143
148
|
}
|
|
144
149
|
|
|
145
150
|
function defaultCreditPlan(): CodexCreditPlan | null {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ContextCard } from './index.js';
|
|
2
|
+
|
|
3
|
+
export interface CellCardItem {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly status: string;
|
|
7
|
+
readonly owner?: string | null;
|
|
8
|
+
readonly disposition?: string;
|
|
9
|
+
readonly evidence?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const POINTER_PATTERN = /#\d+|run-[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/giu;
|
|
13
|
+
|
|
14
|
+
function extractPointers(text: string): string[] {
|
|
15
|
+
return [...text.matchAll(POINTER_PATTERN)].map(([pointer]) => pointer);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Build a compact checklist-cell card; evidence is used only to derive stable source pointers. */
|
|
19
|
+
export function buildCellCard(version: string, item: CellCardItem, asOf: string): ContextCard {
|
|
20
|
+
const pointers = [...new Set([
|
|
21
|
+
...extractPointers(item.evidence ?? ''),
|
|
22
|
+
...extractPointers(item.title),
|
|
23
|
+
`checklist:${version}/${item.id}`,
|
|
24
|
+
])];
|
|
25
|
+
const reasons = [
|
|
26
|
+
item.owner ? `담당 ${item.owner}` : undefined,
|
|
27
|
+
item.disposition ? `처분 ${item.disposition}` : undefined,
|
|
28
|
+
].filter((value): value is string => value !== undefined);
|
|
29
|
+
return {
|
|
30
|
+
id: `cell:${version}/${item.id}`,
|
|
31
|
+
kind: 'cell',
|
|
32
|
+
conclusion: (item.title.split(/[\r\n\u2028\u2029]/u, 1)[0] ?? '').trim(),
|
|
33
|
+
why: reasons.join(' · '),
|
|
34
|
+
verdict: item.status,
|
|
35
|
+
remaining: [],
|
|
36
|
+
pointers,
|
|
37
|
+
source: `release-checklist:${version}`,
|
|
38
|
+
updatedAt: asOf,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
|
|
3
|
+
export interface BootTimer {
|
|
4
|
+
begin(): void;
|
|
5
|
+
phase(name: string): void;
|
|
6
|
+
done(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createBootTimer(now: () => number = performance.now): BootTimer {
|
|
10
|
+
const startedAt = now();
|
|
11
|
+
let phaseStartedAt = startedAt;
|
|
12
|
+
let lastPhase: string | undefined;
|
|
13
|
+
let slowest: { phase: string; ms: number } | undefined;
|
|
14
|
+
let completed = false;
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
begin(): void {
|
|
18
|
+
phaseStartedAt = now();
|
|
19
|
+
},
|
|
20
|
+
phase(name: string): void {
|
|
21
|
+
const current = now();
|
|
22
|
+
const ms = current - phaseStartedAt;
|
|
23
|
+
phaseStartedAt = current;
|
|
24
|
+
lastPhase = name;
|
|
25
|
+
if (!slowest || ms > slowest.ms) slowest = { phase: name, ms };
|
|
26
|
+
try { debug.log('tui.boot', 'phase', { phase: name, ms }); } catch { /* logging must not block startup */ }
|
|
27
|
+
},
|
|
28
|
+
done(): void {
|
|
29
|
+
if (completed) return;
|
|
30
|
+
completed = true;
|
|
31
|
+
const totalMs = now() - startedAt;
|
|
32
|
+
try { debug.log('tui.boot', 'summary', { totalMs, slowest: slowest ?? (lastPhase ? { phase: lastPhase, ms: totalMs } : null) }); } catch { /* logging must not block startup */ }
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -106,6 +106,8 @@ export interface FirstScreenBandInput {
|
|
|
106
106
|
readonly width: number;
|
|
107
107
|
readonly daemon: boolean;
|
|
108
108
|
readonly link?: TuiDaemonLink;
|
|
109
|
+
/** Renders the three available-action rows and the example row in this locale; `undefined` keeps the historical band. */
|
|
110
|
+
readonly locale?: 'ko' | 'en';
|
|
109
111
|
readonly pwa?: {
|
|
110
112
|
readonly tailnet?: string | null;
|
|
111
113
|
readonly lan?: string | null;
|
|
@@ -138,10 +140,37 @@ function fitCells(text: string, limit: number): string {
|
|
|
138
140
|
return result;
|
|
139
141
|
}
|
|
140
142
|
|
|
143
|
+
// First-run guidance: three rows of available actions plus one immediately-typeable
|
|
144
|
+
// example row, per locale. Every row names something the empty TUI can really do.
|
|
145
|
+
const GUIDANCE: Record<'ko' | 'en', {
|
|
146
|
+
readonly actions: readonly [string, string, string];
|
|
147
|
+
readonly example: string;
|
|
148
|
+
}> = {
|
|
149
|
+
ko: {
|
|
150
|
+
actions: [
|
|
151
|
+
'· 대화 — 무엇이든 자연어로 물어보고 시켜보세요',
|
|
152
|
+
'· 명령 — /help 로 전체 명령을 보세요',
|
|
153
|
+
'· 스킬 — /run-skill <이름> 으로 설치된 스킬을 돌리세요',
|
|
154
|
+
],
|
|
155
|
+
example: '바로 입력해 보세요: 무엇을 할 수 있어?',
|
|
156
|
+
},
|
|
157
|
+
en: {
|
|
158
|
+
actions: [
|
|
159
|
+
'· Chat — ask for anything in plain language',
|
|
160
|
+
'· Commands — /help lists every command',
|
|
161
|
+
'· Skills — /run-skill <name> runs an installed skill',
|
|
162
|
+
],
|
|
163
|
+
example: 'Try typing: what can you do?',
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
141
167
|
/** A startup transcript band; never includes credentials or a partial address. */
|
|
142
168
|
export function buildFirstScreenBand(input: FirstScreenBandInput): string[] {
|
|
143
169
|
const width = Number.isFinite(input.width) ? Math.max(0, Math.floor(input.width)) : 0;
|
|
144
|
-
|
|
170
|
+
// The historical band is mixed: the link row speaks Korean, the remaining lines English.
|
|
171
|
+
// An explicit locale unifies them; `undefined` must keep every pinned line byte-identical.
|
|
172
|
+
const linkKorean = input.locale !== 'en';
|
|
173
|
+
const plainKorean = input.locale === 'ko';
|
|
145
174
|
const address = [input.pwa?.tailnet, input.pwa?.lan, input.pwa?.loopback]
|
|
146
175
|
.map((candidate) => {
|
|
147
176
|
if (!candidate) return null;
|
|
@@ -154,32 +183,53 @@ export function buildFirstScreenBand(input: FirstScreenBandInput): string[] {
|
|
|
154
183
|
}
|
|
155
184
|
})
|
|
156
185
|
.find((candidate) => candidate !== null);
|
|
157
|
-
const fallback = input.pwa === undefined
|
|
186
|
+
const fallback = input.pwa === undefined
|
|
187
|
+
? (plainKorean ? 'PWA: 확인 안 함' : 'PWA: not checked')
|
|
188
|
+
: (plainKorean ? 'PWA: 사용할 수 없음' : 'PWA: unavailable');
|
|
158
189
|
const addressLine = address ? `PWA: ${address}` : fallback;
|
|
159
190
|
|
|
160
191
|
const daemonLine = (() => {
|
|
161
192
|
const link = input.link;
|
|
162
|
-
if (!link) return
|
|
163
|
-
|
|
193
|
+
if (!link) return plainKorean
|
|
194
|
+
? `elanous | 데몬: ${input.daemon ? '켜짐' : '꺼짐'}`
|
|
195
|
+
: `elanous | daemon: ${input.daemon ? 'online' : 'offline'}`;
|
|
196
|
+
if (link.status === 'checking') return linkKorean ? 'elanous | 데몬: 확인 중' : 'elanous | daemon: checking';
|
|
164
197
|
if (link.status === 'connected') {
|
|
165
198
|
let address: string;
|
|
166
199
|
try {
|
|
167
200
|
const url = new URL(link.address);
|
|
168
201
|
address = ['http:', 'https:'].includes(url.protocol) && url.hostname ? url.origin : '';
|
|
169
202
|
} catch { address = ''; }
|
|
170
|
-
const
|
|
171
|
-
|
|
203
|
+
const bare = linkKorean ? 'elanous | 데몬: 연결됨' : 'elanous | daemon: connected';
|
|
204
|
+
const line = `${bare}${address ? ` (${address})` : ''}`;
|
|
205
|
+
return cellWidth(line) <= width ? line : bare;
|
|
206
|
+
}
|
|
207
|
+
if (link.status === 'error') {
|
|
208
|
+
return linkKorean ? `elanous | 데몬: ${link.stage} 조회 오류` : `elanous | daemon: ${link.stage} lookup error`;
|
|
172
209
|
}
|
|
173
|
-
|
|
174
|
-
|
|
210
|
+
const bare = linkKorean
|
|
211
|
+
? `elanous | 데몬: ${link.status === 'absent' ? '없음' : '응답 없음'}`
|
|
212
|
+
: `elanous | daemon: ${link.status === 'absent' ? 'absent' : 'unhealthy'}`;
|
|
175
213
|
if (!link.startCommand || CONTROL_CHARS.test(link.startCommand)) return bare;
|
|
176
|
-
const line = `${bare} ·
|
|
214
|
+
const line = `${bare} · ${linkKorean ? '시작' : 'start'}: ${link.startCommand}`;
|
|
177
215
|
return cellWidth(line) <= width ? line : bare;
|
|
178
216
|
})();
|
|
179
217
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
218
|
+
const hintLine = 'Type a message to begin | /help for commands';
|
|
219
|
+
|
|
220
|
+
const statusRows = [
|
|
221
|
+
fitCells(daemonLine, width),
|
|
222
|
+
cellWidth(addressLine) <= width
|
|
223
|
+
? addressLine
|
|
224
|
+
: fitCells(address ? (plainKorean ? 'PWA: 주소 확인됨' : 'PWA: address available') : fallback, width),
|
|
184
225
|
];
|
|
226
|
+
// The historical band folds its guidance into one mixed-language hint row.
|
|
227
|
+
// An explicit locale renders the same guidance as three available-action rows
|
|
228
|
+
// plus one immediately-typeable example row, in that locale — on every screen
|
|
229
|
+
// state (empty, checking, absent, unhealthy, error) because none of these
|
|
230
|
+
// rows depends on the daemon link or the PWA lookup.
|
|
231
|
+
const guidanceRows = input.locale
|
|
232
|
+
? [...GUIDANCE[input.locale].actions, GUIDANCE[input.locale].example].map((row) => fitCells(row, width))
|
|
233
|
+
: [fitCells(hintLine, width)];
|
|
234
|
+
return [...statusRows, ...guidanceRows];
|
|
185
235
|
}
|
package/src/dashboard/index.ts
CHANGED
|
@@ -643,6 +643,7 @@ import { activeCodexAccountView } from '../oauth/codex-account-store.js';
|
|
|
643
643
|
import { buildDashboardStatusLines } from './dashboard-status-lines.js';
|
|
644
644
|
import { readSlashContextNow, seatsNowLine } from '../context-bus/context-now-surfaces.js';
|
|
645
645
|
import { buildFirstScreenBand, resolveTuiDaemonLink, type TuiDaemonLink } from './first-screen-band.js';
|
|
646
|
+
import { detectLocale } from '../expression/locale.js';
|
|
646
647
|
import { runNexusShow, type NexusShowResult } from '../cli/nexus-show.js';
|
|
647
648
|
import {
|
|
648
649
|
workingDirSegment, sessionCwdSegment, modelSegment, gitSegment,
|
|
@@ -965,6 +966,7 @@ import {
|
|
|
965
966
|
enterSessionControlMode,
|
|
966
967
|
exitSessionControlMode,
|
|
967
968
|
isSessionControlActive,
|
|
969
|
+
routeDevHarnessSubmitIntent,
|
|
968
970
|
parseSessionControlSlash,
|
|
969
971
|
parseSessionSurfaceSlash,
|
|
970
972
|
resolveSessionInputModeFromChatMode,
|
|
@@ -1023,7 +1025,7 @@ import { expandPromptReferences } from '../prompt/references.js';
|
|
|
1023
1025
|
import { spawnCodingAgent, CodingAgentBinaryMissing } from '../terminal/coding-agent.js';
|
|
1024
1026
|
import type { TerminalSession } from '../terminal/session-registry.js';
|
|
1025
1027
|
import { createSessionPickerModal } from '../session/picker-modal.js';
|
|
1026
|
-
import { listSessions as listChatSessionsForResume } from '../session/index.js';
|
|
1028
|
+
import { listSessions as listChatSessionsForResume, adoptSession as adoptChatSession, setActiveSessionId as markActiveChatSession } from '../session/index.js';
|
|
1027
1029
|
// TUI 부활 S-b — 타임트래블 포크 엔진 (codex ForkSnapshot 동형 · 2026-07-09
|
|
1028
1030
|
// 이식 후 호출처 0 이던 방치 자산 회수). 순수 히스토리 절단 로직만 소비;
|
|
1029
1031
|
// 영속은 세션 스토어(forkSessionFromHistory)가 담당한다.
|
|
@@ -1179,6 +1181,20 @@ import { buildDebugCallStack } from '../debug/call-stack.js';
|
|
|
1179
1181
|
import { buildAstGrepHostTool } from '../skills/tools/ast-grep.js';
|
|
1180
1182
|
import { buildLspHostTool } from '../skills/tools/lsp/index.js';
|
|
1181
1183
|
import { PluginHost } from '../plugins/core/host.js';
|
|
1184
|
+
|
|
1185
|
+
/** Register the same L2 host tools used by the live TUI before each turn's catalog is assembled. */
|
|
1186
|
+
export function registerDashboardCoreHostTools(host: Pick<PluginHost, 'registerHostTool'>): void {
|
|
1187
|
+
const coreMod = require('../domains/core-tools.js') as typeof import('../domains/core-tools.js');
|
|
1188
|
+
const core = coreMod.buildCoreTools();
|
|
1189
|
+
for (const spec of core.specs) {
|
|
1190
|
+
host.registerHostTool({
|
|
1191
|
+
name: spec.name,
|
|
1192
|
+
description: spec.description,
|
|
1193
|
+
parameters: spec.parameters,
|
|
1194
|
+
handler: async (args) => core.dispatch(spec.name, args as Record<string, unknown>),
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1182
1198
|
import { registerDashboardPaneHostTools } from './panes/host-tools.js';
|
|
1183
1199
|
import { DEFAULT_THEME_TOKENS, mergeThemeTokens, resolveThemeTokens, type ThemeTokenInput, type ThemeTokens } from '../theme/tokens.js';
|
|
1184
1200
|
import { resolveActiveTheme, setActivePresetInConfig } from './render/theme-resolver.js';
|
|
@@ -1407,6 +1423,8 @@ const isPluginBusy = (host: { active(): { plugin: { isBusy?: (s: any) => boolean
|
|
|
1407
1423
|
// ── Main dashboard ──
|
|
1408
1424
|
|
|
1409
1425
|
export interface ShowDashboardOptions {
|
|
1426
|
+
/** Internal startup timing signal for the first successfully flushed dashboard frame. */
|
|
1427
|
+
onFirstFrameRendered?: () => void;
|
|
1410
1428
|
/** Force debug sinks on at launch (file + mirror). Equivalent to
|
|
1411
1429
|
* typing `/debug on` immediately after startup. Paired with
|
|
1412
1430
|
* chatOnly=true by the `elanous --debug` CLI flag so every traced
|
|
@@ -1501,6 +1519,16 @@ export function buildDashboardTurnTypeaheadPromptZone(input: TurnTypeaheadPrompt
|
|
|
1501
1519
|
};
|
|
1502
1520
|
}
|
|
1503
1521
|
|
|
1522
|
+
/** The chat-main submit branch calls this before any model dispatch. Keeping
|
|
1523
|
+
* the decision here lets the dashboard test execute the same entry point. */
|
|
1524
|
+
export function resolveDashboardHarnessSubmitIntent(
|
|
1525
|
+
text: string,
|
|
1526
|
+
options: Parameters<typeof resolveDashboardChatMainSubmitIntent>[1],
|
|
1527
|
+
resolveIntent: typeof resolveDashboardChatMainSubmitIntent = resolveDashboardChatMainSubmitIntent,
|
|
1528
|
+
) {
|
|
1529
|
+
return routeDevHarnessSubmitIntent(resolveIntent(text, options));
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1504
1532
|
/** 프롬프트 zone 에 관측만 덧입힌다 — 렌더 산출은 `inner` 가 소유한다.
|
|
1505
1533
|
*
|
|
1506
1534
|
* ⭐ **왜 뽑았나**(무인 리뷰 must-fix · 2026-08-01): 종전엔 이 래퍼가 `zones.push({...})` 안에
|
|
@@ -1567,6 +1595,7 @@ export interface DashboardFrameInput {
|
|
|
1567
1595
|
promptCaret: CursorState | null;
|
|
1568
1596
|
suppressPromptArea: boolean;
|
|
1569
1597
|
onEssentialFrameCursorDecision?: (observation: EssentialFrameCursorObservation) => void;
|
|
1598
|
+
onFrameWriteComplete?: (error?: Error | null) => void;
|
|
1570
1599
|
}
|
|
1571
1600
|
|
|
1572
1601
|
export interface EssentialFrameCursorObservation {
|
|
@@ -1612,6 +1641,7 @@ export function renderDashboardFrame(
|
|
|
1612
1641
|
overlay: input.overlay,
|
|
1613
1642
|
force: input.force,
|
|
1614
1643
|
cursor: paintCursor(essentialDecision.cursor ?? input.coordinatorCursor ?? null),
|
|
1644
|
+
onWriteComplete: input.onFrameWriteComplete,
|
|
1615
1645
|
});
|
|
1616
1646
|
input.onEssentialFrameCursorDecision?.({
|
|
1617
1647
|
caret: essentialDecision.cursor,
|
|
@@ -1867,18 +1897,20 @@ export function renderDashboardFirstScreenBand(input: {
|
|
|
1867
1897
|
readonly history: ReadonlyArray<{ role: string }>;
|
|
1868
1898
|
readonly lines: string[];
|
|
1869
1899
|
readonly width: number;
|
|
1900
|
+
/** Renders the localized guidance rows; `undefined` keeps the historical mixed band. */
|
|
1901
|
+
readonly locale?: 'ko' | 'en';
|
|
1870
1902
|
readonly draw: () => void;
|
|
1871
1903
|
readonly observe: (data: { daemon: boolean; hasPwa: boolean; hasTailnet: boolean }) => void;
|
|
1872
1904
|
readonly show?: () => Promise<Pick<NexusShowResult, 'status' | 'urls'>>;
|
|
1873
1905
|
readonly daemonLink?: () => Promise<TuiDaemonLink>;
|
|
1874
1906
|
}): Promise<void> {
|
|
1875
1907
|
if (input.history.some((message) => message.role !== 'system')) return Promise.resolve();
|
|
1876
|
-
const band = buildFirstScreenBand({ width: input.width, daemon: false, link: { status: 'checking' } });
|
|
1908
|
+
const band = buildFirstScreenBand({ width: input.width, daemon: false, link: { status: 'checking' }, locale: input.locale });
|
|
1877
1909
|
input.lines.unshift(...band);
|
|
1878
1910
|
const daemonLink = input.daemonLink ?? resolveTuiDaemonLink;
|
|
1879
1911
|
const linkPending = Promise.resolve().then(() => daemonLink()).catch((): TuiDaemonLink => ({ status: 'error', stage: 'health' })).then((link) => {
|
|
1880
1912
|
if (input.lines[0] !== band[0]) return;
|
|
1881
|
-
input.lines[0] = buildFirstScreenBand({ width: input.width, daemon: false, link })[0]!;
|
|
1913
|
+
input.lines[0] = buildFirstScreenBand({ width: input.width, daemon: false, link, locale: input.locale })[0]!;
|
|
1882
1914
|
try { input.draw(); } catch { /* screen may have closed */ }
|
|
1883
1915
|
});
|
|
1884
1916
|
const show = input.show ?? (() => runNexusShow({ format: 'json', out: { log: () => {}, error: () => {} } }));
|
|
@@ -1892,7 +1924,7 @@ export function renderDashboardFirstScreenBand(input: {
|
|
|
1892
1924
|
const hasTailnet = !!pwa?.tailnet;
|
|
1893
1925
|
observe({ daemon, hasPwa, hasTailnet });
|
|
1894
1926
|
if (input.lines[1] !== band[1]) return;
|
|
1895
|
-
input.lines[1] = buildFirstScreenBand({ width: input.width, daemon, pwa })[1]!;
|
|
1927
|
+
input.lines[1] = buildFirstScreenBand({ width: input.width, daemon, pwa, locale: input.locale })[1]!;
|
|
1896
1928
|
try { input.draw(); } catch { /* screen may have closed */ }
|
|
1897
1929
|
}).catch(() => {
|
|
1898
1930
|
observe({ daemon: false, hasPwa: false, hasTailnet: false });
|
|
@@ -1901,6 +1933,7 @@ export function renderDashboardFirstScreenBand(input: {
|
|
|
1901
1933
|
}
|
|
1902
1934
|
|
|
1903
1935
|
export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<DashboardAction> {
|
|
1936
|
+
let firstDashboardFrameRendered = false;
|
|
1904
1937
|
await awaitGlobalPersonaLoad().catch(() => {});
|
|
1905
1938
|
const dashboardQuitConfirmationState = createQuitConfirmationState();
|
|
1906
1939
|
const signalQuitConfirmationState = createQuitConfirmationState();
|
|
@@ -1910,7 +1943,11 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
1910
1943
|
closeTui();
|
|
1911
1944
|
};
|
|
1912
1945
|
const exitDashboardTui = (): void => {
|
|
1913
|
-
closeDashboardForExit({
|
|
1946
|
+
closeDashboardForExit({
|
|
1947
|
+
closeTui: closeDashboardTui,
|
|
1948
|
+
confirmationState: dashboardQuitConfirmationState,
|
|
1949
|
+
getSessionId: (): string | undefined => acpSessionIdRef.current ?? undefined,
|
|
1950
|
+
});
|
|
1914
1951
|
};
|
|
1915
1952
|
// ⭐⭐⭐ `N1` — 신호 경로(`SIGINT`/`SIGTERM`)와 저수준 `Ctrl+C` 도 같은 종료를 타게 «등록»한다.
|
|
1916
1953
|
// ⛔ 종전엔 그 둘만 세션 안내를 «못 받았다»(일곱 경로 중 다섯만 받았다).
|
|
@@ -1920,6 +1957,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
1920
1957
|
closeTui: () => { /* 신호 경로: cleanup() 이 이미 복원했다 */ },
|
|
1921
1958
|
confirmationState: signalQuitConfirmationState,
|
|
1922
1959
|
forceQuit: true,
|
|
1960
|
+
getSessionId: (): string | undefined => acpSessionIdRef.current ?? undefined,
|
|
1923
1961
|
});
|
|
1924
1962
|
});
|
|
1925
1963
|
// E3 (§7.4 TS baseline reduction · 2026-05-17) — forward declarations
|
|
@@ -3342,6 +3380,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3342
3380
|
// ⛔ `attachedSessionId`(대화 세션)와 «다른 축»이다 — 루프는 ACP 세션으로 스코프를 연다.
|
|
3343
3381
|
// ⚠️ 세션은 이 함수 «뒤»에서 만들어지므로 참조로 둔다(호출 시점엔 채워져 있다).
|
|
3344
3382
|
const acpSessionIdRef: { current: string | null } = { current: null };
|
|
3383
|
+
const adoptedAcpSessionIds = new Set<string>();
|
|
3384
|
+
let activeAcpSessionId: string | null = null;
|
|
3345
3385
|
const activeSessionIdForTypeahead = (): string | null => acpSessionIdRef.current;
|
|
3346
3386
|
const paintTurnTypeaheadEcho = (): void => {
|
|
3347
3387
|
const { rows: tr, cols: tc } = termSize();
|
|
@@ -10014,16 +10054,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
10014
10054
|
// family(전 surface 기본) — 이로써 TUI 에서도 "P2 왜 실패?" 를 엘라누스가 툴로 상황판단한다.
|
|
10015
10055
|
// fail-soft: 코어 도구 로드 실패가 대시보드 부팅을 막지 않는다.
|
|
10016
10056
|
try {
|
|
10017
|
-
|
|
10018
|
-
const core = coreMod.buildCoreTools();
|
|
10019
|
-
for (const spec of core.specs) {
|
|
10020
|
-
pluginHost.registerHostTool({
|
|
10021
|
-
name: spec.name,
|
|
10022
|
-
description: spec.description,
|
|
10023
|
-
parameters: spec.parameters,
|
|
10024
|
-
handler: async (args) => core.dispatch(spec.name, args as Record<string, unknown>),
|
|
10025
|
-
});
|
|
10026
|
-
}
|
|
10057
|
+
registerDashboardCoreHostTools(pluginHost);
|
|
10027
10058
|
} catch { /* fail-soft */ }
|
|
10028
10059
|
// LSP (Phase L3 of 내부 문서 `ROADMAP-lsp-integration`) — structural /
|
|
10029
10060
|
// symbol-level source queries via typescript-language-server. Pool
|
|
@@ -11530,6 +11561,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11530
11561
|
// ⭐ Single flush: resolve the prompt caret after overlays.
|
|
11531
11562
|
const frameCursorDecision = display.cursorDecision();
|
|
11532
11563
|
renderDashboardFrame(baseLines, composeDashboardFrameWithCoordinatorModal(display, {
|
|
11564
|
+
onFrameWriteComplete: firstDashboardFrameRendered ? undefined : (error) => {
|
|
11565
|
+
if (error || firstDashboardFrameRendered) return;
|
|
11566
|
+
firstDashboardFrameRendered = true;
|
|
11567
|
+
try { opts.onFirstFrameRendered?.(); } catch { /* timing must not break dashboard */ }
|
|
11568
|
+
},
|
|
11533
11569
|
overlay: modalFrame,
|
|
11534
11570
|
force: forceFromCoordinator || modalKey !== lastModalKey,
|
|
11535
11571
|
cursorOwner: frameCursorDecision.owner,
|
|
@@ -15670,6 +15706,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15670
15706
|
history: chat.history,
|
|
15671
15707
|
lines: chatLines,
|
|
15672
15708
|
width: Math.max(0, termSize().cols - 4),
|
|
15709
|
+
// The band ships ko/en only; any other detected locale keeps the English rows.
|
|
15710
|
+
locale: detectLocale() === 'ko' ? 'ko' : 'en',
|
|
15673
15711
|
draw: () => draw(),
|
|
15674
15712
|
observe: (data) => { try { debug.log('dashboard.first-screen-band', 'resolved', data); } catch { /* observation is best-effort */ } },
|
|
15675
15713
|
});
|
|
@@ -17422,7 +17460,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17422
17460
|
// resource_link blocks so dropped screenshots and PDFs flow
|
|
17423
17461
|
// naturally to the agent. debug.log gates the snapshot so
|
|
17424
17462
|
// off-state stays zero-cost.
|
|
17425
|
-
const submitIntent =
|
|
17463
|
+
const submitIntent = resolveDashboardHarnessSubmitIntent(input.text, {
|
|
17426
17464
|
stickyBackend: dashboardAcpChat.getSticky(),
|
|
17427
17465
|
source: input.externalSubmitSource,
|
|
17428
17466
|
});
|
|
@@ -17443,7 +17481,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17443
17481
|
}
|
|
17444
17482
|
if (submitIntent.kind === 'submit-turn' && submitIntent.route === 'sticky-acp') {
|
|
17445
17483
|
await runDashboardChatMainSubmitIntent({
|
|
17446
|
-
submit: createDashboardChatMainTurnSubmit(
|
|
17484
|
+
submit: createDashboardChatMainTurnSubmit({
|
|
17485
|
+
...submitIntent,
|
|
17486
|
+
sessionId: submitIntent.sessionId ?? dashboardAcpSession.currentSessionId,
|
|
17487
|
+
}),
|
|
17447
17488
|
beforeExecute: (submit) => {
|
|
17448
17489
|
maybeEmitDashboardSubmitQuickPass({
|
|
17449
17490
|
submit,
|
|
@@ -19186,16 +19227,19 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19186
19227
|
do {
|
|
19187
19228
|
const turnText = goalLoopUserText ?? tok.text;
|
|
19188
19229
|
await runDashboardChatMainSubmitIntent({
|
|
19189
|
-
submit: createDashboardChatMainTurnSubmit(
|
|
19190
|
-
submitIntent.kind === 'submit-turn' && submitIntent.route === 'plain' && goalLoopUserText === null
|
|
19191
|
-
|
|
19192
|
-
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19230
|
+
submit: createDashboardChatMainTurnSubmit({
|
|
19231
|
+
...(submitIntent.kind === 'submit-turn' && submitIntent.route === 'plain' && goalLoopUserText === null
|
|
19232
|
+
? submitIntent
|
|
19233
|
+
: {
|
|
19234
|
+
kind: 'submit-turn' as const,
|
|
19235
|
+
source: { kind: 'keyboard' as const, surface: 'dashboard-chat-main' },
|
|
19236
|
+
text: turnText,
|
|
19237
|
+
route: 'plain' as const,
|
|
19238
|
+
}),
|
|
19239
|
+
sessionId: submitIntent.kind === 'submit-turn'
|
|
19240
|
+
? submitIntent.sessionId ?? dashboardAcpSession.currentSessionId
|
|
19241
|
+
: dashboardAcpSession.currentSessionId,
|
|
19242
|
+
}),
|
|
19199
19243
|
beforeExecute: (submit) => {
|
|
19200
19244
|
maybeEmitDashboardSubmitQuickPass({
|
|
19201
19245
|
submit,
|
|
@@ -19246,6 +19290,29 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19246
19290
|
}
|
|
19247
19291
|
} while (goalLoopUserText !== null);
|
|
19248
19292
|
|
|
19293
|
+
// SESSION-RESUME-ISOLATED: 완료된 턴의 ACP 세션을 원장에 등록하고 active 로 지정한다.
|
|
19294
|
+
// 서버의 완료-채택(persistCompletedTuiAcpTurn)은 origin_session 메타가 실렸을 때만
|
|
19295
|
+
// 도는데, 격리 우주 첫 턴에는 origin 세션이 없어 메타가 안 실린다 — 여기가 그 갭을 닫는다.
|
|
19296
|
+
const completedAcpSessionId = dashboardAcpSession.currentSessionId;
|
|
19297
|
+
if (completedAcpSessionId) {
|
|
19298
|
+
acpSessionIdRef.current = completedAcpSessionId;
|
|
19299
|
+
// 원격 데몬 세션의 원장은 데몬이 소유한다. 로컬 등록은 세션마다 한 번만 한다.
|
|
19300
|
+
if (!daemonAttached && activeAcpSessionId !== completedAcpSessionId) {
|
|
19301
|
+
try {
|
|
19302
|
+
if (!adoptedAcpSessionIds.has(completedAcpSessionId)) {
|
|
19303
|
+
adoptChatSession(completedAcpSessionId, { source: 'tui', transport: 'acp' });
|
|
19304
|
+
adoptedAcpSessionIds.add(completedAcpSessionId);
|
|
19305
|
+
}
|
|
19306
|
+
markActiveChatSession(completedAcpSessionId);
|
|
19307
|
+
activeAcpSessionId = completedAcpSessionId;
|
|
19308
|
+
} catch (error) {
|
|
19309
|
+
// 등록 실패가 대화 흐름을 끊지 않되, 다음 턴 재시도 전 원인을 남긴다.
|
|
19310
|
+
debug.log('session.adopt', 'failed', { sessionId: completedAcpSessionId, error: String(error) });
|
|
19311
|
+
pushDebugLine(C.warning(`session adopt failed: ${String(error)}`));
|
|
19312
|
+
}
|
|
19313
|
+
}
|
|
19314
|
+
}
|
|
19315
|
+
|
|
19249
19316
|
continue; // stay in input mode after chat
|
|
19250
19317
|
} // end while (input mode loop)
|
|
19251
19318
|
// Disarm the prompt-repaint hook: textInput's drawAll
|
|
@@ -191,10 +191,15 @@ export async function runDashboardChatMainPlainTurn(
|
|
|
191
191
|
// 「사다리가 안 걸린 것」과 「걸렸는데 키가 딴 데로 간 것」을 ***원리상 못 갈랐다***.
|
|
192
192
|
// ⭐ 이 한 줄이 그 둘을 가른다 — 이 이벤트가 «있는데» typeahead 가 0이면 후자다.
|
|
193
193
|
// ⛔ 행동을 바꾸지 않는다(관측만). 처방은 `RFC-tui-mid-turn-input-queue-2026-08-19` §2 Q1.
|
|
194
|
+
const startedAtDate = new Date(deps.turnStartedAt);
|
|
195
|
+
const turnStartedAtIso = Number.isFinite(startedAtDate.getTime())
|
|
196
|
+
? startedAtDate.toISOString()
|
|
197
|
+
: undefined;
|
|
194
198
|
try {
|
|
195
199
|
deps.debugLog?.('chat-main.plain-turn', 'streaming-keys-attached', {
|
|
196
200
|
userTextBytes: Buffer.byteLength(userText ?? '', 'utf8'),
|
|
197
201
|
turnStartedAt: deps.turnStartedAt,
|
|
202
|
+
turnStartedAtIso,
|
|
198
203
|
});
|
|
199
204
|
} catch { /* fail-soft — 관측이 턴을 막지 않는다 */ }
|
|
200
205
|
let stage = 'streaming-keys-attached';
|
|
@@ -291,11 +296,32 @@ export async function runDashboardChatMainPlainTurn(
|
|
|
291
296
|
});
|
|
292
297
|
|
|
293
298
|
if (finishIfAborted()) return;
|
|
299
|
+
// TUI-FIRST-TURN-STALL — 09:48 표본에서 llm.stream consume-start 뒤
|
|
300
|
+
// first-token 이벤트가 0건이어서 「첫 토큰까지의 구간」을 잴 표면이 없었다.
|
|
301
|
+
// turnStartedAt 를 재사용해 첫 비어 있지 않은 text chunk 에 정확히 한 번
|
|
302
|
+
// chat.turn/first-token 을 남긴다. 도구 호출이 먼저 흘러도 text 가 도착해야
|
|
303
|
+
// 기록되므로 request→first-token 구간은 그대로 측정된다. ISO 시각 좌표는
|
|
304
|
+
// pty record 및 TUI-BOOT-TIME(src/index.ts) 부팅 계측과의 대응용이다.
|
|
305
|
+
let firstTokenLogged = false;
|
|
306
|
+
const logFirstToken = (chunk: string): void => {
|
|
307
|
+
if (firstTokenLogged || !chunk || abortCtrl.signal.aborted) return;
|
|
308
|
+
firstTokenLogged = true;
|
|
309
|
+
const firstTokenAt = Date.now();
|
|
310
|
+
try {
|
|
311
|
+
deps.debugLog?.('chat.turn', 'first-token', {
|
|
312
|
+
ms: firstTokenAt - deps.turnStartedAt,
|
|
313
|
+
turnStartedAt: deps.turnStartedAt,
|
|
314
|
+
turnStartedAtIso,
|
|
315
|
+
firstTokenAtIso: new Date(firstTokenAt).toISOString(),
|
|
316
|
+
});
|
|
317
|
+
} catch { /* fail-soft — 관측이 턴을 막지 않는다 */ }
|
|
318
|
+
};
|
|
294
319
|
const streamResult = await runDashboardPlainTurnStream({
|
|
295
320
|
userText,
|
|
296
321
|
abortCtrl,
|
|
297
322
|
acpSession: deps.acpSession,
|
|
298
323
|
onText: (chunk, accumulated) => {
|
|
324
|
+
logFirstToken(chunk);
|
|
299
325
|
turnStreamRuntime.onText(chunk, accumulated);
|
|
300
326
|
},
|
|
301
327
|
onToolCall: (call) => {
|
|
@@ -7,16 +7,26 @@ import {
|
|
|
7
7
|
} from '../skills/router.js';
|
|
8
8
|
import type { SkillIndexEntry } from '../skills/index.js';
|
|
9
9
|
import type { SkillTier } from '../skills/runner.js';
|
|
10
|
-
import
|
|
10
|
+
import * as llm from '../llm.js';
|
|
11
|
+
import { resolveRoleLlm } from '../user-config.js';
|
|
12
|
+
import { debug } from '../debug/log.js';
|
|
11
13
|
|
|
12
14
|
export interface DashboardSkillDetectionRuntimeDeps {
|
|
13
15
|
llmFallback: boolean;
|
|
14
16
|
keywordScoreThreshold: number;
|
|
15
17
|
llmConfidenceThreshold: number;
|
|
16
18
|
streamLLM: (
|
|
17
|
-
messages: LLMMessage[],
|
|
19
|
+
messages: llm.LLMMessage[],
|
|
18
20
|
onDelta: (chunk: string, full: string) => void,
|
|
19
|
-
opts: {
|
|
21
|
+
opts: {
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
maxTokens?: number;
|
|
24
|
+
temperature?: number;
|
|
25
|
+
/** classify role pin — resolveRoleLlm('classify')가 고른 모델·프로바이더. */
|
|
26
|
+
model?: string;
|
|
27
|
+
provider?: (typeof llm.PROVIDERS)[string];
|
|
28
|
+
usageRole?: 'classify';
|
|
29
|
+
},
|
|
20
30
|
) => Promise<string>;
|
|
21
31
|
/** Active model tier — enables tier-aware full-menu LLM routing in
|
|
22
32
|
* detectLLM (T1 frontier models route the whole menu when keyword is
|
|
@@ -69,10 +79,20 @@ export async function detectDashboardSkillRoute(
|
|
|
69
79
|
if (!deps.llmFallback) return keywordDetection;
|
|
70
80
|
|
|
71
81
|
const classify = async (prompt: string, signal?: AbortSignal): Promise<LLMClassifyResult> => {
|
|
82
|
+
const resolved = resolveRoleLlm('classify');
|
|
83
|
+
const provider = llm.PROVIDERS[resolved.provider];
|
|
84
|
+
if (!provider) throw new Error(`Unknown classify provider: ${resolved.provider}`);
|
|
85
|
+
debug.log('llm.role-pin', 'resolved', {
|
|
86
|
+
site: 'skill-detection-runtime',
|
|
87
|
+
role: 'classify',
|
|
88
|
+
model: resolved.model,
|
|
89
|
+
provider: resolved.provider,
|
|
90
|
+
source: resolved.source,
|
|
91
|
+
});
|
|
72
92
|
const raw = await deps.streamLLM(
|
|
73
93
|
[{ role: 'user', content: prompt }],
|
|
74
94
|
() => {},
|
|
75
|
-
{ signal, maxTokens: 120, temperature: 0 },
|
|
95
|
+
{ signal, maxTokens: 120, temperature: 0, model: resolved.model, provider, usageRole: 'classify' },
|
|
76
96
|
);
|
|
77
97
|
return parseClassifier(raw);
|
|
78
98
|
};
|
|
@@ -2490,6 +2490,12 @@ export function buildDashboardSlashRegistry(nowDeps?: ContextNowDeps, decideLedg
|
|
|
2490
2490
|
});
|
|
2491
2491
|
if (result.kind === 'launch') {
|
|
2492
2492
|
ctx.chatLines.push(ctx.accent(` ✅ 전제 검사 통과 — 골: ${result.goalFile}`));
|
|
2493
|
+
const { resolveObserveOnlyDecision } = await import('../../self-implement/observe-only.js');
|
|
2494
|
+
if (resolveObserveOnlyDecision().enabled) {
|
|
2495
|
+
ctx.chatLines.push(ctx.muted(' 관측 전용이라 런을 발사하지 않았습니다 · 코드도 안 바꿨습니다'));
|
|
2496
|
+
ctx.chatLines.push(ctx.muted(' 조회: elanous logs --category self-implement --since 10m'));
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2493
2499
|
// ⭐ 런을 «띄운다» — detached 라 이 TUI 를 닫아도 런은 산다.
|
|
2494
2500
|
// ⛔ spawn 을 여기서 새로 쓰지 않는다 — `launchDevGoalFileDetached` «한 자리»가 인자·env 를 갖는다.
|
|
2495
2501
|
// ⛔ 그리고 「띄웠다」와 「끝났다」는 다른 값이다 — 이 표면은 «띄운 것»까지만 말한다.
|
package/src/debug/log.ts
CHANGED
|
@@ -949,7 +949,7 @@ const SECRET_TEXT_RULES: readonly { readonly id: string; readonly re: RegExp; re
|
|
|
949
949
|
{ id: 'gcp-api-key', re: /\b(AIza)[0-9A-Za-z_-]{35}\b/g, to: '$1***' },
|
|
950
950
|
{ id: 'jwt', re: /\b(ey)[A-Za-z0-9_-]{10,}\.ey[A-Za-z0-9._\\/-]{10,}/g, to: '$1***' },
|
|
951
951
|
// gitleaks: generic-api-key 축소판 — `key = value` 형태.
|
|
952
|
-
{ id: 'generic-api-key', re: /\b(api[_-]?key|secret|password|passwd|token|credential)\b(\s*[:=]\s*)["']?[^\s"',;)]{4,}/gi, to: '$1$2***' },
|
|
952
|
+
{ id: 'generic-api-key', re: /\b(access[_-]?token|refresh[_-]?token|api[_-]?key|secret|password|passwd|token|credential)\b(\s*[:=]\s*)["']?[^\s"',;)]{4,}/gi, to: '$1$2***' },
|
|
953
953
|
// 환경변수 형태 `OPENROUTER_API_KEY=…` — 위 규칙은 `_API_KEY` 앞에 단어 경계가 없어 못 잡는다. 값에 글자가 있어야 한다(`MAX_TOKEN=4096` 은 그대로).
|
|
954
954
|
{ id: 'env-secret', re: /\b([A-Z][A-Z0-9]*_(?:[A-Z0-9]+_)*(?:API_KEY|TOKEN|SECRET|PASSWORD|ACCESS_KEY))(\s*[:=]\s*)["']?(?=[^\s"',;)]*[A-Za-z])[^\s"',;)]{8,}/g, to: '$1$2***' },
|
|
955
955
|
// BEDROCK-PROVIDER — `AWS_BEARER_TOKEN_BEDROCK=…` 은 이름이 TOKEN 으로 «끝나지» 않아 위 규칙이 못 잡는다.
|