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

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 (375) hide show
  1. package/README.md +133 -19
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  5. package/changelog.json +3353 -0
  6. package/dist/arc/attention-types.js +8 -0
  7. package/dist/arc/cares.js +140 -0
  8. package/dist/arc/episodes.js +117 -0
  9. package/dist/arc/intentions.js +133 -0
  10. package/dist/arc/json-store.js +117 -0
  11. package/dist/arc/obligations.js +237 -0
  12. package/dist/arc/packets.js +193 -0
  13. package/dist/arc/presence.js +185 -0
  14. package/dist/arc/task-lifecycle.js +65 -0
  15. package/dist/heart/active-work.js +837 -26
  16. package/dist/heart/agent-entry.js +58 -3
  17. package/dist/heart/attachments/image-normalize.js +194 -0
  18. package/dist/heart/attachments/materialize.js +97 -0
  19. package/dist/heart/attachments/originals.js +88 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/sources/adapter.js +2 -0
  22. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  23. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  24. package/dist/heart/attachments/sources/index.js +16 -0
  25. package/dist/heart/attachments/store.js +103 -0
  26. package/dist/heart/attachments/types.js +93 -0
  27. package/dist/heart/auth/auth-flow.js +427 -0
  28. package/dist/heart/background-operations.js +281 -0
  29. package/dist/heart/bundle-state.js +168 -0
  30. package/dist/heart/commitments.js +111 -0
  31. package/dist/heart/config-registry.js +304 -0
  32. package/dist/heart/config.js +119 -129
  33. package/dist/heart/core.js +948 -243
  34. package/dist/heart/cross-chat-delivery.js +3 -18
  35. package/dist/heart/daemon/agent-config-check.js +512 -0
  36. package/dist/heart/daemon/agent-discovery.js +102 -3
  37. package/dist/heart/daemon/agent-service.js +360 -0
  38. package/dist/heart/daemon/agentic-repair.js +554 -0
  39. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  40. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  41. package/dist/heart/daemon/cadence.js +70 -0
  42. package/dist/heart/daemon/cli-defaults.js +643 -0
  43. package/dist/heart/daemon/cli-exec.js +7476 -0
  44. package/dist/heart/daemon/cli-help.js +493 -0
  45. package/dist/heart/daemon/cli-parse.js +1557 -0
  46. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  47. package/dist/heart/daemon/cli-render.js +649 -0
  48. package/dist/heart/daemon/cli-types.js +8 -0
  49. package/dist/heart/daemon/connect-bay.js +323 -0
  50. package/dist/heart/daemon/daemon-cli.js +29 -1631
  51. package/dist/heart/daemon/daemon-entry.js +404 -3
  52. package/dist/heart/daemon/daemon-health.js +183 -0
  53. package/dist/heart/daemon/daemon-rollup.js +58 -0
  54. package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
  55. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  56. package/dist/heart/daemon/daemon.js +758 -60
  57. package/dist/heart/daemon/dns-workflow.js +394 -0
  58. package/dist/heart/daemon/doctor-types.js +8 -0
  59. package/dist/heart/daemon/doctor.js +837 -0
  60. package/dist/heart/daemon/drift-detection.js +146 -0
  61. package/dist/heart/daemon/health-monitor.js +92 -1
  62. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  63. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  64. package/dist/heart/daemon/http-health-probe.js +80 -0
  65. package/dist/heart/daemon/human-command-screens.js +234 -0
  66. package/dist/heart/daemon/human-readiness.js +114 -0
  67. package/dist/heart/daemon/inner-status.js +102 -0
  68. package/dist/heart/daemon/interactive-repair.js +394 -0
  69. package/dist/heart/daemon/launchd.js +25 -5
  70. package/dist/heart/daemon/log-tailer.js +82 -12
  71. package/dist/heart/daemon/logs-prune.js +110 -0
  72. package/dist/heart/daemon/message-router.js +2 -2
  73. package/dist/heart/daemon/os-cron-deps.js +134 -0
  74. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  75. package/dist/heart/daemon/ouro-entry.js +3 -1
  76. package/dist/heart/daemon/process-manager.js +381 -26
  77. package/dist/heart/daemon/provider-discovery.js +137 -0
  78. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  79. package/dist/heart/daemon/pulse.js +475 -0
  80. package/dist/heart/daemon/readiness-repair.js +365 -0
  81. package/dist/heart/daemon/run-hooks.js +2 -0
  82. package/dist/heart/daemon/runtime-logging.js +67 -16
  83. package/dist/heart/daemon/runtime-metadata.js +73 -0
  84. package/dist/heart/daemon/runtime-mode.js +67 -0
  85. package/dist/heart/daemon/safe-mode.js +161 -0
  86. package/dist/heart/daemon/sense-manager.js +259 -37
  87. package/dist/heart/daemon/session-id-resolver.js +131 -0
  88. package/dist/heart/daemon/skill-management-installer.js +94 -0
  89. package/dist/heart/daemon/socket-client.js +109 -4
  90. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  91. package/dist/heart/daemon/startup-tui.js +330 -0
  92. package/dist/heart/daemon/task-scheduler.js +3 -25
  93. package/dist/heart/daemon/terminal-ui.js +499 -0
  94. package/dist/heart/daemon/thoughts.js +162 -17
  95. package/dist/heart/daemon/up-progress.js +366 -0
  96. package/dist/heart/daemon/vault-items.js +56 -0
  97. package/dist/heart/delegation.js +1 -1
  98. package/dist/heart/habits/habit-migration.js +189 -0
  99. package/dist/heart/habits/habit-parser.js +140 -0
  100. package/dist/heart/habits/habit-runtime-state.js +100 -0
  101. package/dist/heart/habits/habit-scheduler.js +372 -0
  102. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  103. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  104. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  105. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  106. package/dist/heart/identity.js +205 -66
  107. package/dist/heart/kept-notes.js +357 -0
  108. package/dist/heart/kicks.js +1 -1
  109. package/dist/heart/machine-identity.js +161 -0
  110. package/dist/heart/mail-import-discovery.js +353 -0
  111. package/dist/heart/mcp/mcp-server.js +653 -0
  112. package/dist/heart/migrate-config.js +100 -0
  113. package/dist/heart/model-capabilities.js +19 -0
  114. package/dist/heart/outlook/outlook-http-hooks.js +66 -0
  115. package/dist/heart/outlook/outlook-http-response.js +7 -0
  116. package/dist/heart/outlook/outlook-http-routes.js +244 -0
  117. package/dist/heart/outlook/outlook-http-static.js +103 -0
  118. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  119. package/dist/heart/outlook/outlook-http.js +99 -0
  120. package/dist/heart/outlook/outlook-read.js +31 -0
  121. package/dist/heart/outlook/outlook-types.js +27 -0
  122. package/dist/heart/outlook/outlook-view.js +195 -0
  123. package/dist/heart/outlook/readers/agent-machine.js +382 -0
  124. package/dist/heart/outlook/readers/continuity-readers.js +336 -0
  125. package/dist/heart/outlook/readers/mail.js +362 -0
  126. package/dist/heart/outlook/readers/runtime-readers.js +650 -0
  127. package/dist/heart/outlook/readers/sessions.js +232 -0
  128. package/dist/heart/outlook/readers/shared.js +111 -0
  129. package/dist/heart/platform.js +81 -0
  130. package/dist/heart/provider-attempt.js +134 -0
  131. package/dist/heart/provider-binding-resolver.js +255 -0
  132. package/dist/heart/provider-credentials.js +425 -0
  133. package/dist/heart/provider-failover.js +301 -0
  134. package/dist/heart/provider-models.js +81 -0
  135. package/dist/heart/provider-ping.js +262 -0
  136. package/dist/heart/provider-state.js +216 -0
  137. package/dist/heart/provider-visibility.js +188 -0
  138. package/dist/heart/providers/anthropic-token.js +131 -0
  139. package/dist/heart/providers/anthropic.js +139 -52
  140. package/dist/heart/providers/azure.js +97 -13
  141. package/dist/heart/providers/error-classification.js +127 -0
  142. package/dist/heart/providers/github-copilot.js +145 -0
  143. package/dist/heart/providers/minimax-vlm.js +189 -0
  144. package/dist/heart/providers/minimax.js +26 -8
  145. package/dist/heart/providers/openai-codex.js +55 -40
  146. package/dist/heart/runtime-capability-check.js +170 -0
  147. package/dist/heart/runtime-credentials.js +367 -0
  148. package/dist/heart/sense-truth.js +11 -4
  149. package/dist/heart/session-activity.js +43 -22
  150. package/dist/heart/session-events.js +1149 -0
  151. package/dist/heart/session-playback-cli-main.js +5 -0
  152. package/dist/heart/session-playback-cli.js +36 -0
  153. package/dist/heart/session-playback.js +231 -0
  154. package/dist/heart/session-stats-cli-main.js +5 -0
  155. package/dist/heart/session-stats.js +182 -0
  156. package/dist/heart/session-transcript.js +243 -0
  157. package/dist/heart/start-of-turn-packet.js +345 -0
  158. package/dist/heart/streaming.js +44 -27
  159. package/dist/heart/sync-classification.js +176 -0
  160. package/dist/heart/sync.js +449 -0
  161. package/dist/heart/target-resolution.js +9 -5
  162. package/dist/heart/tempo.js +93 -0
  163. package/dist/heart/temporal-view.js +41 -0
  164. package/dist/heart/timeouts.js +101 -0
  165. package/dist/heart/tool-activity-callbacks.js +36 -0
  166. package/dist/heart/tool-description.js +139 -0
  167. package/dist/heart/tool-friction.js +55 -0
  168. package/dist/heart/tool-loop.js +200 -0
  169. package/dist/heart/turn-context.js +381 -0
  170. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  171. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  172. package/dist/heart/versioning/ouro-path-installer.js +425 -0
  173. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  174. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  175. package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
  176. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  177. package/dist/mailroom/attention.js +167 -0
  178. package/dist/mailroom/autonomy.js +209 -0
  179. package/dist/mailroom/blob-store.js +606 -0
  180. package/dist/mailroom/body-cache.js +61 -0
  181. package/dist/mailroom/core.js +672 -0
  182. package/dist/mailroom/entry.js +160 -0
  183. package/dist/mailroom/file-store.js +426 -0
  184. package/dist/mailroom/mbox-import.js +382 -0
  185. package/dist/mailroom/outbound.js +380 -0
  186. package/dist/mailroom/policy.js +263 -0
  187. package/dist/mailroom/reader.js +228 -0
  188. package/dist/mailroom/search-cache.js +182 -0
  189. package/dist/mailroom/search-relevance.js +319 -0
  190. package/dist/mailroom/smtp-ingress.js +176 -0
  191. package/dist/mailroom/source-state.js +176 -0
  192. package/dist/mailroom/thread.js +109 -0
  193. package/dist/mailroom/travel-extract.js +89 -0
  194. package/dist/mind/bundle-manifest.js +7 -1
  195. package/dist/mind/context.js +165 -101
  196. package/dist/mind/diary-integrity.js +60 -0
  197. package/dist/mind/{memory.js → diary.js} +74 -93
  198. package/dist/mind/embedding-provider.js +60 -0
  199. package/dist/mind/file-state.js +179 -0
  200. package/dist/mind/friends/channel.js +30 -0
  201. package/dist/mind/friends/resolver.js +54 -2
  202. package/dist/mind/friends/store-file.js +39 -3
  203. package/dist/mind/friends/types.js +2 -2
  204. package/dist/mind/journal-index.js +161 -0
  205. package/dist/mind/note-search.js +268 -0
  206. package/dist/mind/obligation-steering.js +221 -0
  207. package/dist/mind/pending.js +4 -0
  208. package/dist/mind/prompt-refresh.js +3 -2
  209. package/dist/mind/prompt.js +942 -122
  210. package/dist/mind/provenance-trust.js +26 -0
  211. package/dist/mind/scrutiny.js +173 -0
  212. package/dist/nerves/cli-logging.js +7 -1
  213. package/dist/nerves/coverage/audit-rules.js +15 -6
  214. package/dist/nerves/coverage/audit.js +28 -2
  215. package/dist/nerves/coverage/cli.js +1 -1
  216. package/dist/nerves/coverage/contract.js +5 -5
  217. package/dist/nerves/coverage/file-completeness.js +139 -5
  218. package/dist/nerves/coverage/run-artifacts.js +1 -1
  219. package/dist/nerves/event-buffer.js +111 -0
  220. package/dist/nerves/index.js +224 -4
  221. package/dist/nerves/observation.js +20 -0
  222. package/dist/nerves/redact.js +79 -0
  223. package/dist/nerves/review/cli-main.js +5 -0
  224. package/dist/nerves/review/cli.js +156 -0
  225. package/dist/nerves/review/core.js +152 -0
  226. package/dist/nerves/runtime.js +5 -1
  227. package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
  228. package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
  229. package/dist/outlook-ui/index.html +15 -0
  230. package/dist/repertoire/ado-client.js +15 -56
  231. package/dist/repertoire/ado-semantic.js +11 -10
  232. package/dist/repertoire/api-client.js +97 -0
  233. package/dist/repertoire/bitwarden-store.js +816 -0
  234. package/dist/repertoire/bundle-templates.js +72 -0
  235. package/dist/repertoire/bw-installer.js +180 -0
  236. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  237. package/dist/repertoire/coding/context-pack.js +330 -0
  238. package/dist/repertoire/coding/feedback.js +197 -30
  239. package/dist/repertoire/coding/manager.js +158 -9
  240. package/dist/repertoire/coding/spawner.js +55 -9
  241. package/dist/repertoire/coding/tools.js +170 -7
  242. package/dist/repertoire/commerce-errors.js +109 -0
  243. package/dist/repertoire/commerce-self-test.js +156 -0
  244. package/dist/repertoire/credential-access.js +111 -0
  245. package/dist/repertoire/duffel-client.js +185 -0
  246. package/dist/repertoire/github-client.js +14 -55
  247. package/dist/repertoire/graph-client.js +11 -52
  248. package/dist/repertoire/guardrails.js +396 -0
  249. package/dist/repertoire/mcp-client.js +255 -0
  250. package/dist/repertoire/mcp-manager.js +305 -0
  251. package/dist/repertoire/mcp-tools.js +63 -0
  252. package/dist/repertoire/shell-sessions.js +133 -0
  253. package/dist/repertoire/skills.js +15 -24
  254. package/dist/repertoire/stripe-client.js +131 -0
  255. package/dist/repertoire/tasks/board.js +31 -5
  256. package/dist/repertoire/tasks/fix.js +182 -0
  257. package/dist/repertoire/tasks/index.js +16 -4
  258. package/dist/repertoire/tasks/lifecycle.js +2 -2
  259. package/dist/repertoire/tasks/parser.js +3 -2
  260. package/dist/repertoire/tasks/scanner.js +194 -37
  261. package/dist/repertoire/tasks/transitions.js +16 -78
  262. package/dist/repertoire/tool-results.js +29 -0
  263. package/dist/repertoire/tools-attachments.js +317 -0
  264. package/dist/repertoire/tools-base.js +47 -1075
  265. package/dist/repertoire/tools-bluebubbles.js +1 -0
  266. package/dist/repertoire/tools-bridge.js +142 -0
  267. package/dist/repertoire/tools-bundle.js +984 -0
  268. package/dist/repertoire/tools-config.js +185 -0
  269. package/dist/repertoire/tools-continuity.js +248 -0
  270. package/dist/repertoire/tools-credential.js +381 -0
  271. package/dist/repertoire/tools-files.js +342 -0
  272. package/dist/repertoire/tools-flight.js +224 -0
  273. package/dist/repertoire/tools-flow.js +119 -0
  274. package/dist/repertoire/tools-github.js +1 -7
  275. package/dist/repertoire/tools-mail.js +1477 -0
  276. package/dist/repertoire/tools-notes.js +421 -0
  277. package/dist/repertoire/tools-session.js +750 -0
  278. package/dist/repertoire/tools-shell.js +120 -0
  279. package/dist/repertoire/tools-stripe.js +180 -0
  280. package/dist/repertoire/tools-surface.js +243 -0
  281. package/dist/repertoire/tools-teams.js +9 -39
  282. package/dist/repertoire/tools-travel.js +125 -0
  283. package/dist/repertoire/tools-trip.js +422 -0
  284. package/dist/repertoire/tools-user-profile.js +144 -0
  285. package/dist/repertoire/tools-vault.js +40 -0
  286. package/dist/repertoire/tools.js +108 -100
  287. package/dist/repertoire/travel-api-client.js +360 -0
  288. package/dist/repertoire/user-profile.js +131 -0
  289. package/dist/repertoire/vault-setup.js +246 -0
  290. package/dist/repertoire/vault-unlock.js +561 -0
  291. package/dist/scripts/claude-code-hook.js +41 -0
  292. package/dist/scripts/claude-code-stop-hook.js +47 -0
  293. package/dist/senses/attention-queue.js +116 -0
  294. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  295. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  296. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  297. package/dist/senses/bluebubbles/entry.js +77 -0
  298. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  299. package/dist/senses/bluebubbles/index.js +1947 -0
  300. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  301. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  302. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  303. package/dist/senses/bluebubbles/processed-log.js +111 -0
  304. package/dist/senses/bluebubbles/replay.js +129 -0
  305. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
  306. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  307. package/dist/senses/cli/bracketed-paste.js +82 -0
  308. package/dist/senses/cli/image-paste.js +287 -0
  309. package/dist/senses/cli/image-ref-navigation.js +75 -0
  310. package/dist/senses/cli/ink-app.js +156 -0
  311. package/dist/senses/cli/inline-diff.js +64 -0
  312. package/dist/senses/cli/input-keys.js +174 -0
  313. package/dist/senses/cli/kill-ring.js +86 -0
  314. package/dist/senses/cli/message-list.js +51 -0
  315. package/dist/senses/cli/ouro-tui.js +607 -0
  316. package/dist/senses/cli/spinner-imperative.js +135 -0
  317. package/dist/senses/cli/spinner.js +101 -0
  318. package/dist/senses/cli/status-line.js +60 -0
  319. package/dist/senses/cli/streaming-markdown.js +526 -0
  320. package/dist/senses/cli/tool-display.js +85 -0
  321. package/dist/senses/cli/tool-render.js +85 -0
  322. package/dist/senses/cli/tui-store.js +240 -0
  323. package/dist/senses/cli/virtual-list.js +35 -0
  324. package/dist/senses/cli-entry.js +60 -8
  325. package/dist/senses/cli-layout.js +187 -0
  326. package/dist/senses/cli.js +520 -209
  327. package/dist/senses/commands.js +66 -3
  328. package/dist/senses/habit-turn-message.js +108 -0
  329. package/dist/senses/inner-dialog-worker.js +175 -21
  330. package/dist/senses/inner-dialog.js +330 -27
  331. package/dist/senses/mail-entry.js +66 -0
  332. package/dist/senses/mail.js +379 -0
  333. package/dist/senses/pipeline.js +569 -182
  334. package/dist/senses/proactive-content-guard.js +51 -0
  335. package/dist/senses/shared-turn.js +248 -0
  336. package/dist/senses/surface-tool.js +68 -0
  337. package/dist/senses/teams-entry.js +60 -8
  338. package/dist/senses/teams.js +387 -98
  339. package/dist/senses/trust-gate.js +100 -5
  340. package/dist/trips/core.js +138 -0
  341. package/dist/trips/store.js +146 -0
  342. package/package.json +37 -7
  343. package/skills/agent-commerce.md +106 -0
  344. package/skills/browser-navigation.md +117 -0
  345. package/skills/commerce-setup-guide.md +116 -0
  346. package/skills/commerce-setup.md +84 -0
  347. package/skills/configure-dev-tools.md +101 -0
  348. package/skills/travel-planning.md +138 -0
  349. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  350. package/dist/heart/daemon/subagent-installer.js +0 -166
  351. package/dist/heart/session-recall.js +0 -116
  352. package/dist/mind/associative-recall.js +0 -209
  353. package/dist/senses/bluebubbles-entry.js +0 -13
  354. package/dist/senses/bluebubbles.js +0 -1177
  355. package/dist/senses/debug-activity.js +0 -148
  356. package/subagents/README.md +0 -86
  357. package/subagents/work-doer.md +0 -237
  358. package/subagents/work-merger.md +0 -618
  359. package/subagents/work-planner.md +0 -390
  360. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  361. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  362. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  363. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  364. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  365. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  366. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  367. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  368. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  369. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  370. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  372. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  373. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  374. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  375. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,394 @@
