@ouro.bot/cli 0.1.0-alpha.52 → 0.1.0-alpha.521

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 (383) 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 +3361 -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 +427 -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 +119 -129
  41. package/dist/heart/core.js +948 -243
  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 +360 -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 +643 -0
  51. package/dist/heart/daemon/cli-exec.js +7476 -0
  52. package/dist/heart/daemon/cli-help.js +493 -0
  53. package/dist/heart/daemon/cli-parse.js +1557 -0
  54. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  55. package/dist/heart/daemon/cli-render.js +649 -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 -1631
  59. package/dist/heart/daemon/daemon-entry.js +404 -3
  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 +190 -12
  63. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  64. package/dist/heart/daemon/daemon.js +758 -60
  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 +837 -0
  68. package/dist/heart/daemon/drift-detection.js +146 -0
  69. package/dist/heart/daemon/health-monitor.js +92 -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 +25 -5
  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/message-router.js +2 -2
  81. package/dist/heart/daemon/os-cron-deps.js +134 -0
  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 +381 -26
  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 +73 -0
  92. package/dist/heart/daemon/runtime-mode.js +67 -0
  93. package/dist/heart/daemon/safe-mode.js +161 -0
  94. package/dist/heart/daemon/sense-manager.js +259 -37
  95. package/dist/heart/daemon/session-id-resolver.js +131 -0
  96. package/dist/heart/daemon/skill-management-installer.js +94 -0
  97. package/dist/heart/daemon/socket-client.js +109 -4
  98. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  99. package/dist/heart/daemon/startup-tui.js +330 -0
  100. package/dist/heart/daemon/task-scheduler.js +3 -25
  101. package/dist/heart/daemon/terminal-ui.js +499 -0
  102. package/dist/heart/daemon/thoughts.js +162 -17
  103. package/dist/heart/daemon/up-progress.js +366 -0
  104. package/dist/heart/daemon/vault-items.js +56 -0
  105. package/dist/heart/delegation.js +1 -1
  106. package/dist/heart/habits/habit-migration.js +189 -0
  107. package/dist/heart/habits/habit-parser.js +140 -0
  108. package/dist/heart/habits/habit-runtime-state.js +100 -0
  109. package/dist/heart/habits/habit-scheduler.js +372 -0
  110. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  111. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  112. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  113. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  114. package/dist/heart/identity.js +205 -66
  115. package/dist/heart/kept-notes.js +357 -0
  116. package/dist/heart/kicks.js +1 -1
  117. package/dist/heart/machine-identity.js +161 -0
  118. package/dist/heart/mail-import-discovery.js +353 -0
  119. package/dist/heart/mcp/mcp-server.js +653 -0
  120. package/dist/heart/migrate-config.js +100 -0
  121. package/dist/heart/model-capabilities.js +19 -0
  122. package/dist/heart/outlook/outlook-http-hooks.js +66 -0
  123. package/dist/heart/outlook/outlook-http-response.js +7 -0
  124. package/dist/heart/outlook/outlook-http-routes.js +244 -0
  125. package/dist/heart/outlook/outlook-http-static.js +103 -0
  126. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  127. package/dist/heart/outlook/outlook-http.js +99 -0
  128. package/dist/heart/outlook/outlook-read.js +31 -0
  129. package/dist/heart/outlook/outlook-types.js +27 -0
  130. package/dist/heart/outlook/outlook-view.js +195 -0
  131. package/dist/heart/outlook/readers/agent-machine.js +382 -0
  132. package/dist/heart/outlook/readers/continuity-readers.js +336 -0
  133. package/dist/heart/outlook/readers/mail.js +362 -0
  134. package/dist/heart/outlook/readers/runtime-readers.js +650 -0
  135. package/dist/heart/outlook/readers/sessions.js +232 -0
  136. package/dist/heart/outlook/readers/shared.js +111 -0
  137. package/dist/heart/platform.js +81 -0
  138. package/dist/heart/provider-attempt.js +134 -0
  139. package/dist/heart/provider-binding-resolver.js +255 -0
  140. package/dist/heart/provider-credentials.js +425 -0
  141. package/dist/heart/provider-failover.js +301 -0
  142. package/dist/heart/provider-models.js +81 -0
  143. package/dist/heart/provider-ping.js +262 -0
  144. package/dist/heart/provider-state.js +216 -0
  145. package/dist/heart/provider-visibility.js +188 -0
  146. package/dist/heart/providers/anthropic-token.js +131 -0
  147. package/dist/heart/providers/anthropic.js +139 -52
  148. package/dist/heart/providers/azure.js +97 -13
  149. package/dist/heart/providers/error-classification.js +127 -0
  150. package/dist/heart/providers/github-copilot.js +145 -0
  151. package/dist/heart/providers/minimax-vlm.js +189 -0
  152. package/dist/heart/providers/minimax.js +26 -8
  153. package/dist/heart/providers/openai-codex.js +55 -40
  154. package/dist/heart/runtime-capability-check.js +170 -0
  155. package/dist/heart/runtime-credentials.js +367 -0
  156. package/dist/heart/sense-truth.js +11 -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 +36 -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 +381 -0
  178. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  179. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  180. package/dist/heart/versioning/ouro-path-installer.js +425 -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 +5 -1
  184. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  185. package/dist/mailroom/attention.js +167 -0
  186. package/dist/mailroom/autonomy.js +209 -0
  187. package/dist/mailroom/blob-store.js +606 -0
  188. package/dist/mailroom/body-cache.js +61 -0
  189. package/dist/mailroom/core.js +672 -0
  190. package/dist/mailroom/entry.js +160 -0
  191. package/dist/mailroom/file-store.js +426 -0
  192. package/dist/mailroom/mbox-import.js +382 -0
  193. package/dist/mailroom/outbound.js +380 -0
  194. package/dist/mailroom/policy.js +263 -0
  195. package/dist/mailroom/reader.js +228 -0
  196. package/dist/mailroom/search-cache.js +182 -0
  197. package/dist/mailroom/search-relevance.js +319 -0
  198. package/dist/mailroom/smtp-ingress.js +176 -0
  199. package/dist/mailroom/source-state.js +176 -0
  200. package/dist/mailroom/thread.js +109 -0
  201. package/dist/mailroom/travel-extract.js +89 -0
  202. package/dist/mind/bundle-manifest.js +7 -1
  203. package/dist/mind/context.js +165 -101
  204. package/dist/mind/diary-integrity.js +60 -0
  205. package/dist/mind/{memory.js → diary.js} +74 -93
  206. package/dist/mind/embedding-provider.js +60 -0
  207. package/dist/mind/file-state.js +179 -0
  208. package/dist/mind/friends/channel.js +30 -0
  209. package/dist/mind/friends/resolver.js +54 -2
  210. package/dist/mind/friends/store-file.js +39 -3
  211. package/dist/mind/friends/types.js +2 -2
  212. package/dist/mind/journal-index.js +161 -0
  213. package/dist/mind/note-search.js +268 -0
  214. package/dist/mind/obligation-steering.js +221 -0
  215. package/dist/mind/pending.js +4 -0
  216. package/dist/mind/prompt-refresh.js +3 -2
  217. package/dist/mind/prompt.js +942 -122
  218. package/dist/mind/provenance-trust.js +26 -0
  219. package/dist/mind/scrutiny.js +173 -0
  220. package/dist/nerves/cli-logging.js +7 -1
  221. package/dist/nerves/coverage/audit-rules.js +15 -6
  222. package/dist/nerves/coverage/audit.js +28 -2
  223. package/dist/nerves/coverage/cli.js +1 -1
  224. package/dist/nerves/coverage/contract.js +5 -5
  225. package/dist/nerves/coverage/file-completeness.js +139 -5
  226. package/dist/nerves/coverage/run-artifacts.js +1 -1
  227. package/dist/nerves/event-buffer.js +111 -0
  228. package/dist/nerves/index.js +224 -4
  229. package/dist/nerves/observation.js +20 -0
  230. package/dist/nerves/redact.js +79 -0
  231. package/dist/nerves/review/cli-main.js +5 -0
  232. package/dist/nerves/review/cli.js +156 -0
  233. package/dist/nerves/review/core.js +152 -0
  234. package/dist/nerves/runtime.js +5 -1
  235. package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
  236. package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
  237. package/dist/outlook-ui/index.html +15 -0
  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 +816 -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 +111 -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 +255 -0
  258. package/dist/repertoire/mcp-manager.js +305 -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 +1477 -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 +422 -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 +561 -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/attachment-cache.js +53 -0
  303. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  304. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  305. package/dist/senses/bluebubbles/entry.js +77 -0
  306. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  307. package/dist/senses/bluebubbles/index.js +1947 -0
  308. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  309. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  310. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  311. package/dist/senses/bluebubbles/processed-log.js +111 -0
  312. package/dist/senses/bluebubbles/replay.js +129 -0
  313. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
  314. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  315. package/dist/senses/cli/bracketed-paste.js +82 -0
  316. package/dist/senses/cli/image-paste.js +287 -0
  317. package/dist/senses/cli/image-ref-navigation.js +75 -0
  318. package/dist/senses/cli/ink-app.js +156 -0
  319. package/dist/senses/cli/inline-diff.js +64 -0
  320. package/dist/senses/cli/input-keys.js +174 -0
  321. package/dist/senses/cli/kill-ring.js +86 -0
  322. package/dist/senses/cli/message-list.js +51 -0
  323. package/dist/senses/cli/ouro-tui.js +607 -0
  324. package/dist/senses/cli/spinner-imperative.js +135 -0
  325. package/dist/senses/cli/spinner.js +101 -0
  326. package/dist/senses/cli/status-line.js +60 -0
  327. package/dist/senses/cli/streaming-markdown.js +526 -0
  328. package/dist/senses/cli/tool-display.js +85 -0
  329. package/dist/senses/cli/tool-render.js +85 -0
  330. package/dist/senses/cli/tui-store.js +240 -0
  331. package/dist/senses/cli/virtual-list.js +35 -0
  332. package/dist/senses/cli-entry.js +60 -8
  333. package/dist/senses/cli-layout.js +187 -0
  334. package/dist/senses/cli.js +520 -209
  335. package/dist/senses/commands.js +66 -3
  336. package/dist/senses/habit-turn-message.js +108 -0
  337. package/dist/senses/inner-dialog-worker.js +175 -21
  338. package/dist/senses/inner-dialog.js +330 -27
  339. package/dist/senses/mail-entry.js +66 -0
  340. package/dist/senses/mail.js +379 -0
  341. package/dist/senses/pipeline.js +569 -182
  342. package/dist/senses/proactive-content-guard.js +51 -0
  343. package/dist/senses/shared-turn.js +248 -0
  344. package/dist/senses/surface-tool.js +68 -0
  345. package/dist/senses/teams-entry.js +60 -8
  346. package/dist/senses/teams.js +387 -98
  347. package/dist/senses/trust-gate.js +100 -5
  348. package/dist/trips/core.js +138 -0
  349. package/dist/trips/store.js +146 -0
  350. package/package.json +38 -7
  351. package/skills/agent-commerce.md +106 -0
  352. package/skills/browser-navigation.md +117 -0
  353. package/skills/commerce-setup-guide.md +116 -0
  354. package/skills/commerce-setup.md +84 -0
  355. package/skills/configure-dev-tools.md +101 -0
  356. package/skills/travel-planning.md +138 -0
  357. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  358. package/dist/heart/daemon/subagent-installer.js +0 -166
  359. package/dist/heart/session-recall.js +0 -116
  360. package/dist/mind/associative-recall.js +0 -209
  361. package/dist/senses/bluebubbles-entry.js +0 -13
  362. package/dist/senses/bluebubbles.js +0 -1177
  363. package/dist/senses/debug-activity.js +0 -148
  364. package/subagents/README.md +0 -86
  365. package/subagents/work-doer.md +0 -237
  366. package/subagents/work-merger.md +0 -618
  367. package/subagents/work-planner.md +0 -390
  368. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  369. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  370. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  372. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  373. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  374. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  375. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  376. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  380. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  381. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  382. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  383. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeDaemonRollup = computeDaemonRollup;
