@murphai/murph 0.2.11 → 0.2.13

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 (299) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +1 -1
  3. package/config.schema.json +6 -12
  4. package/dist/cli-entry.d.ts.map +1 -1
  5. package/dist/cli-entry.js +3 -25
  6. package/dist/cli-entry.js.map +1 -1
  7. package/dist/commands/automation.d.ts +8 -8
  8. package/dist/commands/inbox.d.ts.map +1 -1
  9. package/dist/commands/inbox.js +0 -7
  10. package/dist/commands/inbox.js.map +1 -1
  11. package/dist/commands/meal.d.ts.map +1 -1
  12. package/dist/commands/meal.js +130 -16
  13. package/dist/commands/meal.js.map +1 -1
  14. package/dist/commands/search.d.ts.map +1 -1
  15. package/dist/commands/search.js +47 -11
  16. package/dist/commands/search.js.map +1 -1
  17. package/dist/incur.generated.d.ts +5 -4
  18. package/dist/incur.generated.d.ts.map +1 -1
  19. package/dist/vault-cli-command-manifest.d.ts +1 -1
  20. package/dist/vault-cli-command-manifest.d.ts.map +1 -1
  21. package/dist/vault-cli-command-manifest.js +1 -1
  22. package/dist/vault-cli-command-manifest.js.map +1 -1
  23. package/node_modules/@murphai/assistant-cli/dist/assistant/service.d.ts +2 -2
  24. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts +0 -1
  25. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts.map +1 -1
  26. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js +0 -1
  27. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js.map +1 -1
  28. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.d.ts.map +1 -1
  29. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js +0 -26
  30. package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js.map +1 -1
  31. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js +1 -1
  32. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js.map +1 -1
  33. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts +4 -0
  34. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts.map +1 -1
  35. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js +28 -2
  36. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js.map +1 -1
  37. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts +4 -0
  38. package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts.map +1 -1
  39. package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js +3 -0
  40. package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js.map +1 -1
  41. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts +64 -12
  42. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts.map +1 -1
  43. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js +193 -34
  44. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js.map +1 -1
  45. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts +11 -1
  46. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts.map +1 -1
  47. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js +2 -7
  48. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js.map +1 -1
  49. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts +4 -6
  50. package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts.map +1 -1
  51. package/node_modules/@murphai/assistant-engine/dist/assistant/cron.d.ts.map +1 -1
  52. package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js +510 -166
  53. package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js.map +1 -1
  54. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.d.ts +4 -1
  55. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.d.ts.map +1 -1
  56. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.js +33 -14
  57. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.js.map +1 -1
  58. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.d.ts +6 -0
  59. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.d.ts.map +1 -0
  60. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.js +26 -0
  61. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.js.map +1 -0
  62. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.d.ts +1 -1
  63. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.d.ts.map +1 -1
  64. package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.js +1 -1
  65. package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.d.ts.map +1 -1
  66. package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.js +53 -46
  67. package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.js.map +1 -1
  68. package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts +9 -0
  69. package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts.map +1 -0
  70. package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js +53 -0
  71. package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js.map +1 -0
  72. package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts +1 -1
  73. package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts.map +1 -1
  74. package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js +69 -15
  75. package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js.map +1 -1
  76. package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js +5 -4
  77. package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js.map +1 -1
  78. package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.d.ts.map +1 -1
  79. package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.js +2 -0
  80. package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.js.map +1 -1
  81. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/catalog.js +3 -3
  82. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/catalog.js.map +1 -1
  83. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts +1 -1
  84. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts.map +1 -1
  85. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js +76 -1
  86. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js.map +1 -1
  87. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.d.ts +1 -1
  88. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.d.ts.map +1 -1
  89. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.js +7 -1
  90. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.js.map +1 -1
  91. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.d.ts.map +1 -1
  92. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.js +3 -1
  93. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.js.map +1 -1
  94. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts +3 -0
  95. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts.map +1 -1
  96. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.js +3 -1
  97. package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.js.map +1 -1
  98. package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.d.ts +2 -1
  99. package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.d.ts.map +1 -1
  100. package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.js +30 -8
  101. package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.js.map +1 -1
  102. package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts +2 -0
  103. package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts.map +1 -1
  104. package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js +10 -6
  105. package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js.map +1 -1
  106. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.d.ts +82 -2
  107. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.d.ts.map +1 -1
  108. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.js +71 -13
  109. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.js.map +1 -1
  110. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.d.ts.map +1 -1
  111. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.js +0 -1
  112. package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.js.map +1 -1
  113. package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts +7 -0
  114. package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts.map +1 -1
  115. package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js +75 -1
  116. package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js.map +1 -1
  117. package/node_modules/@murphai/assistant-engine/package.json +2 -2
  118. package/node_modules/@murphai/assistantd/package.json +1 -1
  119. package/node_modules/@murphai/core/dist/automation.d.ts.map +1 -1
  120. package/node_modules/@murphai/core/dist/automation.js +10 -7
  121. package/node_modules/@murphai/core/dist/automation.js.map +1 -1
  122. package/node_modules/@murphai/core/dist/mutations.d.ts +2 -1
  123. package/node_modules/@murphai/core/dist/mutations.d.ts.map +1 -1
  124. package/node_modules/@murphai/core/dist/mutations.js +8 -4
  125. package/node_modules/@murphai/core/dist/mutations.js.map +1 -1
  126. package/node_modules/@murphai/core/dist/operations/canonical-write-lock.d.ts +3 -1
  127. package/node_modules/@murphai/core/dist/operations/canonical-write-lock.d.ts.map +1 -1
  128. package/node_modules/@murphai/core/dist/operations/canonical-write-lock.js +86 -66
  129. package/node_modules/@murphai/core/dist/operations/canonical-write-lock.js.map +1 -1
  130. package/node_modules/@murphai/core/dist/public-mutations.d.ts.map +1 -1
  131. package/node_modules/@murphai/core/dist/public-mutations.js +14 -7
  132. package/node_modules/@murphai/core/dist/public-mutations.js.map +1 -1
  133. package/node_modules/@murphai/core/package.json +1 -1
  134. package/node_modules/@murphai/device-syncd/dist/crypto.d.ts +13 -2
  135. package/node_modules/@murphai/device-syncd/dist/crypto.d.ts.map +1 -1
  136. package/node_modules/@murphai/device-syncd/dist/crypto.js +116 -15
  137. package/node_modules/@murphai/device-syncd/dist/crypto.js.map +1 -1
  138. package/node_modules/@murphai/device-syncd/dist/hosted-runtime.d.ts.map +1 -1
  139. package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js +1 -1
  140. package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js.map +1 -1
  141. package/node_modules/@murphai/device-syncd/dist/http.d.ts.map +1 -1
  142. package/node_modules/@murphai/device-syncd/dist/http.js +6 -5
  143. package/node_modules/@murphai/device-syncd/dist/http.js.map +1 -1
  144. package/node_modules/@murphai/device-syncd/dist/public-ingress.d.ts.map +1 -1
  145. package/node_modules/@murphai/device-syncd/dist/public-ingress.js +3 -2
  146. package/node_modules/@murphai/device-syncd/dist/public-ingress.js.map +1 -1
  147. package/node_modules/@murphai/device-syncd/dist/service.d.ts +1 -0
  148. package/node_modules/@murphai/device-syncd/dist/service.d.ts.map +1 -1
  149. package/node_modules/@murphai/device-syncd/dist/service.js +52 -14
  150. package/node_modules/@murphai/device-syncd/dist/service.js.map +1 -1
  151. package/node_modules/@murphai/device-syncd/dist/shared.d.ts.map +1 -1
  152. package/node_modules/@murphai/device-syncd/dist/shared.js +2 -1
  153. package/node_modules/@murphai/device-syncd/dist/shared.js.map +1 -1
  154. package/node_modules/@murphai/gateway-local/package.json +1 -1
  155. package/node_modules/@murphai/importers/dist/core-port.d.ts +5 -2
  156. package/node_modules/@murphai/importers/dist/core-port.d.ts.map +1 -1
  157. package/node_modules/@murphai/importers/dist/core-port.js.map +1 -1
  158. package/node_modules/@murphai/importers/dist/document-importer.d.ts +2 -1
  159. package/node_modules/@murphai/importers/dist/document-importer.d.ts.map +1 -1
  160. package/node_modules/@murphai/importers/dist/document-importer.js +3 -2
  161. package/node_modules/@murphai/importers/dist/document-importer.js.map +1 -1
  162. package/node_modules/@murphai/importers/dist/meal-importer.d.ts +4 -1
  163. package/node_modules/@murphai/importers/dist/meal-importer.d.ts.map +1 -1
  164. package/node_modules/@murphai/importers/dist/meal-importer.js +18 -4
  165. package/node_modules/@murphai/importers/dist/meal-importer.js.map +1 -1
  166. package/node_modules/@murphai/importers/dist/shared.d.ts +2 -0
  167. package/node_modules/@murphai/importers/dist/shared.d.ts.map +1 -1
  168. package/node_modules/@murphai/importers/dist/shared.js +4 -1
  169. package/node_modules/@murphai/importers/dist/shared.js.map +1 -1
  170. package/node_modules/@murphai/importers/package.json +1 -1
  171. package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.d.ts.map +1 -1
  172. package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js +0 -7
  173. package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js.map +1 -1
  174. package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.d.ts.map +1 -1
  175. package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.js +5 -3
  176. package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.js.map +1 -1
  177. package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.d.ts.map +1 -1
  178. package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.js +4 -4
  179. package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.js.map +1 -1
  180. package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js +6 -6
  181. package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js.map +1 -1
  182. package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts +20 -151
  183. package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts.map +1 -1
  184. package/node_modules/@murphai/inbox-services/dist/inbox-app/types.js.map +1 -1
  185. package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.d.ts +3 -8
  186. package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.d.ts.map +1 -1
  187. package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.js +0 -20
  188. package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.js.map +1 -1
  189. package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts +1 -6
  190. package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts.map +1 -1
  191. package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js +31 -12
  192. package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js.map +1 -1
  193. package/node_modules/@murphai/inbox-services/dist/inbox-services/query.d.ts +8 -8
  194. package/node_modules/@murphai/inbox-services/dist/inbox-services/query.d.ts.map +1 -1
  195. package/node_modules/@murphai/inbox-services/dist/inbox-services/query.js +12 -1
  196. package/node_modules/@murphai/inbox-services/dist/inbox-services/query.js.map +1 -1
  197. package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.d.ts.map +1 -1
  198. package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js +12 -1
  199. package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js.map +1 -1
  200. package/node_modules/@murphai/inbox-services/package.json +1 -1
  201. package/node_modules/@murphai/inboxd/dist/runtime.d.ts +1 -0
  202. package/node_modules/@murphai/inboxd/dist/runtime.d.ts.map +1 -1
  203. package/node_modules/@murphai/inboxd/dist/runtime.js.map +1 -1
  204. package/node_modules/@murphai/inboxd/package.json +1 -1
  205. package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.d.ts +16 -16
  206. package/node_modules/@murphai/operator-config/dist/assistant-backend.d.ts +2 -2
  207. package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts +86 -124
  208. package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts.map +1 -1
  209. package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js +19 -58
  210. package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js.map +1 -1
  211. package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts +6 -66
  212. package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts.map +1 -1
  213. package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js +0 -1
  214. package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js.map +1 -1
  215. package/node_modules/@murphai/operator-config/dist/linq-runtime.d.ts.map +1 -1
  216. package/node_modules/@murphai/operator-config/dist/linq-runtime.js +88 -47
  217. package/node_modules/@murphai/operator-config/dist/linq-runtime.js.map +1 -1
  218. package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.d.ts +1 -1
  219. package/node_modules/@murphai/operator-config/dist/operator-config.d.ts +3 -3
  220. package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts +4 -34
  221. package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts.map +1 -1
  222. package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js +0 -1
  223. package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js.map +1 -1
  224. package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts +31 -0
  225. package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts.map +1 -1
  226. package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js +4 -1
  227. package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js.map +1 -1
  228. package/node_modules/@murphai/operator-config/package.json +2 -2
  229. package/node_modules/@murphai/parsers/README.md +0 -1
  230. package/node_modules/@murphai/parsers/dist/index.d.ts +0 -4
  231. package/node_modules/@murphai/parsers/dist/index.d.ts.map +1 -1
  232. package/node_modules/@murphai/parsers/dist/index.js +0 -3
  233. package/node_modules/@murphai/parsers/dist/index.js.map +1 -1
  234. package/node_modules/@murphai/parsers/dist/toolchain/config.d.ts +1 -1
  235. package/node_modules/@murphai/parsers/dist/toolchain/config.d.ts.map +1 -1
  236. package/node_modules/@murphai/parsers/dist/toolchain/config.js +0 -1
  237. package/node_modules/@murphai/parsers/dist/toolchain/config.js.map +1 -1
  238. package/node_modules/@murphai/parsers/dist/toolchain/discover.d.ts.map +1 -1
  239. package/node_modules/@murphai/parsers/dist/toolchain/discover.js +0 -11
  240. package/node_modules/@murphai/parsers/dist/toolchain/discover.js.map +1 -1
  241. package/node_modules/@murphai/query/dist/automation.d.ts.map +1 -1
  242. package/node_modules/@murphai/query/dist/automation.js +8 -2
  243. package/node_modules/@murphai/query/dist/automation.js.map +1 -1
  244. package/node_modules/@murphai/query/package.json +1 -1
  245. package/node_modules/@murphai/runtime-state/README.md +1 -0
  246. package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.d.ts +2 -0
  247. package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.d.ts.map +1 -0
  248. package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.js +2 -0
  249. package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.js.map +1 -0
  250. package/node_modules/@murphai/runtime-state/dist/node/index.d.ts +1 -0
  251. package/node_modules/@murphai/runtime-state/dist/node/index.d.ts.map +1 -1
  252. package/node_modules/@murphai/runtime-state/dist/node/index.js +1 -0
  253. package/node_modules/@murphai/runtime-state/dist/node/index.js.map +1 -1
  254. package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.d.ts +2 -0
  255. package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.d.ts.map +1 -0
  256. package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.js +2 -0
  257. package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.js.map +1 -0
  258. package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.d.ts +2 -0
  259. package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.d.ts.map +1 -0
  260. package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.js +2 -0
  261. package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.js.map +1 -0
  262. package/node_modules/@murphai/runtime-state/dist/node/ulid.d.ts +2 -0
  263. package/node_modules/@murphai/runtime-state/dist/node/ulid.d.ts.map +1 -0
  264. package/node_modules/@murphai/runtime-state/dist/node/ulid.js +2 -0
  265. package/node_modules/@murphai/runtime-state/dist/node/ulid.js.map +1 -0
  266. package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.d.ts +9 -0
  267. package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.d.ts.map +1 -0
  268. package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.js +63 -0
  269. package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.js.map +1 -0
  270. package/node_modules/@murphai/runtime-state/dist/sqlite.d.ts +2 -1
  271. package/node_modules/@murphai/runtime-state/dist/sqlite.d.ts.map +1 -1
  272. package/node_modules/@murphai/runtime-state/dist/sqlite.js +4 -2
  273. package/node_modules/@murphai/runtime-state/dist/sqlite.js.map +1 -1
  274. package/node_modules/@murphai/runtime-state/package.json +20 -0
  275. package/node_modules/@murphai/setup-cli/dist/setup-services/steps.d.ts +1 -1
  276. package/node_modules/@murphai/setup-cli/dist/setup-services/steps.d.ts.map +1 -1
  277. package/node_modules/@murphai/setup-cli/dist/setup-services/steps.js +0 -17
  278. package/node_modules/@murphai/setup-cli/dist/setup-services/steps.js.map +1 -1
  279. package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.d.ts +1 -1
  280. package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.js +0 -4
  281. package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.js.map +1 -1
  282. package/node_modules/@murphai/setup-cli/dist/setup-services.d.ts.map +1 -1
  283. package/node_modules/@murphai/setup-cli/dist/setup-services.js +0 -2
  284. package/node_modules/@murphai/setup-cli/dist/setup-services.js.map +1 -1
  285. package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts +2 -1
  286. package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts.map +1 -1
  287. package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js +4 -2
  288. package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js.map +1 -1
  289. package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.d.ts.map +1 -1
  290. package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js +6 -1
  291. package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js.map +1 -1
  292. package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts +12 -1
  293. package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts.map +1 -1
  294. package/node_modules/@murphai/vault-usecases/package.json +1 -1
  295. package/package.json +4 -4
  296. package/node_modules/@murphai/parsers/dist/adapters/pdftotext.d.ts +0 -7
  297. package/node_modules/@murphai/parsers/dist/adapters/pdftotext.d.ts.map +0 -1
  298. package/node_modules/@murphai/parsers/dist/adapters/pdftotext.js +0 -60
  299. package/node_modules/@murphai/parsers/dist/adapters/pdftotext.js.map +0 -1
