@ouro.bot/cli 0.1.0-alpha.83 → 0.1.0-alpha.831

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 (647) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5308 -16
  16. package/deploy/unraid/Dockerfile +54 -0
  17. package/deploy/unraid/README.txt +2983 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  34. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  35. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2084 -0
  36. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  37. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  38. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  39. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  40. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  41. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  42. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +795 -0
  43. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  45. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  46. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +15 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +15 -0
  49. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  50. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +135 -0
  51. package/deploy/unraid/sanctuary.xml +28 -0
  52. package/dist/a2a/card.js +57 -0
  53. package/dist/a2a/client.js +180 -0
  54. package/dist/a2a/config.js +50 -0
  55. package/dist/a2a/delegation-stores.js +56 -0
  56. package/dist/a2a/did-resolution.js +93 -0
  57. package/dist/a2a/identity.js +170 -0
  58. package/dist/a2a/inbound-share.js +107 -0
  59. package/dist/a2a/mission-result-wire.js +196 -0
  60. package/dist/a2a/onboarding.js +115 -0
  61. package/dist/a2a/pin-store.js +132 -0
  62. package/dist/a2a/seen-ledger.js +120 -0
  63. package/dist/a2a/server.js +604 -0
  64. package/dist/a2a/task-store.js +69 -0
  65. package/dist/a2a/transport.js +45 -0
  66. package/dist/a2a/types.js +3 -0
  67. package/dist/arc/attention-types.js +8 -0
  68. package/dist/arc/cares.js +360 -0
  69. package/dist/arc/episodes.js +118 -0
  70. package/dist/arc/evolution.js +490 -0
  71. package/dist/arc/flight-recorder.js +1034 -0
  72. package/dist/arc/intentions.js +134 -0
  73. package/dist/arc/json-store.js +117 -0
  74. package/dist/arc/obligations.js +386 -0
  75. package/dist/arc/packets.js +336 -0
  76. package/dist/arc/presence.js +185 -0
  77. package/dist/arc/task-lifecycle.js +57 -0
  78. package/dist/commerce/store.js +755 -0
  79. package/dist/commerce/types.js +3 -0
  80. package/dist/heart/active-work.js +798 -40
  81. package/dist/heart/agent-entry.js +252 -3
  82. package/dist/heart/approval-files.js +113 -0
  83. package/dist/heart/approval-store.js +960 -0
  84. package/dist/heart/attachments/image-normalize.js +194 -0
  85. package/dist/heart/attachments/materialize.js +97 -0
  86. package/dist/heart/attachments/originals.js +88 -0
  87. package/dist/heart/attachments/render.js +29 -0
  88. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  89. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  90. package/dist/heart/attachments/sources/index.js +18 -0
  91. package/dist/heart/attachments/sources/telegram.js +71 -0
  92. package/dist/heart/attachments/store.js +132 -0
  93. package/dist/heart/attachments/types.js +93 -0
  94. package/dist/heart/auth/auth-flow.js +495 -0
  95. package/dist/heart/autonomy-budget.js +478 -0
  96. package/dist/heart/awaiting/await-alert.js +148 -0
  97. package/dist/heart/awaiting/await-expiry.js +143 -0
  98. package/dist/heart/awaiting/await-loader.js +91 -0
  99. package/dist/heart/awaiting/await-parser.js +149 -0
  100. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  101. package/dist/heart/awaiting/await-scheduler.js +382 -0
  102. package/dist/heart/background-operations.js +281 -0
  103. package/dist/heart/bridges/manager.js +137 -17
  104. package/dist/heart/bridges/store.js +14 -2
  105. package/dist/heart/bundle-state.js +168 -0
  106. package/dist/heart/commitments.js +44 -18
  107. package/dist/heart/config-registry.js +331 -0
  108. package/dist/heart/config.js +174 -131
  109. package/dist/heart/context-loss-gauntlet.js +387 -0
  110. package/dist/heart/context-loss-sentinel.js +1157 -0
  111. package/dist/heart/core.js +2169 -581
  112. package/dist/heart/cross-chat-delivery.js +9 -22
  113. package/dist/heart/daemon/agent-config-check.js +451 -0
  114. package/dist/heart/daemon/agent-discovery.js +185 -3
  115. package/dist/heart/daemon/agent-service.js +542 -0
  116. package/dist/heart/daemon/agentic-repair.js +547 -0
  117. package/dist/heart/daemon/await-private-wake.js +59 -0
  118. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  119. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  120. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  121. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  122. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  123. package/dist/heart/daemon/cadence.js +180 -0
  124. package/dist/heart/daemon/cli-defaults.js +854 -0
  125. package/dist/heart/daemon/cli-desk.js +322 -0
  126. package/dist/heart/daemon/cli-exec.js +8822 -0
  127. package/dist/heart/daemon/cli-help.js +716 -0
  128. package/dist/heart/daemon/cli-parse.js +2771 -0
  129. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  130. package/dist/heart/daemon/cli-render.js +777 -0
  131. package/dist/heart/daemon/cli-types.js +8 -0
  132. package/dist/heart/daemon/connect-bay.js +323 -0
  133. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  134. package/dist/heart/daemon/container-healthcheck.js +112 -0
  135. package/dist/heart/daemon/container-runtime.js +97 -0
  136. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  137. package/dist/heart/daemon/container-spec-auditor.js +229 -0
  138. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  139. package/dist/heart/daemon/daemon-cli.js +29 -2349
  140. package/dist/heart/daemon/daemon-entry.js +930 -11
  141. package/dist/heart/daemon/daemon-health.js +186 -0
  142. package/dist/heart/daemon/daemon-rollup.js +57 -0
  143. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  144. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  145. package/dist/heart/daemon/daemon.js +2084 -105
  146. package/dist/heart/daemon/dns-workflow.js +394 -0
  147. package/dist/heart/daemon/doctor-types.js +8 -0
  148. package/dist/heart/daemon/doctor.js +1755 -0
  149. package/dist/heart/daemon/freshness.js +345 -0
  150. package/dist/heart/daemon/habit-private-wake.js +61 -0
  151. package/dist/heart/daemon/health-monitor.js +142 -11
  152. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  153. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  154. package/dist/heart/daemon/http-health-probe.js +80 -0
  155. package/dist/heart/daemon/human-command-screens.js +234 -0
  156. package/dist/heart/daemon/human-readiness.js +114 -0
  157. package/dist/heart/daemon/inner-status.js +78 -0
  158. package/dist/heart/daemon/interactive-repair.js +394 -0
  159. package/dist/heart/daemon/launchd.js +37 -8
  160. package/dist/heart/daemon/log-tailer.js +79 -10
  161. package/dist/heart/daemon/logs-prune.js +132 -0
  162. package/dist/heart/daemon/mcp-canary.js +524 -0
  163. package/dist/heart/daemon/message-router.js +65 -5
  164. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  165. package/dist/heart/daemon/os-cron-deps.js +135 -0
  166. package/dist/heart/daemon/os-cron.js +22 -14
  167. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  168. package/dist/heart/daemon/ouro-entry.js +3 -1
  169. package/dist/heart/daemon/plugin-cli.js +432 -0
  170. package/dist/heart/daemon/process-manager.js +733 -61
  171. package/dist/heart/daemon/provider-discovery.js +137 -0
  172. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  173. package/dist/heart/daemon/prunable-bundle.js +144 -0
  174. package/dist/heart/daemon/pulse.js +511 -0
  175. package/dist/heart/daemon/readiness-repair.js +365 -0
  176. package/dist/heart/daemon/run-hooks.js +2 -0
  177. package/dist/heart/daemon/runtime-logging.js +47 -14
  178. package/dist/heart/daemon/runtime-metadata.js +2 -30
  179. package/dist/heart/daemon/runtime-mode.js +13 -2
  180. package/dist/heart/daemon/safe-mode.js +161 -0
  181. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  182. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  183. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  184. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  185. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  186. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  187. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  188. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  189. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +819 -0
  190. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  191. package/dist/heart/daemon/sanctuary-bundle-migration.js +729 -0
  192. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  193. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  194. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  195. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  196. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  197. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  198. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  199. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  200. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  201. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  202. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  203. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +630 -0
  204. package/dist/heart/daemon/sense-manager.js +699 -48
  205. package/dist/heart/daemon/session-id-resolver.js +131 -0
  206. package/dist/heart/daemon/skill-management-installer.js +1 -1
  207. package/dist/heart/daemon/socket-client.js +180 -12
  208. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  209. package/dist/heart/daemon/startup-tui.js +339 -0
  210. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  211. package/dist/heart/daemon/task-scheduler.js +117 -39
  212. package/dist/heart/daemon/terminal-ui.js +499 -0
  213. package/dist/heart/daemon/thoughts.js +138 -54
  214. package/dist/heart/daemon/up-progress.js +366 -0
  215. package/dist/heart/daemon/vault-items.js +56 -0
  216. package/dist/heart/delegation.js +1 -4
  217. package/dist/heart/external-events/router.js +1430 -0
  218. package/dist/heart/frontend-approval-runtime.js +506 -0
  219. package/dist/heart/frontend-journal.js +215 -0
  220. package/dist/heart/frontend-session-service.js +237 -0
  221. package/dist/heart/frontend-socket-client.js +164 -0
  222. package/dist/heart/frontend-socket.js +400 -0
  223. package/dist/heart/habits/habit-cancel.js +810 -0
  224. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  225. package/dist/heart/habits/habit-migration.js +194 -0
  226. package/dist/heart/habits/habit-parser.js +278 -0
  227. package/dist/heart/habits/habit-runtime-state.js +93 -0
  228. package/dist/heart/habits/habit-scheduler.js +653 -0
  229. package/dist/heart/habits/habit-session-summary.js +318 -0
  230. package/dist/heart/habits/habit-session.js +636 -0
  231. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  232. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  233. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  234. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  235. package/dist/heart/identity.js +196 -59
  236. package/dist/heart/kept-notes.js +289 -0
  237. package/dist/heart/kicks.js +1 -1
  238. package/dist/heart/machine-identity.js +161 -0
  239. package/dist/heart/mail-import-discovery.js +356 -0
  240. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  241. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  242. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  243. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  244. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  245. package/dist/heart/mailbox/mailbox-http.js +99 -0
  246. package/dist/heart/mailbox/mailbox-read.js +39 -0
  247. package/dist/heart/mailbox/mailbox-types.js +27 -0
  248. package/dist/heart/mailbox/mailbox-view.js +197 -0
  249. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  250. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  251. package/dist/heart/mailbox/readers/mail.js +375 -0
  252. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  253. package/dist/heart/mailbox/readers/sessions.js +231 -0
  254. package/dist/heart/mailbox/readers/shared.js +111 -0
  255. package/dist/heart/mcp/mcp-server.js +696 -0
  256. package/dist/heart/migrate-config.js +100 -0
  257. package/dist/heart/model-capabilities.js +11 -0
  258. package/dist/heart/orientation-frame.js +345 -0
  259. package/dist/heart/platform.js +81 -0
  260. package/dist/heart/primitives.js +1 -1
  261. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  262. package/dist/heart/private-runtime/index.js +18 -0
  263. package/dist/heart/private-runtime/ledger.js +221 -0
  264. package/dist/heart/private-runtime/policy.js +252 -0
  265. package/dist/heart/private-runtime/types.js +2 -0
  266. package/dist/heart/progress-story.js +1 -1
  267. package/dist/heart/provider-attempt.js +137 -0
  268. package/dist/heart/provider-binding-resolver.js +273 -0
  269. package/dist/heart/provider-credentials.js +449 -0
  270. package/dist/heart/provider-failover.js +311 -0
  271. package/dist/heart/provider-models.js +96 -0
  272. package/dist/heart/provider-ping.js +265 -0
  273. package/dist/heart/provider-readiness-cache.js +119 -0
  274. package/dist/heart/provider-visibility.js +188 -0
  275. package/dist/heart/providers/anthropic-token.js +131 -0
  276. package/dist/heart/providers/anthropic.js +173 -60
  277. package/dist/heart/providers/azure.js +23 -11
  278. package/dist/heart/providers/error-classification.js +127 -0
  279. package/dist/heart/providers/github-copilot.js +34 -38
  280. package/dist/heart/providers/minimax-vlm.js +189 -0
  281. package/dist/heart/providers/minimax.js +26 -8
  282. package/dist/heart/providers/openai-codex-token.js +349 -0
  283. package/dist/heart/providers/openai-codex.js +55 -40
  284. package/dist/heart/providers/openai-compatible.js +177 -0
  285. package/dist/heart/run-ledger.js +247 -0
  286. package/dist/heart/runtime-capability-check.js +170 -0
  287. package/dist/heart/runtime-credentials.js +607 -0
  288. package/dist/heart/runtime-cwd.js +87 -0
  289. package/dist/heart/sense-truth.js +22 -4
  290. package/dist/heart/session-activity.js +92 -24
  291. package/dist/heart/session-events.js +1504 -0
  292. package/dist/heart/session-playback-cli-main.js +5 -0
  293. package/dist/heart/session-playback-cli.js +36 -0
  294. package/dist/heart/session-playback.js +231 -0
  295. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  296. package/dist/heart/session-redaction-repair.js +552 -0
  297. package/dist/heart/session-stats-cli-main.js +5 -0
  298. package/dist/heart/session-stats.js +183 -0
  299. package/dist/heart/session-transcript.js +133 -0
  300. package/dist/heart/start-of-turn-packet.js +372 -0
  301. package/dist/heart/steward-policy.js +618 -0
  302. package/dist/heart/streaming.js +604 -207
  303. package/dist/heart/structured-output.js +196 -0
  304. package/dist/heart/sync-classification.js +176 -0
  305. package/dist/heart/sync.js +449 -0
  306. package/dist/heart/target-resolution.js +11 -7
  307. package/dist/heart/tempo.js +93 -0
  308. package/dist/heart/temporal-view.js +41 -0
  309. package/dist/heart/timeouts.js +101 -0
  310. package/dist/heart/tool-activity-callbacks.js +59 -0
  311. package/dist/heart/tool-approval.js +382 -0
  312. package/dist/heart/tool-description.js +155 -0
  313. package/dist/heart/tool-friction.js +55 -0
  314. package/dist/heart/tool-loop.js +200 -0
  315. package/dist/heart/turn-context.js +482 -0
  316. package/dist/heart/turn-execution-lease.js +30 -0
  317. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  318. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  319. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  320. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  321. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  322. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  323. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  324. package/dist/heart/versioning/update-hooks.js +154 -0
  325. package/dist/heart/versioning/version-intent.js +114 -0
  326. package/dist/heart/work-card.js +380 -0
  327. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  328. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  329. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  330. package/dist/mailbox-ui/index.html +16 -0
  331. package/dist/mailroom/attention.js +167 -0
  332. package/dist/mailroom/autonomy.js +209 -0
  333. package/dist/mailroom/blob-store.js +889 -0
  334. package/dist/mailroom/body-cache.js +61 -0
  335. package/dist/mailroom/cache-sync-cli.js +58 -0
  336. package/dist/mailroom/core.js +803 -0
  337. package/dist/mailroom/entry.js +160 -0
  338. package/dist/mailroom/file-store.js +568 -0
  339. package/dist/mailroom/hosted-cache-sync.js +384 -0
  340. package/dist/mailroom/mbox-import.js +393 -0
  341. package/dist/mailroom/migration.js +164 -0
  342. package/dist/mailroom/outbound.js +380 -0
  343. package/dist/mailroom/policy.js +263 -0
  344. package/dist/mailroom/reader.js +292 -0
  345. package/dist/mailroom/search-cache.js +513 -0
  346. package/dist/mailroom/search-relevance.js +319 -0
  347. package/dist/mailroom/smtp-ingress.js +176 -0
  348. package/dist/mailroom/source-state.js +176 -0
  349. package/dist/mailroom/thread.js +109 -0
  350. package/dist/mailroom/travel-extract.js +89 -0
  351. package/dist/mind/bundle-manifest.js +24 -2
  352. package/dist/mind/context.js +309 -111
  353. package/dist/mind/desk-section.js +362 -0
  354. package/dist/mind/diary-integrity.js +60 -0
  355. package/dist/mind/{memory.js → diary.js} +68 -77
  356. package/dist/mind/embedding-provider.js +60 -0
  357. package/dist/mind/file-state.js +179 -0
  358. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  359. package/dist/mind/obligation-steering.js +199 -3
  360. package/dist/mind/pending.js +36 -10
  361. package/dist/mind/prompt-budget.js +479 -0
  362. package/dist/mind/prompt-refresh.js +3 -2
  363. package/dist/mind/prompt.js +1050 -189
  364. package/dist/mind/provenance-trust.js +26 -0
  365. package/dist/mind/record-paths.js +312 -0
  366. package/dist/mind/scrutiny.js +173 -0
  367. package/dist/mind/session-transaction.js +564 -0
  368. package/dist/nerves/cli-logging.js +7 -1
  369. package/dist/nerves/coverage/audit-rules.js +15 -6
  370. package/dist/nerves/coverage/audit.js +28 -2
  371. package/dist/nerves/coverage/cli.js +1 -1
  372. package/dist/nerves/coverage/contract.js +5 -5
  373. package/dist/nerves/coverage/file-completeness.js +139 -5
  374. package/dist/nerves/coverage/run-artifacts.js +55 -35
  375. package/dist/nerves/coverage/source-scanner.js +4 -4
  376. package/dist/nerves/event-buffer.js +111 -0
  377. package/dist/nerves/index.js +293 -9
  378. package/dist/nerves/observation.js +20 -0
  379. package/dist/nerves/redact.js +79 -0
  380. package/dist/nerves/review/cli-main.js +5 -0
  381. package/dist/nerves/review/cli.js +156 -0
  382. package/dist/nerves/review/core.js +159 -0
  383. package/dist/nerves/runtime.js +17 -1
  384. package/dist/repertoire/ado-client.js +15 -56
  385. package/dist/repertoire/ado-semantic.js +16 -10
  386. package/dist/repertoire/api-client.js +97 -0
  387. package/dist/repertoire/bitwarden-store.js +1045 -0
  388. package/dist/repertoire/bundle-templates.js +71 -0
  389. package/dist/repertoire/bw-installer.js +180 -0
  390. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  391. package/dist/repertoire/coding/context-pack.js +331 -0
  392. package/dist/repertoire/coding/feedback.js +174 -32
  393. package/dist/repertoire/coding/index.js +15 -3
  394. package/dist/repertoire/coding/manager.js +159 -10
  395. package/dist/repertoire/coding/spawner.js +58 -11
  396. package/dist/repertoire/coding/tools.js +221 -15
  397. package/dist/repertoire/coding/workbench-client.js +272 -0
  398. package/dist/repertoire/coding/workbench-manager.js +346 -0
  399. package/dist/repertoire/commerce-errors.js +109 -0
  400. package/dist/repertoire/commerce-self-test.js +156 -0
  401. package/dist/repertoire/credential-access.js +178 -0
  402. package/dist/repertoire/desk/classifier.js +362 -0
  403. package/dist/repertoire/duffel-client.js +185 -0
  404. package/dist/repertoire/github-client.js +14 -55
  405. package/dist/repertoire/graph-client.js +11 -52
  406. package/dist/repertoire/guardrails.js +811 -18
  407. package/dist/repertoire/mcp-client.js +44 -3
  408. package/dist/repertoire/mcp-manager.js +427 -139
  409. package/dist/repertoire/mcp-tools.js +124 -0
  410. package/dist/repertoire/plugin-mcp.js +175 -0
  411. package/dist/repertoire/plugins.js +253 -0
  412. package/dist/repertoire/relationship-authorization.js +322 -0
  413. package/dist/repertoire/shell-sessions.js +134 -0
  414. package/dist/repertoire/skills.js +48 -4
  415. package/dist/repertoire/stripe-client.js +131 -0
  416. package/dist/repertoire/tool-arguments.js +170 -0
  417. package/dist/repertoire/tool-results.js +29 -0
  418. package/dist/repertoire/tools-a2a.js +699 -0
  419. package/dist/repertoire/tools-attachments.js +322 -0
  420. package/dist/repertoire/tools-awaiting.js +575 -0
  421. package/dist/repertoire/tools-base.js +77 -1138
  422. package/dist/repertoire/tools-bluebubbles.js +2 -0
  423. package/dist/repertoire/tools-bridge.js +144 -0
  424. package/dist/repertoire/tools-bundle.js +993 -0
  425. package/dist/repertoire/tools-commerce.js +253 -0
  426. package/dist/repertoire/tools-config.js +186 -0
  427. package/dist/repertoire/tools-continuity.js +575 -0
  428. package/dist/repertoire/tools-credential.js +383 -0
  429. package/dist/repertoire/tools-evolution.js +527 -0
  430. package/dist/repertoire/tools-files.js +344 -0
  431. package/dist/repertoire/tools-flight.js +290 -0
  432. package/dist/repertoire/tools-flow.js +119 -0
  433. package/dist/repertoire/tools-github.js +3 -8
  434. package/dist/repertoire/tools-habits.js +103 -0
  435. package/dist/repertoire/tools-mail.js +1828 -0
  436. package/dist/repertoire/tools-notes.js +485 -0
  437. package/dist/repertoire/tools-obligations.js +182 -0
  438. package/dist/repertoire/tools-orientation.js +31 -0
  439. package/dist/repertoire/tools-record.js +482 -0
  440. package/dist/repertoire/tools-rsvp.js +139 -0
  441. package/dist/repertoire/tools-runtime.js +150 -0
  442. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  443. package/dist/repertoire/tools-session.js +1133 -0
  444. package/dist/repertoire/tools-shell.js +149 -0
  445. package/dist/repertoire/tools-steward-policy.js +119 -0
  446. package/dist/repertoire/tools-stripe.js +224 -0
  447. package/dist/repertoire/tools-surface.js +369 -0
  448. package/dist/repertoire/tools-teams.js +12 -39
  449. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  450. package/dist/repertoire/tools-travel.js +125 -0
  451. package/dist/repertoire/tools-trip.js +982 -0
  452. package/dist/repertoire/tools-unraid.js +531 -0
  453. package/dist/repertoire/tools-user-profile.js +146 -0
  454. package/dist/repertoire/tools-vault.js +40 -0
  455. package/dist/repertoire/tools-voice.js +145 -0
  456. package/dist/repertoire/tools.js +494 -148
  457. package/dist/repertoire/travel-api-client.js +360 -0
  458. package/dist/repertoire/unraid-client.js +155 -0
  459. package/dist/repertoire/unraid-restart.js +339 -0
  460. package/dist/repertoire/user-profile.js +131 -0
  461. package/dist/repertoire/vault-setup.js +246 -0
  462. package/dist/repertoire/vault-unlock.js +628 -0
  463. package/dist/rsvp/aisleplanner-client.js +354 -0
  464. package/dist/rsvp/cli.js +926 -0
  465. package/dist/rsvp/config.js +327 -0
  466. package/dist/rsvp/cutover.js +433 -0
  467. package/dist/rsvp/diagnostics.js +232 -0
  468. package/dist/rsvp/diff-renderer.js +176 -0
  469. package/dist/rsvp/habit-policy.js +110 -0
  470. package/dist/rsvp/habit-stage.js +123 -0
  471. package/dist/rsvp/incident-bundle.js +97 -0
  472. package/dist/rsvp/migration.js +204 -0
  473. package/dist/rsvp/native-habit-runner.js +630 -0
  474. package/dist/rsvp/outbound-state.js +628 -0
  475. package/dist/rsvp/query.js +118 -0
  476. package/dist/rsvp/replay.js +233 -0
  477. package/dist/rsvp/snapshot.js +232 -0
  478. package/dist/rsvp/spend-ledger.js +175 -0
  479. package/dist/scripts/claude-code-hook.js +41 -0
  480. package/dist/scripts/claude-code-stop-hook.js +47 -0
  481. package/dist/senses/a2a-entry.js +115 -0
  482. package/dist/senses/acp-server.js +386 -0
  483. package/dist/senses/attention-queue.js +186 -0
  484. package/dist/senses/await-turn-message.js +58 -0
  485. package/dist/senses/bluebubbles/active-turns.js +216 -0
  486. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  487. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  488. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  489. package/dist/senses/bluebubbles/context-packet.js +207 -0
  490. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  491. package/dist/senses/bluebubbles/entry.js +90 -0
  492. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  493. package/dist/senses/bluebubbles/index.js +3841 -0
  494. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  495. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  496. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  497. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  498. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  499. package/dist/senses/bluebubbles/processed-log.js +133 -0
  500. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  501. package/dist/senses/bluebubbles/replay.js +284 -0
  502. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  503. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  504. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  505. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  506. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  507. package/dist/senses/cli/bracketed-paste.js +82 -0
  508. package/dist/senses/cli/image-paste.js +287 -0
  509. package/dist/senses/cli/image-ref-navigation.js +75 -0
  510. package/dist/senses/cli/ink-app.js +156 -0
  511. package/dist/senses/cli/inline-diff.js +64 -0
  512. package/dist/senses/cli/input-keys.js +174 -0
  513. package/dist/senses/cli/kill-ring.js +86 -0
  514. package/dist/senses/cli/message-list.js +51 -0
  515. package/dist/senses/cli/ouro-tui.js +607 -0
  516. package/dist/senses/cli/spinner-imperative.js +135 -0
  517. package/dist/senses/cli/spinner.js +101 -0
  518. package/dist/senses/cli/status-line.js +60 -0
  519. package/dist/senses/cli/streaming-markdown.js +526 -0
  520. package/dist/senses/cli/tool-display.js +85 -0
  521. package/dist/senses/cli/tool-render.js +85 -0
  522. package/dist/senses/cli/tui-store.js +241 -0
  523. package/dist/senses/cli/virtual-list.js +35 -0
  524. package/dist/senses/cli-entry.js +60 -8
  525. package/dist/senses/cli.js +604 -320
  526. package/dist/senses/commands.js +66 -3
  527. package/dist/senses/context-packet-ledger.js +371 -0
  528. package/dist/senses/context-packets.js +154 -0
  529. package/dist/senses/habit-lifecycle-guard.js +24 -0
  530. package/dist/senses/habit-turn-message.js +160 -0
  531. package/dist/senses/ingress-evidence.js +2 -0
  532. package/dist/senses/mail-entry.js +66 -0
  533. package/dist/senses/mail.js +524 -0
  534. package/dist/senses/pipeline.js +1115 -204
  535. package/dist/senses/private-runtime-worker.js +859 -0
  536. package/dist/senses/private-runtime.js +1517 -0
  537. package/dist/senses/proactive-content-guard.js +51 -0
  538. package/dist/senses/root-host-approval-port.js +345 -0
  539. package/dist/senses/root-host-approval-runtime.js +393 -0
  540. package/dist/senses/sanctuary-authority-resident.js +102 -0
  541. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  542. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  543. package/dist/senses/sanctuary-grounding.js +118 -0
  544. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  545. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  546. package/dist/senses/sanctuary-health-runner.js +100 -0
  547. package/dist/senses/sanctuary-health.js +408 -0
  548. package/dist/senses/sanctuary-install-state-contract.js +126 -0
  549. package/dist/senses/sanctuary-interactive-control.js +410 -0
  550. package/dist/senses/sanctuary-media-catalog-contract.js +297 -0
  551. package/dist/senses/sanctuary-media-optimization.js +514 -0
  552. package/dist/senses/sanctuary-runtime.js +340 -0
  553. package/dist/senses/sanctuary-sab.js +85 -0
  554. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  555. package/dist/senses/shared-turn.js +772 -0
  556. package/dist/senses/surface-tool.js +109 -0
  557. package/dist/senses/teams-entry.js +60 -8
  558. package/dist/senses/teams.js +519 -218
  559. package/dist/senses/telegram-admission.js +718 -0
  560. package/dist/senses/telegram-approval-runtime.js +793 -0
  561. package/dist/senses/telegram-attachments.js +186 -0
  562. package/dist/senses/telegram-audit-ledger.js +220 -0
  563. package/dist/senses/telegram-authority-transport.js +231 -0
  564. package/dist/senses/telegram-client.js +1749 -0
  565. package/dist/senses/telegram-effect-adapter.js +896 -0
  566. package/dist/senses/telegram-entry.js +83 -0
  567. package/dist/senses/telegram.js +2324 -0
  568. package/dist/senses/trust-gate.js +104 -9
  569. package/dist/senses/voice/audio-playback.js +237 -0
  570. package/dist/senses/voice/audio-routing.js +119 -0
  571. package/dist/senses/voice/elevenlabs.js +202 -0
  572. package/dist/senses/voice/floor-control.js +431 -0
  573. package/dist/senses/voice/floor-controller.js +115 -0
  574. package/dist/senses/voice/golden-path.js +116 -0
  575. package/dist/senses/voice/index.js +29 -0
  576. package/dist/senses/voice/meeting.js +113 -0
  577. package/dist/senses/voice/outbound.js +190 -0
  578. package/dist/senses/voice/phone.js +33 -0
  579. package/dist/senses/voice/playback.js +139 -0
  580. package/dist/senses/voice/realtime-eval.js +496 -0
  581. package/dist/senses/voice/realtime-trace.js +531 -0
  582. package/dist/senses/voice/transcript.js +70 -0
  583. package/dist/senses/voice/turn.js +191 -0
  584. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  585. package/dist/senses/voice/twilio-phone.js +5031 -0
  586. package/dist/senses/voice/types.js +2 -0
  587. package/dist/senses/voice/whisper.js +161 -0
  588. package/dist/senses/voice-entry.js +81 -0
  589. package/dist/senses/voice-realtime-eval-command.js +99 -0
  590. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  591. package/dist/senses/voice-twilio-entry.js +87 -0
  592. package/dist/trips/core.js +138 -0
  593. package/dist/trips/store.js +265 -0
  594. package/dist/util/frontmatter.js +69 -0
  595. package/npm-shrinkwrap.json +8138 -0
  596. package/package.json +72 -13
  597. package/skills/agent-commerce.md +113 -0
  598. package/skills/browser-navigation.md +117 -0
  599. package/skills/commerce-setup-guide.md +116 -0
  600. package/skills/commerce-setup.md +84 -0
  601. package/skills/configure-dev-tools.md +99 -0
  602. package/skills/travel-planning.md +138 -0
  603. package/dist/heart/daemon/auth-flow.js +0 -430
  604. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  605. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  606. package/dist/heart/daemon/update-hooks.js +0 -138
  607. package/dist/heart/obligations.js +0 -191
  608. package/dist/heart/safe-workspace.js +0 -228
  609. package/dist/heart/session-recall.js +0 -116
  610. package/dist/mind/friends/channel.js +0 -84
  611. package/dist/mind/friends/group-context.js +0 -144
  612. package/dist/mind/friends/resolver.js +0 -84
  613. package/dist/mind/friends/store-file.js +0 -190
  614. package/dist/mind/friends/store.js +0 -4
  615. package/dist/mind/friends/tokens.js +0 -26
  616. package/dist/mind/friends/trust-explanation.js +0 -74
  617. package/dist/mind/friends/types.js +0 -29
  618. package/dist/repertoire/tasks/board.js +0 -134
  619. package/dist/repertoire/tasks/index.js +0 -224
  620. package/dist/repertoire/tasks/lifecycle.js +0 -80
  621. package/dist/repertoire/tasks/middleware.js +0 -65
  622. package/dist/repertoire/tasks/parser.js +0 -173
  623. package/dist/repertoire/tasks/scanner.js +0 -132
  624. package/dist/repertoire/tasks/transitions.js +0 -144
  625. package/dist/senses/bluebubbles-entry.js +0 -13
  626. package/dist/senses/bluebubbles.js +0 -1181
  627. package/dist/senses/debug-activity.js +0 -154
  628. package/dist/senses/inner-dialog-worker.js +0 -90
  629. package/dist/senses/inner-dialog.js +0 -525
  630. package/subagents/README.md +0 -7
  631. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  632. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  633. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  634. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  635. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  636. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  637. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  638. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  639. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  640. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  641. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  642. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  643. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  644. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  645. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  646. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  647. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,2771 @@