4
+ /**
5
+ * Pure rollup decision function — given the post-inventory daemon
6
+ * surface, returns the daemon-wide rollup state per the locked Layer 1
7
+ * vocabulary table:
8
+ *
9
+ * | rollup | when |
10
+ * | ---------- | --------------------------------------------------------- |
11
+ * | healthy | every enabled agent serving + no bootstrap-degraded + no safe-mode |
12
+ * | partial | (≥1 serving + ≥1 not serving) OR (all serving + ≥1 bootstrap-degraded) |
13
+ * | degraded | zero enabled agents serving (fresh install OR all unhealthy) |
14
+ * | safe-mode | `safeMode === true` overrides everything else |
15
+ *
16
+ * The function NEVER returns `"down"`. By the time `computeDaemonRollup`
17
+ * is reachable, the daemon process has started, opened its socket, and
18
+ * read its agent inventory — pre-inventory failure is the caller's
19
+ * domain. `daemon-entry.ts`'s startup-failure path assigns `"down"` to
20
+ * `DaemonHealthState.status` directly without consulting this function.
21
+ */
22
+ function computeDaemonRollup(input) {
23
+ // Safe mode wins, period. Crash-loop detection trumps everything —
24
+ // we want the human to see SAFE MODE, not a noisy partial/degraded.
25
+ if (input.safeMode) {
26
+ return "safe-mode";
27
+ }
28
+ // Count serving agents. "Serving" = "running" worker status.
29
+ // Anything else (crashed/stopped/starting/etc) is not serving.
30
+ let serving = 0;
31
+ let notServing = 0;
32
+ for (const agent of input.enabledAgents) {
33
+ if (agent.status === "running") {
34
+ serving++;
35
+ }
36
+ else {
37
+ notServing++;
38
+ }
39
+ }
40
+ // Zero-serving wins over bootstrap-degraded — we have no working
41
+ // agents to surface a "partially working" story about. This covers
42
+ // both fresh-install (`enabledAgents.length === 0`) and
43
+ // all-failed-live-check (`serving === 0` with `notServing > 0`).
44
+ // Render layer (cli-render.ts) splits the UX copy by inspecting the
45
+ // agents map; the rollup itself doesn't carry the distinction.
46
+ if (serving === 0) {
47
+ return "degraded";
48
+ }
49
+ // From here we have ≥1 serving agent. The remaining choice is
50
+ // healthy vs partial.
51
+ const hasUnhealthyAgent = notServing > 0;
52
+ const hasBootstrapDegraded = input.bootstrapDegraded.length > 0;
53
+ const hasDrift = input.driftDetected === true;
54
+ if (hasUnhealthyAgent || hasBootstrapDegraded || hasDrift) {
55
+ return "partial";
56
+ }
57
+ return "healthy";
58
+ }
@@ -2,53 +2,196 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureCurrentDaemonRuntime = ensureCurrentDaemonRuntime;
4
4
  const runtime_1 = require("../../nerves/runtime");