@@ -3,7 +3,7 @@ import { loadVault, upsertAutomation } from '@murphai/core';
3
3
  import { listAutomations as listCanonicalAutomations, showAutomation as showCanonicalAutomation, } from '@murphai/query';
4
4
  import { assistantCronJobSchema, assistantCronRunRecordSchema, assistantCronScheduleSchema, assistantCronTargetSchema, } from '@murphai/operator-config/assistant-cli-contracts';
5
5
  import { loadRuntimeModule } from '@murphai/vault-usecases/runtime';
6
- import { renderAutoLoggedFoodMealNote } from '@murphai/vault-usecases/records';
6
+ import { buildDailyFoodCronJobId, buildDailyFoodCronJobName, buildDailyFoodCronPrompt, buildDailyFoodSchedule, renderAutoLoggedFoodMealNote, } from '@murphai/vault-usecases/records';
7
7
  import { loadImporterRuntime } from '@murphai/vault-usecases/runtime';
8
8
  import { VaultCliError } from '@murphai/operator-config/vault-cli-errors';
9
9
  import { withAssistantCronWriteLock } from "./cron/locking.js";
@@ -11,7 +11,7 @@ import { buildAssistantCronSchedule, computeAssistantCronNextRunAt, } from "./cr
11
11
  import { getAssistantCronPresetDefinition, listAssistantCronPresets as listBuiltinAssistantCronPresets, renderAssistantCronPreset, } from "./cron/presets.js";
