@ouro.bot/cli 0.1.0-alpha.65 → 0.1.0-alpha.650

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.
Files changed (434) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +4151 -14
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +144 -0
  15. package/dist/arc/episodes.js +118 -0
  16. package/dist/arc/evolution.js +487 -0
  17. package/dist/arc/intentions.js +134 -0
  18. package/dist/arc/json-store.js +117 -0
  19. package/dist/arc/obligations.js +270 -0
  20. package/dist/arc/packets.js +288 -0
  21. package/dist/arc/presence.js +185 -0
  22. package/dist/arc/task-lifecycle.js +57 -0
  23. package/dist/heart/active-work.js +860 -43
  24. package/dist/heart/agent-entry.js +69 -3
  25. package/dist/heart/attachments/image-normalize.js +194 -0
  26. package/dist/heart/attachments/materialize.js +97 -0
  27. package/dist/heart/attachments/originals.js +88 -0
  28. package/dist/heart/attachments/render.js +29 -0
  29. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  30. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  31. package/dist/heart/attachments/sources/index.js +16 -0
  32. package/dist/heart/attachments/store.js +103 -0
  33. package/dist/heart/attachments/types.js +93 -0
  34. package/dist/heart/auth/auth-flow.js +479 -0
  35. package/dist/heart/awaiting/await-alert.js +146 -0
  36. package/dist/heart/awaiting/await-expiry.js +108 -0
  37. package/dist/heart/awaiting/await-loader.js +91 -0
  38. package/dist/heart/awaiting/await-parser.js +141 -0
  39. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  40. package/dist/heart/awaiting/await-scheduler.js +377 -0
  41. package/dist/heart/background-operations.js +281 -0
  42. package/dist/heart/bridges/manager.js +137 -17
  43. package/dist/heart/bridges/store.js +14 -2
  44. package/dist/heart/bundle-state.js +168 -0
  45. package/dist/heart/commitments.js +135 -0
  46. package/dist/heart/config-registry.js +322 -0
  47. package/dist/heart/config.js +118 -119
  48. package/dist/heart/core.js +1123 -247
  49. package/dist/heart/cross-chat-delivery.js +3 -18
  50. package/dist/heart/daemon/agent-config-check.js +419 -0
  51. package/dist/heart/daemon/agent-discovery.js +102 -3
  52. package/dist/heart/daemon/agent-service.js +522 -0
  53. package/dist/heart/daemon/agentic-repair.js +547 -0
  54. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  55. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  56. package/dist/heart/daemon/cadence.js +70 -0
  57. package/dist/heart/daemon/cli-defaults.js +780 -0
  58. package/dist/heart/daemon/cli-desk.js +322 -0
  59. package/dist/heart/daemon/cli-exec.js +7480 -0
  60. package/dist/heart/daemon/cli-help.js +505 -0
  61. package/dist/heart/daemon/cli-parse.js +1554 -0
  62. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  63. package/dist/heart/daemon/cli-render.js +763 -0
  64. package/dist/heart/daemon/cli-types.js +8 -0
  65. package/dist/heart/daemon/connect-bay.js +323 -0
  66. package/dist/heart/daemon/daemon-cli.js +29 -1750
  67. package/dist/heart/daemon/daemon-entry.js +485 -2
  68. package/dist/heart/daemon/daemon-health.js +176 -0
  69. package/dist/heart/daemon/daemon-rollup.js +57 -0
  70. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  71. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  72. package/dist/heart/daemon/daemon.js +932 -74
  73. package/dist/heart/daemon/dns-workflow.js +394 -0
  74. package/dist/heart/daemon/doctor-types.js +8 -0
  75. package/dist/heart/daemon/doctor.js +873 -0
  76. package/dist/heart/daemon/health-monitor.js +122 -1
  77. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  78. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  79. package/dist/heart/daemon/http-health-probe.js +80 -0
  80. package/dist/heart/daemon/human-command-screens.js +234 -0
  81. package/dist/heart/daemon/human-readiness.js +114 -0
  82. package/dist/heart/daemon/inner-status.js +89 -0
  83. package/dist/heart/daemon/interactive-repair.js +394 -0
  84. package/dist/heart/daemon/launchd.js +37 -8
  85. package/dist/heart/daemon/log-tailer.js +79 -10
  86. package/dist/heart/daemon/logs-prune.js +110 -0
  87. package/dist/heart/daemon/mcp-canary.js +297 -0
  88. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  89. package/dist/heart/daemon/os-cron-deps.js +135 -0
  90. package/dist/heart/daemon/os-cron.js +14 -12
  91. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  92. package/dist/heart/daemon/ouro-entry.js +3 -1
  93. package/dist/heart/daemon/plugin-cli.js +432 -0
  94. package/dist/heart/daemon/process-manager.js +510 -40
  95. package/dist/heart/daemon/provider-discovery.js +137 -0
  96. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  97. package/dist/heart/daemon/pulse.js +475 -0
  98. package/dist/heart/daemon/readiness-repair.js +365 -0
  99. package/dist/heart/daemon/run-hooks.js +2 -0
  100. package/dist/heart/daemon/runtime-logging.js +35 -14
  101. package/dist/heart/daemon/runtime-metadata.js +2 -30
  102. package/dist/heart/daemon/safe-mode.js +161 -0
  103. package/dist/heart/daemon/sense-manager.js +493 -38
  104. package/dist/heart/daemon/session-id-resolver.js +131 -0
  105. package/dist/heart/daemon/skill-management-installer.js +1 -1
  106. package/dist/heart/daemon/socket-client.js +158 -11
  107. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  108. package/dist/heart/daemon/startup-tui.js +330 -0
  109. package/dist/heart/daemon/task-scheduler.js +117 -39
  110. package/dist/heart/daemon/terminal-ui.js +499 -0
  111. package/dist/heart/daemon/thoughts.js +229 -17
  112. package/dist/heart/daemon/up-progress.js +366 -0
  113. package/dist/heart/daemon/vault-items.js +56 -0
  114. package/dist/heart/delegation.js +1 -4
  115. package/dist/heart/habits/habit-migration.js +189 -0
  116. package/dist/heart/habits/habit-parser.js +140 -0
  117. package/dist/heart/habits/habit-runtime-state.js +100 -0
  118. package/dist/heart/habits/habit-scheduler.js +372 -0
  119. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  120. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  121. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  122. package/dist/heart/{daemon → hatch}/specialist-tools.js +37 -14
  123. package/dist/heart/identity.js +168 -57
  124. package/dist/heart/kept-notes.js +357 -0
  125. package/dist/heart/kicks.js +1 -1
  126. package/dist/heart/machine-identity.js +161 -0
  127. package/dist/heart/mail-import-discovery.js +353 -0
  128. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  129. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  130. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  131. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  132. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  133. package/dist/heart/mailbox/mailbox-http.js +99 -0
  134. package/dist/heart/mailbox/mailbox-read.js +31 -0
  135. package/dist/heart/mailbox/mailbox-types.js +27 -0
  136. package/dist/heart/mailbox/mailbox-view.js +197 -0
  137. package/dist/heart/mailbox/readers/agent-machine.js +418 -0
  138. package/dist/heart/mailbox/readers/continuity-readers.js +319 -0
  139. package/dist/heart/mailbox/readers/mail.js +375 -0
  140. package/dist/heart/mailbox/readers/runtime-readers.js +756 -0
  141. package/dist/heart/mailbox/readers/sessions.js +232 -0
  142. package/dist/heart/mailbox/readers/shared.js +111 -0
  143. package/dist/heart/mcp/mcp-server.js +692 -0
  144. package/dist/heart/migrate-config.js +100 -0
  145. package/dist/heart/model-capabilities.js +19 -0
  146. package/dist/heart/orientation-frame.js +217 -0
  147. package/dist/heart/platform.js +81 -0
  148. package/dist/heart/provider-attempt.js +134 -0
  149. package/dist/heart/provider-binding-resolver.js +272 -0
  150. package/dist/heart/provider-credentials.js +425 -0
  151. package/dist/heart/provider-failover.js +311 -0
  152. package/dist/heart/provider-models.js +81 -0
  153. package/dist/heart/provider-ping.js +262 -0
  154. package/dist/heart/provider-readiness-cache.js +40 -0
  155. package/dist/heart/provider-visibility.js +188 -0
  156. package/dist/heart/providers/anthropic-token.js +131 -0
  157. package/dist/heart/providers/anthropic.js +139 -52
  158. package/dist/heart/providers/azure.js +23 -11
  159. package/dist/heart/providers/error-classification.js +127 -0
  160. package/dist/heart/providers/github-copilot.js +145 -0
  161. package/dist/heart/providers/minimax-vlm.js +189 -0
  162. package/dist/heart/providers/minimax.js +26 -8
  163. package/dist/heart/providers/openai-codex-token.js +349 -0
  164. package/dist/heart/providers/openai-codex.js +55 -40
  165. package/dist/heart/runtime-capability-check.js +170 -0
  166. package/dist/heart/runtime-credentials.js +367 -0
  167. package/dist/heart/runtime-cwd.js +87 -0
  168. package/dist/heart/sense-truth.js +13 -4
  169. package/dist/heart/session-activity.js +48 -24
  170. package/dist/heart/session-events.js +1163 -0
  171. package/dist/heart/session-playback-cli-main.js +5 -0
  172. package/dist/heart/session-playback-cli.js +36 -0
  173. package/dist/heart/session-playback.js +231 -0
  174. package/dist/heart/session-stats-cli-main.js +5 -0
  175. package/dist/heart/session-stats.js +182 -0
  176. package/dist/heart/session-transcript.js +133 -0
  177. package/dist/heart/start-of-turn-packet.js +345 -0
  178. package/dist/heart/streaming.js +44 -27
  179. package/dist/heart/structured-output.js +196 -0
  180. package/dist/heart/sync-classification.js +176 -0
  181. package/dist/heart/sync.js +449 -0
  182. package/dist/heart/target-resolution.js +9 -5
  183. package/dist/heart/tempo.js +93 -0
  184. package/dist/heart/temporal-view.js +41 -0
  185. package/dist/heart/timeouts.js +101 -0
  186. package/dist/heart/tool-activity-callbacks.js +59 -0
  187. package/dist/heart/tool-description.js +143 -0
  188. package/dist/heart/tool-friction.js +55 -0
  189. package/dist/heart/tool-loop.js +200 -0
  190. package/dist/heart/turn-context.js +389 -0
  191. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  192. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  193. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  194. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  195. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  196. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  197. package/dist/heart/versioning/update-hooks.js +154 -0
  198. package/dist/mailbox-ui/assets/index-9-AxCxuB.js +61 -0
  199. package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
  200. package/dist/mailbox-ui/index.html +15 -0
  201. package/dist/mailroom/attention.js +167 -0
  202. package/dist/mailroom/autonomy.js +209 -0
  203. package/dist/mailroom/blob-store.js +715 -0
  204. package/dist/mailroom/body-cache.js +61 -0
  205. package/dist/mailroom/core.js +788 -0
  206. package/dist/mailroom/entry.js +160 -0
  207. package/dist/mailroom/file-store.js +568 -0
  208. package/dist/mailroom/mbox-import.js +393 -0
  209. package/dist/mailroom/migration.js +164 -0
  210. package/dist/mailroom/outbound.js +380 -0
  211. package/dist/mailroom/policy.js +263 -0
  212. package/dist/mailroom/reader.js +233 -0
  213. package/dist/mailroom/search-cache.js +334 -0
  214. package/dist/mailroom/search-relevance.js +319 -0
  215. package/dist/mailroom/smtp-ingress.js +176 -0
  216. package/dist/mailroom/source-state.js +176 -0
  217. package/dist/mailroom/thread.js +109 -0
  218. package/dist/mailroom/travel-extract.js +89 -0
  219. package/dist/mind/bundle-manifest.js +14 -1
  220. package/dist/mind/context.js +251 -101
  221. package/dist/mind/desk-section.js +310 -0
  222. package/dist/mind/diary-integrity.js +60 -0
  223. package/dist/mind/{memory.js → diary.js} +68 -76
  224. package/dist/mind/embedding-provider.js +60 -0
  225. package/dist/mind/file-state.js +179 -0
  226. package/dist/mind/friends/channel.js +39 -0
  227. package/dist/mind/friends/resolver.js +54 -2
  228. package/dist/mind/friends/store-file.js +48 -4
  229. package/dist/mind/friends/types.js +2 -2
  230. package/dist/mind/journal-index.js +162 -0
  231. package/dist/mind/note-search.js +268 -0
  232. package/dist/mind/obligation-steering.js +221 -0
  233. package/dist/mind/pending.js +6 -1
  234. package/dist/mind/prompt-refresh.js +3 -2
  235. package/dist/mind/prompt.js +1051 -138
  236. package/dist/mind/provenance-trust.js +26 -0
  237. package/dist/mind/scrutiny.js +173 -0
  238. package/dist/nerves/cli-logging.js +7 -1
  239. package/dist/nerves/coverage/audit-rules.js +15 -6
  240. package/dist/nerves/coverage/audit.js +28 -2
  241. package/dist/nerves/coverage/cli.js +1 -1
  242. package/dist/nerves/coverage/contract.js +5 -5
  243. package/dist/nerves/coverage/file-completeness.js +139 -5
  244. package/dist/nerves/event-buffer.js +111 -0
  245. package/dist/nerves/index.js +224 -4
  246. package/dist/nerves/observation.js +20 -0
  247. package/dist/nerves/redact.js +79 -0
  248. package/dist/nerves/review/cli-main.js +5 -0
  249. package/dist/nerves/review/cli.js +156 -0
  250. package/dist/nerves/review/core.js +152 -0
  251. package/dist/nerves/runtime.js +5 -1
  252. package/dist/repertoire/ado-client.js +15 -56
  253. package/dist/repertoire/ado-semantic.js +16 -10
  254. package/dist/repertoire/api-client.js +97 -0
  255. package/dist/repertoire/bitwarden-store.js +1041 -0
  256. package/dist/repertoire/bundle-templates.js +72 -0
  257. package/dist/repertoire/bw-installer.js +180 -0
  258. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  259. package/dist/repertoire/coding/context-pack.js +331 -0
  260. package/dist/repertoire/coding/feedback.js +197 -30
  261. package/dist/repertoire/coding/manager.js +166 -10
  262. package/dist/repertoire/coding/spawner.js +55 -9
  263. package/dist/repertoire/coding/tools.js +219 -7
  264. package/dist/repertoire/commerce-errors.js +109 -0
  265. package/dist/repertoire/commerce-self-test.js +156 -0
  266. package/dist/repertoire/credential-access.js +178 -0
  267. package/dist/repertoire/desk/classifier.js +362 -0
  268. package/dist/repertoire/duffel-client.js +185 -0
  269. package/dist/repertoire/github-client.js +14 -55
  270. package/dist/repertoire/graph-client.js +11 -52
  271. package/dist/repertoire/guardrails.js +136 -25
  272. package/dist/repertoire/mcp-client.js +295 -0
  273. package/dist/repertoire/mcp-manager.js +403 -0
  274. package/dist/repertoire/mcp-tools.js +83 -0
  275. package/dist/repertoire/plugin-mcp.js +175 -0
  276. package/dist/repertoire/plugins.js +253 -0
  277. package/dist/repertoire/shell-sessions.js +133 -0
  278. package/dist/repertoire/skills.js +48 -4
  279. package/dist/repertoire/stripe-client.js +131 -0
  280. package/dist/repertoire/tool-results.js +29 -0
  281. package/dist/repertoire/tools-attachments.js +317 -0
  282. package/dist/repertoire/tools-awaiting.js +372 -0
  283. package/dist/repertoire/tools-base.js +59 -1082
  284. package/dist/repertoire/tools-bluebubbles.js +2 -0
  285. package/dist/repertoire/tools-bridge.js +144 -0
  286. package/dist/repertoire/tools-bundle.js +993 -0
  287. package/dist/repertoire/tools-config.js +186 -0
  288. package/dist/repertoire/tools-continuity.js +252 -0
  289. package/dist/repertoire/tools-credential.js +383 -0
  290. package/dist/repertoire/tools-evolution.js +527 -0
  291. package/dist/repertoire/tools-files.js +344 -0
  292. package/dist/repertoire/tools-flight.js +227 -0
  293. package/dist/repertoire/tools-flow.js +119 -0
  294. package/dist/repertoire/tools-github.js +3 -8
  295. package/dist/repertoire/tools-mail.js +1975 -0
  296. package/dist/repertoire/tools-notes.js +438 -0
  297. package/dist/repertoire/tools-obligations.js +143 -0
  298. package/dist/repertoire/tools-orientation.js +31 -0
  299. package/dist/repertoire/tools-record.js +464 -0
  300. package/dist/repertoire/tools-runtime.js +150 -0
  301. package/dist/repertoire/tools-session.js +766 -0
  302. package/dist/repertoire/tools-shell.js +120 -0
  303. package/dist/repertoire/tools-stripe.js +182 -0
  304. package/dist/repertoire/tools-surface.js +344 -0
  305. package/dist/repertoire/tools-teams.js +12 -39
  306. package/dist/repertoire/tools-travel.js +125 -0
  307. package/dist/repertoire/tools-trip.js +982 -0
  308. package/dist/repertoire/tools-user-profile.js +146 -0
  309. package/dist/repertoire/tools-vault.js +40 -0
  310. package/dist/repertoire/tools-voice.js +145 -0
  311. package/dist/repertoire/tools.js +193 -77
  312. package/dist/repertoire/travel-api-client.js +360 -0
  313. package/dist/repertoire/user-profile.js +131 -0
  314. package/dist/repertoire/vault-setup.js +246 -0
  315. package/dist/repertoire/vault-unlock.js +594 -0
  316. package/dist/scripts/claude-code-hook.js +41 -0
  317. package/dist/scripts/claude-code-stop-hook.js +47 -0
  318. package/dist/senses/attention-queue.js +186 -0
  319. package/dist/senses/await-turn-message.js +58 -0
  320. package/dist/senses/bluebubbles/active-turns.js +216 -0
  321. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  322. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  323. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  324. package/dist/senses/bluebubbles/entry.js +77 -0
  325. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  326. package/dist/senses/bluebubbles/index.js +2737 -0
  327. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  328. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  329. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  330. package/dist/senses/bluebubbles/processed-log.js +133 -0
  331. package/dist/senses/bluebubbles/replay.js +137 -0
  332. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  333. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  334. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  335. package/dist/senses/cli/bracketed-paste.js +82 -0
  336. package/dist/senses/cli/image-paste.js +287 -0
  337. package/dist/senses/cli/image-ref-navigation.js +75 -0
  338. package/dist/senses/cli/ink-app.js +156 -0
  339. package/dist/senses/cli/inline-diff.js +64 -0
  340. package/dist/senses/cli/input-keys.js +174 -0
  341. package/dist/senses/cli/kill-ring.js +86 -0
  342. package/dist/senses/cli/message-list.js +51 -0
  343. package/dist/senses/cli/ouro-tui.js +607 -0
  344. package/dist/senses/cli/spinner-imperative.js +135 -0
  345. package/dist/senses/cli/spinner.js +101 -0
  346. package/dist/senses/cli/status-line.js +60 -0
  347. package/dist/senses/cli/streaming-markdown.js +526 -0
  348. package/dist/senses/cli/tool-display.js +85 -0
  349. package/dist/senses/cli/tool-render.js +85 -0
  350. package/dist/senses/cli/tui-store.js +240 -0
  351. package/dist/senses/cli/virtual-list.js +35 -0
  352. package/dist/senses/cli-entry.js +60 -8
  353. package/dist/senses/cli-layout.js +100 -0
  354. package/dist/senses/cli.js +517 -204
  355. package/dist/senses/commands.js +66 -3
  356. package/dist/senses/habit-turn-message.js +108 -0
  357. package/dist/senses/inner-dialog-worker.js +254 -22
  358. package/dist/senses/inner-dialog.js +505 -40
  359. package/dist/senses/mail-entry.js +66 -0
  360. package/dist/senses/mail.js +379 -0
  361. package/dist/senses/pipeline.js +711 -181
  362. package/dist/senses/proactive-content-guard.js +51 -0
  363. package/dist/senses/shared-turn.js +393 -0
  364. package/dist/senses/surface-tool.js +108 -0
  365. package/dist/senses/teams-entry.js +60 -8
  366. package/dist/senses/teams.js +390 -98
  367. package/dist/senses/trust-gate.js +100 -5
  368. package/dist/senses/voice/audio-playback.js +237 -0
  369. package/dist/senses/voice/audio-routing.js +119 -0
  370. package/dist/senses/voice/elevenlabs.js +202 -0
  371. package/dist/senses/voice/floor-control.js +431 -0
  372. package/dist/senses/voice/floor-controller.js +115 -0
  373. package/dist/senses/voice/golden-path.js +116 -0
  374. package/dist/senses/voice/index.js +29 -0
  375. package/dist/senses/voice/meeting.js +113 -0
  376. package/dist/senses/voice/outbound.js +190 -0
  377. package/dist/senses/voice/phone.js +33 -0
  378. package/dist/senses/voice/playback.js +139 -0
  379. package/dist/senses/voice/realtime-eval.js +496 -0
  380. package/dist/senses/voice/realtime-trace.js +531 -0
  381. package/dist/senses/voice/transcript.js +70 -0
  382. package/dist/senses/voice/turn.js +191 -0
  383. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  384. package/dist/senses/voice/twilio-phone.js +5079 -0
  385. package/dist/senses/voice/types.js +2 -0
  386. package/dist/senses/voice/whisper.js +161 -0
  387. package/dist/senses/voice-entry.js +81 -0
  388. package/dist/senses/voice-realtime-eval-command.js +99 -0
  389. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  390. package/dist/senses/voice-twilio-entry.js +87 -0
  391. package/dist/trips/core.js +138 -0
  392. package/dist/trips/store.js +265 -0
  393. package/dist/util/frontmatter.js +53 -0
  394. package/package.json +53 -10
  395. package/skills/agent-commerce.md +106 -0
  396. package/skills/browser-navigation.md +117 -0
  397. package/skills/commerce-setup-guide.md +116 -0
  398. package/skills/commerce-setup.md +84 -0
  399. package/skills/configure-dev-tools.md +99 -0
  400. package/skills/travel-planning.md +138 -0
  401. package/dist/heart/daemon/auth-flow.js +0 -351
  402. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  403. package/dist/heart/daemon/update-hooks.js +0 -138
  404. package/dist/heart/safe-workspace.js +0 -228
  405. package/dist/heart/session-recall.js +0 -116
  406. package/dist/mind/associative-recall.js +0 -209
  407. package/dist/repertoire/tasks/board.js +0 -134
  408. package/dist/repertoire/tasks/index.js +0 -224
  409. package/dist/repertoire/tasks/lifecycle.js +0 -80
  410. package/dist/repertoire/tasks/middleware.js +0 -65
  411. package/dist/repertoire/tasks/parser.js +0 -173
  412. package/dist/repertoire/tasks/scanner.js +0 -132
  413. package/dist/repertoire/tasks/transitions.js +0 -144
  414. package/dist/senses/bluebubbles-entry.js +0 -13
  415. package/dist/senses/bluebubbles.js +0 -1177
  416. package/dist/senses/debug-activity.js +0 -148
  417. package/subagents/README.md +0 -7
  418. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  419. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  420. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  421. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  422. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  423. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  424. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  425. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  426. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  427. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  428. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  429. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  430. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  431. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  432. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  433. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  434. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpClient = void 0;