5
+ /* v8 ignore start -- daemon liveness poll: real socket timing untestable in vitest @preserve */
6
+ async function verifyDaemonStarted(deps) {
7
+ if (!deps.checkSocketAlive)
8
+ return true;
9
+ const maxWaitMs = 10_000;
10
+ const pollIntervalMs = 500;
11
+ const deadline = Date.now() + maxWaitMs;
12
+ deps.onProgress?.("waiting for the replacement background service to answer");
13
+ while (Date.now() < deadline) {
14
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
15
+ if (await deps.checkSocketAlive(deps.socketPath))
16
+ return true;
17
+ }
18
+ return false;
19
+ }
20
+ /* v8 ignore stop */
5
21
  function isKnownVersion(version) {
6
22
  return version !== "unknown" && version.trim().length > 0;
7
23
  }
24
+ function isKnownRuntimeValue(value) {
25
+ return typeof value === "string" && value.trim().length > 0 && value !== "unknown";
26
+ }
8
27
  function formatErrorReason(error) {
9
28
  return error instanceof Error ? error.message : String(error);
10
29
  }
30
+ function normalizeRuntimeIdentity(value) {
31
+ return {
32
+ version: typeof value.version === "string" ? value.version : "unknown",
33
+ lastUpdated: typeof value.lastUpdated === "string" ? value.lastUpdated : "unknown",
34
+ repoRoot: typeof value.repoRoot === "string" ? value.repoRoot : "unknown",
35
+ configFingerprint: typeof value.configFingerprint === "string" ? value.configFingerprint : "unknown",
36
+ managedAgents: typeof value.managedAgents === "string" ? value.managedAgents : "unknown",
37
+ };
38
+ }
39
+ async function readRunningRuntimeIdentity(deps) {
40
+ if (!deps.fetchRunningRuntimeMetadata) {
41
+ return normalizeRuntimeIdentity({
42
+ version: await deps.fetchRunningVersion(),
43
+ });
44
+ }
45
+ const metadata = normalizeRuntimeIdentity(await deps.fetchRunningRuntimeMetadata());
46
+ if (isKnownVersion(metadata.version))
47
+ return metadata;
48
+ return normalizeRuntimeIdentity({
49
+ ...metadata,
50
+ version: await deps.fetchRunningVersion(),
51
+ });
52
+ }
53
+ function collectRuntimeDriftReasons(local, running) {
54
+ const reasons = [];
55
+ const comparableVersions = isKnownVersion(local.version) && isKnownVersion(running.version);
56
+ if (comparableVersions && local.version !== running.version) {
57
+ reasons.push({ key: "version", label: "version", local: local.version, running: running.version });
58
+ }
59
+ if (comparableVersions && isKnownRuntimeValue(local.lastUpdated) && isKnownRuntimeValue(running.lastUpdated) && local.lastUpdated !== running.lastUpdated) {
60
+ reasons.push({ key: "lastUpdated", label: "last updated", local: local.lastUpdated, running: running.lastUpdated });
61
+ }
62
+ if (isKnownRuntimeValue(local.repoRoot) && isKnownRuntimeValue(running.repoRoot) && local.repoRoot !== running.repoRoot) {
63
+ reasons.push({ key: "repoRoot", label: "code path", local: local.repoRoot, running: running.repoRoot });
64
+ }
65
+ if (isKnownRuntimeValue(local.configFingerprint)
66
+ && isKnownRuntimeValue(running.configFingerprint)
67
+ && local.configFingerprint !== running.configFingerprint) {
68
+ reasons.push({
69
+ key: "configFingerprint",
70
+ label: "config fingerprint",
71
+ local: local.configFingerprint,
72
+ running: running.configFingerprint,
73
+ });
74
+ }
75
+ if (isKnownRuntimeValue(local.managedAgents)
76
+ && isKnownRuntimeValue(running.managedAgents)
77
+ && local.managedAgents !== running.managedAgents) {
78
+ reasons.push({
79
+ key: "managedAgents",
80
+ label: "managed agents",
81
+ local: local.managedAgents,
82
+ running: running.managedAgents,
83
+ });
84
+ }
85
+ return reasons;
86
+ }
87
+ function formatRuntimeDriftPublicSummary(reasons) {
88
+ return reasons.map((reason) => reason.label).join(", ");
89
+ }
11
90
  async function ensureCurrentDaemonRuntime(deps) {
91
+ deps.onProgress?.("checking whether an older background service is already running");
92
+ const localRuntime = normalizeRuntimeIdentity({
93
+ version: deps.localVersion,
94
+ lastUpdated: deps.localLastUpdated,
95
+ repoRoot: deps.localRepoRoot,
96
+ configFingerprint: deps.localConfigFingerprint,
97
+ managedAgents: deps.localManagedAgents,
98
+ });
12
99
  try {
13
- const runningVersion = await deps.fetchRunningVersion();
100
+ const runningRuntime = await readRunningRuntimeIdentity(deps);
101
+ const runningVersion = runningRuntime.version;
102
+ const driftReasons = collectRuntimeDriftReasons(localRuntime, runningRuntime);
14
103
  let result;
15
- if (isKnownVersion(deps.localVersion) &&
16
- isKnownVersion(runningVersion) &&
17
- runningVersion !== deps.localVersion) {
104
+ if (driftReasons.length > 0) {
105
+ const includesVersionDrift = driftReasons.some((entry) => entry.key === "version");
106
+ const publicDriftSummary = formatRuntimeDriftPublicSummary(driftReasons);
18
107
  try {
108
+ deps.onProgress?.("stopping the older background service");
19
109
  await deps.stopDaemon();
20
110
  }
21
111
  catch (error) {
22
112
  const reason = formatErrorReason(error);
23
113
  result = {
114
+ ok: false,
24
115
  alreadyRunning: true,
25
- message: `daemon already running (${deps.socketPath}; could not replace stale daemon ${runningVersion} -> ${deps.localVersion}: ${reason})`,
116
+ message: includesVersionDrift
117
+ ? `daemon already running (${deps.socketPath}; could not replace the older background service ${runningVersion} -> ${deps.localVersion}: ${reason})`
118
+ : `daemon already running (${deps.socketPath}; could not replace the older background service after runtime drift ${publicDriftSummary}: ${reason})`,
119
+ startupFailureReason: includesVersionDrift
120
+ ? "could not replace the older background service"
121
+ : "could not replace the older background service after runtime drift",
26
122
  };
27
123
  (0, runtime_1.emitNervesEvent)({
28
124
  level: "warn",
29
125
  component: "daemon",
30
126
  event: "daemon.runtime_sync_decision",
31
127
  message: "evaluated daemon runtime sync outcome",
32
- meta: { socketPath: deps.socketPath, localVersion: deps.localVersion, runningVersion, action: "stale_replace_failed", reason },
128
+ meta: {
129
+ socketPath: deps.socketPath,
130
+ localVersion: deps.localVersion,
131
+ localLastUpdated: localRuntime.lastUpdated,
132
+ localRepoRoot: localRuntime.repoRoot,
133
+ localConfigFingerprint: localRuntime.configFingerprint,
134
+ localManagedAgents: localRuntime.managedAgents,
135
+ runningVersion,
136
+ runningLastUpdated: runningRuntime.lastUpdated,
137
+ runningRepoRoot: runningRuntime.repoRoot,
138
+ runningConfigFingerprint: runningRuntime.configFingerprint,
139
+ runningManagedAgents: runningRuntime.managedAgents,
140
+ action: "stale_replace_failed",
141
+ driftKeys: driftReasons.map((entry) => entry.key),
142
+ reason,
143
+ },
33
144
  });
34
145
  return result;
35
146
  }
36
147
  deps.cleanupStaleSocket(deps.socketPath);
148
+ deps.onProgress?.("starting the replacement background service");
37
149
  const started = await deps.startDaemonProcess(deps.socketPath);
150
+ const pid = started.pid ?? "unknown";
151
+ const startupCheck = deps.waitForDaemonStartup
152
+ ? await deps.waitForDaemonStartup({ pid: started.pid ?? null })
153
+ : { ok: await verifyDaemonStarted(deps) };
154
+ const verified = startupCheck.ok;
155
+ /* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
156
+ const suffix = verified
157
+ ? ""
158
+ : `\n${startupCheck.reason ?? "replacement background service did not answer in time"}; check logs with \`ouro logs\` or run \`ouro doctor\`.`;
38
159
  result = {
160
+ ok: verified,
39
161
  alreadyRunning: false,
40
- message: `restarted stale daemon from ${runningVersion} to ${deps.localVersion} (pid ${started.pid ?? "unknown"})`,
162
+ message: includesVersionDrift
163
+ ? `replaced an older background service ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
164
+ : `replaced an older background service after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
165
+ verifyStartupStatus: verified,
166
+ startedPid: started.pid ?? null,
167
+ startupFailureReason: verified ? null : (startupCheck.reason ?? "replacement background service did not answer in time"),
41
168
  };
42
169
  (0, runtime_1.emitNervesEvent)({
43
170
  component: "daemon",
44
171
  event: "daemon.runtime_sync_decision",
45
172
  message: "evaluated daemon runtime sync outcome",
46
- meta: { socketPath: deps.socketPath, localVersion: deps.localVersion, runningVersion, action: "stale_restarted", pid: started.pid ?? null },
173
+ meta: {
174
+ socketPath: deps.socketPath,
175
+ localVersion: deps.localVersion,
176
+ localLastUpdated: localRuntime.lastUpdated,
177
+ localRepoRoot: localRuntime.repoRoot,
178
+ localConfigFingerprint: localRuntime.configFingerprint,
179
+ localManagedAgents: localRuntime.managedAgents,
180
+ runningVersion,
181
+ runningLastUpdated: runningRuntime.lastUpdated,
182
+ runningRepoRoot: runningRuntime.repoRoot,
183
+ runningConfigFingerprint: runningRuntime.configFingerprint,
184
+ runningManagedAgents: runningRuntime.managedAgents,
185
+ action: "stale_restarted",
186
+ driftKeys: driftReasons.map((entry) => entry.key),
187
+ pid: started.pid ?? null,
188
+ },
47
189
  });
48
190
  return result;
49
191
  }
50
- if (!isKnownVersion(deps.localVersion) || !isKnownVersion(runningVersion)) {
192
+ if (!isKnownVersion(localRuntime.version) || !isKnownVersion(runningVersion)) {
51
193
  result = {
194
+ ok: true,
52
195
  alreadyRunning: true,
53
196
  message: `daemon already running (${deps.socketPath}; unable to verify version)`,
54
197
  };
@@ -56,7 +199,20 @@ async function ensureCurrentDaemonRuntime(deps) {
56
199
  component: "daemon",
57
200
  event: "daemon.runtime_sync_decision",
58
201
  message: "evaluated daemon runtime sync outcome",
59
- meta: { socketPath: deps.socketPath, localVersion: deps.localVersion, runningVersion, action: "unknown_version" },
202
+ meta: {
203
+ socketPath: deps.socketPath,
204
+ localVersion: deps.localVersion,
205
+ localLastUpdated: localRuntime.lastUpdated,
206
+ localRepoRoot: localRuntime.repoRoot,
207
+ localConfigFingerprint: localRuntime.configFingerprint,
208
+ localManagedAgents: localRuntime.managedAgents,
209
+ runningVersion,
210
+ runningLastUpdated: runningRuntime.lastUpdated,
211
+ runningRepoRoot: runningRuntime.repoRoot,
212
+ runningConfigFingerprint: runningRuntime.configFingerprint,
213
+ runningManagedAgents: runningRuntime.managedAgents,
214
+ action: "unknown_version",
215
+ },
60
216
  });
61
217
  return result;
62
218
  }
@@ -64,6 +220,7 @@ async function ensureCurrentDaemonRuntime(deps) {
64
220
  catch (error) {
65
221
  const reason = formatErrorReason(error);
66
222
  const result = {
223
+ ok: true,
67
224
  alreadyRunning: true,
68
225
  message: `daemon already running (${deps.socketPath}; unable to verify version: ${reason})`,
69
226
  };
@@ -72,19 +229,40 @@ async function ensureCurrentDaemonRuntime(deps) {
72
229
  component: "daemon",
73
230
  event: "daemon.runtime_sync_decision",
74
231
  message: "evaluated daemon runtime sync outcome",
75
- meta: { socketPath: deps.socketPath, localVersion: deps.localVersion, action: "status_lookup_failed", reason },
232
+ meta: {
233
+ socketPath: deps.socketPath,
234
+ localVersion: deps.localVersion,
235
+ localLastUpdated: localRuntime.lastUpdated,
236
+ localRepoRoot: localRuntime.repoRoot,
237
+ localConfigFingerprint: localRuntime.configFingerprint,
238
+ localManagedAgents: localRuntime.managedAgents,
239
+ action: "status_lookup_failed",
240
+ reason,
241
+ },
76
242
  });
77
243
  return result;
78
244
  }
79
245
  const result = {
246
+ ok: true,
80
247
  alreadyRunning: true,
81
248
  message: `daemon already running (${deps.socketPath})`,
249
+ verifyStartupStatus: true,
250
+ startedPid: null,
251
+ startupFailureReason: null,
82
252
  };
83
253
  (0, runtime_1.emitNervesEvent)({
84
254
  component: "daemon",
85
255
  event: "daemon.runtime_sync_decision",
86
256
  message: "evaluated daemon runtime sync outcome",
87
- meta: { socketPath: deps.socketPath, localVersion: deps.localVersion, action: "already_current" },
257
+ meta: {
258
+ socketPath: deps.socketPath,
259
+ localVersion: deps.localVersion,
260
+ localLastUpdated: localRuntime.lastUpdated,
261
+ localRepoRoot: localRuntime.repoRoot,
262
+ localConfigFingerprint: localRuntime.configFingerprint,
263
+ localManagedAgents: localRuntime.managedAgents,
264
+ action: "already_current",
265
+ },
88
266
  });
89
267
  return result;
90
268
  }
@@ -0,0 +1,236 @@
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.RECENT_CRASHES_MAX = void 0;
37
+ exports.getTombstonePath = getTombstonePath;
38
+ exports.setTombstonePath = setTombstonePath;
39
+ exports.captureDeathForensics = captureDeathForensics;
40
+ exports.writeDaemonTombstone = writeDaemonTombstone;
41
+ exports.readDaemonTombstone = readDaemonTombstone;
42
+ const child_process_1 = require("child_process");
43
+ const fs = __importStar(require("fs"));
44
+ const os = __importStar(require("os"));
45
+ const path = __importStar(require("path"));
46
+ const runtime_1 = require("../../nerves/runtime");
47
+ /** Maximum number of historical crash timestamps to retain in the tombstone. */
48
+ exports.RECENT_CRASHES_MAX = 100;
49
+ let _tombstonePath = null;
50
+ function getTombstonePath() {
51
+ if (!_tombstonePath) {
52
+ _tombstonePath = path.join(os.homedir(), ".ouro-cli", "daemon-death.json");
53
+ }
54
+ return _tombstonePath;
55
+ }
56
+ /** Overrides the tombstone path for testing. Pass null to reset. */
57
+ function setTombstonePath(p) {
58
+ _tombstonePath = p;
59
+ }
60
+ /* v8 ignore start -- shells out to ps; covered via injected runPs in unit tests @preserve */
61
+ function defaultRunPs(args) {
62
+ try {
63
+ return (0, child_process_1.execSync)(`ps ${args.join(" ")}`, { encoding: "utf-8", timeout: 2000 });
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ /* v8 ignore stop */
70
+ const DEFAULT_FORENSICS_DEPS = {
71
+ /* v8 ignore next -- defensive: process.ppid always exists in node @preserve */
72
+ ppid: () => (typeof process !== "undefined" && typeof process.ppid === "number" ? process.ppid : 0),
73
+ runPs: defaultRunPs,
74
+ };
75
+ /**
76
+ * Capture forensic data about who is likely to have killed the daemon.
77
+ * Synchronous and best-effort: never throws, always returns a structured
78
+ * record (with nulls if anything failed). Called from inside SIGTERM/SIGINT
79
+ * handlers, so it must be fast and have no async dependencies.
80
+ */
81
+ function captureDeathForensics(deps = DEFAULT_FORENSICS_DEPS) {
82
+ const parentPid = (() => {
83
+ try {
84
+ const p = deps.ppid();
85
+ return typeof p === "number" && p > 0 ? p : null;
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ })();
91
+ let parentCommand = null;
92
+ if (parentPid !== null) {
93
+ const psParent = deps.runPs(["-p", String(parentPid), "-o", "command="]);
94
+ if (psParent !== null) {
95
+ const trimmed = psParent.trim();
96
+ parentCommand = trimmed.length > 0 ? trimmed : null;
97
+ }
98
+ }
99
+ const processSnapshot = (() => {
100
+ const psAll = deps.runPs(["-eo", "pid,ppid,command"]);
101
+ if (psAll === null)
102
+ return null;
103
+ const lines = psAll.split("\n");
104
+ // Filter for relevant processes only — node, vitest, ouro, kill commands.
105
+ // Keeps the snapshot small and human-scannable.
106
+ const relevant = lines.filter((line) => {
107
+ const lower = line.toLowerCase();
108
+ return (lower.includes("node")
109
+ || lower.includes("vitest")
110
+ || lower.includes("ouro")
111
+ || lower.includes("/kill ")
112
+ || lower.includes("pkill")
113
+ || lower.includes("killall"));
114
+ });
115
+ if (relevant.length === 0)
116
+ return null;
117
+ return relevant.join("\n");
118
+ })();
119
+ const killerHint = deriveKillerHint(parentCommand, processSnapshot);
120
+ return { parentPid, parentCommand, processSnapshot, killerHint };
121
+ }
122
+ function deriveKillerHint(parentCommand, snapshot) {
123
+ if (parentCommand !== null && parentCommand.toLowerCase().includes("launchd")) {
124
+ return "process was reparented to launchd — likely killed by launchctl bootout, KeepAlive thrash, or RSS pressure";
125
+ }
126
+ if (snapshot !== null) {
127
+ const lower = snapshot.toLowerCase();
128
+ if (lower.includes("vitest")) {
129
+ return "vitest worker is running — possible test cleanup killing detached processes";
130
+ }
131
+ if (lower.includes("pkill") || lower.includes("killall")) {
132
+ return "saw pkill/killall in process list — explicit kill command";
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+ function writeDaemonTombstone(reason, error, forensicsDeps) {
138
+ const now = new Date().toISOString();
139
+ const filePath = getTombstonePath();
140
+ // Read existing recentCrashes from previous tombstone (best-effort)
141
+ let existingCrashes = [];
142
+ try {
143
+ const raw = fs.readFileSync(filePath, "utf-8");
144
+ const existing = JSON.parse(raw);
145
+ if (Array.isArray(existing.recentCrashes)) {
146
+ existingCrashes = existing.recentCrashes.filter((entry) => typeof entry === "string");
147
+ }
148
+ }
149
+ catch {
150
+ // No existing tombstone or unreadable — start fresh
151
+ }
152
+ // Append the new crash and cap at the most recent RECENT_CRASHES_MAX entries
153
+ // so the tombstone doesn't grow without bound (we saw it hit 12,265 entries
154
+ // after a March 31 crash-restart thrash loop).
155
+ const recentCrashes = [...existingCrashes, now].slice(-exports.RECENT_CRASHES_MAX);
156
+ // Forensics: only meaningful for signal-driven deaths (sigterm/sigint).
157
+ // For uncaughtException etc. we skip the snapshot to keep tombstone writes
158
+ // fast on the unhappy path.
159
+ const shouldCaptureForensics = reason === "sigterm" || reason === "sigint";
160
+ const forensics = shouldCaptureForensics
161
+ ? captureDeathForensics(forensicsDeps)
162
+ : undefined;
163
+ const tombstone = {
164
+ reason,
165
+ message: error?.message ?? reason,
166
+ stack: error?.stack ?? null,
167
+ timestamp: now,
168
+ pid: process.pid,
169
+ uptimeSeconds: Math.floor(process.uptime()),
170
+ recentCrashes,
171
+ ...(forensics ? { forensics } : {}),
172
+ };
173
+ try {
174
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
175
+ fs.writeFileSync(filePath, JSON.stringify(tombstone, null, 2) + "\n", "utf-8");
176
+ }
177
+ catch {
178
+ // Best-effort: if we can't write, we're already dying.
179
+ }
180
+ (0, runtime_1.emitNervesEvent)({
181
+ level: "error",
182
+ component: "daemon",
183
+ event: "daemon.tombstone_written",
184
+ message: `daemon tombstone written: ${reason}`,
185
+ meta: {
186
+ reason,
187
+ errorMessage: error?.message ?? null,
188
+ filePath,
189
+ parentPid: forensics?.parentPid ?? null,
190
+ killerHint: forensics?.killerHint ?? null,
191
+ },
192
+ });
193
+ }
194
+ function readDaemonTombstone() {
195
+ const filePath = getTombstonePath();
196
+ try {
197
+ const raw = fs.readFileSync(filePath, "utf-8");
198
+ const parsed = JSON.parse(raw);
199
+ if (typeof parsed.reason !== "string" || typeof parsed.timestamp !== "string") {
200
+ return null;
201
+ }
202
+ (0, runtime_1.emitNervesEvent)({
203
+ component: "daemon",
204
+ event: "daemon.tombstone_read",
205
+ message: "read daemon tombstone",
206
+ meta: { filePath },
207
+ });
208
+ const forensics = parseForensics(parsed.forensics);
209
+ return {
210
+ reason: parsed.reason,
211
+ message: typeof parsed.message === "string" ? parsed.message : String(parsed.reason),
212
+ stack: typeof parsed.stack === "string" ? parsed.stack : null,
213
+ timestamp: parsed.timestamp,
214
+ pid: typeof parsed.pid === "number" ? parsed.pid : 0,
215
+ uptimeSeconds: typeof parsed.uptimeSeconds === "number" ? parsed.uptimeSeconds : 0,
216
+ recentCrashes: Array.isArray(parsed.recentCrashes)
217
+ ? parsed.recentCrashes.filter((e) => typeof e === "string")
218
+ : [],
219
+ ...(forensics ? { forensics } : {}),
220
+ };
221
+ }
222
+ catch {
223
+ return null;
224
+ }
225
+ }
226
+ function parseForensics(value) {
227
+ if (value === null || typeof value !== "object")
228
+ return null;
229
+ const v = value;
230
+ return {
231
+ parentPid: typeof v.parentPid === "number" ? v.parentPid : null,
232
+ parentCommand: typeof v.parentCommand === "string" ? v.parentCommand : null,
233
+ processSnapshot: typeof v.processSnapshot === "string" ? v.processSnapshot : null,
234
+ killerHint: typeof v.killerHint === "string" ? v.killerHint : null,
235
+ };
236
+ }