12
12
  import { appendAssistantCronRun, assertAssistantCronJobNameIsAvailable, buildAssistantCronTarget, createAssistantCronJobId, createAssistantCronRunId, ensureAssistantCronState, isAssistantCronJobDue, normalizeRequiredAssistantCronText, readAssistantCronRuns, readAssistantCronStore, resolveAssistantCronJobFromStore, resolveAssistantCronJobIndex, resolveAssistantCronRunLookupId, sortAssistantCronJobs, writeAssistantCronStore, } from "./cron/store.js";
13
13
  import { buildAssistantCronNotificationDedupeToken } from "./cron/notification-delivery.js";
14
- import { createAssistantCronAutomationRuntimeRecord, findAssistantCronAutomationRuntimeRecord, readAssistantCronAutomationRuntimeStore, removeAssistantCronAutomationRuntimeRecord, upsertAssistantCronAutomationRuntimeRecord, writeAssistantCronAutomationRuntimeStore, } from "./cron/runtime-state.js";
14
+ import { createAssistantCronCanonicalRuntimeRecord, findAssistantCronCanonicalRuntimeRecord, readAssistantCronCanonicalRuntimeStore, removeAssistantCronCanonicalRuntimeRecord, upsertAssistantCronCanonicalRuntimeRecord, writeAssistantCronCanonicalRuntimeStore, } from "./cron/runtime-state.js";
15
15
  import { sendAssistantNotificationLocal } from "../assistant-service.js";
16
16
  import { getAssistantChannelAdapter } from "./channel-adapters.js";
17
17
  import { resolveAssistantBindingDelivery } from "./bindings.js";
@@ -63,11 +63,12 @@ export async function addAssistantCronJob(input) {
63
63
  const name = normalizeRequiredAssistantCronText(resolvedInput.name, 'name');
64
64
  const prompt = normalizeRequiredAssistantCronText(resolvedInput.prompt, 'prompt');
65
65
  const enabled = resolvedInput.enabled ?? true;
66
- const schedule = await resolveAssistantCronScheduleForVault(input.vault, resolvedInput.schedule);
66
+ const resolvedSchedule = await resolveAssistantCronScheduleForVault(input.vault, resolvedInput.schedule);
67
+ const schedule = assistantCronScheduleSchema.parse(resolvedInput.schedule);
67
68
  const keepAfterRun = schedule.kind === 'at'
68
69
  ? resolvedInput.keepAfterRun ?? false
69
70
  : true;
70
- const nextRunAt = computeAssistantCronNextRunAt(schedule, now);
71
+ const nextRunAt = computeAssistantCronNextRunAt(resolvedSchedule, now);
71
72
  if (enabled && nextRunAt === null) {
72
73
  throw new VaultCliError('ASSISTANT_CRON_INVALID_SCHEDULE', 'The assistant cron schedule does not produce a future run time.');
73
74
  }
@@ -91,18 +92,19 @@ export async function addAssistantCronJob(input) {
91
92
  route: buildCanonicalAutomationRoute(target),
92
93
  instructions: prompt,
93
94
  }));
94
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
95
- const runtimeState = createAssistantCronAutomationRuntimeRecord({
96
- automationId: created.record.automationId,
97
- nextRunAt,
95
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
96
+ const timeZone = await resolveAssistantCronDefaultTimeZone(input.vault);
97
+ const source = requireCanonicalAssistantCronRecord(created.record, timeZone);
98
+ const runtimeState = createAssistantCronCanonicalRuntimeRecord({
99
+ jobId: source.automationId,
98
100
  now: now.toISOString(),
99
101
  sessionId: target.sessionId,
100
102
  alias: target.alias,
101
103
  });
102
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, runtimeState);
103
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
104
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, runtimeState);
105
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
104
106
  return projectCanonicalAssistantCronJob({
105
- automation: requireCanonicalAssistantCronRecord(created.record),
107
+ source,
106
108
  runtimeState,
107
109
  });
108
110
  });
@@ -163,19 +165,22 @@ async function resolveAssistantCronTargetDefaults(input) {
163
165
  };
164
166
  }
165
167
  async function listCanonicalAssistantCronRecords(vault, status = ['active', 'paused']) {
166
- const records = await listCanonicalAutomations(vault, {
167
- status: [...status],
168
- });
169
- return records.flatMap((record) => {
170
- const normalized = normalizeCanonicalAssistantCronRecord(record);
171
- return normalized ? [normalized] : [];
172
- });
173
- }
174
- async function findCanonicalAssistantCronRecord(vault, lookup) {
175
- const record = await showCanonicalAutomation(vault, lookup);
176
- return record ? normalizeCanonicalAssistantCronRecord(record) : null;
168
+ const timeZone = await resolveAssistantCronDefaultTimeZone(vault);
169
+ const [automationRecords, foodRecords] = await Promise.all([
170
+ listCanonicalAutomations(vault, {
171
+ status: [...status],
172
+ }),
173
+ listCanonicalFoodAutoLogRecords(vault, timeZone),
174
+ ]);
175
+ return [
176
+ ...automationRecords.flatMap((record) => {
177
+ const normalized = normalizeCanonicalAssistantCronRecord(record, timeZone);
178
+ return normalized ? [normalized] : [];
179
+ }),
180
+ ...(status.includes('active') ? foodRecords : []),
181
+ ];
177
182
  }
