@ouro.bot/cli 0.1.0-alpha.81 → 0.1.0-alpha.810
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/LICENSE +21 -0
- package/README.md +154 -23
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/assets/bluebubbles-host +264 -0
- package/changelog.json +5177 -16
- package/deploy/unraid/Dockerfile +48 -0
- package/deploy/unraid/README.txt +3032 -0
- package/deploy/unraid/audit-container-spec.sh +4 -0
- package/deploy/unraid/container-runtime.json +1 -0
- package/deploy/unraid/docker-man-template-transaction.mjs +526 -0
- package/deploy/unraid/docker-man-template-xml.cjs +105 -0
- package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
- package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
- package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
- package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
- package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
- package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
- package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
- package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
- package/deploy/unraid/sanctuary-deployment-target.mjs +709 -0
- package/deploy/unraid/sanctuary-safe-rename.py +24 -0
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2030 -0
- package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
- package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
- package/deploy/unraid/sanctuary.ouro/agent.json +24 -0
- package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
- package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
- package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
- package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
- package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
- package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +11 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +11 -0
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +23 -0
- package/deploy/unraid/sanctuary.xml +27 -0
- package/dist/a2a/card.js +57 -0
- package/dist/a2a/client.js +180 -0
- package/dist/a2a/config.js +50 -0
- package/dist/a2a/delegation-stores.js +56 -0
- package/dist/a2a/did-resolution.js +93 -0
- package/dist/a2a/identity.js +170 -0
- package/dist/a2a/inbound-share.js +107 -0
- package/dist/a2a/mission-result-wire.js +196 -0
- package/dist/a2a/onboarding.js +115 -0
- package/dist/a2a/pin-store.js +132 -0
- package/dist/a2a/seen-ledger.js +120 -0
- package/dist/a2a/server.js +604 -0
- package/dist/a2a/task-store.js +69 -0
- package/dist/a2a/transport.js +45 -0
- package/dist/a2a/types.js +3 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +360 -0
- package/dist/arc/episodes.js +118 -0
- package/dist/arc/evolution.js +490 -0
- package/dist/arc/flight-recorder.js +1034 -0
- package/dist/arc/intentions.js +134 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +386 -0
- package/dist/arc/packets.js +336 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +57 -0
- package/dist/commerce/store.js +755 -0
- package/dist/commerce/types.js +3 -0
- package/dist/heart/active-work.js +820 -29
- package/dist/heart/agent-entry.js +252 -3
- package/dist/heart/approval-files.js +113 -0
- package/dist/heart/approval-store.js +950 -0
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +18 -0
- package/dist/heart/attachments/sources/telegram.js +71 -0
- package/dist/heart/attachments/store.js +132 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +495 -0
- package/dist/heart/autonomy-budget.js +478 -0
- package/dist/heart/awaiting/await-alert.js +148 -0
- package/dist/heart/awaiting/await-expiry.js +143 -0
- package/dist/heart/awaiting/await-loader.js +91 -0
- package/dist/heart/awaiting/await-parser.js +149 -0
- package/dist/heart/awaiting/await-runtime-state.js +100 -0
- package/dist/heart/awaiting/await-scheduler.js +382 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bridges/manager.js +137 -17
- package/dist/heart/bridges/store.js +14 -2
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +64 -18
- package/dist/heart/config-registry.js +331 -0
- package/dist/heart/config.js +142 -129
- package/dist/heart/context-loss-gauntlet.js +387 -0
- package/dist/heart/context-loss-sentinel.js +1157 -0
- package/dist/heart/core.js +2105 -574
- package/dist/heart/cross-chat-delivery.js +9 -22
- package/dist/heart/daemon/agent-config-check.js +451 -0
- package/dist/heart/daemon/agent-discovery.js +185 -3
- package/dist/heart/daemon/agent-service.js +542 -0
- package/dist/heart/daemon/agentic-repair.js +547 -0
- package/dist/heart/daemon/await-private-wake.js +59 -0
- package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
- package/dist/heart/daemon/bluebubbles-host.js +273 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +180 -0
- package/dist/heart/daemon/cli-defaults.js +854 -0
- package/dist/heart/daemon/cli-desk.js +322 -0
- package/dist/heart/daemon/cli-exec.js +8822 -0
- package/dist/heart/daemon/cli-help.js +716 -0
- package/dist/heart/daemon/cli-parse.js +2771 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +777 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
- package/dist/heart/daemon/container-healthcheck.js +112 -0
- package/dist/heart/daemon/container-runtime.js +97 -0
- package/dist/heart/daemon/container-spec-auditor-main.js +170 -0
- package/dist/heart/daemon/container-spec-auditor.js +236 -0
- package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
- package/dist/heart/daemon/daemon-cli.js +29 -2317
- package/dist/heart/daemon/daemon-entry.js +921 -11
- package/dist/heart/daemon/daemon-health.js +186 -0
- package/dist/heart/daemon/daemon-rollup.js +57 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +2073 -104
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +1755 -0
- package/dist/heart/daemon/freshness.js +345 -0
- package/dist/heart/daemon/habit-private-wake.js +61 -0
- package/dist/heart/daemon/health-monitor.js +142 -11
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +78 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +79 -10
- package/dist/heart/daemon/logs-prune.js +132 -0
- package/dist/heart/daemon/mcp-canary.js +524 -0
- package/dist/heart/daemon/message-router.js +65 -5
- package/dist/heart/daemon/migrate-to-desk.js +848 -0
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +22 -14
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/plugin-cli.js +432 -0
- package/dist/heart/daemon/process-manager.js +733 -61
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/prunable-bundle.js +144 -0
- package/dist/heart/daemon/pulse.js +511 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +47 -14
- package/dist/heart/daemon/runtime-metadata.js +2 -30
- package/dist/heart/daemon/runtime-mode.js +13 -2
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2609 -0
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +1866 -0
- package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
- package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +976 -0
- package/dist/heart/daemon/sanctuary-bundle-migration.js +728 -0
- package/dist/heart/daemon/sanctuary-package-management.js +103 -0
- package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
- package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
- package/dist/heart/daemon/sense-manager.js +689 -48
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +1 -1
- package/dist/heart/daemon/socket-client.js +180 -12
- package/dist/heart/daemon/stale-bundle-prune.js +113 -0
- package/dist/heart/daemon/startup-tui.js +339 -0
- package/dist/heart/daemon/supercronic-supervisor.js +282 -0
- package/dist/heart/daemon/task-scheduler.js +117 -39
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +138 -54
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -4
- package/dist/heart/external-events/router.js +1414 -0
- package/dist/heart/frontend-approval-runtime.js +432 -0
- package/dist/heart/frontend-journal.js +215 -0
- package/dist/heart/frontend-session-service.js +237 -0
- package/dist/heart/frontend-socket-client.js +154 -0
- package/dist/heart/frontend-socket.js +400 -0
- package/dist/heart/habits/habit-cancel.js +810 -0
- package/dist/heart/habits/habit-lifecycle.js +1327 -0
- package/dist/heart/habits/habit-migration.js +194 -0
- package/dist/heart/habits/habit-parser.js +278 -0
- package/dist/heart/habits/habit-runtime-state.js +93 -0
- package/dist/heart/habits/habit-scheduler.js +653 -0
- package/dist/heart/habits/habit-session-summary.js +318 -0
- package/dist/heart/habits/habit-session.js +636 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
- package/dist/heart/identity.js +184 -59
- package/dist/heart/kept-notes.js +289 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +356 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +39 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +197 -0
- package/dist/heart/mailbox/readers/agent-machine.js +428 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
- package/dist/heart/mailbox/readers/mail.js +375 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
- package/dist/heart/mailbox/readers/sessions.js +231 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +696 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +11 -0
- package/dist/heart/orientation-frame.js +345 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/primitives.js +1 -1
- package/dist/heart/private-runtime/decision-renderer.js +158 -0
- package/dist/heart/private-runtime/index.js +18 -0
- package/dist/heart/private-runtime/ledger.js +221 -0
- package/dist/heart/private-runtime/policy.js +252 -0
- package/dist/heart/private-runtime/types.js +2 -0
- package/dist/heart/progress-story.js +1 -1
- package/dist/heart/provider-attempt.js +137 -0
- package/dist/heart/provider-binding-resolver.js +273 -0
- package/dist/heart/provider-credentials.js +449 -0
- package/dist/heart/provider-failover.js +311 -0
- package/dist/heart/provider-models.js +96 -0
- package/dist/heart/provider-ping.js +265 -0
- package/dist/heart/provider-readiness-cache.js +119 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +173 -60
- package/dist/heart/providers/azure.js +23 -11
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +34 -38
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex-token.js +349 -0
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/providers/openai-compatible.js +177 -0
- package/dist/heart/run-ledger.js +247 -0
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +607 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +22 -4
- package/dist/heart/session-activity.js +92 -24
- package/dist/heart/session-events.js +1433 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-redaction-repair-cli-main.js +31 -0
- package/dist/heart/session-redaction-repair.js +543 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +133 -0
- package/dist/heart/start-of-turn-packet.js +372 -0
- package/dist/heart/steward-policy.js +302 -0
- package/dist/heart/streaming.js +604 -207
- package/dist/heart/structured-output.js +196 -0
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +11 -7
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-approval.js +342 -0
- package/dist/heart/tool-description.js +155 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +482 -0
- package/dist/heart/turn-execution-lease.js +30 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +432 -0
- package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
- package/dist/heart/versioning/ouro-version-manager.js +409 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/versioning/update-hooks.js +154 -0
- package/dist/heart/versioning/version-intent.js +114 -0
- package/dist/heart/work-card.js +380 -0
- package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
- package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
- package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
- package/dist/mailbox-ui/index.html +16 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +889 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/cache-sync-cli.js +58 -0
- package/dist/mailroom/core.js +803 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +568 -0
- package/dist/mailroom/hosted-cache-sync.js +384 -0
- package/dist/mailroom/mbox-import.js +393 -0
- package/dist/mailroom/migration.js +164 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +292 -0
- package/dist/mailroom/search-cache.js +513 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +24 -2
- package/dist/mind/context.js +279 -111
- package/dist/mind/desk-section.js +362 -0
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +68 -77
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/{associative-recall.js → note-search.js} +47 -58
- package/dist/mind/obligation-steering.js +227 -0
- package/dist/mind/pending.js +34 -8
- package/dist/mind/prompt-budget.js +479 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1059 -187
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/record-paths.js +312 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/session-transaction.js +564 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +139 -5
- package/dist/nerves/coverage/run-artifacts.js +55 -35
- package/dist/nerves/coverage/source-scanner.js +4 -4
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +293 -9
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +159 -0
- package/dist/nerves/runtime.js +17 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +16 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +1045 -0
- package/dist/repertoire/bundle-templates.js +71 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +331 -0
- package/dist/repertoire/coding/feedback.js +218 -30
- package/dist/repertoire/coding/index.js +15 -3
- package/dist/repertoire/coding/manager.js +166 -10
- package/dist/repertoire/coding/spawner.js +58 -11
- package/dist/repertoire/coding/tools.js +242 -14
- package/dist/repertoire/coding/workbench-client.js +272 -0
- package/dist/repertoire/coding/workbench-manager.js +346 -0
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +178 -0
- package/dist/repertoire/desk/classifier.js +362 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +811 -18
- package/dist/repertoire/mcp-client.js +44 -3
- package/dist/repertoire/mcp-manager.js +331 -27
- package/dist/repertoire/mcp-tools.js +83 -0
- package/dist/repertoire/plugin-mcp.js +175 -0
- package/dist/repertoire/plugins.js +253 -0
- package/dist/repertoire/relationship-authorization.js +194 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +48 -4
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tool-arguments.js +148 -0
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-a2a.js +699 -0
- package/dist/repertoire/tools-attachments.js +322 -0
- package/dist/repertoire/tools-awaiting.js +575 -0
- package/dist/repertoire/tools-base.js +82 -1139
- package/dist/repertoire/tools-bluebubbles.js +2 -0
- package/dist/repertoire/tools-bridge.js +144 -0
- package/dist/repertoire/tools-bundle.js +993 -0
- package/dist/repertoire/tools-commerce.js +253 -0
- package/dist/repertoire/tools-config.js +186 -0
- package/dist/repertoire/tools-continuity.js +575 -0
- package/dist/repertoire/tools-credential.js +383 -0
- package/dist/repertoire/tools-evolution.js +527 -0
- package/dist/repertoire/tools-files.js +344 -0
- package/dist/repertoire/tools-flight.js +290 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +3 -8
- package/dist/repertoire/tools-habits.js +103 -0
- package/dist/repertoire/tools-mail.js +1828 -0
- package/dist/repertoire/tools-notes.js +485 -0
- package/dist/repertoire/tools-obligations.js +182 -0
- package/dist/repertoire/tools-orientation.js +31 -0
- package/dist/repertoire/tools-record.js +482 -0
- package/dist/repertoire/tools-rsvp.js +139 -0
- package/dist/repertoire/tools-runtime.js +150 -0
- package/dist/repertoire/tools-session.js +1108 -0
- package/dist/repertoire/tools-shell.js +133 -0
- package/dist/repertoire/tools-steward-policy.js +95 -0
- package/dist/repertoire/tools-stripe.js +224 -0
- package/dist/repertoire/tools-surface.js +369 -0
- package/dist/repertoire/tools-teams.js +12 -39
- package/dist/repertoire/tools-telegram-contacts.js +37 -0
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +982 -0
- package/dist/repertoire/tools-unraid.js +484 -0
- package/dist/repertoire/tools-user-profile.js +146 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools-voice.js +145 -0
- package/dist/repertoire/tools.js +377 -80
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/unraid-client.js +155 -0
- package/dist/repertoire/unraid-restart.js +212 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +628 -0
- package/dist/rsvp/aisleplanner-client.js +354 -0
- package/dist/rsvp/cli.js +926 -0
- package/dist/rsvp/config.js +327 -0
- package/dist/rsvp/cutover.js +433 -0
- package/dist/rsvp/diagnostics.js +232 -0
- package/dist/rsvp/diff-renderer.js +176 -0
- package/dist/rsvp/habit-policy.js +110 -0
- package/dist/rsvp/habit-stage.js +123 -0
- package/dist/rsvp/incident-bundle.js +97 -0
- package/dist/rsvp/migration.js +204 -0
- package/dist/rsvp/native-habit-runner.js +630 -0
- package/dist/rsvp/outbound-state.js +628 -0
- package/dist/rsvp/query.js +118 -0
- package/dist/rsvp/replay.js +233 -0
- package/dist/rsvp/snapshot.js +232 -0
- package/dist/rsvp/spend-ledger.js +175 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/a2a-entry.js +115 -0
- package/dist/senses/acp-server.js +386 -0
- package/dist/senses/attention-queue.js +186 -0
- package/dist/senses/await-turn-message.js +58 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
- package/dist/senses/bluebubbles/context-packet.js +207 -0
- package/dist/senses/bluebubbles/context-smoke.js +144 -0
- package/dist/senses/bluebubbles/entry.js +90 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
- package/dist/senses/bluebubbles/index.js +3839 -0
- package/dist/senses/bluebubbles/latest-turn.js +311 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
- package/dist/senses/bluebubbles/outbound-state.js +308 -0
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/reaction-policy.js +47 -0
- package/dist/senses/bluebubbles/replay.js +284 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/bluebubbles/webhook-registration.js +228 -0
- package/dist/senses/bluebubbles-meta-guard.js +39 -0
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +241 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli.js +600 -317
- package/dist/senses/commands.js +66 -3
- package/dist/senses/context-packet-ledger.js +371 -0
- package/dist/senses/context-packets.js +154 -0
- package/dist/senses/habit-lifecycle-guard.js +24 -0
- package/dist/senses/habit-turn-message.js +160 -0
- package/dist/senses/ingress-evidence.js +2 -0
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +524 -0
- package/dist/senses/pipeline.js +1115 -204
- package/dist/senses/private-runtime-worker.js +859 -0
- package/dist/senses/private-runtime.js +1496 -0
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
- package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
- package/dist/senses/sanctuary-grounding.js +118 -0
- package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
- package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
- package/dist/senses/sanctuary-health-runner.js +101 -0
- package/dist/senses/sanctuary-health.js +408 -0
- package/dist/senses/sanctuary-install-state-contract.js +126 -0
- package/dist/senses/sanctuary-interactive-control.js +306 -0
- package/dist/senses/sanctuary-media-catalog-contract.js +235 -0
- package/dist/senses/sanctuary-media-optimization.js +514 -0
- package/dist/senses/sanctuary-runtime.js +338 -0
- package/dist/senses/sanctuary-sab.js +85 -0
- package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
- package/dist/senses/shared-turn.js +756 -0
- package/dist/senses/surface-tool.js +109 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +515 -217
- package/dist/senses/telegram-admission.js +711 -0
- package/dist/senses/telegram-approval-runtime.js +566 -0
- package/dist/senses/telegram-attachments.js +182 -0
- package/dist/senses/telegram-audit-ledger.js +220 -0
- package/dist/senses/telegram-client.js +1677 -0
- package/dist/senses/telegram-effect-adapter.js +859 -0
- package/dist/senses/telegram-entry.js +83 -0
- package/dist/senses/telegram.js +2045 -0
- package/dist/senses/trust-gate.js +104 -9
- package/dist/senses/voice/audio-playback.js +237 -0
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +202 -0
- package/dist/senses/voice/floor-control.js +431 -0
- package/dist/senses/voice/floor-controller.js +115 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +29 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/outbound.js +190 -0
- package/dist/senses/voice/phone.js +33 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/realtime-eval.js +496 -0
- package/dist/senses/voice/realtime-trace.js +531 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +191 -0
- package/dist/senses/voice/twilio-phone-runtime.js +807 -0
- package/dist/senses/voice/twilio-phone.js +5081 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +81 -0
- package/dist/senses/voice-realtime-eval-command.js +99 -0
- package/dist/senses/voice-realtime-eval-entry.js +21 -0
- package/dist/senses/voice-twilio-entry.js +87 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +265 -0
- package/dist/util/frontmatter.js +69 -0
- package/npm-shrinkwrap.json +8138 -0
- package/package.json +72 -13
- package/skills/agent-commerce.md +113 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +99 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/auth-flow.js +0 -430
- package/dist/heart/daemon/ouro-path-installer.js +0 -260
- package/dist/heart/daemon/ouro-version-manager.js +0 -164
- package/dist/heart/daemon/update-hooks.js +0 -138
- package/dist/heart/obligations.js +0 -141
- package/dist/heart/safe-workspace.js +0 -228
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/friends/channel.js +0 -84
- package/dist/mind/friends/group-context.js +0 -144
- package/dist/mind/friends/resolver.js +0 -84
- package/dist/mind/friends/store-file.js +0 -190
- package/dist/mind/friends/store.js +0 -4
- package/dist/mind/friends/tokens.js +0 -26
- package/dist/mind/friends/trust-explanation.js +0 -74
- package/dist/mind/friends/types.js +0 -29
- package/dist/repertoire/tasks/board.js +0 -134
- package/dist/repertoire/tasks/index.js +0 -224
- package/dist/repertoire/tasks/lifecycle.js +0 -80
- package/dist/repertoire/tasks/middleware.js +0 -65
- package/dist/repertoire/tasks/parser.js +0 -173
- package/dist/repertoire/tasks/scanner.js +0 -132
- package/dist/repertoire/tasks/transitions.js +0 -144
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1181
- package/dist/senses/debug-activity.js +0 -154
- package/dist/senses/inner-dialog-worker.js +0 -90
- package/dist/senses/inner-dialog.js +0 -525
- package/subagents/README.md +0 -7
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.McpClient = void 0;
|
|
4
|
+
exports.isMcpTransportError = isMcpTransportError;
|
|
4
5
|
const child_process_1 = require("child_process");
|
|
5
6
|
const readline_1 = require("readline");
|
|
6
7
|
const runtime_1 = require("../nerves/runtime");
|
|
8
|
+
const runtime_cwd_1 = require("../heart/runtime-cwd");
|
|
7
9
|
const MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
10
|
+
const DEFAULT_REQUEST_TIMEOUT = 10_000;
|
|
8
11
|
const DEFAULT_TOOL_CALL_TIMEOUT = 30_000;
|
|
12
|
+
function isMcpTransportError(error) {
|
|
13
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14
|
+
const normalized = message.toLowerCase();
|
|
15
|
+
return normalized.includes("disconnected")
|
|
16
|
+
|| normalized.includes("transport")
|
|
17
|
+
|| normalized.includes("closed")
|
|
18
|
+
|| normalized.includes("econnreset")
|
|
19
|
+
|| normalized.includes("econnrefused")
|
|
20
|
+
|| normalized.includes("enoent")
|
|
21
|
+
|| normalized.includes("epipe")
|
|
22
|
+
|| normalized.includes("broken pipe")
|
|
23
|
+
|| normalized.includes("not writable");
|
|
24
|
+
}
|
|
9
25
|
class McpClient {
|
|
10
26
|
config;
|
|
11
27
|
process = null;
|
|
@@ -18,6 +34,9 @@ class McpClient {
|
|
|
18
34
|
this.config = config;
|
|
19
35
|
}
|
|
20
36
|
async connect() {
|
|
37
|
+
if (this.connected)
|
|
38
|
+
return;
|
|
39
|
+
this.shutdownProcessOnly();
|
|
21
40
|
(0, runtime_1.emitNervesEvent)({
|
|
22
41
|
event: "mcp.connect_start",
|
|
23
42
|
component: "repertoire",
|
|
@@ -25,9 +44,11 @@ class McpClient {
|
|
|
25
44
|
meta: { command: this.config.command },
|
|
26
45
|
});
|
|
27
46
|
const env = { ...process.env, ...this.config.env };
|
|
47
|
+
const spawnCwd = this.config.cwd ?? (0, runtime_cwd_1.recoverRuntimeCwd)();
|
|
28
48
|
this.process = (0, child_process_1.spawn)(this.config.command, this.config.args ?? [], {
|
|
29
49
|
env,
|
|
30
50
|
stdio: ["pipe", "pipe", "pipe"],
|
|
51
|
+
cwd: spawnCwd,
|
|
31
52
|
});
|
|
32
53
|
this.setupLineReader();
|
|
33
54
|
this.setupProcessHandlers();
|
|
@@ -43,6 +64,7 @@ class McpClient {
|
|
|
43
64
|
}
|
|
44
65
|
catch (error) {
|
|
45
66
|
this.connected = false;
|
|
67
|
+
this.shutdownProcessOnly();
|
|
46
68
|
(0, runtime_1.emitNervesEvent)({
|
|
47
69
|
level: "error",
|
|
48
70
|
event: "mcp.connect_error",
|
|
@@ -75,6 +97,10 @@ class McpClient {
|
|
|
75
97
|
this.cachedTools = allTools;
|
|
76
98
|
return allTools;
|
|
77
99
|
}
|
|
100
|
+
async refreshTools() {
|
|
101
|
+
this.cachedTools = null;
|
|
102
|
+
return this.listTools();
|
|
103
|
+
}
|
|
78
104
|
async callTool(name, args, timeout = DEFAULT_TOOL_CALL_TIMEOUT) {
|
|
79
105
|
(0, runtime_1.emitNervesEvent)({
|
|
80
106
|
event: "mcp.tool_call_start",
|
|
@@ -138,7 +164,7 @@ class McpClient {
|
|
|
138
164
|
});
|
|
139
165
|
return result;
|
|
140
166
|
}
|
|
141
|
-
sendRequest(method, params, timeout) {
|
|
167
|
+
sendRequest(method, params, timeout = DEFAULT_REQUEST_TIMEOUT) {
|
|
142
168
|
return new Promise((resolve, reject) => {
|
|
143
169
|
if (!this.process || !this.connected && method !== "initialize") {
|
|
144
170
|
reject(new Error("MCP client is disconnected"));
|
|
@@ -159,14 +185,21 @@ class McpClient {
|
|
|
159
185
|
method,
|
|
160
186
|
params,
|
|
161
187
|
};
|
|
162
|
-
this.writeMessage(request)
|
|
188
|
+
if (!this.writeMessage(request)) {
|
|
189
|
+
this.pending.delete(id);
|
|
190
|
+
if (pending.timer) {
|
|
191
|
+
clearTimeout(pending.timer);
|
|
192
|
+
}
|
|
193
|
+
reject(new Error(`MCP transport is not writable for request: ${method}`));
|
|
194
|
+
}
|
|
163
195
|
});
|
|
164
196
|
}
|
|
165
197
|
writeMessage(message) {
|
|
166
|
-
/* v8 ignore next -- defensive: stdin always writable during active connection @preserve */
|
|
167
198
|
if (this.process?.stdin?.writable) {
|
|
168
199
|
this.process.stdin.write(JSON.stringify(message) + "\n");
|
|
200
|
+
return true;
|
|
169
201
|
}
|
|
202
|
+
return false;
|
|
170
203
|
}
|
|
171
204
|
setupLineReader() {
|
|
172
205
|
/* v8 ignore next -- defensive: stdout always exists after spawn @preserve */
|
|
@@ -250,5 +283,13 @@ class McpClient {
|
|
|
250
283
|
this.pending.delete(id);
|
|
251
284
|
}
|
|
252
285
|
}
|
|
286
|
+
shutdownProcessOnly() {
|
|
287
|
+
this.rejectAllPending(new Error("MCP transport closed during reconnect"));
|
|
288
|
+
/* v8 ignore next -- defensive: process may already be absent @preserve */
|
|
289
|
+
if (this.process && !this.process.killed) {
|
|
290
|
+
this.process.kill();
|
|
291
|
+
}
|
|
292
|
+
this.process = null;
|
|
293
|
+
}
|
|
253
294
|
}
|
|
254
295
|
exports.McpClient = McpClient;
|
|
@@ -2,49 +2,232 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.McpManager = void 0;
|
|
4
4
|
exports.getSharedMcpManager = getSharedMcpManager;
|
|
5
|
+
exports.releaseRuntimeMcpServers = releaseRuntimeMcpServers;
|
|
5
6
|
exports.shutdownSharedMcpManager = shutdownSharedMcpManager;
|
|
6
7
|
exports.resetSharedMcpManager = resetSharedMcpManager;
|
|
7
8
|
const mcp_client_1 = require("./mcp-client");
|
|
8
9
|
const identity_1 = require("../heart/identity");
|
|
9
10
|
const runtime_1 = require("../nerves/runtime");
|
|
11
|
+
const credential_access_1 = require("./credential-access");
|
|
12
|
+
const plugin_mcp_1 = require("./plugin-mcp");
|
|
10
13
|
const MAX_RESTART_RETRIES = 5;
|
|
11
14
|
const RESTART_DELAY_MS = 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Merge builtin (agent.json mcpServers) + plugin-declared (.mcp.json) servers.
|
|
17
|
+
*
|
|
18
|
+
* Builtin wins on name collision. Returns the merged config map plus a
|
|
19
|
+
* `pluginOrigins` map (server-name → plugin-id) for tools-surfacing namespace.
|
|
20
|
+
*
|
|
21
|
+
* Shared by `getSharedMcpManager()` (initial start) and `McpManager.reconcile()`
|
|
22
|
+
* (re-read on each turn). Both code paths MUST use the same merge logic — if
|
|
23
|
+
* reconcile reads only builtin, plugin servers get classified as "removed"
|
|
24
|
+
* on the second turn and torn down. See alpha.635 fix.
|
|
25
|
+
*
|
|
26
|
+
* `runtimeServers` are per-turn, per-agent overrides (e.g. Workbench's
|
|
27
|
+
* `ouro_workbench`) supplied as PARAMETER data for the current turn — never read
|
|
28
|
+
* from module state. They merge with the HIGHEST precedence (after builtin), so
|
|
29
|
+
* a stale `agent.json` entry loses to the live runtime path. Because they are a
|
|
30
|
+
* parameter, a turn that omits them produces a merged set WITHOUT them, and
|
|
31
|
+
* `reconcile()` then tears the runtime server down — this is the no-leak
|
|
32
|
+
* invariant that keeps the runtime MCP from bleeding into a different agent's
|
|
33
|
+
* concurrent turn on the shared daemon.
|
|
34
|
+
*/
|
|
35
|
+
function buildMergedServerConfig(runtimeServers) {
|
|
36
|
+
const config = (0, identity_1.loadAgentConfig)();
|
|
37
|
+
const builtinServers = config.mcpServers ?? {};
|
|
38
|
+
const pluginServers = (0, plugin_mcp_1.listPluginMcpServers)();
|
|
39
|
+
const mergedServers = {};
|
|
40
|
+
const pluginOrigins = {};
|
|
41
|
+
for (const p of pluginServers) {
|
|
42
|
+
if (builtinServers[p.serverName] !== undefined)
|
|
43
|
+
continue;
|
|
44
|
+
mergedServers[p.serverName] = (0, plugin_mcp_1.pluginMcpServerToConfig)(p);
|
|
45
|
+
pluginOrigins[p.serverName] = p.pluginId;
|
|
46
|
+
}
|
|
47
|
+
for (const [name, cfg] of Object.entries(builtinServers)) {
|
|
48
|
+
mergedServers[name] = cfg;
|
|
49
|
+
}
|
|
50
|
+
// Runtime overrides win over both plugin and builtin (highest precedence).
|
|
51
|
+
// They are NOT recorded in pluginOrigins, so they surface as builtin-style
|
|
52
|
+
// (un-namespaced) tools — matching how an agent.json mcpServers entry would.
|
|
53
|
+
if (runtimeServers) {
|
|
54
|
+
for (const [name, cfg] of Object.entries(runtimeServers)) {
|
|
55
|
+
mergedServers[name] = cfg;
|
|
56
|
+
delete pluginOrigins[name];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { mergedServers, pluginOrigins };
|
|
60
|
+
}
|
|
61
|
+
function sameMcpServerConfig(left, right) {
|
|
62
|
+
const leftEnv = Object.entries(left.env ?? {}).sort();
|
|
63
|
+
const rightEnv = Object.entries(right.env ?? {}).sort();
|
|
64
|
+
return left.command === right.command
|
|
65
|
+
&& JSON.stringify(left.args ?? []) === JSON.stringify(right.args ?? [])
|
|
66
|
+
&& JSON.stringify(leftEnv) === JSON.stringify(rightEnv)
|
|
67
|
+
&& (left.cwd ?? "") === (right.cwd ?? "");
|
|
68
|
+
}
|
|
12
69
|
class McpManager {
|
|
13
70
|
servers = new Map();
|
|
71
|
+
desiredGenerations = new Map();
|
|
72
|
+
nextGeneration = 0;
|
|
14
73
|
shuttingDown = false;
|
|
15
|
-
async start(servers) {
|
|
74
|
+
async start(servers, pluginOrigins = {}, ownerAgent) {
|
|
16
75
|
(0, runtime_1.emitNervesEvent)({
|
|
17
76
|
event: "mcp.manager_start",
|
|
18
77
|
component: "repertoire",
|
|
19
78
|
message: "starting MCP manager",
|
|
20
|
-
meta: {
|
|
79
|
+
meta: {
|
|
80
|
+
serverCount: Object.keys(servers).length,
|
|
81
|
+
pluginServerCount: Object.keys(pluginOrigins).length,
|
|
82
|
+
},
|
|
21
83
|
});
|
|
22
84
|
const entries = Object.entries(servers);
|
|
23
85
|
for (const [name, config] of entries) {
|
|
24
|
-
await this.connectServer(name, config);
|
|
86
|
+
await this.connectServer(name, config, pluginOrigins[name], ownerAgent);
|
|
25
87
|
}
|
|
26
88
|
}
|
|
27
89
|
listAllTools() {
|
|
28
90
|
const result = [];
|
|
29
91
|
for (const [name, entry] of this.servers) {
|
|
30
|
-
result.push({ server: name, tools: entry.cachedTools });
|
|
92
|
+
result.push({ server: name, tools: entry.cachedTools, pluginId: entry.pluginId });
|
|
31
93
|
}
|
|
32
94
|
return result;
|
|
33
95
|
}
|
|
34
96
|
async callTool(server, tool, args) {
|
|
35
|
-
|
|
97
|
+
let entry = this.servers.get(server);
|
|
36
98
|
if (!entry) {
|
|
37
99
|
throw new Error(`Unknown server: ${server}`);
|
|
38
100
|
}
|
|
39
101
|
if (!entry.client.isConnected()) {
|
|
40
|
-
|
|
102
|
+
await this.recoverStaleTransport(server, "pre-call disconnected");
|
|
103
|
+
entry = this.servers.get(server);
|
|
104
|
+
if (!entry?.client.isConnected()) {
|
|
105
|
+
throw new Error(`Server "${server}" is disconnected`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
return await entry.client.callTool(tool, args);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (!(0, mcp_client_1.isMcpTransportError)(error)) {
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
116
|
+
await this.recoverStaleTransport(server, reason);
|
|
117
|
+
const recovered = this.servers.get(server);
|
|
118
|
+
if (!recovered?.client.isConnected()) {
|
|
119
|
+
throw new Error(`Server "${server}" is disconnected after recovery: ${reason}`);
|
|
120
|
+
}
|
|
121
|
+
return recovered.client.callTool(tool, args);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async runCanaries() {
|
|
125
|
+
const results = [];
|
|
126
|
+
for (const [server, entry] of [...this.servers]) {
|
|
127
|
+
try {
|
|
128
|
+
if (!entry.client.isConnected()) {
|
|
129
|
+
await this.recoverStaleTransport(server, "canary disconnected");
|
|
130
|
+
}
|
|
131
|
+
const current = this.servers.get(server);
|
|
132
|
+
if (!current?.client.isConnected()) {
|
|
133
|
+
results.push({ server, ok: false, detail: "disconnected after recovery attempt" });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const tools = await current.client.refreshTools();
|
|
137
|
+
current.cachedTools = tools;
|
|
138
|
+
current.consecutiveFailures = 0;
|
|
139
|
+
results.push({ server, ok: true, detail: `${tools.length} tools listed` });
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
143
|
+
if ((0, mcp_client_1.isMcpTransportError)(error)) {
|
|
144
|
+
await this.recoverStaleTransport(server, reason);
|
|
145
|
+
}
|
|
146
|
+
results.push({ server, ok: false, detail: reason });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return results;
|
|
150
|
+
}
|
|
151
|
+
/** Re-read agent config AND enabled-plugin .mcp.json files, then connect new
|
|
152
|
+
* servers / disconnect removed ones. Must include plugin-declared servers
|
|
153
|
+
* in the desired set — otherwise plugin servers (e.g. mcp__desk__*) are
|
|
154
|
+
* treated as "removed" on every call and get torn down between turns.
|
|
155
|
+
*
|
|
156
|
+
* `runtimeServers` are the current turn's per-agent overrides. They MUST be
|
|
157
|
+
* passed on every reconcile for the agent that owns them, otherwise the
|
|
158
|
+
* runtime server (e.g. ouro_workbench) is classified as "removed" and torn
|
|
159
|
+
* down — which is exactly the desired no-leak behavior for a turn that omits
|
|
160
|
+
* them. */
|
|
161
|
+
async reconcile(runtimeServers) {
|
|
162
|
+
try {
|
|
163
|
+
const { mergedServers, pluginOrigins } = buildMergedServerConfig(runtimeServers);
|
|
164
|
+
const ownerAgent = (0, identity_1.getAgentName)();
|
|
165
|
+
const currentNames = new Set(this.servers.keys());
|
|
166
|
+
const desiredNames = new Set(Object.keys(mergedServers));
|
|
167
|
+
// Connect new servers
|
|
168
|
+
for (const [name, cfg] of Object.entries(mergedServers)) {
|
|
169
|
+
const current = this.servers.get(name);
|
|
170
|
+
const pluginId = pluginOrigins[name];
|
|
171
|
+
if (!current) {
|
|
172
|
+
(0, runtime_1.emitNervesEvent)({
|
|
173
|
+
event: "mcp.server_added",
|
|
174
|
+
component: "repertoire",
|
|
175
|
+
message: `connecting new MCP server: ${name}`,
|
|
176
|
+
meta: { server: name, command: cfg.command },
|
|
177
|
+
});
|
|
178
|
+
await this.connectServer(name, cfg, pluginId, ownerAgent);
|
|
179
|
+
}
|
|
180
|
+
else if (!sameMcpServerConfig(current.config, cfg)
|
|
181
|
+
|| current.pluginId !== pluginId
|
|
182
|
+
|| current.ownerAgent !== ownerAgent) {
|
|
183
|
+
(0, runtime_1.emitNervesEvent)({
|
|
184
|
+
event: "mcp.server_changed",
|
|
185
|
+
component: "repertoire",
|
|
186
|
+
message: `reconnecting changed MCP server: ${name}`,
|
|
187
|
+
meta: { server: name, command: cfg.command },
|
|
188
|
+
});
|
|
189
|
+
current.client.shutdown();
|
|
190
|
+
this.servers.delete(name);
|
|
191
|
+
await this.connectServer(name, cfg, pluginId, ownerAgent);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Disconnect removed servers
|
|
195
|
+
for (const name of currentNames) {
|
|
196
|
+
if (!desiredNames.has(name)) {
|
|
197
|
+
(0, runtime_1.emitNervesEvent)({
|
|
198
|
+
event: "mcp.server_removed",
|
|
199
|
+
component: "repertoire",
|
|
200
|
+
message: `disconnecting removed MCP server: ${name}`,
|
|
201
|
+
meta: { server: name },
|
|
202
|
+
});
|
|
203
|
+
const entry = this.servers.get(name);
|
|
204
|
+
/* v8 ignore next -- defensive: name comes from this.servers.keys() this same tick, so entry is always present; the guard only protects against an awaited connectServer crash-handler racing a delete @preserve */
|
|
205
|
+
if (entry)
|
|
206
|
+
entry.client.shutdown();
|
|
207
|
+
this.servers.delete(name);
|
|
208
|
+
this.desiredGenerations.delete(name);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
(0, runtime_1.emitNervesEvent)({
|
|
215
|
+
level: "warn",
|
|
216
|
+
event: "mcp.reconcile_error",
|
|
217
|
+
component: "repertoire",
|
|
218
|
+
message: "failed to reconcile MCP servers",
|
|
219
|
+
meta: { reason: error instanceof Error ? error.message : String(error) },
|
|
220
|
+
});
|
|
221
|
+
this.shutdown();
|
|
222
|
+
return false;
|
|
41
223
|
}
|
|
42
|
-
return entry.client.callTool(tool, args);
|
|
43
224
|
}
|
|
44
225
|
shutdown() {
|
|
45
226
|
this.shuttingDown = true;
|
|
227
|
+
// `_end` (not `_stop`) to pair with `mcp.manager_start` under the
|
|
228
|
+
// nerves audit start/end pairing rule.
|
|
46
229
|
(0, runtime_1.emitNervesEvent)({
|
|
47
|
-
event: "mcp.
|
|
230
|
+
event: "mcp.manager_end",
|
|
48
231
|
component: "repertoire",
|
|
49
232
|
message: "shutting down MCP manager",
|
|
50
233
|
meta: { serverCount: this.servers.size },
|
|
@@ -53,45 +236,125 @@ class McpManager {
|
|
|
53
236
|
entry.client.shutdown();
|
|
54
237
|
}
|
|
55
238
|
this.servers.clear();
|
|
239
|
+
this.desiredGenerations.clear();
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Resolve `vault:DOMAIN/FIELD` references in server env config.
|
|
243
|
+
* Returns resolved env or throws with a descriptive error.
|
|
244
|
+
*/
|
|
245
|
+
async resolveVaultEnv(_serverName, env, ownerAgent) {
|
|
246
|
+
const resolved = { ...env };
|
|
247
|
+
// Short-circuit: only spin up a credential store if at least one env value
|
|
248
|
+
// actually requests vault resolution. Plugin MCP servers commonly ship with
|
|
249
|
+
// `env: {}` or pure-string envs, and we shouldn't pay the credential-store
|
|
250
|
+
// boot cost (or fail in test envs that have no vault) for those cases.
|
|
251
|
+
const hasVaultRef = Object.values(resolved).some((v) => /^vault:/.test(v));
|
|
252
|
+
if (!hasVaultRef)
|
|
253
|
+
return resolved;
|
|
254
|
+
const store = (0, credential_access_1.getCredentialStore)(ownerAgent);
|
|
255
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
256
|
+
const match = value.match(/^vault:([^/]+)\/(.+)$/);
|
|
257
|
+
if (!match)
|
|
258
|
+
continue;
|
|
259
|
+
const [, domain, field] = match;
|
|
260
|
+
try {
|
|
261
|
+
resolved[key] = await store.getRawSecret(domain, field);
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
/* v8 ignore next -- reason @preserve */
|
|
265
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
266
|
+
// Classify the error for actionable messaging
|
|
267
|
+
let classification = "vault unreachable";
|
|
268
|
+
if (reason.includes("no credential found")) {
|
|
269
|
+
classification = "item not found";
|
|
270
|
+
}
|
|
271
|
+
else if (reason.includes("field") && reason.includes("not found")) {
|
|
272
|
+
classification = "field empty";
|
|
273
|
+
}
|
|
274
|
+
throw new Error(`vault:${domain}/${field} could not be resolved: ${classification}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return resolved;
|
|
56
278
|
}
|
|
57
|
-
async connectServer(name, config) {
|
|
58
|
-
const
|
|
279
|
+
async connectServer(name, config, pluginId, ownerAgent) {
|
|
280
|
+
const generation = ++this.nextGeneration;
|
|
281
|
+
this.desiredGenerations.set(name, generation);
|
|
282
|
+
// Resolve vault: references in env before spawning
|
|
283
|
+
let resolvedConfig = config;
|
|
284
|
+
if (config.env) {
|
|
285
|
+
try {
|
|
286
|
+
const resolvedEnv = await this.resolveVaultEnv(name, config.env, ownerAgent);
|
|
287
|
+
resolvedConfig = { ...config, env: resolvedEnv };
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
/* v8 ignore next -- reason @preserve */
|
|
291
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
292
|
+
(0, runtime_1.emitNervesEvent)({
|
|
293
|
+
level: "error",
|
|
294
|
+
event: "mcp.vault_resolve_error",
|
|
295
|
+
component: "repertoire",
|
|
296
|
+
message: `skipping MCP server "${name}": ${reason}`,
|
|
297
|
+
meta: { server: name, reason },
|
|
298
|
+
});
|
|
299
|
+
if (this.desiredGenerations.get(name) === generation) {
|
|
300
|
+
this.desiredGenerations.delete(name);
|
|
301
|
+
}
|
|
302
|
+
return; // Skip this server, continue to next
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (this.shuttingDown || this.desiredGenerations.get(name) !== generation)
|
|
306
|
+
return;
|
|
307
|
+
const client = new mcp_client_1.McpClient(resolvedConfig);
|
|
59
308
|
const entry = {
|
|
60
309
|
name,
|
|
61
310
|
config,
|
|
62
311
|
client,
|
|
63
312
|
cachedTools: [],
|
|
64
313
|
consecutiveFailures: 0,
|
|
314
|
+
pluginId,
|
|
315
|
+
ownerAgent,
|
|
316
|
+
generation,
|
|
65
317
|
};
|
|
66
318
|
this.servers.set(name, entry);
|
|
67
319
|
client.onClose(() => {
|
|
68
320
|
if (this.shuttingDown)
|
|
69
321
|
return;
|
|
70
|
-
this.
|
|
322
|
+
if (this.servers.get(name)?.client !== client)
|
|
323
|
+
return;
|
|
324
|
+
this.handleServerCrash(name, client);
|
|
71
325
|
});
|
|
72
326
|
try {
|
|
73
327
|
await client.connect();
|
|
74
328
|
const tools = await client.listTools();
|
|
329
|
+
if (this.shuttingDown
|
|
330
|
+
|| this.desiredGenerations.get(name) !== generation
|
|
331
|
+
|| this.servers.get(name)?.client !== client) {
|
|
332
|
+
client.shutdown();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
75
335
|
entry.cachedTools = tools;
|
|
76
336
|
entry.consecutiveFailures = 0;
|
|
77
337
|
}
|
|
78
338
|
catch (error) {
|
|
339
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
79
340
|
(0, runtime_1.emitNervesEvent)({
|
|
80
341
|
level: "error",
|
|
81
342
|
event: "mcp.connect_error",
|
|
82
343
|
component: "repertoire",
|
|
83
|
-
message: `failed to connect MCP server
|
|
344
|
+
message: `failed to connect MCP server "${name}" (command: ${config.command}). Check that the command exists and is properly configured. Reason: ${reason}`,
|
|
84
345
|
meta: {
|
|
85
346
|
server: name,
|
|
86
|
-
|
|
347
|
+
command: config.command,
|
|
348
|
+
args: config.args,
|
|
349
|
+
reason,
|
|
87
350
|
},
|
|
88
351
|
});
|
|
89
352
|
}
|
|
90
353
|
}
|
|
91
|
-
handleServerCrash(name) {
|
|
354
|
+
handleServerCrash(name, crashedClient) {
|
|
92
355
|
const entry = this.servers.get(name);
|
|
93
|
-
/* v8 ignore next -- defensive: entry removed between close event and handler @preserve */
|
|
94
|
-
if (!entry)
|
|
356
|
+
/* v8 ignore next -- defensive: entry removed or replaced between close event and handler @preserve */
|
|
357
|
+
if (!entry || entry.client !== crashedClient)
|
|
95
358
|
return;
|
|
96
359
|
entry.consecutiveFailures++;
|
|
97
360
|
if (entry.consecutiveFailures > MAX_RESTART_RETRIES) {
|
|
@@ -99,8 +362,8 @@ class McpManager {
|
|
|
99
362
|
level: "error",
|
|
100
363
|
event: "mcp.connect_error",
|
|
101
364
|
component: "repertoire",
|
|
102
|
-
message: `MCP server "${name}" exceeded max restart retries (${MAX_RESTART_RETRIES})
|
|
103
|
-
meta: { server: name, failures: entry.consecutiveFailures },
|
|
365
|
+
message: `MCP server "${name}" exceeded max restart retries (${MAX_RESTART_RETRIES}). Giving up — check that "${entry.config.command}" exists and is properly configured in agent.json mcpServers.`,
|
|
366
|
+
meta: { server: name, command: entry.config.command, failures: entry.consecutiveFailures },
|
|
104
367
|
});
|
|
105
368
|
return;
|
|
106
369
|
}
|
|
@@ -115,26 +378,43 @@ class McpManager {
|
|
|
115
378
|
setTimeout(() => {
|
|
116
379
|
if (this.shuttingDown)
|
|
117
380
|
return;
|
|
118
|
-
this.
|
|
381
|
+
if (this.servers.get(name)?.client !== crashedClient)
|
|
382
|
+
return;
|
|
383
|
+
this.restartServer(name, crashedClient).catch(() => {
|
|
119
384
|
// Error handling is inside restartServer
|
|
120
385
|
});
|
|
121
386
|
}, RESTART_DELAY_MS);
|
|
122
387
|
/* v8 ignore stop */
|
|
123
388
|
}
|
|
124
389
|
/* v8 ignore start -- called from timer callback: covered by mcp-manager.test.ts via fake timers but v8 can't trace @preserve */
|
|
125
|
-
async restartServer(name) {
|
|
390
|
+
async restartServer(name, expectedClient) {
|
|
126
391
|
const entry = this.servers.get(name);
|
|
127
392
|
if (!entry)
|
|
128
393
|
return;
|
|
394
|
+
if (expectedClient && entry.client !== expectedClient)
|
|
395
|
+
return;
|
|
129
396
|
// Remove old entry and reconnect
|
|
130
397
|
this.servers.delete(name);
|
|
131
|
-
|
|
398
|
+
this.desiredGenerations.delete(name);
|
|
399
|
+
entry.client.shutdown();
|
|
400
|
+
await this.connectServer(name, entry.config, entry.pluginId, entry.ownerAgent);
|
|
132
401
|
// Preserve failure count
|
|
133
402
|
const newEntry = this.servers.get(name);
|
|
134
403
|
if (newEntry) {
|
|
135
404
|
newEntry.consecutiveFailures = entry.consecutiveFailures;
|
|
136
405
|
}
|
|
137
406
|
}
|
|
407
|
+
/* v8 ignore stop */
|
|
408
|
+
async recoverStaleTransport(name, reason) {
|
|
409
|
+
(0, runtime_1.emitNervesEvent)({
|
|
410
|
+
level: "warn",
|
|
411
|
+
event: "mcp.transport_recovery",
|
|
412
|
+
component: "repertoire",
|
|
413
|
+
message: `recovering stale MCP transport: ${name}`,
|
|
414
|
+
meta: { server: name, reason },
|
|
415
|
+
});
|
|
416
|
+
await this.restartServer(name);
|
|
417
|
+
}
|
|
138
418
|
}
|
|
139
419
|
exports.McpManager = McpManager;
|
|
140
420
|
let _sharedManager = null;
|
|
@@ -143,21 +423,38 @@ let _sharedManagerPromise = null;
|
|
|
143
423
|
* Get or create a shared McpManager instance from the agent's config.
|
|
144
424
|
* Returns null if no mcpServers are configured.
|
|
145
425
|
* Safe to call from multiple senses — will only create one instance.
|
|
426
|
+
*
|
|
427
|
+
* `options.runtimeServers` are the current turn's per-agent MCP overrides (e.g.
|
|
428
|
+
* Workbench's `ouro_workbench`). They are PARAMETER data for this call only —
|
|
429
|
+
* passed into the merge for both the initial `start()` and every subsequent
|
|
430
|
+
* `reconcile()`, and never persisted as module state. A call that omits them
|
|
431
|
+
* reconciles to a set WITHOUT them, tearing any prior runtime server down — the
|
|
432
|
+
* no-leak invariant for the shared multi-agent daemon.
|
|
146
433
|
*/
|
|
147
|
-
async function getSharedMcpManager() {
|
|
148
|
-
|
|
434
|
+
async function getSharedMcpManager(options) {
|
|
435
|
+
const runtimeServers = options?.runtimeServers;
|
|
436
|
+
// If manager exists, reconcile to pick up config changes (new/removed servers)
|
|
437
|
+
// AND this turn's runtime overrides. Passing runtimeServers per-call is what
|
|
438
|
+
// scopes the runtime MCP to the active agent's turn.
|
|
439
|
+
if (_sharedManager) {
|
|
440
|
+
const reconciled = await _sharedManager.reconcile(runtimeServers);
|
|
441
|
+
if (!reconciled) {
|
|
442
|
+
_sharedManager = null;
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
149
445
|
return _sharedManager;
|
|
446
|
+
}
|
|
150
447
|
/* v8 ignore next -- race guard: deduplicates concurrent initialization calls @preserve */
|
|
151
448
|
if (_sharedManagerPromise)
|
|
152
449
|
return _sharedManagerPromise;
|
|
450
|
+
// Always re-check config — agent may have added servers since last call
|
|
153
451
|
_sharedManagerPromise = (async () => {
|
|
154
452
|
try {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
if (!servers || Object.keys(servers).length === 0)
|
|
453
|
+
const { mergedServers, pluginOrigins } = buildMergedServerConfig(runtimeServers);
|
|
454
|
+
if (Object.keys(mergedServers).length === 0)
|
|
158
455
|
return null;
|
|
159
456
|
const manager = new McpManager();
|
|
160
|
-
await manager.start(
|
|
457
|
+
await manager.start(mergedServers, pluginOrigins, (0, identity_1.getAgentName)());
|
|
161
458
|
_sharedManager = manager;
|
|
162
459
|
return manager;
|
|
163
460
|
}
|
|
@@ -178,6 +475,13 @@ async function getSharedMcpManager() {
|
|
|
178
475
|
})();
|
|
179
476
|
return _sharedManagerPromise;
|
|
180
477
|
}
|
|
478
|
+
async function releaseRuntimeMcpServers() {
|
|
479
|
+
if (!_sharedManager)
|
|
480
|
+
return;
|
|
481
|
+
if (!await _sharedManager.reconcile()) {
|
|
482
|
+
_sharedManager = null;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
181
485
|
/**
|
|
182
486
|
* Shut down the shared MCP manager and clear the singleton.
|
|
183
487
|
* Called during daemon/agent shutdown.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* First-class MCP tool integration — converts MCP server tools into ToolDefinitions
|
|
4
|
+
* so the model can call them directly without shell indirection.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.mcpToolsAsDefinitions = mcpToolsAsDefinitions;
|
|
8
|
+
const runtime_1 = require("../nerves/runtime");
|
|
9
|
+
/**
|
|
10
|
+
* Convert all tools from an McpManager into ToolDefinition objects.
|
|
11
|
+
*
|
|
12
|
+
* Naming rules:
|
|
13
|
+
* - Builtin servers (agent.json `mcpServers`) — legacy `{server}_{tool}`
|
|
14
|
+
* shape (e.g., `browser_navigate`), with double-prefix avoidance when
|
|
15
|
+
* the tool already starts with the server name.
|
|
16
|
+
* - Plugin servers (from `<plugin>/.mcp.json`, W6 Unit 9) — Anthropic public
|
|
17
|
+
* convention `mcp__{server}__{tool}` (e.g., `mcp__desk__task_create`).
|
|
18
|
+
* This matches Claude Code's external naming and the on-prompt promise
|
|
19
|
+
* in `desk-section.ts` (`mcp__desk__*`).
|
|
20
|
+
*
|
|
21
|
+
* The handler always calls `mcpManager.callTool()` with the un-prefixed
|
|
22
|
+
* `(server, tool)` pair regardless of how the surfaced name was shaped.
|
|
23
|
+
*/
|
|
24
|
+
function mcpToolsAsDefinitions(mcpManager) {
|
|
25
|
+
if (!mcpManager)
|
|
26
|
+
return [];
|
|
27
|
+
return mcpManager.listAllTools().flatMap((entry) => {
|
|
28
|
+
const isPluginSourced = Boolean(entry.pluginId);
|
|
29
|
+
return entry.tools.map((tool) => ({
|
|
30
|
+
tool: {
|
|
31
|
+
type: "function",
|
|
32
|
+
function: {
|
|
33
|
+
name: isPluginSourced
|
|
34
|
+
? `mcp__${entry.server}__${tool.name}`
|
|
35
|
+
: tool.name.startsWith(`${entry.server}_`) || tool.name === entry.server
|
|
36
|
+
? tool.name
|
|
37
|
+
: `${entry.server}_${tool.name}`,
|
|
38
|
+
description: tool.description || `MCP tool: ${tool.name} (server: ${entry.server})`,
|
|
39
|
+
parameters: tool.inputSchema ?? { type: "object", properties: {} },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
riskProfile: {
|
|
43
|
+
mutates: "external_side_effect",
|
|
44
|
+
risk: "high",
|
|
45
|
+
reason: "MCP tools may mutate external systems",
|
|
46
|
+
},
|
|
47
|
+
handler: async (args) => {
|
|
48
|
+
(0, runtime_1.emitNervesEvent)({
|
|
49
|
+
event: "mcp.tool_start",
|
|
50
|
+
component: "repertoire",
|
|
51
|
+
message: `calling MCP tool ${entry.server}/${tool.name}`,
|
|
52
|
+
meta: { server: entry.server, tool: tool.name },
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
const result = await mcpManager.callTool(entry.server, tool.name, args);
|
|
56
|
+
const text = result.content
|
|
57
|
+
.filter((c) => c.type === "text" && c.text)
|
|
58
|
+
.map((c) => c.text)
|
|
59
|
+
.join("");
|
|
60
|
+
(0, runtime_1.emitNervesEvent)({
|
|
61
|
+
event: "mcp.tool_end",
|
|
62
|
+
component: "repertoire",
|
|
63
|
+
message: `MCP tool ${entry.server}/${tool.name} completed`,
|
|
64
|
+
meta: { server: entry.server, tool: tool.name },
|
|
65
|
+
});
|
|
66
|
+
return text;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
70
|
+
(0, runtime_1.emitNervesEvent)({
|
|
71
|
+
level: "error",
|
|
72
|
+
event: "mcp.tool_error",
|
|
73
|
+
component: "repertoire",
|
|
74
|
+
message: `MCP tool ${entry.server}/${tool.name} failed: ${reason}`,
|
|
75
|
+
meta: { server: entry.server, tool: tool.name, reason },
|
|
76
|
+
});
|
|
77
|
+
return `[mcp error] ${entry.server}/${tool.name}: ${reason}`;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
mcpServer: entry.server,
|
|
81
|
+
}));
|
|
82
|
+
});
|
|
83
|
+
}
|