@ouro.bot/cli 0.1.0-alpha.83 → 0.1.0-alpha.831

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 (647) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5308 -16
  16. package/deploy/unraid/Dockerfile +54 -0
  17. package/deploy/unraid/README.txt +2983 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  34. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  35. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2084 -0
  36. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  37. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  38. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  39. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  40. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  41. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  42. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +795 -0
  43. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  45. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  46. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +15 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +15 -0
  49. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  50. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +135 -0
  51. package/deploy/unraid/sanctuary.xml +28 -0
  52. package/dist/a2a/card.js +57 -0
  53. package/dist/a2a/client.js +180 -0
  54. package/dist/a2a/config.js +50 -0
  55. package/dist/a2a/delegation-stores.js +56 -0
  56. package/dist/a2a/did-resolution.js +93 -0
  57. package/dist/a2a/identity.js +170 -0
  58. package/dist/a2a/inbound-share.js +107 -0
  59. package/dist/a2a/mission-result-wire.js +196 -0
  60. package/dist/a2a/onboarding.js +115 -0
  61. package/dist/a2a/pin-store.js +132 -0
  62. package/dist/a2a/seen-ledger.js +120 -0
  63. package/dist/a2a/server.js +604 -0
  64. package/dist/a2a/task-store.js +69 -0
  65. package/dist/a2a/transport.js +45 -0
  66. package/dist/a2a/types.js +3 -0
  67. package/dist/arc/attention-types.js +8 -0
  68. package/dist/arc/cares.js +360 -0
  69. package/dist/arc/episodes.js +118 -0
  70. package/dist/arc/evolution.js +490 -0
  71. package/dist/arc/flight-recorder.js +1034 -0
  72. package/dist/arc/intentions.js +134 -0
  73. package/dist/arc/json-store.js +117 -0
  74. package/dist/arc/obligations.js +386 -0
  75. package/dist/arc/packets.js +336 -0
  76. package/dist/arc/presence.js +185 -0
  77. package/dist/arc/task-lifecycle.js +57 -0
  78. package/dist/commerce/store.js +755 -0
  79. package/dist/commerce/types.js +3 -0
  80. package/dist/heart/active-work.js +798 -40
  81. package/dist/heart/agent-entry.js +252 -3
  82. package/dist/heart/approval-files.js +113 -0
  83. package/dist/heart/approval-store.js +960 -0
  84. package/dist/heart/attachments/image-normalize.js +194 -0
  85. package/dist/heart/attachments/materialize.js +97 -0
  86. package/dist/heart/attachments/originals.js +88 -0
  87. package/dist/heart/attachments/render.js +29 -0
  88. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  89. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  90. package/dist/heart/attachments/sources/index.js +18 -0
  91. package/dist/heart/attachments/sources/telegram.js +71 -0
  92. package/dist/heart/attachments/store.js +132 -0
  93. package/dist/heart/attachments/types.js +93 -0
  94. package/dist/heart/auth/auth-flow.js +495 -0
  95. package/dist/heart/autonomy-budget.js +478 -0
  96. package/dist/heart/awaiting/await-alert.js +148 -0
  97. package/dist/heart/awaiting/await-expiry.js +143 -0
  98. package/dist/heart/awaiting/await-loader.js +91 -0
  99. package/dist/heart/awaiting/await-parser.js +149 -0
  100. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  101. package/dist/heart/awaiting/await-scheduler.js +382 -0
  102. package/dist/heart/background-operations.js +281 -0
  103. package/dist/heart/bridges/manager.js +137 -17
  104. package/dist/heart/bridges/store.js +14 -2
  105. package/dist/heart/bundle-state.js +168 -0
  106. package/dist/heart/commitments.js +44 -18
  107. package/dist/heart/config-registry.js +331 -0
  108. package/dist/heart/config.js +174 -131
  109. package/dist/heart/context-loss-gauntlet.js +387 -0
  110. package/dist/heart/context-loss-sentinel.js +1157 -0
  111. package/dist/heart/core.js +2169 -581
  112. package/dist/heart/cross-chat-delivery.js +9 -22
  113. package/dist/heart/daemon/agent-config-check.js +451 -0
  114. package/dist/heart/daemon/agent-discovery.js +185 -3
  115. package/dist/heart/daemon/agent-service.js +542 -0
  116. package/dist/heart/daemon/agentic-repair.js +547 -0
  117. package/dist/heart/daemon/await-private-wake.js +59 -0
  118. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  119. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  120. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  121. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  122. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  123. package/dist/heart/daemon/cadence.js +180 -0
  124. package/dist/heart/daemon/cli-defaults.js +854 -0
  125. package/dist/heart/daemon/cli-desk.js +322 -0
  126. package/dist/heart/daemon/cli-exec.js +8822 -0
  127. package/dist/heart/daemon/cli-help.js +716 -0
  128. package/dist/heart/daemon/cli-parse.js +2771 -0
  129. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  130. package/dist/heart/daemon/cli-render.js +777 -0
  131. package/dist/heart/daemon/cli-types.js +8 -0
  132. package/dist/heart/daemon/connect-bay.js +323 -0
  133. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  134. package/dist/heart/daemon/container-healthcheck.js +112 -0
  135. package/dist/heart/daemon/container-runtime.js +97 -0
  136. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  137. package/dist/heart/daemon/container-spec-auditor.js +229 -0
  138. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  139. package/dist/heart/daemon/daemon-cli.js +29 -2349
  140. package/dist/heart/daemon/daemon-entry.js +930 -11
  141. package/dist/heart/daemon/daemon-health.js +186 -0
  142. package/dist/heart/daemon/daemon-rollup.js +57 -0
  143. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  144. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  145. package/dist/heart/daemon/daemon.js +2084 -105
  146. package/dist/heart/daemon/dns-workflow.js +394 -0
  147. package/dist/heart/daemon/doctor-types.js +8 -0
  148. package/dist/heart/daemon/doctor.js +1755 -0
  149. package/dist/heart/daemon/freshness.js +345 -0
  150. package/dist/heart/daemon/habit-private-wake.js +61 -0
  151. package/dist/heart/daemon/health-monitor.js +142 -11
  152. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  153. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  154. package/dist/heart/daemon/http-health-probe.js +80 -0
  155. package/dist/heart/daemon/human-command-screens.js +234 -0
  156. package/dist/heart/daemon/human-readiness.js +114 -0
  157. package/dist/heart/daemon/inner-status.js +78 -0
  158. package/dist/heart/daemon/interactive-repair.js +394 -0
  159. package/dist/heart/daemon/launchd.js +37 -8
  160. package/dist/heart/daemon/log-tailer.js +79 -10
  161. package/dist/heart/daemon/logs-prune.js +132 -0
  162. package/dist/heart/daemon/mcp-canary.js +524 -0
  163. package/dist/heart/daemon/message-router.js +65 -5
  164. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  165. package/dist/heart/daemon/os-cron-deps.js +135 -0
  166. package/dist/heart/daemon/os-cron.js +22 -14
  167. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  168. package/dist/heart/daemon/ouro-entry.js +3 -1
  169. package/dist/heart/daemon/plugin-cli.js +432 -0
  170. package/dist/heart/daemon/process-manager.js +733 -61
  171. package/dist/heart/daemon/provider-discovery.js +137 -0
  172. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  173. package/dist/heart/daemon/prunable-bundle.js +144 -0
  174. package/dist/heart/daemon/pulse.js +511 -0
  175. package/dist/heart/daemon/readiness-repair.js +365 -0
  176. package/dist/heart/daemon/run-hooks.js +2 -0
  177. package/dist/heart/daemon/runtime-logging.js +47 -14
  178. package/dist/heart/daemon/runtime-metadata.js +2 -30
  179. package/dist/heart/daemon/runtime-mode.js +13 -2
  180. package/dist/heart/daemon/safe-mode.js +161 -0
  181. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  182. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  183. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  184. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  185. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  186. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  187. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  188. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  189. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +819 -0
  190. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  191. package/dist/heart/daemon/sanctuary-bundle-migration.js +729 -0
  192. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  193. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  194. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  195. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  196. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  197. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  198. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  199. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  200. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  201. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  202. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  203. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +630 -0
  204. package/dist/heart/daemon/sense-manager.js +699 -48
  205. package/dist/heart/daemon/session-id-resolver.js +131 -0
  206. package/dist/heart/daemon/skill-management-installer.js +1 -1
  207. package/dist/heart/daemon/socket-client.js +180 -12
  208. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  209. package/dist/heart/daemon/startup-tui.js +339 -0
  210. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  211. package/dist/heart/daemon/task-scheduler.js +117 -39
  212. package/dist/heart/daemon/terminal-ui.js +499 -0
  213. package/dist/heart/daemon/thoughts.js +138 -54
  214. package/dist/heart/daemon/up-progress.js +366 -0
  215. package/dist/heart/daemon/vault-items.js +56 -0
  216. package/dist/heart/delegation.js +1 -4
  217. package/dist/heart/external-events/router.js +1430 -0
  218. package/dist/heart/frontend-approval-runtime.js +506 -0
  219. package/dist/heart/frontend-journal.js +215 -0
  220. package/dist/heart/frontend-session-service.js +237 -0
  221. package/dist/heart/frontend-socket-client.js +164 -0
  222. package/dist/heart/frontend-socket.js +400 -0
  223. package/dist/heart/habits/habit-cancel.js +810 -0
  224. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  225. package/dist/heart/habits/habit-migration.js +194 -0
  226. package/dist/heart/habits/habit-parser.js +278 -0
  227. package/dist/heart/habits/habit-runtime-state.js +93 -0
  228. package/dist/heart/habits/habit-scheduler.js +653 -0
  229. package/dist/heart/habits/habit-session-summary.js +318 -0
  230. package/dist/heart/habits/habit-session.js +636 -0
  231. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  232. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  233. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  234. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  235. package/dist/heart/identity.js +196 -59
  236. package/dist/heart/kept-notes.js +289 -0
  237. package/dist/heart/kicks.js +1 -1
  238. package/dist/heart/machine-identity.js +161 -0
  239. package/dist/heart/mail-import-discovery.js +356 -0
  240. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  241. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  242. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  243. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  244. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  245. package/dist/heart/mailbox/mailbox-http.js +99 -0
  246. package/dist/heart/mailbox/mailbox-read.js +39 -0
  247. package/dist/heart/mailbox/mailbox-types.js +27 -0
  248. package/dist/heart/mailbox/mailbox-view.js +197 -0
  249. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  250. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  251. package/dist/heart/mailbox/readers/mail.js +375 -0
  252. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  253. package/dist/heart/mailbox/readers/sessions.js +231 -0
  254. package/dist/heart/mailbox/readers/shared.js +111 -0
  255. package/dist/heart/mcp/mcp-server.js +696 -0
  256. package/dist/heart/migrate-config.js +100 -0
  257. package/dist/heart/model-capabilities.js +11 -0
  258. package/dist/heart/orientation-frame.js +345 -0
  259. package/dist/heart/platform.js +81 -0
  260. package/dist/heart/primitives.js +1 -1
  261. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  262. package/dist/heart/private-runtime/index.js +18 -0
  263. package/dist/heart/private-runtime/ledger.js +221 -0
  264. package/dist/heart/private-runtime/policy.js +252 -0
  265. package/dist/heart/private-runtime/types.js +2 -0
  266. package/dist/heart/progress-story.js +1 -1
  267. package/dist/heart/provider-attempt.js +137 -0
  268. package/dist/heart/provider-binding-resolver.js +273 -0
  269. package/dist/heart/provider-credentials.js +449 -0
  270. package/dist/heart/provider-failover.js +311 -0
  271. package/dist/heart/provider-models.js +96 -0
  272. package/dist/heart/provider-ping.js +265 -0
  273. package/dist/heart/provider-readiness-cache.js +119 -0
  274. package/dist/heart/provider-visibility.js +188 -0
  275. package/dist/heart/providers/anthropic-token.js +131 -0
  276. package/dist/heart/providers/anthropic.js +173 -60
  277. package/dist/heart/providers/azure.js +23 -11
  278. package/dist/heart/providers/error-classification.js +127 -0
  279. package/dist/heart/providers/github-copilot.js +34 -38
  280. package/dist/heart/providers/minimax-vlm.js +189 -0
  281. package/dist/heart/providers/minimax.js +26 -8
  282. package/dist/heart/providers/openai-codex-token.js +349 -0
  283. package/dist/heart/providers/openai-codex.js +55 -40
  284. package/dist/heart/providers/openai-compatible.js +177 -0
  285. package/dist/heart/run-ledger.js +247 -0
  286. package/dist/heart/runtime-capability-check.js +170 -0
  287. package/dist/heart/runtime-credentials.js +607 -0
  288. package/dist/heart/runtime-cwd.js +87 -0
  289. package/dist/heart/sense-truth.js +22 -4
  290. package/dist/heart/session-activity.js +92 -24
  291. package/dist/heart/session-events.js +1504 -0
  292. package/dist/heart/session-playback-cli-main.js +5 -0
  293. package/dist/heart/session-playback-cli.js +36 -0
  294. package/dist/heart/session-playback.js +231 -0
  295. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  296. package/dist/heart/session-redaction-repair.js +552 -0
  297. package/dist/heart/session-stats-cli-main.js +5 -0
  298. package/dist/heart/session-stats.js +183 -0
  299. package/dist/heart/session-transcript.js +133 -0
  300. package/dist/heart/start-of-turn-packet.js +372 -0
  301. package/dist/heart/steward-policy.js +618 -0
  302. package/dist/heart/streaming.js +604 -207
  303. package/dist/heart/structured-output.js +196 -0
  304. package/dist/heart/sync-classification.js +176 -0
  305. package/dist/heart/sync.js +449 -0
  306. package/dist/heart/target-resolution.js +11 -7
  307. package/dist/heart/tempo.js +93 -0
  308. package/dist/heart/temporal-view.js +41 -0
  309. package/dist/heart/timeouts.js +101 -0
  310. package/dist/heart/tool-activity-callbacks.js +59 -0
  311. package/dist/heart/tool-approval.js +382 -0
  312. package/dist/heart/tool-description.js +155 -0
  313. package/dist/heart/tool-friction.js +55 -0
  314. package/dist/heart/tool-loop.js +200 -0
  315. package/dist/heart/turn-context.js +482 -0
  316. package/dist/heart/turn-execution-lease.js +30 -0
  317. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  318. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  319. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  320. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  321. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  322. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  323. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  324. package/dist/heart/versioning/update-hooks.js +154 -0
  325. package/dist/heart/versioning/version-intent.js +114 -0
  326. package/dist/heart/work-card.js +380 -0
  327. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  328. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  329. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  330. package/dist/mailbox-ui/index.html +16 -0
  331. package/dist/mailroom/attention.js +167 -0
  332. package/dist/mailroom/autonomy.js +209 -0
  333. package/dist/mailroom/blob-store.js +889 -0
  334. package/dist/mailroom/body-cache.js +61 -0
  335. package/dist/mailroom/cache-sync-cli.js +58 -0
  336. package/dist/mailroom/core.js +803 -0
  337. package/dist/mailroom/entry.js +160 -0
  338. package/dist/mailroom/file-store.js +568 -0
  339. package/dist/mailroom/hosted-cache-sync.js +384 -0
  340. package/dist/mailroom/mbox-import.js +393 -0
  341. package/dist/mailroom/migration.js +164 -0
  342. package/dist/mailroom/outbound.js +380 -0
  343. package/dist/mailroom/policy.js +263 -0
  344. package/dist/mailroom/reader.js +292 -0
  345. package/dist/mailroom/search-cache.js +513 -0
  346. package/dist/mailroom/search-relevance.js +319 -0
  347. package/dist/mailroom/smtp-ingress.js +176 -0
  348. package/dist/mailroom/source-state.js +176 -0
  349. package/dist/mailroom/thread.js +109 -0
  350. package/dist/mailroom/travel-extract.js +89 -0
  351. package/dist/mind/bundle-manifest.js +24 -2
  352. package/dist/mind/context.js +309 -111
  353. package/dist/mind/desk-section.js +362 -0
  354. package/dist/mind/diary-integrity.js +60 -0
  355. package/dist/mind/{memory.js → diary.js} +68 -77
  356. package/dist/mind/embedding-provider.js +60 -0
  357. package/dist/mind/file-state.js +179 -0
  358. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  359. package/dist/mind/obligation-steering.js +199 -3
  360. package/dist/mind/pending.js +36 -10
  361. package/dist/mind/prompt-budget.js +479 -0
  362. package/dist/mind/prompt-refresh.js +3 -2
  363. package/dist/mind/prompt.js +1050 -189
  364. package/dist/mind/provenance-trust.js +26 -0
  365. package/dist/mind/record-paths.js +312 -0
  366. package/dist/mind/scrutiny.js +173 -0
  367. package/dist/mind/session-transaction.js +564 -0
  368. package/dist/nerves/cli-logging.js +7 -1
  369. package/dist/nerves/coverage/audit-rules.js +15 -6
  370. package/dist/nerves/coverage/audit.js +28 -2
  371. package/dist/nerves/coverage/cli.js +1 -1
  372. package/dist/nerves/coverage/contract.js +5 -5
  373. package/dist/nerves/coverage/file-completeness.js +139 -5
  374. package/dist/nerves/coverage/run-artifacts.js +55 -35
  375. package/dist/nerves/coverage/source-scanner.js +4 -4
  376. package/dist/nerves/event-buffer.js +111 -0
  377. package/dist/nerves/index.js +293 -9
  378. package/dist/nerves/observation.js +20 -0
  379. package/dist/nerves/redact.js +79 -0
  380. package/dist/nerves/review/cli-main.js +5 -0
  381. package/dist/nerves/review/cli.js +156 -0
  382. package/dist/nerves/review/core.js +159 -0
  383. package/dist/nerves/runtime.js +17 -1
  384. package/dist/repertoire/ado-client.js +15 -56
  385. package/dist/repertoire/ado-semantic.js +16 -10
  386. package/dist/repertoire/api-client.js +97 -0
  387. package/dist/repertoire/bitwarden-store.js +1045 -0
  388. package/dist/repertoire/bundle-templates.js +71 -0
  389. package/dist/repertoire/bw-installer.js +180 -0
  390. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  391. package/dist/repertoire/coding/context-pack.js +331 -0
  392. package/dist/repertoire/coding/feedback.js +174 -32
  393. package/dist/repertoire/coding/index.js +15 -3
  394. package/dist/repertoire/coding/manager.js +159 -10
  395. package/dist/repertoire/coding/spawner.js +58 -11
  396. package/dist/repertoire/coding/tools.js +221 -15
  397. package/dist/repertoire/coding/workbench-client.js +272 -0
  398. package/dist/repertoire/coding/workbench-manager.js +346 -0
  399. package/dist/repertoire/commerce-errors.js +109 -0
  400. package/dist/repertoire/commerce-self-test.js +156 -0
  401. package/dist/repertoire/credential-access.js +178 -0
  402. package/dist/repertoire/desk/classifier.js +362 -0
  403. package/dist/repertoire/duffel-client.js +185 -0
  404. package/dist/repertoire/github-client.js +14 -55
  405. package/dist/repertoire/graph-client.js +11 -52
  406. package/dist/repertoire/guardrails.js +811 -18
  407. package/dist/repertoire/mcp-client.js +44 -3
  408. package/dist/repertoire/mcp-manager.js +427 -139
  409. package/dist/repertoire/mcp-tools.js +124 -0
  410. package/dist/repertoire/plugin-mcp.js +175 -0
  411. package/dist/repertoire/plugins.js +253 -0
  412. package/dist/repertoire/relationship-authorization.js +322 -0
  413. package/dist/repertoire/shell-sessions.js +134 -0
  414. package/dist/repertoire/skills.js +48 -4
  415. package/dist/repertoire/stripe-client.js +131 -0
  416. package/dist/repertoire/tool-arguments.js +170 -0
  417. package/dist/repertoire/tool-results.js +29 -0
  418. package/dist/repertoire/tools-a2a.js +699 -0
  419. package/dist/repertoire/tools-attachments.js +322 -0
  420. package/dist/repertoire/tools-awaiting.js +575 -0
  421. package/dist/repertoire/tools-base.js +77 -1138
  422. package/dist/repertoire/tools-bluebubbles.js +2 -0
  423. package/dist/repertoire/tools-bridge.js +144 -0
  424. package/dist/repertoire/tools-bundle.js +993 -0
  425. package/dist/repertoire/tools-commerce.js +253 -0
  426. package/dist/repertoire/tools-config.js +186 -0
  427. package/dist/repertoire/tools-continuity.js +575 -0
  428. package/dist/repertoire/tools-credential.js +383 -0
  429. package/dist/repertoire/tools-evolution.js +527 -0
  430. package/dist/repertoire/tools-files.js +344 -0
  431. package/dist/repertoire/tools-flight.js +290 -0
  432. package/dist/repertoire/tools-flow.js +119 -0
  433. package/dist/repertoire/tools-github.js +3 -8
  434. package/dist/repertoire/tools-habits.js +103 -0
  435. package/dist/repertoire/tools-mail.js +1828 -0
  436. package/dist/repertoire/tools-notes.js +485 -0
  437. package/dist/repertoire/tools-obligations.js +182 -0
  438. package/dist/repertoire/tools-orientation.js +31 -0
  439. package/dist/repertoire/tools-record.js +482 -0
  440. package/dist/repertoire/tools-rsvp.js +139 -0
  441. package/dist/repertoire/tools-runtime.js +150 -0
  442. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  443. package/dist/repertoire/tools-session.js +1133 -0
  444. package/dist/repertoire/tools-shell.js +149 -0
  445. package/dist/repertoire/tools-steward-policy.js +119 -0
  446. package/dist/repertoire/tools-stripe.js +224 -0
  447. package/dist/repertoire/tools-surface.js +369 -0
  448. package/dist/repertoire/tools-teams.js +12 -39
  449. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  450. package/dist/repertoire/tools-travel.js +125 -0
  451. package/dist/repertoire/tools-trip.js +982 -0
  452. package/dist/repertoire/tools-unraid.js +531 -0
  453. package/dist/repertoire/tools-user-profile.js +146 -0
  454. package/dist/repertoire/tools-vault.js +40 -0
  455. package/dist/repertoire/tools-voice.js +145 -0
  456. package/dist/repertoire/tools.js +494 -148
  457. package/dist/repertoire/travel-api-client.js +360 -0
  458. package/dist/repertoire/unraid-client.js +155 -0
  459. package/dist/repertoire/unraid-restart.js +339 -0
  460. package/dist/repertoire/user-profile.js +131 -0
  461. package/dist/repertoire/vault-setup.js +246 -0
  462. package/dist/repertoire/vault-unlock.js +628 -0
  463. package/dist/rsvp/aisleplanner-client.js +354 -0
  464. package/dist/rsvp/cli.js +926 -0
  465. package/dist/rsvp/config.js +327 -0
  466. package/dist/rsvp/cutover.js +433 -0
  467. package/dist/rsvp/diagnostics.js +232 -0
  468. package/dist/rsvp/diff-renderer.js +176 -0
  469. package/dist/rsvp/habit-policy.js +110 -0
  470. package/dist/rsvp/habit-stage.js +123 -0
  471. package/dist/rsvp/incident-bundle.js +97 -0
  472. package/dist/rsvp/migration.js +204 -0
  473. package/dist/rsvp/native-habit-runner.js +630 -0
  474. package/dist/rsvp/outbound-state.js +628 -0
  475. package/dist/rsvp/query.js +118 -0
  476. package/dist/rsvp/replay.js +233 -0
  477. package/dist/rsvp/snapshot.js +232 -0
  478. package/dist/rsvp/spend-ledger.js +175 -0
  479. package/dist/scripts/claude-code-hook.js +41 -0
  480. package/dist/scripts/claude-code-stop-hook.js +47 -0
  481. package/dist/senses/a2a-entry.js +115 -0
  482. package/dist/senses/acp-server.js +386 -0
  483. package/dist/senses/attention-queue.js +186 -0
  484. package/dist/senses/await-turn-message.js +58 -0
  485. package/dist/senses/bluebubbles/active-turns.js +216 -0
  486. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  487. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  488. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  489. package/dist/senses/bluebubbles/context-packet.js +207 -0
  490. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  491. package/dist/senses/bluebubbles/entry.js +90 -0
  492. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  493. package/dist/senses/bluebubbles/index.js +3841 -0
  494. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  495. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  496. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  497. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  498. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  499. package/dist/senses/bluebubbles/processed-log.js +133 -0
  500. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  501. package/dist/senses/bluebubbles/replay.js +284 -0
  502. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  503. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  504. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  505. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  506. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  507. package/dist/senses/cli/bracketed-paste.js +82 -0
  508. package/dist/senses/cli/image-paste.js +287 -0
  509. package/dist/senses/cli/image-ref-navigation.js +75 -0
  510. package/dist/senses/cli/ink-app.js +156 -0
  511. package/dist/senses/cli/inline-diff.js +64 -0
  512. package/dist/senses/cli/input-keys.js +174 -0
  513. package/dist/senses/cli/kill-ring.js +86 -0
  514. package/dist/senses/cli/message-list.js +51 -0
  515. package/dist/senses/cli/ouro-tui.js +607 -0
  516. package/dist/senses/cli/spinner-imperative.js +135 -0
  517. package/dist/senses/cli/spinner.js +101 -0
  518. package/dist/senses/cli/status-line.js +60 -0
  519. package/dist/senses/cli/streaming-markdown.js +526 -0
  520. package/dist/senses/cli/tool-display.js +85 -0
  521. package/dist/senses/cli/tool-render.js +85 -0
  522. package/dist/senses/cli/tui-store.js +241 -0
  523. package/dist/senses/cli/virtual-list.js +35 -0
  524. package/dist/senses/cli-entry.js +60 -8
  525. package/dist/senses/cli.js +604 -320
  526. package/dist/senses/commands.js +66 -3
  527. package/dist/senses/context-packet-ledger.js +371 -0
  528. package/dist/senses/context-packets.js +154 -0
  529. package/dist/senses/habit-lifecycle-guard.js +24 -0
  530. package/dist/senses/habit-turn-message.js +160 -0
  531. package/dist/senses/ingress-evidence.js +2 -0
  532. package/dist/senses/mail-entry.js +66 -0
  533. package/dist/senses/mail.js +524 -0
  534. package/dist/senses/pipeline.js +1115 -204
  535. package/dist/senses/private-runtime-worker.js +859 -0
  536. package/dist/senses/private-runtime.js +1517 -0
  537. package/dist/senses/proactive-content-guard.js +51 -0
  538. package/dist/senses/root-host-approval-port.js +345 -0
  539. package/dist/senses/root-host-approval-runtime.js +393 -0
  540. package/dist/senses/sanctuary-authority-resident.js +102 -0
  541. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  542. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  543. package/dist/senses/sanctuary-grounding.js +118 -0
  544. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  545. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  546. package/dist/senses/sanctuary-health-runner.js +100 -0
  547. package/dist/senses/sanctuary-health.js +408 -0
  548. package/dist/senses/sanctuary-install-state-contract.js +126 -0
  549. package/dist/senses/sanctuary-interactive-control.js +410 -0
  550. package/dist/senses/sanctuary-media-catalog-contract.js +297 -0
  551. package/dist/senses/sanctuary-media-optimization.js +514 -0
  552. package/dist/senses/sanctuary-runtime.js +340 -0
  553. package/dist/senses/sanctuary-sab.js +85 -0
  554. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  555. package/dist/senses/shared-turn.js +772 -0
  556. package/dist/senses/surface-tool.js +109 -0
  557. package/dist/senses/teams-entry.js +60 -8
  558. package/dist/senses/teams.js +519 -218
  559. package/dist/senses/telegram-admission.js +718 -0
  560. package/dist/senses/telegram-approval-runtime.js +793 -0
  561. package/dist/senses/telegram-attachments.js +186 -0
  562. package/dist/senses/telegram-audit-ledger.js +220 -0
  563. package/dist/senses/telegram-authority-transport.js +231 -0
  564. package/dist/senses/telegram-client.js +1749 -0
  565. package/dist/senses/telegram-effect-adapter.js +896 -0
  566. package/dist/senses/telegram-entry.js +83 -0
  567. package/dist/senses/telegram.js +2324 -0
  568. package/dist/senses/trust-gate.js +104 -9
  569. package/dist/senses/voice/audio-playback.js +237 -0
  570. package/dist/senses/voice/audio-routing.js +119 -0
  571. package/dist/senses/voice/elevenlabs.js +202 -0
  572. package/dist/senses/voice/floor-control.js +431 -0
  573. package/dist/senses/voice/floor-controller.js +115 -0
  574. package/dist/senses/voice/golden-path.js +116 -0
  575. package/dist/senses/voice/index.js +29 -0
  576. package/dist/senses/voice/meeting.js +113 -0
  577. package/dist/senses/voice/outbound.js +190 -0
  578. package/dist/senses/voice/phone.js +33 -0
  579. package/dist/senses/voice/playback.js +139 -0
  580. package/dist/senses/voice/realtime-eval.js +496 -0
  581. package/dist/senses/voice/realtime-trace.js +531 -0
  582. package/dist/senses/voice/transcript.js +70 -0
  583. package/dist/senses/voice/turn.js +191 -0
  584. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  585. package/dist/senses/voice/twilio-phone.js +5031 -0
  586. package/dist/senses/voice/types.js +2 -0
  587. package/dist/senses/voice/whisper.js +161 -0
  588. package/dist/senses/voice-entry.js +81 -0
  589. package/dist/senses/voice-realtime-eval-command.js +99 -0
  590. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  591. package/dist/senses/voice-twilio-entry.js +87 -0
  592. package/dist/trips/core.js +138 -0
  593. package/dist/trips/store.js +265 -0
  594. package/dist/util/frontmatter.js +69 -0
  595. package/npm-shrinkwrap.json +8138 -0
  596. package/package.json +72 -13
  597. package/skills/agent-commerce.md +113 -0
  598. package/skills/browser-navigation.md +117 -0
  599. package/skills/commerce-setup-guide.md +116 -0
  600. package/skills/commerce-setup.md +84 -0
  601. package/skills/configure-dev-tools.md +99 -0
  602. package/skills/travel-planning.md +138 -0
  603. package/dist/heart/daemon/auth-flow.js +0 -430
  604. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  605. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  606. package/dist/heart/daemon/update-hooks.js +0 -138
  607. package/dist/heart/obligations.js +0 -191
  608. package/dist/heart/safe-workspace.js +0 -228
  609. package/dist/heart/session-recall.js +0 -116
  610. package/dist/mind/friends/channel.js +0 -84
  611. package/dist/mind/friends/group-context.js +0 -144
  612. package/dist/mind/friends/resolver.js +0 -84
  613. package/dist/mind/friends/store-file.js +0 -190
  614. package/dist/mind/friends/store.js +0 -4
  615. package/dist/mind/friends/tokens.js +0 -26
  616. package/dist/mind/friends/trust-explanation.js +0 -74
  617. package/dist/mind/friends/types.js +0 -29
  618. package/dist/repertoire/tasks/board.js +0 -134
  619. package/dist/repertoire/tasks/index.js +0 -224
  620. package/dist/repertoire/tasks/lifecycle.js +0 -80
  621. package/dist/repertoire/tasks/middleware.js +0 -65
  622. package/dist/repertoire/tasks/parser.js +0 -173
  623. package/dist/repertoire/tasks/scanner.js +0 -132
  624. package/dist/repertoire/tasks/transitions.js +0 -144
  625. package/dist/senses/bluebubbles-entry.js +0 -13
  626. package/dist/senses/bluebubbles.js +0 -1181
  627. package/dist/senses/debug-activity.js +0 -154
  628. package/dist/senses/inner-dialog-worker.js +0 -90
  629. package/dist/senses/inner-dialog.js +0 -525
  630. package/subagents/README.md +0 -7
  631. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  632. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  633. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  634. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  635. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  636. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  637. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  638. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  639. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  640. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  641. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  642. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  643. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  644. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  645. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  646. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  647. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,1327 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.HabitLifecycleError = exports.HABIT_LIFECYCLE_TIMEOUT_MS = exports.HABIT_LIFECYCLE_POLL_MS = void 0;
