@ouro.bot/cli 0.1.0-alpha.62 → 0.1.0-alpha.637

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 (432) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +4087 -13
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +144 -0
  15. package/dist/arc/episodes.js +118 -0
  16. package/dist/arc/evolution.js +487 -0
  17. package/dist/arc/intentions.js +134 -0
  18. package/dist/arc/json-store.js +117 -0
  19. package/dist/arc/obligations.js +270 -0
  20. package/dist/arc/packets.js +288 -0
  21. package/dist/arc/presence.js +185 -0
  22. package/dist/arc/task-lifecycle.js +57 -0
  23. package/dist/heart/active-work.js +860 -43
  24. package/dist/heart/agent-entry.js +69 -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/bluebubbles.js +156 -0
  30. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  31. package/dist/heart/attachments/sources/index.js +16 -0
  32. package/dist/heart/attachments/store.js +103 -0
  33. package/dist/heart/attachments/types.js +93 -0
  34. package/dist/heart/auth/auth-flow.js +479 -0
  35. package/dist/heart/awaiting/await-alert.js +146 -0
  36. package/dist/heart/awaiting/await-expiry.js +108 -0
  37. package/dist/heart/awaiting/await-loader.js +91 -0
  38. package/dist/heart/awaiting/await-parser.js +141 -0
  39. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  40. package/dist/heart/awaiting/await-scheduler.js +377 -0
  41. package/dist/heart/background-operations.js +281 -0
  42. package/dist/heart/bridges/manager.js +137 -17
  43. package/dist/heart/bridges/store.js +14 -2
  44. package/dist/heart/bundle-state.js +168 -0
  45. package/dist/heart/commitments.js +135 -0
  46. package/dist/heart/config-registry.js +322 -0
  47. package/dist/heart/config.js +114 -119
  48. package/dist/heart/core.js +1028 -248
  49. package/dist/heart/cross-chat-delivery.js +3 -18
  50. package/dist/heart/daemon/agent-config-check.js +419 -0
  51. package/dist/heart/daemon/agent-discovery.js +102 -3
  52. package/dist/heart/daemon/agent-service.js +522 -0
  53. package/dist/heart/daemon/agentic-repair.js +547 -0
  54. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  55. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  56. package/dist/heart/daemon/cadence.js +70 -0
  57. package/dist/heart/daemon/cli-defaults.js +776 -0
  58. package/dist/heart/daemon/cli-desk.js +322 -0
  59. package/dist/heart/daemon/cli-exec.js +7468 -0
  60. package/dist/heart/daemon/cli-help.js +505 -0
  61. package/dist/heart/daemon/cli-parse.js +1554 -0
  62. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  63. package/dist/heart/daemon/cli-render.js +763 -0
  64. package/dist/heart/daemon/cli-types.js +8 -0
  65. package/dist/heart/daemon/connect-bay.js +323 -0
  66. package/dist/heart/daemon/daemon-cli.js +29 -1700
  67. package/dist/heart/daemon/daemon-entry.js +485 -2
  68. package/dist/heart/daemon/daemon-health.js +176 -0
  69. package/dist/heart/daemon/daemon-rollup.js +57 -0
  70. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  71. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  72. package/dist/heart/daemon/daemon.js +906 -71
  73. package/dist/heart/daemon/dns-workflow.js +394 -0
  74. package/dist/heart/daemon/doctor-types.js +8 -0
  75. package/dist/heart/daemon/doctor.js +873 -0
  76. package/dist/heart/daemon/health-monitor.js +122 -1
  77. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  78. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  79. package/dist/heart/daemon/http-health-probe.js +80 -0
  80. package/dist/heart/daemon/human-command-screens.js +234 -0
  81. package/dist/heart/daemon/human-readiness.js +114 -0
  82. package/dist/heart/daemon/inner-status.js +89 -0
  83. package/dist/heart/daemon/interactive-repair.js +394 -0
  84. package/dist/heart/daemon/launchd.js +37 -8
  85. package/dist/heart/daemon/log-tailer.js +79 -10
  86. package/dist/heart/daemon/logs-prune.js +110 -0
  87. package/dist/heart/daemon/mcp-canary.js +297 -0
  88. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  89. package/dist/heart/daemon/os-cron-deps.js +135 -0
  90. package/dist/heart/daemon/os-cron.js +14 -12
  91. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  92. package/dist/heart/daemon/ouro-entry.js +3 -1
  93. package/dist/heart/daemon/plugin-cli.js +432 -0
  94. package/dist/heart/daemon/process-manager.js +501 -35
  95. package/dist/heart/daemon/provider-discovery.js +137 -0
  96. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  97. package/dist/heart/daemon/pulse.js +475 -0
  98. package/dist/heart/daemon/readiness-repair.js +365 -0
  99. package/dist/heart/daemon/run-hooks.js +2 -0
  100. package/dist/heart/daemon/runtime-logging.js +11 -3
  101. package/dist/heart/daemon/runtime-metadata.js +2 -30
  102. package/dist/heart/daemon/safe-mode.js +161 -0
  103. package/dist/heart/daemon/sense-manager.js +493 -38
  104. package/dist/heart/daemon/session-id-resolver.js +131 -0
  105. package/dist/heart/daemon/skill-management-installer.js +22 -9
  106. package/dist/heart/daemon/socket-client.js +158 -11
  107. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  108. package/dist/heart/daemon/startup-tui.js +330 -0
  109. package/dist/heart/daemon/task-scheduler.js +117 -39
  110. package/dist/heart/daemon/terminal-ui.js +499 -0
  111. package/dist/heart/daemon/thoughts.js +229 -17
  112. package/dist/heart/daemon/up-progress.js +366 -0
  113. package/dist/heart/daemon/vault-items.js +56 -0
  114. package/dist/heart/delegation.js +1 -4
  115. package/dist/heart/habits/habit-migration.js +189 -0
  116. package/dist/heart/habits/habit-parser.js +140 -0
  117. package/dist/heart/habits/habit-runtime-state.js +100 -0
  118. package/dist/heart/habits/habit-scheduler.js +372 -0
  119. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  120. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  121. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  122. package/dist/heart/{daemon → hatch}/specialist-tools.js +37 -14
  123. package/dist/heart/identity.js +168 -57
  124. package/dist/heart/kept-notes.js +357 -0
  125. package/dist/heart/kicks.js +1 -1
  126. package/dist/heart/machine-identity.js +161 -0
  127. package/dist/heart/mail-import-discovery.js +353 -0
  128. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  129. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  130. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  131. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  132. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  133. package/dist/heart/mailbox/mailbox-http.js +99 -0
  134. package/dist/heart/mailbox/mailbox-read.js +31 -0
  135. package/dist/heart/mailbox/mailbox-types.js +27 -0
  136. package/dist/heart/mailbox/mailbox-view.js +197 -0
  137. package/dist/heart/mailbox/readers/agent-machine.js +418 -0
  138. package/dist/heart/mailbox/readers/continuity-readers.js +319 -0
  139. package/dist/heart/mailbox/readers/mail.js +375 -0
  140. package/dist/heart/mailbox/readers/runtime-readers.js +756 -0
  141. package/dist/heart/mailbox/readers/sessions.js +232 -0
  142. package/dist/heart/mailbox/readers/shared.js +111 -0
  143. package/dist/heart/mcp/mcp-server.js +692 -0
  144. package/dist/heart/migrate-config.js +100 -0
  145. package/dist/heart/model-capabilities.js +19 -0
  146. package/dist/heart/orientation-frame.js +217 -0
  147. package/dist/heart/platform.js +81 -0
  148. package/dist/heart/provider-attempt.js +134 -0
  149. package/dist/heart/provider-binding-resolver.js +272 -0
  150. package/dist/heart/provider-credentials.js +425 -0
  151. package/dist/heart/provider-failover.js +301 -0
  152. package/dist/heart/provider-models.js +81 -0
  153. package/dist/heart/provider-ping.js +262 -0
  154. package/dist/heart/provider-readiness-cache.js +40 -0
  155. package/dist/heart/provider-visibility.js +188 -0
  156. package/dist/heart/providers/anthropic-token.js +131 -0
  157. package/dist/heart/providers/anthropic.js +139 -52
  158. package/dist/heart/providers/azure.js +23 -11
  159. package/dist/heart/providers/error-classification.js +127 -0
  160. package/dist/heart/providers/github-copilot.js +145 -0
  161. package/dist/heart/providers/minimax-vlm.js +189 -0
  162. package/dist/heart/providers/minimax.js +26 -8
  163. package/dist/heart/providers/openai-codex.js +55 -40
  164. package/dist/heart/runtime-capability-check.js +170 -0
  165. package/dist/heart/runtime-credentials.js +367 -0
  166. package/dist/heart/runtime-cwd.js +87 -0
  167. package/dist/heart/sense-truth.js +13 -4
  168. package/dist/heart/session-activity.js +48 -24
  169. package/dist/heart/session-events.js +1163 -0
  170. package/dist/heart/session-playback-cli-main.js +5 -0
  171. package/dist/heart/session-playback-cli.js +36 -0
  172. package/dist/heart/session-playback.js +231 -0
  173. package/dist/heart/session-stats-cli-main.js +5 -0
  174. package/dist/heart/session-stats.js +182 -0
  175. package/dist/heart/session-transcript.js +133 -0
  176. package/dist/heart/start-of-turn-packet.js +345 -0
  177. package/dist/heart/streaming.js +44 -27
  178. package/dist/heart/structured-output.js +196 -0
  179. package/dist/heart/sync-classification.js +176 -0
  180. package/dist/heart/sync.js +449 -0
  181. package/dist/heart/target-resolution.js +9 -5
  182. package/dist/heart/tempo.js +93 -0
  183. package/dist/heart/temporal-view.js +41 -0
  184. package/dist/heart/timeouts.js +101 -0
  185. package/dist/heart/tool-activity-callbacks.js +59 -0
  186. package/dist/heart/tool-description.js +143 -0
  187. package/dist/heart/tool-friction.js +55 -0
  188. package/dist/heart/tool-loop.js +200 -0
  189. package/dist/heart/turn-context.js +389 -0
  190. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  191. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  192. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  193. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  194. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  195. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  196. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  197. package/dist/mailbox-ui/assets/index-9-AxCxuB.js +61 -0
  198. package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
  199. package/dist/mailbox-ui/index.html +15 -0
  200. package/dist/mailroom/attention.js +167 -0
  201. package/dist/mailroom/autonomy.js +209 -0
  202. package/dist/mailroom/blob-store.js +715 -0
  203. package/dist/mailroom/body-cache.js +61 -0
  204. package/dist/mailroom/core.js +788 -0
  205. package/dist/mailroom/entry.js +160 -0
  206. package/dist/mailroom/file-store.js +568 -0
  207. package/dist/mailroom/mbox-import.js +393 -0
  208. package/dist/mailroom/migration.js +164 -0
  209. package/dist/mailroom/outbound.js +380 -0
  210. package/dist/mailroom/policy.js +263 -0
  211. package/dist/mailroom/reader.js +233 -0
  212. package/dist/mailroom/search-cache.js +334 -0
  213. package/dist/mailroom/search-relevance.js +319 -0
  214. package/dist/mailroom/smtp-ingress.js +176 -0
  215. package/dist/mailroom/source-state.js +176 -0
  216. package/dist/mailroom/thread.js +109 -0
  217. package/dist/mailroom/travel-extract.js +89 -0
  218. package/dist/mind/bundle-manifest.js +14 -1
  219. package/dist/mind/context.js +251 -101
  220. package/dist/mind/desk-section.js +310 -0
  221. package/dist/mind/diary-integrity.js +60 -0
  222. package/dist/mind/{memory.js → diary.js} +68 -76
  223. package/dist/mind/embedding-provider.js +60 -0
  224. package/dist/mind/file-state.js +179 -0
  225. package/dist/mind/friends/channel.js +39 -0
  226. package/dist/mind/friends/resolver.js +54 -2
  227. package/dist/mind/friends/store-file.js +48 -4
  228. package/dist/mind/friends/types.js +2 -2
  229. package/dist/mind/journal-index.js +162 -0
  230. package/dist/mind/note-search.js +268 -0
  231. package/dist/mind/obligation-steering.js +221 -0
  232. package/dist/mind/pending.js +6 -1
  233. package/dist/mind/prompt-refresh.js +3 -2
  234. package/dist/mind/prompt.js +1075 -146
  235. package/dist/mind/provenance-trust.js +26 -0
  236. package/dist/mind/scrutiny.js +173 -0
  237. package/dist/nerves/cli-logging.js +7 -1
  238. package/dist/nerves/coverage/audit-rules.js +15 -6
  239. package/dist/nerves/coverage/audit.js +28 -2
  240. package/dist/nerves/coverage/cli.js +1 -1
  241. package/dist/nerves/coverage/contract.js +5 -5
  242. package/dist/nerves/coverage/file-completeness.js +139 -5
  243. package/dist/nerves/event-buffer.js +111 -0
  244. package/dist/nerves/index.js +224 -4
  245. package/dist/nerves/observation.js +20 -0
  246. package/dist/nerves/redact.js +79 -0
  247. package/dist/nerves/review/cli-main.js +5 -0
  248. package/dist/nerves/review/cli.js +156 -0
  249. package/dist/nerves/review/core.js +152 -0
  250. package/dist/nerves/runtime.js +5 -1
  251. package/dist/repertoire/ado-client.js +15 -56
  252. package/dist/repertoire/ado-semantic.js +16 -10
  253. package/dist/repertoire/api-client.js +97 -0
  254. package/dist/repertoire/bitwarden-store.js +1040 -0
  255. package/dist/repertoire/bundle-templates.js +72 -0
  256. package/dist/repertoire/bw-installer.js +180 -0
  257. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  258. package/dist/repertoire/coding/context-pack.js +331 -0
  259. package/dist/repertoire/coding/feedback.js +197 -30
  260. package/dist/repertoire/coding/manager.js +166 -10
  261. package/dist/repertoire/coding/spawner.js +55 -9
  262. package/dist/repertoire/coding/tools.js +219 -7
  263. package/dist/repertoire/commerce-errors.js +109 -0
  264. package/dist/repertoire/commerce-self-test.js +156 -0
  265. package/dist/repertoire/credential-access.js +178 -0
  266. package/dist/repertoire/desk/classifier.js +362 -0
  267. package/dist/repertoire/duffel-client.js +185 -0
  268. package/dist/repertoire/github-client.js +14 -55
  269. package/dist/repertoire/graph-client.js +11 -52
  270. package/dist/repertoire/guardrails.js +385 -0
  271. package/dist/repertoire/mcp-client.js +295 -0
  272. package/dist/repertoire/mcp-manager.js +403 -0
  273. package/dist/repertoire/mcp-tools.js +83 -0
  274. package/dist/repertoire/plugin-mcp.js +175 -0
  275. package/dist/repertoire/plugins.js +253 -0
  276. package/dist/repertoire/shell-sessions.js +133 -0
  277. package/dist/repertoire/skills.js +48 -4
  278. package/dist/repertoire/stripe-client.js +131 -0
  279. package/dist/repertoire/tool-results.js +29 -0
  280. package/dist/repertoire/tools-attachments.js +317 -0
  281. package/dist/repertoire/tools-awaiting.js +372 -0
  282. package/dist/repertoire/tools-base.js +59 -1082
  283. package/dist/repertoire/tools-bluebubbles.js +2 -0
  284. package/dist/repertoire/tools-bridge.js +144 -0
  285. package/dist/repertoire/tools-bundle.js +993 -0
  286. package/dist/repertoire/tools-config.js +186 -0
  287. package/dist/repertoire/tools-continuity.js +252 -0
  288. package/dist/repertoire/tools-credential.js +383 -0
  289. package/dist/repertoire/tools-evolution.js +527 -0
  290. package/dist/repertoire/tools-files.js +344 -0
  291. package/dist/repertoire/tools-flight.js +227 -0
  292. package/dist/repertoire/tools-flow.js +119 -0
  293. package/dist/repertoire/tools-github.js +3 -8
  294. package/dist/repertoire/tools-mail.js +1975 -0
  295. package/dist/repertoire/tools-notes.js +438 -0
  296. package/dist/repertoire/tools-obligations.js +143 -0
  297. package/dist/repertoire/tools-orientation.js +31 -0
  298. package/dist/repertoire/tools-record.js +464 -0
  299. package/dist/repertoire/tools-runtime.js +150 -0
  300. package/dist/repertoire/tools-session.js +766 -0
  301. package/dist/repertoire/tools-shell.js +120 -0
  302. package/dist/repertoire/tools-stripe.js +182 -0
  303. package/dist/repertoire/tools-surface.js +344 -0
  304. package/dist/repertoire/tools-teams.js +12 -39
  305. package/dist/repertoire/tools-travel.js +125 -0
  306. package/dist/repertoire/tools-trip.js +982 -0
  307. package/dist/repertoire/tools-user-profile.js +146 -0
  308. package/dist/repertoire/tools-vault.js +40 -0
  309. package/dist/repertoire/tools-voice.js +145 -0
  310. package/dist/repertoire/tools.js +215 -103
  311. package/dist/repertoire/travel-api-client.js +360 -0
  312. package/dist/repertoire/user-profile.js +131 -0
  313. package/dist/repertoire/vault-setup.js +246 -0
  314. package/dist/repertoire/vault-unlock.js +594 -0
  315. package/dist/scripts/claude-code-hook.js +41 -0
  316. package/dist/scripts/claude-code-stop-hook.js +47 -0
  317. package/dist/senses/attention-queue.js +186 -0
  318. package/dist/senses/await-turn-message.js +58 -0
  319. package/dist/senses/bluebubbles/active-turns.js +216 -0
  320. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  321. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  322. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  323. package/dist/senses/bluebubbles/entry.js +77 -0
  324. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  325. package/dist/senses/bluebubbles/index.js +2737 -0
  326. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  327. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  328. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  329. package/dist/senses/bluebubbles/processed-log.js +133 -0
  330. package/dist/senses/bluebubbles/replay.js +137 -0
  331. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  332. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  333. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  334. package/dist/senses/cli/bracketed-paste.js +82 -0
  335. package/dist/senses/cli/image-paste.js +287 -0
  336. package/dist/senses/cli/image-ref-navigation.js +75 -0
  337. package/dist/senses/cli/ink-app.js +156 -0
  338. package/dist/senses/cli/inline-diff.js +64 -0
  339. package/dist/senses/cli/input-keys.js +174 -0
  340. package/dist/senses/cli/kill-ring.js +86 -0
  341. package/dist/senses/cli/message-list.js +51 -0
  342. package/dist/senses/cli/ouro-tui.js +607 -0
  343. package/dist/senses/cli/spinner-imperative.js +135 -0
  344. package/dist/senses/cli/spinner.js +101 -0
  345. package/dist/senses/cli/status-line.js +60 -0
  346. package/dist/senses/cli/streaming-markdown.js +526 -0
  347. package/dist/senses/cli/tool-display.js +85 -0
  348. package/dist/senses/cli/tool-render.js +85 -0
  349. package/dist/senses/cli/tui-store.js +240 -0
  350. package/dist/senses/cli/virtual-list.js +35 -0
  351. package/dist/senses/cli-entry.js +60 -8
  352. package/dist/senses/cli-layout.js +100 -0
  353. package/dist/senses/cli.js +517 -204
  354. package/dist/senses/commands.js +66 -3
  355. package/dist/senses/habit-turn-message.js +108 -0
  356. package/dist/senses/inner-dialog-worker.js +254 -22
  357. package/dist/senses/inner-dialog.js +505 -40
  358. package/dist/senses/mail-entry.js +66 -0
  359. package/dist/senses/mail.js +379 -0
  360. package/dist/senses/pipeline.js +666 -181
  361. package/dist/senses/proactive-content-guard.js +51 -0
  362. package/dist/senses/shared-turn.js +393 -0
  363. package/dist/senses/surface-tool.js +108 -0
  364. package/dist/senses/teams-entry.js +60 -8
  365. package/dist/senses/teams.js +388 -98
  366. package/dist/senses/trust-gate.js +100 -5
  367. package/dist/senses/voice/audio-playback.js +237 -0
  368. package/dist/senses/voice/audio-routing.js +119 -0
  369. package/dist/senses/voice/elevenlabs.js +202 -0
  370. package/dist/senses/voice/floor-control.js +431 -0
  371. package/dist/senses/voice/floor-controller.js +115 -0
  372. package/dist/senses/voice/golden-path.js +116 -0
  373. package/dist/senses/voice/index.js +29 -0
  374. package/dist/senses/voice/meeting.js +113 -0
  375. package/dist/senses/voice/outbound.js +190 -0
  376. package/dist/senses/voice/phone.js +33 -0
  377. package/dist/senses/voice/playback.js +139 -0
  378. package/dist/senses/voice/realtime-eval.js +496 -0
  379. package/dist/senses/voice/realtime-trace.js +531 -0
  380. package/dist/senses/voice/transcript.js +70 -0
  381. package/dist/senses/voice/turn.js +191 -0
  382. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  383. package/dist/senses/voice/twilio-phone.js +5079 -0
  384. package/dist/senses/voice/types.js +2 -0
  385. package/dist/senses/voice/whisper.js +161 -0
  386. package/dist/senses/voice-entry.js +81 -0
  387. package/dist/senses/voice-realtime-eval-command.js +99 -0
  388. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  389. package/dist/senses/voice-twilio-entry.js +87 -0
  390. package/dist/trips/core.js +138 -0
  391. package/dist/trips/store.js +265 -0
  392. package/dist/util/frontmatter.js +53 -0
  393. package/package.json +48 -8
  394. package/skills/agent-commerce.md +106 -0
  395. package/skills/browser-navigation.md +117 -0
  396. package/skills/commerce-setup-guide.md +116 -0
  397. package/skills/commerce-setup.md +84 -0
  398. package/skills/configure-dev-tools.md +99 -0
  399. package/skills/travel-planning.md +138 -0
  400. package/dist/heart/daemon/auth-flow.js +0 -351
  401. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  402. package/dist/heart/safe-workspace.js +0 -228
  403. package/dist/heart/session-recall.js +0 -116
  404. package/dist/mind/associative-recall.js +0 -209
  405. package/dist/repertoire/tasks/board.js +0 -134
  406. package/dist/repertoire/tasks/index.js +0 -224
  407. package/dist/repertoire/tasks/lifecycle.js +0 -80
  408. package/dist/repertoire/tasks/middleware.js +0 -65
  409. package/dist/repertoire/tasks/parser.js +0 -173
  410. package/dist/repertoire/tasks/scanner.js +0 -132
  411. package/dist/repertoire/tasks/transitions.js +0 -144
  412. package/dist/senses/bluebubbles-entry.js +0 -13
  413. package/dist/senses/bluebubbles.js +0 -1177
  414. package/dist/senses/debug-activity.js +0 -148
  415. package/subagents/README.md +0 -7
  416. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  417. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  418. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  419. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  420. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  421. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  422. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  423. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  424. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  425. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  426. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  427. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  428. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  429. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  430. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  431. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  432. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Commerce self-test — per-service health checks for the agent's
