elanous 0.2.4 → 0.2.5
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/README.md +3 -3
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 1751.50b96ea9c37b49b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +25 -0
- package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +5 -0
- package/apps/pwa/out/_next/static/chunks/4440-18bb160d95819f4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → 4daa2798-1363d725c79f3593.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5791-bb82743fa6299562.js → 5348-bbf838e119661eee.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5391-8793f88b03b30161.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7527.943753b6ed829f09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 8617.465ca22a319c95b3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5080-1613752891fcadb4.js → 8918-482b30ce2a8ebf4c.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9238.2cd5f47f4bf7a2c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 9704-3221c102623c8d73.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f89e9a303515a033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-4f403cd060442c95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-9fa879ebf5959096.js → page-0ac5d053f0444d21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-4472ddf1e2458e69.js → page-72bd384898d88955.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-112f7e477bda77fd.js → page-bccce0babceae30f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6f3850d-7f324c6566002113.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-e5bea36f183b25e6.js → webpack-2bf59c720fe9542c.js} +1 -1
- package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
- package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → ktMqfrBbf8BMGac0jqLrb}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +29 -27
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +29 -27
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +29 -27
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +26 -24
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +26 -24
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +26 -24
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +29 -27
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +29 -27
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +29 -27
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/icons/elanous-16.png +0 -0
- package/apps/pwa/out/icons/elanous-180.png +0 -0
- package/apps/pwa/out/icons/elanous-192.png +0 -0
- package/apps/pwa/out/icons/elanous-32.png +0 -0
- package/apps/pwa/out/icons/elanous-512.png +0 -0
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +26 -24
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +29 -27
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +29 -27
- package/apps/pwa/out/manifest.webmanifest +5 -2
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +26 -24
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +26 -24
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +29 -27
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +29 -27
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +27 -25
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +29 -27
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +26 -24
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +29 -27
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +29 -27
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +29 -27
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +29 -27
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +29 -27
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +26 -24
- package/apps/pwa/out/sw-strategies.js +44 -0
- package/apps/pwa/out/sw.js +6 -44
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +29 -27
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +29 -27
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +29 -27
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +29 -27
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +29 -27
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +29 -27
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +29 -27
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +29 -27
- package/catalog/resources.yaml +6 -6
- package/docs/goal-context/steward-directives-2026-09-28.md +35 -37
- package/graphs/landing/landing-heal.yaml +1 -1
- package/graphs/release/recipes.yaml +8 -1
- package/graphs/release/release-loop.yaml +6 -1
- package/graphs/video/README.md +1 -0
- package/graphs/video/explainer-line.yaml +58 -0
- package/package.json +3 -1
- package/plugins/job-coach/.codex-plugin/plugin.json +18 -1
- package/plugins/job-coach/README.md +12 -0
- package/plugins/job-coach/connectors/ncs/server.ts +4 -3
- package/plugins/job-coach/graphs/gap-judge.ts +44 -0
- package/plugins/job-coach/graphs/recipes.yaml +27 -0
- package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
- package/plugins/job-coach/graphs/run-step.ts +211 -17
- package/plugins/job-coach/plugin.json +16 -3
- package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
- package/plugins/job-coach/skills/interview-to-profile/SKILL.md +18 -1
- package/scripts/backup/elanous-backup.sh +4 -1
- package/scripts/build-docs-site.ts +4 -3
- package/scripts/coord-channel-watch.sh +23 -4
- package/scripts/coord-post.sh +49 -12
- package/scripts/coord-tracks.json +5 -5
- package/scripts/eval-bot-vs-grok.ts +79 -0
- package/scripts/eval-grok-live-baseline.ts +36 -0
- package/scripts/fixtures/front-route-corpus.sample.json +17 -0
- package/scripts/fleet/node-setup.sh +46 -7
- package/scripts/landing-heal/must-fix-match.ts +26 -0
- package/scripts/landing-heal/run-mission.ts +114 -20
- package/scripts/lib/front-route-measurement.ts +131 -0
- package/scripts/lib/tui-sim-keys.ts +42 -0
- package/scripts/measure-front-route-classifier.ts +56 -0
- package/scripts/media/ocr-leak-scan.sh +21 -0
- package/scripts/public-export.ts +2 -3
- package/scripts/public-import-pr.ts +80 -6
- package/scripts/publish-internal-dist.ts +2 -3
- package/scripts/red-sweep-diff.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +72 -0
- package/scripts/release-loop/gate-node.ts +332 -44
- package/scripts/release-loop/publish-node.ts +7 -3
- package/scripts/release-loop/release-docs.ts +20 -13
- package/scripts/release-loop/test-durations.ts +63 -0
- package/scripts/release-loop/upgrade-node.ts +3 -2
- package/scripts/test-audit-coverage-per-file.sh +16 -0
- package/scripts/test-audit-meaningless.ts +88 -0
- package/scripts/test-audit-overlap-and-weak.ts +73 -0
- package/scripts/test-deterministic.ts +27 -5
- package/scripts/tui-sim.ts +59 -14
- package/scripts/ux/bump-installed.sh +20 -0
- package/scripts/ux/lib/cdp.ts +72 -0
- package/scripts/ux/record-page.ts +50 -0
- package/skills/explainer-video/SKILL.md +99 -0
- package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
- package/skills/explainer-video/engine/build.mjs +431 -0
- package/skills/explainer-video/engine/vo.ts +37 -0
- package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
- package/src/agent/nested-agent-env.ts +1 -0
- package/src/agent-mission/driver.ts +95 -16
- package/src/agent-mission/mission-cli.ts +6 -0
- package/src/agent-mission/resource-ladder.ts +73 -25
- package/src/auth/acp-token.ts +16 -0
- package/src/auth/github-app-token.ts +112 -0
- package/src/autopilot/gh-rest-fallback.ts +177 -0
- package/src/autopilot/pr-manager.ts +51 -4
- package/src/boot/acp-server.ts +2 -16
- package/src/boot/daemon-tools/web-search.ts +2 -1
- package/src/boot/ws-bridge.ts +11 -0
- package/src/chat/index.ts +37 -8
- package/src/chat/log-scroll-key.ts +12 -0
- package/src/chat/submit-trace.ts +30 -0
- package/src/cli/agent-cli.ts +7 -2
- package/src/cli/decisions-cli.ts +94 -0
- package/src/cli/doctor-cli.ts +40 -54
- package/src/cli/doctor-readiness.ts +16 -24
- package/src/cli/intake-cli.ts +1 -1
- package/src/cli/mcp-call.ts +9 -0
- package/src/cli/mcp-gateway-cli.ts +7 -3
- package/src/cli/plugin-cli.ts +109 -11
- package/src/cli/pr-lineage.ts +2 -1
- package/src/cli/pwa-start.ts +3 -0
- package/src/cli/release-cli.ts +94 -7
- package/src/cli/self-update.ts +7 -4
- package/src/cli/start-cli.ts +33 -14
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/index.ts +62 -13
- package/src/dashboard/input/no-provider-reply.ts +13 -0
- package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
- package/src/dashboard/stale-install-check.ts +77 -0
- package/src/decisions/decision-ledger.ts +404 -0
- package/src/domains/outbound-alert.ts +8 -2
- package/src/domains/telegram-kind-route.ts +21 -0
- package/src/execution-loop/dispatch-task.ts +139 -0
- package/src/execution-loop/gate-decision-summary.ts +29 -0
- package/src/execution-loop/gates.ts +197 -0
- package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
- package/src/graph-kinds/plugin-nodes.ts +10 -2
- package/src/graph-runner/runner.ts +35 -5
- package/src/grounding/token.ts +12 -6
- package/src/harness/harness-cli-command.ts +68 -9
- package/src/harness/harness-pod-dispatch.ts +8 -2
- package/src/harness/harness-stop.ts +147 -18
- package/src/harness/self-send-decide.ts +26 -17
- package/src/harness/self-send-target.ts +22 -1
- package/src/harness/worktree-branch-prefix.ts +4 -3
- package/src/index.ts +56 -13
- package/src/instance/resolve.ts +6 -0
- package/src/intake-plane/collect-telegram-saved.ts +5 -0
- package/src/intake-plane/digest.ts +11 -2
- package/src/live/detail-switch.ts +8 -3
- package/src/llm/usable-llm.ts +32 -0
- package/src/loops/registry.ts +27 -5
- package/src/market/publish.ts +59 -3
- package/src/native-tool-catalog.ts +2 -2
- package/src/nexus/api/graph-approvals.ts +125 -0
- package/src/nexus/api/http-server.ts +60 -6
- package/src/nexus/api/log-fabric.ts +10 -1
- package/src/nexus/api/mcp-oauth-hint.ts +10 -9
- package/src/nexus/api/merge-approvals.ts +2 -1
- package/src/nexus/api/meta-api.ts +14 -0
- package/src/nexus/api/plugins-credentials-api.ts +47 -0
- package/src/nexus/api/plugins-market.ts +87 -3
- package/src/nexus/api/pod-credential-api.ts +68 -14
- package/src/nexus/api/public-routes.ts +7 -0
- package/src/nexus/api/trace.ts +57 -6
- package/src/nexus/boot/register-mcp-clients.ts +99 -14
- package/src/nexus/index.ts +33 -32
- package/src/nexus/outbound/router.ts +1 -1
- package/src/onboarding.ts +25 -2
- package/src/plugins/core/host.ts +14 -0
- package/src/plugins/install/market-fetch.ts +4 -3
- package/src/plugins/install/plugin-credentials.ts +106 -0
- package/src/plugins/install/plugin-install.ts +163 -32
- package/src/prompt-library/universal-preamble.ts +8 -2
- package/src/release-loop/checklist.ts +191 -0
- package/src/release-loop/release-note.ts +6 -3
- package/src/self-dev/dev-cli.ts +40 -20
- package/src/self-dev/dev-pipeline.ts +77 -1
- package/src/self-implement/gate-baseline.ts +3 -1
- package/src/self-implement/goal-author.ts +18 -1
- package/src/self-implement/host-regate.ts +6 -2
- package/src/self-implement/orchestrator.ts +7 -2
- package/src/self-implement/seams.ts +4 -2
- package/src/skills/tools/dev-harness.ts +42 -0
- package/src/steward/steward-cards.ts +45 -0
- package/src/steward/triage.ts +50 -14
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +61 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +27 -6
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +39 -9
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +16 -1
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +51 -13
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -28
- package/src/telegram-report.ts +12 -6
- package/src/tui-client/acp-transport-ws-client.ts +72 -5
- package/src/tui.ts +3 -2
- package/src/user-config.ts +28 -2
- package/src/util/spawn-sync-output.ts +15 -0
- package/src/version/code-revision.ts +1 -1
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/free.ts +77 -0
- package/src/web-search/index.ts +2 -0
- package/src/workflow-runtime/deps-bridge.ts +4 -3
- package/src/workflow-runtime/plugin-kind-node.ts +32 -4
- package/src/workflow-runtime/types.ts +2 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1191-7b13a24117a689fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-3fcae5186c64fe6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/319-d37df1b6e0cbeff4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4836-3c93795ab834381e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6090-1bd6077591603947.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7457-f5cb1cc8db9f7453.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-011e1f474efb8b33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-0059d82bdb4812bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9740-52467f244755917f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-21c3261af6ab377c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1991445b8ea86274.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4ebfaee2369fe248.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ca7c3cc305c3285a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9951930add3d2051.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4de08d4b766f134b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7a975e2b9db1dfb7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-49270714ef35bb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-33fbdf353e2a5982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-259f122e2dd64317.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-65b82726753658e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4b8df3748dc06285.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-542a5c0006da637c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-63ffb347831262ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-98e4e359d97263b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-97e24ac675ce576e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ac6391f26391d89d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f45c9d45ffc43bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-36995b9cb5d98218.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0c795b577988d63f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b4311e2f71c6735a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-eb2381074df20dba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-b01336e64eba01ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7af7f21c1f2858ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a98ecd364586c89b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-57f0502dfbfa089b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-3467d2e1abd8a14a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-7842ca23d53ba682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-ae9ac882912b0198.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3a0d72e3f783bcef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-f3b39fe8358c2a97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-5a22af3181ac2afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-1457627bb302a22c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/css/e66b7f5efc8df3f3.css +0 -1
- /package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → ktMqfrBbf8BMGac0jqLrb}/_ssgManifest.js +0 -0
package/src/cli/doctor-cli.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import type { Command } from 'commander';
|
|
9
9
|
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
10
10
|
import { discoverChromeBinary } from '../browser-cdp/client.js';
|
|
11
|
-
import {
|
|
11
|
+
import { resolveUsableLlm, type UsableLlm } from '../llm/usable-llm.js';
|
|
12
12
|
import { detectLocale } from '../expression/locale.js';
|
|
13
13
|
import { findRetiredConfigKeysInFile, getUserConfig, type RetiredConfigKey, type UserConfig } from '../user-config.js';
|
|
14
14
|
import { codeRevision } from '../version/code-revision.js';
|
|
@@ -142,7 +142,8 @@ export interface DoctorOptions {
|
|
|
142
142
|
*/
|
|
143
143
|
readiness?: ReadinessDeps;
|
|
144
144
|
checkReadiness?: (deps: ReadinessDeps) => ReadinessReport;
|
|
145
|
-
|
|
145
|
+
resolveLlm?: () => UsableLlm;
|
|
146
|
+
/** Legacy read-only seam; route selection no longer uses provider-name presence. */
|
|
146
147
|
listAuthProviders?: () => readonly string[];
|
|
147
148
|
/** Read-only `codeRevision()`. */
|
|
148
149
|
codeRevision?: () => string | undefined;
|
|
@@ -187,15 +188,6 @@ export interface DoctorCliDeps extends DoctorOptions, Pick<DoctorFixDeps, 'home'
|
|
|
187
188
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
188
189
|
const tavilyNames = new Set(['TAVILY_API_KEY', 'TAVILY_KEY']);
|
|
189
190
|
|
|
190
|
-
function codexLoginPresent(providers: readonly string[]): boolean {
|
|
191
|
-
return providers.some((name) => name === 'openai-codex' || name.startsWith('openai-codex:'));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** Presence only. Token strings from the auth store never leave this function. */
|
|
195
|
-
function defaultListAuthProviders(): readonly string[] {
|
|
196
|
-
return listProviders();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
191
|
function defaultCodeRevision(): string | undefined {
|
|
200
192
|
try {
|
|
201
193
|
return codeRevision();
|
|
@@ -294,7 +286,6 @@ interface ReadinessLookup {
|
|
|
294
286
|
platform: NodeJS.Platform;
|
|
295
287
|
commandExists: (name: string) => boolean;
|
|
296
288
|
getConfig: () => UserConfig;
|
|
297
|
-
listAuthProviders: () => readonly string[];
|
|
298
289
|
codeRevision: () => string | undefined;
|
|
299
290
|
fetchHealth: () => { daemonSha?: string } | null;
|
|
300
291
|
readInstallPrefix: () => string | null | undefined;
|
|
@@ -306,8 +297,6 @@ interface ReadinessLookup {
|
|
|
306
297
|
/** 저장소가 시험한 bun 판(`.bun-version`) · 지금 도는 bun 판(시험 seam). */
|
|
307
298
|
bunPin?: () => string | null;
|
|
308
299
|
bunVersion?: () => string | null;
|
|
309
|
-
/** LLM 키가 하나라도 풀렸나(자격 보고서에서 · 없으면 못 쟀다). */
|
|
310
|
-
llmKeyResolved?: boolean;
|
|
311
300
|
/** `/etc/os-release` 본문(시험 seam) — 못 읽으면 null. */
|
|
312
301
|
readOsRelease?: () => string | null;
|
|
313
302
|
/** 빌드 도구 탐침(시험 seam). */
|
|
@@ -371,19 +360,6 @@ function resolveReadinessDeps(lookup: ReadinessLookup): ReadinessDeps {
|
|
|
371
360
|
if (provider !== null && provider !== 'auto' && !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(provider)) {
|
|
372
361
|
provider = null;
|
|
373
362
|
}
|
|
374
|
-
let codexLogin: boolean | null = null;
|
|
375
|
-
let anyLogin: boolean | null = null;
|
|
376
|
-
try {
|
|
377
|
-
const providers = lookup.listAuthProviders();
|
|
378
|
-
codexLogin = codexLoginPresent(providers);
|
|
379
|
-
anyLogin = providers.length > 0;
|
|
380
|
-
} catch {
|
|
381
|
-
codexLogin = null;
|
|
382
|
-
}
|
|
383
|
-
// 로그인이 있거나 LLM 키가 풀렸으면 true · 둘 다 «아니라고 잰» 경우만 false · 하나라도 못 쟀으면 null.
|
|
384
|
-
const llmCredentialAvailable = anyLogin === true || lookup.llmKeyResolved === true
|
|
385
|
-
? true
|
|
386
|
-
: anyLogin === false && lookup.llmKeyResolved === false ? false : null;
|
|
387
363
|
const pathEntries = (lookup.env.PATH ?? '').split(lookup.pathDelimiter).filter((entry) => entry.length > 0);
|
|
388
364
|
let ghOnPath: boolean | null = null;
|
|
389
365
|
let ghAuthStatus: number | null = null;
|
|
@@ -466,8 +442,6 @@ function resolveReadinessDeps(lookup: ReadinessLookup): ReadinessDeps {
|
|
|
466
442
|
}
|
|
467
443
|
return {
|
|
468
444
|
provider,
|
|
469
|
-
codexLogin,
|
|
470
|
-
llmCredentialAvailable,
|
|
471
445
|
ghOnPath,
|
|
472
446
|
ghAuthStatus,
|
|
473
447
|
ghVersion,
|
|
@@ -1045,8 +1019,7 @@ export function runDoctor(options: DoctorOptions = {}): DoctorReport {
|
|
|
1045
1019
|
pathDelimiter,
|
|
1046
1020
|
platform,
|
|
1047
1021
|
commandExists,
|
|
1048
|
-
getConfig,
|
|
1049
|
-
listAuthProviders: options.listAuthProviders ?? defaultListAuthProviders,
|
|
1022
|
+
getConfig: () => resolutionOptions.userConfig,
|
|
1050
1023
|
codeRevision: options.codeRevision ?? defaultCodeRevision,
|
|
1051
1024
|
fetchHealth: options.fetchHealth ?? (() => defaultFetchHealth(options.resolveDaemonEndpoint ?? resolveDaemonEndpoint)),
|
|
1052
1025
|
readInstallPrefix: options.readInstallPrefix ?? (() => defaultReadInstallPrefix(root, exists)),
|
|
@@ -1054,12 +1027,17 @@ export function runDoctor(options: DoctorOptions = {}): DoctorReport {
|
|
|
1054
1027
|
ghAuthStatus: options.ghAuthStatus ?? (() => defaultGhAuthStatus(commandExists)),
|
|
1055
1028
|
ghVersion: options.ghVersion ?? (() => defaultGhVersion(commandExists)),
|
|
1056
1029
|
tmpdirSameFsAsBunCache: options.tmpdirSameFsAsBunCache ?? (() => defaultTmpdirSameFsAsBunCache(env)),
|
|
1057
|
-
llmKeyResolved: llmKeyResolvedFrom(credentials),
|
|
1058
1030
|
nodePty: nodePtyStatus(externalCommands.commands),
|
|
1059
1031
|
...(options.probeBuildToolchain ? { probeBuildToolchain: options.probeBuildToolchain } : {}),
|
|
1060
1032
|
...(options.checkPythonEnv ? { checkPythonEnv: options.checkPythonEnv } : {}),
|
|
1061
1033
|
...(options.probeHostEnvironment ? { probeHostEnvironment: options.probeHostEnvironment } : {}),
|
|
1062
1034
|
});
|
|
1035
|
+
// An injected readiness snapshot stays as-is. For a real machine, measure the
|
|
1036
|
+
// same runtime route as `start` rather than inferring usability from key names.
|
|
1037
|
+
if (options.readiness === undefined && readiness.provider !== null) {
|
|
1038
|
+
try { readiness.usableLlm = options.resolveLlm ? options.resolveLlm() : resolveUsableLlm({ config: resolutionOptions.userConfig }); }
|
|
1039
|
+
catch { readiness.usableLlm = null; }
|
|
1040
|
+
}
|
|
1063
1041
|
return {
|
|
1064
1042
|
ok: true,
|
|
1065
1043
|
credentials,
|
|
@@ -1083,15 +1061,14 @@ function formatReadiness(readiness: ReadinessReport | undefined): string[] {
|
|
|
1083
1061
|
if (readiness === undefined) return [];
|
|
1084
1062
|
const todo = readiness.items.filter((entry) => entry.status === 'manual' || entry.status === 'fixable');
|
|
1085
1063
|
return [
|
|
1086
|
-
'
|
|
1064
|
+
'Readiness:',
|
|
1087
1065
|
...readiness.items.map((entry) => {
|
|
1088
1066
|
const remedy = entry.remedy === undefined ? '' : ` — ${entry.remedy}`;
|
|
1089
1067
|
return ` ${entry.id}: ${entry.status} — ${entry.evidence}${remedy}`;
|
|
1090
1068
|
}),
|
|
1091
1069
|
todo.length === 0
|
|
1092
|
-
? '
|
|
1093
|
-
|
|
1094
|
-
: `할 일 ${todo.length}개: ${todo.map((entry) => entry.id).join(', ')} — 처방은 위 각 줄 끝`,
|
|
1070
|
+
? 'Nothing to do.'
|
|
1071
|
+
: `To do (${todo.length}): ${todo.map((entry) => entry.id).join(', ')} — each line above ends with its fix`,
|
|
1095
1072
|
];
|
|
1096
1073
|
}
|
|
1097
1074
|
|
|
@@ -1105,14 +1082,21 @@ function humanFreeFallback(value: string): string {
|
|
|
1105
1082
|
.replace(/\s{2,}/g, ' ').trim().replace(/[—–·;,\s]+$/, '');
|
|
1106
1083
|
}
|
|
1107
1084
|
|
|
1085
|
+
export function humanBreaks(value: string): string | undefined {
|
|
1086
|
+
if (value.trim().toLowerCase() === 'unmeasured'
|
|
1087
|
+
|| /\b\d+ test (failures|errors)\b|\bmeasured\b|\bpostmortem\b|\bquota\b/i.test(value)
|
|
1088
|
+
|| /[가-힣ㄱ-ㅎㅏ-ㅣ]/.test(value)) return undefined;
|
|
1089
|
+
return humanFreeFallback(value) || undefined;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1108
1092
|
function formatCapabilitySummary(summary: DoctorCapabilitySummary): string[] {
|
|
1109
1093
|
const unavailable = summary.unavailable.map((capability) =>
|
|
1110
1094
|
` ${capability.name} — unlock with ${capability.credential}${capability.freeFallback !== undefined && humanFreeFallback(capability.freeFallback) ? `; free alternative: ${humanFreeFallback(capability.freeFallback)}` : ''}`,
|
|
1111
1095
|
);
|
|
1112
1096
|
return [
|
|
1113
|
-
'
|
|
1097
|
+
'Available:',
|
|
1114
1098
|
...(summary.available.length === 0 ? [' None.'] : summary.available.map((capability) => ` ${capability.name} — unlocked by ${capability.credential}`)),
|
|
1115
|
-
'
|
|
1099
|
+
'Unavailable:',
|
|
1116
1100
|
...(unavailable.length === 0 ? [' None.'] : unavailable),
|
|
1117
1101
|
'Unknown by credential:',
|
|
1118
1102
|
...(summary.unknownCredentials.length === 0 ? [' Empty.'] : summary.unknownCredentials.map((credential) => ` ${credential}`)),
|
|
@@ -1129,8 +1113,8 @@ export function formatDoctorReport(report: DoctorReport, options: { credentials?
|
|
|
1129
1113
|
const satisfied = report.credentials.filter((credential) => !credential.resolved && credential.satisfiedBy !== undefined).length;
|
|
1130
1114
|
return [
|
|
1131
1115
|
...formatReadiness(report.readiness),
|
|
1132
|
-
...(requiredMissing.length ? [`⛔
|
|
1133
|
-
|
|
1116
|
+
...(requiredMissing.length ? [`⛔ Required commands missing: ${requiredMissing.join(', ')}`] : []),
|
|
1117
|
+
`Credentials: ${resolved}/${report.credentials.length} resolved${satisfied ? ` · ${satisfied} satisfied by alternative names` : ''} · details: elanous doctor --credentials`,
|
|
1134
1118
|
...(options.credentials ? report.credentials.map((credential) => [
|
|
1135
1119
|
`${credential.name}: ${credential.resolved ? 'resolved' : 'unresolved'} (${credential.source}) — ${credential.note}`,
|
|
1136
1120
|
...(credential.satisfiedBy !== undefined ? [` Satisfied by: ${credential.satisfiedBy.name} (${credential.satisfiedBy.source})`] : []),
|
|
@@ -1138,14 +1122,15 @@ export function formatDoctorReport(report: DoctorReport, options: { credentials?
|
|
|
1138
1122
|
...(credential.freeFallback !== undefined ? [` Free fallback${credential.freeFallbackMode === 'auto' || credential.freeFallbackMode === 'manual' || credential.freeFallbackMode === 'none' ? ` [${credential.freeFallbackMode}]` : ''}: ${humanFreeFallback(credential.freeFallback)}`] : []),
|
|
1139
1123
|
].join('\n')) : []),
|
|
1140
1124
|
...(report.catalogMetadataUnavailable ? ['Catalog metadata unavailable: could not read catalog/resources.yaml.'] : []),
|
|
1141
|
-
...(report.retiredConfigKeys ?? []).map(({ path, reason }) =>
|
|
1125
|
+
...(report.retiredConfigKeys ?? []).map(({ path, reason }) => `Retired config key: ${path} — ${reason}`),
|
|
1142
1126
|
'External commands:',
|
|
1143
1127
|
...report.externalCommands.map((command) => {
|
|
1144
1128
|
const breaks = command.status === 'broken' ? command.breaks_broken ?? command.breaks : command.breaks;
|
|
1129
|
+
const visibleBreaks = breaks === undefined ? undefined : humanBreaks(breaks);
|
|
1145
1130
|
const fix = command.status === 'broken' ? command.fix_broken ?? command.fix : command.fix;
|
|
1146
1131
|
return [
|
|
1147
1132
|
`${command.name}: ${command.status === 'skipped' ? `skipped (${command.platform}-only)` : `${command.status} (${command.tier})`}${command.detail === undefined ? '' : ` — ${command.detail}`}`,
|
|
1148
|
-
...((command.status === 'missing' || command.status === 'broken') &&
|
|
1133
|
+
...((command.status === 'missing' || command.status === 'broken') && visibleBreaks !== undefined ? [` Breaks: ${visibleBreaks}`] : []),
|
|
1149
1134
|
...((command.status === 'missing' || command.status === 'broken') && fix !== undefined ? [` Fix: ${fix}`] : []),
|
|
1150
1135
|
].join('\n');
|
|
1151
1136
|
}),
|
|
@@ -1260,13 +1245,12 @@ export function registerDoctorCommand(program: Command, deps: DoctorCliDeps = {}
|
|
|
1260
1245
|
home: deps.home,
|
|
1261
1246
|
cacheDir: deps.cacheDir,
|
|
1262
1247
|
readdir: deps.readdir,
|
|
1263
|
-
readiness: deps.readiness ?? resolveReadinessDeps({
|
|
1248
|
+
readiness: deps.readiness ?? { ...resolveReadinessDeps({
|
|
1264
1249
|
env: deps.env ?? process.env,
|
|
1265
1250
|
pathDelimiter: deps.pathDelimiter ?? delimiter,
|
|
1266
1251
|
platform: deps.platform ?? process.platform,
|
|
1267
1252
|
commandExists: deps.commandExists ?? ((name) => (deps.env ?? process.env).PATH?.split(deps.pathDelimiter ?? delimiter).some((dir) => existsSync(join(dir, name))) ?? false),
|
|
1268
|
-
getConfig: deps.getUserConfig ?? getUserConfig,
|
|
1269
|
-
listAuthProviders: deps.listAuthProviders ?? defaultListAuthProviders,
|
|
1253
|
+
getConfig: () => deps.userConfig ?? (deps.getUserConfig ?? getUserConfig)(),
|
|
1270
1254
|
codeRevision: deps.codeRevision ?? defaultCodeRevision,
|
|
1271
1255
|
fetchHealth: deps.fetchHealth ?? (() => defaultFetchHealth(deps.resolveDaemonEndpoint ?? resolveDaemonEndpoint)),
|
|
1272
1256
|
readInstallPrefix: deps.readInstallPrefix ?? (() => defaultReadInstallPrefix(deps.repositoryRoot ?? repositoryRoot, deps.exists ?? existsSync)),
|
|
@@ -1274,13 +1258,15 @@ export function registerDoctorCommand(program: Command, deps: DoctorCliDeps = {}
|
|
|
1274
1258
|
// gh 판은 수리 계획에 쓰인다(낡은 gh → 정적 gh) — 🩸 09-25: 여기서 안 재서 계획은 보고서에만 뜨고 적용이 안 됐다.
|
|
1275
1259
|
ghVersion: deps.ghVersion ?? (() => defaultGhVersion((name) => (deps.env ?? process.env).PATH?.split(deps.pathDelimiter ?? delimiter).some((dir) => existsSync(join(dir, name))) ?? false)),
|
|
1276
1260
|
tmpdirSameFsAsBunCache: deps.tmpdirSameFsAsBunCache ?? (() => defaultTmpdirSameFsAsBunCache(deps.env ?? process.env)),
|
|
1277
|
-
|
|
1278
|
-
...(source.ok ? { llmKeyResolved: llmKeyResolvedFrom(source.credentials), nodePty: nodePtyStatus(source.externalCommands) } : {}),
|
|
1261
|
+
...(source.ok ? { nodePty: nodePtyStatus(source.externalCommands) } : {}),
|
|
1279
1262
|
// L0 칸(substrate·docker·kubernetes·memory)은 «정보성·선택 기능»이라 수리 계획에 싣지 않는다 —
|
|
1280
1263
|
// `--sudo` 가 `sudo systemctl start docker` 를 «설치 줄»로 치지 않게 하고, docker·kubectl 탐침(최대 수 초)을 두 번 돌리지 않는다.
|
|
1281
1264
|
// 보고서(`runDoctor`)에는 그대로 나온다.
|
|
1282
1265
|
probeHostEnvironment: () => null,
|
|
1283
|
-
}),
|
|
1266
|
+
}), usableLlm: (() => {
|
|
1267
|
+
try { return deps.resolveLlm ? deps.resolveLlm() : resolveUsableLlm({ config: deps.userConfig ?? (deps.getUserConfig ?? getUserConfig)() }); }
|
|
1268
|
+
catch { return null; }
|
|
1269
|
+
})() },
|
|
1284
1270
|
exists: deps.exists,
|
|
1285
1271
|
readFile: deps.readFile,
|
|
1286
1272
|
writeFile: deps.writeFile,
|
|
@@ -1374,16 +1360,16 @@ export function registerDoctorCommand(program: Command, deps: DoctorCliDeps = {}
|
|
|
1374
1360
|
else out.log([
|
|
1375
1361
|
formatDoctorReport(currentReport, { credentials: opts.credentials }),
|
|
1376
1362
|
...(advice ? [formatDoctorAdvice(advice)] : []),
|
|
1377
|
-
'
|
|
1363
|
+
'Fix plan:',
|
|
1378
1364
|
...plan.items.map((item) => ` ${item.id}: ${item.status} — ${item.path} — ${item.action}${item.reason ? ` — ${item.reason}` : ''}`),
|
|
1379
1365
|
...plan.manual.map((item) => ` ${item.id}: manual${item.remedy ? ` — ${item.remedy}` : ''}`),
|
|
1380
1366
|
...manualCommandFixes(currentReport).map((line) => ` ${line}`),
|
|
1381
|
-
...(gitInstall ? [`
|
|
1367
|
+
...(gitInstall ? [`Git installation: ${gitInstall.detail}${gitPlan?.note ? ` — ${gitPlan.note}` : ''}`] : []),
|
|
1382
1368
|
...(sudoResult ? [sudoResult.sudoAvailable
|
|
1383
|
-
? `
|
|
1384
|
-
: '
|
|
1385
|
-
...(results ? ['
|
|
1386
|
-
...(restartResult ? [
|
|
1369
|
+
? `Sudo installation: ${sudoResult.runs.length ? sudoResult.runs.map((entry) => `${entry.result} — ${entry.command}${entry.detail ? ` — ${entry.detail}` : ''}`).join(' · ') : '칠 줄 없음'}`
|
|
1370
|
+
: 'Sudo installation: 건너뜀 — 이 기계는 sudo 에 암호가 필요하다(sudo -n true 실패). 위 «manual» 줄을 직접 치세요.'] : []),
|
|
1371
|
+
...(results ? ['Applied:', ...results.items.map((item) => ` ${item.id}: ${item.result} — ${item.path}${item.reason ? ` — ${item.reason}` : ''}`)] : ['적용하려면 --fix --yes']),
|
|
1372
|
+
...(restartResult ? [`Service restart: ${restartResult.result} — ${restartResult.reason}`] : []),
|
|
1387
1373
|
].join('\n'));
|
|
1388
1374
|
const exitCode = Math.max(results?.exitCode ?? 0, sudoResult?.exitCode ?? 0, restartResult?.result === 'failed' ? 1 : 0, currentReport.requiredMissing?.length ? 1 : 0, gitInstall?.ran && !gitInstall.ok ? 1 : 0);
|
|
1389
1375
|
if (results || exitCode) setExitCode(exitCode);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { remediesFor, type DistroFamily } from './doctor-distro.js';
|
|
2
|
+
import type { UsableLlm } from '../llm/usable-llm.js';
|
|
2
3
|
import { providerSecretNames } from '../nexus/install/launchd.js';
|
|
3
4
|
import { win32 } from 'node:path';
|
|
4
5
|
/**
|
|
@@ -42,13 +43,8 @@ export interface ReadinessDeps {
|
|
|
42
43
|
* must pass `null` rather than omit it).
|
|
43
44
|
*/
|
|
44
45
|
provider?: string | null;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
* The token itself is never passed in.
|
|
48
|
-
*/
|
|
49
|
-
codexLogin?: boolean | null;
|
|
50
|
-
/** LLM 을 부를 자격이 «하나라도» 있나(어떤 로그인이든 · LLM 키가 풀렸든). 없으면(undefined/null) 못 쟀다. */
|
|
51
|
-
llmCredentialAvailable?: boolean | null;
|
|
46
|
+
/** Selected runtime route, already resolved with the runtime auto selector. null = unmeasured. */
|
|
47
|
+
usableLlm?: UsableLlm | null;
|
|
52
48
|
/** `gh` is on PATH. `null` means not measured. */
|
|
53
49
|
ghOnPath?: boolean | null;
|
|
54
50
|
/** `gh --version` 의 판 · null/undefined = 못 쟀다. */
|
|
@@ -210,23 +206,19 @@ function providerDecision(deps: ReadinessDeps): ReadinessItem {
|
|
|
210
206
|
return item('provider-decision', 'unknown', 'llm.provider was not measured');
|
|
211
207
|
}
|
|
212
208
|
const provider = deps.provider.trim() || 'auto';
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (deps.llmCredentialAvailable === false) {
|
|
227
|
-
return item('provider-decision', 'manual', 'llm.provider=auto but no LLM login or key was found — LLM commands will fail', 'elanous login openai-codex');
|
|
228
|
-
}
|
|
229
|
-
return item('provider-decision', 'ok', 'llm.provider=auto and no codex login');
|
|
209
|
+
const shown = KNOWN_PROVIDERS.has(provider) ? provider : '(set · value not shown)';
|
|
210
|
+
if (deps.usableLlm == null) return item('provider-decision', 'unknown', `llm.provider=${shown} route was not measured`);
|
|
211
|
+
const { usable, provider: selected, via, why } = deps.usableLlm;
|
|
212
|
+
if (!usable) {
|
|
213
|
+
const reason = why === 'no usable LLM route selected' ? why : 'route unavailable';
|
|
214
|
+
const remedy = provider === 'auto' || provider === 'openai-codex' ? 'elanous login openai-codex'
|
|
215
|
+
: provider === 'openai' ? 'Set OPENAI_API_KEY or llm.apiKey for openai'
|
|
216
|
+
: provider === 'local' ? 'Set llm.baseUrl or LOCAL_LLM_URL for local'
|
|
217
|
+
: KNOWN_PROVIDERS.has(provider) ? `Configure credentials for llm.provider=${provider}` : undefined;
|
|
218
|
+
return item('provider-decision', 'manual', `llm.provider=${shown} selected no usable LLM (via none) — ${reason}`, remedy);
|
|
219
|
+
}
|
|
220
|
+
const selectedName = selected && KNOWN_PROVIDERS.has(selected) ? selected : 'selected provider';
|
|
221
|
+
return item('provider-decision', 'ok', `llm.provider=${shown} → ${via} ${selectedName}`);
|
|
230
222
|
}
|
|
231
223
|
|
|
232
224
|
/** Debian 계열 apt 의 gh 는 GH_MIN_VERSION 미만이다(📏 09-25: Debian 12 = 2.23 · Ubuntu 24.04 = 2.45) — apt 로 깔면 곧바로
|
package/src/cli/intake-cli.ts
CHANGED
|
@@ -282,7 +282,7 @@ export function registerIntakeCommands(program: Command): void {
|
|
|
282
282
|
const { sendTelegramReport } = await import('../telegram-report.js');
|
|
283
283
|
const { getUserConfig } = await import('../user-config.js');
|
|
284
284
|
const text = renderDigestTelegram(d, { ...(opts.vault ? { vaultRoot: opts.vault } : {}), ...(opts.note ? { notePath: opts.note } : {}) });
|
|
285
|
-
const sent = await sendTelegramReport(getUserConfig(), text, { markdown: true });
|
|
285
|
+
const sent = await sendTelegramReport(getUserConfig(), text, { markdown: true, kind: 'intake' });
|
|
286
286
|
debug.log('intake.digest', 'telegram', { day, absorbed: d.absorbed.length, goals: d.goals.length, sent });
|
|
287
287
|
console.log(sent ? `텔레그램 보고 채널로 보냈다 (${day} · 흡수 ${d.absorbed.length} · 골 후보 ${d.goals.length})` : '텔레그램 보고 채널 설정이 없다(telegram.reportChannel) — 보내지 않음');
|
|
288
288
|
if (!sent) process.exitCode = 3;
|
package/src/cli/mcp-call.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveDaemonEndpoint, type ResolveDaemonEndpointOpts } from '../nexus/daemon-endpoint.js';
|
|
2
2
|
import { RemotesStore } from './remotes.js';
|
|
3
3
|
import { bookmarkAttachDefaults } from './remote-resolve.js';
|
|
4
|
+
import { getNodeKind } from '../graph-kinds/registry.js';
|
|
4
5
|
|
|
5
6
|
export type McpCliClassification =
|
|
6
7
|
| 'ok'
|
|
@@ -84,7 +85,15 @@ export async function callDaemonMcpTool(opts: {
|
|
|
84
85
|
arguments: Record<string, unknown>;
|
|
85
86
|
endpoint?: string | ResolvedEndpoint;
|
|
86
87
|
fetchFn?: McpCallOpts['fetchFn'];
|
|
88
|
+
pluginKind?: string;
|
|
87
89
|
}): Promise<unknown> {
|
|
90
|
+
if (opts.pluginKind) {
|
|
91
|
+
const entry = getNodeKind('workflow', opts.pluginKind);
|
|
92
|
+
if (!entry || entry.core || !entry.plugin || !entry.run || !('mcp' in entry.run)
|
|
93
|
+
|| opts.tool !== `${entry.run.mcp.server}.${entry.run.mcp.tool}`) {
|
|
94
|
+
throw new McpCliFailure('mcp-usage-error', 'invalid plugin MCP kind');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
const endpoint = typeof opts.endpoint === 'string' ? { url: opts.endpoint } : opts.endpoint;
|
|
89
98
|
const resolved = endpoint ? { ok: true as const, value: endpoint } : resolveMcpEndpoint({});
|
|
90
99
|
if (!resolved.ok) throw new McpCliFailure(resolved.classification, resolved.message);
|
|
@@ -6,6 +6,7 @@ import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
|
6
6
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
7
7
|
import { issueMcpPat, listMcpPats, revokeMcpPat } from '../mcp-gateway/pat-store.js';
|
|
8
8
|
import { startMcpGateway } from '../mcp-gateway/gateway.js';
|
|
9
|
+
import { resolveDaemonEndpoint } from '../nexus/daemon-endpoint.js';
|
|
9
10
|
|
|
10
11
|
function privateTokenFile(path: string): string {
|
|
11
12
|
const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
@@ -47,12 +48,15 @@ export function registerMcpGatewayCommands(mcp: Command): void {
|
|
|
47
48
|
.description('Owner-PAT authenticated public MCP relay to the scoped NEXUS endpoint')
|
|
48
49
|
.option('--host <host>', 'Bind host', '127.0.0.1')
|
|
49
50
|
.option('--port <port>', 'Bind port', '31482')
|
|
50
|
-
.
|
|
51
|
+
.option('--nexus-url <url>', 'NEXUS base URL. Default: the current daemon (elanous nexus show).')
|
|
51
52
|
.option('--public-url <url>', 'Public HTTPS origin used in protected resource metadata')
|
|
52
53
|
.option('--nexus-token-file <path>', 'Private file holding the mcp-public NEXUS token; use - for stdin')
|
|
53
|
-
.action(safeAction(async (opts: { host: string; port: string; nexusUrl
|
|
54
|
+
.action(safeAction(async (opts: { host: string; port: string; nexusUrl?: string; publicUrl?: string; nexusTokenFile?: string }) => {
|
|
54
55
|
const port = Number(opts.port);
|
|
55
56
|
if (!Number.isSafeInteger(port) || port < 1 || port > 65535) throw new Error('invalid gateway port');
|
|
57
|
+
// 데몬 주소는 짐작하지 않는다 — 통합관제(daemon-endpoint)에 묻고, 모르면 멈춘다(대표 09-28).
|
|
58
|
+
const nexusUrl = opts.nexusUrl ?? resolveDaemonEndpoint()?.baseUrl;
|
|
59
|
+
if (!nexusUrl) throw new Error('daemon address unknown — pass --nexus-url or start the daemon (elanous nexus show)');
|
|
56
60
|
if (!opts.publicUrl) throw new Error('--public-url <url> required for protected-resource metadata');
|
|
57
61
|
if (!opts.nexusTokenFile) throw new Error('--nexus-token-file <path|-> required (no token argv)');
|
|
58
62
|
if (opts.nexusTokenFile === '-' && process.stdin.isTTY) throw new Error('pipe the nexus token on stdin');
|
|
@@ -66,7 +70,7 @@ export function registerMcpGatewayCommands(mcp: Command): void {
|
|
|
66
70
|
if (!stat.isFile() || (stat.mode & 0o077) !== 0) throw new Error('PAT store must be a private regular file (0600)');
|
|
67
71
|
} finally { closeSync(fd); }
|
|
68
72
|
listMcpPats(patRoot);
|
|
69
|
-
const server = startMcpGateway({ host: opts.host, port, nexusUrl
|
|
73
|
+
const server = startMcpGateway({ host: opts.host, port, nexusUrl, nexusToken, patRoot, publicUrl: opts.publicUrl });
|
|
70
74
|
process.stderr.write(`MCP gateway listening on ${server.hostname}:${server.port}\n`);
|
|
71
75
|
}));
|
|
72
76
|
|
package/src/cli/plugin-cli.ts
CHANGED
|
@@ -5,10 +5,12 @@ import { join } from 'node:path';
|
|
|
5
5
|
import { existsSync, readFileSync } from 'node:fs';
|
|
6
6
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
7
7
|
import { userConfigPath } from '../user-config.js';
|
|
8
|
-
import { debug } from '../debug/log.js';
|
|
8
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
9
|
+
import { addMarket, listMarkets, MarketFetchError, updateMarket } from '../plugins/install/market-fetch.js';
|
|
9
10
|
import { emitDecision } from '../live/detail-switch.js';
|
|
10
11
|
import { OFFICIAL_INDEX_KEYS } from '../market/official-keys.js';
|
|
11
12
|
import { installPlugin, listInstalledPlugins, PluginInstallError, removePlugin, type InstallEvent } from '../plugins/install/plugin-install.js';
|
|
13
|
+
import { credentialStatus, setPluginCredentials } from '../plugins/install/plugin-credentials.js';
|
|
12
14
|
|
|
13
15
|
function keys(): ReadonlyArray<{ keyId: string; publicKey: string }> {
|
|
14
16
|
const configPath = userConfigPath();
|
|
@@ -32,43 +34,99 @@ async function askConsent(capabilities: string[], json: boolean): Promise<boolea
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
function outputEvent(event: InstallEvent, json: boolean): void {
|
|
37
|
+
function outputEvent(event: InstallEvent, json: boolean, nodeCount: { value: number }): void {
|
|
36
38
|
// Connector field names are useful; values and secret-field metadata are not needed here.
|
|
37
39
|
const safe = event.event === 'credentials'
|
|
38
40
|
? { event: 'credentials', connectors: event.connectors.map(({ id, fields }) => ({ id, fields: fields.map(({ name }) => name) })) }
|
|
39
41
|
: event;
|
|
40
42
|
debug.log('plugin.cli', event.event, { event: event.event });
|
|
43
|
+
if (event.event === 'registered') nodeCount.value = event.nodes.length;
|
|
41
44
|
if (json) stdout.write(JSON.stringify(safe) + '\n');
|
|
42
45
|
else if (event.event === 'credentials') {
|
|
43
46
|
if (event.connectors.length) console.log(`Connectors: ${event.connectors.map(connector => connector.id).join(', ')} — configure via elanous connector settings (no secrets requested here)`);
|
|
44
|
-
} else if (event.event === 'done') console.log(`Installed ${event.plugin}@${event.version}`);
|
|
47
|
+
} else if (event.event === 'done') console.log(`Installed ${event.plugin}@${event.version} (${nodeCount.value} nodes)`);
|
|
45
48
|
else if (event.event === 'consent' && event.required) console.log(`Permissions: ${event.capabilities.join(', ')}`);
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
/** Only our own install/market errors carry a cause (fixed wording that may name the user's own spec); URLs and secrets are masked; any other error stays generic. */
|
|
52
|
+
function safeCause(error: unknown): string {
|
|
53
|
+
if (!(error instanceof PluginInstallError || error instanceof MarketFetchError)) return 'unexpected error';
|
|
54
|
+
return redactSecretText(error.message.replace(/https?:\/\/[^\s"'<>]+/gi, '[redacted URL]'));
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
export function registerPluginCommands(program: Command): void {
|
|
49
58
|
const plugin = program.command('plugin').description('Install and manage Elanous plugins');
|
|
50
59
|
plugin.command('add <spec>').description('Install a local path, pinned git plugin or signed market plugin')
|
|
51
60
|
.option('--yes', 'Accept requested capabilities')
|
|
52
61
|
.option('--json', 'NDJSON progress events')
|
|
53
62
|
.option('--allow-unsigned', 'Allow unsigned marketplace indices')
|
|
54
|
-
.
|
|
63
|
+
.option('--refresh', 'Refresh the signed marketplace index before installing')
|
|
64
|
+
.action(async (spec: string, opts: { yes?: boolean; json?: boolean; allowUnsigned?: boolean; refresh?: boolean }) => {
|
|
55
65
|
try {
|
|
56
66
|
const root = elanousStateRoot();
|
|
67
|
+
const nodeCount = { value: 0 };
|
|
57
68
|
await installPlugin(spec, {
|
|
58
69
|
root, marketDir: join(root, 'plugins', 'markets'), trustedKeys: keys(),
|
|
59
|
-
yes: opts.yes, allowUnsigned: opts.allowUnsigned,
|
|
60
|
-
onEvent: event => outputEvent(event, !!opts.json),
|
|
70
|
+
yes: opts.yes, allowUnsigned: opts.allowUnsigned, refresh: opts.refresh,
|
|
71
|
+
onEvent: event => outputEvent(event, !!opts.json, nodeCount),
|
|
61
72
|
consent: capabilities => askConsent(capabilities, !!opts.json),
|
|
62
73
|
});
|
|
63
74
|
emitDecision({ kind: 'ROUTE', what: 'plugin add', reason: 'plugin installed', purpose: 'make plugin available', target: 'plugin host' });
|
|
64
75
|
} catch (error) {
|
|
65
76
|
const reason = error instanceof PluginInstallError ? error.reason : 'io';
|
|
66
|
-
// Installer errors may embed an arbitrary source path or git URL; never echo them or config secrets.
|
|
67
77
|
const detail = reason === 'consent-denied' ? 'plugin capabilities require consent' : `plugin installation ${reason} error`;
|
|
68
|
-
|
|
78
|
+
const cause = safeCause(error);
|
|
79
|
+
debug.log('plugin.cli', 'failed', { reason, cause }, { level: 'error' });
|
|
69
80
|
emitDecision({ kind: 'ESCALATE', what: 'plugin add', reason, purpose: 'report installation failure', target: 'user' });
|
|
70
|
-
if (opts.json) stdout.write(JSON.stringify({ event: 'failed', reason, detail }) + '\n');
|
|
71
|
-
else console.error(`plugin add failed: ${detail}`);
|
|
81
|
+
if (opts.json) stdout.write(JSON.stringify({ event: 'failed', reason, detail, ...(reason === 'consent-denied' ? {} : { cause }) }) + '\n');
|
|
82
|
+
else console.error(`plugin add failed: ${detail}${reason === 'consent-denied' ? '' : `: ${cause}`}`);
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
const market = plugin.command('market').description('Manage signed plugin marketplaces');
|
|
87
|
+
market.command('add <name> <url>').description('Register a marketplace URL')
|
|
88
|
+
.action((name: string, url: string) => {
|
|
89
|
+
try {
|
|
90
|
+
const added = addMarket(name, url);
|
|
91
|
+
debug.log('plugin.cli', 'market.add', { name: added.name });
|
|
92
|
+
console.log(`Added market ${added.name} (${added.url})`);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`plugin market add failed: ${safeCause(error)}`);
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
market.command('list').description('List configured marketplaces').option('--json', 'JSON array')
|
|
99
|
+
.action((opts: { json?: boolean }) => {
|
|
100
|
+
try {
|
|
101
|
+
const markets = listMarkets();
|
|
102
|
+
debug.log('plugin.cli', 'market.list', { count: markets.length });
|
|
103
|
+
if (opts.json) stdout.write(JSON.stringify(markets) + '\n');
|
|
104
|
+
else for (const entry of markets) console.log(`${entry.name} (${entry.url})`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (opts.json) stdout.write(JSON.stringify({ event: 'failed', cause: safeCause(error) }) + '\n');
|
|
107
|
+
else console.error(`plugin market list failed: ${safeCause(error)}`);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
market.command('update [name]').description('Refresh signed marketplace indices')
|
|
112
|
+
.action(async (name?: string) => {
|
|
113
|
+
try {
|
|
114
|
+
const markets = listMarkets();
|
|
115
|
+
const selected = name ? markets.filter(entry => entry.name === name) : markets;
|
|
116
|
+
if (!selected.length) throw new Error('market not configured');
|
|
117
|
+
const root = elanousStateRoot();
|
|
118
|
+
for (const entry of selected) {
|
|
119
|
+
try {
|
|
120
|
+
const result = await updateMarket(entry.name, { root, marketDir: join(root, 'plugins', 'markets') });
|
|
121
|
+
debug.log('plugin.cli', 'market.update', { name: result.market.name, sequence: result.index.sequence });
|
|
122
|
+
console.log(`Updated market ${result.market.name} (sequence ${result.index.sequence})`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(`plugin market update ${entry.name} failed: ${safeCause(error)}`);
|
|
125
|
+
process.exitCode = 1;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(`plugin market update failed: ${safeCause(error)}`);
|
|
72
130
|
process.exitCode = 1;
|
|
73
131
|
}
|
|
74
132
|
});
|
|
@@ -83,12 +141,52 @@ export function registerPluginCommands(program: Command): void {
|
|
|
83
141
|
const installed = listInstalledPlugins(root).filter(item => registered.has(`${item.market}/${item.name}/${item.version}`));
|
|
84
142
|
debug.log('plugin.cli', 'list', { count: installed.length });
|
|
85
143
|
if (opts.json) stdout.write(JSON.stringify(installed) + '\n');
|
|
86
|
-
else for (const item of installed) console.log(`${item.name}@${item.version} (${item.market})`);
|
|
144
|
+
else for (const item of installed) console.log(`${item.name}@${item.version} (${item.market})${item.installedAt ? ` — installed ${item.installedAt}` : ''}`);
|
|
87
145
|
} catch {
|
|
88
146
|
console.error('plugin list failed: invalid plugin ledger');
|
|
89
147
|
process.exitCode = 1;
|
|
90
148
|
}
|
|
91
149
|
});
|
|
150
|
+
plugin.command('credentials <plugin>').description('Show or update installed plugin credential status')
|
|
151
|
+
.option('--set <NAME=VALUE>', 'Set a declared field', (value: string, values: string[]) => [...values, value], [] as string[])
|
|
152
|
+
.option('--unset <NAME>', 'Remove a declared field', (value: string, values: string[]) => [...values, value], [] as string[])
|
|
153
|
+
.option('--stdin <NAME>', 'Read one credential value from standard input')
|
|
154
|
+
.option('--json', 'JSON status')
|
|
155
|
+
.action(async (name: string, opts: { set: string[]; unset: string[]; stdin?: string; json?: boolean }) => {
|
|
156
|
+
try {
|
|
157
|
+
const root = elanousStateRoot();
|
|
158
|
+
const fields: Record<string, string | null> = Object.create(null);
|
|
159
|
+
for (const assignment of opts.set) {
|
|
160
|
+
const equal = assignment.indexOf('=');
|
|
161
|
+
if (equal < 1) throw new Error('invalid credential assignment');
|
|
162
|
+
fields[assignment.slice(0, equal)] = assignment.slice(equal + 1);
|
|
163
|
+
}
|
|
164
|
+
for (const field of opts.unset) fields[field] = null;
|
|
165
|
+
if (opts.stdin !== undefined) {
|
|
166
|
+
let input = '';
|
|
167
|
+
for await (const chunk of stdin) {
|
|
168
|
+
input += chunk.toString();
|
|
169
|
+
if (input.includes('\n')) break;
|
|
170
|
+
}
|
|
171
|
+
if (!input) throw new Error('credential stdin is empty');
|
|
172
|
+
fields[opts.stdin] = input.split(/\r?\n/, 1)[0]!;
|
|
173
|
+
}
|
|
174
|
+
if (Object.keys(fields).length > 0) {
|
|
175
|
+
setPluginCredentials(name, fields, root);
|
|
176
|
+
debug.log('plugin.credentials', 'set', { plugin: name, fields: Object.keys(fields), count: Object.keys(fields).length });
|
|
177
|
+
}
|
|
178
|
+
const status = credentialStatus(name, root);
|
|
179
|
+
if (opts.json) stdout.write(JSON.stringify(status) + '\n');
|
|
180
|
+
else for (const field of status.fields) console.log(`${field.name}\t${field.env}\t${field.set ? 'set' : 'unset'}`);
|
|
181
|
+
// The web app's PUT reloads MCP clients itself; a CLI write reaches an already-running daemon only after a reload.
|
|
182
|
+
// stderr in both modes, so `--json` stdout stays one JSON line.
|
|
183
|
+
if (Object.keys(fields).length > 0) console.error('A running daemon applies this to plugin MCP servers after `elanous mcp reload` (the web app does it for you).');
|
|
184
|
+
} catch {
|
|
185
|
+
if (opts.json) stdout.write(JSON.stringify({ error: 'plugin credentials failed' }) + '\n');
|
|
186
|
+
else console.error('plugin credentials failed');
|
|
187
|
+
process.exitCode = 1;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
92
190
|
plugin.command('remove <name>').description('Remove installed plugin versions')
|
|
93
191
|
.action((name: string) => {
|
|
94
192
|
try {
|
package/src/cli/pr-lineage.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const SELF_IMPL_PREFIX = 'self-impl/';
|
|
2
2
|
const LINEAGE_HASH_SUFFIX = /-[0-9a-f]{7,8}$/i;
|
|
3
|
+
const RUN_SUFFIX = /-r[a-z0-9]{6}$/i;
|
|
3
4
|
/**
|
|
4
5
|
* Formal new-generation segment after `self-impl/`: dash-delimited `-goalid-<id>-`.
|
|
5
6
|
* ⛔ A substring like `mygoalid-foo` is not that segment — it has no leading `-`/`^` boundary.
|
|
@@ -9,7 +10,7 @@ const GOAL_ID_SEGMENT = /(?:^|-)goalid-([^/-]+)-/;
|
|
|
9
10
|
/** Lineage slug of a harness branch: `self-impl/<slug>-<7–8 hex>`, or null when the name is not that shape. */
|
|
10
11
|
export function branchLineageSlug(branch: string): string | null {
|
|
11
12
|
if (!branch.startsWith(SELF_IMPL_PREFIX)) return null;
|
|
12
|
-
const rest = branch.slice(SELF_IMPL_PREFIX.length);
|
|
13
|
+
const rest = branch.slice(SELF_IMPL_PREFIX.length).replace(RUN_SUFFIX, '');
|
|
13
14
|
const hash = LINEAGE_HASH_SUFFIX.exec(rest);
|
|
14
15
|
return hash ? rest.slice(0, rest.length - hash[0].length) : rest;
|
|
15
16
|
}
|
package/src/cli/pwa-start.ts
CHANGED
|
@@ -126,6 +126,8 @@ export interface PwaStartOpts {
|
|
|
126
126
|
* MCP-client boot is skipped (PR1 2026-05-13). Default undefined =
|
|
127
127
|
* leave the decision to the daemon-side `mcp.enabled` config. */
|
|
128
128
|
mcpEnabled?: boolean;
|
|
129
|
+
/** Forward an explicit --no-auth opt-out to the detached Nexus child. */
|
|
130
|
+
noAuth?: boolean;
|
|
129
131
|
out?: { log: (s: string) => void; error: (s: string) => void };
|
|
130
132
|
// ─── Test seams ─────────────────────────────────────────────
|
|
131
133
|
bgLaunchFn?: (opts: {
|
|
@@ -237,6 +239,7 @@ function collectForwardArgs(opts: PwaStartOpts, httpPort: number): string[] {
|
|
|
237
239
|
// those gates only matter on the parent (build runs before fork).
|
|
238
240
|
if (opts.watch && (opts.mode ?? 'static') === 'static') args.push('--watch');
|
|
239
241
|
if (opts.mcpEnabled === false) args.push('--no-mcp');
|
|
242
|
+
if (opts.noAuth === true) args.push('--no-auth');
|
|
240
243
|
return args;
|
|
241
244
|
}
|
|
242
245
|
|