4
+ exports.isMcpTransportError = isMcpTransportError;
5
+ const child_process_1 = require("child_process");
6
+ const readline_1 = require("readline");
7
+ const runtime_1 = require("../nerves/runtime");
8
+ const runtime_cwd_1 = require("../heart/runtime-cwd");
9
+ const MCP_PROTOCOL_VERSION = "2024-11-05";
10
+ const DEFAULT_REQUEST_TIMEOUT = 10_000;
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
+ }
25
+ class McpClient {
26
+ config;
27
+ process = null;
28
+ nextId = 1;
29
+ pending = new Map();
30
+ connected = false;
31
+ cachedTools = null;
32
+ onCloseCallback = null;
33
+ constructor(config) {
34
+ this.config = config;
35
+ }
36
+ async connect() {
37
+ if (this.connected)
38
+ return;
39
+ this.shutdownProcessOnly();
40
+ (0, runtime_1.emitNervesEvent)({
41
+ event: "mcp.connect_start",
42
+ component: "repertoire",
43
+ message: "starting MCP server connection",
44
+ meta: { command: this.config.command },
45
+ });
46
+ const env = { ...process.env, ...this.config.env };
47
+ const spawnCwd = this.config.cwd ?? (0, runtime_cwd_1.recoverRuntimeCwd)();
48
+ this.process = (0, child_process_1.spawn)(this.config.command, this.config.args ?? [], {
49
+ env,
50
+ stdio: ["pipe", "pipe", "pipe"],
51
+ cwd: spawnCwd,
52
+ });
53
+ this.setupLineReader();
54
+ this.setupProcessHandlers();
55
+ try {
56
+ await this.initialize();
57
+ this.connected = true;
58
+ (0, runtime_1.emitNervesEvent)({
59
+ event: "mcp.connect_end",
60
+ component: "repertoire",
61
+ message: "MCP server connected",
62
+ meta: { command: this.config.command },
63
+ });
64
+ }
65
+ catch (error) {
66
+ this.connected = false;
67
+ this.shutdownProcessOnly();
68
+ (0, runtime_1.emitNervesEvent)({
69
+ level: "error",
70
+ event: "mcp.connect_error",
71
+ component: "repertoire",
72
+ message: "MCP server connection failed",
73
+ meta: {
74
+ command: this.config.command,
75
+ /* v8 ignore next -- defensive: spawn errors are always Error instances @preserve */
76
+ reason: error instanceof Error ? error.message : String(error),
77
+ },
78
+ });
79
+ throw error;
80
+ }
81
+ }
82
+ async listTools() {
83
+ if (this.cachedTools) {
84
+ return this.cachedTools;
85
+ }
86
+ const allTools = [];
87
+ let cursor;
88
+ do {
89
+ const params = {};
90
+ if (cursor) {
91
+ params.cursor = cursor;
92
+ }
93
+ const result = await this.sendRequest("tools/list", params);
94
+ allTools.push(...result.tools);
95
+ cursor = result.nextCursor;
96
+ } while (cursor);
97
+ this.cachedTools = allTools;
98
+ return allTools;
99
+ }
100
+ async refreshTools() {
101
+ this.cachedTools = null;
102
+ return this.listTools();
103
+ }
104
+ async callTool(name, args, timeout = DEFAULT_TOOL_CALL_TIMEOUT) {
105
+ (0, runtime_1.emitNervesEvent)({
106
+ event: "mcp.tool_call_start",
107
+ component: "repertoire",
108
+ message: `calling MCP tool: ${name}`,
109
+ meta: { tool: name },
110
+ });
111
+ try {
112
+ const result = await this.sendRequest("tools/call", {
113
+ name,
114
+ arguments: args,
115
+ }, timeout);
116
+ (0, runtime_1.emitNervesEvent)({
117
+ event: "mcp.tool_call_end",
118
+ component: "repertoire",
119
+ message: `MCP tool call completed: ${name}`,
120
+ meta: { tool: name },
121
+ });
122
+ return result;
123
+ }
124
+ catch (error) {
125
+ (0, runtime_1.emitNervesEvent)({
126
+ level: "error",
127
+ event: "mcp.tool_call_error",
128
+ component: "repertoire",
129
+ message: `MCP tool call failed: ${name}`,
130
+ meta: {
131
+ tool: name,
132
+ /* v8 ignore next -- defensive: callTool errors are always Error instances @preserve */
133
+ reason: error instanceof Error ? error.message : String(error),
134
+ },
135
+ });
136
+ throw error;
137
+ }
138
+ }
139
+ shutdown() {
140
+ this.connected = false;
141
+ this.rejectAllPending(new Error("Client shutdown"));
142
+ /* v8 ignore next -- defensive: process always exists during normal shutdown @preserve */
143
+ if (this.process && !this.process.killed) {
144
+ this.process.kill();
145
+ }
146
+ this.process = null;
147
+ }
148
+ isConnected() {
149
+ return this.connected;
150
+ }
151
+ onClose(callback) {
152
+ this.onCloseCallback = callback;
153
+ }
154
+ async initialize() {
155
+ const result = await this.sendRequest("initialize", {
156
+ protocolVersion: MCP_PROTOCOL_VERSION,
157
+ clientInfo: { name: "ouroboros", version: "1.0" },
158
+ capabilities: {},
159
+ });
160
+ // Send initialized notification (no id, no response expected)
161
+ this.writeMessage({
162
+ jsonrpc: "2.0",
163
+ method: "initialized",
164
+ });
165
+ return result;
166
+ }
167
+ sendRequest(method, params, timeout = DEFAULT_REQUEST_TIMEOUT) {
168
+ return new Promise((resolve, reject) => {
169
+ if (!this.process || !this.connected && method !== "initialize") {
170
+ reject(new Error("MCP client is disconnected"));
171
+ return;
172
+ }
173
+ const id = this.nextId++;
174
+ const pending = { resolve, reject };
175
+ if (timeout) {
176
+ pending.timer = setTimeout(() => {
177
+ this.pending.delete(id);
178
+ reject(new Error(`MCP request timeout after ${timeout}ms: ${method}`));
179
+ }, timeout);
180
+ }
181
+ this.pending.set(id, pending);
182
+ const request = {
183
+ jsonrpc: "2.0",
184
+ id,
185
+ method,
186
+ params,
187
+ };
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
+ }
195
+ });
196
+ }
197
+ writeMessage(message) {
198
+ if (this.process?.stdin?.writable) {
199
+ this.process.stdin.write(JSON.stringify(message) + "\n");
200
+ return true;
201
+ }
202
+ return false;
203
+ }
204
+ setupLineReader() {
205
+ /* v8 ignore next -- defensive: stdout always exists after spawn @preserve */
206
+ if (!this.process?.stdout)
207
+ return;
208
+ const rl = (0, readline_1.createInterface)({ input: this.process.stdout });
209
+ rl.on("line", (line) => {
210
+ this.handleLine(line);
211
+ });
212
+ }
213
+ handleLine(line) {
214
+ let response;
215
+ try {
216
+ response = JSON.parse(line);
217
+ }
218
+ catch {
219
+ (0, runtime_1.emitNervesEvent)({
220
+ level: "warn",
221
+ event: "mcp.connect_error",
222
+ component: "repertoire",
223
+ message: "received malformed JSON from MCP server",
224
+ meta: { line },
225
+ });
226
+ return;
227
+ }
228
+ if (response.id === undefined || response.id === null) {
229
+ // Notification or invalid — ignore
230
+ return;
231
+ }
232
+ const pending = this.pending.get(response.id);
233
+ if (!pending)
234
+ return;
235
+ this.pending.delete(response.id);
236
+ if (pending.timer) {
237
+ clearTimeout(pending.timer);
238
+ }
239
+ if (response.error) {
240
+ pending.reject(new Error(response.error.message));
241
+ }
242
+ else {
243
+ pending.resolve(response.result);
244
+ }
245
+ }
246
+ setupProcessHandlers() {
247
+ /* v8 ignore next -- defensive: process always exists after spawn @preserve */
248
+ if (!this.process)
249
+ return;
250
+ this.process.on("error", (error) => {
251
+ (0, runtime_1.emitNervesEvent)({
252
+ level: "error",
253
+ event: "mcp.connect_error",
254
+ component: "repertoire",
255
+ message: "MCP server process error",
256
+ meta: { reason: error.message },
257
+ });
258
+ });
259
+ this.process.on("close", (code) => {
260
+ const wasConnected = this.connected;
261
+ this.connected = false;
262
+ this.rejectAllPending(new Error(`MCP server process closed with code ${code}`));
263
+ if (wasConnected) {
264
+ (0, runtime_1.emitNervesEvent)({
265
+ level: "error",
266
+ event: "mcp.connect_error",
267
+ component: "repertoire",
268
+ message: "MCP server process exited unexpectedly",
269
+ meta: { exitCode: code },
270
+ });
271
+ }
272
+ if (this.onCloseCallback) {
273
+ this.onCloseCallback();
274
+ }
275
+ });
276
+ }
277
+ rejectAllPending(error) {
278
+ for (const [id, pending] of this.pending) {
279
+ if (pending.timer) {
280
+ clearTimeout(pending.timer);
281
+ }
282
+ pending.reject(error);
283
+ this.pending.delete(id);
284
+ }
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
+ }
294
+ }
295
+ exports.McpClient = McpClient;
@@ -0,0 +1,403 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpManager = void 0;
4
+ exports.getSharedMcpManager = getSharedMcpManager;
5
+ exports.shutdownSharedMcpManager = shutdownSharedMcpManager;
6
+ exports.resetSharedMcpManager = resetSharedMcpManager;
7
+ const mcp_client_1 = require("./mcp-client");
8
+ const identity_1 = require("../heart/identity");
9
+ const runtime_1 = require("../nerves/runtime");
10
+ const credential_access_1 = require("./credential-access");
11
+ const plugin_mcp_1 = require("./plugin-mcp");
12
+ const MAX_RESTART_RETRIES = 5;
13
+ const RESTART_DELAY_MS = 1000;
14
+ /**
15
+ * Merge builtin (agent.json mcpServers) + plugin-declared (.mcp.json) servers.
16
+ *
17
+ * Builtin wins on name collision. Returns the merged config map plus a
18
+ * `pluginOrigins` map (server-name → plugin-id) for tools-surfacing namespace.
19
+ *
20
+ * Shared by `getSharedMcpManager()` (initial start) and `McpManager.reconcile()`
21
+ * (re-read on each turn). Both code paths MUST use the same merge logic — if
22
+ * reconcile reads only builtin, plugin servers get classified as "removed"
23
+ * on the second turn and torn down. See alpha.635 fix.
24
+ */
25
+ function buildMergedServerConfig() {
26
+ const config = (0, identity_1.loadAgentConfig)();
27
+ const builtinServers = config.mcpServers ?? {};
28
+ const pluginServers = (0, plugin_mcp_1.listPluginMcpServers)();
29
+ const mergedServers = {};
30
+ const pluginOrigins = {};
31
+ for (const p of pluginServers) {
32
+ if (builtinServers[p.serverName] !== undefined)
33
+ continue;
34
+ mergedServers[p.serverName] = (0, plugin_mcp_1.pluginMcpServerToConfig)(p);
35
+ pluginOrigins[p.serverName] = p.pluginId;
36
+ }
37
+ for (const [name, cfg] of Object.entries(builtinServers)) {
38
+ mergedServers[name] = cfg;
39
+ }
40
+ return { mergedServers, pluginOrigins };
41
+ }
42
+ class McpManager {
43
+ servers = new Map();
44
+ shuttingDown = false;
45
+ async start(servers, pluginOrigins = {}) {
46
+ (0, runtime_1.emitNervesEvent)({
47
+ event: "mcp.manager_start",
48
+ component: "repertoire",
49
+ message: "starting MCP manager",
50
+ meta: {
51
+ serverCount: Object.keys(servers).length,
52
+ pluginServerCount: Object.keys(pluginOrigins).length,
53
+ },
54
+ });
55
+ const entries = Object.entries(servers);
56
+ for (const [name, config] of entries) {
57
+ await this.connectServer(name, config, pluginOrigins[name]);
58
+ }
59
+ }
60
+ listAllTools() {
61
+ const result = [];
62
+ for (const [name, entry] of this.servers) {
63
+ result.push({ server: name, tools: entry.cachedTools, pluginId: entry.pluginId });
64
+ }
65
+ return result;
66
+ }
67
+ async callTool(server, tool, args) {
68
+ let entry = this.servers.get(server);
69
+ if (!entry) {
70
+ throw new Error(`Unknown server: ${server}`);
71
+ }
72
+ if (!entry.client.isConnected()) {
73
+ await this.recoverStaleTransport(server, "pre-call disconnected");
74
+ entry = this.servers.get(server);
75
+ if (!entry?.client.isConnected()) {
76
+ throw new Error(`Server "${server}" is disconnected`);
77
+ }
78
+ }
79
+ try {
80
+ return await entry.client.callTool(tool, args);
81
+ }
82
+ catch (error) {
83
+ if (!(0, mcp_client_1.isMcpTransportError)(error)) {
84
+ throw error;
85
+ }
86
+ const reason = error instanceof Error ? error.message : String(error);
87
+ await this.recoverStaleTransport(server, reason);
88
+ const recovered = this.servers.get(server);
89
+ if (!recovered?.client.isConnected()) {
90
+ throw new Error(`Server "${server}" is disconnected after recovery: ${reason}`);
91
+ }
92
+ return recovered.client.callTool(tool, args);
93
+ }
94
+ }
95
+ async runCanaries() {
96
+ const results = [];
97
+ for (const [server, entry] of [...this.servers]) {
98
+ try {
99
+ if (!entry.client.isConnected()) {
100
+ await this.recoverStaleTransport(server, "canary disconnected");
101
+ }
102
+ const current = this.servers.get(server);
103
+ if (!current?.client.isConnected()) {
104
+ results.push({ server, ok: false, detail: "disconnected after recovery attempt" });
105
+ continue;
106
+ }
107
+ const tools = await current.client.refreshTools();
108
+ current.cachedTools = tools;
109
+ current.consecutiveFailures = 0;
110
+ results.push({ server, ok: true, detail: `${tools.length} tools listed` });
111
+ }
112
+ catch (error) {
113
+ const reason = error instanceof Error ? error.message : String(error);
114
+ if ((0, mcp_client_1.isMcpTransportError)(error)) {
115
+ await this.recoverStaleTransport(server, reason);
116
+ }
117
+ results.push({ server, ok: false, detail: reason });
118
+ }
119
+ }
120
+ return results;
121
+ }
122
+ /* v8 ignore start — reconcile: dynamic MCP server management, tested via integration @preserve */
123
+ /** Re-read agent config AND enabled-plugin .mcp.json files, then connect new
124
+ * servers / disconnect removed ones. Must include plugin-declared servers
125
+ * in the desired set — otherwise plugin servers (e.g. mcp__desk__*) are
126
+ * treated as "removed" on every call and get torn down between turns. */
127
+ async reconcile() {
128
+ try {
129
+ const { mergedServers, pluginOrigins } = buildMergedServerConfig();
130
+ const currentNames = new Set(this.servers.keys());
131
+ const desiredNames = new Set(Object.keys(mergedServers));
132
+ // Connect new servers
133
+ for (const [name, cfg] of Object.entries(mergedServers)) {
134
+ if (!currentNames.has(name)) {
135
+ (0, runtime_1.emitNervesEvent)({
136
+ event: "mcp.server_added",
137
+ component: "repertoire",
138
+ message: `connecting new MCP server: ${name}`,
139
+ meta: { server: name, command: cfg.command },
140
+ });
141
+ await this.connectServer(name, cfg, pluginOrigins[name]);
142
+ }
143
+ }
144
+ // Disconnect removed servers
145
+ for (const name of currentNames) {
146
+ if (!desiredNames.has(name)) {
147
+ (0, runtime_1.emitNervesEvent)({
148
+ event: "mcp.server_removed",
149
+ component: "repertoire",
150
+ message: `disconnecting removed MCP server: ${name}`,
151
+ meta: { server: name },
152
+ });
153
+ const entry = this.servers.get(name);
154
+ if (entry)
155
+ entry.client.shutdown();
156
+ this.servers.delete(name);
157
+ }
158
+ }
159
+ }
160
+ catch (error) {
161
+ (0, runtime_1.emitNervesEvent)({
162
+ level: "warn",
163
+ event: "mcp.reconcile_error",
164
+ component: "repertoire",
165
+ message: "failed to reconcile MCP servers",
166
+ meta: { reason: error instanceof Error ? error.message : String(error) },
167
+ });
168
+ }
169
+ }
170
+ /* v8 ignore stop */
171
+ shutdown() {
172
+ this.shuttingDown = true;
173
+ // `_end` (not `_stop`) to pair with `mcp.manager_start` under the
174
+ // nerves audit start/end pairing rule.
175
+ (0, runtime_1.emitNervesEvent)({
176
+ event: "mcp.manager_end",
177
+ component: "repertoire",
178
+ message: "shutting down MCP manager",
179
+ meta: { serverCount: this.servers.size },
180
+ });
181
+ for (const [, entry] of this.servers) {
182
+ entry.client.shutdown();
183
+ }
184
+ this.servers.clear();
185
+ }
186
+ /**
187
+ * Resolve `vault:DOMAIN/FIELD` references in server env config.
188
+ * Returns resolved env or throws with a descriptive error.
189
+ */
190
+ async resolveVaultEnv(_serverName, env) {
191
+ const resolved = { ...env };
192
+ // Short-circuit: only spin up a credential store if at least one env value
193
+ // actually requests vault resolution. Plugin MCP servers commonly ship with
194
+ // `env: {}` or pure-string envs, and we shouldn't pay the credential-store
195
+ // boot cost (or fail in test envs that have no vault) for those cases.
196
+ const hasVaultRef = Object.values(resolved).some((v) => /^vault:/.test(v));
197
+ if (!hasVaultRef)
198
+ return resolved;
199
+ const store = (0, credential_access_1.getCredentialStore)();
200
+ for (const [key, value] of Object.entries(resolved)) {
201
+ const match = value.match(/^vault:([^/]+)\/(.+)$/);
202
+ if (!match)
203
+ continue;
204
+ const [, domain, field] = match;
205
+ try {
206
+ resolved[key] = await store.getRawSecret(domain, field);
207
+ }
208
+ catch (err) {
209
+ /* v8 ignore next -- reason @preserve */
210
+ const reason = err instanceof Error ? err.message : String(err);
211
+ // Classify the error for actionable messaging
212
+ let classification = "vault unreachable";
213
+ if (reason.includes("no credential found")) {
214
+ classification = "item not found";
215
+ }
216
+ else if (reason.includes("field") && reason.includes("not found")) {
217
+ classification = "field empty";
218
+ }
219
+ throw new Error(`vault:${domain}/${field} could not be resolved: ${classification}`);
220
+ }
221
+ }
222
+ return resolved;
223
+ }
224
+ async connectServer(name, config, pluginId) {
225
+ // Resolve vault: references in env before spawning
226
+ let resolvedConfig = config;
227
+ if (config.env) {
228
+ try {
229
+ const resolvedEnv = await this.resolveVaultEnv(name, config.env);
230
+ resolvedConfig = { ...config, env: resolvedEnv };
231
+ }
232
+ catch (err) {
233
+ /* v8 ignore next -- reason @preserve */
234
+ const reason = err instanceof Error ? err.message : String(err);
235
+ (0, runtime_1.emitNervesEvent)({
236
+ level: "error",
237
+ event: "mcp.vault_resolve_error",
238
+ component: "repertoire",
239
+ message: `skipping MCP server "${name}": ${reason}`,
240
+ meta: { server: name, reason },
241
+ });
242
+ return; // Skip this server, continue to next
243
+ }
244
+ }
245
+ const client = new mcp_client_1.McpClient(resolvedConfig);
246
+ const entry = {
247
+ name,
248
+ config,
249
+ client,
250
+ cachedTools: [],
251
+ consecutiveFailures: 0,
252
+ pluginId,
253
+ };
254
+ this.servers.set(name, entry);
255
+ client.onClose(() => {
256
+ if (this.shuttingDown)
257
+ return;
258
+ this.handleServerCrash(name);
259
+ });
260
+ try {
261
+ await client.connect();
262
+ const tools = await client.listTools();
263
+ entry.cachedTools = tools;
264
+ entry.consecutiveFailures = 0;
265
+ }
266
+ catch (error) {
267
+ const reason = error instanceof Error ? error.message : String(error);
268
+ (0, runtime_1.emitNervesEvent)({
269
+ level: "error",
270
+ event: "mcp.connect_error",
271
+ component: "repertoire",
272
+ message: `failed to connect MCP server "${name}" (command: ${config.command}). Check that the command exists and is properly configured. Reason: ${reason}`,
273
+ meta: {
274
+ server: name,
275
+ command: config.command,
276
+ args: config.args,
277
+ reason,
278
+ },
279
+ });
280
+ }
281
+ }
282
+ handleServerCrash(name) {
283
+ const entry = this.servers.get(name);
284
+ /* v8 ignore next -- defensive: entry removed between close event and handler @preserve */
285
+ if (!entry)
286
+ return;
287
+ entry.consecutiveFailures++;
288
+ if (entry.consecutiveFailures > MAX_RESTART_RETRIES) {
289
+ (0, runtime_1.emitNervesEvent)({
290
+ level: "error",
291
+ event: "mcp.connect_error",
292
+ component: "repertoire",
293
+ 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.`,
294
+ meta: { server: name, command: entry.config.command, failures: entry.consecutiveFailures },
295
+ });
296
+ return;
297
+ }
298
+ (0, runtime_1.emitNervesEvent)({
299
+ level: "warn",
300
+ event: "mcp.server_restart",
301
+ component: "repertoire",
302
+ message: `restarting crashed MCP server: ${name}`,
303
+ meta: { server: name, attempt: entry.consecutiveFailures },
304
+ });
305
+ /* v8 ignore start -- timer callback: covered by mcp-manager.test.ts via fake timers but v8 can't trace @preserve */
306
+ setTimeout(() => {
307
+ if (this.shuttingDown)
308
+ return;
309
+ this.restartServer(name).catch(() => {
310
+ // Error handling is inside restartServer
311
+ });
312
+ }, RESTART_DELAY_MS);
313
+ /* v8 ignore stop */
314
+ }
315
+ /* v8 ignore start -- called from timer callback: covered by mcp-manager.test.ts via fake timers but v8 can't trace @preserve */
316
+ async restartServer(name) {
317
+ const entry = this.servers.get(name);
318
+ if (!entry)
319
+ return;
320
+ // Remove old entry and reconnect
321
+ this.servers.delete(name);
322
+ entry.client.shutdown();
323
+ await this.connectServer(name, entry.config);
324
+ // Preserve failure count
325
+ const newEntry = this.servers.get(name);
326
+ if (newEntry) {
327
+ newEntry.consecutiveFailures = entry.consecutiveFailures;
328
+ }
329
+ }
330
+ /* v8 ignore stop */
331
+ async recoverStaleTransport(name, reason) {
332
+ (0, runtime_1.emitNervesEvent)({
333
+ level: "warn",
334
+ event: "mcp.transport_recovery",
335
+ component: "repertoire",
336
+ message: `recovering stale MCP transport: ${name}`,
337
+ meta: { server: name, reason },
338
+ });
339
+ await this.restartServer(name);
340
+ }
341
+ }
342
+ exports.McpManager = McpManager;
343
+ let _sharedManager = null;
344
+ let _sharedManagerPromise = null;
345
+ /**
346
+ * Get or create a shared McpManager instance from the agent's config.
347
+ * Returns null if no mcpServers are configured.
348
+ * Safe to call from multiple senses — will only create one instance.
349
+ */
350
+ async function getSharedMcpManager() {
351
+ // If manager exists, reconcile to pick up config changes (new/removed servers)
352
+ /* v8 ignore start — reconcile on existing manager @preserve */
353
+ if (_sharedManager) {
354
+ await _sharedManager.reconcile();
355
+ return _sharedManager;
356
+ }
357
+ /* v8 ignore stop */
358
+ /* v8 ignore next -- race guard: deduplicates concurrent initialization calls @preserve */
359
+ if (_sharedManagerPromise)
360
+ return _sharedManagerPromise;
361
+ // Always re-check config — agent may have added servers since last call
362
+ _sharedManagerPromise = (async () => {
363
+ try {
364
+ const { mergedServers, pluginOrigins } = buildMergedServerConfig();
365
+ if (Object.keys(mergedServers).length === 0)
366
+ return null;
367
+ const manager = new McpManager();
368
+ await manager.start(mergedServers, pluginOrigins);
369
+ _sharedManager = manager;
370
+ return manager;
371
+ }
372
+ catch (error) {
373
+ (0, runtime_1.emitNervesEvent)({
374
+ level: "error",
375
+ event: "mcp.manager_start",
376
+ component: "repertoire",
377
+ message: "failed to initialize shared MCP manager",
378
+ /* v8 ignore next -- both branches tested: Error in wiring test, non-Error is defensive @preserve */
379
+ meta: { reason: error instanceof Error ? error.message : String(error) },
380
+ });
381
+ return null;
382
+ }
383
+ finally {
384
+ _sharedManagerPromise = null;
385
+ }
386
+ })();
387
+ return _sharedManagerPromise;
388
+ }
389
+ /**
390
+ * Shut down the shared MCP manager and clear the singleton.
391
+ * Called during daemon/agent shutdown.
392
+ */
393
+ function shutdownSharedMcpManager() {
394
+ if (_sharedManager) {
395
+ _sharedManager.shutdown();
396
+ _sharedManager = null;
397
+ }
398
+ }
399
+ /** Reset for testing only */
400
+ function resetSharedMcpManager() {
401
+ _sharedManager = null;
402
+ _sharedManagerPromise = null;
403
+ }