@ouro.bot/cli 0.1.0-alpha.56 → 0.1.0-alpha.560

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 (392) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +3596 -0
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +140 -0
  15. package/dist/arc/episodes.js +117 -0
  16. package/dist/arc/intentions.js +133 -0
  17. package/dist/arc/json-store.js +117 -0
  18. package/dist/arc/obligations.js +237 -0
  19. package/dist/arc/packets.js +193 -0
  20. package/dist/arc/presence.js +185 -0
  21. package/dist/arc/task-lifecycle.js +65 -0
  22. package/dist/heart/active-work.js +837 -26
  23. package/dist/heart/agent-entry.js +58 -3
  24. package/dist/heart/attachments/image-normalize.js +194 -0
  25. package/dist/heart/attachments/materialize.js +97 -0
  26. package/dist/heart/attachments/originals.js +88 -0
  27. package/dist/heart/attachments/render.js +29 -0
  28. package/dist/heart/attachments/sources/adapter.js +2 -0
  29. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  30. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  31. package/dist/heart/attachments/sources/index.js +16 -0
  32. package/dist/heart/attachments/store.js +103 -0
  33. package/dist/heart/attachments/types.js +93 -0
  34. package/dist/heart/auth/auth-flow.js +479 -0
  35. package/dist/heart/background-operations.js +281 -0
  36. package/dist/heart/bundle-state.js +168 -0
  37. package/dist/heart/commitments.js +111 -0
  38. package/dist/heart/config-registry.js +322 -0
  39. package/dist/heart/config.js +114 -118
  40. package/dist/heart/core.js +913 -246
  41. package/dist/heart/cross-chat-delivery.js +3 -18
  42. package/dist/heart/daemon/agent-config-check.js +419 -0
  43. package/dist/heart/daemon/agent-discovery.js +102 -3
  44. package/dist/heart/daemon/agent-service.js +522 -0
  45. package/dist/heart/daemon/agentic-repair.js +547 -0
  46. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  47. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  48. package/dist/heart/daemon/cadence.js +70 -0
  49. package/dist/heart/daemon/cli-defaults.js +776 -0
  50. package/dist/heart/daemon/cli-exec.js +7457 -0
  51. package/dist/heart/daemon/cli-help.js +498 -0
  52. package/dist/heart/daemon/cli-parse.js +1592 -0
  53. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  54. package/dist/heart/daemon/cli-render.js +763 -0
  55. package/dist/heart/daemon/cli-types.js +8 -0
  56. package/dist/heart/daemon/connect-bay.js +323 -0
  57. package/dist/heart/daemon/daemon-cli.js +29 -1698
  58. package/dist/heart/daemon/daemon-entry.js +387 -2
  59. package/dist/heart/daemon/daemon-health.js +176 -0
  60. package/dist/heart/daemon/daemon-rollup.js +57 -0
  61. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  62. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  63. package/dist/heart/daemon/daemon.js +796 -71
  64. package/dist/heart/daemon/dns-workflow.js +394 -0
  65. package/dist/heart/daemon/doctor-types.js +8 -0
  66. package/dist/heart/daemon/doctor.js +826 -0
  67. package/dist/heart/daemon/health-monitor.js +122 -1
  68. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  69. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  70. package/dist/heart/daemon/http-health-probe.js +80 -0
  71. package/dist/heart/daemon/human-command-screens.js +234 -0
  72. package/dist/heart/daemon/human-readiness.js +114 -0
  73. package/dist/heart/daemon/inner-status.js +89 -0
  74. package/dist/heart/daemon/interactive-repair.js +394 -0
  75. package/dist/heart/daemon/launchd.js +37 -8
  76. package/dist/heart/daemon/log-tailer.js +82 -12
  77. package/dist/heart/daemon/logs-prune.js +110 -0
  78. package/dist/heart/daemon/mcp-canary.js +297 -0
  79. package/dist/heart/daemon/message-router.js +2 -2
  80. package/dist/heart/daemon/os-cron-deps.js +135 -0
  81. package/dist/heart/daemon/os-cron.js +14 -12
  82. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  83. package/dist/heart/daemon/ouro-entry.js +3 -1
  84. package/dist/heart/daemon/process-manager.js +375 -33
  85. package/dist/heart/daemon/provider-discovery.js +137 -0
  86. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  87. package/dist/heart/daemon/pulse.js +475 -0
  88. package/dist/heart/daemon/readiness-repair.js +365 -0
  89. package/dist/heart/daemon/run-hooks.js +2 -0
  90. package/dist/heart/daemon/runtime-logging.js +67 -16
  91. package/dist/heart/daemon/runtime-metadata.js +3 -31
  92. package/dist/heart/daemon/safe-mode.js +161 -0
  93. package/dist/heart/daemon/sense-manager.js +389 -38
  94. package/dist/heart/daemon/session-id-resolver.js +131 -0
  95. package/dist/heart/daemon/skill-management-installer.js +94 -0
  96. package/dist/heart/daemon/socket-client.js +158 -11
  97. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  98. package/dist/heart/daemon/startup-tui.js +330 -0
  99. package/dist/heart/daemon/task-scheduler.js +3 -25
  100. package/dist/heart/daemon/terminal-ui.js +499 -0
  101. package/dist/heart/daemon/thoughts.js +162 -17
  102. package/dist/heart/daemon/up-progress.js +366 -0
  103. package/dist/heart/daemon/vault-items.js +56 -0
  104. package/dist/heart/delegation.js +1 -1
  105. package/dist/heart/habits/habit-migration.js +189 -0
  106. package/dist/heart/habits/habit-parser.js +140 -0
  107. package/dist/heart/habits/habit-runtime-state.js +100 -0
  108. package/dist/heart/habits/habit-scheduler.js +372 -0
  109. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  110. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  111. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  112. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  113. package/dist/heart/identity.js +203 -57
  114. package/dist/heart/kept-notes.js +357 -0
  115. package/dist/heart/kicks.js +1 -1
  116. package/dist/heart/machine-identity.js +161 -0
  117. package/dist/heart/mail-import-discovery.js +353 -0
  118. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  119. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  120. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  121. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  122. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  123. package/dist/heart/mailbox/mailbox-http.js +99 -0
  124. package/dist/heart/mailbox/mailbox-read.js +31 -0
  125. package/dist/heart/mailbox/mailbox-types.js +27 -0
  126. package/dist/heart/mailbox/mailbox-view.js +195 -0
  127. package/dist/heart/mailbox/readers/agent-machine.js +382 -0
  128. package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
  129. package/dist/heart/mailbox/readers/mail.js +362 -0
  130. package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
  131. package/dist/heart/mailbox/readers/sessions.js +232 -0
  132. package/dist/heart/mailbox/readers/shared.js +111 -0
  133. package/dist/heart/mcp/mcp-server.js +683 -0
  134. package/dist/heart/migrate-config.js +100 -0
  135. package/dist/heart/model-capabilities.js +19 -0
  136. package/dist/heart/platform.js +81 -0
  137. package/dist/heart/provider-attempt.js +134 -0
  138. package/dist/heart/provider-binding-resolver.js +267 -0
  139. package/dist/heart/provider-credentials.js +425 -0
  140. package/dist/heart/provider-failover.js +301 -0
  141. package/dist/heart/provider-models.js +81 -0
  142. package/dist/heart/provider-ping.js +262 -0
  143. package/dist/heart/provider-readiness-cache.js +40 -0
  144. package/dist/heart/provider-visibility.js +188 -0
  145. package/dist/heart/providers/anthropic-token.js +131 -0
  146. package/dist/heart/providers/anthropic.js +139 -52
  147. package/dist/heart/providers/azure.js +97 -13
  148. package/dist/heart/providers/error-classification.js +127 -0
  149. package/dist/heart/providers/github-copilot.js +145 -0
  150. package/dist/heart/providers/minimax-vlm.js +189 -0
  151. package/dist/heart/providers/minimax.js +26 -8
  152. package/dist/heart/providers/openai-codex.js +55 -40
  153. package/dist/heart/runtime-capability-check.js +170 -0
  154. package/dist/heart/runtime-credentials.js +367 -0
  155. package/dist/heart/runtime-cwd.js +87 -0
  156. package/dist/heart/sense-truth.js +13 -4
  157. package/dist/heart/session-activity.js +43 -22
  158. package/dist/heart/session-events.js +1149 -0
  159. package/dist/heart/session-playback-cli-main.js +5 -0
  160. package/dist/heart/session-playback-cli.js +36 -0
  161. package/dist/heart/session-playback.js +231 -0
  162. package/dist/heart/session-stats-cli-main.js +5 -0
  163. package/dist/heart/session-stats.js +182 -0
  164. package/dist/heart/session-transcript.js +243 -0
  165. package/dist/heart/start-of-turn-packet.js +345 -0
  166. package/dist/heart/streaming.js +44 -27
  167. package/dist/heart/sync-classification.js +176 -0
  168. package/dist/heart/sync.js +449 -0
  169. package/dist/heart/target-resolution.js +9 -5
  170. package/dist/heart/tempo.js +93 -0
  171. package/dist/heart/temporal-view.js +41 -0
  172. package/dist/heart/timeouts.js +101 -0
  173. package/dist/heart/tool-activity-callbacks.js +59 -0
  174. package/dist/heart/tool-description.js +139 -0
  175. package/dist/heart/tool-friction.js +55 -0
  176. package/dist/heart/tool-loop.js +200 -0
  177. package/dist/heart/turn-context.js +389 -0
  178. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  179. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  180. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  181. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  182. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  183. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  184. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  185. package/dist/mailbox-ui/assets/index-B-461hes.js +61 -0
  186. package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
  187. package/dist/mailbox-ui/index.html +15 -0
  188. package/dist/mailroom/attention.js +167 -0
  189. package/dist/mailroom/autonomy.js +209 -0
  190. package/dist/mailroom/blob-store.js +674 -0
  191. package/dist/mailroom/body-cache.js +61 -0
  192. package/dist/mailroom/core.js +720 -0
  193. package/dist/mailroom/entry.js +160 -0
  194. package/dist/mailroom/file-store.js +430 -0
  195. package/dist/mailroom/mbox-import.js +383 -0
  196. package/dist/mailroom/outbound.js +380 -0
  197. package/dist/mailroom/policy.js +263 -0
  198. package/dist/mailroom/reader.js +233 -0
  199. package/dist/mailroom/search-cache.js +256 -0
  200. package/dist/mailroom/search-relevance.js +319 -0
  201. package/dist/mailroom/smtp-ingress.js +176 -0
  202. package/dist/mailroom/source-state.js +176 -0
  203. package/dist/mailroom/thread.js +109 -0
  204. package/dist/mailroom/travel-extract.js +89 -0
  205. package/dist/mind/bundle-manifest.js +7 -1
  206. package/dist/mind/context.js +165 -101
  207. package/dist/mind/diary-integrity.js +60 -0
  208. package/dist/mind/{memory.js → diary.js} +62 -75
  209. package/dist/mind/embedding-provider.js +60 -0
  210. package/dist/mind/file-state.js +179 -0
  211. package/dist/mind/friends/channel.js +39 -0
  212. package/dist/mind/friends/resolver.js +54 -2
  213. package/dist/mind/friends/store-file.js +39 -3
  214. package/dist/mind/friends/types.js +2 -2
  215. package/dist/mind/journal-index.js +161 -0
  216. package/dist/mind/note-search.js +268 -0
  217. package/dist/mind/obligation-steering.js +221 -0
  218. package/dist/mind/pending.js +4 -0
  219. package/dist/mind/prompt-refresh.js +3 -2
  220. package/dist/mind/prompt.js +1011 -123
  221. package/dist/mind/provenance-trust.js +26 -0
  222. package/dist/mind/scrutiny.js +173 -0
  223. package/dist/nerves/cli-logging.js +7 -1
  224. package/dist/nerves/coverage/audit-rules.js +15 -6
  225. package/dist/nerves/coverage/audit.js +28 -2
  226. package/dist/nerves/coverage/cli.js +1 -1
  227. package/dist/nerves/coverage/contract.js +5 -5
  228. package/dist/nerves/coverage/file-completeness.js +129 -5
  229. package/dist/nerves/coverage/run-artifacts.js +1 -1
  230. package/dist/nerves/event-buffer.js +111 -0
  231. package/dist/nerves/index.js +224 -4
  232. package/dist/nerves/observation.js +20 -0
  233. package/dist/nerves/redact.js +79 -0
  234. package/dist/nerves/review/cli-main.js +5 -0
  235. package/dist/nerves/review/cli.js +156 -0
  236. package/dist/nerves/review/core.js +152 -0
  237. package/dist/nerves/runtime.js +5 -1
  238. package/dist/repertoire/ado-client.js +15 -56
  239. package/dist/repertoire/ado-semantic.js +11 -10
  240. package/dist/repertoire/api-client.js +97 -0
  241. package/dist/repertoire/bitwarden-store.js +963 -0
  242. package/dist/repertoire/bundle-templates.js +72 -0
  243. package/dist/repertoire/bw-installer.js +180 -0
  244. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  245. package/dist/repertoire/coding/context-pack.js +330 -0
  246. package/dist/repertoire/coding/feedback.js +197 -30
  247. package/dist/repertoire/coding/manager.js +158 -9
  248. package/dist/repertoire/coding/spawner.js +55 -9
  249. package/dist/repertoire/coding/tools.js +170 -7
  250. package/dist/repertoire/commerce-errors.js +109 -0
  251. package/dist/repertoire/commerce-self-test.js +156 -0
  252. package/dist/repertoire/credential-access.js +178 -0
  253. package/dist/repertoire/duffel-client.js +185 -0
  254. package/dist/repertoire/github-client.js +14 -55
  255. package/dist/repertoire/graph-client.js +11 -52
  256. package/dist/repertoire/guardrails.js +396 -0
  257. package/dist/repertoire/mcp-client.js +295 -0
  258. package/dist/repertoire/mcp-manager.js +362 -0
  259. package/dist/repertoire/mcp-tools.js +63 -0
  260. package/dist/repertoire/shell-sessions.js +133 -0
  261. package/dist/repertoire/skills.js +15 -24
  262. package/dist/repertoire/stripe-client.js +131 -0
  263. package/dist/repertoire/tasks/board.js +31 -5
  264. package/dist/repertoire/tasks/fix.js +182 -0
  265. package/dist/repertoire/tasks/index.js +16 -4
  266. package/dist/repertoire/tasks/lifecycle.js +2 -2
  267. package/dist/repertoire/tasks/parser.js +3 -2
  268. package/dist/repertoire/tasks/scanner.js +194 -37
  269. package/dist/repertoire/tasks/transitions.js +16 -78
  270. package/dist/repertoire/tool-results.js +29 -0
  271. package/dist/repertoire/tools-attachments.js +317 -0
  272. package/dist/repertoire/tools-base.js +47 -1075
  273. package/dist/repertoire/tools-bluebubbles.js +1 -0
  274. package/dist/repertoire/tools-bridge.js +142 -0
  275. package/dist/repertoire/tools-bundle.js +984 -0
  276. package/dist/repertoire/tools-config.js +185 -0
  277. package/dist/repertoire/tools-continuity.js +248 -0
  278. package/dist/repertoire/tools-credential.js +381 -0
  279. package/dist/repertoire/tools-files.js +342 -0
  280. package/dist/repertoire/tools-flight.js +224 -0
  281. package/dist/repertoire/tools-flow.js +119 -0
  282. package/dist/repertoire/tools-github.js +1 -7
  283. package/dist/repertoire/tools-mail.js +1857 -0
  284. package/dist/repertoire/tools-notes.js +421 -0
  285. package/dist/repertoire/tools-session.js +750 -0
  286. package/dist/repertoire/tools-shell.js +120 -0
  287. package/dist/repertoire/tools-stripe.js +180 -0
  288. package/dist/repertoire/tools-surface.js +243 -0
  289. package/dist/repertoire/tools-teams.js +9 -39
  290. package/dist/repertoire/tools-travel.js +125 -0
  291. package/dist/repertoire/tools-trip.js +604 -0
  292. package/dist/repertoire/tools-user-profile.js +144 -0
  293. package/dist/repertoire/tools-vault.js +40 -0
  294. package/dist/repertoire/tools.js +108 -100
  295. package/dist/repertoire/travel-api-client.js +360 -0
  296. package/dist/repertoire/user-profile.js +131 -0
  297. package/dist/repertoire/vault-setup.js +246 -0
  298. package/dist/repertoire/vault-unlock.js +594 -0
  299. package/dist/scripts/claude-code-hook.js +41 -0
  300. package/dist/scripts/claude-code-stop-hook.js +47 -0
  301. package/dist/senses/attention-queue.js +116 -0
  302. package/dist/senses/bluebubbles/active-turns.js +216 -0
  303. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  304. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  305. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  306. package/dist/senses/bluebubbles/entry.js +77 -0
  307. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  308. package/dist/senses/bluebubbles/index.js +2305 -0
  309. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  310. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  311. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  312. package/dist/senses/bluebubbles/processed-log.js +133 -0
  313. package/dist/senses/bluebubbles/replay.js +137 -0
  314. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  315. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  316. package/dist/senses/cli/bracketed-paste.js +82 -0
  317. package/dist/senses/cli/image-paste.js +287 -0
  318. package/dist/senses/cli/image-ref-navigation.js +75 -0
  319. package/dist/senses/cli/ink-app.js +156 -0
  320. package/dist/senses/cli/inline-diff.js +64 -0
  321. package/dist/senses/cli/input-keys.js +174 -0
  322. package/dist/senses/cli/kill-ring.js +86 -0
  323. package/dist/senses/cli/message-list.js +51 -0
  324. package/dist/senses/cli/ouro-tui.js +607 -0
  325. package/dist/senses/cli/spinner-imperative.js +135 -0
  326. package/dist/senses/cli/spinner.js +101 -0
  327. package/dist/senses/cli/status-line.js +60 -0
  328. package/dist/senses/cli/streaming-markdown.js +526 -0
  329. package/dist/senses/cli/tool-display.js +85 -0
  330. package/dist/senses/cli/tool-render.js +85 -0
  331. package/dist/senses/cli/tui-store.js +240 -0
  332. package/dist/senses/cli/virtual-list.js +35 -0
  333. package/dist/senses/cli-entry.js +60 -8
  334. package/dist/senses/cli-layout.js +187 -0
  335. package/dist/senses/cli.js +520 -209
  336. package/dist/senses/commands.js +66 -3
  337. package/dist/senses/habit-turn-message.js +108 -0
  338. package/dist/senses/inner-dialog-worker.js +175 -21
  339. package/dist/senses/inner-dialog.js +330 -27
  340. package/dist/senses/mail-entry.js +66 -0
  341. package/dist/senses/mail.js +379 -0
  342. package/dist/senses/pipeline.js +549 -181
  343. package/dist/senses/proactive-content-guard.js +51 -0
  344. package/dist/senses/shared-turn.js +248 -0
  345. package/dist/senses/surface-tool.js +68 -0
  346. package/dist/senses/teams-entry.js +60 -8
  347. package/dist/senses/teams.js +387 -98
  348. package/dist/senses/trust-gate.js +100 -5
  349. package/dist/senses/voice/elevenlabs.js +125 -0
  350. package/dist/senses/voice/index.js +22 -0
  351. package/dist/senses/voice/transcript.js +70 -0
  352. package/dist/senses/voice/turn.js +85 -0
  353. package/dist/senses/voice/types.js +2 -0
  354. package/dist/senses/voice/whisper.js +133 -0
  355. package/dist/senses/voice-entry.js +80 -0
  356. package/dist/trips/core.js +138 -0
  357. package/dist/trips/store.js +146 -0
  358. package/package.json +38 -7
  359. package/skills/agent-commerce.md +106 -0
  360. package/skills/browser-navigation.md +117 -0
  361. package/skills/commerce-setup-guide.md +116 -0
  362. package/skills/commerce-setup.md +84 -0
  363. package/skills/configure-dev-tools.md +101 -0
  364. package/skills/travel-planning.md +138 -0
  365. package/dist/heart/daemon/auth-flow.js +0 -351
  366. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  367. package/dist/heart/daemon/subagent-installer.js +0 -166
  368. package/dist/heart/session-recall.js +0 -116
  369. package/dist/mind/associative-recall.js +0 -209
  370. package/dist/senses/bluebubbles-entry.js +0 -13
  371. package/dist/senses/bluebubbles.js +0 -1177
  372. package/dist/senses/debug-activity.js +0 -148
  373. package/subagents/README.md +0 -86
  374. package/subagents/work-doer.md +0 -237
  375. package/subagents/work-merger.md +0 -618
  376. package/subagents/work-planner.md +0 -390
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  380. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  381. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  382. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  383. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  384. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  385. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  386. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  387. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  388. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  389. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  390. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  391. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  392. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,763 @@
1
+ "use strict";
2
+ /**
3
+ * CLI output formatting and rendering helpers.
4
+ *
5
+ * Pure functions that transform data into human-readable CLI output.
6
+ * No side effects — callers handle writing to stdout.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.parseStatusPayload = parseStatusPayload;
43
+ exports.humanizeSenseName = humanizeSenseName;
44
+ exports.formatTable = formatTable;
45
+ exports.formatDaemonStatusOutput = formatDaemonStatusOutput;
46
+ exports.formatVersionOutput = formatVersionOutput;
47
+ exports.buildStoppedStatusPayload = buildStoppedStatusPayload;
48
+ exports.renderRollupStatusLine = renderRollupStatusLine;
49
+ exports.daemonUnavailableStatusOutput = daemonUnavailableStatusOutput;
50
+ exports.isDaemonUnavailableError = isDaemonUnavailableError;
51
+ exports.formatMcpResponse = formatMcpResponse;
52
+ const path = __importStar(require("path"));
53
+ const runtime_metadata_1 = require("./runtime-metadata");
54
+ const runtime_mode_1 = require("./runtime-mode");
55
+ const identity_1 = require("../identity");
56
+ const daemon_tombstone_1 = require("./daemon-tombstone");
57
+ const daemon_health_1 = require("./daemon-health");
58
+ const agent_discovery_1 = require("./agent-discovery");
59
+ // ── Field extractors ──
60
+ function stringField(value) {
61
+ return typeof value === "string" ? value : null;
62
+ }
63
+ function numberField(value) {
64
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
65
+ }
66
+ function booleanField(value) {
67
+ return typeof value === "boolean" ? value : null;
68
+ }
69
+ function formatDurationMs(ms) {
70
+ if (ms < 1_000)
71
+ return `${Math.round(ms)}ms`;
72
+ if (ms < 60_000)
73
+ return `${Math.round(ms / 1_000)}s`;
74
+ if (ms < 3_600_000)
75
+ return `${Math.round(ms / 60_000)}m`;
76
+ if (ms < 86_400_000)
77
+ return `${Math.round(ms / 3_600_000)}h`;
78
+ return `${Math.round(ms / 86_400_000)}d`;
79
+ }
80
+ function formatSenseDetail(row) {
81
+ const details = [row.detail];
82
+ const proofParts = [];
83
+ if (row.proofMethod)
84
+ proofParts.push(`proof=${row.proofMethod}`);
85
+ if (row.lastProofAt)
86
+ proofParts.push(`lastProof=${row.lastProofAt}`);
87
+ if (row.proofAgeMs !== undefined)
88
+ proofParts.push(`proofAge=${formatDurationMs(row.proofAgeMs)}`);
89
+ if (proofParts.length > 0)
90
+ details.push(proofParts.join(" "));
91
+ const recoveryParts = [];
92
+ if (row.pendingRecoveryCount !== undefined)
93
+ recoveryParts.push(`pendingRecovery=${row.pendingRecoveryCount}`);
94
+ if (row.failedRecoveryCount !== undefined)
95
+ recoveryParts.push(`failedRecovery=${row.failedRecoveryCount}`);
96
+ if (row.oldestPendingRecoveryAt)
97
+ recoveryParts.push(`oldestPending=${row.oldestPendingRecoveryAt}`);
98
+ if (row.oldestPendingRecoveryAgeMs !== undefined)
99
+ recoveryParts.push(`oldestPendingAge=${formatDurationMs(row.oldestPendingRecoveryAgeMs)}`);
100
+ if (row.activeTurnCount !== undefined)
101
+ recoveryParts.push(`activeTurns=${row.activeTurnCount}`);
102
+ if (row.stalledTurnCount !== undefined)
103
+ recoveryParts.push(`stalledTurns=${row.stalledTurnCount}`);
104
+ if (row.oldestActiveTurnStartedAt)
105
+ recoveryParts.push(`oldestActive=${row.oldestActiveTurnStartedAt}`);
106
+ if (row.oldestActiveTurnAgeMs !== undefined)
107
+ recoveryParts.push(`oldestActiveAge=${formatDurationMs(row.oldestActiveTurnAgeMs)}`);
108
+ if (recoveryParts.length > 0)
109
+ details.push(recoveryParts.join(" "));
110
+ const failureParts = [];
111
+ if (row.failureLayer)
112
+ failureParts.push(`failureLayer=${row.failureLayer}`);
113
+ if (row.lastFailure)
114
+ failureParts.push(`lastFailure=${row.lastFailure}`);
115
+ if (row.recoveryAction)
116
+ failureParts.push(`recovery=${row.recoveryAction}`);
117
+ if (failureParts.length > 0)
118
+ details.push(failureParts.join(" "));
119
+ return details.filter(Boolean).join("; ");
120
+ }
121
+ // ── Parsers ──
122
+ function parseStatusPayload(data) {
123
+ if (!data || typeof data !== "object" || Array.isArray(data))
124
+ return null;
125
+ const raw = data;
126
+ const overview = raw.overview;
127
+ const senses = raw.senses;
128
+ const workers = raw.workers;
129
+ const sync = raw.sync;
130
+ const agents = raw.agents;
131
+ const providers = raw.providers;
132
+ const healthChecks = raw.healthChecks;
133
+ if (!overview || typeof overview !== "object" || Array.isArray(overview))
134
+ return null;
135
+ if (!Array.isArray(senses) || !Array.isArray(workers))
136
+ return null;
137
+ // sync, agents, and providers are optional for backward compatibility — older daemons may omit them
138
+ if (sync !== undefined && !Array.isArray(sync))
139
+ return null;
140
+ if (agents !== undefined && !Array.isArray(agents))
141
+ return null;
142
+ if (providers !== undefined && !Array.isArray(providers))
143
+ return null;
144
+ if (healthChecks !== undefined && !Array.isArray(healthChecks))
145
+ return null;
146
+ const parsedOverview = {
147
+ daemon: stringField(overview.daemon) ?? "unknown",
148
+ health: stringField(overview.health) ?? "unknown",
149
+ socketPath: stringField(overview.socketPath) ?? "unknown",
150
+ mailboxUrl: stringField(overview.mailboxUrl)
151
+ ?? stringField(overview.outlookUrl)
152
+ ?? "unavailable",
153
+ outlookUrl: stringField(overview.outlookUrl) ?? undefined,
154
+ version: stringField(overview.version) ?? "unknown",
155
+ lastUpdated: stringField(overview.lastUpdated) ?? "unknown",
156
+ repoRoot: stringField(overview.repoRoot) ?? "unknown",
157
+ configFingerprint: stringField(overview.configFingerprint) ?? "unknown",
158
+ workerCount: numberField(overview.workerCount) ?? 0,
159
+ senseCount: numberField(overview.senseCount) ?? 0,
160
+ entryPath: stringField(overview.entryPath) ?? "unknown",
161
+ mode: stringField(overview.mode) ?? "unknown",
162
+ };
163
+ const parsedSenses = senses.map((entry) => {
164
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
165
+ return null;
166
+ const row = entry;
167
+ const agent = stringField(row.agent);
168
+ const sense = stringField(row.sense);
169
+ const status = stringField(row.status);
170
+ const detail = stringField(row.detail);
171
+ const enabled = booleanField(row.enabled);
172
+ if (!agent || !sense || !status || detail === null || enabled === null)
173
+ return null;
174
+ const parsed = {
175
+ agent,
176
+ sense,
177
+ label: stringField(row.label) ?? undefined,
178
+ enabled,
179
+ status,
180
+ detail,
181
+ };
182
+ const proofMethod = stringField(row.proofMethod);
183
+ const lastProofAt = stringField(row.lastProofAt);
184
+ const proofAgeMs = numberField(row.proofAgeMs);
185
+ const lastFailure = stringField(row.lastFailure);
186
+ const failureLayer = stringField(row.failureLayer);
187
+ const recoveryAction = stringField(row.recoveryAction);
188
+ const pendingRecoveryCount = numberField(row.pendingRecoveryCount);
189
+ const failedRecoveryCount = numberField(row.failedRecoveryCount);
190
+ const oldestPendingRecoveryAt = stringField(row.oldestPendingRecoveryAt);
191
+ const oldestPendingRecoveryAgeMs = numberField(row.oldestPendingRecoveryAgeMs);
192
+ const activeTurnCount = numberField(row.activeTurnCount);
193
+ const stalledTurnCount = numberField(row.stalledTurnCount);
194
+ const oldestActiveTurnStartedAt = stringField(row.oldestActiveTurnStartedAt);
195
+ const oldestActiveTurnAgeMs = numberField(row.oldestActiveTurnAgeMs);
196
+ if (proofMethod !== null)
197
+ parsed.proofMethod = proofMethod;
198
+ if (lastProofAt !== null)
199
+ parsed.lastProofAt = lastProofAt;
200
+ if (proofAgeMs !== null)
201
+ parsed.proofAgeMs = proofAgeMs;
202
+ if (lastFailure !== null)
203
+ parsed.lastFailure = lastFailure;
204
+ if (failureLayer !== null)
205
+ parsed.failureLayer = failureLayer;
206
+ if (recoveryAction !== null)
207
+ parsed.recoveryAction = recoveryAction;
208
+ if (pendingRecoveryCount !== null)
209
+ parsed.pendingRecoveryCount = pendingRecoveryCount;
210
+ if (failedRecoveryCount !== null)
211
+ parsed.failedRecoveryCount = failedRecoveryCount;
212
+ if (oldestPendingRecoveryAt !== null)
213
+ parsed.oldestPendingRecoveryAt = oldestPendingRecoveryAt;
214
+ if (oldestPendingRecoveryAgeMs !== null)
215
+ parsed.oldestPendingRecoveryAgeMs = oldestPendingRecoveryAgeMs;
216
+ if (activeTurnCount !== null)
217
+ parsed.activeTurnCount = activeTurnCount;
218
+ if (stalledTurnCount !== null)
219
+ parsed.stalledTurnCount = stalledTurnCount;
220
+ if (oldestActiveTurnStartedAt !== null)
221
+ parsed.oldestActiveTurnStartedAt = oldestActiveTurnStartedAt;
222
+ if (oldestActiveTurnAgeMs !== null)
223
+ parsed.oldestActiveTurnAgeMs = oldestActiveTurnAgeMs;
224
+ return parsed;
225
+ });
226
+ const parsedWorkers = workers.map((entry) => {
227
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
228
+ return null;
229
+ const row = entry;
230
+ const agent = stringField(row.agent);
231
+ const worker = stringField(row.worker);
232
+ const status = stringField(row.status);
233
+ const restartCount = numberField(row.restartCount);
234
+ const hasPid = Object.prototype.hasOwnProperty.call(row, "pid");
235
+ const pid = row.pid === null ? null : numberField(row.pid);
236
+ const pidInvalid = !hasPid || (row.pid !== null && pid === null);
237
+ if (!agent || !worker || !status || restartCount === null || pidInvalid)
238
+ return null;
239
+ return {
240
+ agent,
241
+ worker,
242
+ status,
243
+ pid,
244
+ restartCount,
245
+ lastExitCode: numberField(row.lastExitCode) ?? null,
246
+ lastSignal: stringField(row.lastSignal) ?? null,
247
+ startedAt: stringField(row.startedAt) ?? null,
248
+ errorReason: stringField(row.errorReason) ?? null,
249
+ fixHint: stringField(row.fixHint) ?? null,
250
+ };
251
+ });
252
+ const parsedSync = (sync ?? []).map((entry) => {
253
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
254
+ return null;
255
+ const row = entry;
256
+ const agent = stringField(row.agent);
257
+ const enabled = booleanField(row.enabled);
258
+ const remote = stringField(row.remote);
259
+ if (!agent || enabled === null || !remote)
260
+ return null;
261
+ const parsed = { agent, enabled, remote };
262
+ const remoteUrl = stringField(row.remoteUrl);
263
+ if (remoteUrl !== null)
264
+ parsed.remoteUrl = remoteUrl;
265
+ const gitInitialized = booleanField(row.gitInitialized);
266
+ if (gitInitialized !== null)
267
+ parsed.gitInitialized = gitInitialized;
268
+ return parsed;
269
+ });
270
+ const parsedAgents = (agents ?? []).map((entry) => {
271
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
272
+ return null;
273
+ const row = entry;
274
+ const name = stringField(row.name);
275
+ const enabled = booleanField(row.enabled);
276
+ if (!name || enabled === null)
277
+ return null;
278
+ return { name, enabled };
279
+ });
280
+ const parsedProviders = (providers ?? []).map((entry) => {
281
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
282
+ return null;
283
+ const row = entry;
284
+ const agent = stringField(row.agent);
285
+ const lane = stringField(row.lane);
286
+ const provider = stringField(row.provider);
287
+ const model = stringField(row.model);
288
+ const source = stringField(row.source);
289
+ const readiness = stringField(row.readiness);
290
+ const credential = stringField(row.credential);
291
+ if (!agent || !lane || !provider || !model || !source || !readiness || !credential)
292
+ return null;
293
+ const parsed = {
294
+ agent,
295
+ lane,
296
+ provider,
297
+ model,
298
+ source,
299
+ readiness,
300
+ credential,
301
+ };
302
+ const detail = stringField(row.detail);
303
+ if (detail !== null)
304
+ parsed.detail = detail;
305
+ return parsed;
306
+ });
307
+ const parsedHealthChecks = (healthChecks ?? []).map((entry) => {
308
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
309
+ return null;
310
+ const row = entry;
311
+ const name = stringField(row.name);
312
+ const status = stringField(row.status);
313
+ const message = stringField(row.message);
314
+ if (!name || !status || !message)
315
+ return null;
316
+ return { name, status, message };
317
+ });
318
+ if (parsedSenses.some((row) => row === null) ||
319
+ parsedWorkers.some((row) => row === null) ||
320
+ parsedSync.some((row) => row === null) ||
321
+ parsedAgents.some((row) => row === null) ||
322
+ parsedProviders.some((row) => row === null) ||
323
+ parsedHealthChecks.some((row) => row === null))
324
+ return null;
325
+ return {
326
+ overview: parsedOverview,
327
+ senses: parsedSenses,
328
+ workers: parsedWorkers,
329
+ healthChecks: parsedHealthChecks,
330
+ sync: parsedSync,
331
+ agents: parsedAgents,
332
+ providers: parsedProviders,
333
+ };
334
+ }
335
+ // ── ANSI color helpers (private) ──
336
+ const RESET = "\x1b[0m";
337
+ const BOLD = "\x1b[1m";
338
+ const DIM = "\x1b[2m";
339
+ const TEAL = "\x1b[38;2;78;201;176m";
340
+ const GREEN = "\x1b[38;2;46;204;64m";
341
+ const RED = "\x1b[38;2;231;76;60m";
342
+ const YELLOW = "\x1b[38;2;230;190;50m";
343
+ /* v8 ignore start -- cosmetic ANSI wrappers @preserve */
344
+ function teal(text) { return `${TEAL}${text}${RESET}`; }
345
+ function green(text) { return `${GREEN}${text}${RESET}`; }
346
+ function red(text) { return `${RED}${text}${RESET}`; }
347
+ function yellow(text) { return `${YELLOW}${text}${RESET}`; }
348
+ function bold(text) { return `${BOLD}${text}${RESET}`; }
349
+ function dim(text) { return `${DIM}${text}${RESET}`; }
350
+ /* v8 ignore stop */
351
+ /* v8 ignore start -- cosmetic display: status dot color mapping tested visually @preserve */
352
+ function statusDot(status) {
353
+ switch (status) {
354
+ case "running":
355
+ case "ok":
356
+ case "interactive":
357
+ case "enabled":
358
+ case "ready":
359
+ return green("●");
360
+ case "crashed":
361
+ case "warn":
362
+ case "error":
363
+ case "failed":
364
+ return red("●");
365
+ case "needs_config":
366
+ case "not_attached":
367
+ case "stale":
368
+ return yellow("●");
369
+ case "disabled":
370
+ case "stopped":
371
+ return dim("○");
372
+ default:
373
+ return dim("●");
374
+ }
375
+ }
376
+ /* v8 ignore stop */
377
+ // ── Formatters ──
378
+ function humanizeSenseName(sense, label) {
379
+ if (label)
380
+ return label;
381
+ if (sense === "cli")
382
+ return "CLI";
383
+ if (sense === "bluebubbles")
384
+ return "BlueBubbles";
385
+ if (sense === "teams")
386
+ return "Teams";
387
+ return sense;
388
+ }
389
+ /* v8 ignore start -- utility formatter; retained for non-status table output @preserve */
390
+ function formatTable(headers, rows) {
391
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index].length)));
392
+ const renderRow = (row) => `| ${row.map((cell, index) => (index === row.length - 1
393
+ ? cell
394
+ : cell.padEnd(widths[index]))).join(" | ")} |`;
395
+ const divider = `|-${widths.map((width) => "-".repeat(width)).join("-|-")}-|`;
396
+ return [
397
+ renderRow(headers),
398
+ divider,
399
+ ...rows.map(renderRow),
400
+ ].join("\n");
401
+ }
402
+ /* v8 ignore stop */
403
+ function formatDaemonStatusOutput(response, fallback) {
404
+ const payload = parseStatusPayload(response.data);
405
+ if (!payload)
406
+ return fallback;
407
+ const ov = payload.overview;
408
+ const lines = [];
409
+ // ── Header banner ──
410
+ const modeTag = ov.mode === "dev" ? "dev" : "";
411
+ const daemonStatus = ov.daemon === "running" ? green("●") + " " + bold("running") : red("●") + " " + bold(ov.daemon);
412
+ const modeStr = modeTag ? ` ${dim(`(${modeTag})`)}` : "";
413
+ const bannerContent = ` ${bold(ov.version)} ${daemonStatus}${modeStr} `;
414
+ // Measure raw content width (strip ANSI for width calc)
415
+ const rawBanner = bannerContent.replace(/\x1b\[[0-9;]*m/g, "");
416
+ const bannerWidth = Math.max(rawBanner.length, 42);
417
+ const titleLabel = " ouroboros daemon ";
418
+ const topRightPad = Math.max(0, bannerWidth - titleLabel.length - 2);
419
+ lines.push(` ${teal("╭─")}${teal(titleLabel)}${teal("─".repeat(topRightPad))}${teal("╮")}`);
420
+ lines.push(` ${teal("│")}${bannerContent}${" ".repeat(Math.max(0, bannerWidth - rawBanner.length))}${teal("│")}`);
421
+ lines.push(` ${teal("╰")}${teal("─".repeat(bannerWidth))}${teal("╯")}`);
422
+ lines.push("");
423
+ // ── Key-value overview ──
424
+ const kvLine = (label, value) => ` ${teal(label.padEnd(11))} ${value}`;
425
+ lines.push(kvLine("Socket", ov.socketPath));
426
+ lines.push(kvLine("Mailbox", ov.mailboxUrl));
427
+ lines.push(kvLine("Health", `${statusDot(ov.health)} ${ov.health}`));
428
+ lines.push(kvLine("Updated", ov.lastUpdated));
429
+ lines.push("");
430
+ // ── Agents ──
431
+ // Every discovered bundle, including disabled ones. The Senses/Workers/
432
+ // Git Sync sections below only show enabled bundles, so without this
433
+ // section disabled agents would be invisible in `ouro status`.
434
+ if (payload.agents.length > 0) {
435
+ lines.push(` ${teal("──")} ${bold("Agents")} ${teal("─".repeat(37))}`);
436
+ const agentNameWidth = Math.max(12, ...payload.agents.map((r) => r.name.length));
437
+ for (const row of payload.agents) {
438
+ const name = row.name.padEnd(agentNameWidth);
439
+ const dot = row.enabled ? green("●") : dim("○");
440
+ const stateText = row.enabled ? "enabled " : "disabled";
441
+ lines.push(` ${name} ${dot} ${stateText}`);
442
+ }
443
+ lines.push("");
444
+ }
445
+ // ── Providers ──
446
+ if (payload.providers.length > 0) {
447
+ lines.push(` ${teal("──")} ${bold("Providers")} ${teal("─".repeat(34))}`);
448
+ const agentLaneWidth = Math.max(16, ...payload.providers.map((r) => `${r.agent} ${r.lane}`.length));
449
+ for (const row of payload.providers) {
450
+ const agentLane = `${row.agent} ${row.lane}`.padEnd(agentLaneWidth);
451
+ const model = `${row.provider} / ${row.model}`;
452
+ const detail = [row.readiness, row.detail, row.source, row.credential].filter(Boolean).join("; ");
453
+ lines.push(` ${agentLane} ${statusDot(row.readiness)} ${model} ${dim(detail)}`);
454
+ }
455
+ lines.push("");
456
+ }
457
+ // ── Senses ──
458
+ if (payload.senses.length > 0) {
459
+ lines.push(` ${teal("──")} ${bold("Senses")} ${teal("─".repeat(37))}`);
460
+ // Group senses by agent
461
+ const sensesByAgent = new Map();
462
+ for (const row of payload.senses) {
463
+ const list = sensesByAgent.get(row.agent) ?? [];
464
+ list.push(row);
465
+ sensesByAgent.set(row.agent, list);
466
+ }
467
+ // Calculate column widths for alignment
468
+ const allSenseNames = payload.senses.map((r) => humanizeSenseName(r.sense, r.label));
469
+ const nameWidth = Math.max(12, ...allSenseNames.map((n) => n.length));
470
+ const allStatuses = payload.senses.map((r) => r.status);
471
+ const statusWidth = Math.max(10, ...allStatuses.map((s) => s.length));
472
+ for (const [agent, rows] of sensesByAgent) {
473
+ lines.push(` ${bold(agent)}`);
474
+ for (const row of rows) {
475
+ const name = humanizeSenseName(row.sense, row.label).padEnd(nameWidth);
476
+ const dot = row.enabled ? statusDot(row.status) : dim("○");
477
+ const statusText = (row.enabled ? row.status : "disabled").padEnd(statusWidth);
478
+ lines.push(` ${name} ${dot} ${statusText} ${dim(formatSenseDetail(row))}`);
479
+ }
480
+ }
481
+ lines.push("");
482
+ }
483
+ // ── Workers ──
484
+ if (payload.workers.length > 0) {
485
+ lines.push(` ${teal("──")} ${bold("Workers")} ${teal("─".repeat(36))}`);
486
+ // Group workers by agent
487
+ const workersByAgent = new Map();
488
+ for (const row of payload.workers) {
489
+ const list = workersByAgent.get(row.agent) ?? [];
490
+ list.push(row);
491
+ workersByAgent.set(row.agent, list);
492
+ }
493
+ const allWorkerNames = payload.workers.map((r) => r.worker);
494
+ const workerNameWidth = Math.max(12, ...allWorkerNames.map((n) => n.length));
495
+ for (const [agent, rows] of workersByAgent) {
496
+ lines.push(` ${bold(agent)}`);
497
+ for (const row of rows) {
498
+ const name = row.worker.padEnd(workerNameWidth);
499
+ const dot = statusDot(row.status);
500
+ const pidStr = row.pid !== null ? `pid ${row.pid}` : "";
501
+ const restartStr = `restarts: ${row.restartCount}`;
502
+ /* v8 ignore start — exit info branches tested via daemon-crash-context; v8 misreports conditional chains @preserve */
503
+ let exitStr = "";
504
+ if (row.lastExitCode !== null)
505
+ exitStr = `exit=${row.lastExitCode}`;
506
+ if (row.lastSignal !== null)
507
+ exitStr = row.lastExitCode !== null ? `exit=${row.lastExitCode} sig=${row.lastSignal}` : `sig=${row.lastSignal}`;
508
+ /* v8 ignore stop */
509
+ const details = [pidStr, restartStr, exitStr].filter(Boolean).join(" ");
510
+ lines.push(` ${name} ${dot} ${row.status.padEnd(10)} ${dim(details)}`);
511
+ if (row.errorReason) {
512
+ lines.push(` ${dim(`error: ${row.errorReason}`)}`);
513
+ }
514
+ if (row.fixHint) {
515
+ lines.push(` ${dim(`fix: ${row.fixHint}`)}`);
516
+ }
517
+ }
518
+ }
519
+ lines.push("");
520
+ }
521
+ // ── Health Checks ──
522
+ if (payload.healthChecks.length > 0) {
523
+ lines.push(` ${teal("──")} ${bold("Health Checks")} ${teal("─".repeat(29))}`);
524
+ const nameWidth = Math.max(16, ...payload.healthChecks.map((r) => r.name.length));
525
+ const statusWidth = Math.max(8, ...payload.healthChecks.map((r) => r.status.length));
526
+ for (const row of payload.healthChecks) {
527
+ lines.push(` ${row.name.padEnd(nameWidth)} ${statusDot(row.status)} ${row.status.padEnd(statusWidth)} ${dim(row.message)}`);
528
+ }
529
+ lines.push("");
530
+ }
531
+ // ── Git Sync (per agent) ──
532
+ if (payload.sync.length > 0) {
533
+ lines.push(` ${teal("──")} ${bold("Git Sync")} ${teal("─".repeat(35))}`);
534
+ const agentNameWidth = Math.max(12, ...payload.sync.map((r) => r.agent.length));
535
+ for (const row of payload.sync) {
536
+ const name = row.agent.padEnd(agentNameWidth);
537
+ // Three states for enabled rows: error (not a repo), ok (remote URL), ok (local only).
538
+ // Disabled rows show the usual dim dot + "disabled".
539
+ let dot;
540
+ let stateText;
541
+ let detail;
542
+ if (!row.enabled) {
543
+ dot = dim("○");
544
+ stateText = "disabled".padEnd(10);
545
+ detail = "";
546
+ }
547
+ else if (row.gitInitialized === false) {
548
+ dot = red("●");
549
+ stateText = "error ".padEnd(10);
550
+ detail = "not a git repo — run `git init` to enable sync";
551
+ }
552
+ else if (row.remoteUrl !== undefined) {
553
+ dot = green("●");
554
+ stateText = "enabled ".padEnd(10);
555
+ detail = `${row.remote} → ${row.remoteUrl}`;
556
+ }
557
+ else {
558
+ dot = green("●");
559
+ stateText = "enabled ".padEnd(10);
560
+ detail = "local only";
561
+ }
562
+ lines.push(` ${name} ${dot} ${stateText} ${dim(detail)}`);
563
+ }
564
+ lines.push("");
565
+ }
566
+ return lines.join("\n");
567
+ }
568
+ function formatVersionOutput() {
569
+ const version = (0, runtime_metadata_1.getRuntimeMetadata)().version;
570
+ const mode = (0, runtime_mode_1.detectRuntimeMode)((0, identity_1.getRepoRoot)());
571
+ /* v8 ignore start — cosmetic display toggle; dev mode always true in test env */
572
+ return mode === "dev" ? `${version} (dev)` : version;
573
+ /* v8 ignore stop */
574
+ }
575
+ function buildStoppedStatusPayload(socketPath, syncRows = [], agentRows = []) {
576
+ const metadata = (0, runtime_metadata_1.getRuntimeMetadata)();
577
+ const repoRoot = (0, identity_1.getRepoRoot)();
578
+ return {
579
+ overview: {
580
+ daemon: "stopped",
581
+ health: "warn",
582
+ socketPath,
583
+ mailboxUrl: "unavailable",
584
+ outlookUrl: "unavailable",
585
+ version: metadata.version,
586
+ lastUpdated: metadata.lastUpdated,
587
+ repoRoot: metadata.repoRoot,
588
+ configFingerprint: metadata.configFingerprint,
589
+ workerCount: 0,
590
+ senseCount: 0,
591
+ entryPath: path.join(repoRoot, "dist", "heart", "daemon", "daemon-entry.js"),
592
+ mode: (0, runtime_mode_1.detectRuntimeMode)(repoRoot),
593
+ },
594
+ senses: [],
595
+ workers: [],
596
+ healthChecks: [],
597
+ sync: syncRows,
598
+ agents: agentRows,
599
+ providers: [],
600
+ };
601
+ }
602
+ /**
603
+ * Render the cached daemon-rollup status as a one-line string for the
604
+ * "daemon not running" view. Each `DaemonStatus` literal maps to a
605
+ * label + a brief explanatory copy fragment. The default branch is
606
+ * `never`-typed so future widening of `DaemonStatus` compile-errors
607
+ * here — Layer 1's compiler-forced exhaustiveness contract.
608
+ *
609
+ * The `degraded` literal splits into two copy variants based on the
610
+ * cached health file's `agents` map:
611
+ * - empty map → "no agents configured" (fresh-install copy).
612
+ * - non-empty map → "none ready" (all-agents-failed-live-check copy).
613
+ *
614
+ * The split lives at the render layer (not in the rollup status itself)
615
+ * so the same status can carry distinct UX copy without inflating the
616
+ * type union.
617
+ */
618
+ function renderRollupStatusLine(health) {
619
+ const status = health.status;
620
+ const tail = `(pid ${health.pid}, uptime ${health.uptimeSeconds}s)`;
621
+ /* v8 ignore next -- v8 instruments the switch statement itself as a branch; the never-typed default below is unreachable by construction so v8 cannot observe its branch firing @preserve */
622
+ switch (status) {
623
+ case "healthy":
624
+ return `Last known status: healthy ${tail}`;
625
+ case "partial": {
626
+ const unhealthyCount = Object.values(health.agents).filter((agent) => agent.status !== "running").length;
627
+ const parts = [];
628
+ if (unhealthyCount > 0) {
629
+ parts.push(`${unhealthyCount} agent${unhealthyCount === 1 ? "" : "s"} unhealthy`);
630
+ }
631
+ // Fallback for legacy cached files: status="partial" with no
632
+ // visible cause. Prompt refresh via `ouro up` rather than asserting
633
+ // a specific cause.
634
+ const detail = parts.length > 0
635
+ ? ` — ${parts.join("; ")}`
636
+ : " — stale cache, run `ouro up` to refresh";
637
+ return `Last known status: partial${detail} ${tail}`;
638
+ }
639
+ case "degraded": {
640
+ // Three-way copy split based on the cached agents map:
641
+ // - empty map → fresh install / no agents configured.
642
+ // - non-empty + any agent reports "running" → legacy stale cache:
643
+ // pre-Layer-1, status="degraded" meant "any sick component," so a
644
+ // running agent could coexist with a degraded daemon. Post-Layer-1,
645
+ // degraded means "zero serving" — mutually exclusive with a running
646
+ // agent. A live disagreement therefore implies the cache pre-dates
647
+ // the rollup-semantics fix; prompt for `ouro up` to refresh rather
648
+ // than falsely claim "none ready."
649
+ // - non-empty + zero agents reporting "running" → all-failed copy.
650
+ const agentEntries = Object.values(health.agents);
651
+ if (agentEntries.length === 0) {
652
+ return `Last known status: degraded — no agents configured (run \`ouro hatch\` to add one) ${tail}`;
653
+ }
654
+ const anyRunning = agentEntries.some((agent) => agent.status === "running");
655
+ if (anyRunning) {
656
+ return `Last known status: degraded — stale cache, run \`ouro up\` to refresh ${tail}`;
657
+ }
658
+ return `Last known status: degraded — agents configured but none ready (run \`ouro doctor\`) ${tail}`;
659
+ }
660
+ case "safe-mode":
661
+ return `Last known status: safe-mode — crash loop tripped ${tail}`;
662
+ case "down":
663
+ return `Last known status: down ${tail}`;
664
+ /* v8 ignore start -- compiler-forced exhaustiveness: the never-typed default branch is unreachable by construction; if DaemonStatus widens, tsc errors at the assignment before the throw can run @preserve */
665
+ default: {
666
+ // Compiler-forced exhaustiveness. If DaemonStatus grows a new
667
+ // literal, this `never` cast errors at tsc, forcing every
668
+ // consumer to handle it explicitly. NEVER replace this with a
669
+ // permissive `default:` returning a fallback string — that's
670
+ // exactly how the old "ok | degraded" semantics leaked through.
671
+ const _exhaustive = status;
672
+ throw new Error(`unhandled daemon status: ${_exhaustive}`);
673
+ }
674
+ /* v8 ignore stop */
675
+ }
676
+ }
677
+ function daemonUnavailableStatusOutput(socketPath, healthFilePath) {
678
+ // Read per-agent sync config and bundle list from disk so the user still
679
+ // sees them when the daemon is down. Best-effort: any fs error returns []
680
+ // and the corresponding section is omitted.
681
+ let syncRows = [];
682
+ let agentRows = [];
683
+ try {
684
+ syncRows = (0, agent_discovery_1.listBundleSyncRows)();
685
+ }
686
+ catch {
687
+ // listBundleSyncRows already swallows fs errors internally; this catch is a defensive
688
+ // safety net for environments where the fs module itself is partially mocked.
689
+ }
690
+ try {
691
+ agentRows = (0, agent_discovery_1.listAllBundleAgents)();
692
+ }
693
+ catch {
694
+ // Same defensive safety net for the bundle list.
695
+ }
696
+ /* v8 ignore start — tombstone read tested in daemon-status-tombstone.test; branch misreported @preserve */
697
+ const tombstone = (0, daemon_tombstone_1.readDaemonTombstone)();
698
+ const deathLine = tombstone
699
+ ? `Last death: ${tombstone.timestamp} -- ${tombstone.reason}: ${tombstone.message}`
700
+ : null;
701
+ /* v8 ignore stop */
702
+ const lines = [
703
+ formatDaemonStatusOutput({
704
+ ok: true,
705
+ summary: "daemon not running",
706
+ data: buildStoppedStatusPayload(socketPath, syncRows, agentRows),
707
+ }, "daemon not running"),
708
+ "",
709
+ ];
710
+ /* v8 ignore start — tombstone presence requires real daemon crash @preserve */
711
+ if (deathLine) {
712
+ lines.push(deathLine);
713
+ lines.push("");
714
+ /* v8 ignore stop */
715
+ }
716
+ // Read health file for last-known state (best-effort)
717
+ const resolvedHealthPath = healthFilePath ?? (0, daemon_health_1.getDefaultHealthPath)();
718
+ const health = (0, daemon_health_1.readHealth)(resolvedHealthPath);
719
+ if (health) {
720
+ lines.push(renderRollupStatusLine(health));
721
+ if (health.safeMode?.active) {
722
+ lines.push(`SAFE MODE: ${health.safeMode.reason}`);
723
+ }
724
+ if (health.degraded.length > 0) {
725
+ lines.push("");
726
+ lines.push("Degraded:");
727
+ for (const d of health.degraded) {
728
+ lines.push(` ${d.component}: ${d.reason} (since ${d.since})`);
729
+ }
730
+ }
731
+ lines.push("");
732
+ }
733
+ lines.push("daemon not running; run `ouro up`");
734
+ return lines.join("\n");
735
+ }
736
+ function isDaemonUnavailableError(error) {
737
+ const code = typeof error === "object" && error !== null && "code" in error
738
+ ? String(error.code ?? "")
739
+ : "";
740
+ return code === "ENOENT" || code === "ECONNREFUSED";
741
+ }
742
+ function formatMcpResponse(command, response) {
743
+ if (command.kind === "mcp.list") {
744
+ const allTools = response.data;
745
+ if (!allTools || allTools.length === 0) {
746
+ return response.message ?? "no tools available from connected MCP servers";
747
+ }
748
+ const lines = [];
749
+ for (const entry of allTools) {
750
+ lines.push(`[${entry.server}]`);
751
+ for (const tool of entry.tools) {
752
+ lines.push(` ${tool.name}: ${tool.description}`);
753
+ }
754
+ }
755
+ return lines.join("\n");
756
+ }
757
+ // mcp.call
758
+ const result = response.data;
759
+ if (!result) {
760
+ return response.message ?? "no result";
761
+ }
762
+ return result.content.map((c) => c.text).join("\n");
763
+ }