1
+ "use strict";
2
+ /**
3
+ * Interactive repair flow for degraded agents detected during `ouro up`.
4
+ *
5
+ * Examines each degraded agent's errorReason and fixHint to detect common
6
+ * issue patterns and prompt the user for repair actions.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.hasRunnableInteractiveRepair = hasRunnableInteractiveRepair;
10
+ exports.isAffirmativeAnswer = isAffirmativeAnswer;
11
+ exports.runInteractiveRepair = runInteractiveRepair;
12
+ const runtime_1 = require("../../nerves/runtime");
13
+ const identity_1 = require("../identity");
14
+ const terminal_ui_1 = require("./terminal-ui");
15
+ function isCredentialIssue(degraded) {
16
+ const reason = degraded.errorReason.toLowerCase();
17
+ const hint = degraded.fixHint.toLowerCase();
18
+ return reason.includes("credentials") || hint.includes("ouro auth");
19
+ }
20
+ function isVaultUnlockIssue(degraded) {
21
+ const text = `${degraded.errorReason}\n${degraded.fixHint}`.toLowerCase();
22
+ return /ouro vault unlock|credential vault is locked|vault(?: is)? locked/.test(text);
23
+ }
24
+ function isConfigError(degraded) {
25
+ return degraded.fixHint.length > 0 && !isVaultUnlockIssue(degraded) && !isCredentialIssue(degraded);
26
+ }
27
+ function hasRunnableInteractiveRepair(degraded) {
28
+ if (degraded.issue?.actions.some((action) => typedActionToRunnable(degraded, action) !== undefined)) {
29
+ return true;
30
+ }
31
+ return isVaultUnlockIssue(degraded) || isCredentialIssue(degraded);
32
+ }
33
+ function isAgentProvider(value) {
34
+ return Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
35
+ }
36
+ function extractProviderFromFixHint(fixHint) {
37
+ const provider = fixHint.match(/--provider\s+([a-z0-9-]+)/)?.[1]
38
+ ?? fixHint.match(/providers\.([a-z0-9-]+)/)?.[1];
39
+ if (!provider || !isAgentProvider(provider))
40
+ return undefined;
41
+ return provider;
42
+ }
43
+ function escapeRegExp(value) {
44
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45
+ }
46
+ function cleanExtractedCommand(command) {
47
+ const cleaned = command?.trim().replace(/[`'",;:.)]+$/g, "").trim();
48
+ return cleaned && cleaned.length > 0 ? cleaned : undefined;
49
+ }
50
+ function extractRepairCommand(fixHint, commandPrefix) {
51
+ const escapedPrefix = escapeRegExp(commandPrefix);
52
+ const commandBody = `${escapedPrefix}(?=\\s|$)[^\`'"]*`;
53
+ const quoted = fixHint.match(new RegExp(`[\`'"](${commandBody})[\`'"]`, "i"))?.[1];
54
+ const unquoted = fixHint.match(new RegExp(`(${escapedPrefix}(?=\\s|$)[^\\n,;.]+)`, "i"))?.[1];
55
+ return cleanExtractedCommand(quoted) ?? cleanExtractedCommand(unquoted);
56
+ }
57
+ function authCommandFor(degraded) {
58
+ const command = extractRepairCommand(degraded.fixHint, "ouro auth");
59
+ return command && command.length > 0 ? command : `ouro auth --agent ${degraded.agent}`;
60
+ }
61
+ function vaultUnlockCommandFor(degraded) {
62
+ const command = extractRepairCommand(degraded.fixHint, "ouro vault unlock");
63
+ return command && command.length > 0 ? command : `ouro vault unlock --agent ${degraded.agent}`;
64
+ }
65
+ function isAffirmativeAnswer(answer) {
66
+ return /^(y|yes)$/i.test(answer.trim());
67
+ }
68
+ function uniqueCommands(commands) {
69
+ const seen = new Set();
70
+ const unique = [];
71
+ commands.forEach((command) => {
72
+ if (!command)
73
+ return;
74
+ if (seen.has(command))
75
+ return;
76
+ seen.add(command);
77
+ unique.push(command);
78
+ });
79
+ return unique;
80
+ }
81
+ function fallbackCommandsFor(degraded, primaryCommand) {
82
+ const issueCommands = degraded.issue?.actions.map((action) => action.command) ?? [];
83
+ return uniqueCommands([
84
+ primaryCommand,
85
+ ...issueCommands,
86
+ extractRepairCommand(degraded.fixHint, "ouro vault replace"),
87
+ extractRepairCommand(degraded.fixHint, "ouro vault recover"),
88
+ extractRepairCommand(degraded.fixHint, "ouro use"),
89
+ ]);
90
+ }
91
+ function renderRepairChoices(prefix, commands) {
92
+ return commands.map((command, index) => ` ${index === 0 ? prefix : "or"}: ${command}`);
93
+ }
94
+ function repairStatusFor(action) {
95
+ return action.kind === "vault-unlock" ? "locked" : "needs credentials";
96
+ }
97
+ function renderRepairQueueSummaryLines(degraded) {
98
+ const repairable = degraded
99
+ .map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
100
+ .filter((item) => item.action !== undefined);
101
+ if (repairable.length < 2)
102
+ return [];
103
+ const lines = [
104
+ "Repair queue",
105
+ `${repairable.length} agents need attention before startup can finish.`,
106
+ "",
107
+ ];
108
+ repairable.forEach(({ entry, action }, index) => {
109
+ lines.push(`${entry.agent} - ${action.label}`);
110
+ lines.push(` ${action.command}`);
111
+ if (index < repairable.length - 1)
112
+ lines.push("");
113
+ });
114
+ return lines;
115
+ }
116
+ function renderRepairQueueSummary(degraded, deps) {
117
+ const repairable = degraded
118
+ .map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
119
+ .filter((item) => item.action !== undefined);
120
+ if (!deps.isTTY) {
121
+ return renderRepairQueueSummaryLines(degraded).join("\n");
122
+ }
123
+ return (0, terminal_ui_1.renderTerminalWizard)({
124
+ isTTY: true,
125
+ columns: deps.stdoutColumns,
126
+ masthead: {
127
+ subtitle: "Repair paths ready.",
128
+ },
129
+ title: "Needs attention before startup can finish",
130
+ summary: "Ouro found repair steps it can open right now. It will walk through them one at a time.",
131
+ sections: [{
132
+ title: "Repair queue",
133
+ items: repairable.map(({ entry, action }) => ({
134
+ label: entry.agent,
135
+ status: repairStatusFor(action),
136
+ summary: action.label,
137
+ detailLines: [entry.errorReason],
138
+ command: action.command,
139
+ })),
140
+ }],
141
+ suppressEvent: true,
142
+ }).trimEnd();
143
+ }
144
+ function renderActionPromptLines(agent, action) {
145
+ const lines = [
146
+ `${agent}`,
147
+ ` needs: ${action.label}`,
148
+ ` run: ${action.command}`,
149
+ ];
150
+ if (action.kind === "vault-unlock") {
151
+ lines.push(" note: use the saved vault unlock secret");
152
+ }
153
+ return lines;
154
+ }
155
+ function renderActionPrompt(entry, action, deps) {
156
+ if (!deps.isTTY)
157
+ return renderActionPromptLines(entry.agent, action).join("\n");
158
+ const footer = action.kind === "vault-unlock"
159
+ ? "Only say yes if you have the saved vault unlock secret."
160
+ : "Say yes if you want Ouro to open the auth flow now.";
161
+ return (0, terminal_ui_1.renderTerminalWizard)({
162
+ isTTY: true,
163
+ columns: deps.stdoutColumns,
164
+ masthead: {
165
+ subtitle: "One repair step at a time.",
166
+ },
167
+ title: `Repair ${entry.agent}`,
168
+ summary: "Ouro found one clear next move for this agent.",
169
+ nextStep: {
170
+ label: action.kind === "vault-unlock"
171
+ ? "Unlock the credential vault on this machine."
172
+ : "Refresh provider authentication.",
173
+ detail: action.kind === "vault-unlock"
174
+ ? "Use the saved unlock secret if you have it. If not, leave this for later and choose a replacement or recovery path."
175
+ : "This opens the provider login or refresh flow for the selected provider.",
176
+ command: action.command,
177
+ },
178
+ sections: [{
179
+ title: "Why startup paused",
180
+ items: [{
181
+ label: entry.agent,
182
+ status: repairStatusFor(action),
183
+ summary: entry.errorReason,
184
+ }],
185
+ }],
186
+ footerLines: [footer],
187
+ suppressEvent: true,
188
+ }).trimEnd();
189
+ }
190
+ function renderDeferredRepair(agent, commands, deps) {
191
+ if (!deps.isTTY) {
192
+ return [
193
+ `Leaving ${agent} for later.`,
194
+ ...renderRepairChoices("next", commands),
195
+ ].join("\n");
196
+ }
197
+ return (0, terminal_ui_1.renderTerminalWizard)({
198
+ isTTY: true,
199
+ columns: deps.stdoutColumns,
200
+ masthead: {
201
+ subtitle: "Nothing changed yet.",
202
+ },
203
+ title: `Leaving ${agent} for later`,
204
+ summary: "Ouro did not open this repair flow right now.",
205
+ sections: [{
206
+ title: "Next time",
207
+ items: commands.map((command, index) => ({
208
+ key: String(index + 1),
209
+ label: index === 0 ? "Start here" : "Or try this",
210
+ command,
211
+ })),
212
+ }],
213
+ suppressEvent: true,
214
+ }).trimEnd();
215
+ }
216
+ function renderManualRepairHint(agent, fixHint) {
217
+ return [
218
+ `${agent}`,
219
+ " needs manual attention",
220
+ ` next: ${fixHint}`,
221
+ ].join("\n");
222
+ }
223
+ function renderUnknownRepair(agent, errorReason) {
224
+ return [
225
+ `${agent}`,
226
+ ` ${errorReason}`,
227
+ ].join("\n");
228
+ }
229
+ function writeDeclinedRepair(degraded, command, deps) {
230
+ deps.writeStdout(renderDeferredRepair(degraded.agent, fallbackCommandsFor(degraded, command), deps));
231
+ }
232
+ function runnableRepairActionFor(degraded) {
233
+ const typedAction = degraded.issue?.actions
234
+ .map((action) => typedActionToRunnable(degraded, action))
235
+ .find((action) => action !== undefined);
236
+ if (typedAction)
237
+ return typedAction;
238
+ if (isVaultUnlockIssue(degraded)) {
239
+ return { kind: "vault-unlock", label: "vault unlock", command: vaultUnlockCommandFor(degraded) };
240
+ }
241
+ if (isCredentialIssue(degraded)) {
242
+ return {
243
+ kind: "provider-auth",
244
+ label: "provider auth",
245
+ command: authCommandFor(degraded),
246
+ provider: extractProviderFromFixHint(degraded.fixHint),
247
+ };
248
+ }
249
+ return undefined;
250
+ }
251
+ function typedActionToRunnable(degraded, action) {
252
+ if (action.executable === false || action.command.includes("<"))
253
+ return undefined;
254
+ if (action.kind === "vault-unlock") {
255
+ return { kind: "vault-unlock", label: "vault unlock", command: action.command };
256
+ }
257
+ if (action.kind === "provider-auth") {
258
+ return {
259
+ kind: "provider-auth",
260
+ label: "provider auth",
261
+ command: action.command || `ouro auth --agent ${degraded.agent}`,
262
+ provider: action.provider,
263
+ };
264
+ }
265
+ return undefined;
266
+ }
267
+ function writeRepairQueueSummary(degraded, deps) {
268
+ const lines = renderRepairQueueSummaryLines(degraded);
269
+ if (lines.length > 0)
270
+ deps.writeStdout(renderRepairQueueSummary(degraded, deps));
271
+ }
272
+ async function attemptVaultUnlock(entry, action, deps) {
273
+ deps.writeStdout(renderActionPrompt(entry, action, deps));
274
+ const answer = await deps.promptInput(`Unlock ${entry.agent}'s vault now? [y/N] `);
275
+ if (!isAffirmativeAnswer(answer)) {
276
+ writeDeclinedRepair(entry, action.command, deps);
277
+ return { succeeded: false, attempted: false };
278
+ }
279
+ try {
280
+ if (!deps.runVaultUnlock) {
281
+ deps.writeStdout(renderManualRepairHint(entry.agent, entry.fixHint));
282
+ return { succeeded: false, attempted: false };
283
+ }
284
+ await deps.runVaultUnlock(entry.agent);
285
+ return { succeeded: true, attempted: true };
286
+ }
287
+ catch (error) {
288
+ const msg = error instanceof Error ? error.message : String(error);
289
+ deps.writeStdout(`Vault unlock did not finish for ${entry.agent}.\n ${msg}`);
290
+ (0, runtime_1.emitNervesEvent)({
291
+ level: "error",
292
+ component: "daemon",
293
+ event: "daemon.interactive_repair_vault_unlock_error",
294
+ message: `vault unlock failed for ${entry.agent}`,
295
+ meta: { agent: entry.agent, error: msg },
296
+ });
297
+ return { succeeded: false, attempted: true };
298
+ }
299
+ }
300
+ async function attemptProviderAuth(entry, action, deps) {
301
+ deps.writeStdout(renderActionPrompt(entry, action, deps));
302
+ const answer = await deps.promptInput(`Open the auth flow for ${entry.agent} now? [y/N] `);
303
+ if (!isAffirmativeAnswer(answer)) {
304
+ writeDeclinedRepair(entry, action.command, deps);
305
+ return { succeeded: false, attempted: false };
306
+ }
307
+ try {
308
+ if (action.provider) {
309
+ await deps.runAuthFlow(entry.agent, action.provider);
310
+ }
311
+ else {
312
+ await deps.runAuthFlow(entry.agent);
313
+ }
314
+ return { succeeded: true, attempted: true };
315
+ }
316
+ catch (error) {
317
+ const msg = error instanceof Error ? error.message : String(error);
318
+ deps.writeStdout(`Auth did not finish for ${entry.agent}.\n ${msg}`);
319
+ (0, runtime_1.emitNervesEvent)({
320
+ level: "error",
321
+ component: "daemon",
322
+ event: "daemon.interactive_repair_auth_error",
323
+ message: `auth flow failed for ${entry.agent}`,
324
+ meta: { agent: entry.agent, error: msg },
325
+ });
326
+ return { succeeded: false, attempted: true };
327
+ }
328
+ }
329
+ async function processEntry(entry, deps) {
330
+ let current = entry;
331
+ while (current) {
332
+ const action = runnableRepairActionFor(current);
333
+ let outcome;
334
+ if (action?.kind === "vault-unlock") {
335
+ outcome = await attemptVaultUnlock(current, action, deps);
336
+ }
337
+ else if (action?.kind === "provider-auth") {
338
+ outcome = await attemptProviderAuth(current, action, deps);
339
+ }
340
+ else if (isConfigError(current)) {
341
+ deps.writeStdout(renderManualRepairHint(current.agent, current.fixHint));
342
+ return { attempted: false };
343
+ }
344
+ else {
345
+ deps.writeStdout(renderUnknownRepair(current.agent, current.errorReason));
346
+ return { attempted: false };
347
+ }
348
+ if (!outcome.succeeded || !deps.recheckAgent) {
349
+ return { attempted: outcome.attempted };
350
+ }
351
+ // Re-evaluate the agent after successful repair
352
+ const recheckResult = await deps.recheckAgent(current.agent);
353
+ if (recheckResult === null) {
354
+ deps.writeStdout(`${current.agent} recovered.`);
355
+ return { attempted: true };
356
+ }
357
+ // Agent still degraded with a new error -- loop to present the new action
358
+ current = recheckResult;
359
+ }
360
+ /* v8 ignore next -- unreachable: loop always returns from within @preserve */
361
+ return { attempted: false };
362
+ }
363
+ async function runInteractiveRepair(degraded, deps) {
364
+ (0, runtime_1.emitNervesEvent)({
365
+ level: "info",
366
+ component: "daemon",
367
+ event: "daemon.interactive_repair_start",
368
+ message: "interactive repair flow started",
369
+ meta: { degradedCount: degraded.length },
370
+ });
371
+ if (degraded.length === 0) {
372
+ return { repairsAttempted: false };
373
+ }
374
+ let repairsAttempted = false;
375
+ if (!deps.skipQueueSummary) {
376
+ writeRepairQueueSummary(degraded, deps);
377
+ }
378
+ for (const entry of degraded) {
379
+ const result = await processEntry(entry, deps);
380
+ if (result.attempted)
381
+ repairsAttempted = true;
382
+ }
383
+ if (repairsAttempted) {
384
+ deps.writeStdout("Repair flow complete.");
385
+ }
386
+ (0, runtime_1.emitNervesEvent)({
387
+ level: "info",
388
+ component: "daemon",
389
+ event: "daemon.interactive_repair_end",
390
+ message: "interactive repair flow completed",
391
+ meta: { repairsAttempted },
392
+ });
393
+ return { repairsAttempted };
394
+ }
@@ -45,6 +45,9 @@ exports.DAEMON_PLIST_LABEL = "bot.ouro.daemon";
45
45
  function plistFilePath(homeDir) {
46
46
  return path.join(homeDir, "Library", "LaunchAgents", `${exports.DAEMON_PLIST_LABEL}.plist`);
47
47
  }