178
- function normalizeCanonicalAssistantCronRecord(record) {
183
+ function normalizeCanonicalAssistantCronRecord(record, timeZone) {
179
184
  if (record.status !== 'active' && record.status !== 'paused') {
180
185
  return null;
181
186
  }
@@ -183,67 +188,190 @@ function normalizeCanonicalAssistantCronRecord(record) {
183
188
  if (typeof instructions !== 'string') {
184
189
  throw new VaultCliError('ASSISTANT_CRON_INVALID_AUTOMATION', `Canonical automation "${record.automationId}" is missing scheduled instructions.`);
185
190
  }
186
- const { prompt: _prompt, ...rest } = record;
187
191
  return {
188
- ...rest,
192
+ kind: 'automation',
193
+ automationId: record.automationId,
194
+ continuityPolicy: record.continuityPolicy,
195
+ createdAt: record.createdAt,
189
196
  instructions,
197
+ route: record.route,
198
+ schedule: normalizeAssistantCronPublicSchedule(record.schedule),
199
+ slug: record.slug,
190
200
  status: record.status,
201
+ summary: record.summary,
202
+ tags: [...record.tags],
203
+ timeZone: record.schedule.kind === 'cron' || record.schedule.kind === 'dailyLocal'
204
+ ? timeZone
205
+ : null,
206
+ title: record.title,
207
+ updatedAt: record.updatedAt,
191
208
  };
192
209
  }
193
- function requireCanonicalAssistantCronRecord(record) {
194
- const normalized = normalizeCanonicalAssistantCronRecord(record);
210
+ function requireCanonicalAssistantCronRecord(record, timeZone) {
211
+ const normalized = normalizeCanonicalAssistantCronRecord(record, timeZone);
195
212
  if (!normalized) {
196
213
  throw new VaultCliError('ASSISTANT_CRON_INVALID_AUTOMATION', `Canonical automation "${record.automationId}" is not active or paused.`);
197
214
  }
198
215
  return normalized;
199
216
  }
200
- function createInitialCanonicalAutomationRuntimeState(automation) {
201
- const createdAt = automation.createdAt;
202
- return createAssistantCronAutomationRuntimeRecord({
203
- automationId: automation.automationId,
204
- nextRunAt: automation.status === 'active'
205
- ? computeAssistantCronNextRunAt(toAssistantCronSchedule(automation.schedule), new Date(createdAt))
206
- : null,
207
- now: createdAt,
217
+ async function listCanonicalFoodAutoLogRecords(vault, timeZone) {
218
+ const core = await loadFoodAutoLogCoreRuntime();
219
+ if (typeof core.listFoods !== 'function') {
220
+ return [];
221
+ }
222
+ const foods = await core.listFoods(vault);
223
+ return foods.flatMap((food) => {
224
+ const localTime = normalizeNullableString(food.autoLogDaily?.time);
225
+ const slug = normalizeNullableString(food.slug);
226
+ if (!localTime || !slug) {
227
+ return [];
228
+ }
229
+ return [{
230
+ kind: 'foodAutoLog',
231
+ foodId: food.foodId,
232
+ jobId: buildDailyFoodCronJobId(food.foodId),
233
+ schedule: buildDailyFoodSchedule(localTime),
234
+ slug,
235
+ timeZone,
236
+ title: food.title,
237
+ }];
208
238
  });
209
239
  }
210
- function resolveCanonicalAutomationRuntimeState(automation, store) {
211
- return (findAssistantCronAutomationRuntimeRecord(store, automation.automationId) ??
212
- createInitialCanonicalAutomationRuntimeState(automation));
240
+ function resolveCanonicalAssistantCronJobLookupKeys(record) {
241
+ if (record.kind === 'automation') {
242
+ return [record.automationId, record.slug, record.title];
243
+ }
244
+ return [record.jobId, buildDailyFoodCronJobName(record.slug)];
245
+ }
246
+ function findCanonicalAssistantCronRecordInList(records, lookup) {
247
+ const normalizedLookup = normalizeRequiredAssistantCronText(lookup, 'job');
248
+ const foldedLookup = normalizedLookup.toLocaleLowerCase();
249
+ return (records.find((record) => resolveCanonicalAssistantCronJobLookupKeys(record).some((candidate) => typeof candidate === 'string' &&
250
+ candidate.toLocaleLowerCase() === foldedLookup)) ?? null);
251
+ }
252
+ function createInitialCanonicalRuntimeState(source, now) {
253
+ return createAssistantCronCanonicalRuntimeRecord({
254
+ jobId: resolveCanonicalAssistantCronJobId(source),
255
+ now,
256
+ });
257
+ }
258
+ function resolveCanonicalRuntimeState(source, store, legacyLocalJob) {
259
+ return (findAssistantCronCanonicalRuntimeRecord(store, resolveCanonicalAssistantCronJobId(source)) ??
260
+ migrateLegacyLocalFoodRuntimeState(source, legacyLocalJob) ??
261
+ createInitialCanonicalRuntimeState(source, new Date().toISOString()));
213
262
  }
214
263
  function projectCanonicalAssistantCronJob(input) {
215
- const continuitySessionId = input.automation.continuityPolicy === 'preserve'
264
+ const continuitySessionId = input.source.kind === 'automation' &&
265
+ input.source.continuityPolicy === 'preserve'
216
266
  ? input.runtimeState.sessionId
217
267
  : null;
218
- const continuityAlias = input.automation.continuityPolicy === 'preserve'
268
+ const continuityAlias = input.source.kind === 'automation' &&
269
+ input.source.continuityPolicy === 'preserve'
219
270
  ? input.runtimeState.alias
220
271
  : null;
272
+ const targetRoute = input.source.kind === 'automation'
273
+ ? input.source.route
274
+ : {
275
+ channel: null,
276
+ deliveryTarget: null,
277
+ identityId: null,
278
+ participantId: null,
279
+ sourceThreadId: null,
280
+ };
221
281
  const target = assistantCronTargetSchema.parse({
222
282
  sessionId: continuitySessionId,
223
283
  alias: continuityAlias,
224
- channel: input.automation.route.channel,
225
- identityId: input.automation.route.identityId,
226
- participantId: input.automation.route.participantId,
227
- sourceThreadId: input.automation.route.sourceThreadId,
228
- deliveryTarget: input.automation.route.deliveryTarget,
284
+ channel: targetRoute.channel,
285
+ identityId: targetRoute.identityId,
286
+ participantId: targetRoute.participantId,
287
+ sourceThreadId: targetRoute.sourceThreadId,
288
+ deliveryTarget: targetRoute.deliveryTarget,
289
+ });
290
+ const projectedState = projectCanonicalAssistantCronJobState({
291
+ source: input.source,
292
+ runtimeState: input.runtimeState,
229
293
  });
230
294
  return assistantCronJobSchema.parse({
231
295
  schema: ASSISTANT_CRON_JOB_SCHEMA,
232
- jobId: input.automation.automationId,
233
- name: input.automation.title,
234
- enabled: input.automation.status === 'active',
235
- keepAfterRun: input.automation.schedule.kind !== 'at',
236
- prompt: input.automation.instructions,
237
- schedule: toAssistantCronSchedule(input.automation.schedule),
296
+ jobId: resolveCanonicalAssistantCronJobId(input.source),
297
+ name: input.source.kind === 'automation'
298
+ ? input.source.title
299
+ : buildDailyFoodCronJobName(input.source.slug),
300
+ enabled: isCanonicalAssistantCronSourceEnabled(input.source),
301
+ keepAfterRun: input.source.schedule.kind !== 'at',
302
+ prompt: input.source.kind === 'automation'
303
+ ? input.source.instructions
304
+ : buildDailyFoodCronPrompt(input.source.title),
305
+ schedule: input.source.schedule,
238
306
  target,
239
- createdAt: input.automation.createdAt,
240
- updatedAt: input.automation.updatedAt,
307
+ foodAutoLog: input.source.kind === 'foodAutoLog'
308
+ ? {
309
+ foodId: input.source.foodId,
310
+ }
311
+ : undefined,
312
+ createdAt: input.source.kind === 'automation'
313
+ ? input.source.createdAt
314
+ : input.runtimeState.createdAt,
315
+ updatedAt: input.source.kind === 'automation'
316
+ ? input.source.updatedAt
317
+ : input.runtimeState.updatedAt,
318
+ state: projectedState,
319
+ });
320
+ }
321
+ function projectCanonicalAssistantCronJobState(input) {
322
+ const nextRunAt = resolveCanonicalAssistantCronNextRunAt({
323
+ source: input.source,
241
324
  state: input.runtimeState.state,
242
325
  });
326
+ return {
327
+ nextRunAt,
328
+ lastRunAt: input.runtimeState.state.lastRunAt,
329
+ lastSucceededAt: input.runtimeState.state.lastSucceededAt,
330
+ lastFailedAt: input.runtimeState.state.lastFailedAt,
331
+ consecutiveFailures: input.runtimeState.state.consecutiveFailures,
332
+ lastError: input.runtimeState.state.lastError,
333
+ runningAt: input.runtimeState.state.runningAt,
334
+ runningPid: input.runtimeState.state.runningPid,
335
+ };
336
+ }
337
+ function resolveCanonicalAssistantCronJobId(source) {
338
+ return source.kind === 'automation' ? source.automationId : source.jobId;
339
+ }
340
+ function isCanonicalAssistantCronSourceEnabled(source) {
341
+ return source.kind === 'automation' ? source.status === 'active' : true;
243
342
  }
244
- function toAssistantCronSchedule(schedule) {
343
+ function normalizeAssistantCronPublicSchedule(schedule) {
344
+ if (schedule.kind === 'cron') {
345
+ return assistantCronScheduleSchema.parse({
346
+ kind: 'cron',
347
+ expression: schedule.expression,
348
+ });
349
+ }
350
+ if (schedule.kind === 'dailyLocal') {
351
+ return assistantCronScheduleSchema.parse({
352
+ kind: 'dailyLocal',
353
+ localTime: schedule.localTime,
354
+ });
355
+ }
245
356
  return assistantCronScheduleSchema.parse(schedule);
246
357
  }
358
+ function resolveAssistantCronResolvedSchedule(input) {
359
+ if (input.schedule.kind === 'cron') {
360
+ return {
361
+ kind: 'cron',
362
+ expression: input.schedule.expression,
363
+ timeZone: input.timeZone ?? 'UTC',
364
+ };
365
+ }
366
+ if (input.schedule.kind === 'dailyLocal') {
367
+ return {
368
+ kind: 'dailyLocal',
369
+ localTime: input.schedule.localTime,
370
+ timeZone: input.timeZone ?? 'UTC',
371
+ };
372
+ }
373
+ return input.schedule;
374
+ }
247
375
  function buildCanonicalAutomationRoute(target) {
248
376
  return {
249
377
  channel: target.channel ?? '',
@@ -270,50 +398,80 @@ function buildCanonicalAutomationUpsertInput(input) {
270
398
  }
271
399
  async function projectResolvedAssistantCronJob(vault, lookup) {
272
400
  const paths = resolveAssistantStatePaths(vault);
273
- const localStore = await readAssistantCronStore(paths);
274
- const localJob = tryResolveLocalAssistantCronJob(localStore, lookup);
401
+ const [localStore, canonicalRecords, runtimeStore] = await Promise.all([
402
+ readAssistantCronStore(paths),
403
+ listCanonicalAssistantCronRecords(vault),
404
+ readAssistantCronCanonicalRuntimeStore(paths),
405
+ ]);
406
+ const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
407
+ const visibleLocalStore = buildVisibleLocalAssistantCronStore(localStore, canonicalFoodIds);
408
+ const localJob = tryResolveLocalAssistantCronJob(visibleLocalStore, lookup);
275
409
  if (localJob) {
276
410
  return {
277
411
  kind: 'local',
278
412
  job: localJob,
279
413
  };
280
414
  }
281
- const automation = await findCanonicalAssistantCronRecord(vault, lookup);
282
- if (!automation) {
415
+ const source = findCanonicalAssistantCronRecordInList(canonicalRecords, lookup);
416
+ if (!source) {
283
417
  throw new VaultCliError('ASSISTANT_CRON_JOB_NOT_FOUND', `Assistant cron job "${normalizeRequiredAssistantCronText(lookup, 'job')}" was not found.`);
284
418
  }
285
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
286
- const runtimeState = resolveCanonicalAutomationRuntimeState(automation, runtimeStore);
419
+ const legacyFoodJob = source.kind === 'foodAutoLog'
420
+ ? tryResolveLocalAssistantCronFoodJobByFoodId(localStore, source.foodId)
421
+ : null;
422
+ const runtimeState = resolveCanonicalRuntimeState(source, runtimeStore, legacyFoodJob);
287
423
  return {
288
- kind: 'automation',
289
- automation,
424
+ kind: 'canonical',
425
+ source,
290
426
  runtimeState,
291
427
  job: projectCanonicalAssistantCronJob({
292
- automation,
428
+ source,
293
429
  runtimeState,
294
430
  }),
295
431
  };
296
432
  }
297
- function tryResolveLocalAssistantCronJob(store, lookup) {
433
+ function tryResolveLocalAssistantCronJob(store, lookup, options = {}) {
298
434
  try {
299
- return resolveAssistantCronJobFromStore(store, lookup);
435
+ const resolved = resolveAssistantCronJobFromStore(store, lookup);
436
+ if (options.allowFoodAutoLog === false && resolved.foodAutoLog) {
437
+ return null;
438
+ }
439
+ return resolved;
300
440
  }
301
441
  catch {
302
442
  return null;
303
443
  }
304
444
  }
445
+ function tryResolveLocalAssistantCronFoodJobByFoodId(store, foodId) {
446
+ return store.jobs.find((job) => job.foodAutoLog?.foodId === foodId) ?? null;
447
+ }
448
+ function buildCanonicalFoodIdSet(records) {
449
+ return new Set(records.flatMap((record) => record.kind === 'foodAutoLog' ? [record.foodId] : []));
450
+ }
451
+ function buildVisibleLocalAssistantCronStore(store, canonicalFoodIds) {
452
+ if (canonicalFoodIds.size === 0) {
453
+ return store;
454
+ }
455
+ return {
456
+ ...store,
457
+ jobs: store.jobs.filter((job) => !job.foodAutoLog || !canonicalFoodIds.has(job.foodAutoLog.foodId)),
458
+ };
459
+ }
305
460
  export async function listAssistantCronJobs(vault) {
306
461
  const paths = resolveAssistantStatePaths(vault);
307
462
  const [localStore, canonicalRecords, runtimeStore] = await Promise.all([
308
463
  readAssistantCronStore(paths),
309
464
  listCanonicalAssistantCronRecords(vault),
310
- readAssistantCronAutomationRuntimeStore(paths),
465
+ readAssistantCronCanonicalRuntimeStore(paths),
311
466
  ]);
467
+ const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
312
468
  return sortAssistantCronJobs([
313
- ...localStore.jobs,
314
- ...canonicalRecords.map((automation) => projectCanonicalAssistantCronJob({
315
- automation,
316
- runtimeState: resolveCanonicalAutomationRuntimeState(automation, runtimeStore),
469
+ ...buildVisibleLocalAssistantCronStore(localStore, canonicalFoodIds).jobs,
470
+ ...canonicalRecords.map((source) => projectCanonicalAssistantCronJob({
471
+ source,
472
+ runtimeState: resolveCanonicalRuntimeState(source, runtimeStore, source.kind === 'foodAutoLog'
473
+ ? tryResolveLocalAssistantCronFoodJobByFoodId(localStore, source.foodId)
474
+ : null),
317
475
  })),
318
476
  ]);
319
477
  }
@@ -329,30 +487,44 @@ export async function removeAssistantCronJob(vault, job) {
329
487
  await ensureAssistantCronState(paths);
330
488
  return withAssistantCronWriteLock(paths, async () => {
331
489
  const store = await readAssistantCronStore(paths);
332
- const localJob = tryResolveLocalAssistantCronJob(store, job);
490
+ const canonicalRecords = await listCanonicalAssistantCronRecords(vault);
491
+ const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
492
+ const visibleLocalStore = buildVisibleLocalAssistantCronStore(store, canonicalFoodIds);
493
+ const localJob = tryResolveLocalAssistantCronJob(visibleLocalStore, job);
333
494
  if (localJob) {
334
- const index = resolveAssistantCronJobIndex(store, job);
495
+ const index = store.jobs.findIndex((entry) => entry.jobId === localJob.jobId);
335
496
  const [removed] = store.jobs.splice(index, 1);
336
497
  await writeAssistantCronStore(paths, store);
337
498
  return removed;
338
499
  }
339
500
  const resolved = await projectResolvedAssistantCronJob(vault, job);
340
- if (resolved.kind !== 'automation') {
501
+ if (resolved.kind !== 'canonical') {
341
502
  return resolved.job;
342
503
  }
343
- await upsertAutomation(buildCanonicalAutomationUpsertInput({
344
- vault,
345
- automationId: resolved.automation.automationId,
346
- automation: resolved.automation,
347
- title: resolved.automation.title,
348
- status: 'archived',
349
- schedule: toAssistantCronSchedule(resolved.automation.schedule),
350
- route: resolved.automation.route,
351
- instructions: resolved.automation.instructions,
352
- }));
353
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
354
- if (removeAssistantCronAutomationRuntimeRecord(runtimeStore, resolved.automation.automationId)) {
355
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
504
+ if (resolved.source.kind === 'automation') {
505
+ await upsertAutomation(buildCanonicalAutomationUpsertInput({
506
+ vault,
507
+ automationId: resolved.source.automationId,
508
+ automation: resolved.source,
509
+ title: resolved.source.title,
510
+ status: 'archived',
511
+ schedule: resolved.source.schedule,
512
+ route: resolved.source.route,
513
+ instructions: resolved.source.instructions,
514
+ }));
515
+ }
516
+ else {
517
+ const foodId = resolved.source.foodId;
518
+ await clearCanonicalFoodAutoLogSchedule(vault, foodId);
519
+ const nextLocalJobs = store.jobs.filter((entry) => entry.foodAutoLog?.foodId !== foodId);
520
+ if (nextLocalJobs.length !== store.jobs.length) {
521
+ store.jobs = nextLocalJobs;
522
+ await writeAssistantCronStore(paths, store);
523
+ }
524
+ }
525
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
526
+ if (removeAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(resolved.source))) {
527
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
356
528
  }
357
529
  return resolved.job;
358
530
  });
@@ -387,39 +559,47 @@ export async function setAssistantCronJobEnabled(vault, job, enabled) {
387
559
  return updated;
388
560
  }
389
561
  const resolved = await projectResolvedAssistantCronJob(vault, job);
390
- if (resolved.kind !== 'automation') {
562
+ if (resolved.kind !== 'canonical') {
391
563
  return resolved.job;
392
564
  }
565
+ if (resolved.source.kind === 'foodAutoLog') {
566
+ throw new VaultCliError('ASSISTANT_CRON_INVALID_STATE', `Recurring food auto-log job "${resolved.job.name}" is controlled by the canonical food record, not assistant cron enable/disable.`);
567
+ }
393
568
  const now = new Date();
394
569
  const nextRunAt = enabled
395
- ? resolveAssistantCronReenabledNextRunAt(resolved.job, now)
396
- : resolved.runtimeState.state.nextRunAt;
570
+ ? computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
571
+ schedule: resolved.source.schedule,
572
+ timeZone: resolved.source.timeZone,
573
+ }), now)
574
+ : null;
397
575
  if (enabled && nextRunAt === null) {
398
576
  throw new VaultCliError('ASSISTANT_CRON_INVALID_STATE', `Assistant cron job "${resolved.job.name}" no longer has a future scheduled run. Run it manually or recreate it with a new schedule.`);
399
577
  }
400
578
  const updatedAutomation = await upsertAutomation(buildCanonicalAutomationUpsertInput({
401
579
  vault,
402
- automationId: resolved.automation.automationId,
403
- automation: resolved.automation,
404
- title: resolved.automation.title,
580
+ automationId: resolved.source.automationId,
581
+ automation: resolved.source,
582
+ title: resolved.source.title,
405
583
  status: enabled ? 'active' : 'paused',
406
- schedule: toAssistantCronSchedule(resolved.automation.schedule),
407
- route: resolved.automation.route,
408
- instructions: resolved.automation.instructions,
584
+ schedule: resolved.source.schedule,
585
+ route: resolved.source.route,
586
+ instructions: resolved.source.instructions,
409
587
  }));
410
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
588
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
411
589
  const updatedRuntimeState = {
412
590
  ...resolved.runtimeState,
413
591
  updatedAt: now.toISOString(),
414
592
  state: {
415
593
  ...resolved.runtimeState.state,
416
- nextRunAt,
594
+ activatedAt: enabled ? now.toISOString() : resolved.runtimeState.state.activatedAt,
595
+ pendingOccurrenceAt: null,
596
+ retryAfterAt: null,
417
597
  },
418
598
  };
419
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, updatedRuntimeState);
420
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
599
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
600
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
421
601
  return projectCanonicalAssistantCronJob({
422
- automation: requireCanonicalAssistantCronRecord(updatedAutomation.record),
602
+ source: requireCanonicalAssistantCronRecord(updatedAutomation.record, await resolveAssistantCronDefaultTimeZone(vault)),
423
603
  runtimeState: updatedRuntimeState,
424
604
  });
425
605
  });
@@ -488,7 +668,7 @@ export async function setAssistantCronJobTarget(input) {
488
668
  };
489
669
  }
490
670
  const resolved = await projectResolvedAssistantCronJob(resolvedInput.vault, resolvedInput.job);
491
- if (resolved.kind !== 'automation') {
671
+ if (resolved.kind !== 'canonical') {
492
672
  return {
493
673
  job: resolved.job,
494
674
  beforeTarget: buildAssistantCronTargetSnapshot(resolved.job),
@@ -498,6 +678,9 @@ export async function setAssistantCronJobTarget(input) {
498
678
  dryRun: Boolean(resolvedInput.dryRun),
499
679
  };
500
680
  }
681
+ if (resolved.source.kind === 'foodAutoLog') {
682
+ throw new VaultCliError('ASSISTANT_CRON_DELIVERY_REQUIRED', `Recurring food auto-log job "${resolved.job.name}" does not support assistant delivery targeting.`);
683
+ }
501
684
  if (resolved.runtimeState.state.runningAt !== null) {
502
685
  throw new VaultCliError('ASSISTANT_CRON_JOB_RUNNING', `Assistant cron job "${resolved.job.name}" is already running.`);
503
686
  }
@@ -536,25 +719,25 @@ export async function setAssistantCronJobTarget(input) {
536
719
  const now = (resolvedInput.now ?? new Date()).toISOString();
537
720
  const updatedAutomation = await upsertAutomation(buildCanonicalAutomationUpsertInput({
538
721
  vault: resolvedInput.vault,
539
- automationId: resolved.automation.automationId,
540
- automation: resolved.automation,
541
- title: resolved.automation.title,
542
- status: resolved.automation.status,
543
- schedule: toAssistantCronSchedule(resolved.automation.schedule),
722
+ automationId: resolved.source.automationId,
723
+ automation: resolved.source,
724
+ title: resolved.source.title,
725
+ status: resolved.source.status,
726
+ schedule: resolved.source.schedule,
544
727
  route: buildCanonicalAutomationRoute(afterTarget.target),
545
- instructions: resolved.automation.instructions,
728
+ instructions: resolved.source.instructions,
546
729
  }));
547
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
730
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
548
731
  const updatedRuntimeState = {
549
732
  ...resolved.runtimeState,
550
733
  alias: afterTarget.target.alias,
551
734
  sessionId: afterTarget.target.sessionId,
552
735
  updatedAt: now,
553
736
  };
554
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, updatedRuntimeState);
555
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
737
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
738
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
556
739
  const updatedJob = projectCanonicalAssistantCronJob({
557
- automation: requireCanonicalAssistantCronRecord(updatedAutomation.record),
740
+ source: requireCanonicalAssistantCronRecord(updatedAutomation.record, await resolveAssistantCronDefaultTimeZone(resolvedInput.vault)),
558
741
  runtimeState: updatedRuntimeState,
559
742
  });
560
743
  return {
@@ -638,29 +821,34 @@ export async function runAssistantCronJobNow(input) {
638
821
  };
639
822
  }
640
823
  const resolved = await projectResolvedAssistantCronJob(input.vault, input.job);
641
- if (resolved.kind !== 'automation') {
824
+ if (resolved.kind !== 'canonical') {
642
825
  return resolved;
643
826
  }
644
827
  if (resolved.runtimeState.state.runningAt !== null) {
645
828
  throw new VaultCliError('ASSISTANT_CRON_JOB_RUNNING', `Assistant cron job "${resolved.job.name}" is already running.`);
646
829
  }
647
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(paths);
830
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
831
+ const now = new Date().toISOString();
832
+ const occurrenceAt = resolveCanonicalAssistantCronOccurrenceAt(resolved.source, resolved.runtimeState) ??
833
+ now;
648
834
  const updatedRuntimeState = {
649
835
  ...resolved.runtimeState,
650
- updatedAt: new Date().toISOString(),
836
+ updatedAt: now,
651
837
  state: {
652
838
  ...resolved.runtimeState.state,
653
- runningAt: new Date().toISOString(),
839
+ pendingOccurrenceAt: occurrenceAt,
840
+ retryAfterAt: null,
841
+ runningAt: now,
654
842
  runningPid: process.pid,
655
843
  },
656
844
  };
657
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, updatedRuntimeState);
658
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
845
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
846
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
659
847
  return {
660
848
  ...resolved,
661
849
  runtimeState: updatedRuntimeState,
662
850
  job: projectCanonicalAssistantCronJob({
663
- automation: resolved.automation,
851
+ source: resolved.source,
664
852
  runtimeState: updatedRuntimeState,
665
853
  }),
666
854
  };
@@ -755,22 +943,26 @@ async function claimNextDueAssistantCronJob(paths, vault) {
755
943
  const [store, canonicalRecords, runtimeStore] = await Promise.all([
756
944
  readAssistantCronStore(paths),
757
945
  listCanonicalAssistantCronRecords(vault, ['active']),
758
- readAssistantCronAutomationRuntimeStore(paths),
946
+ readAssistantCronCanonicalRuntimeStore(paths),
759
947
  ]);
760
948
  const now = new Date().toISOString();
761
- const canonicalEntries = canonicalRecords.map((automation) => {
762
- const runtimeState = resolveCanonicalAutomationRuntimeState(automation, runtimeStore);
949
+ const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
950
+ const visibleLocalStore = buildVisibleLocalAssistantCronStore(store, canonicalFoodIds);
951
+ const canonicalEntries = canonicalRecords.map((source) => {
952
+ const runtimeState = resolveCanonicalRuntimeState(source, runtimeStore, source.kind === 'foodAutoLog'
953
+ ? tryResolveLocalAssistantCronFoodJobByFoodId(store, source.foodId)
954
+ : null);
763
955
  return {
764
- automation,
956
+ source,
765
957
  runtimeState,
766
958
  job: projectCanonicalAssistantCronJob({
767
- automation,
959
+ source,
768
960
  runtimeState,
769
961
  }),
770
962
  };
771
963
  });
772
964
  const candidate = sortAssistantCronJobs([
773
- ...store.jobs,
965
+ ...visibleLocalStore.jobs,
774
966
  ...canonicalEntries.map((entry) => entry.job),
775
967
  ]).find((job) => isAssistantCronJobDue(job, now));
776
968
  if (!candidate) {
@@ -794,24 +986,27 @@ async function claimNextDueAssistantCronJob(paths, vault) {
794
986
  job: claimed,
795
987
  };
796
988
  }
797
- const canonicalEntry = canonicalEntries.find((entry) => entry.automation.automationId === candidate.jobId);
989
+ const canonicalEntry = canonicalEntries.find((entry) => resolveCanonicalAssistantCronJobId(entry.source) === candidate.jobId);
990
+ const occurrenceAt = resolveCanonicalAssistantCronOccurrenceAt(canonicalEntry.source, canonicalEntry.runtimeState) ?? candidate.state.nextRunAt ?? now;
798
991
  const updatedRuntimeState = {
799
992
  ...canonicalEntry.runtimeState,
800
993
  updatedAt: now,
801
994
  state: {
802
995
  ...canonicalEntry.runtimeState.state,
996
+ pendingOccurrenceAt: occurrenceAt,
997
+ retryAfterAt: null,
803
998
  runningAt: now,
804
999
  runningPid: process.pid,
805
1000
  },
806
1001
  };
807
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, updatedRuntimeState);
808
- await writeAssistantCronAutomationRuntimeStore(paths, runtimeStore);
1002
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
1003
+ await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
809
1004
  return {
810
- kind: 'automation',
811
- automation: canonicalEntry.automation,
1005
+ kind: 'canonical',
1006
+ source: canonicalEntry.source,
812
1007
  runtimeState: updatedRuntimeState,
813
1008
  job: projectCanonicalAssistantCronJob({
814
- automation: canonicalEntry.automation,
1009
+ source: canonicalEntry.source,
815
1010
  runtimeState: updatedRuntimeState,
816
1011
  }),
817
1012
  };
@@ -918,57 +1113,65 @@ async function executeClaimedAssistantCronJob(input) {
918
1113
  removedAfterRun,
919
1114
  };
920
1115
  }
921
- const runtimeStore = await readAssistantCronAutomationRuntimeStore(input.paths);
922
- const currentRuntimeState = findAssistantCronAutomationRuntimeRecord(runtimeStore, input.job.automation.automationId) ?? input.job.runtimeState;
923
- const currentJob = projectCanonicalAssistantCronJob({
924
- automation: input.job.automation,
925
- runtimeState: currentRuntimeState,
926
- });
927
- const finalizedJob = finalizeAssistantCronJobAfterRun({
928
- job: currentJob,
1116
+ const runtimeStore = await readAssistantCronCanonicalRuntimeStore(input.paths);
1117
+ const currentRuntimeState = findAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(input.job.source)) ?? input.job.runtimeState;
1118
+ const updatedRuntimeState = finalizeCanonicalAssistantCronRuntimeAfterRun({
929
1119
  finishedAt,
930
- responseSessionId: input.job.automation.continuityPolicy === 'preserve' ? sessionId : null,
931
1120
  run: {
932
1121
  ...run,
933
1122
  status,
934
1123
  },
1124
+ runtimeState: currentRuntimeState,
1125
+ responseSessionId: input.job.source.kind === 'automation' &&
1126
+ input.job.source.continuityPolicy === 'preserve'
1127
+ ? sessionId
1128
+ : null,
1129
+ source: input.job.source,
935
1130
  });
936
- const updatedRuntimeState = {
1131
+ const persistedRuntimeState = {
937
1132
  ...currentRuntimeState,
938
- alias: input.job.automation.continuityPolicy === 'preserve'
939
- ? finalizedJob.target.alias
1133
+ alias: input.job.source.kind === 'automation' &&
1134
+ input.job.source.continuityPolicy === 'preserve'
1135
+ ? updatedRuntimeState.alias
940
1136
  : null,
941
- sessionId: input.job.automation.continuityPolicy === 'preserve'
942
- ? finalizedJob.target.sessionId
1137
+ sessionId: input.job.source.kind === 'automation' &&
1138
+ input.job.source.continuityPolicy === 'preserve'
1139
+ ? updatedRuntimeState.sessionId
943
1140
  : null,
944
1141
  updatedAt: finishedAt,
945
- state: finalizedJob.state,
1142
+ state: updatedRuntimeState.state,
946
1143
  };
1144
+ const finalizedJob = projectCanonicalAssistantCronJob({
1145
+ source: input.job.source,
1146
+ runtimeState: persistedRuntimeState,
1147
+ });
947
1148
  let removedAfterRun = false;
948
1149
  if (shouldRemoveAssistantCronJobAfterRun(finalizedJob, run)) {
949
- await upsertAutomation(buildCanonicalAutomationUpsertInput({
950
- vault: input.vault,
951
- automationId: input.job.automation.automationId,
952
- automation: input.job.automation,
953
- title: input.job.automation.title,
954
- status: 'archived',
955
- schedule: toAssistantCronSchedule(input.job.automation.schedule),
956
- route: input.job.automation.route,
957
- instructions: input.job.automation.instructions,
958
- }));
959
- removeAssistantCronAutomationRuntimeRecord(runtimeStore, input.job.automation.automationId);
1150
+ if (input.job.source.kind === 'automation') {
1151
+ await upsertAutomation(buildCanonicalAutomationUpsertInput({
1152
+ vault: input.vault,
1153
+ automationId: input.job.source.automationId,
1154
+ automation: input.job.source,
1155
+ title: input.job.source.title,
1156
+ status: 'archived',
1157
+ schedule: input.job.source.schedule,
1158
+ route: input.job.source.route,
1159
+ instructions: input.job.source.instructions,
1160
+ }));
1161
+ }
1162
+ removeAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(input.job.source));
960
1163
  removedAfterRun = true;
961
1164
  }
962
1165
  else {
963
- upsertAssistantCronAutomationRuntimeRecord(runtimeStore, updatedRuntimeState);
1166
+ upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, persistedRuntimeState);
964
1167
  }
965
- await writeAssistantCronAutomationRuntimeStore(input.paths, runtimeStore);
1168
+ await writeAssistantCronCanonicalRuntimeStore(input.paths, runtimeStore);
966
1169
  return {
967
1170
  job: removedAfterRun
968
1171
  ? finalizedJob
969
1172
  : projectCanonicalAssistantCronJob({
970
- automation: input.job.automation,
971
- runtimeState: updatedRuntimeState,
1173
+ source: input.job.source,
1174
+ runtimeState: persistedRuntimeState,
972
1175
  }),
973
1176
  removedAfterRun,
974
1177
  };
@@ -1063,14 +1266,125 @@ function resolveAssistantCronFailureBackoffMs(failureCount) {
1063
1266
  }
1064
1267
  return 60 * 60_000;
1065
1268
  }
1269
+ function resolveCanonicalAssistantCronOccurrenceAt(source, runtimeState) {
1270
+ if (!isCanonicalAssistantCronSourceEnabled(source)) {
1271
+ return null;
1272
+ }
1273
+ if (runtimeState.state.pendingOccurrenceAt) {
1274
+ return runtimeState.state.pendingOccurrenceAt;
1275
+ }
1276
+ if (source.schedule.kind === 'at') {
1277
+ return source.schedule.at;
1278
+ }
1279
+ const anchorAt = runtimeState.state.lastSucceededAt ?? runtimeState.state.activatedAt;
1280
+ if (!anchorAt) {
1281
+ return null;
1282
+ }
1283
+ return computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
1284
+ schedule: source.schedule,
1285
+ timeZone: source.kind === 'automation' ? source.timeZone : source.timeZone,
1286
+ }), new Date(anchorAt));
1287
+ }
1288
+ function resolveCanonicalAssistantCronNextRunAt(input) {
1289
+ if (!isCanonicalAssistantCronSourceEnabled(input.source)) {
1290
+ return null;
1291
+ }
1292
+ if (input.state.pendingOccurrenceAt) {
1293
+ return input.state.retryAfterAt ?? input.state.pendingOccurrenceAt;
1294
+ }
1295
+ if (input.source.schedule.kind === 'at') {
1296
+ return input.source.schedule.at;
1297
+ }
1298
+ const anchorAt = input.state.lastSucceededAt ?? input.state.activatedAt;
1299
+ if (!anchorAt) {
1300
+ return null;
1301
+ }
1302
+ return computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
1303
+ schedule: input.source.schedule,
1304
+ timeZone: input.source.kind === 'automation'
1305
+ ? input.source.timeZone
1306
+ : input.source.timeZone,
1307
+ }), new Date(anchorAt));
1308
+ }
1309
+ function finalizeCanonicalAssistantCronRuntimeAfterRun(input) {
1310
+ const runningClearedState = {
1311
+ ...input.runtimeState.state,
1312
+ runningAt: null,
1313
+ runningPid: null,
1314
+ lastRunAt: input.finishedAt,
1315
+ };
1316
+ if (input.run.status === 'succeeded') {
1317
+ return {
1318
+ ...input.runtimeState,
1319
+ sessionId: input.responseSessionId ?? input.runtimeState.sessionId,
1320
+ updatedAt: input.finishedAt,
1321
+ state: {
1322
+ ...runningClearedState,
1323
+ pendingOccurrenceAt: null,
1324
+ retryAfterAt: null,
1325
+ lastSucceededAt: input.finishedAt,
1326
+ lastError: null,
1327
+ consecutiveFailures: 0,
1328
+ },
1329
+ };
1330
+ }
1331
+ const failureCount = input.runtimeState.state.consecutiveFailures + 1;
1332
+ const retryAfterAt = isCanonicalAssistantCronSourceEnabled(input.source)
1333
+ ? new Date(Date.parse(input.finishedAt) + resolveAssistantCronFailureBackoffMs(failureCount)).toISOString()
1334
+ : null;
1335
+ return {
1336
+ ...input.runtimeState,
1337
+ updatedAt: input.finishedAt,
1338
+ state: {
1339
+ ...runningClearedState,
1340
+ pendingOccurrenceAt: input.runtimeState.state.pendingOccurrenceAt ??
1341
+ resolveCanonicalAssistantCronOccurrenceAt(input.source, input.runtimeState),
1342
+ retryAfterAt,
1343
+ lastFailedAt: input.finishedAt,
1344
+ lastError: input.run.error,
1345
+ consecutiveFailures: failureCount,
1346
+ },
1347
+ };
1348
+ }
1349
+ function migrateLegacyLocalFoodRuntimeState(source, legacyLocalJob) {
1350
+ if (source.kind !== 'foodAutoLog' || !legacyLocalJob) {
1351
+ return null;
1352
+ }
1353
+ return {
1354
+ schema: 'murph.assistant-canonical-cron-runtime-state.v2',
1355
+ jobId: source.jobId,
1356
+ alias: null,
1357
+ sessionId: null,
1358
+ createdAt: legacyLocalJob.createdAt,
1359
+ updatedAt: legacyLocalJob.updatedAt,
1360
+ state: {
1361
+ activatedAt: legacyLocalJob.createdAt,
1362
+ pendingOccurrenceAt: legacyLocalJob.state.runningAt !== null ||
1363
+ legacyLocalJob.state.consecutiveFailures > 0
1364
+ ? legacyLocalJob.state.nextRunAt
1365
+ : null,
1366
+ retryAfterAt: legacyLocalJob.state.consecutiveFailures > 0
1367
+ ? legacyLocalJob.state.nextRunAt
1368
+ : null,
1369
+ lastRunAt: legacyLocalJob.state.lastRunAt,
1370
+ lastSucceededAt: legacyLocalJob.state.lastSucceededAt,
1371
+ lastFailedAt: legacyLocalJob.state.lastFailedAt,
1372
+ consecutiveFailures: legacyLocalJob.state.consecutiveFailures,
1373
+ lastError: legacyLocalJob.state.lastError,
1374
+ runningAt: legacyLocalJob.state.runningAt,
1375
+ runningPid: legacyLocalJob.state.runningPid,
1376
+ },
1377
+ };
1378
+ }
1066
1379
  async function resolveAssistantCronScheduleForVault(vault, schedule) {
1067
- if (schedule.kind !== 'cron' || schedule.timeZone) {
1068
- return assistantCronScheduleSchema.parse(schedule);
1380
+ const publicSchedule = assistantCronScheduleSchema.parse(schedule);
1381
+ if (publicSchedule.kind === 'cron' || publicSchedule.kind === 'dailyLocal') {
1382
+ return resolveAssistantCronResolvedSchedule({
1383
+ schedule: publicSchedule,
1384
+ timeZone: await resolveAssistantCronDefaultTimeZone(vault),
1385
+ });
1069
1386
  }
1070
- return assistantCronScheduleSchema.parse({
1071
- ...schedule,
1072
- timeZone: await resolveAssistantCronDefaultTimeZone(vault),
1073
- });
1387
+ return publicSchedule;
1074
1388
  }
1075
1389
  async function resolveAssistantCronDefaultTimeZone(vault) {
1076
1390
  try {
@@ -1083,6 +1397,36 @@ async function resolveAssistantCronDefaultTimeZone(vault) {
1083
1397
  return resolveSystemTimeZone();
1084
1398
  }
1085
1399
  }
1400
+ async function loadFoodAutoLogCoreRuntime() {
1401
+ return loadRuntimeModule('@murphai/core');
1402
+ }
1403
+ async function clearCanonicalFoodAutoLogSchedule(vault, foodId) {
1404
+ const core = await loadFoodAutoLogCoreRuntime();
1405
+ const existing = await core.readFood({
1406
+ vaultRoot: vault,
1407
+ foodId,
1408
+ });
1409
+ await core.upsertFood({
1410
+ vaultRoot: vault,
1411
+ foodId: existing.foodId,
1412
+ slug: existing.slug,
1413
+ title: existing.title,
1414
+ status: existing.status,
1415
+ summary: existing.summary,
1416
+ kind: existing.kind,
1417
+ brand: existing.brand,
1418
+ vendor: existing.vendor,
1419
+ location: existing.location,
1420
+ serving: existing.serving,
1421
+ nutrition: existing.nutrition,
1422
+ aliases: existing.aliases,
1423
+ ingredients: existing.ingredients,
1424
+ tags: existing.tags,
1425
+ note: existing.note,
1426
+ attachedProtocolIds: existing.attachedProtocolIds,
1427
+ autoLogDaily: null,
1428
+ });
1429
+ }
1086
1430
  function assistantCronJobHasStableSessionLocator(job) {
1087
1431
  return Boolean(job.target.sessionId ||
1088
1432
  job.target.alias ||