@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.550

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 (386) hide show
  1. package/README.md +133 -19
  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-bootstrap-drift.md +54 -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/changelog.json +3555 -0
  14. package/dist/arc/attention-types.js +8 -0
  15. package/dist/arc/cares.js +140 -0
  16. package/dist/arc/episodes.js +117 -0
  17. package/dist/arc/intentions.js +133 -0
  18. package/dist/arc/json-store.js +117 -0
  19. package/dist/arc/obligations.js +237 -0
  20. package/dist/arc/packets.js +193 -0
  21. package/dist/arc/presence.js +185 -0
  22. package/dist/arc/task-lifecycle.js +65 -0
  23. package/dist/heart/active-work.js +837 -26
  24. package/dist/heart/agent-entry.js +58 -3
  25. package/dist/heart/attachments/image-normalize.js +194 -0
  26. package/dist/heart/attachments/materialize.js +97 -0
  27. package/dist/heart/attachments/originals.js +88 -0
  28. package/dist/heart/attachments/render.js +29 -0
  29. package/dist/heart/attachments/sources/adapter.js +2 -0
  30. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  31. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  32. package/dist/heart/attachments/sources/index.js +16 -0
  33. package/dist/heart/attachments/store.js +103 -0
  34. package/dist/heart/attachments/types.js +93 -0
  35. package/dist/heart/auth/auth-flow.js +479 -0
  36. package/dist/heart/background-operations.js +281 -0
  37. package/dist/heart/bundle-state.js +168 -0
  38. package/dist/heart/commitments.js +111 -0
  39. package/dist/heart/config-registry.js +304 -0
  40. package/dist/heart/config.js +114 -118
  41. package/dist/heart/core.js +925 -246
  42. package/dist/heart/cross-chat-delivery.js +3 -18
  43. package/dist/heart/daemon/agent-config-check.js +512 -0
  44. package/dist/heart/daemon/agent-discovery.js +102 -3
  45. package/dist/heart/daemon/agent-service.js +522 -0
  46. package/dist/heart/daemon/agentic-repair.js +554 -0
  47. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  48. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  49. package/dist/heart/daemon/cadence.js +70 -0
  50. package/dist/heart/daemon/cli-defaults.js +665 -0
  51. package/dist/heart/daemon/cli-exec.js +7565 -0
  52. package/dist/heart/daemon/cli-help.js +498 -0
  53. package/dist/heart/daemon/cli-parse.js +1590 -0
  54. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  55. package/dist/heart/daemon/cli-render.js +775 -0
  56. package/dist/heart/daemon/cli-types.js +8 -0
  57. package/dist/heart/daemon/connect-bay.js +323 -0
  58. package/dist/heart/daemon/daemon-cli.js +29 -1672
  59. package/dist/heart/daemon/daemon-entry.js +417 -2
  60. package/dist/heart/daemon/daemon-health.js +183 -0
  61. package/dist/heart/daemon/daemon-rollup.js +58 -0
  62. package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
  63. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  64. package/dist/heart/daemon/daemon.js +758 -71
  65. package/dist/heart/daemon/dns-workflow.js +394 -0
  66. package/dist/heart/daemon/doctor-types.js +8 -0
  67. package/dist/heart/daemon/doctor.js +844 -0
  68. package/dist/heart/daemon/drift-detection.js +146 -0
  69. package/dist/heart/daemon/health-monitor.js +122 -1
  70. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  71. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  72. package/dist/heart/daemon/http-health-probe.js +80 -0
  73. package/dist/heart/daemon/human-command-screens.js +234 -0
  74. package/dist/heart/daemon/human-readiness.js +114 -0
  75. package/dist/heart/daemon/inner-status.js +102 -0
  76. package/dist/heart/daemon/interactive-repair.js +394 -0
  77. package/dist/heart/daemon/launchd.js +37 -8
  78. package/dist/heart/daemon/log-tailer.js +82 -12
  79. package/dist/heart/daemon/logs-prune.js +110 -0
  80. package/dist/heart/daemon/mcp-canary.js +297 -0
  81. package/dist/heart/daemon/message-router.js +2 -2
  82. package/dist/heart/daemon/os-cron-deps.js +135 -0
  83. package/dist/heart/daemon/os-cron.js +14 -12
  84. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  85. package/dist/heart/daemon/ouro-entry.js +3 -1
  86. package/dist/heart/daemon/process-manager.js +375 -33
  87. package/dist/heart/daemon/provider-discovery.js +137 -0
  88. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  89. package/dist/heart/daemon/pulse.js +475 -0
  90. package/dist/heart/daemon/readiness-repair.js +365 -0
  91. package/dist/heart/daemon/run-hooks.js +2 -0
  92. package/dist/heart/daemon/runtime-logging.js +67 -16
  93. package/dist/heart/daemon/runtime-metadata.js +3 -31
  94. package/dist/heart/daemon/safe-mode.js +161 -0
  95. package/dist/heart/daemon/sense-manager.js +353 -38
  96. package/dist/heart/daemon/session-id-resolver.js +131 -0
  97. package/dist/heart/daemon/skill-management-installer.js +94 -0
  98. package/dist/heart/daemon/socket-client.js +158 -11
  99. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  100. package/dist/heart/daemon/startup-tui.js +330 -0
  101. package/dist/heart/daemon/task-scheduler.js +3 -25
  102. package/dist/heart/daemon/terminal-ui.js +499 -0
  103. package/dist/heart/daemon/thoughts.js +162 -17
  104. package/dist/heart/daemon/up-progress.js +366 -0
  105. package/dist/heart/daemon/vault-items.js +56 -0
  106. package/dist/heart/delegation.js +1 -1
  107. package/dist/heart/habits/habit-migration.js +189 -0
  108. package/dist/heart/habits/habit-parser.js +140 -0
  109. package/dist/heart/habits/habit-runtime-state.js +100 -0
  110. package/dist/heart/habits/habit-scheduler.js +372 -0
  111. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  112. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  113. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  114. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  115. package/dist/heart/identity.js +200 -51
  116. package/dist/heart/kept-notes.js +357 -0
  117. package/dist/heart/kicks.js +1 -1
  118. package/dist/heart/machine-identity.js +161 -0
  119. package/dist/heart/mail-import-discovery.js +353 -0
  120. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  121. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  122. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  123. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  124. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  125. package/dist/heart/mailbox/mailbox-http.js +99 -0
  126. package/dist/heart/mailbox/mailbox-read.js +31 -0
  127. package/dist/heart/mailbox/mailbox-types.js +27 -0
  128. package/dist/heart/mailbox/mailbox-view.js +195 -0
  129. package/dist/heart/mailbox/readers/agent-machine.js +382 -0
  130. package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
  131. package/dist/heart/mailbox/readers/mail.js +362 -0
  132. package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
  133. package/dist/heart/mailbox/readers/sessions.js +232 -0
  134. package/dist/heart/mailbox/readers/shared.js +111 -0
  135. package/dist/heart/mcp/mcp-server.js +683 -0
  136. package/dist/heart/migrate-config.js +100 -0
  137. package/dist/heart/model-capabilities.js +19 -0
  138. package/dist/heart/platform.js +81 -0
  139. package/dist/heart/provider-attempt.js +134 -0
  140. package/dist/heart/provider-binding-resolver.js +255 -0
  141. package/dist/heart/provider-credentials.js +425 -0
  142. package/dist/heart/provider-failover.js +301 -0
  143. package/dist/heart/provider-models.js +81 -0
  144. package/dist/heart/provider-ping.js +262 -0
  145. package/dist/heart/provider-state.js +216 -0
  146. package/dist/heart/provider-visibility.js +188 -0
  147. package/dist/heart/providers/anthropic-token.js +131 -0
  148. package/dist/heart/providers/anthropic.js +139 -52
  149. package/dist/heart/providers/azure.js +97 -13
  150. package/dist/heart/providers/error-classification.js +127 -0
  151. package/dist/heart/providers/github-copilot.js +145 -0
  152. package/dist/heart/providers/minimax-vlm.js +189 -0
  153. package/dist/heart/providers/minimax.js +26 -8
  154. package/dist/heart/providers/openai-codex.js +55 -40
  155. package/dist/heart/runtime-capability-check.js +170 -0
  156. package/dist/heart/runtime-credentials.js +367 -0
  157. package/dist/heart/runtime-cwd.js +87 -0
  158. package/dist/heart/sense-truth.js +11 -4
  159. package/dist/heart/session-activity.js +43 -22
  160. package/dist/heart/session-events.js +1149 -0
  161. package/dist/heart/session-playback-cli-main.js +5 -0
  162. package/dist/heart/session-playback-cli.js +36 -0
  163. package/dist/heart/session-playback.js +231 -0
  164. package/dist/heart/session-stats-cli-main.js +5 -0
  165. package/dist/heart/session-stats.js +182 -0
  166. package/dist/heart/session-transcript.js +243 -0
  167. package/dist/heart/start-of-turn-packet.js +345 -0
  168. package/dist/heart/streaming.js +44 -27
  169. package/dist/heart/sync-classification.js +176 -0
  170. package/dist/heart/sync.js +449 -0
  171. package/dist/heart/target-resolution.js +9 -5
  172. package/dist/heart/tempo.js +93 -0
  173. package/dist/heart/temporal-view.js +41 -0
  174. package/dist/heart/timeouts.js +101 -0
  175. package/dist/heart/tool-activity-callbacks.js +59 -0
  176. package/dist/heart/tool-description.js +139 -0
  177. package/dist/heart/tool-friction.js +55 -0
  178. package/dist/heart/tool-loop.js +200 -0
  179. package/dist/heart/turn-context.js +381 -0
  180. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  181. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  182. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  183. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  184. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  185. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  186. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  187. package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
  188. package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -0
  189. package/dist/mailbox-ui/index.html +15 -0
  190. package/dist/mailroom/attention.js +167 -0
  191. package/dist/mailroom/autonomy.js +209 -0
  192. package/dist/mailroom/blob-store.js +674 -0
  193. package/dist/mailroom/body-cache.js +61 -0
  194. package/dist/mailroom/core.js +720 -0
  195. package/dist/mailroom/entry.js +160 -0
  196. package/dist/mailroom/file-store.js +430 -0
  197. package/dist/mailroom/mbox-import.js +383 -0
  198. package/dist/mailroom/outbound.js +380 -0
  199. package/dist/mailroom/policy.js +263 -0
  200. package/dist/mailroom/reader.js +233 -0
  201. package/dist/mailroom/search-cache.js +256 -0
  202. package/dist/mailroom/search-relevance.js +319 -0
  203. package/dist/mailroom/smtp-ingress.js +176 -0
  204. package/dist/mailroom/source-state.js +176 -0
  205. package/dist/mailroom/thread.js +109 -0
  206. package/dist/mailroom/travel-extract.js +89 -0
  207. package/dist/mind/bundle-manifest.js +7 -1
  208. package/dist/mind/context.js +165 -101
  209. package/dist/mind/diary-integrity.js +60 -0
  210. package/dist/mind/{memory.js → diary.js} +62 -75
  211. package/dist/mind/embedding-provider.js +60 -0
  212. package/dist/mind/file-state.js +179 -0
  213. package/dist/mind/friends/channel.js +30 -0
  214. package/dist/mind/friends/resolver.js +54 -2
  215. package/dist/mind/friends/store-file.js +39 -3
  216. package/dist/mind/friends/types.js +2 -2
  217. package/dist/mind/journal-index.js +161 -0
  218. package/dist/mind/note-search.js +268 -0
  219. package/dist/mind/obligation-steering.js +221 -0
  220. package/dist/mind/pending.js +4 -0
  221. package/dist/mind/prompt-refresh.js +3 -2
  222. package/dist/mind/prompt.js +995 -123
  223. package/dist/mind/provenance-trust.js +26 -0
  224. package/dist/mind/scrutiny.js +173 -0
  225. package/dist/nerves/cli-logging.js +7 -1
  226. package/dist/nerves/coverage/audit-rules.js +15 -6
  227. package/dist/nerves/coverage/audit.js +28 -2
  228. package/dist/nerves/coverage/cli.js +1 -1
  229. package/dist/nerves/coverage/contract.js +5 -5
  230. package/dist/nerves/coverage/file-completeness.js +139 -5
  231. package/dist/nerves/coverage/run-artifacts.js +1 -1
  232. package/dist/nerves/event-buffer.js +111 -0
  233. package/dist/nerves/index.js +224 -4
  234. package/dist/nerves/observation.js +20 -0
  235. package/dist/nerves/redact.js +79 -0
  236. package/dist/nerves/review/cli-main.js +5 -0
  237. package/dist/nerves/review/cli.js +156 -0
  238. package/dist/nerves/review/core.js +152 -0
  239. package/dist/nerves/runtime.js +5 -1
  240. package/dist/repertoire/ado-client.js +15 -56
  241. package/dist/repertoire/ado-semantic.js +11 -10
  242. package/dist/repertoire/api-client.js +97 -0
  243. package/dist/repertoire/bitwarden-store.js +816 -0
  244. package/dist/repertoire/bundle-templates.js +72 -0
  245. package/dist/repertoire/bw-installer.js +180 -0
  246. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  247. package/dist/repertoire/coding/context-pack.js +330 -0
  248. package/dist/repertoire/coding/feedback.js +197 -30
  249. package/dist/repertoire/coding/manager.js +158 -9
  250. package/dist/repertoire/coding/spawner.js +55 -9
  251. package/dist/repertoire/coding/tools.js +170 -7
  252. package/dist/repertoire/commerce-errors.js +109 -0
  253. package/dist/repertoire/commerce-self-test.js +156 -0
  254. package/dist/repertoire/credential-access.js +111 -0
  255. package/dist/repertoire/duffel-client.js +185 -0
  256. package/dist/repertoire/github-client.js +14 -55
  257. package/dist/repertoire/graph-client.js +11 -52
  258. package/dist/repertoire/guardrails.js +396 -0
  259. package/dist/repertoire/mcp-client.js +295 -0
  260. package/dist/repertoire/mcp-manager.js +362 -0
  261. package/dist/repertoire/mcp-tools.js +63 -0
  262. package/dist/repertoire/shell-sessions.js +133 -0
  263. package/dist/repertoire/skills.js +15 -24
  264. package/dist/repertoire/stripe-client.js +131 -0
  265. package/dist/repertoire/tasks/board.js +31 -5
  266. package/dist/repertoire/tasks/fix.js +182 -0
  267. package/dist/repertoire/tasks/index.js +16 -4
  268. package/dist/repertoire/tasks/lifecycle.js +2 -2
  269. package/dist/repertoire/tasks/parser.js +3 -2
  270. package/dist/repertoire/tasks/scanner.js +194 -37
  271. package/dist/repertoire/tasks/transitions.js +16 -78
  272. package/dist/repertoire/tool-results.js +29 -0
  273. package/dist/repertoire/tools-attachments.js +317 -0
  274. package/dist/repertoire/tools-base.js +47 -1075
  275. package/dist/repertoire/tools-bluebubbles.js +1 -0
  276. package/dist/repertoire/tools-bridge.js +142 -0
  277. package/dist/repertoire/tools-bundle.js +984 -0
  278. package/dist/repertoire/tools-config.js +185 -0
  279. package/dist/repertoire/tools-continuity.js +248 -0
  280. package/dist/repertoire/tools-credential.js +381 -0
  281. package/dist/repertoire/tools-files.js +342 -0
  282. package/dist/repertoire/tools-flight.js +224 -0
  283. package/dist/repertoire/tools-flow.js +119 -0
  284. package/dist/repertoire/tools-github.js +1 -7
  285. package/dist/repertoire/tools-mail.js +1857 -0
  286. package/dist/repertoire/tools-notes.js +421 -0
  287. package/dist/repertoire/tools-session.js +750 -0
  288. package/dist/repertoire/tools-shell.js +120 -0
  289. package/dist/repertoire/tools-stripe.js +180 -0
  290. package/dist/repertoire/tools-surface.js +243 -0
  291. package/dist/repertoire/tools-teams.js +9 -39
  292. package/dist/repertoire/tools-travel.js +125 -0
  293. package/dist/repertoire/tools-trip.js +604 -0
  294. package/dist/repertoire/tools-user-profile.js +144 -0
  295. package/dist/repertoire/tools-vault.js +40 -0
  296. package/dist/repertoire/tools.js +108 -100
  297. package/dist/repertoire/travel-api-client.js +360 -0
  298. package/dist/repertoire/user-profile.js +131 -0
  299. package/dist/repertoire/vault-setup.js +246 -0
  300. package/dist/repertoire/vault-unlock.js +561 -0
  301. package/dist/scripts/claude-code-hook.js +41 -0
  302. package/dist/scripts/claude-code-stop-hook.js +47 -0
  303. package/dist/senses/attention-queue.js +116 -0
  304. package/dist/senses/bluebubbles/active-turns.js +216 -0
  305. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  306. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  307. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  308. package/dist/senses/bluebubbles/entry.js +77 -0
  309. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  310. package/dist/senses/bluebubbles/index.js +2305 -0
  311. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  312. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  313. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  314. package/dist/senses/bluebubbles/processed-log.js +133 -0
  315. package/dist/senses/bluebubbles/replay.js +137 -0
  316. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  317. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  318. package/dist/senses/cli/bracketed-paste.js +82 -0
  319. package/dist/senses/cli/image-paste.js +287 -0
  320. package/dist/senses/cli/image-ref-navigation.js +75 -0
  321. package/dist/senses/cli/ink-app.js +156 -0
  322. package/dist/senses/cli/inline-diff.js +64 -0
  323. package/dist/senses/cli/input-keys.js +174 -0
  324. package/dist/senses/cli/kill-ring.js +86 -0
  325. package/dist/senses/cli/message-list.js +51 -0
  326. package/dist/senses/cli/ouro-tui.js +607 -0
  327. package/dist/senses/cli/spinner-imperative.js +135 -0
  328. package/dist/senses/cli/spinner.js +101 -0
  329. package/dist/senses/cli/status-line.js +60 -0
  330. package/dist/senses/cli/streaming-markdown.js +526 -0
  331. package/dist/senses/cli/tool-display.js +85 -0
  332. package/dist/senses/cli/tool-render.js +85 -0
  333. package/dist/senses/cli/tui-store.js +240 -0
  334. package/dist/senses/cli/virtual-list.js +35 -0
  335. package/dist/senses/cli-entry.js +60 -8
  336. package/dist/senses/cli-layout.js +187 -0
  337. package/dist/senses/cli.js +520 -209
  338. package/dist/senses/commands.js +66 -3
  339. package/dist/senses/habit-turn-message.js +108 -0
  340. package/dist/senses/inner-dialog-worker.js +175 -21
  341. package/dist/senses/inner-dialog.js +330 -27
  342. package/dist/senses/mail-entry.js +66 -0
  343. package/dist/senses/mail.js +379 -0
  344. package/dist/senses/pipeline.js +569 -182
  345. package/dist/senses/proactive-content-guard.js +51 -0
  346. package/dist/senses/shared-turn.js +248 -0
  347. package/dist/senses/surface-tool.js +68 -0
  348. package/dist/senses/teams-entry.js +60 -8
  349. package/dist/senses/teams.js +387 -98
  350. package/dist/senses/trust-gate.js +100 -5
  351. package/dist/trips/core.js +138 -0
  352. package/dist/trips/store.js +146 -0
  353. package/package.json +38 -7
  354. package/skills/agent-commerce.md +106 -0
  355. package/skills/browser-navigation.md +117 -0
  356. package/skills/commerce-setup-guide.md +116 -0
  357. package/skills/commerce-setup.md +84 -0
  358. package/skills/configure-dev-tools.md +101 -0
  359. package/skills/travel-planning.md +138 -0
  360. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  361. package/dist/heart/daemon/subagent-installer.js +0 -166
  362. package/dist/heart/session-recall.js +0 -116
  363. package/dist/mind/associative-recall.js +0 -209
  364. package/dist/senses/bluebubbles-entry.js +0 -13
  365. package/dist/senses/bluebubbles.js +0 -1177
  366. package/dist/senses/debug-activity.js +0 -148
  367. package/subagents/README.md +0 -86
  368. package/subagents/work-doer.md +0 -237
  369. package/subagents/work-merger.md +0 -618
  370. package/subagents/work-planner.md +0 -390
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  372. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  373. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  374. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  375. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  376. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  380. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  381. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  382. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  383. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  384. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  385. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  386. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectProviderBindingDrift = detectProviderBindingDrift;
37
+ exports.loadDriftInputsForAgent = loadDriftInputsForAgent;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const provider_state_1 = require("../provider-state");
41
+ /**
42
+ * Pull the per-lane intent out of an agent.json view, preferring the new
43
+ * `outward`/`inner` keys over the legacy `humanFacing`/`agentFacing` keys
44
+ * when both are present. Returns `null` if neither set carries a usable
45
+ * binding for this lane (the comparator treats that as "no intent to
46
+ * compare against" and emits no drift for that lane).
47
+ */
48
+ function resolveLaneIntent(agentJson, lane) {
49
+ const newKey = lane === "outward" ? agentJson.outward : agentJson.inner;
50
+ if (newKey && typeof newKey.provider === "string" && typeof newKey.model === "string") {
51
+ return { provider: newKey.provider, model: newKey.model };
52
+ }
53
+ const legacy = lane === "outward" ? agentJson.humanFacing : agentJson.agentFacing;
54
+ if (legacy && typeof legacy.provider === "string" && typeof legacy.model === "string") {
55
+ return { provider: legacy.provider, model: legacy.model };
56
+ }
57
+ return null;
58
+ }
59
+ function buildRepairCommand(agentName, lane, provider, model) {
60
+ return `ouro use --agent ${agentName} --lane ${lane} --provider ${provider} --model ${model}`;
61
+ }
62
+ /**
63
+ * Pure intent-vs-observed comparator. Emits one `DriftFinding` per lane
64
+ * whose intent (agent.json) does not match its observation
65
+ * (state/providers.json).
66
+ *
67
+ * Returns `[]` when:
68
+ * - `providerState === null` (fresh install, nothing to drift against), OR
69
+ * - both lanes match, OR
70
+ * - a lane has no intent in agent.json AND no observation in providerState
71
+ * (deferred to other layers — drift detection is silent on that lane).
72
+ */
73
+ function detectProviderBindingDrift(input) {
74
+ if (input.providerState === null) {
75
+ return [];
76
+ }
77
+ const findings = [];
78
+ const lanes = ["outward", "inner"];
79
+ for (const lane of lanes) {
80
+ const intent = resolveLaneIntent(input.agentJson, lane);
81
+ if (!intent)
82
+ continue;
83
+ const observed = input.providerState.lanes[lane];
84
+ if (intent.provider === observed.provider && intent.model === observed.model) {
85
+ continue;
86
+ }
87
+ findings.push({
88
+ agent: input.agentName,
89
+ lane,
90
+ intentProvider: intent.provider,
91
+ intentModel: intent.model,
92
+ observedProvider: observed.provider,
93
+ observedModel: observed.model,
94
+ reason: "provider-model-changed",
95
+ repairCommand: buildRepairCommand(input.agentName, lane, intent.provider, intent.model),
96
+ });
97
+ }
98
+ return findings;
99
+ }
100
+ function agentRootFor(bundlesRoot, agentName) {
101
+ return path.join(bundlesRoot, `${agentName}.ouro`);
102
+ }
103
+ function readAgentJson(agentJsonPath) {
104
+ let raw;
105
+ try {
106
+ raw = fs.readFileSync(agentJsonPath, "utf-8");
107
+ }
108
+ catch {
109
+ throw new Error(`agent.json not found at ${agentJsonPath}`);
110
+ }
111
+ let parsed;
112
+ try {
113
+ parsed = JSON.parse(raw);
114
+ }
115
+ catch (error) {
116
+ throw new Error(`agent.json at ${agentJsonPath} contains invalid JSON: ${String(error)}`);
117
+ }
118
+ // The drift loader is intentionally permissive: it parses the file as a
119
+ // typed `AgentConfig` view but does not validate every field. The
120
+ // comparator (Unit 1) is the one that decides which intent fields are
121
+ // usable; non-conforming bindings just silently skip drift detection
122
+ // on that lane. Stricter validation belongs to `loadAgentConfig` in
123
+ // identity.ts (which also has side effects we don't want here).
124
+ return parsed;
125
+ }
126
+ /**
127
+ * Loader for the drift comparator. Reads the per-agent `agent.json` and
128
+ * `state/providers.json` off disk, returning typed inputs ready to feed
129
+ * into `detectProviderBindingDrift`.
130
+ *
131
+ * - Throws when `agent.json` is missing or unparseable. The caller decides
132
+ * whether to swallow (drift detection has no opinion on a broken
133
+ * `agent.json` — that's the existing `agent-config-check` flow's job).
134
+ * - Returns `providerState: null` when `state/providers.json` is missing
135
+ * (fresh install) or invalid (the comparator interprets `null` as "no
136
+ * observation, nothing to drift against").
137
+ * - Never writes to disk.
138
+ */
139
+ function loadDriftInputsForAgent(bundlesRoot, agentName) {
140
+ const agentRoot = agentRootFor(bundlesRoot, agentName);
141
+ const agentJsonPath = path.join(agentRoot, "agent.json");
142
+ const agentJson = readAgentJson(agentJsonPath);
143
+ const stateResult = (0, provider_state_1.readProviderState)(agentRoot);
144
+ const providerState = stateResult.ok ? stateResult.state : null;
145
+ return { agentJson, providerState };
146
+ }
@@ -7,22 +7,100 @@ class HealthMonitor {
7
7
  scheduler;
8
8
  alertSink;
9
9
  diskUsagePercent;
10
+ onCriticalAgent;
11
+ onCriticalSense;
12
+ senseProbes;
13
+ senseProbeProvider;
14
+ intervalHandle = null;
15
+ lastResults = [];
10
16
  constructor(options) {
11
17
  this.processManager = options.processManager;
12
18
  this.scheduler = options.scheduler;
13
19
  this.alertSink = options.alertSink ?? (() => undefined);
14
20
  this.diskUsagePercent = options.diskUsagePercent ?? (() => 0);
21
+ this.onCriticalAgent = options.onCriticalAgent ?? (() => undefined);
22
+ this.onCriticalSense = options.onCriticalSense ?? (() => undefined);
23
+ this.senseProbes = options.senseProbes ?? [];
24
+ this.senseProbeProvider = options.senseProbeProvider ?? (() => []);
25
+ }
26
+ triggerSenseRecovery(probe, detail) {
27
+ if (!probe.managedName)
28
+ return;
29
+ try {
30
+ (0, runtime_1.emitNervesEvent)({
31
+ level: "warn",
32
+ component: "daemon",
33
+ event: "daemon.health_check_sense_recovery_attempted",
34
+ message: "triggering recovery restart for failed sense probe",
35
+ meta: {
36
+ probeName: probe.name,
37
+ managedName: probe.managedName,
38
+ detail,
39
+ },
40
+ });
41
+ this.onCriticalSense(probe.managedName, probe.name);
42
+ }
43
+ catch {
44
+ // Recovery is best-effort -- callback errors must not crash runChecks
45
+ }
46
+ }
47
+ startPeriodicChecks(intervalMs) {
48
+ if (this.intervalHandle !== null)
49
+ return;
50
+ (0, runtime_1.emitNervesEvent)({
51
+ level: "info",
52
+ component: "daemon",
53
+ event: "daemon.health_check_scheduled",
54
+ message: "periodic health checks started",
55
+ meta: { intervalMs },
56
+ });
57
+ this.intervalHandle = setInterval(() => {
58
+ void this.runChecks();
59
+ }, intervalMs);
60
+ }
61
+ stopPeriodicChecks() {
62
+ if (this.intervalHandle === null)
63
+ return;
64
+ clearInterval(this.intervalHandle);
65
+ this.intervalHandle = null;
15
66
  }
16
67
  async runChecks() {
17
68
  const results = [];
18
69
  const snapshots = this.processManager.listAgentSnapshots();
19
70
  const unhealthy = snapshots.filter((snapshot) => snapshot.status !== "running");
20
71
  if (unhealthy.length > 0) {
72
+ const unhealthySummary = unhealthy.map((item) => {
73
+ const detail = [
74
+ item.errorReason ?? null,
75
+ item.fixHint ? `fix: ${item.fixHint}` : null,
76
+ ].filter((part) => part !== null).join("; ");
77
+ return detail.length > 0 ? `${item.name} (${detail})` : item.name;
78
+ }).join(", ");
21
79
  results.push({
22
80
  name: "agent-processes",
23
81
  status: "critical",
24
- message: `non-running agents: ${unhealthy.map((item) => item.name).join(", ")}`,
82
+ message: `non-running agents: ${unhealthySummary}`,
25
83
  });
84
+ for (const agent of unhealthy) {
85
+ try {
86
+ (0, runtime_1.emitNervesEvent)({
87
+ level: "warn",
88
+ component: "daemon",
89
+ event: "daemon.health_check_recovery_attempted",
90
+ message: "triggering recovery restart for non-running agent",
91
+ meta: {
92
+ agentName: agent.name,
93
+ agentStatus: agent.status,
94
+ errorReason: agent.errorReason ?? null,
95
+ fixHint: agent.fixHint ?? null,
96
+ },
97
+ });
98
+ this.onCriticalAgent(agent.name);
99
+ }
100
+ catch {
101
+ // Recovery is best-effort -- callback errors must not crash runChecks
102
+ }
103
+ }
26
104
  }
27
105
  else {
28
106
  results.push({ name: "agent-processes", status: "ok", message: "all managed agents running" });
@@ -61,6 +139,46 @@ class HealthMonitor {
61
139
  message: `disk usage healthy (${diskPercent}%)`,
62
140
  });
63
141
  }
142
+ const senseProbes = [...this.senseProbes];
143
+ try {
144
+ senseProbes.push(...this.senseProbeProvider());
145
+ }
146
+ catch (error) {
147
+ results.push({
148
+ name: "sense-probes",
149
+ status: "warn",
150
+ message: `sense probe discovery failed: ${error instanceof Error ? error.message : String(error)}`,
151
+ });
152
+ }
153
+ for (const probe of senseProbes) {
154
+ try {
155
+ const outcome = await probe.check();
156
+ if (outcome.ok) {
157
+ results.push({
158
+ name: `sense-probe:${probe.name}`,
159
+ status: "ok",
160
+ message: `${probe.name} healthy`,
161
+ });
162
+ }
163
+ else {
164
+ this.triggerSenseRecovery(probe, outcome.detail ?? "unknown");
165
+ results.push({
166
+ name: `sense-probe:${probe.name}`,
167
+ status: "critical",
168
+ message: `${probe.name} failed: ${outcome.detail ?? "unknown"}`,
169
+ });
170
+ }
171
+ }
172
+ catch (error) {
173
+ this.triggerSenseRecovery(probe, error instanceof Error ? error.message : String(error));
174
+ results.push({
175
+ name: `sense-probe:${probe.name}`,
176
+ status: "critical",
177
+ message: `${probe.name} error: ${error instanceof Error ? error.message : String(error)}`,
178
+ });
179
+ }
180
+ }
181
+ this.lastResults = results.map((result) => ({ ...result }));
64
182
  for (const result of results) {
65
183
  (0, runtime_1.emitNervesEvent)({
66
184
  level: result.status === "critical" ? "error" : result.status === "warn" ? "warn" : "info",
@@ -75,5 +193,8 @@ class HealthMonitor {
75
193
  }
76
194
  return results;
77
195
  }
196
+ getLastResults() {
197
+ return this.lastResults.map((result) => ({ ...result }));
198
+ }
78
199
  }
79
200
  exports.HealthMonitor = HealthMonitor;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.agentConfigV2Hook = agentConfigV2Hook;
4
+ const runtime_1 = require("../../../nerves/runtime");
5
+ const migrate_config_1 = require("../../migrate-config");
6
+ async function agentConfigV2Hook(ctx) {
7
+ (0, runtime_1.emitNervesEvent)({
8
+ component: "daemon",
9
+ event: "daemon.agent_config_v2_hook_start",
10
+ message: "running agent-config-v2 update hook",
11
+ meta: { agentRoot: ctx.agentRoot, currentVersion: ctx.currentVersion },
12
+ });
13
+ try {
14
+ (0, migrate_config_1.migrateAgentConfigV1ToV2)(ctx.agentRoot);
15
+ }
16
+ catch (err) {
17
+ const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
18
+ (0, runtime_1.emitNervesEvent)({
19
+ component: "daemon",
20
+ event: "daemon.agent_config_v2_hook_error",
21
+ message: "agent-config-v2 hook migration failed",
22
+ meta: { agentRoot: ctx.agentRoot, error: errorMessage },
23
+ });
24
+ return { ok: false, error: errorMessage };
25
+ }
26
+ (0, runtime_1.emitNervesEvent)({
27
+ component: "daemon",
28
+ event: "daemon.agent_config_v2_hook_end",
29
+ message: "agent-config-v2 hook completed",
30
+ meta: { agentRoot: ctx.agentRoot },
31
+ });
32
+ return { ok: true };
33
+ }
@@ -37,6 +37,115 @@ exports.bundleMetaHook = bundleMetaHook;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const runtime_1 = require("../../../nerves/runtime");
40
+ /**
41
+ * Migrate bundle from schema 1 to schema 2:
42
+ * - Move state/{episodes,obligations,cares,intentions}/* to arc/{name}/*
43
+ * - Move the old psyche note store to diary/
44
+ * Idempotent: skips missing sources; on collision, newer mtime wins.
45
+ */
46
+ function migrateToSchema2(agentRoot) {
47
+ (0, runtime_1.emitNervesEvent)({
48
+ component: "daemon",
49
+ event: "daemon.bundle_migration_start",
50
+ message: "migrating bundle to schema 2",
51
+ meta: { agentRoot },
52
+ });
53
+ // Migrate arc entities
54
+ for (const name of ["episodes", "obligations", "cares", "intentions"]) {
55
+ const src = path.join(agentRoot, "state", name);
56
+ const dest = path.join(agentRoot, "arc", name);
57
+ migrateDirectory(src, dest);
58
+ }
59
+ // Migrate diary from the old pre-diary bundle layout.
60
+ const legacyDiarySrc = path.join(agentRoot, "psyche", "mem" + "ory");
61
+ const diaryDest = path.join(agentRoot, "diary");
62
+ migrateDirectory(legacyDiarySrc, diaryDest);
63
+ // Update bundle .gitignore
64
+ updateBundleGitignore(agentRoot);
65
+ (0, runtime_1.emitNervesEvent)({
66
+ component: "daemon",
67
+ event: "daemon.bundle_migration_end",
68
+ message: "bundle migration to schema 2 complete",
69
+ meta: { agentRoot },
70
+ });
71
+ }
72
+ /**
73
+ * Ensure bundle .gitignore has state/ ignored and does NOT ignore arc/, diary/, journal/.
74
+ */
75
+ function updateBundleGitignore(agentRoot) {
76
+ const gitignorePath = path.join(agentRoot, ".gitignore");
77
+ let lines = [];
78
+ try {
79
+ if (fs.existsSync(gitignorePath)) {
80
+ lines = fs.readFileSync(gitignorePath, "utf-8").split("\n");
81
+ }
82
+ }
83
+ catch {
84
+ // If we can't read, start fresh
85
+ }
86
+ // Remove arc/, diary/, journal/ from ignore (they should be tracked)
87
+ const toRemove = new Set(["arc/", "diary/", "journal/"]);
88
+ lines = lines.filter((line) => !toRemove.has(line.trim()));
89
+ // Ensure state/ is in the ignore list
90
+ const hasState = lines.some((line) => line.trim() === "state/");
91
+ if (!hasState) {
92
+ lines.push("state/");
93
+ }
94
+ // Write back, trimming trailing empty lines and ensuring trailing newline
95
+ const content = lines.join("\n").replace(/\n+$/, "") + "\n";
96
+ try {
97
+ fs.writeFileSync(gitignorePath, content, "utf-8");
98
+ }
99
+ catch {
100
+ // Non-blocking: if we can't write .gitignore, migration still succeeds
101
+ }
102
+ }
103
+ /**
104
+ * Recursively copy files from src to dest.
105
+ * Creates destination directories as needed. Skips if source doesn't exist.
106
+ * When both source and destination exist, compares mtimes: newer file wins.
107
+ * Logs a warning either way when a collision is detected.
108
+ */
109
+ function migrateDirectory(src, dest) {
110
+ if (!fs.existsSync(src))
111
+ return;
112
+ fs.mkdirSync(dest, { recursive: true });
113
+ const entries = fs.readdirSync(src, { withFileTypes: true });
114
+ for (const entry of entries) {
115
+ const srcPath = path.join(src, entry.name);
116
+ const destPath = path.join(dest, entry.name);
117
+ if (entry.isDirectory()) {
118
+ migrateDirectory(srcPath, destPath);
119
+ }
120
+ else if (!fs.existsSync(destPath)) {
121
+ fs.copyFileSync(srcPath, destPath);
122
+ }
123
+ else {
124
+ // Collision: both source and destination exist — compare mtimes
125
+ const srcMtime = fs.statSync(srcPath).mtimeMs;
126
+ const destMtime = fs.statSync(destPath).mtimeMs;
127
+ if (srcMtime > destMtime) {
128
+ fs.copyFileSync(srcPath, destPath);
129
+ (0, runtime_1.emitNervesEvent)({
130
+ level: "warn",
131
+ component: "daemon",
132
+ event: "daemon.bundle_migration_collision",
133
+ message: `migration collision: source newer, overwriting destination`,
134
+ meta: { srcPath, destPath, srcMtime, destMtime },
135
+ });
136
+ }
137
+ else {
138
+ (0, runtime_1.emitNervesEvent)({
139
+ level: "warn",
140
+ component: "daemon",
141
+ event: "daemon.bundle_migration_collision",
142
+ message: `migration collision: destination newer or equal, keeping destination`,
143
+ meta: { srcPath, destPath, srcMtime, destMtime },
144
+ });
145
+ }
146
+ }
147
+ }
148
+ }
40
149
  async function bundleMetaHook(ctx) {
41
150
  (0, runtime_1.emitNervesEvent)({
42
151
  component: "daemon",
@@ -56,9 +165,14 @@ async function bundleMetaHook(ctx) {
56
165
  // Malformed JSON -- treat as missing, will overwrite with fresh
57
166
  existing = undefined;
58
167
  }
168
+ // Run schema-2 migration if needed
169
+ const currentSchema = existing?.bundleSchemaVersion ?? 1;
170
+ if (currentSchema < 2) {
171
+ migrateToSchema2(ctx.agentRoot);
172
+ }
59
173
  const updated = {
60
174
  runtimeVersion: ctx.currentVersion,
61
- bundleSchemaVersion: existing?.bundleSchemaVersion ?? 1,
175
+ bundleSchemaVersion: currentSchema < 2 ? 2 : currentSchema,
62
176
  lastUpdated: new Date().toISOString(),
63
177
  };
64
178
  // Save old runtimeVersion as previousRuntimeVersion (if there was one)
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createHttpHealthProbe = createHttpHealthProbe;
37
+ const http = __importStar(require("node:http"));
38
+ function createHttpHealthProbe(name, port, timeoutMs = 5000) {
39
+ return {
40
+ name,
41
+ check: () => new Promise((resolve) => {
42
+ const req = http.get({
43
+ hostname: "127.0.0.1",
44
+ port,
45
+ path: "/health",
46
+ timeout: timeoutMs,
47
+ }, (res) => {
48
+ let body = "";
49
+ res.on("data", (chunk) => {
50
+ body += chunk.toString();
51
+ });
52
+ res.on("end", () => {
53
+ if (res.statusCode !== 200) {
54
+ resolve({ ok: false, detail: `HTTP ${res.statusCode}` });
55
+ return;
56
+ }
57
+ try {
58
+ const parsed = JSON.parse(body);
59
+ if (parsed.status === "ok") {
60
+ resolve({ ok: true });
61
+ }
62
+ else {
63
+ resolve({ ok: false, detail: `unexpected status: ${String(parsed.status)}` });
64
+ }
65
+ }
66
+ catch {
67
+ resolve({ ok: false, detail: "invalid JSON response" });
68
+ }
69
+ });
70
+ });
71
+ req.on("timeout", () => {
72
+ req.destroy();
73
+ resolve({ ok: false, detail: "timeout" });
74
+ });
75
+ req.on("error", (err) => {
76
+ resolve({ ok: false, detail: err.message });
77
+ });
78
+ }),
79
+ };
80
+ }