48
+ function userLaunchDomain(userUid) {
49
+ return `gui/${userUid}`;
50
+ }
48
51
  function generateDaemonPlist(options) {
49
52
  (0, runtime_1.emitNervesEvent)({
50
53
  component: "daemon",
@@ -71,8 +74,17 @@ function generateDaemonPlist(options) {
71
74
  ` <key>KeepAlive</key>`,
72
75
  ` <true/>`,
73
76
  ];
77
+ if (options.envPath) {
78
+ lines.push(` <key>EnvironmentVariables</key>`, ` <dict>`, ` <key>PATH</key>`, ` <string>${options.envPath}</string>`, ` </dict>`);
79
+ }
74
80
  if (options.logDir) {
75
- lines.push(` <key>StandardOutPath</key>`, ` <string>${path.join(options.logDir, "ouro-daemon-stdout.log")}</string>`, ` <key>StandardErrorPath</key>`, ` <string>${path.join(options.logDir, "ouro-daemon-stderr.log")}</string>`);
81
+ // PR 1 decision: we no longer emit `StandardErrorPath` for the daemon.
82
+ // The daemon's structured nerves ndjson pipeline (rotated + gzipped via
83
+ // createNdjsonFileSink) is the source of truth for diagnostics. Writing
84
+ // raw process stderr to an unrotated file grew to 366 MB in the wild;
85
+ // dropping the key lets launchd forward stray stderr to the system log
86
+ // where it gets rotated by the OS.
87
+ lines.push(` <key>StandardOutPath</key>`, ` <string>${path.join(options.logDir, "ouro-daemon-stdout.log")}</string>`);
76
88
  }
77
89
  lines.push(`</dict>`, `</plist>`, ``);
78
90
  return lines.join("\n");
@@ -102,19 +114,26 @@ function installLaunchAgent(deps, options) {
102
114
  meta: { entryPath: options.entryPath, socketPath: options.socketPath },
103
115
  });
104
116
  const fullPath = plistFilePath(deps.homeDir);
117
+ const domain = userLaunchDomain(deps.userUid);
105
118
  // Unload existing (best effort) for idempotent re-install
106
119
  if (deps.existsFile(fullPath)) {
107
120
  try {
108
- deps.exec(`launchctl unload "${fullPath}"`);
121
+ deps.exec(`launchctl bootout ${domain} "${fullPath}"`);
109
122
  }
110
123
  catch { /* best effort */ }
111
124
  }
112
125
  writeLaunchAgentPlist(deps, options);
113
- deps.exec(`launchctl load "${fullPath}"`);
126
+ // Bootstrap the plist so launchd manages crash recovery via KeepAlive.
127
+ // This is safe because ouro up calls this AFTER the daemon is already running,
128
+ // so launchd sees the existing process and just registers for KeepAlive.
129
+ try {
130
+ deps.exec(`launchctl bootstrap ${domain} "${fullPath}"`);
131
+ }
132
+ catch { /* already loaded */ }
114
133
  (0, runtime_1.emitNervesEvent)({
115
134
  component: "daemon",
116
135
  event: "daemon.launchd_installed",
117
- message: "launch agent installed",
136
+ message: "launch agent installed with KeepAlive",
118
137
  meta: { plistPath: fullPath },
119
138
  });
120
139
  }
@@ -126,9 +145,10 @@ function uninstallLaunchAgent(deps) {
126
145
  meta: {},
127
146
  });