40
+ exports.serializeHabitLifecycleJson = serializeHabitLifecycleJson;
41
+ exports.getHabitLifecyclePaths = getHabitLifecyclePaths;
42
+ exports.buildHabitEvidenceIdentity = buildHabitEvidenceIdentity;
43
+ exports.buildHabitCancellationOperation = buildHabitCancellationOperation;
44
+ exports.buildHabitSendOperation = buildHabitSendOperation;
45
+ exports.buildHabitLifecycleOwner = buildHabitLifecycleOwner;
46
+ exports.probeHabitBootIdentity = probeHabitBootIdentity;
47
+ exports.probeHabitProcessStartedAt = probeHabitProcessStartedAt;
48
+ exports.probeHabitProcessLiveness = probeHabitProcessLiveness;
49
+ exports.classifyHabitLifecycleOwner = classifyHabitLifecycleOwner;
50
+ exports.acquireHabitLifecycleLock = acquireHabitLifecycleLock;
51
+ exports.releaseHabitLifecycleLock = releaseHabitLifecycleLock;
52
+ exports.habitLifecycleLeaseIsCurrent = habitLifecycleLeaseIsCurrent;
53
+ exports.confirmHabitLifecyclePathDurability = confirmHabitLifecyclePathDurability;
54
+ exports.createHabitLifecycleJournal = createHabitLifecycleJournal;
55
+ exports.transitionHabitLifecycleJournal = transitionHabitLifecycleJournal;
56
+ exports.writeHabitLifecycleJournal = writeHabitLifecycleJournal;
57
+ exports.readHabitLifecycleJournal = readHabitLifecycleJournal;
58
+ exports.listHabitLifecycleJournals = listHabitLifecycleJournals;
59
+ exports.writeHabitLifecycleDefinition = writeHabitLifecycleDefinition;
60
+ exports.publishNewHabitDefinition = publishNewHabitDefinition;
61
+ exports.publishHabitLifecycleReceipt = publishHabitLifecycleReceipt;
62
+ exports.readHabitLifecycleReceipt = readHabitLifecycleReceipt;
63
+ exports.renderHabitCancellationAcknowledgement = renderHabitCancellationAcknowledgement;
64
+ const node_crypto_1 = require("node:crypto");
65
+ const node_child_process_1 = require("node:child_process");
66
+ const fs = __importStar(require("node:fs"));
67
+ const os = __importStar(require("node:os"));
68
+ const path = __importStar(require("node:path"));
69
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
70
+ const runtime_1 = require("../../nerves/runtime");
71
+ exports.HABIT_LIFECYCLE_POLL_MS = 50;
72
+ exports.HABIT_LIFECYCLE_TIMEOUT_MS = 5_000;
73
+ const HASH_PATTERN = /^[a-f0-9]{64}$/;
74
+ const UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
75
+ const TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
76
+ const OWNER_KEYS = [
77
+ "schemaVersion",
78
+ "operationId",
79
+ "pid",
80
+ "bootIdentity",
81
+ "processStartedAt",
82
+ "acquiredAt",
83
+ ];
84
+ const JOURNAL_KEYS = [
85
+ "schemaVersion",
86
+ "habitId",
87
+ "operationId",
88
+ "operationKind",
89
+ "state",
90
+ "updatedAt",
91
+ "generation",
92
+ "evidenceKeyHash",
93
+ "cancellationPreparation",
94
+ "intentAt",
95
+ "transportInvokedAt",
96
+ "classifiedAt",
97
+ "boundaryState",
98
+ "transportResult",
99
+ ];
100
+ const RECEIPT_KEYS = [
101
+ "schemaVersion",
102
+ "habitId",
103
+ "operationId",
104
+ "evidenceKeyHash",
105
+ "evidenceLocator",
106
+ "actor",
107
+ "request",
108
+ "transition",
109
+ "acknowledgement",
110
+ "createdAt",
111
+ ];
112
+ class HabitLifecycleError extends Error {
113
+ code;
114
+ durabilityUnknown;
115
+ constructor(code, options = {}) {
116
+ super(code);
117
+ if (options.cause !== undefined) {
118
+ Object.defineProperty(this, "cause", {
119
+ value: options.cause,
120
+ configurable: true,
121
+ writable: true,
122
+ });
123
+ }
124
+ this.name = "HabitLifecycleError";
125
+ this.code = code;
126
+ this.durabilityUnknown = options.durabilityUnknown ?? false;
127
+ }
128
+ }
129
+ exports.HabitLifecycleError = HabitLifecycleError;
130
+ function serializeHabitLifecycleJson(value) {
131
+ return `${JSON.stringify(value, null, 2)}\n`;
132
+ }
133
+ function getHabitLifecyclePaths(input) {
134
+ const agentRoot = requiredString(input.agentRoot, "agent_root_required");
135
+ const habitId = validatedHabitId(input.habitId);
136
+ if (input.operationId !== undefined)
137
+ validatedOperationId(input.operationId);
138
+ if (input.evidenceKeyHash !== undefined)
139
+ validatedHash(input.evidenceKeyHash, "evidence_key_hash_invalid");
140
+ const root = path.join(agentRoot, "state", "habits", "lifecycle", sha256(habitId));
141
+ const journalDirectory = path.join(root, "journal");
142
+ const receiptsDirectory = path.join(root, "receipts");
143
+ return {
144
+ root,
145
+ coordination: path.join(root, "coordination.sqlite"),
146
+ owner: path.join(root, "owner.lock"),
147
+ journalDirectory,
148
+ ...(input.operationId === undefined
149
+ ? {}
150
+ : { journal: path.join(journalDirectory, `${sha256(input.operationId)}.json`) }),
151
+ receiptsDirectory,
152
+ ...(input.evidenceKeyHash === undefined
153
+ ? {}
154
+ : { receipt: path.join(receiptsDirectory, `${input.evidenceKeyHash}.json`) }),
155
+ };
156
+ }
157
+ function buildHabitEvidenceIdentity(input) {
158
+ const habitId = validatedHabitId(input.habitId);
159
+ if (input.kind !== "bridge" && input.kind !== "capture") {
160
+ throw new HabitLifecycleError("evidence_kind_invalid");
161
+ }
162
+ const id = requiredString(input.id, "evidence_id_required");
163
+ if (input.kind === "capture")
164
+ validatedHash(id, "evidence_id_invalid");
165
+ if (/[/\\\0\r\n]/.test(id))
166
+ throw new HabitLifecycleError("evidence_id_invalid");
167
+ const canonicalKey = JSON.stringify(["habit-evidence-v1", habitId, input.kind, id]);
168
+ return { canonicalKey, evidenceKeyHash: sha256(canonicalKey) };
169
+ }
170
+ function buildHabitCancellationOperation(evidenceKeyHash) {
171
+ const hash = validatedHash(evidenceKeyHash, "evidence_key_hash_invalid");
172
+ const operationId = `cancel:${hash}`;
173
+ return { operationId, operationIdHash: sha256(operationId) };
174
+ }
175
+ function buildHabitSendOperation(input) {
176
+ const habitId = validatedHabitId(input.habitId);
177
+ const outboundIdempotencyKey = requiredString(input.outboundIdempotencyKey, "outbound_idempotency_key_required");
178
+ const canonicalKey = JSON.stringify(["habit-send-v1", habitId, outboundIdempotencyKey]);
179
+ const operationHash = sha256(canonicalKey);
180
+ return { canonicalKey, operationHash, operationId: `send:${operationHash}` };
181
+ }
182
+ function buildHabitLifecycleOwner(input) {
183
+ return {
184
+ schemaVersion: 1,
185
+ operationId: validatedOperationId(input.operationId),
186
+ pid: validatedPid(input.pid),
187
+ bootIdentity: requiredString(input.bootIdentity, "boot_identity_invalid"),
188
+ processStartedAt: requiredString(input.processStartedAt, "process_started_at_invalid"),
189
+ acquiredAt: validatedTimestamp(input.acquiredAt, "acquired_at_invalid"),
190
+ };
191
+ }
192
+ function probeHabitBootIdentity(deps = {}) {
193
+ if (deps.bootIdentity)
194
+ return requiredString(deps.bootIdentity(), "boot_identity_invalid");
195
+ const platform = deps.platform ?? process.platform;
196
+ const storeFs = deps.fs ?? fs;
197
+ const run = deps.execFileSync ?? node_child_process_1.execFileSync;
198
+ if (platform === "linux") {
199
+ return requiredString(storeFs.readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim(), "boot_identity_invalid");
200
+ }
201
+ if (platform === "darwin" || platform === "freebsd") {
202
+ const output = run("/usr/sbin/sysctl", ["-n", "kern.boottime"], { encoding: "utf8" });
203
+ return sha256(String(output));
204
+ }
205
+ if (platform === "win32") {
206
+ const output = run("powershell.exe", [
207
+ "-NoProfile",
208
+ "-Command",
209
+ "(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToUniversalTime().Ticks",
210
+ ], { encoding: "utf8" });
211
+ return sha256(String(output));
212
+ }
213
+ const uptime = deps.uptime ?? os.uptime;
214
+ const now = lifecycleNow(deps).getTime();
215
+ return sha256(`${platform}:${Math.round((now - (uptime() * 1_000)) / 1_000)}`);
216
+ }
217
+ function probeHabitProcessStartedAt(pid, deps = {}) {
218
+ const validPid = validatedPid(pid);
219
+ if (deps.processStartedAt)
220
+ return deps.processStartedAt(validPid);
221
+ const platform = deps.platform ?? process.platform;
222
+ const storeFs = deps.fs ?? fs;
223
+ const run = deps.execFileSync ?? node_child_process_1.execFileSync;
224
+ if (platform === "linux") {
225
+ try {
226
+ const stat = storeFs.readFileSync(`/proc/${validPid}/stat`, "utf8");
227
+ const closeParen = stat.lastIndexOf(")");
228
+ if (closeParen < 0)
229
+ return null;
230
+ const fields = stat.slice(closeParen + 2).trim().split(/\s+/);
231
+ return fields[19] ? `linux:${fields[19]}` : null;
232
+ }
233
+ catch (error) {
234
+ if (isNodeError(error, "ENOENT") || isNodeError(error, "ESRCH"))
235
+ return null;
236
+ throw error;
237
+ }
238
+ }
239
+ if (platform === "win32") {
240
+ try {
241
+ const output = run("powershell.exe", ["-NoProfile", "-Command", `(Get-Process -Id ${validPid}).StartTime.ToUniversalTime().Ticks`], { encoding: "utf8" }).trim();
242
+ return output ? `win32:${output}` : null;
243
+ }
244
+ catch {
245
+ return null;
246
+ }
247
+ }
248
+ try {
249
+ const output = run("/bin/ps", ["-o", "lstart=", "-p", String(validPid)], {
250
+ encoding: "utf8",
251
+ }).trim();
252
+ return output ? `${platform}:${output}` : null;
253
+ }
254
+ catch {
255
+ return null;
256
+ }
257
+ }
258
+ function probeHabitProcessLiveness(pid, deps = {}) {
259
+ const validPid = validatedPid(pid);
260
+ if (deps.processLiveness)
261
+ return deps.processLiveness(validPid);
262
+ const kill = deps.kill ?? process.kill;
263
+ try {
264
+ kill(validPid, 0);
265
+ return "alive";
266
+ }
267
+ catch (error) {
268
+ if (isNodeError(error, "ESRCH"))
269
+ return "missing";
270
+ return "unknown";
271
+ }
272
+ }
273
+ function classifyHabitLifecycleOwner(owner, deps = {}) {
274
+ return classifyOwner(owner, deps).status;
275
+ }
276
+ async function acquireHabitLifecycleLock(input, deps = {}) {
277
+ const paths = getHabitLifecyclePaths(input);
278
+ const habitId = validatedHabitId(input.habitId);
279
+ const operationId = validatedOperationId(input.operationId);
280
+ (0, runtime_1.emitNervesEvent)({
281
+ component: "daemon",
282
+ event: "daemon.habit_lifecycle_lock_start",
283
+ message: "habit lifecycle lock acquisition started",
284
+ meta: { habitId, operationId },
285
+ });
286
+ let candidate;
287
+ try {
288
+ const pid = lifecyclePid(deps);
289
+ const processStartedAt = probeHabitProcessStartedAt(pid, deps);
290
+ if (processStartedAt === null || processStartedAt.length === 0) {
291
+ throw new HabitLifecycleError("process_started_at_invalid");
292
+ }
293
+ candidate = buildHabitLifecycleOwner({
294
+ operationId,
295
+ pid,
296
+ bootIdentity: probeHabitBootIdentity(deps),
297
+ processStartedAt,
298
+ acquiredAt: lifecycleNow(deps).toISOString(),
299
+ });
300
+ }
301
+ catch (error) {
302
+ const wrapped = asLifecycleError(error, "lifecycle_lock_failed");
303
+ emitLockError(habitId, operationId, wrapped.code, "unknown", true);
304
+ throw wrapped;
305
+ }
306
+ const startedAt = lifecycleNow(deps).getTime();
307
+ let lastOwnerStatus = "unknown";
308
+ let lastProbeError = false;
309
+ while (true) {
310
+ let coordinated;
311
+ try {
312
+ coordinated = withCoordination(paths, 0, () => acquireUnderCoordination(paths, input.agentRoot, habitId, operationId, candidate, deps));
313
+ }
314
+ catch (error) {
315
+ const wrapped = asLifecycleError(error, "lifecycle_lock_failed");
316
+ emitLockError(habitId, operationId, wrapped.code, lastOwnerStatus, lastProbeError);
317
+ throw wrapped;
318
+ }
319
+ if (coordinated.status === "completed") {
320
+ const attempt = coordinated.value;
321
+ if (attempt.status === "acquired") {
322
+ (0, runtime_1.emitNervesEvent)({
323
+ component: "daemon",
324
+ event: "daemon.habit_lifecycle_lock_end",
325
+ message: "habit lifecycle lock acquired",
326
+ meta: {
327
+ habitId,
328
+ operationId,
329
+ recoveredOwner: attempt.recoveredOwner,
330
+ recoveredOwnerStatus: attempt.recoveredOwner ? "recoverable" : null,
331
+ },
332
+ });
333
+ return { status: "acquired", lease: attempt.lease };
334
+ }
335
+ lastOwnerStatus = attempt.ownerStatus;
336
+ lastProbeError = attempt.probeError;
337
+ }
338
+ if (lifecycleNow(deps).getTime() - startedAt >= exports.HABIT_LIFECYCLE_TIMEOUT_MS) {
339
+ emitLockError(habitId, operationId, "lifecycle_lock_timeout", lastOwnerStatus, lastProbeError);
340
+ return { status: "timeout", error: "lifecycle_lock_timeout" };
341
+ }
342
+ await lifecycleSleep(exports.HABIT_LIFECYCLE_POLL_MS, deps);
343
+ }
344
+ }
345
+ function releaseHabitLifecycleLock(lease, deps = {}) {
346
+ const paths = getHabitLifecyclePaths({ agentRoot: lease.agentRoot, habitId: lease.habitId });
347
+ const attempt = withCoordination(paths, 0, () => {
348
+ const snapshot = inspectOwner(paths.owner, deps.fs ?? fs);
349
+ if (!snapshotMatchesLease(snapshot, lease))
350
+ return false;
351
+ const storeFs = deps.fs ?? fs;
352
+ storeFs.unlinkSync(paths.owner);
353
+ fsyncDirectory(paths.root, storeFs);
354
+ return true;
355
+ });
356
+ if (attempt.status === "busy")
357
+ return false;
358
+ return attempt.value;
359
+ }
360
+ function habitLifecycleLeaseIsCurrent(lease, deps = {}) {
361
+ return snapshotMatchesLease(inspectOwner(lease.ownerPath, deps.fs ?? fs, true), lease);
362
+ }
363
+ function confirmHabitLifecyclePathDurability(lease, filePath, deps = {}) {
364
+ const storeFs = deps.fs ?? fs;
365
+ let descriptor = null;
366
+ try {
367
+ assertLease(lease, storeFs);
368
+ const resolvedPath = path.resolve(requiredString(filePath, "definition_path_invalid"));
369
+ const resolvedRoot = path.resolve(lease.agentRoot);
370
+ if (!resolvedPath.startsWith(`${resolvedRoot}${path.sep}`)) {
371
+ throw new HabitLifecycleError("definition_path_invalid");
372
+ }
373
+ descriptor = storeFs.openSync(resolvedPath, "r");
374
+ storeFs.fsyncSync(descriptor);
375
+ storeFs.closeSync(descriptor);
376
+ descriptor = null;
377
+ fsyncDirectory(path.dirname(resolvedPath), storeFs);
378
+ }
379
+ catch (error) {
380
+ if (descriptor !== null)
381
+ bestEffortClose(descriptor, storeFs);
382
+ const wrapped = error instanceof HabitLifecycleError && error.code === "lifecycle_lease_lost"
383
+ ? error
384
+ : new HabitLifecycleError("lifecycle_durability_unknown", {
385
+ durabilityUnknown: true,
386
+ cause: error,
387
+ });
388
+ emitWriteError(lease, wrapped);
389
+ throw wrapped;
390
+ }
391
+ }
392
+ function createHabitLifecycleJournal(input) {
393
+ const habitId = validatedHabitId(input.habitId);
394
+ const operationId = validatedOperationId(input.operationId);
395
+ if (input.operationKind !== "cancel" && input.operationKind !== "send") {
396
+ throw new HabitLifecycleError("lifecycle_operation_kind_invalid");
397
+ }
398
+ if (!operationId.startsWith(`${input.operationKind}:`)) {
399
+ throw new HabitLifecycleError("lifecycle_operation_kind_invalid");
400
+ }
401
+ return {
402
+ schemaVersion: 1,
403
+ habitId,
404
+ operationId,
405
+ operationKind: input.operationKind,
406
+ state: "lock_acquired",
407
+ updatedAt: validatedTimestamp(input.updatedAt, "lifecycle_timestamp_invalid"),
408
+ generation: 0,
409
+ evidenceKeyHash: null,
410
+ cancellationPreparation: null,
411
+ intentAt: null,
412
+ transportInvokedAt: null,
413
+ classifiedAt: null,
414
+ boundaryState: null,
415
+ transportResult: null,
416
+ };
417
+ }
418
+ function transitionHabitLifecycleJournal(current, transition) {
419
+ if (!isValidJournal(current))
420
+ throw new HabitLifecycleError("lifecycle_journal_invalid");
421
+ const edge = `${current.operationKind}:${current.state}->${transition.state}`;
422
+ const permitted = new Set([
423
+ "cancel:lock_acquired->cancellation_intent",
424
+ "cancel:cancellation_intent->definition_cancelled",
425
+ "cancel:definition_cancelled->cancellation_receipt_committed",
426
+ "send:lock_acquired->send_intent",
427
+ "send:send_intent->not_crossed",
428
+ "send:send_intent->crossing_unknown",
429
+ "send:send_intent->crossed",
430
+ ]);
431
+ if (!permitted.has(edge))
432
+ throw new HabitLifecycleError("lifecycle_transition_invalid");
433
+ const at = validatedTimestamp(transition.at, "lifecycle_timestamp_invalid");
434
+ const next = {
435
+ schemaVersion: 1,
436
+ habitId: current.habitId,
437
+ operationId: current.operationId,
438
+ operationKind: current.operationKind,
439
+ state: transition.state,
440
+ updatedAt: at,
441
+ generation: current.generation + 1,
442
+ evidenceKeyHash: current.evidenceKeyHash,
443
+ cancellationPreparation: current.cancellationPreparation,
444
+ intentAt: current.intentAt,
445
+ transportInvokedAt: current.transportInvokedAt,
446
+ classifiedAt: current.classifiedAt,
447
+ boundaryState: current.boundaryState,
448
+ transportResult: current.transportResult,
449
+ };
450
+ if (transition.state === "cancellation_intent") {
451
+ next.evidenceKeyHash = validatedHash(transition.evidenceKeyHash, "evidence_key_hash_invalid");
452
+ next.cancellationPreparation = validatedCancellationPreparation(transition.cancellationPreparation, current.habitId, current.operationId, next.evidenceKeyHash);
453
+ next.intentAt = at;
454
+ }
455
+ else if (transition.state === "definition_cancelled") {
456
+ next.classifiedAt = at;
457
+ next.boundaryState = validatedBoundaryState(transition.boundaryState);
458
+ if (next.boundaryState !== current.cancellationPreparation?.receipt.transition.boundaryState) {
459
+ throw new HabitLifecycleError("lifecycle_transition_invalid");
460
+ }
461
+ }
462
+ else if (transition.state === "send_intent") {
463
+ next.intentAt = at;
464
+ }
465
+ else if (transition.state === "not_crossed"
466
+ || transition.state === "crossing_unknown"
467
+ || transition.state === "crossed") {
468
+ next.transportInvokedAt = transition.transportInvokedAt === null
469
+ ? null
470
+ : validatedTimestamp(transition.transportInvokedAt, "lifecycle_timestamp_invalid");
471
+ next.classifiedAt = at;
472
+ next.boundaryState = transition.state;
473
+ next.transportResult = validatedTransportResult(transition.transportResult);
474
+ }
475
+ if (!isValidJournal(next))
476
+ throw new HabitLifecycleError("lifecycle_transition_invalid");
477
+ return next;
478
+ }
479
+ function writeHabitLifecycleJournal(lease, journal, deps = {}) {
480
+ try {
481
+ if (!isValidJournal(journal)
482
+ || journal.habitId !== lease.habitId
483
+ || journal.operationId !== lease.operationId)
484
+ throw new HabitLifecycleError("lifecycle_journal_invalid");
485
+ const paths = getHabitLifecyclePaths({
486
+ agentRoot: lease.agentRoot,
487
+ habitId: lease.habitId,
488
+ operationId: lease.operationId,
489
+ });
490
+ writeMutableLifecycleFile(lease, paths.journal, serializeHabitLifecycleJson(journal), deps);
491
+ }
492
+ catch (error) {
493
+ emitWriteError(lease, error);
494
+ throw error;
495
+ }
496
+ }
497
+ function readHabitLifecycleJournal(input, deps = {}) {
498
+ const paths = getHabitLifecyclePaths(input);
499
+ const storeFs = deps.fs ?? fs;
500
+ let bytes;
501
+ try {
502
+ bytes = storeFs.readFileSync(paths.journal, "utf8");
503
+ }
504
+ catch (error) {
505
+ if (isNodeError(error, "ENOENT"))
506
+ return null;
507
+ throw new HabitLifecycleError("lifecycle_journal_read_failed", { cause: error });
508
+ }
509
+ const value = parseJson(bytes, "lifecycle_journal_invalid");
510
+ if (!isValidJournal(value)
511
+ || value.habitId !== input.habitId
512
+ || value.operationId !== input.operationId
513
+ || serializeHabitLifecycleJson(value) !== bytes)
514
+ throw new HabitLifecycleError("lifecycle_journal_invalid");
515
+ return value;
516
+ }
517
+ function listHabitLifecycleJournals(input, deps = {}) {
518
+ const paths = getHabitLifecyclePaths(input);
519
+ const storeFs = deps.fs ?? fs;
520
+ let names;
521
+ try {
522
+ names = storeFs.readdirSync(paths.journalDirectory);
523
+ }
524
+ catch (error) {
525
+ if (isNodeError(error, "ENOENT"))
526
+ return [];
527
+ throw new HabitLifecycleError("lifecycle_journal_read_failed", { cause: error });
528
+ }
529
+ const journals = [];
530
+ for (const name of names.filter((entry) => HASH_PATTERN.test(entry.slice(0, -5)) && entry.endsWith(".json")).sort()) {
531
+ const journalPath = path.join(paths.journalDirectory, name);
532
+ let bytes;
533
+ try {
534
+ bytes = storeFs.readFileSync(journalPath, "utf8");
535
+ }
536
+ catch (error) {
537
+ throw new HabitLifecycleError("lifecycle_journal_read_failed", { cause: error });
538
+ }
539
+ const value = parseJson(bytes, "lifecycle_journal_invalid");
540
+ if (!isValidJournal(value)
541
+ || value.habitId !== input.habitId
542
+ || sha256(value.operationId) !== name.slice(0, -5)
543
+ || serializeHabitLifecycleJson(value) !== bytes)
544
+ throw new HabitLifecycleError("lifecycle_journal_invalid");
545
+ journals.push(value);
546
+ }
547
+ return journals;
548
+ }
549
+ function writeHabitLifecycleDefinition(lease, definitionPath, bytes, deps = {}) {
550
+ try {
551
+ const resolvedDefinition = path.resolve(requiredString(definitionPath, "definition_path_invalid"));
552
+ const resolvedRoot = path.resolve(lease.agentRoot);
553
+ if (!resolvedDefinition.startsWith(`${resolvedRoot}${path.sep}`)) {
554
+ throw new HabitLifecycleError("definition_path_invalid");
555
+ }
556
+ if (typeof bytes !== "string")
557
+ throw new HabitLifecycleError("definition_bytes_invalid");
558
+ writeMutableLifecycleFile(lease, resolvedDefinition, bytes, deps);
559
+ }
560
+ catch (error) {
561
+ emitWriteError(lease, error);
562
+ throw error;
563
+ }
564
+ }
565
+ /** Publish a new habit definition without ever replacing an existing path.
566
+ * This is the creation-side counterpart to lease-owned definition mutation:
567
+ * concurrent creators race at link(2), while cancellation remains the sole
568
+ * cooperative writer allowed to replace an existing definition. */
569
+ function publishNewHabitDefinition(input, deps = {}) {
570
+ const storeFs = deps.fs ?? fs;
571
+ const agentRoot = path.resolve(requiredString(input.agentRoot, "agent_root_required"));
572
+ const habitId = validatedHabitId(input.habitId);
573
+ if (typeof input.bytes !== "string")
574
+ throw new HabitLifecycleError("definition_bytes_invalid");
575
+ const definitionPath = path.join(agentRoot, "habits", `${habitId}.md`);
576
+ const directoryPath = path.dirname(definitionPath);
577
+ storeFs.mkdirSync(directoryPath, { recursive: true });
578
+ const tempPath = lifecycleTempPath(definitionPath, deps);
579
+ let tempFd = null;
580
+ let tempOwned = false;
581
+ let published = false;
582
+ try {
583
+ tempFd = storeFs.openSync(tempPath, "wx", 0o600);
584
+ tempOwned = true;
585
+ storeFs.writeFileSync(tempFd, input.bytes, "utf8");
586
+ storeFs.fsyncSync(tempFd);
587
+ storeFs.closeSync(tempFd);
588
+ tempFd = null;
589
+ try {
590
+ storeFs.linkSync(tempPath, definitionPath);
591
+ published = true;
592
+ }
593
+ catch (error) {
594
+ if (!isNodeError(error, "EEXIST"))
595
+ throw error;
596
+ }
597
+ if (published)
598
+ fsyncDirectory(directoryPath, storeFs);
599
+ }
600
+ catch (error) {
601
+ if (tempFd !== null)
602
+ bestEffortClose(tempFd, storeFs);
603
+ if (tempOwned)
604
+ bestEffortUnlink(tempPath, storeFs);
605
+ throw new HabitLifecycleError(published ? "lifecycle_durability_unknown" : "lifecycle_write_failed", { durabilityUnknown: published, cause: error });
606
+ }
607
+ bestEffortUnlink(tempPath, storeFs);
608
+ return published ? "published" : "exists";
609
+ }
610
+ function publishHabitLifecycleReceipt(lease, evidenceKeyHash, receipt, deps = {}) {
611
+ try {
612
+ assertLease(lease, deps.fs ?? fs);
613
+ const hash = validatedHash(evidenceKeyHash, "evidence_key_hash_invalid");
614
+ if (!isValidCancellationReceipt(receipt)
615
+ || receipt.habitId !== lease.habitId
616
+ || receipt.operationId !== lease.operationId
617
+ || receipt.evidenceKeyHash !== hash)
618
+ throw new HabitLifecycleError("lifecycle_receipt_invalid");
619
+ const paths = getHabitLifecyclePaths({
620
+ agentRoot: lease.agentRoot,
621
+ habitId: lease.habitId,
622
+ evidenceKeyHash: hash,
623
+ });
624
+ const bytes = serializeHabitLifecycleJson(receipt);
625
+ const publication = publishImmutableLifecycleFile(lease, paths.receipt, bytes, deps);
626
+ if (publication === "published")
627
+ return "published";
628
+ const existing = readHabitLifecycleReceipt({
629
+ agentRoot: lease.agentRoot,
630
+ habitId: lease.habitId,
631
+ evidenceKeyHash: hash,
632
+ }, deps);
633
+ if (existing !== null && serializeHabitLifecycleJson(existing) === bytes)
634
+ return "duplicate";
635
+ throw new HabitLifecycleError("lifecycle_receipt_collision");
636
+ }
637
+ catch (error) {
638
+ emitWriteError(lease, error);
639
+ throw error;
640
+ }
641
+ }
642
+ function readHabitLifecycleReceipt(input, deps = {}) {
643
+ const paths = getHabitLifecyclePaths(input);
644
+ const storeFs = deps.fs ?? fs;
645
+ let bytes;
646
+ try {
647
+ bytes = storeFs.readFileSync(paths.receipt, "utf8");
648
+ }
649
+ catch (error) {
650
+ if (isNodeError(error, "ENOENT"))
651
+ return null;
652
+ throw new HabitLifecycleError("lifecycle_receipt_read_failed", { cause: error });
653
+ }
654
+ const value = parseJson(bytes, "lifecycle_receipt_invalid");
655
+ if (!isValidCancellationReceipt(value)
656
+ || value.habitId !== input.habitId
657
+ || value.evidenceKeyHash !== input.evidenceKeyHash
658
+ || serializeHabitLifecycleJson(value) !== bytes)
659
+ throw new HabitLifecycleError("lifecycle_receipt_invalid");
660
+ return value;
661
+ }
662
+ function acquireUnderCoordination(paths, agentRoot, habitId, operationId, candidate, deps) {
663
+ const storeFs = deps.fs ?? fs;
664
+ const observed = inspectOwner(paths.owner, storeFs);
665
+ if (observed.status === "missing") {
666
+ const identity = publishOwner(paths, candidate, deps);
667
+ return {
668
+ status: "acquired",
669
+ lease: buildLease(agentRoot, habitId, operationId, paths.owner, candidate, identity),
670
+ recoveredOwner: false,
671
+ };
672
+ }
673
+ if (observed.status === "invalid") {
674
+ return { status: "wait", ownerStatus: "unknown", probeError: false };
675
+ }
676
+ const classification = classifyOwner(observed.owner, deps);
677
+ if (classification.status !== "recoverable") {
678
+ return { status: "wait", ownerStatus: classification.status, probeError: classification.probeError };
679
+ }
680
+ deps.beforeOwnerRecovery?.();
681
+ const revalidated = inspectOwner(paths.owner, storeFs);
682
+ if (!sameOwnerSnapshot(observed, revalidated)) {
683
+ if (revalidated.status !== "valid") {
684
+ return { status: "wait", ownerStatus: "unknown", probeError: false };
685
+ }
686
+ const successor = classifyOwner(revalidated.owner, deps);
687
+ return { status: "wait", ownerStatus: successor.status, probeError: successor.probeError };
688
+ }
689
+ storeFs.unlinkSync(paths.owner);
690
+ fsyncDirectory(paths.root, storeFs);
691
+ const identity = publishOwner(paths, candidate, deps);
692
+ return {
693
+ status: "acquired",
694
+ lease: buildLease(agentRoot, habitId, operationId, paths.owner, candidate, identity),
695
+ recoveredOwner: true,
696
+ };
697
+ }
698
+ function buildLease(agentRoot, habitId, operationId, ownerPath, owner, ownerIdentity) {
699
+ return {
700
+ agentRoot,
701
+ habitId,
702
+ operationId,
703
+ ownerPath,
704
+ owner,
705
+ ownerBytes: serializeHabitLifecycleJson(owner),
706
+ ownerIdentity,
707
+ };
708
+ }
709
+ function publishOwner(paths, owner, deps) {
710
+ const storeFs = deps.fs ?? fs;
711
+ storeFs.mkdirSync(paths.root, { recursive: true });
712
+ const tempPath = lifecycleTempPath(paths.owner, deps);
713
+ const bytes = serializeHabitLifecycleJson(owner);
714
+ let tempFd = null;
715
+ let tempOwned = false;
716
+ let published = false;
717
+ let publishedIdentity = null;
718
+ try {
719
+ tempFd = storeFs.openSync(tempPath, "wx", 0o600);
720
+ tempOwned = true;
721
+ storeFs.writeFileSync(tempFd, bytes, "utf8");
722
+ storeFs.fsyncSync(tempFd);
723
+ storeFs.closeSync(tempFd);
724
+ tempFd = null;
725
+ storeFs.linkSync(tempPath, paths.owner);
726
+ published = true;
727
+ publishedIdentity = fileIdentity(storeFs.lstatSync(paths.owner));
728
+ fsyncDirectory(paths.root, storeFs);
729
+ }
730
+ catch (error) {
731
+ if (tempFd !== null)
732
+ bestEffortClose(tempFd, storeFs);
733
+ if (published) {
734
+ try {
735
+ const snapshot = inspectOwner(paths.owner, storeFs);
736
+ if (snapshot.status === "valid"
737
+ && snapshot.bytes === bytes
738
+ && publishedIdentity !== null
739
+ && sameIdentity(snapshot.identity, publishedIdentity)) {
740
+ storeFs.unlinkSync(paths.owner);
741
+ fsyncDirectory(paths.root, storeFs);
742
+ published = false;
743
+ }
744
+ }
745
+ catch {
746
+ throw new HabitLifecycleError("lifecycle_lock_durability_unknown", {
747
+ durabilityUnknown: true,
748
+ cause: error,
749
+ });
750
+ }
751
+ }
752
+ if (tempOwned)
753
+ bestEffortUnlink(tempPath, storeFs);
754
+ throw new HabitLifecycleError(published ? "lifecycle_lock_durability_unknown" : "lifecycle_lock_failed", { durabilityUnknown: published, cause: error });
755
+ }
756
+ bestEffortUnlink(tempPath, storeFs);
757
+ const snapshot = inspectOwner(paths.owner, storeFs);
758
+ if (snapshot.status !== "valid" || snapshot.bytes !== bytes) {
759
+ throw new HabitLifecycleError("lifecycle_lock_durability_unknown", { durabilityUnknown: true });
760
+ }
761
+ return snapshot.identity;
762
+ }
763
+ function writeMutableLifecycleFile(lease, finalPath, bytes, deps) {
764
+ const storeFs = deps.fs ?? fs;
765
+ assertLease(lease, storeFs);
766
+ const directoryPath = path.dirname(finalPath);
767
+ storeFs.mkdirSync(directoryPath, { recursive: true });
768
+ const tempPath = lifecycleTempPath(finalPath, deps);
769
+ let tempFd = null;
770
+ let tempOwned = false;
771
+ let published = false;
772
+ try {
773
+ tempFd = storeFs.openSync(tempPath, "wx", 0o600);
774
+ tempOwned = true;
775
+ storeFs.writeFileSync(tempFd, bytes, "utf8");
776
+ storeFs.fsyncSync(tempFd);
777
+ storeFs.closeSync(tempFd);
778
+ tempFd = null;
779
+ assertLease(lease, storeFs);
780
+ storeFs.renameSync(tempPath, finalPath);
781
+ tempOwned = false;
782
+ published = true;
783
+ fsyncDirectory(directoryPath, storeFs);
784
+ }
785
+ catch (error) {
786
+ if (tempFd !== null)
787
+ bestEffortClose(tempFd, storeFs);
788
+ if (tempOwned)
789
+ bestEffortUnlink(tempPath, storeFs);
790
+ if (error instanceof HabitLifecycleError && error.code === "lifecycle_lease_lost")
791
+ throw error;
792
+ throw new HabitLifecycleError(published ? "lifecycle_durability_unknown" : "lifecycle_write_failed", { durabilityUnknown: published, cause: error });
793
+ }
794
+ }
795
+ function publishImmutableLifecycleFile(lease, finalPath, bytes, deps) {
796
+ const storeFs = deps.fs ?? fs;
797
+ assertLease(lease, storeFs);
798
+ const directoryPath = path.dirname(finalPath);
799
+ storeFs.mkdirSync(directoryPath, { recursive: true });
800
+ const tempPath = lifecycleTempPath(finalPath, deps);
801
+ let tempFd = null;
802
+ let tempOwned = false;
803
+ let published = false;
804
+ let exists = false;
805
+ try {
806
+ tempFd = storeFs.openSync(tempPath, "wx", 0o600);
807
+ tempOwned = true;
808
+ storeFs.writeFileSync(tempFd, bytes, "utf8");
809
+ storeFs.fsyncSync(tempFd);
810
+ storeFs.closeSync(tempFd);
811
+ tempFd = null;
812
+ assertLease(lease, storeFs);
813
+ try {
814
+ storeFs.linkSync(tempPath, finalPath);
815
+ published = true;
816
+ }
817
+ catch (error) {
818
+ if (!isNodeError(error, "EEXIST"))
819
+ throw error;
820
+ exists = true;
821
+ }
822
+ fsyncDirectory(directoryPath, storeFs);
823
+ }
824
+ catch (error) {
825
+ if (tempFd !== null)
826
+ bestEffortClose(tempFd, storeFs);
827
+ if (tempOwned)
828
+ bestEffortUnlink(tempPath, storeFs);
829
+ if (error instanceof HabitLifecycleError && error.code === "lifecycle_lease_lost")
830
+ throw error;
831
+ throw new HabitLifecycleError(published || exists ? "lifecycle_durability_unknown" : "lifecycle_write_failed", { durabilityUnknown: published || exists, cause: error });
832
+ }
833
+ bestEffortUnlink(tempPath, storeFs);
834
+ return published ? "published" : "exists";
835
+ }
836
+ function assertLease(lease, storeFs) {
837
+ const snapshot = inspectOwner(lease.ownerPath, storeFs);
838
+ if (!snapshotMatchesLease(snapshot, lease)) {
839
+ throw new HabitLifecycleError("lifecycle_lease_lost");
840
+ }
841
+ }
842
+ function snapshotMatchesLease(snapshot, lease) {
843
+ return snapshot.status === "valid"
844
+ && snapshot.bytes === lease.ownerBytes
845
+ && sameIdentity(snapshot.identity, lease.ownerIdentity);
846
+ }
847
+ function inspectOwner(ownerPath, storeFs, failOnIo = false) {
848
+ let before;
849
+ try {
850
+ before = storeFs.lstatSync(ownerPath);
851
+ }
852
+ catch (error) {
853
+ if (isNodeError(error, "ENOENT"))
854
+ return { status: "missing" };
855
+ if (failOnIo)
856
+ throw new HabitLifecycleError("lifecycle_owner_inspection_failed", { cause: error });
857
+ return { status: "invalid" };
858
+ }
859
+ if (!before.isFile())
860
+ return { status: "invalid" };
861
+ let bytes;
862
+ let after;
863
+ try {
864
+ bytes = storeFs.readFileSync(ownerPath, "utf8");
865
+ after = storeFs.lstatSync(ownerPath);
866
+ }
867
+ catch (error) {
868
+ if (isNodeError(error, "ENOENT"))
869
+ return { status: "missing" };
870
+ if (failOnIo)
871
+ throw new HabitLifecycleError("lifecycle_owner_inspection_failed", { cause: error });
872
+ return { status: "invalid" };
873
+ }
874
+ const beforeIdentity = fileIdentity(before);
875
+ const afterIdentity = fileIdentity(after);
876
+ if (!after.isFile() || !sameIdentity(beforeIdentity, afterIdentity))
877
+ return { status: "invalid" };
878
+ const parsed = parseOwner(bytes);
879
+ if (parsed === null)
880
+ return { status: "invalid", bytes, identity: afterIdentity };
881
+ return { status: "valid", bytes, identity: afterIdentity, owner: parsed };
882
+ }
883
+ function parseOwner(bytes) {
884
+ let value;
885
+ try {
886
+ value = JSON.parse(bytes);
887
+ }
888
+ catch {
889
+ return null;
890
+ }
891
+ if (!isRecord(value) || !hasExactKeys(value, OWNER_KEYS))
892
+ return null;
893
+ try {
894
+ const owner = buildHabitLifecycleOwner({
895
+ operationId: value.operationId,
896
+ pid: value.pid,
897
+ bootIdentity: value.bootIdentity,
898
+ processStartedAt: value.processStartedAt,
899
+ acquiredAt: value.acquiredAt,
900
+ });
901
+ if (value.schemaVersion !== 1 || serializeHabitLifecycleJson(owner) !== bytes)
902
+ return null;
903
+ return owner;
904
+ }
905
+ catch {
906
+ return null;
907
+ }
908
+ }
909
+ function classifyOwner(owner, deps) {
910
+ try {
911
+ if (probeHabitBootIdentity(deps) !== owner.bootIdentity) {
912
+ return { status: "recoverable", probeError: false };
913
+ }
914
+ const liveness = probeHabitProcessLiveness(owner.pid, deps);
915
+ if (liveness === "missing")
916
+ return { status: "recoverable", probeError: false };
917
+ if (liveness === "unknown")
918
+ return { status: "unknown", probeError: false };
919
+ const processStartedAt = probeHabitProcessStartedAt(owner.pid, deps);
920
+ if (processStartedAt === null || processStartedAt.length === 0) {
921
+ return { status: "unknown", probeError: false };
922
+ }
923
+ return processStartedAt === owner.processStartedAt
924
+ ? { status: "live", probeError: false }
925
+ : { status: "recoverable", probeError: false };
926
+ }
927
+ catch {
928
+ return { status: "unknown", probeError: true };
929
+ }
930
+ }
931
+ function sameOwnerSnapshot(left, right) {
932
+ return left.status === "valid"
933
+ && right.status === "valid"
934
+ && left.bytes === right.bytes
935
+ && sameIdentity(left.identity, right.identity);
936
+ }
937
+ function withCoordination(paths, busyTimeoutMs, operation) {
938
+ fs.mkdirSync(paths.root, { recursive: true });
939
+ let database;
940
+ try {
941
+ database = new better_sqlite3_1.default(paths.coordination);
942
+ database.pragma(`busy_timeout = ${busyTimeoutMs}`);
943
+ }
944
+ catch (error) {
945
+ throw new HabitLifecycleError("lifecycle_coordination_failed", { cause: error });
946
+ }
947
+ let operationStarted = false;
948
+ let operationCompleted = false;
949
+ let completedValue;
950
+ try {
951
+ const transaction = database.transaction(() => {
952
+ operationStarted = true;
953
+ const value = operation();
954
+ completedValue = value;
955
+ operationCompleted = true;
956
+ return value;
957
+ });
958
+ return { status: "completed", value: transaction.immediate() };
959
+ }
960
+ catch (error) {
961
+ if (isSqliteBusy(error)) {
962
+ if (!operationStarted)
963
+ return { status: "busy" };
964
+ if (operationCompleted)
965
+ return { status: "completed", value: completedValue };
966
+ }
967
+ throw error;
968
+ }
969
+ finally {
970
+ database.close();
971
+ }
972
+ }
973
+ function isValidJournal(value) {
974
+ if (!isRecord(value) || !hasExactKeys(value, JOURNAL_KEYS))
975
+ return false;
976
+ if (value.schemaVersion !== 1
977
+ || !isValidHabitId(value.habitId)
978
+ || !isValidOperationId(value.operationId)
979
+ || (value.operationKind !== "cancel" && value.operationKind !== "send")
980
+ || !value.operationId.startsWith(`${value.operationKind}:`)
981
+ || !isJournalState(value.state)
982
+ || !isCanonicalTimestamp(value.updatedAt)
983
+ || !Number.isInteger(value.generation)
984
+ || value.generation < 0
985
+ || (value.evidenceKeyHash !== null && !isHash(value.evidenceKeyHash))
986
+ || (value.cancellationPreparation !== null && !isValidCancellationPreparation(value.cancellationPreparation))
987
+ || !isNullableTimestamp(value.intentAt)
988
+ || !isNullableTimestamp(value.transportInvokedAt)
989
+ || !isNullableTimestamp(value.classifiedAt)
990
+ || (value.boundaryState !== null && !isBoundaryState(value.boundaryState))
991
+ || (value.transportResult !== null && !isValidTransportResult(value.transportResult)))
992
+ return false;
993
+ if (value.state === "lock_acquired") {
994
+ return value.generation === 0
995
+ && value.evidenceKeyHash === null
996
+ && value.cancellationPreparation === null
997
+ && value.intentAt === null
998
+ && value.transportInvokedAt === null
999
+ && value.classifiedAt === null
1000
+ && value.boundaryState === null
1001
+ && value.transportResult === null;
1002
+ }
1003
+ if (value.state === "cancellation_intent") {
1004
+ return value.operationKind === "cancel"
1005
+ && value.generation === 1
1006
+ && value.evidenceKeyHash !== null
1007
+ && cancellationPreparationMatchesJournal(value)
1008
+ && value.intentAt !== null
1009
+ && value.transportInvokedAt === null
1010
+ && value.classifiedAt === null
1011
+ && value.boundaryState === null
1012
+ && value.transportResult === null;
1013
+ }
1014
+ if (value.state === "definition_cancelled" || value.state === "cancellation_receipt_committed") {
1015
+ return value.operationKind === "cancel"
1016
+ && value.generation === (value.state === "definition_cancelled" ? 2 : 3)
1017
+ && value.evidenceKeyHash !== null
1018
+ && cancellationPreparationMatchesJournal(value)
1019
+ && value.boundaryState === value.cancellationPreparation.receipt.transition.boundaryState
1020
+ && value.intentAt !== null
1021
+ && value.transportInvokedAt === null
1022
+ && value.classifiedAt !== null
1023
+ && value.boundaryState !== null
1024
+ && value.transportResult === null;
1025
+ }
1026
+ if (value.state === "send_intent") {
1027
+ return value.operationKind === "send"
1028
+ && value.generation === 1
1029
+ && value.evidenceKeyHash === null
1030
+ && value.cancellationPreparation === null
1031
+ && value.intentAt !== null
1032
+ && value.transportInvokedAt === null
1033
+ && value.classifiedAt === null
1034
+ && value.boundaryState === null
1035
+ && value.transportResult === null;
1036
+ }
1037
+ return value.operationKind === "send"
1038
+ && value.generation === 2
1039
+ && value.evidenceKeyHash === null
1040
+ && value.cancellationPreparation === null
1041
+ && value.intentAt !== null
1042
+ && (value.state === "not_crossed" || value.transportInvokedAt !== null)
1043
+ && value.classifiedAt !== null
1044
+ && value.boundaryState === value.state
1045
+ && value.transportResult !== null;
1046
+ }
1047
+ function isValidCancellationReceipt(value) {
1048
+ if (!isRecord(value) || !hasExactKeys(value, RECEIPT_KEYS))
1049
+ return false;
1050
+ if (value.schemaVersion !== 1
1051
+ || !isValidHabitId(value.habitId)
1052
+ || !isHash(value.evidenceKeyHash)
1053
+ || value.operationId !== `cancel:${value.evidenceKeyHash}`
1054
+ || !isRecord(value.evidenceLocator)
1055
+ || !hasExactKeys(value.evidenceLocator, ["kind", "id"])
1056
+ || (value.evidenceLocator.kind !== "bridge" && value.evidenceLocator.kind !== "capture")
1057
+ || typeof value.evidenceLocator.id !== "string"
1058
+ || !isRecord(value.actor)
1059
+ || !hasExactKeys(value.actor, ["displayName", "provider", "externalId"])
1060
+ || typeof value.actor.displayName !== "string"
1061
+ || value.actor.displayName.trim().length === 0
1062
+ || (value.actor.provider !== null && typeof value.actor.provider !== "string")
1063
+ || (value.actor.externalId !== null && typeof value.actor.externalId !== "string")
1064
+ || !isRecord(value.request)
1065
+ || !hasExactKeys(value.request, ["text", "sha256", "observedAt"])
1066
+ || typeof value.request.text !== "string"
1067
+ || !isHash(value.request.sha256)
1068
+ || value.request.sha256 !== sha256(value.request.text)
1069
+ || !isCanonicalTimestamp(value.request.observedAt)
1070
+ || !isRecord(value.transition)
1071
+ || !hasExactKeys(value.transition, ["fromStatus", "toStatus", "cancelledAt", "boundaryState"])
1072
+ || (value.transition.fromStatus !== "active" && value.transition.fromStatus !== "paused")
1073
+ || value.transition.toStatus !== "cancelled"
1074
+ || !isCanonicalTimestamp(value.transition.cancelledAt)
1075
+ || !isBoundaryState(value.transition.boundaryState)
1076
+ || typeof value.acknowledgement !== "string"
1077
+ || !isCanonicalTimestamp(value.createdAt)
1078
+ || value.transition.cancelledAt !== value.createdAt)
1079
+ return false;
1080
+ try {
1081
+ const identity = buildHabitEvidenceIdentity({
1082
+ habitId: value.habitId,
1083
+ kind: value.evidenceLocator.kind,
1084
+ id: value.evidenceLocator.id,
1085
+ });
1086
+ if (identity.evidenceKeyHash !== value.evidenceKeyHash)
1087
+ return false;
1088
+ }
1089
+ catch {
1090
+ return false;
1091
+ }
1092
+ return value.acknowledgement === renderHabitCancellationAcknowledgement(value.habitId, value.actor.displayName, value.transition.boundaryState);
1093
+ }
1094
+ function renderHabitCancellationAcknowledgement(habitId, actorDisplayName, boundaryState) {
1095
+ if (!isValidHabitId(habitId) || typeof actorDisplayName !== "string" || actorDisplayName.trim().length === 0) {
1096
+ throw new HabitLifecycleError("lifecycle_receipt_invalid");
1097
+ }
1098
+ const prefix = `Cancelled habit ${JSON.stringify(habitId)} from confirmed requester ${JSON.stringify(actorDisplayName)}.`;
1099
+ if (boundaryState === "not_crossed") {
1100
+ return `${prefix} No concurrent send crossed the transport boundary.`;
1101
+ }
1102
+ if (boundaryState === "crossing_unknown") {
1103
+ return `${prefix} A concurrent send may have crossed the transport boundary; delivery is unknown.`;
1104
+ }
1105
+ return `${prefix} A concurrent send crossed the transport boundary before cancellation took effect.`;
1106
+ }
1107
+ function isValidCancellationPreparation(value) {
1108
+ return isRecord(value)
1109
+ && hasExactKeys(value, ["receipt", "definitionBeforeSha256", "definitionCancelledSha256"])
1110
+ && isValidCancellationReceipt(value.receipt)
1111
+ && isHash(value.definitionBeforeSha256)
1112
+ && isHash(value.definitionCancelledSha256);
1113
+ }
1114
+ function cancellationPreparationMatchesJournal(value) {
1115
+ const preparation = value.cancellationPreparation;
1116
+ return isValidCancellationPreparation(preparation)
1117
+ && preparation.receipt.habitId === value.habitId
1118
+ && preparation.receipt.operationId === value.operationId
1119
+ && preparation.receipt.evidenceKeyHash === value.evidenceKeyHash;
1120
+ }
1121
+ function validatedCancellationPreparation(value, habitId, operationId, evidenceKeyHash) {
1122
+ if (!isValidCancellationPreparation(value)) {
1123
+ throw new HabitLifecycleError("cancellation_preparation_invalid");
1124
+ }
1125
+ if (value.receipt.habitId !== habitId
1126
+ || value.receipt.operationId !== operationId
1127
+ || value.receipt.evidenceKeyHash !== evidenceKeyHash)
1128
+ throw new HabitLifecycleError("cancellation_preparation_invalid");
1129
+ return {
1130
+ receipt: value.receipt,
1131
+ definitionBeforeSha256: value.definitionBeforeSha256,
1132
+ definitionCancelledSha256: value.definitionCancelledSha256,
1133
+ };
1134
+ }
1135
+ function validatedTransportResult(value) {
1136
+ if (!isValidTransportResult(value))
1137
+ throw new HabitLifecycleError("transport_result_invalid");
1138
+ return {
1139
+ httpStatus: value.httpStatus,
1140
+ messageGuid: value.messageGuid,
1141
+ errorCode: value.errorCode,
1142
+ };
1143
+ }
1144
+ function isValidTransportResult(value) {
1145
+ return isRecord(value)
1146
+ && hasExactKeys(value, ["httpStatus", "messageGuid", "errorCode"])
1147
+ && (value.httpStatus === null || (Number.isInteger(value.httpStatus) && value.httpStatus >= 100 && value.httpStatus <= 599))
1148
+ && (value.messageGuid === null || typeof value.messageGuid === "string")
1149
+ && (value.errorCode === null || typeof value.errorCode === "string");
1150
+ }
1151
+ function parseJson(bytes, code) {
1152
+ try {
1153
+ return JSON.parse(bytes);
1154
+ }
1155
+ catch (error) {
1156
+ throw new HabitLifecycleError(code, { cause: error });
1157
+ }
1158
+ }
1159
+ function lifecycleTempPath(finalPath, deps) {
1160
+ const uuid = (deps.randomUUID ?? node_crypto_1.randomUUID)();
1161
+ if (!UUID_PATTERN.test(uuid))
1162
+ throw new HabitLifecycleError("lifecycle_uuid_invalid");
1163
+ return `${finalPath}.${uuid}.tmp`;
1164
+ }
1165
+ function lifecyclePid(deps) {
1166
+ return validatedPid((deps.pid ?? (() => process.pid))());
1167
+ }
1168
+ function lifecycleNow(deps) {
1169
+ const now = (deps.now ?? (() => new Date()))();
1170
+ if (!(now instanceof Date) || Number.isNaN(now.getTime())) {
1171
+ throw new HabitLifecycleError("lifecycle_clock_invalid");
1172
+ }
1173
+ return now;
1174
+ }
1175
+ async function lifecycleSleep(milliseconds, deps) {
1176
+ if (deps.sleep) {
1177
+ await deps.sleep(milliseconds);
1178
+ return;
1179
+ }
1180
+ await new Promise((resolve) => setTimeout(resolve, milliseconds));
1181
+ }
1182
+ function fsyncDirectory(directoryPath, storeFs) {
1183
+ const directoryFd = storeFs.openSync(directoryPath, "r");
1184
+ try {
1185
+ storeFs.fsyncSync(directoryFd);
1186
+ }
1187
+ finally {
1188
+ storeFs.closeSync(directoryFd);
1189
+ }
1190
+ }
1191
+ function bestEffortClose(fd, storeFs) {
1192
+ try {
1193
+ storeFs.closeSync(fd);
1194
+ }
1195
+ catch { /* preserve primary failure */ }
1196
+ }
1197
+ function bestEffortUnlink(filePath, storeFs) {
1198
+ try {
1199
+ storeFs.unlinkSync(filePath);
1200
+ }
1201
+ catch (error) {
1202
+ if (isNodeError(error, "ENOENT"))
1203
+ return;
1204
+ try {
1205
+ storeFs.unlinkSync(filePath);
1206
+ }
1207
+ catch { /* recoverable orphan temp */ }
1208
+ }
1209
+ }
1210
+ function fileIdentity(stats) {
1211
+ return { dev: stats.dev, ino: stats.ino };
1212
+ }
1213
+ function sameIdentity(left, right) {
1214
+ return left.dev === right.dev && left.ino === right.ino;
1215
+ }
1216
+ function sha256(value) {
1217
+ return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
1218
+ }
1219
+ function validatedHabitId(value) {
1220
+ if (!isValidHabitId(value))
1221
+ throw new HabitLifecycleError("habit_id_invalid");
1222
+ return value;
1223
+ }
1224
+ function isValidHabitId(value) {
1225
+ return typeof value === "string"
1226
+ && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value)
1227
+ && value !== "."
1228
+ && value !== "..";
1229
+ }
1230
+ function validatedOperationId(value) {
1231
+ if (!isValidOperationId(value))
1232
+ throw new HabitLifecycleError("operation_id_invalid");
1233
+ return value;
1234
+ }
1235
+ function isValidOperationId(value) {
1236
+ return typeof value === "string"
1237
+ && value.trim().length > 0
1238
+ && value === value.trim()
1239
+ && !/[\0\r\n]/.test(value);
1240
+ }
1241
+ function validatedPid(value) {
1242
+ if (!Number.isInteger(value) || value <= 0) {
1243
+ throw new HabitLifecycleError("pid_invalid");
1244
+ }
1245
+ return value;
1246
+ }
1247
+ function validatedHash(value, code) {
1248
+ if (!isHash(value))
1249
+ throw new HabitLifecycleError(code);
1250
+ return value;
1251
+ }
1252
+ function isHash(value) {
1253
+ return typeof value === "string" && HASH_PATTERN.test(value);
1254
+ }
1255
+ function validatedTimestamp(value, code) {
1256
+ if (!isCanonicalTimestamp(value))
1257
+ throw new HabitLifecycleError(code);
1258
+ return value;
1259
+ }
1260
+ function isCanonicalTimestamp(value) {
1261
+ if (typeof value !== "string" || !TIMESTAMP_PATTERN.test(value))
1262
+ return false;
1263
+ const parsed = new Date(value);
1264
+ return !Number.isNaN(parsed.getTime()) && parsed.toISOString() === value;
1265
+ }
1266
+ function isNullableTimestamp(value) {
1267
+ return value === null || isCanonicalTimestamp(value);
1268
+ }
1269
+ function validatedBoundaryState(value) {
1270
+ if (!isBoundaryState(value))
1271
+ throw new HabitLifecycleError("boundary_state_invalid");
1272
+ return value;
1273
+ }
1274
+ function isBoundaryState(value) {
1275
+ return value === "not_crossed" || value === "crossing_unknown" || value === "crossed";
1276
+ }
1277
+ function isJournalState(value) {
1278
+ return value === "lock_acquired"
1279
+ || value === "cancellation_intent"
1280
+ || value === "definition_cancelled"
1281
+ || value === "cancellation_receipt_committed"
1282
+ || value === "send_intent"
1283
+ || isBoundaryState(value);
1284
+ }
1285
+ function requiredString(value, code) {
1286
+ if (typeof value !== "string" || value.trim().length === 0) {
1287
+ throw new HabitLifecycleError(code);
1288
+ }
1289
+ return value;
1290
+ }
1291
+ function isRecord(value) {
1292
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1293
+ }
1294
+ function hasExactKeys(value, keys) {
1295
+ const actual = Object.keys(value);
1296
+ return actual.length === keys.length && actual.every((key, index) => key === keys[index]);
1297
+ }
1298
+ function isNodeError(error, code) {
1299
+ return error instanceof Error && "code" in error && error.code === code;
1300
+ }
1301
+ function isSqliteBusy(error) {
1302
+ return error instanceof Error && "code" in error && error.code === "SQLITE_BUSY";
1303
+ }
1304
+ function asLifecycleError(error, fallbackCode) {
1305
+ return error instanceof HabitLifecycleError
1306
+ ? error
1307
+ : new HabitLifecycleError(fallbackCode, { cause: error });
1308
+ }
1309
+ function emitLockError(habitId, operationId, errorCode, ownerStatus, probeError) {
1310
+ (0, runtime_1.emitNervesEvent)({
1311
+ level: "error",
1312
+ component: "daemon",
1313
+ event: "daemon.habit_lifecycle_lock_error",
1314
+ message: "habit lifecycle lock acquisition failed",
1315
+ meta: { habitId, operationId, errorCode, ownerStatus, probeError },
1316
+ });
1317
+ }
1318
+ function emitWriteError(lease, error) {
1319
+ const errorCode = error instanceof HabitLifecycleError ? error.code : "lifecycle_write_failed";
1320
+ (0, runtime_1.emitNervesEvent)({
1321
+ level: "error",
1322
+ component: "daemon",
1323
+ event: "daemon.habit_lifecycle_write_error",
1324
+ message: "habit lifecycle durable write failed",
1325
+ meta: { habitId: lease.habitId, operationId: lease.operationId, errorCode },
1326
+ });
1327
+ }