1
+ "use strict";
2
+ /**
3
+ * CLI argument parsing — converts argv into OuroCliCommand objects.
4
+ *
5
+ * Pure functions: no side effects, no daemon communication.
6
+ * Each command group has its own parser; parseOuroCommand dispatches.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.extractAgentFlag = extractAgentFlag;
10
+ exports.extractFacingFlag = extractFacingFlag;
11
+ exports.facingToProviderLane = facingToProviderLane;
12
+ exports.isAgentProvider = isAgentProvider;
13
+ exports.usage = usage;
14
+ exports.inferAgentNameFromRemote = inferAgentNameFromRemote;
15
+ exports.parseMcpServeCommand = parseMcpServeCommand;
16
+ exports.parseAcpServeCommand = parseAcpServeCommand;
17
+ exports.parseOuroCommand = parseOuroCommand;
18
+ const friends_1 = require("@ouro.bot/friends");
19
+ const cli_help_1 = require("./cli-help");
20
+ const cli_desk_1 = require("./cli-desk");
21
+ const flight_recorder_1 = require("../../arc/flight-recorder");
22
+ const core_1 = require("../../nerves/review/core");
23
+ const prunable_bundle_1 = require("./prunable-bundle");
24
+ const vault_items_1 = require("./vault-items");
25
+ // ── Shared helpers ──
26
+ function extractAgentFlag(args) {
27
+ const idx = args.indexOf("--agent");
28
+ if (idx === -1 || idx + 1 >= args.length)
29
+ return { rest: args };
30
+ const agent = args[idx + 1];
31
+ const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
32
+ return { agent, rest };
33
+ }
34
+ function parseLogsCommand(args) {
35
+ if (args.length === 0)
36
+ return { kind: "daemon.logs" };
37
+ if (args[0] !== "prune")
38
+ throw new Error("Usage: ouro logs prune [--agent <name>]");
39
+ const tail = args.slice(1);
40
+ const agentFlagCount = tail.filter((token) => token === "--agent").length;
41
+ const { agent, rest } = extractAgentFlag(tail);
42
+ if (agentFlagCount > 1 ||
43
+ rest.length > 0 ||
44
+ (agentFlagCount === 1 && !agent) ||
45
+ (agent !== undefined && !(0, prunable_bundle_1.isSafePrunableAgentName)(agent))) {
46
+ throw new Error("Usage: ouro logs prune [--agent <name>]");
47
+ }
48
+ return { kind: "daemon.logs.prune", ...(agent ? { agent } : {}) };
49
+ }
50
+ function extractFacingFlag(args) {
51
+ const idx = args.indexOf("--facing");
52
+ if (idx === -1 || idx + 1 >= args.length)
53
+ return { rest: args };
54
+ const value = args[idx + 1];
55
+ if (value !== "human" && value !== "agent") {
56
+ throw new Error(`--facing must be 'human' or 'agent'`);
57
+ }
58
+ const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
59
+ return { facing: value, rest };
60
+ }
61
+ function facingToProviderLane(facing) {
62
+ return facing === "human" ? "outward" : "inner";
63
+ }
64
+ function isProviderLane(value) {
65
+ return value === "outward" || value === "inner";
66
+ }
67
+ function helpCommandName(args) {
68
+ const positional = [];
69
+ for (const arg of args) {
70
+ if (arg === "--help" || arg === "-h")
71
+ break;
72
+ if (arg.startsWith("-"))
73
+ break;
74
+ positional.push(arg);
75
+ }
76
+ return positional.length > 0 ? positional.join(" ") : undefined;
77
+ }
78
+ function extractLaneFlag(args) {
79
+ const idx = args.indexOf("--lane");
80
+ if (idx === -1 || idx + 1 >= args.length)
81
+ return { rest: args };
82
+ const value = args[idx + 1];
83
+ if (!isProviderLane(value)) {
84
+ throw new Error("--lane must be 'outward' or 'inner'");
85
+ }
86
+ const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
87
+ return { lane: value, rest };
88
+ }
89
+ function isAgentProvider(value) {
90
+ return value === "azure" || value === "anthropic" || value === "minimax" || value === "openai-codex" || value === "github-copilot" || value === "openai-compatible" || value === "openai-compatible-gemini";
91
+ }
92
+ function usage() {
93
+ return [
94
+ "Usage:",
95
+ " ouro [up] [--no-repair]",
96
+ " ouro dev [--repo-path <path>] [--clone [--clone-path <path>]]",
97
+ " ouro stop|down|status|logs|hatch",
98
+ " ouro status --agent <name>",
99
+ " ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]",
100
+ " ouro check [--agent <name>] --lane outward|inner",
101
+ " ouro repair [--agent <name>]",
102
+ " ouro provider refresh [--agent <name>]",
103
+ " ouro mailbox [--json]",
104
+ " ouro -v|--version",
105
+ " ouro auth [--agent <name>] [--provider <provider>]",
106
+ " ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
107
+ " ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail|voice|a2a|telegram|workbench] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
108
+ " ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]",
109
+ " ouro mail backfill-indexes [--agent <name>] [--foreground]",
110
+ " ouro auth verify [--agent <name>] [--provider <provider>]",
111
+ " ouro vault create [--agent <name>] --email <email> [--server <url>] [--store <store>]",
112
+ " ouro vault replace [--agent <name>] [--email <email>] [--server <url>] [--store <store>]",
113
+ " ouro vault recover [--agent <name>] --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
114
+ " ouro vault unlock [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
115
+ " ouro vault status [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
116
+ " ouro vault config set [--agent <name>] --key <path> [--value <value>] [--scope agent|machine]",
117
+ " ouro vault config status [--agent <name>] [--scope agent|machine|all]",
118
+ " ouro vault item set [--agent <name>] --item <path> --secret-field <name> [--public-field <key=value>] [--note <text>]",
119
+ " ouro vault item status [--agent <name>] --item <path>",
120
+ " ouro vault item list [--agent <name>] [--prefix <path-prefix>]",
121
+ " ouro vault ops porkbun set [--agent <name>] --account <account>",
122
+ " ouro vault ops porkbun status [--agent <name>] [--account <account>]",
123
+ " ouro dns backup|plan|apply|verify|rollback|certificate [--agent <name>] --binding <path> [--output <path>] [--backup <path>] [--yes]",
124
+ " ouro chat <agent>",
125
+ " ouro msg --to <agent> [--session <id>] [--task <ref>] <message>",
126
+ " ouro event submit --agent <agent> --source <source> --type <event-type> --id <provider-id> [--summary <text>] [--evidence <path>] [--payload <path>] [--priority high|normal|low] [--no-wake]",
127
+ " ouro poke <agent> --task <task-id>",
128
+ " ouro poke <agent> --habit <name> [--trigger poke|launchd|cron|overdue|manual]",
129
+ " ouro habit list [--agent <name>]",
130
+ " ouro habit create [--agent <name>] <name> [--cadence <interval>]",
131
+ " ouro habit runs [--agent <name>] [--limit <n>]",
132
+ " ouro habit inspect [--agent <name>] <runId>",
133
+ " ouro habit summary [--agent <name>] (--run-id <id>|--habit <name>|--operation-id <id>) [--which latest|previous|latest-success|latest-failure] [--json]",
134
+ " ouro habit cancel --agent <name> --habit <name> --evidence <bridge-id>",
135
+ " ouro habit probe --agent <name> --habit <name> --no-send [--json]",
136
+ " ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
137
+ " ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
138
+ " ouro bluebubbles context-smoke [--agent <name>] --message-guid <guid> [--persist] [--json]",
139
+ " ouro bluebubbles host <install|status|repair|remove|collect> [--username <name> --uid <uid> --home <path>] [--request-id <id>] [--json]",
140
+ " ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...",
141
+ " ouro friend list [--agent <name>]",
142
+ " ouro friend show <id> [--agent <name>]",
143
+ " ouro friend create --name <name> [--trust <level>] [--agent <name>]",
144
+ " ouro friend update <id> --trust <level> [--agent <name>]",
145
+ " ouro thoughts [--last <n>] [--json] [--follow] [--agent <name>]",
146
+ " ouro private decisions [--agent <name>] [--limit <n>] [--json]",
147
+ " ouro private status [--agent <name>] [--json]",
148
+ " ouro work card|gauntlet|sentinel [refresh] [--agent <name>] [--format text|json|--json]",
149
+ " ouro nerves-review [--agent <name>] [--process <name>] [--component <substr>] [--event <substr>] [--level <level>] [--since <duration>] [--limit <n>] [--json]",
150
+ " ouro friend link <agent> --friend <id> --provider <p> --external-id <eid>",
151
+ " ouro friend unlink <agent> --friend <id> --provider <p> --external-id <eid>",
152
+ " ouro a2a card [--agent <name>] [--base-url <url>] [--json]",
153
+ " ouro a2a onboard [--agent <name>] --card-url <url> [--trust <level>] [--name <name>]",
154
+ " ouro a2a serve [--agent <name>] [--host <host>] [--port <port>] [--base-url <url>] [--path <path>]",
155
+ " ouro whoami [--agent <name>]",
156
+ " ouro session list [--agent <name>]",
157
+ " ouro mcp list",
158
+ " ouro mcp call <server> <tool> [--args '{...}']",
159
+ " ouro mcp doctor --agent <name> [--json]",
160
+ " ouro rollback [<version>]",
161
+ " ouro versions",
162
+ " ouro clone <remote> [--agent <name>]",
163
+ " ouro doctor",
164
+ ].join("\n");
165
+ }
166
+ // ── Per-group parsers ──
167
+ function parseMessageCommand(args) {
168
+ let to;
169
+ let sessionId;
170
+ let taskRef;
171
+ const messageParts = [];
172
+ for (let i = 0; i < args.length; i += 1) {
173
+ const token = args[i];
174
+ if (token === "--to") {
175
+ to = args[i + 1];
176
+ i += 1;
177
+ continue;
178
+ }
179
+ if (token === "--session") {
180
+ sessionId = args[i + 1];
181
+ i += 1;
182
+ continue;
183
+ }
184
+ if (token === "--task") {
185
+ taskRef = args[i + 1];
186
+ i += 1;
187
+ continue;
188
+ }
189
+ messageParts.push(token);
190
+ }
191
+ const content = messageParts.join(" ").trim();
192
+ if (!to || !content)
193
+ throw new Error(`Usage\n${usage()}`);
194
+ return {
195
+ kind: "message.send",
196
+ from: "ouro-cli",
197
+ to,
198
+ content,
199
+ sessionId,
200
+ taskRef,
201
+ };
202
+ }
203
+ function parseEventCommand(args) {
204
+ const sub = args[0];
205
+ if (sub === "repair") {
206
+ if (args.length !== 3 || args[1] !== "--manifest" || !args[2])
207
+ throw new Error(`Usage\n${usage()}`);
208
+ return { kind: "external.event.repair", manifestPath: args[2] };
209
+ }
210
+ if (sub !== "submit")
211
+ throw new Error(`Usage\n${usage()}`);
212
+ let agent;
213
+ let source;
214
+ let eventType;
215
+ let eventId;
216
+ let summary;
217
+ const evidence = [];
218
+ let payloadPath;
219
+ let priority;
220
+ let sessionId;
221
+ let taskRef;
222
+ let wake = true;
223
+ for (let i = 1; i < args.length; i += 1) {
224
+ const token = args[i];
225
+ const value = args[i + 1];
226
+ if (token === "--agent" && value) {
227
+ agent = value;
228
+ i += 1;
229
+ continue;
230
+ }
231
+ if (token === "--source" && value) {
232
+ source = value;
233
+ i += 1;
234
+ continue;
235
+ }
236
+ if (token === "--type" && value) {
237
+ eventType = value;
238
+ i += 1;
239
+ continue;
240
+ }
241
+ if (token === "--id" && value) {
242
+ eventId = value;
243
+ i += 1;
244
+ continue;
245
+ }
246
+ if (token === "--summary" && value) {
247
+ summary = value;
248
+ i += 1;
249
+ continue;
250
+ }
251
+ if (token === "--evidence" && value) {
252
+ evidence.push(value);
253
+ i += 1;
254
+ continue;
255
+ }
256
+ if (token === "--payload" && value) {
257
+ payloadPath = value;
258
+ i += 1;
259
+ continue;
260
+ }
261
+ if (token === "--priority" && value) {
262
+ priority = value;
263
+ i += 1;
264
+ continue;
265
+ }
266
+ if (token === "--session" && value) {
267
+ sessionId = value;
268
+ i += 1;
269
+ continue;
270
+ }
271
+ if (token === "--task" && value) {
272
+ taskRef = value;
273
+ i += 1;
274
+ continue;
275
+ }
276
+ if (token === "--no-wake") {
277
+ wake = false;
278
+ continue;
279
+ }
280
+ throw new Error(`Usage\n${usage()}`);
281
+ }
282
+ if (!agent || !source || !eventType || !eventId)
283
+ throw new Error(`Usage\n${usage()}`);
284
+ if (priority && !["high", "normal", "low"].includes(priority))
285
+ throw new Error("--priority must be high, normal, or low");
286
+ return {
287
+ kind: "external.event.submit",
288
+ agent,
289
+ source,
290
+ eventType,
291
+ eventId,
292
+ ...(summary ? { summary } : {}),
293
+ ...(evidence.length > 0 ? { evidence } : {}),
294
+ ...(payloadPath ? { payloadPath } : {}),
295
+ ...(priority ? { priority } : {}),
296
+ ...(sessionId ? { sessionId } : {}),
297
+ ...(taskRef ? { taskRef } : {}),
298
+ wake,
299
+ };
300
+ }
301
+ function parsePokeCommand(args) {
302
+ const agent = args[0];
303
+ if (!agent)
304
+ throw new Error(`Usage\n${usage()}`);
305
+ let taskId;
306
+ let habitName;
307
+ let awaitName;
308
+ let trigger;
309
+ for (let i = 1; i < args.length; i += 1) {
310
+ if (args[i] === "--task") {
311
+ taskId = args[i + 1];
312
+ i += 1;
313
+ }
314
+ if (args[i] === "--habit") {
315
+ habitName = args[i + 1];
316
+ i += 1;
317
+ }
318
+ if (args[i] === "--await") {
319
+ awaitName = args[i + 1];
320
+ i += 1;
321
+ }
322
+ if (args[i] === "--trigger") {
323
+ const rawTrigger = args[i + 1];
324
+ if (!(0, flight_recorder_1.isHabitRunTrigger)(rawTrigger))
325
+ throw new Error("invalid habit trigger");
326
+ trigger = rawTrigger;
327
+ i += 1;
328
+ }
329
+ }
330
+ // Priority order: --await > --habit > --task
331
+ if (awaitName)
332
+ return { kind: "await.poke", agent, awaitName };
333
+ if (habitName)
334
+ return { kind: "habit.poke", agent, habitName, trigger: trigger ?? "poke" };
335
+ if (trigger)
336
+ throw new Error(`Usage\n${usage()}`);
337
+ if (!taskId)
338
+ throw new Error(`Usage\n${usage()}`);
339
+ return { kind: "task.poke", agent, taskId };
340
+ }
341
+ function parseHabitCommand(args) {
342
+ const { agent, rest } = extractAgentFlag(args);
343
+ const sub = rest[0];
344
+ if (sub === "probe") {
345
+ if (args.includes("--allow-send")) {
346
+ throw new Error("habit probe cannot allow send");
347
+ }
348
+ if (args.filter((value) => value === "--agent").length !== 1
349
+ || !agent
350
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(agent))
351
+ throw new Error("habit probe requires --agent <name>");
352
+ let habitName;
353
+ let json = false;
354
+ let sawNoSend = false;
355
+ const options = rest.slice(1);
356
+ for (let index = 0; index < options.length; index += 1) {
357
+ const option = options[index];
358
+ if (option === "--json") {
359
+ if (json)
360
+ throw new Error("habit probe received duplicate --json");
361
+ json = true;
362
+ continue;
363
+ }
364
+ if (option === "--no-send") {
365
+ if (sawNoSend)
366
+ throw new Error("habit probe received duplicate --no-send");
367
+ sawNoSend = true;
368
+ continue;
369
+ }
370
+ if (option === "--habit" && options[index + 1]) {
371
+ if (habitName !== undefined)
372
+ throw new Error("habit probe received duplicate --habit");
373
+ habitName = options[index + 1];
374
+ index += 1;
375
+ continue;
376
+ }
377
+ throw new Error("Usage: ouro habit probe --agent <name> --habit <name> --no-send [--json]");
378
+ }
379
+ if (!habitName)
380
+ throw new Error("habit probe requires --habit <name>");
381
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(habitName)) {
382
+ throw new Error("habit probe requires a valid --habit name");
383
+ }
384
+ return { kind: "habit.probe", agent, habitName, noSend: true, json };
385
+ }
386
+ if (sub === "cancel") {
387
+ if (args.filter((value) => value === "--agent").length !== 1
388
+ || !agent
389
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(agent)) {
390
+ throw new Error(`Usage\n${usage()}`);
391
+ }
392
+ let habitName;
393
+ let evidenceLocator;
394
+ const options = rest.slice(1);
395
+ for (let index = 0; index < options.length; index += 1) {
396
+ const option = options[index];
397
+ const value = options[index + 1];
398
+ if ((option !== "--habit" && option !== "--evidence") || value === undefined) {
399
+ throw new Error(`Usage\n${usage()}`);
400
+ }
401
+ if (option === "--habit") {
402
+ if (habitName !== undefined)
403
+ throw new Error(`Usage\n${usage()}`);
404
+ habitName = value;
405
+ }
406
+ else {
407
+ if (evidenceLocator !== undefined)
408
+ throw new Error(`Usage\n${usage()}`);
409
+ evidenceLocator = value;
410
+ }
411
+ index += 1;
412
+ }
413
+ if (!habitName || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(habitName)) {
414
+ throw new Error("habit cancellation requires a valid --habit name");
415
+ }
416
+ if (!evidenceLocator
417
+ || evidenceLocator.startsWith("capture:")
418
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(evidenceLocator))
419
+ throw new Error("habit cancellation requires an offline evidence bridge ID");
420
+ return { kind: "habit.cancel", agent, habitName, evidenceLocator };
421
+ }
422
+ if (sub === "list") {
423
+ return { kind: "habit.list", ...(agent ? { agent } : {}) };
424
+ }
425
+ if (sub === "create") {
426
+ const nameArgs = rest.slice(1);
427
+ let name;
428
+ let cadence;
429
+ const positional = [];
430
+ for (let i = 0; i < nameArgs.length; i++) {
431
+ if (nameArgs[i] === "--cadence" && nameArgs[i + 1]) {
432
+ cadence = nameArgs[++i];
433
+ continue;
434
+ }
435
+ /* v8 ignore start -- defensive: --agent already extracted by extractAgentFlag; guard prevents regression if parsing flow changes @preserve */
436
+ if (nameArgs[i] === "--agent" && nameArgs[i + 1]) {
437
+ i++; // skip --agent value (already extracted)
438
+ continue;
439
+ }
440
+ /* v8 ignore stop */
441
+ positional.push(nameArgs[i]);
442
+ }
443
+ name = positional[0];
444
+ if (!name)
445
+ throw new Error(`Usage\n${usage()}`);
446
+ return { kind: "habit.create", name, ...(agent ? { agent } : {}), ...(cadence ? { cadence } : {}) };
447
+ }
448
+ if (sub === "runs") {
449
+ let limit = 20;
450
+ const options = rest.slice(1);
451
+ for (let i = 0; i < options.length; i += 1) {
452
+ if (options[i] !== "--limit" || !options[i + 1])
453
+ throw new Error(`Usage\n${usage()}`);
454
+ const parsedLimit = Number.parseInt(options[i + 1], 10);
455
+ if (!Number.isInteger(parsedLimit) || String(parsedLimit) !== options[i + 1] || parsedLimit < 1 || parsedLimit > 100) {
456
+ throw new Error("--limit must be an integer between 1 and 100");
457
+ }
458
+ limit = parsedLimit;
459
+ i += 1;
460
+ }
461
+ return { kind: "habit.runs", ...(agent ? { agent } : {}), limit };
462
+ }
463
+ if (sub === "inspect") {
464
+ const positional = rest.slice(1);
465
+ if (positional.length !== 1 || !positional[0])
466
+ throw new Error(`Usage\n${usage()}`);
467
+ return { kind: "habit.inspect", ...(agent ? { agent } : {}), runId: positional[0] };
468
+ }
469
+ if (sub === "summary") {
470
+ let runId;
471
+ let habitName;
472
+ let operationId;
473
+ let which;
474
+ let json = false;
475
+ const options = rest.slice(1);
476
+ for (let i = 0; i < options.length; i += 1) {
477
+ const option = options[i];
478
+ if (option === "--json") {
479
+ json = true;
480
+ continue;
481
+ }
482
+ if ((option === "--run-id" || option === "--habit" || option === "--operation-id" || option === "--which") && options[i + 1]) {
483
+ const value = options[++i];
484
+ if (option === "--run-id")
485
+ runId = value;
486
+ if (option === "--habit")
487
+ habitName = value;
488
+ if (option === "--operation-id")
489
+ operationId = value;
490
+ if (option === "--which") {
491
+ if (!["latest", "previous", "latest-success", "latest-failure"].includes(value)) {
492
+ throw new Error("--which must be latest, previous, latest-success, or latest-failure");
493
+ }
494
+ which = value;
495
+ }
496
+ continue;
497
+ }
498
+ throw new Error(`Usage\n${usage()}`);
499
+ }
500
+ if (runId !== undefined && (habitName !== undefined || operationId !== undefined || which !== undefined)) {
501
+ throw new Error("--run-id cannot be combined with --habit, --operation-id, or --which");
502
+ }
503
+ if (runId === undefined && habitName === undefined && operationId === undefined) {
504
+ throw new Error("provide --run-id, --habit, or --operation-id");
505
+ }
506
+ return {
507
+ kind: "habit.summary",
508
+ ...(agent ? { agent } : {}),
509
+ ...(runId ? { runId } : {}),
510
+ ...(habitName ? { habitName } : {}),
511
+ ...(operationId ? { operationId } : {}),
512
+ ...(which ? { which } : {}),
513
+ json,
514
+ };
515
+ }
516
+ throw new Error(`Usage\n${usage()}`);
517
+ }
518
+ function parseLinkCommand(args, kind = "friend.link") {
519
+ const agent = args[0];
520
+ if (!agent)
521
+ throw new Error(`Usage\n${usage()}`);
522
+ let friendId;
523
+ let providerRaw;
524
+ let externalId;
525
+ for (let i = 1; i < args.length; i += 1) {
526
+ const token = args[i];
527
+ if (token === "--friend") {
528
+ friendId = args[i + 1];
529
+ i += 1;
530
+ continue;
531
+ }
532
+ if (token === "--provider") {
533
+ providerRaw = args[i + 1];
534
+ i += 1;
535
+ continue;
536
+ }
537
+ if (token === "--external-id") {
538
+ externalId = args[i + 1];
539
+ i += 1;
540
+ continue;
541
+ }
542
+ }
543
+ if (!friendId || !providerRaw || !externalId) {
544
+ throw new Error(`Usage\n${usage()}`);
545
+ }
546
+ if (!(0, friends_1.isIdentityProvider)(providerRaw)) {
547
+ throw new Error(`Unknown identity provider '${providerRaw}'. Use aad|local|teams-conversation|imessage-handle|email-address|a2a-agent.`);
548
+ }
549
+ return {
550
+ kind,
551
+ agent,
552
+ friendId,
553
+ provider: providerRaw,
554
+ externalId,
555
+ };
556
+ }
557
+ function parseHatchCommand(args) {
558
+ let agentName;
559
+ let humanName;
560
+ let providerRaw;
561
+ let migrationPath;
562
+ const credentials = {};
563
+ for (let i = 0; i < args.length; i += 1) {
564
+ const token = args[i];
565
+ if (token === "--agent") {
566
+ agentName = args[i + 1];
567
+ i += 1;
568
+ continue;
569
+ }
570
+ if (token === "--human") {
571
+ humanName = args[i + 1];
572
+ i += 1;
573
+ continue;
574
+ }
575
+ if (token === "--provider") {
576
+ providerRaw = args[i + 1];
577
+ i += 1;
578
+ continue;
579
+ }
580
+ if (token === "--setup-token") {
581
+ credentials.setupToken = args[i + 1];
582
+ i += 1;
583
+ continue;
584
+ }
585
+ if (token === "--oauth-token") {
586
+ credentials.oauthAccessToken = args[i + 1];
587
+ i += 1;
588
+ continue;
589
+ }
590
+ if (token === "--api-key") {
591
+ credentials.apiKey = args[i + 1];
592
+ i += 1;
593
+ continue;
594
+ }
595
+ if (token === "--endpoint") {
596
+ credentials.endpoint = args[i + 1];
597
+ i += 1;
598
+ continue;
599
+ }
600
+ if (token === "--deployment") {
601
+ credentials.deployment = args[i + 1];
602
+ i += 1;
603
+ continue;
604
+ }
605
+ if (token === "--github-token") {
606
+ credentials.githubToken = args[i + 1];
607
+ i += 1;
608
+ continue;
609
+ }
610
+ if (token === "--base-url") {
611
+ credentials.baseUrl = args[i + 1];
612
+ i += 1;
613
+ continue;
614
+ }
615
+ if (token === "--migration-path") {
616
+ migrationPath = args[i + 1];
617
+ i += 1;
618
+ continue;
619
+ }
620
+ }
621
+ if (providerRaw && !isAgentProvider(providerRaw)) {
622
+ throw new Error("Unknown provider. Use azure|anthropic|minimax|openai-codex|github-copilot.");
623
+ }
624
+ const provider = providerRaw && isAgentProvider(providerRaw) ? providerRaw : undefined;
625
+ return {
626
+ kind: "hatch.start",
627
+ agentName,
628
+ humanName,
629
+ provider,
630
+ credentials: Object.keys(credentials).length > 0 ? credentials : undefined,
631
+ migrationPath,
632
+ };
633
+ }
634
+ function parseAuthCommand(args) {
635
+ const first = args[0];
636
+ // Support both positional (`auth switch`) and flag (`auth --switch`) forms
637
+ if (first === "verify" || first === "switch" || first === "--verify" || first === "--switch") {
638
+ const subcommand = first.replace(/^--/, "");
639
+ const { agent, rest: afterAgent } = extractAgentFlag(args.slice(1));
640
+ const { facing, rest } = extractFacingFlag(afterAgent);
641
+ let provider;
642
+ /* v8 ignore start -- provider flag parsing: branches tested via CLI parsing tests @preserve */
643
+ for (let i = 0; i < rest.length; i += 1) {
644
+ if (rest[i] === "--provider") {
645
+ const value = rest[i + 1];
646
+ if (!isAgentProvider(value))
647
+ throw new Error(`Usage\n${usage()}`);
648
+ provider = value;
649
+ i += 1;
650
+ continue;
651
+ }
652
+ }
653
+ /* v8 ignore stop */
654
+ if (subcommand === "switch") {
655
+ if (!provider)
656
+ throw new Error(`auth switch requires --provider.\n${usage()}`);
657
+ return {
658
+ kind: "auth.switch",
659
+ ...(agent ? { agent } : {}),
660
+ provider,
661
+ ...(facing ? { facing } : {}),
662
+ };
663
+ }
664
+ return {
665
+ kind: "auth.verify",
666
+ ...(agent ? { agent } : {}),
667
+ ...(provider ? { provider } : {}),
668
+ };
669
+ }
670
+ const { agent, rest } = extractAgentFlag(args);
671
+ let provider;
672
+ for (let i = 0; i < rest.length; i += 1) {
673
+ if (rest[i] === "--provider") {
674
+ const value = rest[i + 1];
675
+ if (!isAgentProvider(value))
676
+ throw new Error(`Usage\n${usage()}`);
677
+ provider = value;
678
+ i += 1;
679
+ continue;
680
+ }
681
+ }
682
+ return {
683
+ kind: "auth.run",
684
+ ...(agent ? { agent } : {}),
685
+ ...(provider ? { provider } : {}),
686
+ };
687
+ }
688
+ function isVaultUnlockStoreKind(value) {
689
+ return value === "auto" || value === "macos-keychain" || value === "windows-dpapi" || value === "linux-secret-service" || value === "plaintext-file";
690
+ }
691
+ function parseVaultCommand(args) {
692
+ const sub = args[0];
693
+ if (sub === "config")
694
+ return parseVaultConfigCommand(args.slice(1));
695
+ if (sub === "item")
696
+ return parseVaultItemCommand(args.slice(1));
697
+ if (sub === "ops")
698
+ return parseVaultOpsCommand(args.slice(1));
699
+ const { agent, rest } = extractAgentFlag(args.slice(1));
700
+ let email;
701
+ let serverUrl;
702
+ let store;
703
+ let generateUnlockSecret = false;
704
+ const sources = [];
705
+ for (let i = 0; i < rest.length; i += 1) {
706
+ const token = rest[i];
707
+ if (token === "--email") {
708
+ email = rest[i + 1];
709
+ i += 1;
710
+ continue;
711
+ }
712
+ if (token === "--server") {
713
+ serverUrl = rest[i + 1];
714
+ i += 1;
715
+ continue;
716
+ }
717
+ if (token === "--store") {
718
+ const value = rest[i + 1];
719
+ if (!isVaultUnlockStoreKind(value)) {
720
+ throw new Error("vault --store must be auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file");
721
+ }
722
+ store = value;
723
+ i += 1;
724
+ continue;
725
+ }
726
+ if (token === "--from") {
727
+ if (sub !== "recover") {
728
+ throw new Error("--from is only valid with `ouro vault recover`; use `ouro vault replace` when there is no JSON export to import.");
729
+ }
730
+ const value = rest[i + 1];
731
+ if (!value)
732
+ throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
733
+ sources.push(value);
734
+ i += 1;
735
+ continue;
736
+ }
737
+ if (token === "--generate-unlock-secret") {
738
+ generateUnlockSecret = true;
739
+ continue;
740
+ }
741
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
742
+ }
743
+ if (sub !== "create" && sub !== "replace" && sub !== "recover" && sub !== "unlock" && sub !== "status") {
744
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
745
+ }
746
+ if (sub === "create") {
747
+ return {
748
+ kind: "vault.create",
749
+ ...(agent ? { agent } : {}),
750
+ ...(email ? { email } : {}),
751
+ ...(serverUrl ? { serverUrl } : {}),
752
+ ...(store ? { store } : {}),
753
+ ...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
754
+ };
755
+ }
756
+ if (sub === "replace") {
757
+ return {
758
+ kind: "vault.replace",
759
+ ...(agent ? { agent } : {}),
760
+ ...(email ? { email } : {}),
761
+ ...(serverUrl ? { serverUrl } : {}),
762
+ ...(store ? { store } : {}),
763
+ ...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
764
+ };
765
+ }
766
+ if (sub === "recover") {
767
+ if (sources.length === 0) {
768
+ throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
769
+ }
770
+ return {
771
+ kind: "vault.recover",
772
+ ...(agent ? { agent } : {}),
773
+ sources,
774
+ ...(email ? { email } : {}),
775
+ ...(serverUrl ? { serverUrl } : {}),
776
+ ...(store ? { store } : {}),
777
+ ...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
778
+ };
779
+ }
780
+ if (sub === "unlock") {
781
+ return { kind: "vault.unlock", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
782
+ }
783
+ return { kind: "vault.status", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
784
+ }
785
+ function parseVaultItemCommand(args) {
786
+ const action = args[0];
787
+ if (action !== "set" && action !== "status" && action !== "list") {
788
+ throw new Error("Usage: ouro vault item set|status|list [--agent <name>] --item <path>");
789
+ }
790
+ const { agent, rest } = extractAgentFlag(args.slice(1));
791
+ let item;
792
+ let prefix;
793
+ let template;
794
+ let note;
795
+ const secretFields = [];
796
+ const publicFields = [];
797
+ for (let i = 0; i < rest.length; i += 1) {
798
+ const token = rest[i];
799
+ if (token === "--item") {
800
+ item = (0, vault_items_1.normalizeVaultItemName)(rest[i + 1]);
801
+ i += 1;
802
+ continue;
803
+ }
804
+ if (token === "--prefix") {
805
+ const value = rest[i + 1]?.trim() ?? "";
806
+ if (!value || /[\r\n\t]/.test(value) || value.startsWith("/")) {
807
+ throw new Error("Vault item prefix must be non-empty, relative, and free of control characters.");
808
+ }
809
+ prefix = value;
810
+ i += 1;
811
+ continue;
812
+ }
813
+ if (token === "--template") {
814
+ const value = rest[i + 1];
815
+ if (!(0, vault_items_1.isVaultItemTemplate)(value)) {
816
+ throw new Error("vault item --template must be porkbun-api");
817
+ }
818
+ template = value;
819
+ i += 1;
820
+ continue;
821
+ }
822
+ if (token === "--secret-field") {
823
+ secretFields.push((0, vault_items_1.normalizeVaultItemFieldName)(rest[i + 1]));
824
+ i += 1;
825
+ continue;
826
+ }
827
+ if (token === "--public-field") {
828
+ const value = rest[i + 1]?.trim() ?? "";
829
+ const separator = value.indexOf("=");
830
+ if (separator <= 0 || separator === value.length - 1) {
831
+ throw new Error("vault item --public-field must be key=value");
832
+ }
833
+ (0, vault_items_1.normalizeVaultItemFieldName)(value.slice(0, separator));
834
+ publicFields.push(value);
835
+ i += 1;
836
+ continue;
837
+ }
838
+ if (token === "--note") {
839
+ note = rest[i + 1] ?? "";
840
+ i += 1;
841
+ continue;
842
+ }
843
+ throw new Error(`Usage: ouro vault item ${action} [--agent <name>] --item <path>`);
844
+ }
845
+ if (action === "list") {
846
+ return { kind: "vault.item.list", ...(agent ? { agent } : {}), ...(prefix ? { prefix } : {}) };
847
+ }
848
+ if (!item)
849
+ throw new Error(`Usage: ouro vault item ${action} [--agent <name>] --item <path>`);
850
+ if (action === "status") {
851
+ return { kind: "vault.item.status", ...(agent ? { agent } : {}), item };
852
+ }
853
+ if (!template && secretFields.length === 0) {
854
+ throw new Error("ouro vault item set requires --secret-field or --template");
855
+ }
856
+ return {
857
+ kind: "vault.item.set",
858
+ ...(agent ? { agent } : {}),
859
+ item,
860
+ ...(template ? { template } : {}),
861
+ ...(secretFields.length > 0 ? { secretFields } : {}),
862
+ ...(publicFields.length > 0 ? { publicFields } : {}),
863
+ ...(note !== undefined ? { note } : {}),
864
+ };
865
+ }
866
+ function parseVaultOpsCommand(args) {
867
+ const provider = args[0];
868
+ const action = args[1];
869
+ if (provider !== "porkbun") {
870
+ throw new Error("Usage: ouro vault ops porkbun set|status [--agent <name>] [--account <account>]");
871
+ }
872
+ if (action !== "set" && action !== "status") {
873
+ throw new Error("Usage: ouro vault ops porkbun set|status [--agent <name>] [--account <account>]");
874
+ }
875
+ const { agent, rest } = extractAgentFlag(args.slice(2));
876
+ let account;
877
+ for (let i = 0; i < rest.length; i += 1) {
878
+ const token = rest[i];
879
+ if (token === "--account") {
880
+ account = (0, vault_items_1.normalizePorkbunOpsAccount)(rest[i + 1]);
881
+ i += 1;
882
+ continue;
883
+ }
884
+ throw new Error(`Usage: ouro vault ops porkbun ${action} [--agent <name>] [--account <account>]`);
885
+ }
886
+ if (action === "set") {
887
+ if (!account)
888
+ throw new Error("Usage: ouro vault ops porkbun set [--agent <name>] --account <account>");
889
+ return {
890
+ kind: "vault.item.set",
891
+ ...(agent ? { agent } : {}),
892
+ item: (0, vault_items_1.porkbunOpsCredentialItemName)(account),
893
+ template: "porkbun-api",
894
+ compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
895
+ };
896
+ }
897
+ if (account) {
898
+ return {
899
+ kind: "vault.item.status",
900
+ ...(agent ? { agent } : {}),
901
+ item: (0, vault_items_1.porkbunOpsCredentialItemName)(account),
902
+ compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
903
+ };
904
+ }
905
+ return {
906
+ kind: "vault.item.list",
907
+ ...(agent ? { agent } : {}),
908
+ prefix: vault_items_1.PORKBUN_OPS_CREDENTIAL_PREFIX,
909
+ compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
910
+ };
911
+ }
912
+ function isDnsWorkflowAction(value) {
913
+ return value === "backup" || value === "plan" || value === "apply" || value === "verify" || value === "rollback" || value === "certificate";
914
+ }
915
+ function normalizeWorkflowPath(value, label) {
916
+ const trimmed = value?.trim() ?? "";
917
+ if (!trimmed || /[\r\n\t]/.test(trimmed)) {
918
+ throw new Error(`${label} must be a non-empty path without control characters.`);
919
+ }
920
+ return trimmed;
921
+ }
922
+ function parseDnsCommand(args) {
923
+ const action = args[0];
924
+ if (!isDnsWorkflowAction(action)) {
925
+ throw new Error("Usage: ouro dns backup|plan|apply|verify|rollback|certificate [--agent <name>] --binding <path>");
926
+ }
927
+ const { agent, rest } = extractAgentFlag(args.slice(1));
928
+ let bindingPath;
929
+ let outputPath;
930
+ let backupPath;
931
+ let yes = false;
932
+ for (let i = 0; i < rest.length; i += 1) {
933
+ const token = rest[i];
934
+ if (token === "--binding") {
935
+ bindingPath = normalizeWorkflowPath(rest[i + 1], "dns --binding");
936
+ i += 1;
937
+ continue;
938
+ }
939
+ if (token === "--output") {
940
+ outputPath = normalizeWorkflowPath(rest[i + 1], "dns --output");
941
+ i += 1;
942
+ continue;
943
+ }
944
+ if (token === "--backup") {
945
+ backupPath = normalizeWorkflowPath(rest[i + 1], "dns --backup");
946
+ i += 1;
947
+ continue;
948
+ }
949
+ if (token === "--yes") {
950
+ yes = true;
951
+ continue;
952
+ }
953
+ if (token === "--credential-item") {
954
+ throw new Error("credential item belongs in the DNS workflow binding");
955
+ }
956
+ throw new Error(`Usage: ouro dns ${action} [--agent <name>] --binding <path>`);
957
+ }
958
+ if (!bindingPath) {
959
+ throw new Error(`Usage: ouro dns ${action} [--agent <name>] --binding <path>`);
960
+ }
961
+ if (action === "apply" && !yes) {
962
+ throw new Error("dns apply requires --yes after a reviewed dry-run");
963
+ }
964
+ if (action === "rollback") {
965
+ if (!backupPath)
966
+ throw new Error("dns rollback requires --backup <path>");
967
+ if (!yes)
968
+ throw new Error("dns rollback requires --yes after choosing a backup");
969
+ }
970
+ return {
971
+ kind: "dns.workflow",
972
+ action,
973
+ ...(agent ? { agent } : {}),
974
+ bindingPath,
975
+ ...(outputPath ? { outputPath } : {}),
976
+ ...(backupPath ? { backupPath } : {}),
977
+ ...(yes ? { yes: true } : {}),
978
+ };
979
+ }
980
+ function parseVaultConfigCommand(args) {
981
+ const sub = args[0];
982
+ const { agent, rest } = extractAgentFlag(args.slice(1));
983
+ let key;
984
+ let value;
985
+ let scope;
986
+ for (let i = 0; i < rest.length; i += 1) {
987
+ const token = rest[i];
988
+ if (token === "--key") {
989
+ key = rest[i + 1];
990
+ i += 1;
991
+ continue;
992
+ }
993
+ if (token === "--value") {
994
+ value = rest[i + 1];
995
+ i += 1;
996
+ continue;
997
+ }
998
+ if (token === "--scope") {
999
+ const raw = rest[i + 1];
1000
+ if (raw !== "agent" && raw !== "machine" && raw !== "all") {
1001
+ throw new Error("vault config --scope must be agent, machine, or all");
1002
+ }
1003
+ scope = raw;
1004
+ i += 1;
1005
+ continue;
1006
+ }
1007
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
1008
+ }
1009
+ if (sub !== "set" && sub !== "status") {
1010
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
1011
+ }
1012
+ if (sub === "status") {
1013
+ if (key || value) {
1014
+ throw new Error("Usage: ouro vault config status [--agent <name>]");
1015
+ }
1016
+ return { kind: "vault.config.status", ...(agent ? { agent } : {}), ...(scope ? { scope } : {}) };
1017
+ }
1018
+ if (scope === "all")
1019
+ throw new Error("vault config --scope all is only valid for status");
1020
+ if (!key) {
1021
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>]");
1022
+ }
1023
+ return { kind: "vault.config.set", ...(agent ? { agent } : {}), key, ...(value !== undefined ? { value } : {}), ...(scope ? { scope } : {}) };
1024
+ }
1025
+ function normalizeConnectTarget(value) {
1026
+ if (!value)
1027
+ return undefined;
1028
+ if (value === "providers" || value === "provider" || value === "auth")
1029
+ return "providers";
1030
+ if (value === "perplexity" || value === "perplexity-search")
1031
+ return "perplexity";
1032
+ if (value === "embeddings" || value === "embedding" || value === "memory" || value === "note-search" || value === "notes")
1033
+ return "embeddings";
1034
+ if (value === "teams" || value === "msteams" || value === "microsoft-teams")
1035
+ return "teams";
1036
+ if (value === "bluebubbles" || value === "imessage" || value === "messages")
1037
+ return "bluebubbles";
1038
+ if (value === "mail" || value === "email" || value === "mailroom")
1039
+ return "mail";
1040
+ if (value === "voice" || value === "audio" || value === "speech")
1041
+ return "voice";
1042
+ if (value === "a2a" || value === "agent2agent" || value === "agent-to-agent")
1043
+ return "a2a";
1044
+ if (value === "telegram")
1045
+ return "telegram";
1046
+ if (value === "workbench" || value === "ouro-workbench" || value === "terminal-workbench")
1047
+ return "workbench";
1048
+ throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail|voice|a2a|telegram|workbench] [--agent <name>]");
1049
+ }
1050
+ function extractMailSourceFlags(args, usageText) {
1051
+ const rest = [];
1052
+ let ownerEmail;
1053
+ let source;
1054
+ let noDelegatedSource = false;
1055
+ let rotateMissingMailKeys = false;
1056
+ let hasMailSourceFlags = false;
1057
+ for (let i = 0; i < args.length; i += 1) {
1058
+ const token = args[i];
1059
+ if (token === "--owner-email") {
1060
+ if (args[i + 1] === undefined)
1061
+ throw new Error(usageText);
1062
+ ownerEmail = args[++i];
1063
+ hasMailSourceFlags = true;
1064
+ continue;
1065
+ }
1066
+ if (token === "--source") {
1067
+ if (args[i + 1] === undefined)
1068
+ throw new Error(usageText);
1069
+ source = args[++i];
1070
+ hasMailSourceFlags = true;
1071
+ continue;
1072
+ }
1073
+ if (token === "--no-delegated-source") {
1074
+ noDelegatedSource = true;
1075
+ hasMailSourceFlags = true;
1076
+ continue;
1077
+ }
1078
+ if (token === "--rotate-missing-mail-keys") {
1079
+ rotateMissingMailKeys = true;
1080
+ hasMailSourceFlags = true;
1081
+ continue;
1082
+ }
1083
+ rest.push(token);
1084
+ }
1085
+ if (noDelegatedSource && (ownerEmail !== undefined || source !== undefined)) {
1086
+ throw new Error("--no-delegated-source cannot be combined with --owner-email or --source");
1087
+ }
1088
+ if (source !== undefined && ownerEmail === undefined) {
1089
+ throw new Error("--source requires --owner-email");
1090
+ }
1091
+ return {
1092
+ rest,
1093
+ ...(ownerEmail !== undefined ? { ownerEmail } : {}),
1094
+ ...(source !== undefined ? { source } : {}),
1095
+ ...(noDelegatedSource ? { noDelegatedSource: true } : {}),
1096
+ ...(rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
1097
+ hasMailSourceFlags,
1098
+ };
1099
+ }
1100
+ function parseConnectCommand(args) {
1101
+ const usageText = "Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail|voice|a2a|telegram|workbench] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
1102
+ const { agent, rest: afterAgent } = extractAgentFlag(args);
1103
+ const mailFlags = extractMailSourceFlags(afterAgent, usageText);
1104
+ if (mailFlags.rest.length > 1)
1105
+ throw new Error(usageText);
1106
+ const target = normalizeConnectTarget(mailFlags.rest[0]);
1107
+ if (mailFlags.hasMailSourceFlags && target !== "mail") {
1108
+ throw new Error("Mail source flags require `ouro connect mail`.");
1109
+ }
1110
+ return {
1111
+ kind: "connect",
1112
+ ...(agent ? { agent } : {}),
1113
+ ...(target ? { target } : {}),
1114
+ ...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
1115
+ ...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
1116
+ ...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
1117
+ ...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
1118
+ };
1119
+ }
1120
+ function parseMailCommand(args) {
1121
+ const [sub, ...subArgs] = args;
1122
+ const usageText = "Usage: ouro mail import-mbox (--file <path>|--discover) [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]\n ouro mail backfill-indexes [--agent <name>] [--foreground]\n ouro mail sync-cache [--agent <name>]";
1123
+ if (sub === "sync-cache") {
1124
+ const agentFlagCount = subArgs.filter((token) => token === "--agent").length;
1125
+ const { agent, rest } = extractAgentFlag(subArgs);
1126
+ if (agentFlagCount > 1 ||
1127
+ rest.length > 0 ||
1128
+ (agentFlagCount === 1 && (!agent || agent.trim().length === 0 || agent.trim().startsWith("--")))) {
1129
+ throw new Error("Usage: ouro mail sync-cache [--agent <name>]");
1130
+ }
1131
+ return { kind: "mail.sync-cache", ...(agent ? { agent } : {}) };
1132
+ }
1133
+ if (sub === "backfill-indexes") {
1134
+ const { agent, rest } = extractAgentFlag(subArgs);
1135
+ let foreground = false;
1136
+ let operationId;
1137
+ for (let i = 0; i < rest.length; i += 1) {
1138
+ const token = rest[i];
1139
+ if (token === "--foreground") {
1140
+ foreground = true;
1141
+ continue;
1142
+ }
1143
+ if (token === "--operation-id" && rest[i + 1]) {
1144
+ operationId = rest[++i];
1145
+ continue;
1146
+ }
1147
+ throw new Error(usageText);
1148
+ }
1149
+ return {
1150
+ kind: "mail.backfill-indexes",
1151
+ ...(agent ? { agent } : {}),
1152
+ ...(foreground ? { foreground: true } : {}),
1153
+ ...(operationId ? { operationId } : {}),
1154
+ };
1155
+ }
1156
+ if (sub !== "import-mbox") {
1157
+ throw new Error(usageText);
1158
+ }
1159
+ const { agent, rest } = extractAgentFlag(subArgs);
1160
+ let filePath;
1161
+ let discover = false;
1162
+ let ownerEmail;
1163
+ let source;
1164
+ let foreground = false;
1165
+ let operationId;
1166
+ for (let i = 0; i < rest.length; i += 1) {
1167
+ const token = rest[i];
1168
+ if (token === "--file" && rest[i + 1]) {
1169
+ filePath = rest[++i];
1170
+ continue;
1171
+ }
1172
+ if (token === "--discover") {
1173
+ discover = true;
1174
+ continue;
1175
+ }
1176
+ if (token === "--owner-email" && rest[i + 1]) {
1177
+ ownerEmail = rest[++i];
1178
+ continue;
1179
+ }
1180
+ if (token === "--source" && rest[i + 1]) {
1181
+ source = rest[++i];
1182
+ continue;
1183
+ }
1184
+ if (token === "--foreground") {
1185
+ foreground = true;
1186
+ continue;
1187
+ }
1188
+ if (token === "--operation-id" && rest[i + 1]) {
1189
+ operationId = rest[++i];
1190
+ continue;
1191
+ }
1192
+ throw new Error(usageText);
1193
+ }
1194
+ if ((filePath ? 1 : 0) + (discover ? 1 : 0) !== 1) {
1195
+ throw new Error(usageText);
1196
+ }
1197
+ return {
1198
+ kind: "mail.import-mbox",
1199
+ ...(agent ? { agent } : {}),
1200
+ ...(filePath ? { filePath } : {}),
1201
+ ...(discover ? { discover: true } : {}),
1202
+ ...(ownerEmail ? { ownerEmail } : {}),
1203
+ ...(source ? { source } : {}),
1204
+ ...(foreground ? { foreground: true } : {}),
1205
+ ...(operationId ? { operationId } : {}),
1206
+ };
1207
+ }
1208
+ function parseAccountCommand(args) {
1209
+ const [sub, ...subArgs] = args;
1210
+ const usageText = "Usage: ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
1211
+ if (sub !== "ensure") {
1212
+ throw new Error(usageText);
1213
+ }
1214
+ const { agent, rest: afterAgent } = extractAgentFlag(subArgs);
1215
+ const mailFlags = extractMailSourceFlags(afterAgent, usageText);
1216
+ if (mailFlags.rest.length > 0)
1217
+ throw new Error(usageText);
1218
+ return {
1219
+ kind: "account.ensure",
1220
+ ...(agent ? { agent } : {}),
1221
+ ...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
1222
+ ...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
1223
+ ...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
1224
+ ...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
1225
+ };
1226
+ }
1227
+ function parseProviderUseCommand(args) {
1228
+ const { agent, rest: afterAgent } = extractAgentFlag(args);
1229
+ const { facing, rest: afterFacing } = extractFacingFlag(afterAgent);
1230
+ const { lane, rest } = extractLaneFlag(afterFacing);
1231
+ let provider;
1232
+ let model;
1233
+ let force = false;
1234
+ for (let i = 0; i < rest.length; i += 1) {
1235
+ const token = rest[i];
1236
+ if (token === "--provider") {
1237
+ const value = rest[i + 1];
1238
+ if (!isAgentProvider(value))
1239
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model>");
1240
+ provider = value;
1241
+ i += 1;
1242
+ continue;
1243
+ }
1244
+ if (token === "--model") {
1245
+ model = rest[i + 1];
1246
+ i += 1;
1247
+ continue;
1248
+ }
1249
+ if (token === "--force") {
1250
+ force = true;
1251
+ continue;
1252
+ }
1253
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
1254
+ }
1255
+ const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
1256
+ if (!resolvedLane || !provider || !model) {
1257
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
1258
+ }
1259
+ return {
1260
+ kind: "provider.use",
1261
+ ...(agent ? { agent } : {}),
1262
+ lane: resolvedLane,
1263
+ provider,
1264
+ model,
1265
+ ...(force ? { force: true } : {}),
1266
+ ...(facing ? { legacyFacing: facing } : {}),
1267
+ };
1268
+ }
1269
+ function parseProviderCheckCommand(args) {
1270
+ const { agent, rest: afterAgent } = extractAgentFlag(args);
1271
+ const { facing, rest: afterFacing } = extractFacingFlag(afterAgent);
1272
+ const { lane, rest } = extractLaneFlag(afterFacing);
1273
+ const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
1274
+ if (!resolvedLane || rest.length > 0) {
1275
+ throw new Error("Usage: ouro check [--agent <name>] --lane outward|inner");
1276
+ }
1277
+ return {
1278
+ kind: "provider.check",
1279
+ ...(agent ? { agent } : {}),
1280
+ lane: resolvedLane,
1281
+ ...(facing ? { legacyFacing: facing } : {}),
1282
+ };
1283
+ }
1284
+ function parseProviderCommand(args) {
1285
+ const sub = args[0];
1286
+ if (sub === "check")
1287
+ return parseProviderCheckCommand(args.slice(1));
1288
+ const { agent, rest } = extractAgentFlag(args.slice(1));
1289
+ if (sub === "refresh" && rest.length === 0) {
1290
+ return { kind: "provider.refresh", ...(agent ? { agent } : {}) };
1291
+ }
1292
+ throw new Error("Usage: ouro provider refresh [--agent <name>] OR ouro provider check [--agent <name>] --lane outward|inner");
1293
+ }
1294
+ function parseSessionCommand(args) {
1295
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1296
+ const [sub] = cleaned;
1297
+ if (!sub)
1298
+ throw new Error(`Usage\n${usage()}`);
1299
+ if (sub === "list")
1300
+ return { kind: "session.list", ...(agent ? { agent } : {}) };
1301
+ throw new Error(`Usage\n${usage()}`);
1302
+ }
1303
+ function parseAttentionCommand(args) {
1304
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1305
+ const sub = cleaned[0];
1306
+ if (sub === "show" && cleaned[1]) {
1307
+ return { kind: "attention.show", id: cleaned[1], ...(agent ? { agent } : {}) };
1308
+ }
1309
+ if (sub === "history") {
1310
+ return { kind: "attention.history", ...(agent ? { agent } : {}) };
1311
+ }
1312
+ return { kind: "attention.list", ...(agent ? { agent } : {}) };
1313
+ }
1314
+ function parseWorkFormat(args, usageText) {
1315
+ let format = "text";
1316
+ for (let i = 0; i < args.length; i += 1) {
1317
+ if (args[i] === "--json") {
1318
+ format = "json";
1319
+ continue;
1320
+ }
1321
+ if (args[i] === "--format" && args[i + 1]) {
1322
+ const value = args[++i];
1323
+ if (value !== "text" && value !== "json") {
1324
+ throw new Error("--format must be text or json");
1325
+ }
1326
+ format = value;
1327
+ continue;
1328
+ }
1329
+ throw new Error(usageText);
1330
+ }
1331
+ return format;
1332
+ }
1333
+ function parseWorkCommand(args) {
1334
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1335
+ const sub = cleaned[0];
1336
+ if (sub === "sentinel") {
1337
+ const refresh = cleaned[1] === "refresh";
1338
+ const usageText = "Usage: ouro work sentinel [refresh] [--agent <name>] [--format text|json|--json]";
1339
+ const format = parseWorkFormat(cleaned.slice(refresh ? 2 : 1), usageText);
1340
+ return {
1341
+ kind: refresh ? "work.sentinel.refresh" : "work.sentinel",
1342
+ ...(agent ? { agent } : {}),
1343
+ ...(format !== "text" ? { format } : {}),
1344
+ };
1345
+ }
1346
+ if (sub !== "card" && sub !== "gauntlet") {
1347
+ throw new Error("Usage: ouro work card|gauntlet|sentinel [refresh] [--agent <name>] [--format text|json|--json]");
1348
+ }
1349
+ const format = parseWorkFormat(cleaned.slice(1), `Usage: ouro work ${sub} [--agent <name>] [--format text|json|--json]`);
1350
+ return { kind: sub === "card" ? "work.card" : "work.gauntlet", ...(agent ? { agent } : {}), ...(format !== "text" ? { format } : {}) };
1351
+ }
1352
+ function parseThoughtsCommand(args) {
1353
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1354
+ let last;
1355
+ let json = false;
1356
+ let follow = false;
1357
+ for (let i = 0; i < cleaned.length; i++) {
1358
+ if (cleaned[i] === "--last" && i + 1 < cleaned.length) {
1359
+ last = Number.parseInt(cleaned[i + 1], 10);
1360
+ i++;
1361
+ }
1362
+ if (cleaned[i] === "--json")
1363
+ json = true;
1364
+ if (cleaned[i] === "--follow" || cleaned[i] === "-f")
1365
+ follow = true;
1366
+ }
1367
+ return { kind: "thoughts", ...(agent ? { agent } : {}), ...(last ? { last } : {}), ...(json ? { json } : {}), ...(follow ? { follow } : {}) };
1368
+ }
1369
+ function parseFriendCommand(args) {
1370
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1371
+ const [sub, ...rest] = cleaned;
1372
+ if (!sub)
1373
+ throw new Error(`Usage\n${usage()}`);
1374
+ if (sub === "list")
1375
+ return { kind: "friend.list", ...(agent ? { agent } : {}) };
1376
+ if (sub === "show") {
1377
+ const friendId = rest[0];
1378
+ if (!friendId)
1379
+ throw new Error(`Usage\n${usage()}`);
1380
+ return { kind: "friend.show", friendId, ...(agent ? { agent } : {}) };
1381
+ }
1382
+ if (sub === "create") {
1383
+ let name;
1384
+ let trustLevel;
1385
+ for (let i = 0; i < rest.length; i++) {
1386
+ if (rest[i] === "--name" && rest[i + 1]) {
1387
+ name = rest[i + 1];
1388
+ i += 1;
1389
+ }
1390
+ else if (rest[i] === "--trust" && rest[i + 1]) {
1391
+ trustLevel = rest[i + 1];
1392
+ i += 1;
1393
+ }
1394
+ }
1395
+ if (!name)
1396
+ throw new Error(`Usage\n${usage()}`);
1397
+ return {
1398
+ kind: "friend.create",
1399
+ name,
1400
+ ...(trustLevel ? { trustLevel } : {}),
1401
+ ...(agent ? { agent } : {}),
1402
+ };
1403
+ }
1404
+ if (sub === "update") {
1405
+ const friendId = rest[0];
1406
+ if (!friendId)
1407
+ throw new Error(`Usage: ouro friend update <id> --trust <level>`);
1408
+ let trustLevel;
1409
+ /* v8 ignore start -- flag parsing loop: tested via CLI parsing tests @preserve */
1410
+ for (let i = 1; i < rest.length; i++) {
1411
+ if (rest[i] === "--trust" && rest[i + 1]) {
1412
+ trustLevel = rest[i + 1];
1413
+ i += 1;
1414
+ }
1415
+ }
1416
+ /* v8 ignore stop */
1417
+ const VALID_TRUST_LEVELS = new Set(["stranger", "acquaintance", "friend", "family"]);
1418
+ if (!trustLevel || !VALID_TRUST_LEVELS.has(trustLevel)) {
1419
+ throw new Error(`Usage: ouro friend update <id> --trust <stranger|acquaintance|friend|family>`);
1420
+ }
1421
+ return {
1422
+ kind: "friend.update",
1423
+ friendId,
1424
+ trustLevel: trustLevel,
1425
+ ...(agent ? { agent } : {}),
1426
+ };
1427
+ }
1428
+ if (sub === "link")
1429
+ return parseLinkCommand(rest, "friend.link");
1430
+ if (sub === "unlink")
1431
+ return parseLinkCommand(rest, "friend.unlink");
1432
+ throw new Error(`Usage\n${usage()}`);
1433
+ }
1434
+ function parseA2ACommand(args) {
1435
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1436
+ const [sub, ...rest] = cleaned;
1437
+ if (sub === "card") {
1438
+ let baseUrl;
1439
+ let json = false;
1440
+ for (let i = 0; i < rest.length; i += 1) {
1441
+ if (rest[i] === "--base-url" && rest[i + 1]) {
1442
+ baseUrl = rest[++i];
1443
+ continue;
1444
+ }
1445
+ if (rest[i] === "--json") {
1446
+ json = true;
1447
+ continue;
1448
+ }
1449
+ throw new Error("Usage: ouro a2a card [--agent <name>] [--base-url <url>] [--json]");
1450
+ }
1451
+ return { kind: "a2a.card", ...(agent ? { agent } : {}), ...(baseUrl ? { baseUrl } : {}), ...(json ? { json: true } : {}) };
1452
+ }
1453
+ if (sub === "onboard") {
1454
+ let cardUrl;
1455
+ let trustLevel;
1456
+ let name;
1457
+ const VALID_TRUST_LEVELS = new Set(["stranger", "acquaintance", "friend", "family"]);
1458
+ for (let i = 0; i < rest.length; i += 1) {
1459
+ if (rest[i] === "--card-url" && rest[i + 1]) {
1460
+ cardUrl = rest[++i];
1461
+ continue;
1462
+ }
1463
+ if (rest[i] === "--trust" && rest[i + 1]) {
1464
+ const raw = rest[++i];
1465
+ if (!VALID_TRUST_LEVELS.has(raw))
1466
+ throw new Error("Usage: ouro a2a onboard [--agent <name>] --card-url <url> [--trust <stranger|acquaintance|friend|family>] [--name <name>]");
1467
+ trustLevel = raw;
1468
+ continue;
1469
+ }
1470
+ if (rest[i] === "--name" && rest[i + 1]) {
1471
+ name = rest[++i];
1472
+ continue;
1473
+ }
1474
+ throw new Error("Usage: ouro a2a onboard [--agent <name>] --card-url <url> [--trust <level>] [--name <name>]");
1475
+ }
1476
+ if (!cardUrl)
1477
+ throw new Error("Usage: ouro a2a onboard [--agent <name>] --card-url <url> [--trust <level>] [--name <name>]");
1478
+ return { kind: "a2a.onboard", cardUrl, ...(agent ? { agent } : {}), ...(trustLevel ? { trustLevel } : {}), ...(name ? { name } : {}) };
1479
+ }
1480
+ if (sub === "serve") {
1481
+ let host;
1482
+ let port;
1483
+ let baseUrl;
1484
+ let path;
1485
+ for (let i = 0; i < rest.length; i += 1) {
1486
+ if (rest[i] === "--host" && rest[i + 1]) {
1487
+ host = rest[++i];
1488
+ continue;
1489
+ }
1490
+ if (rest[i] === "--port" && rest[i + 1]) {
1491
+ const rawPort = Number.parseInt(rest[++i], 10);
1492
+ if (!Number.isInteger(rawPort) || rawPort < 1 || rawPort > 65535)
1493
+ throw new Error("A2A port must be 1-65535");
1494
+ port = rawPort;
1495
+ continue;
1496
+ }
1497
+ if (rest[i] === "--base-url" && rest[i + 1]) {
1498
+ baseUrl = rest[++i];
1499
+ continue;
1500
+ }
1501
+ if (rest[i] === "--path" && rest[i + 1]) {
1502
+ path = rest[++i];
1503
+ continue;
1504
+ }
1505
+ throw new Error("Usage: ouro a2a serve [--agent <name>] [--host <host>] [--port <port>] [--base-url <url>] [--path <path>]");
1506
+ }
1507
+ return { kind: "a2a.serve", ...(agent ? { agent } : {}), ...(host ? { host } : {}), ...(port ? { port } : {}), ...(baseUrl ? { baseUrl } : {}), ...(path ? { path } : {}) };
1508
+ }
1509
+ throw new Error("Usage: ouro a2a card|onboard|serve ...");
1510
+ }
1511
+ function parseConfigCommand(args) {
1512
+ const { agent, rest: afterAgent } = extractAgentFlag(args);
1513
+ const { facing, rest: cleaned } = extractFacingFlag(afterAgent);
1514
+ const [sub, ...rest] = cleaned;
1515
+ if (!sub)
1516
+ throw new Error(`Usage\n${usage()}`);
1517
+ if (sub === "model") {
1518
+ const modelName = rest[0];
1519
+ if (!modelName)
1520
+ throw new Error("Usage: ouro config model [--agent <name>] <model-name>");
1521
+ if (modelName.startsWith("-"))
1522
+ throw new Error("config model requires a model name, not another flag.");
1523
+ return {
1524
+ kind: "config.model",
1525
+ ...(agent ? { agent } : {}),
1526
+ modelName,
1527
+ ...(facing ? { facing } : {}),
1528
+ };
1529
+ }
1530
+ if (sub === "models") {
1531
+ return { kind: "config.models", ...(agent ? { agent } : {}) };
1532
+ }
1533
+ throw new Error(`Usage\n${usage()}`);
1534
+ }
1535
+ function parseMcpCommand(args) {
1536
+ const { agent, rest: cleaned } = extractAgentFlag(args);
1537
+ const [sub, ...rest] = cleaned;
1538
+ if (!sub)
1539
+ throw new Error(`Usage\n${usage()}`);
1540
+ if (sub === "list")
1541
+ return { kind: "mcp.list", ...(agent ? { agent } : {}) };
1542
+ if (sub === "call") {
1543
+ const server = rest[0];
1544
+ const tool = rest[1];
1545
+ if (!server || !tool)
1546
+ throw new Error(`Usage\n${usage()}`);
1547
+ const argsIdx = rest.indexOf("--args");
1548
+ const mcpArgs = argsIdx !== -1 && rest[argsIdx + 1] ? rest[argsIdx + 1] : undefined;
1549
+ return { kind: "mcp.call", server, tool, ...(mcpArgs ? { args: mcpArgs } : {}), ...(agent ? { agent } : {}) };
1550
+ }
1551
+ if (sub === "canary") {
1552
+ let socketOverride;
1553
+ let json = false;
1554
+ const requiredSenses = [];
1555
+ for (let i = 0; i < rest.length; i++) {
1556
+ if (rest[i] === "--socket" && rest[i + 1]) {
1557
+ socketOverride = rest[++i];
1558
+ continue;
1559
+ }
1560
+ if (rest[i] === "--require-sense" && rest[i + 1]) {
1561
+ requiredSenses.push(rest[++i]);
1562
+ continue;
1563
+ }
1564
+ if (rest[i] === "--json") {
1565
+ json = true;
1566
+ continue;
1567
+ }
1568
+ }
1569
+ if (!agent)
1570
+ throw new Error("mcp canary requires --agent <name>");
1571
+ return {
1572
+ kind: "mcp.canary",
1573
+ agent,
1574
+ ...(socketOverride ? { socketOverride } : {}),
1575
+ ...(requiredSenses.length > 0 ? { requiredSenses } : {}),
1576
+ ...(json ? { json: true } : {}),
1577
+ };
1578
+ }
1579
+ if (sub === "doctor") {
1580
+ let socketOverride;
1581
+ let json = false;
1582
+ let hostStallObserved = false;
1583
+ for (let i = 0; i < rest.length; i++) {
1584
+ if (rest[i] === "--socket") {
1585
+ if (!rest[i + 1])
1586
+ throw new Error("mcp doctor requires a value after --socket");
1587
+ socketOverride = rest[++i];
1588
+ continue;
1589
+ }
1590
+ if (rest[i] === "--json") {
1591
+ json = true;
1592
+ continue;
1593
+ }
1594
+ if (rest[i] === "--host-stall-observed") {
1595
+ hostStallObserved = true;
1596
+ continue;
1597
+ }
1598
+ throw new Error(`Unknown mcp doctor flag: ${rest[i]}`);
1599
+ }
1600
+ if (!agent)
1601
+ throw new Error("mcp doctor requires --agent <name>");
1602
+ return {
1603
+ kind: "mcp.doctor",
1604
+ agent,
1605
+ ...(socketOverride ? { socketOverride } : {}),
1606
+ ...(json ? { json: true } : {}),
1607
+ ...(hostStallObserved ? { hostStallObserved: true } : {}),
1608
+ };
1609
+ }
1610
+ throw new Error(`Usage\n${usage()}`);
1611
+ }
1612
+ function inferAgentNameFromRemote(remote) {
1613
+ // Remove trailing slash
1614
+ let name = remote.replace(/\/+$/, "");
1615
+ // Handle SSH URLs (git@host:user/repo) — extract after last / or :
1616
+ const lastSlash = name.lastIndexOf("/");
1617
+ const lastColon = name.lastIndexOf(":");
1618
+ const lastSep = Math.max(lastSlash, lastColon);
1619
+ if (lastSep !== -1) {
1620
+ name = name.slice(lastSep + 1);
1621
+ }
1622
+ // Strip .git suffix
1623
+ name = name.replace(/\.git$/, "");
1624
+ // Strip .ouro suffix
1625
+ name = name.replace(/\.ouro$/, "");
1626
+ return name;
1627
+ }
1628
+ function parseCloneCommand(args) {
1629
+ let remote;
1630
+ let agent;
1631
+ for (let i = 0; i < args.length; i++) {
1632
+ if (args[i] === "--agent" && args[i + 1]) {
1633
+ agent = args[++i];
1634
+ continue;
1635
+ }
1636
+ if (!remote) {
1637
+ remote = args[i];
1638
+ }
1639
+ }
1640
+ if (!remote) {
1641
+ throw new Error("clone requires a remote URL.\nUsage: ouro clone <remote> [--agent <name>]");
1642
+ }
1643
+ return agent
1644
+ ? { kind: "clone", remote, agent }
1645
+ : { kind: "clone", remote };
1646
+ }
1647
+ function parseMcpServeCommand(args) {
1648
+ let agent;
1649
+ let friendId;
1650
+ let socketOverride;
1651
+ // Optional runtime Workbench MCP injection. The path is OPTIONAL: when a
1652
+ // concrete path follows the flag it is carried verbatim; when the flag stands
1653
+ // alone (or is immediately followed by another `--flag`) it is a boolean
1654
+ // opt-in and the daemon self-discovers the installed OuroWorkbenchMCP binary.
1655
+ let workbenchMcp;
1656
+ for (let i = 0; i < args.length; i++) {
1657
+ if (args[i] === "--agent" && args[i + 1]) {
1658
+ agent = args[++i];
1659
+ continue;
1660
+ }
1661
+ if (args[i] === "--friend" && args[i + 1]) {
1662
+ friendId = args[++i];
1663
+ continue;
1664
+ }
1665
+ if (args[i] === "--socket" && args[i + 1]) {
1666
+ socketOverride = args[++i];
1667
+ continue;
1668
+ }
1669
+ if (args[i] === "--workbench-mcp") {
1670
+ const next = args[i + 1];
1671
+ if (next && !next.startsWith("--")) {
1672
+ workbenchMcp = args[++i];
1673
+ }
1674
+ else {
1675
+ workbenchMcp = true;
1676
+ }
1677
+ continue;
1678
+ }
1679
+ }
1680
+ if (!agent)
1681
+ throw new Error("mcp-serve requires --agent <name>");
1682
+ return {
1683
+ kind: "mcp-serve",
1684
+ agent,
1685
+ ...(friendId ? { friendId } : {}),
1686
+ ...(socketOverride ? { socketOverride } : {}),
1687
+ ...(workbenchMcp !== undefined ? { workbenchMcp } : {}),
1688
+ };
1689
+ }
1690
+ function parseAcpServeCommand(args) {
1691
+ const usage = "Usage: ouro acp-serve --agent <name> [--friend-id <id>] [--socket <path>] [--workbench-mcp [path]] [--observe-only]";
1692
+ let agent;
1693
+ let friendId;
1694
+ let socketOverride;
1695
+ let workbenchMcp;
1696
+ let observeOnly = false;
1697
+ for (let i = 0; i < args.length; i++) {
1698
+ const token = args[i];
1699
+ if (token === "--workbench-mcp") {
1700
+ const next = args[i + 1];
1701
+ if (next && !next.startsWith("--"))
1702
+ workbenchMcp = args[++i];
1703
+ else
1704
+ workbenchMcp = true;
1705
+ continue;
1706
+ }
1707
+ if (token === "--observe-only") {
1708
+ observeOnly = true;
1709
+ continue;
1710
+ }
1711
+ const next = args[i + 1];
1712
+ if (token === "--agent" || token === "--friend-id" || token === "--socket") {
1713
+ if (!next || next.startsWith("--"))
1714
+ throw new Error(`${token} requires a value\n${usage}`);
1715
+ if (token === "--agent")
1716
+ agent = next;
1717
+ else if (token === "--friend-id")
1718
+ friendId = next;
1719
+ else
1720
+ socketOverride = next;
1721
+ i += 1;
1722
+ continue;
1723
+ }
1724
+ throw new Error(usage);
1725
+ }
1726
+ if (!agent)
1727
+ throw new Error(`acp-serve requires --agent <name>\n${usage}`);
1728
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(agent))
1729
+ throw new Error("acp-serve requires a safe agent name");
1730
+ return {
1731
+ kind: "acp-serve",
1732
+ agent,
1733
+ ...(friendId ? { friendId } : {}),
1734
+ ...(socketOverride ? { socketOverride } : {}),
1735
+ ...(workbenchMcp !== undefined ? { workbenchMcp } : {}),
1736
+ ...(observeOnly ? { observeOnly: true } : {}),
1737
+ };
1738
+ }
1739
+ function parseSetupCommand(args) {
1740
+ let tool;
1741
+ let agent;
1742
+ for (let i = 0; i < args.length; i++) {
1743
+ if (args[i] === "--tool" && args[i + 1]) {
1744
+ tool = args[++i];
1745
+ continue;
1746
+ }
1747
+ if (args[i] === "--agent" && args[i + 1]) {
1748
+ agent = args[++i];
1749
+ continue;
1750
+ }
1751
+ }
1752
+ if (args.includes("--agent") && !agent)
1753
+ throw new Error("setup requires --agent <name>");
1754
+ if (!tool)
1755
+ throw new Error("setup requires --tool (claude-code | codex)");
1756
+ if (tool !== "claude-code" && tool !== "codex")
1757
+ throw new Error(`Unknown tool: ${tool}. Supported: claude-code, codex`);
1758
+ return { kind: "setup", tool, ...(agent ? { agent } : {}) };
1759
+ }
1760
+ function parsePluginCommand(args) {
1761
+ const subcommand = args[0];
1762
+ if (!subcommand) {
1763
+ throw new Error("plugin requires a subcommand: install <source> | list | remove <pluginId>");
1764
+ }
1765
+ let agent;
1766
+ let version;
1767
+ const positional = [];
1768
+ for (let i = 1; i < args.length; i++) {
1769
+ if (args[i] === "--agent" && args[i + 1]) {
1770
+ agent = args[++i];
1771
+ continue;
1772
+ }
1773
+ if (args[i] === "--version" && args[i + 1]) {
1774
+ version = args[++i];
1775
+ continue;
1776
+ }
1777
+ positional.push(args[i]);
1778
+ }
1779
+ if (subcommand === "install") {
1780
+ const source = positional[0];
1781
+ if (!source) {
1782
+ throw new Error("plugin install requires a source (e.g. github:ourostack/ouroboros-skills:plugins/desk)");
1783
+ }
1784
+ return {
1785
+ kind: "plugin.install",
1786
+ source,
1787
+ ...(agent ? { agent } : {}),
1788
+ ...(version ? { version } : {}),
1789
+ };
1790
+ }
1791
+ if (subcommand === "list") {
1792
+ return { kind: "plugin.list", ...(agent ? { agent } : {}) };
1793
+ }
1794
+ if (subcommand === "remove") {
1795
+ const pluginId = positional[0];
1796
+ if (!pluginId) {
1797
+ throw new Error("plugin remove requires a plugin id");
1798
+ }
1799
+ return {
1800
+ kind: "plugin.remove",
1801
+ pluginId,
1802
+ ...(agent ? { agent } : {}),
1803
+ };
1804
+ }
1805
+ throw new Error(`Unknown plugin subcommand: ${subcommand}. Supported: install | list | remove`);
1806
+ }
1807
+ function parseMigrateToDeskCommand(args) {
1808
+ let agent;
1809
+ let root;
1810
+ let force = false;
1811
+ let dryRun = false;
1812
+ for (let i = 0; i < args.length; i += 1) {
1813
+ const token = args[i];
1814
+ if (token === "--agent" && args[i + 1]) {
1815
+ agent = args[++i];
1816
+ continue;
1817
+ }
1818
+ if (token === "--root" && args[i + 1]) {
1819
+ root = args[++i];
1820
+ continue;
1821
+ }
1822
+ if (token === "--force") {
1823
+ force = true;
1824
+ continue;
1825
+ }
1826
+ if (token === "--dry-run") {
1827
+ dryRun = true;
1828
+ continue;
1829
+ }
1830
+ throw new Error("Usage: ouro migrate-to-desk --agent <name> [--root <path>] [--force] [--dry-run]");
1831
+ }
1832
+ if (!agent) {
1833
+ throw new Error("Usage: ouro migrate-to-desk --agent <name> [--root <path>] [--force] [--dry-run]");
1834
+ }
1835
+ return {
1836
+ kind: "migrate-to-desk",
1837
+ agent,
1838
+ ...(root ? { root } : {}),
1839
+ ...(force ? { force: true } : {}),
1840
+ ...(dryRun ? { dryRun: true } : {}),
1841
+ };
1842
+ }
1843
+ function parseBlueBubblesCommand(args) {
1844
+ const subcommand = args[0];
1845
+ if (subcommand === "host") {
1846
+ const action = args[1];
1847
+ const usageText = "Usage: ouro bluebubbles host <install|status|repair|remove|collect> [--username <name> --uid <uid> --home <path>] [--request-id <id>] [--json]";
1848
+ if (action === "collect") {
1849
+ let requestId;
1850
+ let json = false;
1851
+ for (let index = 2; index < args.length; index += 1) {
1852
+ if (args[index] === "--request-id" && args[index + 1]) {
1853
+ requestId = args[++index];
1854
+ }
1855
+ else if (args[index] === "--json") {
1856
+ json = true;
1857
+ }
1858
+ else {
1859
+ throw new Error(usageText);
1860
+ }
1861
+ }
1862
+ if (!requestId)
1863
+ throw new Error(`${usageText}\ncollect requires --request-id <id>`);
1864
+ return { kind: "bluebubbles.host.collect", requestId, ...(json ? { json: true } : {}) };
1865
+ }
1866
+ if (action !== "install" && action !== "status" && action !== "repair" && action !== "remove") {
1867
+ throw new Error(usageText);
1868
+ }
1869
+ let username;
1870
+ let uid;
1871
+ let homeDir;
1872
+ let json = false;
1873
+ for (let index = 2; index < args.length; index += 1) {
1874
+ const token = args[index];
1875
+ if (token === "--username" && args[index + 1])
1876
+ username = args[++index];
1877
+ else if (token === "--uid" && args[index + 1]) {
1878
+ const value = Number(args[++index]);
1879
+ if (!Number.isInteger(value))
1880
+ throw new Error(`${usageText}\n--uid must be an integer`);
1881
+ uid = value;
1882
+ }
1883
+ else if (token === "--home" && args[index + 1])
1884
+ homeDir = args[++index];
1885
+ else if (token === "--json")
1886
+ json = true;
1887
+ else
1888
+ throw new Error(usageText);
1889
+ }
1890
+ const targetFields = [username, uid, homeDir].filter((value) => value !== undefined).length;
1891
+ if (targetFields !== 0 && targetFields !== 3) {
1892
+ throw new Error(`${usageText}\ncross-user setup requires --username, --uid, and --home together`);
1893
+ }
1894
+ return {
1895
+ kind: "bluebubbles.host",
1896
+ action,
1897
+ ...(targetFields === 3 ? { target: { username: username, uid: uid, homeDir: homeDir } } : {}),
1898
+ ...(json ? { json: true } : {}),
1899
+ };
1900
+ }
1901
+ if (subcommand !== "replay" && subcommand !== "context-smoke") {
1902
+ throw new Error(`Usage\n${usage()}`);
1903
+ }
1904
+ let agent;
1905
+ let messageGuid;
1906
+ let eventType = "new-message";
1907
+ let persist = false;
1908
+ let json = false;
1909
+ for (let i = 1; i < args.length; i += 1) {
1910
+ if (args[i] === "--agent" && args[i + 1]) {
1911
+ agent = args[++i];
1912
+ continue;
1913
+ }
1914
+ if (args[i] === "--message-guid" && args[i + 1]) {
1915
+ messageGuid = args[++i];
1916
+ continue;
1917
+ }
1918
+ if (args[i] === "--event-type" && args[i + 1]) {
1919
+ const candidate = args[++i];
1920
+ if (candidate !== "new-message" && candidate !== "updated-message") {
1921
+ throw new Error("bluebubbles replay --event-type must be new-message or updated-message");
1922
+ }
1923
+ eventType = candidate;
1924
+ continue;
1925
+ }
1926
+ if (args[i] === "--persist") {
1927
+ persist = true;
1928
+ continue;
1929
+ }
1930
+ if (args[i] === "--json") {
1931
+ json = true;
1932
+ continue;
1933
+ }
1934
+ }
1935
+ if (!messageGuid)
1936
+ throw new Error(`bluebubbles ${subcommand} requires --message-guid <guid>`);
1937
+ if (subcommand === "context-smoke") {
1938
+ return {
1939
+ kind: "bluebubbles.context-smoke",
1940
+ ...(agent ? { agent } : {}),
1941
+ messageGuid,
1942
+ ...(persist ? { persist: true } : {}),
1943
+ ...(json ? { json: true } : {}),
1944
+ };
1945
+ }
1946
+ return {
1947
+ kind: "bluebubbles.replay",
1948
+ ...(agent ? { agent } : {}),
1949
+ messageGuid,
1950
+ eventType,
1951
+ ...(json ? { json: true } : {}),
1952
+ };
1953
+ }
1954
+ const RSVP_USAGE = "Usage: ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...";
1955
+ function isRsvpMode(value) {
1956
+ return value === "shadow" || value === "live";
1957
+ }
1958
+ function isRsvpCutoverAction(value) {
1959
+ return value === "check" || value === "quarantine-launchd" || value === "retire-legacy-send-config";
1960
+ }
1961
+ function isRsvpSmokeMode(value) {
1962
+ return value === "preflight" || value === "live";
1963
+ }
1964
+ function isRsvpSmokeSurface(value) {
1965
+ return value === "bluebubbles";
1966
+ }
1967
+ function rsvpPath(value, label) {
1968
+ const trimmed = value.trim();
1969
+ if (!trimmed || /[\r\n\t]/.test(trimmed))
1970
+ throw new Error(`rsvp ${label} requires a non-empty path`);
1971
+ return trimmed;
1972
+ }
1973
+ function rsvpText(value, label) {
1974
+ const trimmed = value.trim();
1975
+ if (!trimmed || /[\r\n\t]/.test(trimmed))
1976
+ throw new Error(`rsvp ${label} requires non-empty text`);
1977
+ return trimmed;
1978
+ }
1979
+ function rsvpHabitName(value, label) {
1980
+ const trimmed = rsvpText(value, label);
1981
+ if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(trimmed) || !trimmed.startsWith("rsvp-")) {
1982
+ throw new Error(`rsvp ${label} must start with rsvp- and contain only letters, numbers, underscores, or hyphens`);
1983
+ }
1984
+ return trimmed;
1985
+ }
1986
+ function validRsvpCronCadence(value) {
1987
+ const fields = value.trim().split(/\s+/);
1988
+ return fields.length === 5 && fields.every((field) => field.length > 0);
1989
+ }
1990
+ function parseRsvpCommand(args) {
1991
+ const subcommand = args[0];
1992
+ if (!subcommand)
1993
+ throw new Error(RSVP_USAGE);
1994
+ if (subcommand === "config") {
1995
+ const nested = args[1];
1996
+ if (nested !== "import-legacy")
1997
+ throw new Error("Usage: ouro rsvp config import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]");
1998
+ return parseRsvpImportLegacyCommand(args.slice(2), "rsvp.config.import-legacy");
1999
+ }
2000
+ if (subcommand === "habit") {
2001
+ const nested = args[1];
2002
+ if (nested !== "stage")
2003
+ throw new Error("Usage: ouro rsvp habit stage [--agent <name>] [--name <rsvp-name>] [--title <title>] [--report-title <title>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]");
2004
+ return parseRsvpHabitStageCommand(args.slice(2));
2005
+ }
2006
+ if (subcommand === "doctor")
2007
+ return parseRsvpDoctorCommand(args.slice(1));
2008
+ if (subcommand === "incident")
2009
+ return parseRsvpIncidentCommand(args.slice(1));
2010
+ if (subcommand === "cutover")
2011
+ return parseRsvpCutoverCommand(args.slice(1));
2012
+ if (subcommand === "legacy-render")
2013
+ return parseRsvpLegacyRenderCommand(args.slice(1));
2014
+ if (subcommand === "replay")
2015
+ return parseRsvpReplayCommand(args.slice(1));
2016
+ if (subcommand === "import-legacy")
2017
+ return parseRsvpImportLegacyCommand(args.slice(1), "rsvp.import-legacy");
2018
+ if (subcommand === "refresh")
2019
+ return parseRsvpRefreshCommand(args.slice(1));
2020
+ if (subcommand === "compare")
2021
+ return parseRsvpCompareCommand(args.slice(1));
2022
+ if (subcommand === "smoke")
2023
+ return parseRsvpSmokeCommand(args.slice(1));
2024
+ throw new Error(RSVP_USAGE);
2025
+ }
2026
+ function parseRsvpDoctorCommand(args) {
2027
+ const { agent, rest } = extractAgentFlag(args);
2028
+ let json = false;
2029
+ let strict = false;
2030
+ let outputPath;
2031
+ for (let i = 0; i < rest.length; i += 1) {
2032
+ const token = rest[i];
2033
+ if (token === "--json") {
2034
+ json = true;
2035
+ continue;
2036
+ }
2037
+ if (token === "--strict") {
2038
+ strict = true;
2039
+ continue;
2040
+ }
2041
+ if (token === "--output" && rest[i + 1]) {
2042
+ outputPath = rsvpPath(rest[++i], "--output");
2043
+ continue;
2044
+ }
2045
+ throw new Error("Usage: ouro rsvp doctor [--agent <name>] [--strict] [--output <path>] [--json]");
2046
+ }
2047
+ return {
2048
+ kind: "rsvp.doctor",
2049
+ ...(agent ? { agent } : {}),
2050
+ ...(json ? { json: true } : {}),
2051
+ ...(strict ? { strict: true } : {}),
2052
+ ...(outputPath ? { outputPath } : {}),
2053
+ };
2054
+ }
2055
+ function parseRsvpIncidentCommand(args) {
2056
+ const { agent, rest } = extractAgentFlag(args);
2057
+ let json = false;
2058
+ let outputPath;
2059
+ for (let i = 0; i < rest.length; i += 1) {
2060
+ const token = rest[i];
2061
+ if (token === "--json") {
2062
+ json = true;
2063
+ continue;
2064
+ }
2065
+ if (token === "--output" && rest[i + 1]) {
2066
+ outputPath = rsvpPath(rest[++i], "--output");
2067
+ continue;
2068
+ }
2069
+ throw new Error("Usage: ouro rsvp incident [--agent <name>] [--output <path>] [--json]");
2070
+ }
2071
+ return {
2072
+ kind: "rsvp.incident",
2073
+ ...(agent ? { agent } : {}),
2074
+ ...(json ? { json: true } : {}),
2075
+ ...(outputPath ? { outputPath } : {}),
2076
+ };
2077
+ }
2078
+ function parseRsvpCutoverCommand(args) {
2079
+ const { agent, rest } = extractAgentFlag(args);
2080
+ let legacyRoot;
2081
+ let action;
2082
+ let yes = false;
2083
+ let json = false;
2084
+ let outputPath;
2085
+ for (let i = 0; i < rest.length; i += 1) {
2086
+ const token = rest[i];
2087
+ if (token === "--legacy-root" && rest[i + 1]) {
2088
+ legacyRoot = rsvpPath(rest[++i], "--legacy-root");
2089
+ continue;
2090
+ }
2091
+ if (token === "--action" && rest[i + 1]) {
2092
+ const value = rest[++i];
2093
+ if (!isRsvpCutoverAction(value))
2094
+ throw new Error("rsvp cutover --action must be check, quarantine-launchd, or retire-legacy-send-config");
2095
+ action = value;
2096
+ continue;
2097
+ }
2098
+ if (token === "--yes") {
2099
+ yes = true;
2100
+ continue;
2101
+ }
2102
+ if (token === "--json") {
2103
+ json = true;
2104
+ continue;
2105
+ }
2106
+ if (token === "--output" && rest[i + 1]) {
2107
+ outputPath = rsvpPath(rest[++i], "--output");
2108
+ continue;
2109
+ }
2110
+ throw new Error("Usage: ouro rsvp cutover [--agent <name>] --legacy-root <path> --action check|quarantine-launchd|retire-legacy-send-config [--yes] [--output <path>] [--json]");
2111
+ }
2112
+ if (!legacyRoot)
2113
+ throw new Error("rsvp cutover requires --legacy-root <path>");
2114
+ if (!action)
2115
+ throw new Error("rsvp cutover requires --action check|quarantine-launchd|retire-legacy-send-config");
2116
+ return {
2117
+ kind: "rsvp.cutover",
2118
+ ...(agent ? { agent } : {}),
2119
+ legacyRoot,
2120
+ action,
2121
+ ...(yes ? { yes: true } : {}),
2122
+ ...(json ? { json: true } : {}),
2123
+ ...(outputPath ? { outputPath } : {}),
2124
+ };
2125
+ }
2126
+ function parseRsvpLegacyRenderCommand(args) {
2127
+ const { agent, rest } = extractAgentFlag(args);
2128
+ let legacyRoot;
2129
+ let json = false;
2130
+ let outputPath;
2131
+ for (let i = 0; i < rest.length; i += 1) {
2132
+ const token = rest[i];
2133
+ if (token === "--legacy-root" && rest[i + 1]) {
2134
+ legacyRoot = rsvpPath(rest[++i], "--legacy-root");
2135
+ continue;
2136
+ }
2137
+ if (token === "--json") {
2138
+ json = true;
2139
+ continue;
2140
+ }
2141
+ if (token === "--output" && rest[i + 1]) {
2142
+ outputPath = rsvpPath(rest[++i], "--output");
2143
+ continue;
2144
+ }
2145
+ throw new Error("Usage: ouro rsvp legacy-render --legacy-root <path> [--agent <name>] [--output <path>] [--json]");
2146
+ }
2147
+ if (!legacyRoot)
2148
+ throw new Error("rsvp legacy-render requires --legacy-root <path>");
2149
+ return {
2150
+ kind: "rsvp.legacy-render",
2151
+ ...(agent ? { agent } : {}),
2152
+ legacyRoot,
2153
+ ...(json ? { json: true } : {}),
2154
+ ...(outputPath ? { outputPath } : {}),
2155
+ };
2156
+ }
2157
+ function parseRsvpReplayCommand(args) {
2158
+ const { agent, rest } = extractAgentFlag(args);
2159
+ let fixturePath;
2160
+ let json = false;
2161
+ let outputPath;
2162
+ for (let i = 0; i < rest.length; i += 1) {
2163
+ const token = rest[i];
2164
+ if (token === "--fixture" && rest[i + 1]) {
2165
+ fixturePath = rsvpPath(rest[++i], "--fixture");
2166
+ continue;
2167
+ }
2168
+ if (token === "--json") {
2169
+ json = true;
2170
+ continue;
2171
+ }
2172
+ if (token === "--output" && rest[i + 1]) {
2173
+ outputPath = rsvpPath(rest[++i], "--output");
2174
+ continue;
2175
+ }
2176
+ throw new Error("Usage: ouro rsvp replay [--agent <name>] --fixture <path> [--output <path>] [--json]");
2177
+ }
2178
+ if (!fixturePath)
2179
+ throw new Error("rsvp replay requires --fixture <path>");
2180
+ return {
2181
+ kind: "rsvp.replay",
2182
+ ...(agent ? { agent } : {}),
2183
+ fixturePath,
2184
+ ...(json ? { json: true } : {}),
2185
+ ...(outputPath ? { outputPath } : {}),
2186
+ };
2187
+ }
2188
+ function parseRsvpImportLegacyCommand(args, kind) {
2189
+ const { agent, rest } = extractAgentFlag(args);
2190
+ let legacyRoot;
2191
+ let mode;
2192
+ let yes = false;
2193
+ let json = false;
2194
+ let outputPath;
2195
+ for (let i = 0; i < rest.length; i += 1) {
2196
+ const token = rest[i];
2197
+ if (token === "--legacy-root" && rest[i + 1]) {
2198
+ legacyRoot = rsvpPath(rest[++i], "--legacy-root");
2199
+ continue;
2200
+ }
2201
+ if (token === "--mode" && rest[i + 1]) {
2202
+ const value = rest[++i];
2203
+ if (!isRsvpMode(value))
2204
+ throw new Error("rsvp import-legacy --mode must be shadow or live");
2205
+ mode = value;
2206
+ continue;
2207
+ }
2208
+ if (token === "--yes") {
2209
+ yes = true;
2210
+ continue;
2211
+ }
2212
+ if (token === "--json") {
2213
+ json = true;
2214
+ continue;
2215
+ }
2216
+ if (token === "--output" && rest[i + 1]) {
2217
+ outputPath = rsvpPath(rest[++i], "--output");
2218
+ continue;
2219
+ }
2220
+ throw new Error("Usage: ouro rsvp config import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]");
2221
+ }
2222
+ if (!legacyRoot)
2223
+ throw new Error("rsvp import-legacy requires --legacy-root <path>");
2224
+ if (!mode)
2225
+ throw new Error("rsvp import-legacy requires --mode shadow|live");
2226
+ return {
2227
+ kind,
2228
+ ...(agent ? { agent } : {}),
2229
+ legacyRoot,
2230
+ mode,
2231
+ ...(yes ? { yes: true } : {}),
2232
+ ...(json ? { json: true } : {}),
2233
+ ...(outputPath ? { outputPath } : {}),
2234
+ };
2235
+ }
2236
+ function parseRsvpHabitStageCommand(args) {
2237
+ const { agent, rest } = extractAgentFlag(args);
2238
+ let habitName;
2239
+ let title;
2240
+ let reportTitle;
2241
+ let mode;
2242
+ let cadence;
2243
+ let json = false;
2244
+ let outputPath;
2245
+ for (let i = 0; i < rest.length; i += 1) {
2246
+ const token = rest[i];
2247
+ if (token === "--mode" && rest[i + 1]) {
2248
+ const value = rest[++i];
2249
+ if (!isRsvpMode(value))
2250
+ throw new Error("rsvp habit stage --mode must be shadow or live");
2251
+ mode = value;
2252
+ continue;
2253
+ }
2254
+ if (token === "--name" && rest[i + 1]) {
2255
+ habitName = rsvpHabitName(rest[++i], "--name");
2256
+ continue;
2257
+ }
2258
+ if (token === "--title" && rest[i + 1]) {
2259
+ title = rsvpText(rest[++i], "--title");
2260
+ continue;
2261
+ }
2262
+ if (token === "--report-title" && rest[i + 1]) {
2263
+ reportTitle = rsvpText(rest[++i], "--report-title");
2264
+ continue;
2265
+ }
2266
+ if (token === "--cadence" && rest[i + 1]) {
2267
+ cadence = rest[++i];
2268
+ continue;
2269
+ }
2270
+ if (token === "--json") {
2271
+ json = true;
2272
+ continue;
2273
+ }
2274
+ if (token === "--output" && rest[i + 1]) {
2275
+ outputPath = rsvpPath(rest[++i], "--output");
2276
+ continue;
2277
+ }
2278
+ throw new Error("Usage: ouro rsvp habit stage [--agent <name>] [--name <rsvp-name>] [--title <title>] [--report-title <title>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]");
2279
+ }
2280
+ if (!mode)
2281
+ throw new Error("rsvp habit stage requires --mode shadow|live");
2282
+ if (!cadence || !validRsvpCronCadence(cadence))
2283
+ throw new Error("rsvp habit stage --cadence must be a five-field cron cadence");
2284
+ return {
2285
+ kind: "rsvp.habit.stage",
2286
+ ...(agent ? { agent } : {}),
2287
+ ...(habitName ? { habitName } : {}),
2288
+ ...(title ? { title } : {}),
2289
+ ...(reportTitle ? { reportTitle } : {}),
2290
+ mode,
2291
+ cadence,
2292
+ ...(json ? { json: true } : {}),
2293
+ ...(outputPath ? { outputPath } : {}),
2294
+ };
2295
+ }
2296
+ function parseRsvpRefreshCommand(args) {
2297
+ const { agent, rest } = extractAgentFlag(args);
2298
+ let habitName;
2299
+ let mode = "shadow";
2300
+ let noSend = false;
2301
+ let allowSend = false;
2302
+ let json = false;
2303
+ let outputPath;
2304
+ for (let i = 0; i < rest.length; i += 1) {
2305
+ const token = rest[i];
2306
+ if (token === "--mode" && rest[i + 1]) {
2307
+ const value = rest[++i];
2308
+ if (!isRsvpMode(value))
2309
+ throw new Error("rsvp refresh --mode must be shadow or live");
2310
+ mode = value;
2311
+ continue;
2312
+ }
2313
+ if (token === "--habit" && rest[i + 1]) {
2314
+ habitName = rsvpHabitName(rest[++i], "--habit");
2315
+ continue;
2316
+ }
2317
+ if (token === "--no-send") {
2318
+ noSend = true;
2319
+ continue;
2320
+ }
2321
+ if (token === "--allow-send") {
2322
+ allowSend = true;
2323
+ continue;
2324
+ }
2325
+ if (token === "--json") {
2326
+ json = true;
2327
+ continue;
2328
+ }
2329
+ if (token === "--output" && rest[i + 1]) {
2330
+ outputPath = rsvpPath(rest[++i], "--output");
2331
+ continue;
2332
+ }
2333
+ throw new Error("Usage: ouro rsvp refresh [--agent <name>] [--habit <rsvp-name>] --mode shadow|live [--no-send|--allow-send] [--output <path>] [--json]");
2334
+ }
2335
+ if (noSend && allowSend)
2336
+ throw new Error("rsvp refresh cannot combine --allow-send and --no-send");
2337
+ if (mode === "shadow" && allowSend)
2338
+ throw new Error("rsvp refresh --mode shadow cannot use --allow-send; use --no-send or omit send flags");
2339
+ if (mode === "live" && !allowSend)
2340
+ throw new Error("rsvp refresh --mode live requires --allow-send, or use --no-send for a dry run");
2341
+ return {
2342
+ kind: "rsvp.refresh",
2343
+ ...(agent ? { agent } : {}),
2344
+ ...(habitName ? { habitName } : {}),
2345
+ mode,
2346
+ ...(noSend ? { noSend: true } : {}),
2347
+ ...(allowSend ? { allowSend: true } : {}),
2348
+ ...(json ? { json: true } : {}),
2349
+ ...(outputPath ? { outputPath } : {}),
2350
+ };
2351
+ }
2352
+ function parseRsvpCompareCommand(args) {
2353
+ const { agent, rest } = extractAgentFlag(args);
2354
+ let nativePath;
2355
+ let legacyPath;
2356
+ let json = false;
2357
+ let outputPath;
2358
+ for (let i = 0; i < rest.length; i += 1) {
2359
+ const token = rest[i];
2360
+ if (token === "--native" && rest[i + 1]) {
2361
+ nativePath = rsvpPath(rest[++i], "--native");
2362
+ continue;
2363
+ }
2364
+ if (token === "--legacy" && rest[i + 1]) {
2365
+ legacyPath = rsvpPath(rest[++i], "--legacy");
2366
+ continue;
2367
+ }
2368
+ if (token === "--json") {
2369
+ json = true;
2370
+ continue;
2371
+ }
2372
+ if (token === "--output" && rest[i + 1]) {
2373
+ outputPath = rsvpPath(rest[++i], "--output");
2374
+ continue;
2375
+ }
2376
+ throw new Error("Usage: ouro rsvp compare [--agent <name>] --native <path> --legacy <path> [--output <path>] [--json]");
2377
+ }
2378
+ if (!nativePath)
2379
+ throw new Error("rsvp compare requires --native <path>");
2380
+ if (!legacyPath)
2381
+ throw new Error("rsvp compare requires --legacy <path>");
2382
+ return {
2383
+ kind: "rsvp.compare",
2384
+ ...(agent ? { agent } : {}),
2385
+ nativePath,
2386
+ legacyPath,
2387
+ ...(json ? { json: true } : {}),
2388
+ ...(outputPath ? { outputPath } : {}),
2389
+ };
2390
+ }
2391
+ function parseRsvpSmokeCommand(args) {
2392
+ const { agent, rest } = extractAgentFlag(args);
2393
+ let mode = "preflight";
2394
+ let surface;
2395
+ let question;
2396
+ let allowSend = false;
2397
+ let json = false;
2398
+ let outputPath;
2399
+ let replayOutputPath;
2400
+ for (let i = 0; i < rest.length; i += 1) {
2401
+ const token = rest[i];
2402
+ if (token === "--mode" && rest[i + 1]) {
2403
+ const value = rest[++i];
2404
+ if (!isRsvpSmokeMode(value))
2405
+ throw new Error("rsvp smoke --mode must be preflight or live");
2406
+ mode = value;
2407
+ continue;
2408
+ }
2409
+ if (token === "--surface" && rest[i + 1]) {
2410
+ const value = rest[++i];
2411
+ if (!isRsvpSmokeSurface(value))
2412
+ throw new Error("rsvp smoke --surface must be bluebubbles");
2413
+ surface = value;
2414
+ continue;
2415
+ }
2416
+ if (token === "--question" && rest[i + 1]) {
2417
+ question = rest[++i];
2418
+ continue;
2419
+ }
2420
+ if (token === "--allow-send") {
2421
+ allowSend = true;
2422
+ continue;
2423
+ }
2424
+ if (token === "--json") {
2425
+ json = true;
2426
+ continue;
2427
+ }
2428
+ if (token === "--output" && rest[i + 1]) {
2429
+ outputPath = rsvpPath(rest[++i], "--output");
2430
+ continue;
2431
+ }
2432
+ if (token === "--replay-output" && rest[i + 1]) {
2433
+ replayOutputPath = rsvpPath(rest[++i], "--replay-output");
2434
+ continue;
2435
+ }
2436
+ throw new Error("Usage: ouro rsvp smoke [--agent <name>] --mode preflight|live --surface bluebubbles [--question <text>] [--allow-send] [--output <path>] [--replay-output <path>] [--json]");
2437
+ }
2438
+ if (!surface)
2439
+ throw new Error("rsvp smoke requires --surface bluebubbles");
2440
+ if (mode === "live" && !allowSend)
2441
+ throw new Error("rsvp smoke --mode live requires --allow-send");
2442
+ return {
2443
+ kind: "rsvp.smoke",
2444
+ ...(agent ? { agent } : {}),
2445
+ mode,
2446
+ surface,
2447
+ ...(question ? { question } : {}),
2448
+ ...(allowSend ? { allowSend: true } : {}),
2449
+ ...(json ? { json: true } : {}),
2450
+ ...(outputPath ? { outputPath } : {}),
2451
+ ...(replayOutputPath ? { replayOutputPath } : {}),
2452
+ };
2453
+ }
2454
+ function parseNervesReviewCommand(args) {
2455
+ const { agent, rest } = extractAgentFlag(args);
2456
+ let processName = core_1.DEFAULT_NERVES_PROCESS;
2457
+ let component;
2458
+ let event;
2459
+ let level;
2460
+ let since;
2461
+ let limit;
2462
+ let json = false;
2463
+ for (let i = 0; i < rest.length; i += 1) {
2464
+ const token = rest[i];
2465
+ const next = rest[i + 1];
2466
+ if (token === "--json") {
2467
+ json = true;
2468
+ continue;
2469
+ }
2470
+ if ((token === "--process" || token === "--component" || token === "--event" || token === "--level" || token === "--since" || token === "--limit") && next) {
2471
+ if (token === "--process")
2472
+ processName = next;
2473
+ if (token === "--component")
2474
+ component = next;
2475
+ if (token === "--event")
2476
+ event = next;
2477
+ if (token === "--level")
2478
+ level = next;
2479
+ if (token === "--since")
2480
+ since = next;
2481
+ if (token === "--limit") {
2482
+ const parsed = Number.parseInt(next, 10);
2483
+ if (!Number.isInteger(parsed) || String(parsed) !== next || parsed < 1 || parsed > 1000) {
2484
+ throw new Error("--limit must be an integer between 1 and 1000");
2485
+ }
2486
+ limit = parsed;
2487
+ }
2488
+ i += 1;
2489
+ continue;
2490
+ }
2491
+ throw new Error(`Usage\n${usage()}`);
2492
+ }
2493
+ return {
2494
+ kind: "nerves-review",
2495
+ ...(agent ? { agent } : {}),
2496
+ process: processName,
2497
+ ...(component ? { component } : {}),
2498
+ ...(event ? { event } : {}),
2499
+ ...(level ? { level } : {}),
2500
+ ...(since ? { since } : {}),
2501
+ ...(limit ? { limit } : {}),
2502
+ json,
2503
+ };
2504
+ }
2505
+ function parsePrivateCommand(args) {
2506
+ const [subcommand] = args;
2507
+ if (subcommand === "status") {
2508
+ const { agent, rest } = extractAgentFlag(args.slice(1));
2509
+ let json = false;
2510
+ for (const token of rest) {
2511
+ if (token === "--json") {
2512
+ json = true;
2513
+ }
2514
+ else {
2515
+ throw new Error("Usage: ouro private status [--agent <name>] [--json]");
2516
+ }
2517
+ }
2518
+ return { kind: "private.status", ...(agent ? { agent } : {}), json };
2519
+ }
2520
+ if (subcommand !== "decisions") {
2521
+ throw new Error("Usage: ouro private decisions [--agent <name>] [--limit <n>] [--json] OR ouro private status [--agent <name>] [--json]");
2522
+ }
2523
+ const { agent, rest } = extractAgentFlag(args.slice(1));
2524
+ let limit = 20;
2525
+ let json = false;
2526
+ for (let i = 0; i < rest.length; i += 1) {
2527
+ const token = rest[i];
2528
+ const next = rest[i + 1];
2529
+ if (token === "--json") {
2530
+ json = true;
2531
+ continue;
2532
+ }
2533
+ if (token === "--limit" && next) {
2534
+ const parsed = Number.parseInt(next, 10);
2535
+ if (!Number.isInteger(parsed) || String(parsed) !== next || parsed < 1 || parsed > 1000) {
2536
+ throw new Error("private decisions --limit must be an integer between 1 and 1000");
2537
+ }
2538
+ limit = parsed;
2539
+ i += 1;
2540
+ continue;
2541
+ }
2542
+ throw new Error("Usage: ouro private decisions [--agent <name>] [--limit <n>] [--json]");
2543
+ }
2544
+ return {
2545
+ kind: "private.decisions",
2546
+ ...(agent ? { agent } : {}),
2547
+ limit,
2548
+ json,
2549
+ };
2550
+ }
2551
+ // ── Main dispatch ──
2552
+ function parseOuroCommand(args) {
2553
+ const [head, second] = args;
2554
+ if (!head)
2555
+ return { kind: "daemon.up" };
2556
+ // ── help command ──
2557
+ if (head === "help") {
2558
+ const command = helpCommandName(args.slice(1));
2559
+ return command ? { kind: "help", command } : { kind: "help" };
2560
+ }
2561
+ // ── per-command --help ──
2562
+ if (args.includes("--help") || args.includes("-h")) {
2563
+ const command = helpCommandName(args);
2564
+ return command ? { kind: "help", command } : { kind: "help" };
2565
+ }
2566
+ if (head === "--agent" && second) {
2567
+ return parseOuroCommand(args.slice(2));
2568
+ }
2569
+ if (head === "hook") {
2570
+ const hookArgs = args.slice(1);
2571
+ let event;
2572
+ let hookAgent;
2573
+ for (let i = 0; i < hookArgs.length; i++) {
2574
+ if (hookArgs[i] === "--agent" && hookArgs[i + 1]) {
2575
+ hookAgent = hookArgs[++i];
2576
+ continue;
2577
+ }
2578
+ /* v8 ignore start -- false branch: extra positional args after event are ignored */
2579
+ if (!event) {
2580
+ event = hookArgs[i];
2581
+ }
2582
+ /* v8 ignore stop */
2583
+ }
2584
+ if (!event)
2585
+ throw new Error("hook requires an event name (session-start, stop, post-tool-use)");
2586
+ if (!hookAgent)
2587
+ throw new Error("hook requires --agent <name>");
2588
+ return { kind: "hook", event, agent: hookAgent };
2589
+ }
2590
+ if (head === "up") {
2591
+ const noRepair = args.includes("--no-repair");
2592
+ const latest = args.includes("--latest");
2593
+ return {
2594
+ kind: "daemon.up",
2595
+ ...(noRepair ? { noRepair: true } : {}),
2596
+ ...(latest ? { latest: true } : {}),
2597
+ };
2598
+ }
2599
+ if (head === "dev") {
2600
+ const devArgs = args.slice(1);
2601
+ let repoPath;
2602
+ let clone = false;
2603
+ let clonePath;
2604
+ for (let i = 0; i < devArgs.length; i++) {
2605
+ if (devArgs[i] === "--repo-path" && devArgs[i + 1]) {
2606
+ repoPath = devArgs[++i];
2607
+ continue;
2608
+ }
2609
+ if (devArgs[i] === "--clone") {
2610
+ clone = true;
2611
+ continue;
2612
+ }
2613
+ if (devArgs[i] === "--clone-path" && devArgs[i + 1]) {
2614
+ clonePath = devArgs[++i];
2615
+ continue;
2616
+ }
2617
+ }
2618
+ return { kind: "daemon.dev", repoPath, clone, clonePath };
2619
+ }
2620
+ if (head === "rollback")
2621
+ return { kind: "rollback", ...(second ? { version: second } : {}) };
2622
+ if (head === "versions")
2623
+ return { kind: "versions" };
2624
+ if (head === "stop" || head === "down")
2625
+ return { kind: "daemon.stop" };
2626
+ if (head === "status") {
2627
+ const { agent, rest } = extractAgentFlag(args.slice(1));
2628
+ const json = rest.includes("--json");
2629
+ const unknown = rest.filter((token) => token !== "--json");
2630
+ if (agent) {
2631
+ if (unknown.length > 0 || json)
2632
+ throw new Error("Usage: ouro status [--json] OR ouro status --agent <name>");
2633
+ return { kind: "provider.status", agent };
2634
+ }
2635
+ if (unknown.length > 0)
2636
+ throw new Error("Usage: ouro status [--json] OR ouro status --agent <name>");
2637
+ return { kind: "daemon.status", ...(json ? { json: true } : {}) };
2638
+ }
2639
+ if (head === "use")
2640
+ return parseProviderUseCommand(args.slice(1));
2641
+ if (head === "check")
2642
+ return parseProviderCheckCommand(args.slice(1));
2643
+ if (head === "repair") {
2644
+ const { agent, rest } = extractAgentFlag(args.slice(1));
2645
+ if (rest.length > 0)
2646
+ throw new Error("Usage: ouro repair [--agent <name>]");
2647
+ return agent ? { kind: "repair", agent } : { kind: "repair" };
2648
+ }
2649
+ if (head === "provider")
2650
+ return parseProviderCommand(args.slice(1));
2651
+ if (head === "mail")
2652
+ return parseMailCommand(args.slice(1));
2653
+ if (head === "dns")
2654
+ return parseDnsCommand(args.slice(1));
2655
+ if (head === "logs")
2656
+ return parseLogsCommand(args.slice(1));
2657
+ if (head === "mailbox" || head === "outlook")
2658
+ return { kind: "mailbox", ...(args.includes("--json") ? { json: true } : {}) };
2659
+ if (head === "hatch")
2660
+ return parseHatchCommand(args.slice(1));
2661
+ if (head === "auth")
2662
+ return parseAuthCommand(args.slice(1));
2663
+ if (head === "account")
2664
+ return parseAccountCommand(args.slice(1));
2665
+ if (head === "connect")
2666
+ return parseConnectCommand(args.slice(1));
2667
+ if (head === "vault")
2668
+ return parseVaultCommand(args.slice(1));
2669
+ if (head === "habit")
2670
+ return parseHabitCommand(args.slice(1));
2671
+ if (head === "desk")
2672
+ return (0, cli_desk_1.parseDeskCommand)(args.slice(1));
2673
+ if (head === "task")
2674
+ return (0, cli_desk_1.parseTaskAliasCommand)(args.slice(1));
2675
+ if (head === "migrate-to-desk")
2676
+ return parseMigrateToDeskCommand(args.slice(1));
2677
+ if (head === "friend")
2678
+ return parseFriendCommand(args.slice(1));
2679
+ if (head === "a2a")
2680
+ return parseA2ACommand(args.slice(1));
2681
+ if (head === "config")
2682
+ return parseConfigCommand(args.slice(1));
2683
+ if (head === "mcp")
2684
+ return parseMcpCommand(args.slice(1));
2685
+ if (head === "whoami") {
2686
+ const { agent } = extractAgentFlag(args.slice(1));
2687
+ return { kind: "whoami", ...(agent ? { agent } : {}) };
2688
+ }
2689
+ if (head === "session")
2690
+ return parseSessionCommand(args.slice(1));
2691
+ if (head === "changelog") {
2692
+ const sliced = args.slice(1);
2693
+ const { agent, rest: remaining } = extractAgentFlag(sliced);
2694
+ let from;
2695
+ const fromIdx = remaining.indexOf("--from");
2696
+ if (fromIdx !== -1 && remaining[fromIdx + 1]) {
2697
+ from = remaining[fromIdx + 1];
2698
+ }
2699
+ return { kind: "changelog", ...(from ? { from } : {}), ...(agent ? { agent } : {}) };
2700
+ }
2701
+ if (head === "thoughts")
2702
+ return parseThoughtsCommand(args.slice(1));
2703
+ if (head === "private")
2704
+ return parsePrivateCommand(args.slice(1));
2705
+ if (head === "attention")
2706
+ return parseAttentionCommand(args.slice(1));
2707
+ if (head === "work")
2708
+ return parseWorkCommand(args.slice(1));
2709
+ if (head === "inner") {
2710
+ const { agent } = extractAgentFlag(args.slice(1));
2711
+ return { kind: "private.status", ...(agent ? { agent } : {}), legacyAlias: "inner" };
2712
+ }
2713
+ if (head === "chat") {
2714
+ if (!second)
2715
+ return { kind: "chat.connect", agent: "" };
2716
+ return { kind: "chat.connect", agent: second };
2717
+ }
2718
+ if (head === "msg")
2719
+ return parseMessageCommand(args.slice(1));
2720
+ if (head === "event")
2721
+ return parseEventCommand(args.slice(1));
2722
+ if (head === "poke")
2723
+ return parsePokeCommand(args.slice(1));
2724
+ if (head === "nerves-review")
2725
+ return parseNervesReviewCommand(args.slice(1));
2726
+ if (head === "link")
2727
+ return parseLinkCommand(args.slice(1));
2728
+ if (head === "acp-serve")
2729
+ return parseAcpServeCommand(args.slice(1));
2730
+ if (head === "mcp-serve")
2731
+ return parseMcpServeCommand(args.slice(1));
2732
+ if (head === "setup")
2733
+ return parseSetupCommand(args.slice(1));
2734
+ if (head === "plugin")
2735
+ return parsePluginCommand(args.slice(1));
2736
+ if (head === "clone")
2737
+ return parseCloneCommand(args.slice(1));
2738
+ if (head === "doctor") {
2739
+ const tail = args.slice(1);
2740
+ const json = tail.includes("--json");
2741
+ const hasCategoryFlag = tail.includes("--category");
2742
+ const hasStrictFlag = tail.includes("--strict");
2743
+ let category;
2744
+ let strict = false;
2745
+ for (let i = 0; i < tail.length; i++) {
2746
+ if (tail[i] === "--category" && typeof tail[i + 1] === "string") {
2747
+ category = tail[i + 1];
2748
+ }
2749
+ else if (tail[i] === "--strict") {
2750
+ strict = true;
2751
+ }
2752
+ }
2753
+ const command = { kind: "doctor" };
2754
+ if (category !== undefined)
2755
+ command.category = category;
2756
+ if (strict)
2757
+ command.strict = true;
2758
+ // --json default is only emitted for "plain" doctor invocations.
2759
+ // CI variants (--strict, --category) omit it; consumers go through doctorResult directly.
2760
+ if (!hasCategoryFlag && !hasStrictFlag)
2761
+ command.json = json;
2762
+ return command;
2763
+ }
2764
+ if (head === "bluebubbles")
2765
+ return parseBlueBubblesCommand(args.slice(1));
2766
+ if (head === "rsvp")
2767
+ return parseRsvpCommand(args.slice(1));
2768
+ const suggestion = (0, cli_help_1.suggestCommand)(head);
2769
+ const hint = suggestion ? ` Did you mean '${suggestion}'?` : "";
2770
+ throw new Error(`Unknown command '${args.join(" ")}'.${hint}\n${usage()}`);
2771
+ }