128
147
  const fullPath = plistFilePath(deps.homeDir);
148
+ const domain = userLaunchDomain(deps.userUid);
129
149
  if (deps.existsFile(fullPath)) {
130
150
  try {
131
- deps.exec(`launchctl unload "${fullPath}"`);
151
+ deps.exec(`launchctl bootout ${domain} "${fullPath}"`);
132
152
  }
133
153
  catch { /* best effort */ }
134
154
  deps.removeFile(fullPath);
@@ -37,39 +37,103 @@ exports.discoverLogFiles = discoverLogFiles;
37
37
  exports.readLastLines = readLastLines;
38
38
  exports.formatLogLine = formatLogLine;
39
39
  exports.tailLogs = tailLogs;
40
- const os = __importStar(require("os"));
41
40
  const path = __importStar(require("path"));
41
+ const zlib = __importStar(require("zlib"));
42
42
  const nerves_1 = require("../../nerves");
43
43
  const runtime_1 = require("../../nerves/runtime");
44
+ const identity_1 = require("../identity");
44
45
  const LEVEL_COLORS = {
45
46
  debug: "\x1b[2m",
46
47
  info: "\x1b[36m",
47
48
  warn: "\x1b[33m",
48
49
  error: "\x1b[31m",
49
50
  };
51
+ /**
52
+ * Parse a log filename into a (streamBase, generationRank) tuple.
53
+ *
54
+ * - `daemon.ndjson` → { streamBase: "daemon", rank: 0 } (active, newest)
55
+ * - `daemon.1.ndjson.gz` → { streamBase: "daemon", rank: 1 }
56
+ * - `daemon.5.ndjson.gz` → { streamBase: "daemon", rank: 5 } (oldest)
57
+ * - Anything else → null (not a log file).
58
+ *
59
+ * Higher rank = older. Used to sort so the oldest generation is read first
60
+ * and the active stream is read last, producing chronological output.
61
+ */
62
+ function parseLogFilename(name) {
63
+ if (name.endsWith(".ndjson.gz")) {
64
+ // e.g. daemon.1.ndjson.gz → base "daemon.1", strip ".gz" then ".ndjson" then ".<n>"
65
+ const withoutGz = name.slice(0, -".gz".length); // daemon.1.ndjson
66
+ const withoutNdjson = withoutGz.slice(0, -".ndjson".length); // daemon.1
67
+ const genMatch = withoutNdjson.match(/^(.+)\.(\d+)$/);
68
+ if (!genMatch)
69
+ return null;
70
+ return { streamBase: genMatch[1], rank: parseInt(genMatch[2], 10) };
71
+ }
72
+ if (name.endsWith(".ndjson")) {
73
+ const withoutNdjson = name.slice(0, -".ndjson".length);
74
+ // Active file: daemon.ndjson → base "daemon", rank 0
75
+ // Legacy numeric gen: daemon.1.ndjson → base "daemon", rank 1 (treat same as gzipped)
76
+ const legacyMatch = withoutNdjson.match(/^(.+)\.(\d+)$/);
77
+ if (legacyMatch) {
78
+ return { streamBase: legacyMatch[1], rank: parseInt(legacyMatch[2], 10) };
79
+ }
80
+ return { streamBase: withoutNdjson, rank: 0 };
81
+ }
82
+ return null;
83
+ }
50
84
  function discoverLogFiles(options) {
51
85
  /* v8 ignore start -- integration: default DI stubs for real OS @preserve */
52
- const homeDir = options.homeDir ?? os.homedir();
53
86
  const existsSync = options.existsSync ?? (() => false);
54
87
  const readdirSync = options.readdirSync ?? (() => []);
55
88
  /* v8 ignore stop */
56
- const logDir = path.join(homeDir, ".agentstate", "daemon", "logs");
57
- const files = [];
89
+ const logDir = options.homeDir
90
+ ? path.join(options.homeDir, "AgentBundles", `${options.agentName ?? "slugger"}.ouro`, "state", "daemon", "logs")
91
+ : (0, identity_1.getAgentDaemonLogsDir)(options.agentName);
92
+ const entries = [];
58
93
  if (existsSync(logDir)) {
59
94
  for (const name of readdirSync(logDir)) {
60
- if (!name.endsWith(".ndjson"))
95
+ const parsed = parseLogFilename(name);
96
+ if (!parsed)
61
97
  continue;
62
98
  if (options.agentFilter && !name.includes(options.agentFilter))
63
99
  continue;
64
- files.push(path.join(logDir, name));
100
+ entries.push({ name, parsed });
65
101
  }
66
102
  }
67
- return files.sort();
103
+ // Sort chronologically: for each stream, oldest generation first, active last.
104
+ // Across streams, sort alphabetically by streamBase so output is stable.
105
+ entries.sort((a, b) => {
106
+ if (a.parsed.streamBase !== b.parsed.streamBase) {
107
+ return a.parsed.streamBase < b.parsed.streamBase ? -1 : 1;
108
+ }
109
+ // Same stream: higher rank = older = read first.
110
+ return b.parsed.rank - a.parsed.rank;
111
+ });
112
+ return entries.map((e) => path.join(logDir, e.name));
113
+ }
114
+ /**
115
+ * Read a log file as a string, transparently handling gzipped rotations.
116
+ *
117
+ * For `.ndjson.gz` files we read the raw bytes via `fs.readFileSync` (ignoring
118
+ * any caller-supplied DI `readFileSync`, since that stub returns a `string`
119
+ * and would corrupt gzip bytes) and then `zlib.gunzipSync` to recover the
120
+ * original text. For plain `.ndjson` files we defer to the DI stub so tests
121
+ * can keep mocking fs.
122
+ */
123
+ function readNdjsonFileContents(filePath, readFileSync) {
124
+ if (filePath.endsWith(".gz")) {
125
+ // Binary path: tests can mock readFileSync to return a Buffer (typed as
126
+ // string) via `as unknown as string` — we accept both Buffer and Uint8Array.
127
+ const raw = readFileSync(filePath);
128
+ const buf = typeof raw === "string" ? Buffer.from(raw, "binary") : Buffer.from(raw);
129
+ return zlib.gunzipSync(buf).toString("utf-8");
130
+ }
131
+ return readFileSync(filePath, "utf-8");
68
132
  }
69
133
  function readLastLines(filePath, count, readFileSync) {
70
134
  let content;
71
135
  try {
72
- content = readFileSync(filePath, "utf-8");
136
+ content = readNdjsonFileContents(filePath, readFileSync);
73
137
  }
74
138
  catch {
75
139
  return [];
@@ -99,12 +163,17 @@ function tailLogs(options = {}) {
99
163
  const files = discoverLogFiles(options);
100
164
  (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.log_tailer_started", message: "log tailer started", meta: { fileCount: files.length, follow: !!options.follow } });
101
165
  const fileSizes = new Map();
102
- // Read initial lines
166
+ // Read initial lines from each discovered file (oldest gz → newest gz → active).
167
+ // Gzipped files are historical and never tailed in follow mode.
103
168
  for (const file of files) {
104
169
  const lines = readLastLines(file, lineCount, readFileSync);
105
170
  for (const line of lines) {
106
171
  writer(`${formatLogLine(line)}\n`);
107
172
  }
173
+ if (file.endsWith(".gz")) {
174
+ // Historical rotation — skip size tracking, never followed.
175
+ continue;
176
+ }
108
177
  try {
109
178
  const content = readFileSync(file, "utf-8");
110
179
  fileSizes.set(file, content.length);
@@ -113,9 +182,10 @@ function tailLogs(options = {}) {
113
182
  fileSizes.set(file, 0);
114
183
  }
115
184
  }
116
- // Follow mode
185
+ // Follow mode: only the active (non-gzipped) stream is watched.
117
186
  if (options.follow && watchFile && unwatchFile) {
118
- for (const file of files) {
187
+ const activeFiles = files.filter((f) => !f.endsWith(".gz"));
188
+ for (const file of activeFiles) {
119
189
  watchFile(file, () => {
120
190
  let content;
121
191
  try {
@@ -137,7 +207,7 @@ function tailLogs(options = {}) {
137
207
  });
138
208
  }
139
209
  return () => {
140
- for (const file of files) {
210
+ for (const file of activeFiles) {
141
211
  unwatchFile(file);
142
212
  }
143
213
  };