4
+ * commerce infrastructure (Stripe, Duffel, LiteAPI).
5
+ *
6
+ * Used by the setup wizard to verify configuration and provide
7
+ * actionable error messages when services are misconfigured.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.commerceSelfTest = commerceSelfTest;
11
+ const stripe_client_1 = require("./stripe-client");
12
+ const duffel_client_1 = require("./duffel-client");
13
+ const credential_access_1 = require("./credential-access");
14
+ const runtime_1 = require("../nerves/runtime");
15
+ // ---------------------------------------------------------------------------
16
+ // Per-service tests
17
+ // ---------------------------------------------------------------------------
18
+ async function testStripe() {
19
+ try {
20
+ const client = await (0, stripe_client_1.createStripeClient)();
21
+ // Create a test card and immediately deactivate it
22
+ const card = await client.createVirtualCard({
23
+ type: "single_use",
24
+ spendLimit: 1,
25
+ currency: "usd",
26
+ });
27
+ await client.deactivateCard(card.cardId);
28
+ return { status: "ok", message: "Stripe Issuing working. Test card created and deactivated." };
29
+ }
30
+ catch (err) {
31
+ /* v8 ignore next -- reason @preserve */
32
+ const reason = err instanceof Error ? err.message : String(err);
33
+ if (reason.includes("no credential found") || reason.includes("restrictedKey")) {
34
+ return {
35
+ status: "error",
36
+ message: `Stripe key missing. Add your restricted key at https://dashboard.stripe.com/apikeys and store it in the vault as stripe.com/restrictedKey.`,
37
+ };
38
+ }
39
+ if (reason.includes("401") || reason.includes("Invalid API Key")) {
40
+ return {
41
+ status: "error",
42
+ message: `Stripe key returned 401. Verify it at https://dashboard.stripe.com/apikeys.`,
43
+ };
44
+ }
45
+ return {
46
+ status: "error",
47
+ message: `Stripe error: ${reason}`,
48
+ };
49
+ }
50
+ }
51
+ async function testDuffel() {
52
+ try {
53
+ const client = await (0, duffel_client_1.createDuffelClient)();
54
+ await client.searchFlights({
55
+ origin: "SFO",
56
+ destination: "JFK",
57
+ departureDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
58
+ passengers: [{ type: "adult" }],
59
+ });
60
+ return { status: "ok", message: "Duffel Flights working. Test search completed." };
61
+ }
62
+ catch (err) {
63
+ /* v8 ignore next -- reason @preserve */
64
+ const reason = err instanceof Error ? err.message : String(err);
65
+ if (reason.includes("no credential found") || reason.includes("apiKey")) {
66
+ return {
67
+ status: "error",
68
+ message: `Duffel key missing. Add your API key from https://app.duffel.com/tokens and store it in the vault as duffel.com/apiKey.`,
69
+ };
70
+ }
71
+ if (reason.includes("401") || reason.includes("Unauthorized")) {
72
+ return {
73
+ status: "error",
74
+ message: `Your Duffel key returned 401. Verify it at https://app.duffel.com/tokens.`,
75
+ };
76
+ }
77
+ return {
78
+ status: "error",
79
+ message: `Duffel error: ${reason}`,
80
+ };
81
+ }
82
+ }
83
+ async function testLiteApi() {
84
+ try {
85
+ const store = (0, credential_access_1.getCredentialStore)();
86
+ await store.getRawSecret("liteapi.travel", "apiKey");
87
+ // If we can retrieve the key, the config is present.
88
+ // LiteAPI is accessed via MCP, so we can't do a direct API call here.
89
+ // The actual health check happens when the MCP server starts.
90
+ return { status: "ok", message: "LiteAPI key found in vault. MCP server will use vault:liteapi.travel/apiKey." };
91
+ }
92
+ catch (err) {
93
+ /* v8 ignore next -- reason @preserve */
94
+ const reason = err instanceof Error ? err.message : String(err);
95
+ if (reason.includes("no credential found")) {
96
+ return {
97
+ status: "error",
98
+ message: `LiteAPI key missing. Get your API key from https://dashboard.liteapi.travel and store it in the vault as liteapi.travel/apiKey.`,
99
+ };
100
+ }
101
+ return {
102
+ status: "error",
103
+ message: `LiteAPI error: ${reason}`,
104
+ };
105
+ }
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Main self-test
109
+ // ---------------------------------------------------------------------------
110
+ async function commerceSelfTest() {
111
+ (0, runtime_1.emitNervesEvent)({
112
+ component: "repertoire",
113
+ event: "repertoire.commerce_self_test_start",
114
+ message: "starting commerce self-test",
115
+ meta: {},
116
+ });
117
+ const [stripe, duffel, liteapi] = await Promise.all([
118
+ testStripe(),
119
+ testDuffel(),
120
+ testLiteApi(),
121
+ ]);
122
+ const services = { stripe, duffel, liteapi };
123
+ const okCount = Object.values(services).filter((s) => s.status === "ok").length;
124
+ const total = Object.keys(services).length;
125
+ let overall;
126
+ if (okCount === total) {
127
+ overall = "healthy";
128
+ }
129
+ else if (okCount > 0) {
130
+ overall = "partial";
131
+ }
132
+ else {
133
+ overall = "unhealthy";
134
+ }
135
+ const lines = [];
136
+ if (stripe.status === "ok")
137
+ lines.push("Stripe: working");
138
+ else
139
+ lines.push(`Stripe: ${stripe.message}`);
140
+ if (duffel.status === "ok")
141
+ lines.push("Duffel: working");
142
+ else
143
+ lines.push(`Duffel: ${duffel.message}`);
144
+ if (liteapi.status === "ok")
145
+ lines.push("LiteAPI: working");
146
+ else
147
+ lines.push(`LiteAPI: ${liteapi.message}`);
148
+ const summary = `Commerce health: ${okCount}/${total} services ok.\n${lines.join("\n")}`;
149
+ (0, runtime_1.emitNervesEvent)({
150
+ component: "repertoire",
151
+ event: "repertoire.commerce_self_test_end",
152
+ message: "commerce self-test complete",
153
+ meta: { overall, okCount, total },
154
+ });
155
+ return { overall, services, summary };
156
+ }
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /**
3
+ * Credential access layer.
4
+ *
5
+ * Bitwarden/Vaultwarden is the sole runtime credential store. The only local
6
+ * secret is the vault unlock material held by an explicit local unlock store.
7
+ *
8
+ * Each agent owns one credential vault. getCredentialStore() returns that
9
+ * agent's vault directly; item names are not shared or namespaced across
10
+ * agents.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.getCredentialStore = getCredentialStore;
47
+ exports.probeCredentialVaultAccess = probeCredentialVaultAccess;
48
+ exports.resetCredentialStore = resetCredentialStore;
49
+ const crypto = __importStar(require("node:crypto"));
50
+ const fs = __importStar(require("node:fs"));
51
+ const os = __importStar(require("node:os"));
52
+ const path = __importStar(require("node:path"));
53
+ const runtime_1 = require("../nerves/runtime");
54
+ const identity = __importStar(require("../heart/identity"));
55
+ const bitwarden_store_1 = require("./bitwarden-store");
56
+ const vault_unlock_1 = require("./vault-unlock");
57
+ let stores = new Map();
58
+ function loadVaultSectionForAgent(agentName) {
59
+ const configPath = path.join(identity.getAgentRoot(agentName), "agent.json");
60
+ try {
61
+ const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
62
+ return { configPath, vault: parsed.vault };
63
+ }
64
+ catch {
65
+ return { configPath };
66
+ }
67
+ }
68
+ function bitwardenAppDataDir(agentName, vaultConfig, homeDir = os.homedir()) {
69
+ const digest = crypto
70
+ .createHash("sha256")
71
+ .update(`${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`)
72
+ .digest("hex")
73
+ .slice(0, 24);
74
+ return path.join(homeDir, ".ouro-cli", "bitwarden", digest);
75
+ }
76
+ function getCredentialStore(agentNameInput) {
77
+ const agentName = agentNameInput ?? identity.getAgentName();
78
+ if (agentName === "SerpentGuide") {
79
+ throw new Error("SerpentGuide does not have a persistent credential vault; hatch bootstrap uses provider credentials in memory only.");
80
+ }
81
+ const { configPath, vault } = loadVaultSectionForAgent(agentName);
82
+ if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
83
+ throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
84
+ }
85
+ const vaultConfig = identity.resolveVaultConfig(agentName, vault);
86
+ const cacheKey = `${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`;
87
+ const cached = stores.get(cacheKey);
88
+ if (cached)
89
+ return cached;
90
+ const unlock = (0, vault_unlock_1.readVaultUnlockSecret)({
91
+ agentName,
92
+ email: vaultConfig.email,
93
+ serverUrl: vaultConfig.serverUrl,
94
+ });
95
+ const unlockConfig = { agentName, email: vaultConfig.email, serverUrl: vaultConfig.serverUrl };
96
+ const unlockSource = unlock.source ?? unlockConfig;
97
+ let invalidUnlockCleared = false;
98
+ let canonicalUnlockStored = false;
99
+ const store = new bitwarden_store_1.BitwardenCredentialStore(vaultConfig.serverUrl, vaultConfig.email, unlock.secret, {
100
+ appDataDir: bitwardenAppDataDir(agentName, vaultConfig),
101
+ onInvalidUnlockSecret: (error) => {
102
+ if (invalidUnlockCleared)
103
+ return;
104
+ invalidUnlockCleared = true;
105
+ (0, vault_unlock_1.clearVaultUnlockSecret)({
106
+ agentName,
107
+ email: unlockSource.email,
108
+ serverUrl: unlockSource.serverUrl,
109
+ });
110
+ stores.delete(cacheKey);
111
+ (0, runtime_1.emitNervesEvent)({
112
+ level: "warn",
113
+ event: "repertoire.credential_store_invalid_unlock_cleared",
114
+ component: "repertoire",
115
+ message: "cleared rejected local vault unlock material",
116
+ meta: {
117
+ agentName,
118
+ serverUrl: vaultConfig.serverUrl,
119
+ email: vaultConfig.email,
120
+ sourceServerUrl: unlockSource.serverUrl,
121
+ error: error.message,
122
+ },
123
+ });
124
+ },
125
+ onLoginSuccess: () => {
126
+ if (canonicalUnlockStored)
127
+ return;
128
+ if (unlockSource.serverUrl === vaultConfig.serverUrl && unlockSource.email === vaultConfig.email)
129
+ return;
130
+ canonicalUnlockStored = true;
131
+ try {
132
+ (0, vault_unlock_1.storeVaultUnlockSecret)(unlockConfig, unlock.secret);
133
+ (0, vault_unlock_1.noteVaultUnlockSelfHeal)(unlockConfig, unlock.store.kind, unlockSource.serverUrl);
134
+ }
135
+ catch (error) {
136
+ (0, runtime_1.emitNervesEvent)({
137
+ level: "warn",
138
+ event: "repertoire.vault_unlock_self_heal_failed",
139
+ component: "repertoire",
140
+ message: "failed to rewrite local unlock material using canonical vault coordinates",
141
+ meta: {
142
+ store: unlock.store.kind,
143
+ email: vaultConfig.email,
144
+ sourceServerUrl: unlockSource.serverUrl,
145
+ targetServerUrl: vaultConfig.serverUrl,
146
+ error: error instanceof Error ? error.message : String(error),
147
+ },
148
+ });
149
+ }
150
+ },
151
+ });
152
+ stores.set(cacheKey, store);
153
+ (0, runtime_1.emitNervesEvent)({
154
+ event: "repertoire.credential_store_init",
155
+ component: "repertoire",
156
+ message: "credential store initialized",
157
+ meta: {
158
+ backend: "bitwarden",
159
+ agentName,
160
+ serverUrl: vaultConfig.serverUrl,
161
+ email: vaultConfig.email,
162
+ },
163
+ });
164
+ return store;
165
+ }
166
+ async function probeCredentialVaultAccess(agentNameInput, unlockSecret, options = {}) {
167
+ const agentName = agentNameInput;
168
+ const { configPath, vault } = loadVaultSectionForAgent(agentName);
169
+ if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
170
+ throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
171
+ }
172
+ const vaultConfig = identity.resolveVaultConfig(agentName, vault);
173
+ const store = new bitwarden_store_1.BitwardenCredentialStore(vaultConfig.serverUrl, vaultConfig.email, unlockSecret, { appDataDir: bitwardenAppDataDir(agentName, vaultConfig, options.homeDir) });
174
+ await store.get("__ouro_vault_probe__");
175
+ }
176
+ function resetCredentialStore() {
177
+ stores = new Map();
178
+ }
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ /**
3
+ * Shared classifier for legacy `tasks/` → `desk/` migration.
4
+ *
5
+ * Pure data + parsing. Takes a file path relative to `<bundle>/tasks/` plus
6
+ * its content, returns a classification bucket. Used by `migrate-to-desk.ts`
7
+ * to decide where each file lands in the new `desk/` shape.
8
+ *
9
+ * Bucket definitions:
10
+ * - **terminal** — explicit done/complete/approved/cancelled/fixed status (or
11
+ * synonyms). Always archived. Files under `tasks/archive/` are unconditionally
12
+ * terminal regardless of frontmatter.
13
+ * - **stale_live** — live-looking status (`in-progress`, `ready_for_execution`,
14
+ * `drafting`, `collaborating`, etc.) but the resolved `updated` date is
15
+ * older than the 30-day cutoff. → archive (when-in-doubt rule).
16
+ * - **ambiguous** — no status, junk format, unknown status, `.md.bak` backup,
17
+ * or empty file. → archive.
18
+ * - **live_clear** — live status AND updated within the last 30 days AND
19
+ * coherent. → migrate to `legacy` track on the new desk.
20
+ * - **special_europe_trip** — historical one-off `ongoing/2026-03-09-1410-summer-2026-europe-trip.md` from the initial bundle that authored this migrator; kept as a labelled special case until the bundle is deprecated.
21
+ *
22
+ * Effective `updated` resolution priority: YAML `updated` → `approved` →
23
+ * `created` → body `**Updated**:` → date prefix in filename → file mtime.
24
+ *
25
+ * This is a pure-data helper: no side effects, no nerves observability of
26
+ * its own. The migrator emits nerves events around classify() calls.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.resolveUpdatedMs = resolveUpdatedMs;
30
+ exports.classifyFile = classifyFile;
31
+ exports.deriveTaskSlug = deriveTaskSlug;
32
+ exports.extractParentTaskDir = extractParentTaskDir;
33
+ const frontmatter_1 = require("../../util/frontmatter");
34
+ // ── Status vocabulary ──
35
+ const TERMINAL_STATUSES = new Set([
36
+ "done",
37
+ "complete",
38
+ "completed",
39
+ "approved",
40
+ "cancelled",
41
+ "canceled",
42
+ "fixed",
43
+ "merged",
44
+ "merged_and_published",
45
+ "abandoned",
46
+ "rejected",
47
+ "closed",
48
+ "shipped",
49
+ "resolved",
50
+ "archived",
51
+ "obsolete",
52
+ "deprecated",
53
+ "superseded",
54
+ "converted",
55
+ "discarded",
56
+ "won't-do",
57
+ "wontfix",
58
+ "won't-fix",
59
+ ]);
60
+ const LIVE_STATUSES = new Set([
61
+ "drafting",
62
+ "in-progress",
63
+ "in_progress",
64
+ "inprogress",
65
+ "ready_for_execution",
66
+ "ready-for-execution",
67
+ "collaborating",
68
+ "processing",
69
+ "validating",
70
+ "blocked",
71
+ "paused",
72
+ "open",
73
+ "needs_review",
74
+ "needs-review",
75
+ "handoff_needs_work_planner",
76
+ "running",
77
+ "active",
78
+ "reopened",
79
+ "handed-off",
80
+ "local_verified",
81
+ "ongoing",
82
+ ]);
83
+ // ── Helpers ──
84
+ function isMarkdownFile(relPath) {
85
+ return relPath.endsWith(".md");
86
+ }
87
+ function isBackupFile(relPath) {
88
+ return relPath.endsWith(".md.bak") || relPath.endsWith("~") || relPath.endsWith(".swp");
89
+ }
90
+ function isInArchiveSubdir(relPath) {
91
+ return relPath.startsWith("archive/") || relPath.includes("/archive/");
92
+ }
93
+ /**
94
+ * Detect the historical europe-trip task. Per the lift plan:
95
+ * `ongoing/2026-03-09-1410-summer-2026-europe-trip.md` is the only
96
+ * special-cased file.
97
+ */
98
+ function isEuropeTripTask(relPath) {
99
+ return relPath === "ongoing/2026-03-09-1410-summer-2026-europe-trip.md";
100
+ }
101
+ /**
102
+ * Extract the frontmatter block (between `---` fences) from a markdown file.
103
+ * Returns the raw frontmatter text or undefined if no fenced block exists.
104
+ */
105
+ function extractFrontmatterBlock(content) {
106
+ const trimmed = content.trimStart();
107
+ if (!trimmed.startsWith("---"))
108
+ return undefined;
109
+ const afterFirstFence = trimmed.slice(3);
110
+ const closeIdx = afterFirstFence.indexOf("\n---");
111
+ if (closeIdx === -1)
112
+ return undefined;
113
+ return afterFirstFence.slice(0, closeIdx).replace(/^\r?\n/, "");
114
+ }
115
+ function readStatusFromFrontmatter(fm) {
116
+ const candidates = ["status", "Status", "STATUS", "state", "State"];
117
+ for (const key of candidates) {
118
+ const value = fm[key];
119
+ if (typeof value === "string" && value.trim()) {
120
+ return value.trim().toLowerCase();
121
+ }
122
+ }
123
+ return undefined;
124
+ }
125
+ function readDateFromFrontmatter(fm, key) {
126
+ const value = fm[key];
127
+ if (typeof value !== "string")
128
+ return undefined;
129
+ const parsed = parseDateString(value);
130
+ return parsed;
131
+ }
132
+ /**
133
+ * Parse a date string into epoch ms. Accepts YYYY-MM-DD and full ISO 8601
134
+ * timestamps. Returns undefined for unparseable input.
135
+ */
136
+ function parseDateString(raw) {
137
+ const trimmed = raw.trim();
138
+ /* v8 ignore start -- defensive: callers (readDateFromFrontmatter, extractUpdatedFromBody) only pass values that have already been confirmed non-empty (frontmatter scalar or regex-captured digits). The empty-string fallback is unreachable in practice. @preserve */
139
+ if (!trimmed)
140
+ return undefined;
141
+ /* v8 ignore stop */
142
+ // YYYY-MM-DD or YYYY-MM-DD HH:MM or full ISO
143
+ const dateOnlyMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
144
+ if (dateOnlyMatch) {
145
+ const ms = Date.UTC(Number(dateOnlyMatch[1]), Number(dateOnlyMatch[2]) - 1, Number(dateOnlyMatch[3]));
146
+ /* v8 ignore start -- Date.UTC normalizes out-of-range numeric inputs to finite ms; the regex already guarantees four+two+two-digit ints. The undefined branch is genuinely unreachable. @preserve */
147
+ return Number.isFinite(ms) ? ms : undefined;
148
+ /* v8 ignore stop */
149
+ }
150
+ const ms = Date.parse(trimmed);
151
+ /* v8 ignore start -- v8 coverage tooling intermittently fails to register the NaN→undefined branch even when tests demonstrably exercise it (see "garbage123" / "not-a-date-at-all-12345xyz67890" tests in migrate-to-desk.test.ts). The behavior is correct; the coverage signal is the noise. @preserve */
152
+ if (!Number.isFinite(ms))
153
+ return undefined;
154
+ /* v8 ignore stop */
155
+ return ms;
156
+ }
157
+ /**
158
+ * Extract date prefix from a filename like `2026-05-12-1122-doing-foo.md`.
159
+ * Returns epoch ms or undefined.
160
+ */
161
+ function extractDatePrefixFromFilename(relPath) {
162
+ /* v8 ignore start -- defensive `?? relPath` fallback: String.split() always returns at least one element, so pop() never returns undefined on a non-empty input. The fallback exists only as a type guard for the strict no-implicit-any setting. @preserve */
163
+ const base = relPath.split("/").pop() ?? relPath;
164
+ /* v8 ignore stop */
165
+ const match = /^(\d{4})-(\d{2})-(\d{2})(?:-(\d{2})(\d{2}))?/.exec(base);
166
+ if (!match)
167
+ return undefined;
168
+ const ms = Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]), match[4] ? Number(match[4]) : 0, match[5] ? Number(match[5]) : 0);
169
+ /* v8 ignore start -- Date.UTC normalizes out-of-range numeric inputs to finite ms; the regex already guarantees four+two+two-digit ints. The undefined branch is genuinely unreachable. @preserve */
170
+ return Number.isFinite(ms) ? ms : undefined;
171
+ /* v8 ignore stop */
172
+ }
173
+ /**
174
+ * Extract `**Updated**: YYYY-MM-DD` from body prose (some legacy task formats
175
+ * use this convention instead of YAML frontmatter).
176
+ */
177
+ function extractUpdatedFromBody(content) {
178
+ const match = /\*\*Updated\*\*:\s*([0-9]{4}-[0-9]{2}-[0-9]{2}[A-Za-z0-9:_\- .]*)/.exec(content);
179
+ if (!match)
180
+ return undefined;
181
+ return parseDateString(match[1]);
182
+ }
183
+ /**
184
+ * Resolve the effective `updated` timestamp using the priority chain.
185
+ * Priority: YAML `updated` → `approved` → `created` → body `**Updated**:` →
186
+ * date prefix in filename → file mtime.
187
+ */
188
+ function resolveUpdatedMs(input) {
189
+ const fmBlock = extractFrontmatterBlock(input.content);
190
+ if (fmBlock) {
191
+ const fm = (0, frontmatter_1.parseFrontmatter)(fmBlock);
192
+ const updated = readDateFromFrontmatter(fm, "updated") ?? readDateFromFrontmatter(fm, "Updated");
193
+ if (updated !== undefined)
194
+ return updated;
195
+ const approved = readDateFromFrontmatter(fm, "approved") ?? readDateFromFrontmatter(fm, "Approved");
196
+ if (approved !== undefined)
197
+ return approved;
198
+ const created = readDateFromFrontmatter(fm, "created") ?? readDateFromFrontmatter(fm, "Created");
199
+ if (created !== undefined)
200
+ return created;
201
+ }
202
+ const bodyUpdated = extractUpdatedFromBody(input.content);
203
+ if (bodyUpdated !== undefined)
204
+ return bodyUpdated;
205
+ const filenameDate = extractDatePrefixFromFilename(input.relPath);
206
+ if (filenameDate !== undefined)
207
+ return filenameDate;
208
+ return input.mtimeMs;
209
+ }
210
+ /**
211
+ * Classify a status string into a coarse category. `terminal` overrides
212
+ * everything. `live` is the explicit live set. `unknown` is anything else.
213
+ */
214
+ function classifyStatus(status) {
215
+ if (!status)
216
+ return "missing";
217
+ const normalized = status.trim().toLowerCase();
218
+ // Some statuses are free-text sentences (e.g. "core line approved, companion proof line in discussion").
219
+ // Match terminal keywords if they appear as the leading word.
220
+ const head = normalized.split(/[\s,;:]+/)[0];
221
+ if (TERMINAL_STATUSES.has(head) || TERMINAL_STATUSES.has(normalized))
222
+ return "terminal";
223
+ if (LIVE_STATUSES.has(head) || LIVE_STATUSES.has(normalized))
224
+ return "live";
225
+ return "unknown";
226
+ }
227
+ // ── Public classifier ──
228
+ /**
229
+ * Classify a single file. Pairing/grouping is handled by the migrator at a
230
+ * higher level — this function is purely per-file.
231
+ */
232
+ function classifyFile(input) {
233
+ // Europe-trip override comes first.
234
+ if (isEuropeTripTask(input.relPath)) {
235
+ return {
236
+ bucket: "special_europe_trip",
237
+ updatedMs: resolveUpdatedMs(input),
238
+ status: undefined,
239
+ reason: "operator-flagged europe-trip task",
240
+ };
241
+ }
242
+ // Backup files and `archive/` subdir are unconditionally archived.
243
+ if (isBackupFile(input.relPath)) {
244
+ return {
245
+ bucket: "ambiguous",
246
+ updatedMs: resolveUpdatedMs(input),
247
+ status: undefined,
248
+ reason: "backup or swap file",
249
+ };
250
+ }
251
+ if (isInArchiveSubdir(input.relPath)) {
252
+ return {
253
+ bucket: "terminal",
254
+ updatedMs: resolveUpdatedMs(input),
255
+ status: undefined,
256
+ reason: "under archive/ subdir",
257
+ };
258
+ }
259
+ // Empty file → ambiguous.
260
+ if (input.content.trim().length === 0) {
261
+ return {
262
+ bucket: "ambiguous",
263
+ updatedMs: input.mtimeMs,
264
+ status: undefined,
265
+ reason: "empty file",
266
+ };
267
+ }
268
+ // Non-markdown files inherit from their parent task dir (handled at the
269
+ // migrator level via the pairing rule). Classifier defaults to ambiguous
270
+ // for non-md singletons.
271
+ if (!isMarkdownFile(input.relPath)) {
272
+ return {
273
+ bucket: "ambiguous",
274
+ updatedMs: resolveUpdatedMs(input),
275
+ status: undefined,
276
+ reason: "non-markdown file (will inherit from parent if grouped)",
277
+ };
278
+ }
279
+ const fmBlock = extractFrontmatterBlock(input.content);
280
+ const fm = fmBlock ? (0, frontmatter_1.parseFrontmatter)(fmBlock) : {};
281
+ const status = readStatusFromFrontmatter(fm);
282
+ const category = classifyStatus(status);
283
+ const updatedMs = resolveUpdatedMs(input);
284
+ if (category === "terminal") {
285
+ return {
286
+ bucket: "terminal",
287
+ updatedMs,
288
+ status,
289
+ reason: `terminal status: ${status}`,
290
+ };
291
+ }
292
+ if (category === "missing" || category === "unknown") {
293
+ return {
294
+ bucket: "ambiguous",
295
+ updatedMs,
296
+ status,
297
+ reason: status ? `unknown status: ${status}` : "no status",
298
+ };
299
+ }
300
+ // category === "live"
301
+ if (updatedMs < input.cutoffMs) {
302
+ return {
303
+ bucket: "stale_live",
304
+ updatedMs,
305
+ status,
306
+ reason: `live status (${status}) but updated >30d ago`,
307
+ };
308
+ }
309
+ return {
310
+ bucket: "live_clear",
311
+ updatedMs,
312
+ status,
313
+ reason: `live status (${status}) within 30d`,
314
+ };
315
+ }
316
+ // ── Pairing rules ──
317
+ /**
318
+ * Derive a task slug from a filename. Strips the `YYYY-MM-DD-HHMM-` (or
319
+ * `YYYY-MM-DD-`) prefix and the `planning-` / `doing-` / `ideation-` /
320
+ * `audit-` / `audit-report-` / `audit-backlog-` infix. Returns the remaining
321
+ * stem (without `.md`).
322
+ *
323
+ * Examples:
324
+ * `2026-05-10-doing-foo.md` → `foo`
325
+ * `2026-05-12-1122-doing-rest-loop-incident.md` → `rest-loop-incident`
326
+ * `2026-05-12-1122-planning-rest-loop-incident.md` → `rest-loop-incident`
327
+ * `one-shots/2026-04-29-0942-planning-substrate-trip-control-deploy.md`
328
+ * → `substrate-trip-control-deploy`
329
+ */
330
+ function deriveTaskSlug(relPath) {
331
+ /* v8 ignore start -- defensive `?? relPath` fallback: String.split() always returns at least one element, so pop() never returns undefined. The fallback exists as a type guard. @preserve */
332
+ const base = relPath.split("/").pop() ?? relPath;
333
+ /* v8 ignore stop */
334
+ const stem = base.replace(/\.md$/, "");
335
+ // Strip YYYY-MM-DD[-HHMM]- prefix
336
+ let remainder = stem.replace(/^\d{4}-\d{2}-\d{2}(?:-\d{4})?-/, "");
337
+ // Strip role infix: planning, doing, ideation, audit, audit-report, audit-backlog
338
+ remainder = remainder.replace(/^(planning|doing|ideation|audit-report|audit-backlog|audit)-/, "");
339
+ return remainder;
340
+ }
341
+ /**
342
+ * Extract the parent task directory for a sub-artifact path. Returns
343
+ * undefined for top-level files.
344
+ *
345
+ * Examples:
346
+ * `one-shots/2026-05-10-doing-foo/baseline.md` → `one-shots/2026-05-10-doing-foo`
347
+ * `one-shots/2026-05-10-doing-foo.md` → undefined
348
+ */
349
+ function extractParentTaskDir(relPath) {
350
+ const segments = relPath.split("/");
351
+ if (segments.length < 2)
352
+ return undefined;
353
+ // Walk segments — if any intermediate segment looks like a task-dir name
354
+ // (matches the `YYYY-MM-DD[-HHMM]-(planning|doing|ideation|audit*)-` pattern),
355
+ // return everything up to and including it. Otherwise no parent.
356
+ for (let i = segments.length - 2; i >= 0; i -= 1) {
357
+ if (/^\d{4}-\d{2}-\d{2}(?:-\d{4})?-(planning|doing|ideation|audit-report|audit-backlog|audit)-/.test(segments[i])) {
358
+ return segments.slice(0, i + 1).join("/");
359
+ }
360
+ }
361
+ return undefined;
362
+ }