@elizaos/plugin-personal-assistant 2.0.3-beta.5 → 2.0.3-beta.7

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 (1317) hide show
  1. package/dist/actions/app-block.d.ts +15 -0
  2. package/dist/actions/app-block.d.ts.map +1 -0
  3. package/dist/actions/app-block.js +349 -0
  4. package/dist/actions/app-block.js.map +1 -0
  5. package/dist/actions/autofill.d.ts +20 -0
  6. package/dist/actions/autofill.d.ts.map +1 -0
  7. package/dist/actions/autofill.js +370 -0
  8. package/dist/actions/autofill.js.map +1 -0
  9. package/dist/actions/block.d.ts +30 -0
  10. package/dist/actions/block.d.ts.map +1 -0
  11. package/dist/actions/block.js +326 -0
  12. package/dist/actions/block.js.map +1 -0
  13. package/dist/actions/book-travel.d.ts +10 -0
  14. package/dist/actions/book-travel.d.ts.map +1 -0
  15. package/dist/actions/book-travel.js +467 -0
  16. package/dist/actions/book-travel.js.map +1 -0
  17. package/dist/actions/brief.d.ts +60 -0
  18. package/dist/actions/brief.d.ts.map +1 -0
  19. package/dist/actions/brief.js +485 -0
  20. package/dist/actions/brief.js.map +1 -0
  21. package/dist/actions/calendar.d.ts +22 -0
  22. package/dist/actions/calendar.d.ts.map +1 -0
  23. package/dist/actions/calendar.js +832 -0
  24. package/dist/actions/calendar.js.map +1 -0
  25. package/dist/actions/conflict-detect.d.ts +67 -0
  26. package/dist/actions/conflict-detect.d.ts.map +1 -0
  27. package/dist/actions/conflict-detect.js +310 -0
  28. package/dist/actions/conflict-detect.js.map +1 -0
  29. package/dist/actions/connector.d.ts +5 -0
  30. package/dist/actions/connector.d.ts.map +1 -0
  31. package/dist/actions/connector.js +1354 -0
  32. package/dist/actions/connector.js.map +1 -0
  33. package/dist/actions/credentials.d.ts +14 -0
  34. package/dist/actions/credentials.d.ts.map +1 -0
  35. package/dist/actions/credentials.js +191 -0
  36. package/dist/actions/credentials.js.map +1 -0
  37. package/dist/actions/document.d.ts +36 -0
  38. package/dist/actions/document.d.ts.map +1 -0
  39. package/dist/actions/document.js +613 -0
  40. package/dist/actions/document.js.map +1 -0
  41. package/dist/actions/entity.d.ts +20 -0
  42. package/dist/actions/entity.d.ts.map +1 -0
  43. package/dist/actions/entity.js +785 -0
  44. package/dist/actions/entity.js.map +1 -0
  45. package/dist/actions/health.d.ts +4 -0
  46. package/dist/actions/health.d.ts.map +1 -0
  47. package/dist/actions/health.js +37 -0
  48. package/dist/actions/health.js.map +1 -0
  49. package/dist/actions/inbox.d.ts +12 -0
  50. package/dist/actions/inbox.d.ts.map +1 -0
  51. package/dist/actions/inbox.js +13 -0
  52. package/dist/actions/inbox.js.map +1 -0
  53. package/dist/actions/lib/calendly-handler.d.ts +3 -0
  54. package/dist/actions/lib/calendly-handler.d.ts.map +1 -0
  55. package/dist/actions/lib/calendly-handler.js +506 -0
  56. package/dist/actions/lib/calendly-handler.js.map +1 -0
  57. package/dist/actions/lib/extract-goal-plan.d.ts +69 -0
  58. package/dist/actions/lib/extract-goal-plan.d.ts.map +1 -0
  59. package/dist/actions/lib/extract-goal-plan.js +488 -0
  60. package/dist/actions/lib/extract-goal-plan.js.map +1 -0
  61. package/dist/actions/lib/extract-life-operation.d.ts +18 -0
  62. package/dist/actions/lib/extract-life-operation.d.ts.map +1 -0
  63. package/dist/actions/lib/extract-life-operation.js +318 -0
  64. package/dist/actions/lib/extract-life-operation.js.map +1 -0
  65. package/dist/actions/lib/extract-task-plan.d.ts +78 -0
  66. package/dist/actions/lib/extract-task-plan.d.ts.map +1 -0
  67. package/dist/actions/lib/extract-task-plan.js +355 -0
  68. package/dist/actions/lib/extract-task-plan.js.map +1 -0
  69. package/dist/actions/lib/extract-update-fields.d.ts +27 -0
  70. package/dist/actions/lib/extract-update-fields.d.ts.map +1 -0
  71. package/dist/actions/lib/extract-update-fields.js +172 -0
  72. package/dist/actions/lib/extract-update-fields.js.map +1 -0
  73. package/dist/actions/lib/lifeops-deferred-draft.d.ts +68 -0
  74. package/dist/actions/lib/lifeops-deferred-draft.d.ts.map +1 -0
  75. package/dist/actions/lib/lifeops-deferred-draft.js +315 -0
  76. package/dist/actions/lib/lifeops-deferred-draft.js.map +1 -0
  77. package/dist/actions/lib/messaging-helpers.d.ts +20 -0
  78. package/dist/actions/lib/messaging-helpers.d.ts.map +1 -0
  79. package/dist/actions/lib/messaging-helpers.js +103 -0
  80. package/dist/actions/lib/messaging-helpers.js.map +1 -0
  81. package/dist/actions/lib/owner-policy-writes.d.ts +49 -0
  82. package/dist/actions/lib/owner-policy-writes.d.ts.map +1 -0
  83. package/dist/actions/lib/owner-policy-writes.js +157 -0
  84. package/dist/actions/lib/owner-policy-writes.js.map +1 -0
  85. package/dist/actions/lib/prompt-format.d.ts +3 -0
  86. package/dist/actions/lib/prompt-format.d.ts.map +1 -0
  87. package/dist/actions/lib/prompt-format.js +42 -0
  88. package/dist/actions/lib/prompt-format.js.map +1 -0
  89. package/dist/actions/lib/scheduling-handler.d.ts +93 -0
  90. package/dist/actions/lib/scheduling-handler.d.ts.map +1 -0
  91. package/dist/actions/lib/scheduling-handler.js +868 -0
  92. package/dist/actions/lib/scheduling-handler.js.map +1 -0
  93. package/dist/actions/life.d.ts +13 -0
  94. package/dist/actions/life.d.ts.map +1 -0
  95. package/dist/actions/life.js +2524 -0
  96. package/dist/actions/life.js.map +1 -0
  97. package/dist/actions/money.d.ts +24 -0
  98. package/dist/actions/money.d.ts.map +1 -0
  99. package/dist/actions/money.js +41 -0
  100. package/dist/actions/money.js.map +1 -0
  101. package/dist/actions/owner-surfaces.d.ts +11 -0
  102. package/dist/actions/owner-surfaces.d.ts.map +1 -0
  103. package/dist/actions/owner-surfaces.js +493 -0
  104. package/dist/actions/owner-surfaces.js.map +1 -0
  105. package/dist/actions/password-manager.d.ts +10 -0
  106. package/dist/actions/password-manager.d.ts.map +1 -0
  107. package/dist/actions/password-manager.js +195 -0
  108. package/dist/actions/password-manager.js.map +1 -0
  109. package/dist/actions/payments.d.ts +10 -0
  110. package/dist/actions/payments.d.ts.map +1 -0
  111. package/dist/actions/payments.js +5 -0
  112. package/dist/actions/payments.js.map +1 -0
  113. package/dist/actions/prioritize.d.ts +49 -0
  114. package/dist/actions/prioritize.d.ts.map +1 -0
  115. package/dist/actions/prioritize.js +313 -0
  116. package/dist/actions/prioritize.js.map +1 -0
  117. package/dist/actions/remote-desktop.d.ts +13 -0
  118. package/dist/actions/remote-desktop.d.ts.map +1 -0
  119. package/dist/actions/remote-desktop.js +11 -0
  120. package/dist/actions/remote-desktop.js.map +1 -0
  121. package/dist/actions/resolve-request.d.ts +12 -0
  122. package/dist/actions/resolve-request.d.ts.map +1 -0
  123. package/dist/actions/resolve-request.js +427 -0
  124. package/dist/actions/resolve-request.js.map +1 -0
  125. package/dist/actions/schedule.d.ts +10 -0
  126. package/dist/actions/schedule.d.ts.map +1 -0
  127. package/dist/actions/schedule.js +113 -0
  128. package/dist/actions/schedule.js.map +1 -0
  129. package/dist/actions/scheduled-task.d.ts +32 -0
  130. package/dist/actions/scheduled-task.d.ts.map +1 -0
  131. package/dist/actions/scheduled-task.js +661 -0
  132. package/dist/actions/scheduled-task.js.map +1 -0
  133. package/dist/actions/screen-time.d.ts +4 -0
  134. package/dist/actions/screen-time.d.ts.map +1 -0
  135. package/dist/actions/screen-time.js +47 -0
  136. package/dist/actions/screen-time.js.map +1 -0
  137. package/dist/actions/subscriptions.d.ts +8 -0
  138. package/dist/actions/subscriptions.d.ts.map +1 -0
  139. package/dist/actions/subscriptions.js +327 -0
  140. package/dist/actions/subscriptions.js.map +1 -0
  141. package/dist/actions/voice-call.d.ts +16 -0
  142. package/dist/actions/voice-call.d.ts.map +1 -0
  143. package/dist/actions/voice-call.js +756 -0
  144. package/dist/actions/voice-call.js.map +1 -0
  145. package/dist/actions/website-block.d.ts +15 -0
  146. package/dist/actions/website-block.d.ts.map +1 -0
  147. package/dist/actions/website-block.js +719 -0
  148. package/dist/actions/website-block.js.map +1 -0
  149. package/dist/actions/work-thread.d.ts +5 -0
  150. package/dist/actions/work-thread.d.ts.map +1 -0
  151. package/dist/actions/work-thread.js +556 -0
  152. package/dist/actions/work-thread.js.map +1 -0
  153. package/dist/activity-profile/activity-tracker-repo.d.ts +28 -0
  154. package/dist/activity-profile/activity-tracker-repo.d.ts.map +1 -0
  155. package/dist/activity-profile/activity-tracker-repo.js +61 -0
  156. package/dist/activity-profile/activity-tracker-repo.js.map +1 -0
  157. package/dist/activity-profile/activity-tracker-reporting.d.ts +52 -0
  158. package/dist/activity-profile/activity-tracker-reporting.d.ts.map +1 -0
  159. package/dist/activity-profile/activity-tracker-reporting.js +119 -0
  160. package/dist/activity-profile/activity-tracker-reporting.js.map +1 -0
  161. package/dist/activity-profile/activity-tracker-service.d.ts +36 -0
  162. package/dist/activity-profile/activity-tracker-service.d.ts.map +1 -0
  163. package/dist/activity-profile/activity-tracker-service.js +187 -0
  164. package/dist/activity-profile/activity-tracker-service.js.map +1 -0
  165. package/dist/activity-profile/analyzer.d.ts +23 -0
  166. package/dist/activity-profile/analyzer.d.ts.map +1 -0
  167. package/dist/activity-profile/analyzer.js +485 -0
  168. package/dist/activity-profile/analyzer.js.map +1 -0
  169. package/dist/activity-profile/presence-signal-bridge-service.d.ts +14 -0
  170. package/dist/activity-profile/presence-signal-bridge-service.d.ts.map +1 -0
  171. package/dist/activity-profile/presence-signal-bridge-service.js +159 -0
  172. package/dist/activity-profile/presence-signal-bridge-service.js.map +1 -0
  173. package/dist/activity-profile/proactive-inbox-digest.d.ts +3 -0
  174. package/dist/activity-profile/proactive-inbox-digest.d.ts.map +1 -0
  175. package/dist/activity-profile/proactive-inbox-digest.js +21 -0
  176. package/dist/activity-profile/proactive-inbox-digest.js.map +1 -0
  177. package/dist/activity-profile/proactive-planner.d.ts +150 -0
  178. package/dist/activity-profile/proactive-planner.d.ts.map +1 -0
  179. package/dist/activity-profile/proactive-planner.js +529 -0
  180. package/dist/activity-profile/proactive-planner.js.map +1 -0
  181. package/dist/activity-profile/proactive-worker.d.ts +33 -0
  182. package/dist/activity-profile/proactive-worker.d.ts.map +1 -0
  183. package/dist/activity-profile/proactive-worker.js +779 -0
  184. package/dist/activity-profile/proactive-worker.js.map +1 -0
  185. package/dist/activity-profile/profile-metadata.d.ts +10 -0
  186. package/dist/activity-profile/profile-metadata.d.ts.map +1 -0
  187. package/dist/activity-profile/profile-metadata.js +16 -0
  188. package/dist/activity-profile/profile-metadata.js.map +1 -0
  189. package/dist/activity-profile/redactor.d.ts +15 -0
  190. package/dist/activity-profile/redactor.d.ts.map +1 -0
  191. package/dist/activity-profile/redactor.js +22 -0
  192. package/dist/activity-profile/redactor.js.map +1 -0
  193. package/dist/activity-profile/service.d.ts +11 -0
  194. package/dist/activity-profile/service.d.ts.map +1 -0
  195. package/dist/activity-profile/service.js +272 -0
  196. package/dist/activity-profile/service.js.map +1 -0
  197. package/dist/activity-profile/types.d.ts +97 -0
  198. package/dist/activity-profile/types.d.ts.map +1 -0
  199. package/dist/activity-profile/types.js +36 -0
  200. package/dist/activity-profile/types.js.map +1 -0
  201. package/dist/agent-lifeops.d.ts +2 -0
  202. package/dist/agent-lifeops.d.ts.map +1 -0
  203. package/dist/agent-lifeops.js +2 -0
  204. package/dist/agent-lifeops.js.map +1 -0
  205. package/dist/api/client-lifeops.d.ts +319 -0
  206. package/dist/api/client-lifeops.d.ts.map +1 -0
  207. package/dist/api/client-lifeops.js +794 -0
  208. package/dist/api/client-lifeops.js.map +1 -0
  209. package/dist/automation-node-contributor.d.ts +2 -0
  210. package/dist/automation-node-contributor.d.ts.map +1 -0
  211. package/dist/automation-node-contributor.js +184 -0
  212. package/dist/automation-node-contributor.js.map +1 -0
  213. package/dist/client.d.ts +16 -0
  214. package/dist/client.d.ts.map +1 -0
  215. package/dist/client.js +18 -0
  216. package/dist/client.js.map +1 -0
  217. package/dist/components/AppBlockerSettingsCard.d.ts +3 -0
  218. package/dist/components/AppBlockerSettingsCard.d.ts.map +1 -0
  219. package/dist/components/AppBlockerSettingsCard.js +538 -0
  220. package/dist/components/AppBlockerSettingsCard.js.map +1 -0
  221. package/dist/components/WebsiteBlockerSettingsCard.d.ts +3 -0
  222. package/dist/components/WebsiteBlockerSettingsCard.d.ts.map +1 -0
  223. package/dist/components/WebsiteBlockerSettingsCard.js +148 -0
  224. package/dist/components/WebsiteBlockerSettingsCard.js.map +1 -0
  225. package/dist/contracts/index.d.ts +2 -0
  226. package/dist/contracts/index.d.ts.map +1 -0
  227. package/dist/contracts/index.js +2 -0
  228. package/dist/contracts/index.js.map +1 -0
  229. package/dist/contracts/lifeops.d.ts +2 -0
  230. package/dist/contracts/lifeops.d.ts.map +1 -0
  231. package/dist/contracts/lifeops.js +2 -0
  232. package/dist/contracts/lifeops.js.map +1 -0
  233. package/dist/default-packs/autofill-whitelist-pack.d.ts +17 -0
  234. package/dist/default-packs/autofill-whitelist-pack.d.ts.map +1 -0
  235. package/dist/default-packs/autofill-whitelist-pack.js +56 -0
  236. package/dist/default-packs/autofill-whitelist-pack.js.map +1 -0
  237. package/dist/default-packs/consolidation-policies.d.ts +14 -0
  238. package/dist/default-packs/consolidation-policies.d.ts.map +1 -0
  239. package/dist/default-packs/consolidation-policies.js +17 -0
  240. package/dist/default-packs/consolidation-policies.js.map +1 -0
  241. package/dist/default-packs/contract-types.d.ts +200 -0
  242. package/dist/default-packs/contract-types.d.ts.map +1 -0
  243. package/dist/default-packs/contract-types.js +1 -0
  244. package/dist/default-packs/contract-types.js.map +1 -0
  245. package/dist/default-packs/daily-rhythm.d.ts +28 -0
  246. package/dist/default-packs/daily-rhythm.d.ts.map +1 -0
  247. package/dist/default-packs/daily-rhythm.js +136 -0
  248. package/dist/default-packs/daily-rhythm.js.map +1 -0
  249. package/dist/default-packs/escalation-ladders.d.ts +18 -0
  250. package/dist/default-packs/escalation-ladders.d.ts.map +1 -0
  251. package/dist/default-packs/escalation-ladders.js +17 -0
  252. package/dist/default-packs/escalation-ladders.js.map +1 -0
  253. package/dist/default-packs/executive-assistant.d.ts +50 -0
  254. package/dist/default-packs/executive-assistant.d.ts.map +1 -0
  255. package/dist/default-packs/executive-assistant.js +745 -0
  256. package/dist/default-packs/executive-assistant.js.map +1 -0
  257. package/dist/default-packs/followup-starter.d.ts +49 -0
  258. package/dist/default-packs/followup-starter.d.ts.map +1 -0
  259. package/dist/default-packs/followup-starter.js +104 -0
  260. package/dist/default-packs/followup-starter.js.map +1 -0
  261. package/dist/default-packs/habit-starters.d.ts +37 -0
  262. package/dist/default-packs/habit-starters.d.ts.map +1 -0
  263. package/dist/default-packs/habit-starters.js +255 -0
  264. package/dist/default-packs/habit-starters.js.map +1 -0
  265. package/dist/default-packs/inbox-triage-starter.d.ts +23 -0
  266. package/dist/default-packs/inbox-triage-starter.d.ts.map +1 -0
  267. package/dist/default-packs/inbox-triage-starter.js +61 -0
  268. package/dist/default-packs/inbox-triage-starter.js.map +1 -0
  269. package/dist/default-packs/index.d.ts +54 -0
  270. package/dist/default-packs/index.d.ts.map +1 -0
  271. package/dist/default-packs/index.js +150 -0
  272. package/dist/default-packs/index.js.map +1 -0
  273. package/dist/default-packs/lint.d.ts +62 -0
  274. package/dist/default-packs/lint.d.ts.map +1 -0
  275. package/dist/default-packs/lint.js +161 -0
  276. package/dist/default-packs/lint.js.map +1 -0
  277. package/dist/default-packs/morning-brief.d.ts +44 -0
  278. package/dist/default-packs/morning-brief.d.ts.map +1 -0
  279. package/dist/default-packs/morning-brief.js +69 -0
  280. package/dist/default-packs/morning-brief.js.map +1 -0
  281. package/dist/default-packs/quiet-user-watcher.d.ts +49 -0
  282. package/dist/default-packs/quiet-user-watcher.d.ts.map +1 -0
  283. package/dist/default-packs/quiet-user-watcher.js +92 -0
  284. package/dist/default-packs/quiet-user-watcher.js.map +1 -0
  285. package/dist/default-packs/registry-types.d.ts +51 -0
  286. package/dist/default-packs/registry-types.d.ts.map +1 -0
  287. package/dist/default-packs/registry-types.js +1 -0
  288. package/dist/default-packs/registry-types.js.map +1 -0
  289. package/dist/default-packs/task-definitions.d.ts +88 -0
  290. package/dist/default-packs/task-definitions.d.ts.map +1 -0
  291. package/dist/default-packs/task-definitions.js +87 -0
  292. package/dist/default-packs/task-definitions.js.map +1 -0
  293. package/dist/events/index.d.ts +34 -0
  294. package/dist/events/index.d.ts.map +1 -0
  295. package/dist/events/index.js +30 -0
  296. package/dist/events/index.js.map +1 -0
  297. package/dist/followup/actions/listOverdueFollowups.d.ts +3 -0
  298. package/dist/followup/actions/listOverdueFollowups.d.ts.map +1 -0
  299. package/dist/followup/actions/listOverdueFollowups.js +90 -0
  300. package/dist/followup/actions/listOverdueFollowups.js.map +1 -0
  301. package/dist/followup/actions/markFollowupDone.d.ts +3 -0
  302. package/dist/followup/actions/markFollowupDone.d.ts.map +1 -0
  303. package/dist/followup/actions/markFollowupDone.js +171 -0
  304. package/dist/followup/actions/markFollowupDone.js.map +1 -0
  305. package/dist/followup/actions/setFollowupThreshold.d.ts +3 -0
  306. package/dist/followup/actions/setFollowupThreshold.d.ts.map +1 -0
  307. package/dist/followup/actions/setFollowupThreshold.js +171 -0
  308. package/dist/followup/actions/setFollowupThreshold.js.map +1 -0
  309. package/dist/followup/followup-tracker.d.ts +83 -0
  310. package/dist/followup/followup-tracker.d.ts.map +1 -0
  311. package/dist/followup/followup-tracker.js +311 -0
  312. package/dist/followup/followup-tracker.js.map +1 -0
  313. package/dist/followup/index.d.ts +5 -0
  314. package/dist/followup/index.d.ts.map +1 -0
  315. package/dist/followup/index.js +39 -0
  316. package/dist/followup/index.js.map +1 -0
  317. package/dist/hooks/connector-error.d.ts +2 -0
  318. package/dist/hooks/connector-error.d.ts.map +1 -0
  319. package/dist/hooks/connector-error.js +13 -0
  320. package/dist/hooks/connector-error.js.map +1 -0
  321. package/dist/hooks/useDiscordConnector.d.ts +11 -0
  322. package/dist/hooks/useDiscordConnector.d.ts.map +1 -0
  323. package/dist/hooks/useDiscordConnector.js +95 -0
  324. package/dist/hooks/useDiscordConnector.js.map +1 -0
  325. package/dist/hooks/useGoogleLifeOpsConnector.d.ts +23 -0
  326. package/dist/hooks/useGoogleLifeOpsConnector.d.ts.map +1 -0
  327. package/dist/hooks/useGoogleLifeOpsConnector.js +630 -0
  328. package/dist/hooks/useGoogleLifeOpsConnector.js.map +1 -0
  329. package/dist/hooks/useIMessageConnector.d.ts +10 -0
  330. package/dist/hooks/useIMessageConnector.d.ts.map +1 -0
  331. package/dist/hooks/useIMessageConnector.js +57 -0
  332. package/dist/hooks/useIMessageConnector.js.map +1 -0
  333. package/dist/hooks/useInbox.d.ts +36 -0
  334. package/dist/hooks/useInbox.d.ts.map +1 -0
  335. package/dist/hooks/useInbox.js +96 -0
  336. package/dist/hooks/useInbox.js.map +1 -0
  337. package/dist/hooks/useLifeOpsActivitySignals.d.ts +2 -0
  338. package/dist/hooks/useLifeOpsActivitySignals.d.ts.map +1 -0
  339. package/dist/hooks/useLifeOpsActivitySignals.js +358 -0
  340. package/dist/hooks/useLifeOpsActivitySignals.js.map +1 -0
  341. package/dist/hooks/useLifeOpsAppState.d.ts +9 -0
  342. package/dist/hooks/useLifeOpsAppState.d.ts.map +1 -0
  343. package/dist/hooks/useLifeOpsAppState.js +79 -0
  344. package/dist/hooks/useLifeOpsAppState.js.map +1 -0
  345. package/dist/hooks/useLifeOpsCapabilitiesStatus.d.ts +8 -0
  346. package/dist/hooks/useLifeOpsCapabilitiesStatus.d.ts.map +1 -0
  347. package/dist/hooks/useLifeOpsCapabilitiesStatus.js +60 -0
  348. package/dist/hooks/useLifeOpsCapabilitiesStatus.js.map +1 -0
  349. package/dist/hooks/useLifeOpsXConnector.d.ts +11 -0
  350. package/dist/hooks/useLifeOpsXConnector.d.ts.map +1 -0
  351. package/dist/hooks/useLifeOpsXConnector.js +92 -0
  352. package/dist/hooks/useLifeOpsXConnector.js.map +1 -0
  353. package/dist/hooks/useSignalConnector.d.ts +14 -0
  354. package/dist/hooks/useSignalConnector.d.ts.map +1 -0
  355. package/dist/hooks/useSignalConnector.js +89 -0
  356. package/dist/hooks/useSignalConnector.js.map +1 -0
  357. package/dist/hooks/useTelegramConnector.d.ts +14 -0
  358. package/dist/hooks/useTelegramConnector.d.ts.map +1 -0
  359. package/dist/hooks/useTelegramConnector.js +97 -0
  360. package/dist/hooks/useTelegramConnector.js.map +1 -0
  361. package/dist/hooks/useWhatsAppConnector.d.ts +8 -0
  362. package/dist/hooks/useWhatsAppConnector.d.ts.map +1 -0
  363. package/dist/hooks/useWhatsAppConnector.js +62 -0
  364. package/dist/hooks/useWhatsAppConnector.js.map +1 -0
  365. package/dist/inbox/message-fetcher.d.ts +11 -0
  366. package/dist/inbox/message-fetcher.d.ts.map +1 -0
  367. package/dist/inbox/message-fetcher.js +13 -0
  368. package/dist/inbox/message-fetcher.js.map +1 -0
  369. package/dist/inbox/repository.d.ts +11 -0
  370. package/dist/inbox/repository.d.ts.map +1 -0
  371. package/dist/inbox/repository.js +5 -0
  372. package/dist/inbox/repository.js.map +1 -0
  373. package/dist/inbox/types.d.ts +10 -0
  374. package/dist/inbox/types.d.ts.map +1 -0
  375. package/dist/inbox/types.js +2 -0
  376. package/dist/inbox/types.js.map +1 -0
  377. package/dist/index.d.ts +36 -0
  378. package/dist/index.d.ts.map +1 -0
  379. package/dist/index.js +188 -0
  380. package/dist/index.js.map +1 -0
  381. package/dist/lifeops/access.d.ts +29 -0
  382. package/dist/lifeops/access.d.ts.map +1 -0
  383. package/dist/lifeops/access.js +56 -0
  384. package/dist/lifeops/access.js.map +1 -0
  385. package/dist/lifeops/app-state.d.ts +22 -0
  386. package/dist/lifeops/app-state.d.ts.map +1 -0
  387. package/dist/lifeops/app-state.js +67 -0
  388. package/dist/lifeops/app-state.js.map +1 -0
  389. package/dist/lifeops/apple-reminders.d.ts +67 -0
  390. package/dist/lifeops/apple-reminders.d.ts.map +1 -0
  391. package/dist/lifeops/apple-reminders.js +396 -0
  392. package/dist/lifeops/apple-reminders.js.map +1 -0
  393. package/dist/lifeops/approval-queue.d.ts +38 -0
  394. package/dist/lifeops/approval-queue.d.ts.map +1 -0
  395. package/dist/lifeops/approval-queue.js +575 -0
  396. package/dist/lifeops/approval-queue.js.map +1 -0
  397. package/dist/lifeops/approval-queue.types.d.ts +172 -0
  398. package/dist/lifeops/approval-queue.types.d.ts.map +1 -0
  399. package/dist/lifeops/approval-queue.types.js +27 -0
  400. package/dist/lifeops/approval-queue.types.js.map +1 -0
  401. package/dist/lifeops/autofill-whitelist.d.ts +20 -0
  402. package/dist/lifeops/autofill-whitelist.d.ts.map +1 -0
  403. package/dist/lifeops/autofill-whitelist.js +59 -0
  404. package/dist/lifeops/autofill-whitelist.js.map +1 -0
  405. package/dist/lifeops/background-planner-dispatch.d.ts +60 -0
  406. package/dist/lifeops/background-planner-dispatch.d.ts.map +1 -0
  407. package/dist/lifeops/background-planner-dispatch.js +113 -0
  408. package/dist/lifeops/background-planner-dispatch.js.map +1 -0
  409. package/dist/lifeops/background-planner.d.ts +140 -0
  410. package/dist/lifeops/background-planner.d.ts.map +1 -0
  411. package/dist/lifeops/background-planner.js +359 -0
  412. package/dist/lifeops/background-planner.js.map +1 -0
  413. package/dist/lifeops/bill-extraction.d.ts +46 -0
  414. package/dist/lifeops/bill-extraction.d.ts.map +1 -0
  415. package/dist/lifeops/bill-extraction.js +325 -0
  416. package/dist/lifeops/bill-extraction.js.map +1 -0
  417. package/dist/lifeops/browser-constants.d.ts +4 -0
  418. package/dist/lifeops/browser-constants.d.ts.map +1 -0
  419. package/dist/lifeops/browser-constants.js +27 -0
  420. package/dist/lifeops/browser-constants.js.map +1 -0
  421. package/dist/lifeops/browser-extension-store.d.ts +61 -0
  422. package/dist/lifeops/browser-extension-store.d.ts.map +1 -0
  423. package/dist/lifeops/browser-extension-store.js +176 -0
  424. package/dist/lifeops/browser-extension-store.js.map +1 -0
  425. package/dist/lifeops/browser-session-lifecycle.d.ts +57 -0
  426. package/dist/lifeops/browser-session-lifecycle.d.ts.map +1 -0
  427. package/dist/lifeops/browser-session-lifecycle.js +308 -0
  428. package/dist/lifeops/browser-session-lifecycle.js.map +1 -0
  429. package/dist/lifeops/bulk-review.d.ts +333 -0
  430. package/dist/lifeops/bulk-review.d.ts.map +1 -0
  431. package/dist/lifeops/bulk-review.js +1120 -0
  432. package/dist/lifeops/bulk-review.js.map +1 -0
  433. package/dist/lifeops/calendar-gate.d.ts +20 -0
  434. package/dist/lifeops/calendar-gate.d.ts.map +1 -0
  435. package/dist/lifeops/calendar-gate.js +30 -0
  436. package/dist/lifeops/calendar-gate.js.map +1 -0
  437. package/dist/lifeops/channels/contract.d.ts +47 -0
  438. package/dist/lifeops/channels/contract.d.ts.map +1 -0
  439. package/dist/lifeops/channels/contract.js +1 -0
  440. package/dist/lifeops/channels/contract.js.map +1 -0
  441. package/dist/lifeops/channels/default-pack.d.ts +26 -0
  442. package/dist/lifeops/channels/default-pack.d.ts.map +1 -0
  443. package/dist/lifeops/channels/default-pack.js +243 -0
  444. package/dist/lifeops/channels/default-pack.js.map +1 -0
  445. package/dist/lifeops/channels/index.d.ts +5 -0
  446. package/dist/lifeops/channels/index.d.ts.map +1 -0
  447. package/dist/lifeops/channels/index.js +23 -0
  448. package/dist/lifeops/channels/index.js.map +1 -0
  449. package/dist/lifeops/channels/priority-posture.d.ts +36 -0
  450. package/dist/lifeops/channels/priority-posture.d.ts.map +1 -0
  451. package/dist/lifeops/channels/priority-posture.js +27 -0
  452. package/dist/lifeops/channels/priority-posture.js.map +1 -0
  453. package/dist/lifeops/channels/registry.d.ts +7 -0
  454. package/dist/lifeops/channels/registry.d.ts.map +1 -0
  455. package/dist/lifeops/channels/registry.js +49 -0
  456. package/dist/lifeops/channels/registry.js.map +1 -0
  457. package/dist/lifeops/checkin/checkin-service.d.ts +66 -0
  458. package/dist/lifeops/checkin/checkin-service.d.ts.map +1 -0
  459. package/dist/lifeops/checkin/checkin-service.js +1084 -0
  460. package/dist/lifeops/checkin/checkin-service.js.map +1 -0
  461. package/dist/lifeops/checkin/schedule-resolver.d.ts +17 -0
  462. package/dist/lifeops/checkin/schedule-resolver.d.ts.map +1 -0
  463. package/dist/lifeops/checkin/schedule-resolver.js +26 -0
  464. package/dist/lifeops/checkin/schedule-resolver.js.map +1 -0
  465. package/dist/lifeops/checkin/types.d.ts +106 -0
  466. package/dist/lifeops/checkin/types.d.ts.map +1 -0
  467. package/dist/lifeops/checkin/types.js +1 -0
  468. package/dist/lifeops/checkin/types.js.map +1 -0
  469. package/dist/lifeops/connectors/_helpers.d.ts +51 -0
  470. package/dist/lifeops/connectors/_helpers.d.ts.map +1 -0
  471. package/dist/lifeops/connectors/_helpers.js +104 -0
  472. package/dist/lifeops/connectors/_helpers.js.map +1 -0
  473. package/dist/lifeops/connectors/calendly.d.ts +11 -0
  474. package/dist/lifeops/connectors/calendly.d.ts.map +1 -0
  475. package/dist/lifeops/connectors/calendly.js +61 -0
  476. package/dist/lifeops/connectors/calendly.js.map +1 -0
  477. package/dist/lifeops/connectors/contract.d.ts +88 -0
  478. package/dist/lifeops/connectors/contract.d.ts.map +1 -0
  479. package/dist/lifeops/connectors/contract.js +1 -0
  480. package/dist/lifeops/connectors/contract.js.map +1 -0
  481. package/dist/lifeops/connectors/default-pack.d.ts +35 -0
  482. package/dist/lifeops/connectors/default-pack.d.ts.map +1 -0
  483. package/dist/lifeops/connectors/default-pack.js +37 -0
  484. package/dist/lifeops/connectors/default-pack.js.map +1 -0
  485. package/dist/lifeops/connectors/discord.d.ts +8 -0
  486. package/dist/lifeops/connectors/discord.d.ts.map +1 -0
  487. package/dist/lifeops/connectors/discord.js +53 -0
  488. package/dist/lifeops/connectors/discord.js.map +1 -0
  489. package/dist/lifeops/connectors/dispatch-policy.d.ts +75 -0
  490. package/dist/lifeops/connectors/dispatch-policy.d.ts.map +1 -0
  491. package/dist/lifeops/connectors/dispatch-policy.js +35 -0
  492. package/dist/lifeops/connectors/dispatch-policy.js.map +1 -0
  493. package/dist/lifeops/connectors/duffel.d.ts +11 -0
  494. package/dist/lifeops/connectors/duffel.d.ts.map +1 -0
  495. package/dist/lifeops/connectors/duffel.js +74 -0
  496. package/dist/lifeops/connectors/duffel.js.map +1 -0
  497. package/dist/lifeops/connectors/google.d.ts +27 -0
  498. package/dist/lifeops/connectors/google.d.ts.map +1 -0
  499. package/dist/lifeops/connectors/google.js +80 -0
  500. package/dist/lifeops/connectors/google.js.map +1 -0
  501. package/dist/lifeops/connectors/imessage.d.ts +11 -0
  502. package/dist/lifeops/connectors/imessage.d.ts.map +1 -0
  503. package/dist/lifeops/connectors/imessage.js +55 -0
  504. package/dist/lifeops/connectors/imessage.js.map +1 -0
  505. package/dist/lifeops/connectors/index.d.ts +5 -0
  506. package/dist/lifeops/connectors/index.d.ts.map +1 -0
  507. package/dist/lifeops/connectors/index.js +23 -0
  508. package/dist/lifeops/connectors/index.js.map +1 -0
  509. package/dist/lifeops/connectors/mockoon-redirect.d.ts +54 -0
  510. package/dist/lifeops/connectors/mockoon-redirect.d.ts.map +1 -0
  511. package/dist/lifeops/connectors/mockoon-redirect.js +71 -0
  512. package/dist/lifeops/connectors/mockoon-redirect.js.map +1 -0
  513. package/dist/lifeops/connectors/registry.d.ts +7 -0
  514. package/dist/lifeops/connectors/registry.d.ts.map +1 -0
  515. package/dist/lifeops/connectors/registry.js +55 -0
  516. package/dist/lifeops/connectors/registry.js.map +1 -0
  517. package/dist/lifeops/connectors/signal.d.ts +8 -0
  518. package/dist/lifeops/connectors/signal.d.ts.map +1 -0
  519. package/dist/lifeops/connectors/signal.js +60 -0
  520. package/dist/lifeops/connectors/signal.js.map +1 -0
  521. package/dist/lifeops/connectors/telegram.d.ts +12 -0
  522. package/dist/lifeops/connectors/telegram.d.ts.map +1 -0
  523. package/dist/lifeops/connectors/telegram.js +65 -0
  524. package/dist/lifeops/connectors/telegram.js.map +1 -0
  525. package/dist/lifeops/connectors/twilio.d.ts +15 -0
  526. package/dist/lifeops/connectors/twilio.d.ts.map +1 -0
  527. package/dist/lifeops/connectors/twilio.js +126 -0
  528. package/dist/lifeops/connectors/twilio.js.map +1 -0
  529. package/dist/lifeops/connectors/whatsapp.d.ts +10 -0
  530. package/dist/lifeops/connectors/whatsapp.d.ts.map +1 -0
  531. package/dist/lifeops/connectors/whatsapp.js +56 -0
  532. package/dist/lifeops/connectors/whatsapp.js.map +1 -0
  533. package/dist/lifeops/connectors/x.d.ts +8 -0
  534. package/dist/lifeops/connectors/x.d.ts.map +1 -0
  535. package/dist/lifeops/connectors/x.js +62 -0
  536. package/dist/lifeops/connectors/x.js.map +1 -0
  537. package/dist/lifeops/contact-route-policy.d.ts +27 -0
  538. package/dist/lifeops/contact-route-policy.d.ts.map +1 -0
  539. package/dist/lifeops/contact-route-policy.js +153 -0
  540. package/dist/lifeops/contact-route-policy.js.map +1 -0
  541. package/dist/lifeops/continuity-probe.d.ts +49 -0
  542. package/dist/lifeops/continuity-probe.d.ts.map +1 -0
  543. package/dist/lifeops/continuity-probe.js +161 -0
  544. package/dist/lifeops/continuity-probe.js.map +1 -0
  545. package/dist/lifeops/cross-channel-search.d.ts +108 -0
  546. package/dist/lifeops/cross-channel-search.d.ts.map +1 -0
  547. package/dist/lifeops/cross-channel-search.js +888 -0
  548. package/dist/lifeops/cross-channel-search.js.map +1 -0
  549. package/dist/lifeops/defaults.d.ts +30 -0
  550. package/dist/lifeops/defaults.d.ts.map +1 -0
  551. package/dist/lifeops/defaults.js +206 -0
  552. package/dist/lifeops/defaults.js.map +1 -0
  553. package/dist/lifeops/device-bus-service.d.ts +16 -0
  554. package/dist/lifeops/device-bus-service.d.ts.map +1 -0
  555. package/dist/lifeops/device-bus-service.js +20 -0
  556. package/dist/lifeops/device-bus-service.js.map +1 -0
  557. package/dist/lifeops/device-identity.d.ts +31 -0
  558. package/dist/lifeops/device-identity.d.ts.map +1 -0
  559. package/dist/lifeops/device-identity.js +94 -0
  560. package/dist/lifeops/device-identity.js.map +1 -0
  561. package/dist/lifeops/document-review.d.ts +264 -0
  562. package/dist/lifeops/document-review.d.ts.map +1 -0
  563. package/dist/lifeops/document-review.js +925 -0
  564. package/dist/lifeops/document-review.js.map +1 -0
  565. package/dist/lifeops/email-classifier.d.ts +9 -0
  566. package/dist/lifeops/email-classifier.d.ts.map +1 -0
  567. package/dist/lifeops/email-classifier.js +15 -0
  568. package/dist/lifeops/email-classifier.js.map +1 -0
  569. package/dist/lifeops/email-curation.d.ts +13 -0
  570. package/dist/lifeops/email-curation.d.ts.map +1 -0
  571. package/dist/lifeops/email-curation.js +2 -0
  572. package/dist/lifeops/email-curation.js.map +1 -0
  573. package/dist/lifeops/email-unsubscribe-types.d.ts +7 -0
  574. package/dist/lifeops/email-unsubscribe-types.d.ts.map +1 -0
  575. package/dist/lifeops/email-unsubscribe-types.js +1 -0
  576. package/dist/lifeops/email-unsubscribe-types.js.map +1 -0
  577. package/dist/lifeops/enforcement-windows.d.ts +34 -0
  578. package/dist/lifeops/enforcement-windows.d.ts.map +1 -0
  579. package/dist/lifeops/enforcement-windows.js +80 -0
  580. package/dist/lifeops/enforcement-windows.js.map +1 -0
  581. package/dist/lifeops/engine.d.ts +8 -0
  582. package/dist/lifeops/engine.d.ts.map +1 -0
  583. package/dist/lifeops/engine.js +540 -0
  584. package/dist/lifeops/engine.js.map +1 -0
  585. package/dist/lifeops/entities/index.d.ts +4 -0
  586. package/dist/lifeops/entities/index.d.ts.map +1 -0
  587. package/dist/lifeops/entities/index.js +29 -0
  588. package/dist/lifeops/entities/index.js.map +1 -0
  589. package/dist/lifeops/entities/merge.d.ts +9 -0
  590. package/dist/lifeops/entities/merge.d.ts.map +1 -0
  591. package/dist/lifeops/entities/merge.js +17 -0
  592. package/dist/lifeops/entities/merge.js.map +1 -0
  593. package/dist/lifeops/entities/store.d.ts +13 -0
  594. package/dist/lifeops/entities/store.d.ts.map +1 -0
  595. package/dist/lifeops/entities/store.js +7 -0
  596. package/dist/lifeops/entities/store.js.map +1 -0
  597. package/dist/lifeops/entities/types.d.ts +9 -0
  598. package/dist/lifeops/entities/types.d.ts.map +1 -0
  599. package/dist/lifeops/entities/types.js +13 -0
  600. package/dist/lifeops/entities/types.js.map +1 -0
  601. package/dist/lifeops/entities/voice-attribution.d.ts +70 -0
  602. package/dist/lifeops/entities/voice-attribution.d.ts.map +1 -0
  603. package/dist/lifeops/entities/voice-attribution.js +121 -0
  604. package/dist/lifeops/entities/voice-attribution.js.map +1 -0
  605. package/dist/lifeops/entities/voice-observer-bridge.d.ts +32 -0
  606. package/dist/lifeops/entities/voice-observer-bridge.d.ts.map +1 -0
  607. package/dist/lifeops/entities/voice-observer-bridge.js +68 -0
  608. package/dist/lifeops/entities/voice-observer-bridge.js.map +1 -0
  609. package/dist/lifeops/entities/voice-observer.d.ts +72 -0
  610. package/dist/lifeops/entities/voice-observer.d.ts.map +1 -0
  611. package/dist/lifeops/entities/voice-observer.js +97 -0
  612. package/dist/lifeops/entities/voice-observer.js.map +1 -0
  613. package/dist/lifeops/escalation-ladders.d.ts +28 -0
  614. package/dist/lifeops/escalation-ladders.d.ts.map +1 -0
  615. package/dist/lifeops/escalation-ladders.js +17 -0
  616. package/dist/lifeops/escalation-ladders.js.map +1 -0
  617. package/dist/lifeops/fda-probe.d.ts +23 -0
  618. package/dist/lifeops/fda-probe.d.ts.map +1 -0
  619. package/dist/lifeops/fda-probe.js +59 -0
  620. package/dist/lifeops/fda-probe.js.map +1 -0
  621. package/dist/lifeops/feature-flags.d.ts +24 -0
  622. package/dist/lifeops/feature-flags.d.ts.map +1 -0
  623. package/dist/lifeops/feature-flags.js +261 -0
  624. package/dist/lifeops/feature-flags.js.map +1 -0
  625. package/dist/lifeops/feature-flags.types.d.ts +156 -0
  626. package/dist/lifeops/feature-flags.types.d.ts.map +1 -0
  627. package/dist/lifeops/feature-flags.types.js +129 -0
  628. package/dist/lifeops/feature-flags.types.js.map +1 -0
  629. package/dist/lifeops/first-run/defaults.d.ts +57 -0
  630. package/dist/lifeops/first-run/defaults.d.ts.map +1 -0
  631. package/dist/lifeops/first-run/defaults.js +159 -0
  632. package/dist/lifeops/first-run/defaults.js.map +1 -0
  633. package/dist/lifeops/first-run/questions.d.ts +74 -0
  634. package/dist/lifeops/first-run/questions.d.ts.map +1 -0
  635. package/dist/lifeops/first-run/questions.js +184 -0
  636. package/dist/lifeops/first-run/questions.js.map +1 -0
  637. package/dist/lifeops/first-run/replay.d.ts +41 -0
  638. package/dist/lifeops/first-run/replay.d.ts.map +1 -0
  639. package/dist/lifeops/first-run/replay.js +34 -0
  640. package/dist/lifeops/first-run/replay.js.map +1 -0
  641. package/dist/lifeops/first-run/service.d.ts +147 -0
  642. package/dist/lifeops/first-run/service.d.ts.map +1 -0
  643. package/dist/lifeops/first-run/service.js +455 -0
  644. package/dist/lifeops/first-run/service.js.map +1 -0
  645. package/dist/lifeops/first-run/state.d.ts +36 -0
  646. package/dist/lifeops/first-run/state.d.ts.map +1 -0
  647. package/dist/lifeops/first-run/state.js +128 -0
  648. package/dist/lifeops/first-run/state.js.map +1 -0
  649. package/dist/lifeops/global-pause/store.d.ts +22 -0
  650. package/dist/lifeops/global-pause/store.d.ts.map +1 -0
  651. package/dist/lifeops/global-pause/store.js +18 -0
  652. package/dist/lifeops/global-pause/store.js.map +1 -0
  653. package/dist/lifeops/goal-grounding.d.ts +9 -0
  654. package/dist/lifeops/goal-grounding.d.ts.map +1 -0
  655. package/dist/lifeops/goal-grounding.js +19 -0
  656. package/dist/lifeops/goal-grounding.js.map +1 -0
  657. package/dist/lifeops/goal-semantic-evaluator.d.ts +8 -0
  658. package/dist/lifeops/goal-semantic-evaluator.d.ts.map +1 -0
  659. package/dist/lifeops/goal-semantic-evaluator.js +7 -0
  660. package/dist/lifeops/goal-semantic-evaluator.js.map +1 -0
  661. package/dist/lifeops/google/format-helpers.d.ts +63 -0
  662. package/dist/lifeops/google/format-helpers.d.ts.map +1 -0
  663. package/dist/lifeops/google/format-helpers.js +597 -0
  664. package/dist/lifeops/google/format-helpers.js.map +1 -0
  665. package/dist/lifeops/google-plugin-delegates.d.ts +59 -0
  666. package/dist/lifeops/google-plugin-delegates.d.ts.map +1 -0
  667. package/dist/lifeops/google-plugin-delegates.js +408 -0
  668. package/dist/lifeops/google-plugin-delegates.js.map +1 -0
  669. package/dist/lifeops/google-scopes.d.ts +15 -0
  670. package/dist/lifeops/google-scopes.d.ts.map +1 -0
  671. package/dist/lifeops/google-scopes.js +118 -0
  672. package/dist/lifeops/google-scopes.js.map +1 -0
  673. package/dist/lifeops/handoff/store.d.ts +23 -0
  674. package/dist/lifeops/handoff/store.d.ts.map +1 -0
  675. package/dist/lifeops/handoff/store.js +20 -0
  676. package/dist/lifeops/handoff/store.js.map +1 -0
  677. package/dist/lifeops/i18n/localized-examples-provider.d.ts +16 -0
  678. package/dist/lifeops/i18n/localized-examples-provider.d.ts.map +1 -0
  679. package/dist/lifeops/i18n/localized-examples-provider.js +33 -0
  680. package/dist/lifeops/i18n/localized-examples-provider.js.map +1 -0
  681. package/dist/lifeops/i18n/localized-examples-resolver.d.ts +32 -0
  682. package/dist/lifeops/i18n/localized-examples-resolver.d.ts.map +1 -0
  683. package/dist/lifeops/i18n/localized-examples-resolver.js +28 -0
  684. package/dist/lifeops/i18n/localized-examples-resolver.js.map +1 -0
  685. package/dist/lifeops/i18n/prompt-registry.d.ts +64 -0
  686. package/dist/lifeops/i18n/prompt-registry.d.ts.map +1 -0
  687. package/dist/lifeops/i18n/prompt-registry.js +283 -0
  688. package/dist/lifeops/i18n/prompt-registry.js.map +1 -0
  689. package/dist/lifeops/imessage-outbound-probe.d.ts +7 -0
  690. package/dist/lifeops/imessage-outbound-probe.d.ts.map +1 -0
  691. package/dist/lifeops/imessage-outbound-probe.js +81 -0
  692. package/dist/lifeops/imessage-outbound-probe.js.map +1 -0
  693. package/dist/lifeops/index.d.ts +24 -0
  694. package/dist/lifeops/index.d.ts.map +1 -0
  695. package/dist/lifeops/index.js +24 -0
  696. package/dist/lifeops/index.js.map +1 -0
  697. package/dist/lifeops/intent-sync.d.ts +64 -0
  698. package/dist/lifeops/intent-sync.d.ts.map +1 -0
  699. package/dist/lifeops/intent-sync.js +321 -0
  700. package/dist/lifeops/intent-sync.js.map +1 -0
  701. package/dist/lifeops/messaging/index.d.ts +2 -0
  702. package/dist/lifeops/messaging/index.d.ts.map +1 -0
  703. package/dist/lifeops/messaging/index.js +5 -0
  704. package/dist/lifeops/messaging/index.js.map +1 -0
  705. package/dist/lifeops/messaging/owner-send-policy.d.ts +3 -0
  706. package/dist/lifeops/messaging/owner-send-policy.d.ts.map +1 -0
  707. package/dist/lifeops/messaging/owner-send-policy.js +83 -0
  708. package/dist/lifeops/messaging/owner-send-policy.js.map +1 -0
  709. package/dist/lifeops/notifications-push.d.ts +37 -0
  710. package/dist/lifeops/notifications-push.d.ts.map +1 -0
  711. package/dist/lifeops/notifications-push.js +95 -0
  712. package/dist/lifeops/notifications-push.js.map +1 -0
  713. package/dist/lifeops/optimized-prompt-instructions.d.ts +5 -0
  714. package/dist/lifeops/optimized-prompt-instructions.d.ts.map +1 -0
  715. package/dist/lifeops/optimized-prompt-instructions.js +48 -0
  716. package/dist/lifeops/optimized-prompt-instructions.js.map +1 -0
  717. package/dist/lifeops/owner/fact-store.d.ts +143 -0
  718. package/dist/lifeops/owner/fact-store.d.ts.map +1 -0
  719. package/dist/lifeops/owner/fact-store.js +446 -0
  720. package/dist/lifeops/owner/fact-store.js.map +1 -0
  721. package/dist/lifeops/owner/profile-extraction-evaluator.d.ts +3 -0
  722. package/dist/lifeops/owner/profile-extraction-evaluator.d.ts.map +1 -0
  723. package/dist/lifeops/owner/profile-extraction-evaluator.js +241 -0
  724. package/dist/lifeops/owner/profile-extraction-evaluator.js.map +1 -0
  725. package/dist/lifeops/owner-profile.d.ts +61 -0
  726. package/dist/lifeops/owner-profile.d.ts.map +1 -0
  727. package/dist/lifeops/owner-profile.js +407 -0
  728. package/dist/lifeops/owner-profile.js.map +1 -0
  729. package/dist/lifeops/pending-prompts/store.d.ts +23 -0
  730. package/dist/lifeops/pending-prompts/store.d.ts.map +1 -0
  731. package/dist/lifeops/pending-prompts/store.js +16 -0
  732. package/dist/lifeops/pending-prompts/store.js.map +1 -0
  733. package/dist/lifeops/policy-memory.d.ts +190 -0
  734. package/dist/lifeops/policy-memory.d.ts.map +1 -0
  735. package/dist/lifeops/policy-memory.js +1026 -0
  736. package/dist/lifeops/policy-memory.js.map +1 -0
  737. package/dist/lifeops/priority-scoring.d.ts +51 -0
  738. package/dist/lifeops/priority-scoring.d.ts.map +1 -0
  739. package/dist/lifeops/priority-scoring.js +305 -0
  740. package/dist/lifeops/priority-scoring.js.map +1 -0
  741. package/dist/lifeops/privacy-egress.d.ts +92 -0
  742. package/dist/lifeops/privacy-egress.d.ts.map +1 -0
  743. package/dist/lifeops/privacy-egress.js +230 -0
  744. package/dist/lifeops/privacy-egress.js.map +1 -0
  745. package/dist/lifeops/privacy.d.ts +49 -0
  746. package/dist/lifeops/privacy.d.ts.map +1 -0
  747. package/dist/lifeops/privacy.js +66 -0
  748. package/dist/lifeops/privacy.js.map +1 -0
  749. package/dist/lifeops/redact-sensitive-data.d.ts +32 -0
  750. package/dist/lifeops/redact-sensitive-data.d.ts.map +1 -0
  751. package/dist/lifeops/redact-sensitive-data.js +98 -0
  752. package/dist/lifeops/redact-sensitive-data.js.map +1 -0
  753. package/dist/lifeops/registries/app-blocker-contribution.d.ts +13 -0
  754. package/dist/lifeops/registries/app-blocker-contribution.d.ts.map +1 -0
  755. package/dist/lifeops/registries/app-blocker-contribution.js +73 -0
  756. package/dist/lifeops/registries/app-blocker-contribution.js.map +1 -0
  757. package/dist/lifeops/registries/blocker-registry.d.ts +76 -0
  758. package/dist/lifeops/registries/blocker-registry.d.ts.map +1 -0
  759. package/dist/lifeops/registries/blocker-registry.js +40 -0
  760. package/dist/lifeops/registries/blocker-registry.js.map +1 -0
  761. package/dist/lifeops/registries/event-kind-registry.d.ts +57 -0
  762. package/dist/lifeops/registries/event-kind-registry.d.ts.map +1 -0
  763. package/dist/lifeops/registries/event-kind-registry.js +82 -0
  764. package/dist/lifeops/registries/event-kind-registry.js.map +1 -0
  765. package/dist/lifeops/registries/family-registry.d.ts +72 -0
  766. package/dist/lifeops/registries/family-registry.d.ts.map +1 -0
  767. package/dist/lifeops/registries/family-registry.js +98 -0
  768. package/dist/lifeops/registries/family-registry.js.map +1 -0
  769. package/dist/lifeops/registries/feature-flag-default-pack.d.ts +32 -0
  770. package/dist/lifeops/registries/feature-flag-default-pack.d.ts.map +1 -0
  771. package/dist/lifeops/registries/feature-flag-default-pack.js +36 -0
  772. package/dist/lifeops/registries/feature-flag-default-pack.js.map +1 -0
  773. package/dist/lifeops/registries/feature-flag-registry.d.ts +76 -0
  774. package/dist/lifeops/registries/feature-flag-registry.d.ts.map +1 -0
  775. package/dist/lifeops/registries/feature-flag-registry.js +68 -0
  776. package/dist/lifeops/registries/feature-flag-registry.js.map +1 -0
  777. package/dist/lifeops/registries/index.d.ts +24 -0
  778. package/dist/lifeops/registries/index.d.ts.map +1 -0
  779. package/dist/lifeops/registries/index.js +115 -0
  780. package/dist/lifeops/registries/index.js.map +1 -0
  781. package/dist/lifeops/registries/website-blocker-contribution.d.ts +21 -0
  782. package/dist/lifeops/registries/website-blocker-contribution.d.ts.map +1 -0
  783. package/dist/lifeops/registries/website-blocker-contribution.js +76 -0
  784. package/dist/lifeops/registries/website-blocker-contribution.js.map +1 -0
  785. package/dist/lifeops/registries/workflow-step-default-pack.d.ts +30 -0
  786. package/dist/lifeops/registries/workflow-step-default-pack.d.ts.map +1 -0
  787. package/dist/lifeops/registries/workflow-step-default-pack.js +315 -0
  788. package/dist/lifeops/registries/workflow-step-default-pack.js.map +1 -0
  789. package/dist/lifeops/registries/workflow-step-registry.d.ts +101 -0
  790. package/dist/lifeops/registries/workflow-step-registry.d.ts.map +1 -0
  791. package/dist/lifeops/registries/workflow-step-registry.js +56 -0
  792. package/dist/lifeops/registries/workflow-step-registry.js.map +1 -0
  793. package/dist/lifeops/relationships/extraction.d.ts +77 -0
  794. package/dist/lifeops/relationships/extraction.d.ts.map +1 -0
  795. package/dist/lifeops/relationships/extraction.js +146 -0
  796. package/dist/lifeops/relationships/extraction.js.map +1 -0
  797. package/dist/lifeops/relationships/index.d.ts +4 -0
  798. package/dist/lifeops/relationships/index.d.ts.map +1 -0
  799. package/dist/lifeops/relationships/index.js +19 -0
  800. package/dist/lifeops/relationships/index.js.map +1 -0
  801. package/dist/lifeops/relationships/mapping.d.ts +34 -0
  802. package/dist/lifeops/relationships/mapping.d.ts.map +1 -0
  803. package/dist/lifeops/relationships/mapping.js +87 -0
  804. package/dist/lifeops/relationships/mapping.js.map +1 -0
  805. package/dist/lifeops/relationships/store.d.ts +12 -0
  806. package/dist/lifeops/relationships/store.d.ts.map +1 -0
  807. package/dist/lifeops/relationships/store.js +5 -0
  808. package/dist/lifeops/relationships/store.js.map +1 -0
  809. package/dist/lifeops/relationships/types.d.ts +9 -0
  810. package/dist/lifeops/relationships/types.d.ts.map +1 -0
  811. package/dist/lifeops/relationships/types.js +11 -0
  812. package/dist/lifeops/relationships/types.js.map +1 -0
  813. package/dist/lifeops/relative-schedule-resolver.d.ts +13 -0
  814. package/dist/lifeops/relative-schedule-resolver.d.ts.map +1 -0
  815. package/dist/lifeops/relative-schedule-resolver.js +107 -0
  816. package/dist/lifeops/relative-schedule-resolver.js.map +1 -0
  817. package/dist/lifeops/relative-time.d.ts +15 -0
  818. package/dist/lifeops/relative-time.d.ts.map +1 -0
  819. package/dist/lifeops/relative-time.js +191 -0
  820. package/dist/lifeops/relative-time.js.map +1 -0
  821. package/dist/lifeops/repository.d.ts +638 -0
  822. package/dist/lifeops/repository.d.ts.map +1 -0
  823. package/dist/lifeops/repository.js +6289 -0
  824. package/dist/lifeops/repository.js.map +1 -0
  825. package/dist/lifeops/runtime-cache.d.ts +4 -0
  826. package/dist/lifeops/runtime-cache.d.ts.map +1 -0
  827. package/dist/lifeops/runtime-cache.js +7 -0
  828. package/dist/lifeops/runtime-cache.js.map +1 -0
  829. package/dist/lifeops/runtime-service-delegates.d.ts +236 -0
  830. package/dist/lifeops/runtime-service-delegates.d.ts.map +1 -0
  831. package/dist/lifeops/runtime-service-delegates.js +839 -0
  832. package/dist/lifeops/runtime-service-delegates.js.map +1 -0
  833. package/dist/lifeops/runtime.d.ts +13 -0
  834. package/dist/lifeops/runtime.d.ts.map +1 -0
  835. package/dist/lifeops/runtime.js +104 -0
  836. package/dist/lifeops/runtime.js.map +1 -0
  837. package/dist/lifeops/schedule-insight.d.ts +133 -0
  838. package/dist/lifeops/schedule-insight.d.ts.map +1 -0
  839. package/dist/lifeops/schedule-insight.js +726 -0
  840. package/dist/lifeops/schedule-insight.js.map +1 -0
  841. package/dist/lifeops/schedule-state.d.ts +39 -0
  842. package/dist/lifeops/schedule-state.d.ts.map +1 -0
  843. package/dist/lifeops/schedule-state.js +671 -0
  844. package/dist/lifeops/schedule-state.js.map +1 -0
  845. package/dist/lifeops/schedule-sync-config.d.ts +3 -0
  846. package/dist/lifeops/schedule-sync-config.d.ts.map +1 -0
  847. package/dist/lifeops/schedule-sync-config.js +23 -0
  848. package/dist/lifeops/schedule-sync-config.js.map +1 -0
  849. package/dist/lifeops/schedule-sync-contracts.d.ts +2 -0
  850. package/dist/lifeops/schedule-sync-contracts.d.ts.map +1 -0
  851. package/dist/lifeops/schedule-sync-contracts.js +2 -0
  852. package/dist/lifeops/schedule-sync-contracts.js.map +1 -0
  853. package/dist/lifeops/scheduled-task/index.d.ts +13 -0
  854. package/dist/lifeops/scheduled-task/index.d.ts.map +1 -0
  855. package/dist/lifeops/scheduled-task/index.js +14 -0
  856. package/dist/lifeops/scheduled-task/index.js.map +1 -0
  857. package/dist/lifeops/scheduled-task/runtime-wiring.d.ts +33 -0
  858. package/dist/lifeops/scheduled-task/runtime-wiring.d.ts.map +1 -0
  859. package/dist/lifeops/scheduled-task/runtime-wiring.js +334 -0
  860. package/dist/lifeops/scheduled-task/runtime-wiring.js.map +1 -0
  861. package/dist/lifeops/scheduled-task/scheduler.d.ts +28 -0
  862. package/dist/lifeops/scheduled-task/scheduler.d.ts.map +1 -0
  863. package/dist/lifeops/scheduled-task/scheduler.js +202 -0
  864. package/dist/lifeops/scheduled-task/scheduler.js.map +1 -0
  865. package/dist/lifeops/scheduled-task/service.d.ts +61 -0
  866. package/dist/lifeops/scheduled-task/service.d.ts.map +1 -0
  867. package/dist/lifeops/scheduled-task/service.js +64 -0
  868. package/dist/lifeops/scheduled-task/service.js.map +1 -0
  869. package/dist/lifeops/scheduler-task.d.ts +19 -0
  870. package/dist/lifeops/scheduler-task.d.ts.map +1 -0
  871. package/dist/lifeops/scheduler-task.js +201 -0
  872. package/dist/lifeops/scheduler-task.js.map +1 -0
  873. package/dist/lifeops/schema.d.ts +28068 -0
  874. package/dist/lifeops/schema.d.ts.map +1 -0
  875. package/dist/lifeops/schema.js +1689 -0
  876. package/dist/lifeops/schema.js.map +1 -0
  877. package/dist/lifeops/screen-context.d.ts +66 -0
  878. package/dist/lifeops/screen-context.d.ts.map +1 -0
  879. package/dist/lifeops/screen-context.js +347 -0
  880. package/dist/lifeops/screen-context.js.map +1 -0
  881. package/dist/lifeops/seed-routine-migration/migrator.d.ts +113 -0
  882. package/dist/lifeops/seed-routine-migration/migrator.d.ts.map +1 -0
  883. package/dist/lifeops/seed-routine-migration/migrator.js +142 -0
  884. package/dist/lifeops/seed-routine-migration/migrator.js.map +1 -0
  885. package/dist/lifeops/seed-routines.d.ts +24 -0
  886. package/dist/lifeops/seed-routines.d.ts.map +1 -0
  887. package/dist/lifeops/seed-routines.js +140 -0
  888. package/dist/lifeops/seed-routines.js.map +1 -0
  889. package/dist/lifeops/send-policy/contract.d.ts +81 -0
  890. package/dist/lifeops/send-policy/contract.d.ts.map +1 -0
  891. package/dist/lifeops/send-policy/contract.js +1 -0
  892. package/dist/lifeops/send-policy/contract.js.map +1 -0
  893. package/dist/lifeops/send-policy/index.d.ts +3 -0
  894. package/dist/lifeops/send-policy/index.d.ts.map +1 -0
  895. package/dist/lifeops/send-policy/index.js +13 -0
  896. package/dist/lifeops/send-policy/index.js.map +1 -0
  897. package/dist/lifeops/send-policy/registry.d.ts +7 -0
  898. package/dist/lifeops/send-policy/registry.d.ts.map +1 -0
  899. package/dist/lifeops/send-policy/registry.js +62 -0
  900. package/dist/lifeops/send-policy/registry.js.map +1 -0
  901. package/dist/lifeops/sensitive-request-delivery.d.ts +46 -0
  902. package/dist/lifeops/sensitive-request-delivery.d.ts.map +1 -0
  903. package/dist/lifeops/sensitive-request-delivery.js +103 -0
  904. package/dist/lifeops/sensitive-request-delivery.js.map +1 -0
  905. package/dist/lifeops/service-constants.d.ts +10 -0
  906. package/dist/lifeops/service-constants.d.ts.map +1 -0
  907. package/dist/lifeops/service-constants.js +129 -0
  908. package/dist/lifeops/service-constants.js.map +1 -0
  909. package/dist/lifeops/service-helpers-browser.d.ts +41 -0
  910. package/dist/lifeops/service-helpers-browser.d.ts.map +1 -0
  911. package/dist/lifeops/service-helpers-browser.js +290 -0
  912. package/dist/lifeops/service-helpers-browser.js.map +1 -0
  913. package/dist/lifeops/service-helpers-misc.d.ts +68 -0
  914. package/dist/lifeops/service-helpers-misc.d.ts.map +1 -0
  915. package/dist/lifeops/service-helpers-misc.js +531 -0
  916. package/dist/lifeops/service-helpers-misc.js.map +1 -0
  917. package/dist/lifeops/service-helpers-occurrence.d.ts +23 -0
  918. package/dist/lifeops/service-helpers-occurrence.d.ts.map +1 -0
  919. package/dist/lifeops/service-helpers-occurrence.js +257 -0
  920. package/dist/lifeops/service-helpers-occurrence.js.map +1 -0
  921. package/dist/lifeops/service-helpers-reminder.d.ts +260 -0
  922. package/dist/lifeops/service-helpers-reminder.d.ts.map +1 -0
  923. package/dist/lifeops/service-helpers-reminder.js +1186 -0
  924. package/dist/lifeops/service-helpers-reminder.js.map +1 -0
  925. package/dist/lifeops/service-mixin-browser.d.ts +31 -0
  926. package/dist/lifeops/service-mixin-browser.d.ts.map +1 -0
  927. package/dist/lifeops/service-mixin-browser.js +975 -0
  928. package/dist/lifeops/service-mixin-browser.js.map +1 -0
  929. package/dist/lifeops/service-mixin-calendar.d.ts +53 -0
  930. package/dist/lifeops/service-mixin-calendar.d.ts.map +1 -0
  931. package/dist/lifeops/service-mixin-calendar.js +68 -0
  932. package/dist/lifeops/service-mixin-calendar.js.map +1 -0
  933. package/dist/lifeops/service-mixin-core.d.ts +51 -0
  934. package/dist/lifeops/service-mixin-core.d.ts.map +1 -0
  935. package/dist/lifeops/service-mixin-core.js +500 -0
  936. package/dist/lifeops/service-mixin-core.js.map +1 -0
  937. package/dist/lifeops/service-mixin-definitions.d.ts +14 -0
  938. package/dist/lifeops/service-mixin-definitions.d.ts.map +1 -0
  939. package/dist/lifeops/service-mixin-definitions.js +470 -0
  940. package/dist/lifeops/service-mixin-definitions.js.map +1 -0
  941. package/dist/lifeops/service-mixin-discord.d.ts +49 -0
  942. package/dist/lifeops/service-mixin-discord.d.ts.map +1 -0
  943. package/dist/lifeops/service-mixin-discord.js +1253 -0
  944. package/dist/lifeops/service-mixin-discord.js.map +1 -0
  945. package/dist/lifeops/service-mixin-drive.d.ts +96 -0
  946. package/dist/lifeops/service-mixin-drive.d.ts.map +1 -0
  947. package/dist/lifeops/service-mixin-drive.js +213 -0
  948. package/dist/lifeops/service-mixin-drive.js.map +1 -0
  949. package/dist/lifeops/service-mixin-email-unsubscribe.d.ts +23 -0
  950. package/dist/lifeops/service-mixin-email-unsubscribe.d.ts.map +1 -0
  951. package/dist/lifeops/service-mixin-email-unsubscribe.js +27 -0
  952. package/dist/lifeops/service-mixin-email-unsubscribe.js.map +1 -0
  953. package/dist/lifeops/service-mixin-gmail.d.ts +43 -0
  954. package/dist/lifeops/service-mixin-gmail.d.ts.map +1 -0
  955. package/dist/lifeops/service-mixin-gmail.js +727 -0
  956. package/dist/lifeops/service-mixin-gmail.js.map +1 -0
  957. package/dist/lifeops/service-mixin-goals.d.ts +22 -0
  958. package/dist/lifeops/service-mixin-goals.d.ts.map +1 -0
  959. package/dist/lifeops/service-mixin-goals.js +884 -0
  960. package/dist/lifeops/service-mixin-goals.js.map +1 -0
  961. package/dist/lifeops/service-mixin-google.d.ts +13 -0
  962. package/dist/lifeops/service-mixin-google.d.ts.map +1 -0
  963. package/dist/lifeops/service-mixin-google.js +398 -0
  964. package/dist/lifeops/service-mixin-google.js.map +1 -0
  965. package/dist/lifeops/service-mixin-health.d.ts +27 -0
  966. package/dist/lifeops/service-mixin-health.d.ts.map +1 -0
  967. package/dist/lifeops/service-mixin-health.js +670 -0
  968. package/dist/lifeops/service-mixin-health.js.map +1 -0
  969. package/dist/lifeops/service-mixin-imessage.d.ts +106 -0
  970. package/dist/lifeops/service-mixin-imessage.d.ts.map +1 -0
  971. package/dist/lifeops/service-mixin-imessage.js +303 -0
  972. package/dist/lifeops/service-mixin-imessage.js.map +1 -0
  973. package/dist/lifeops/service-mixin-inbox.d.ts +55 -0
  974. package/dist/lifeops/service-mixin-inbox.d.ts.map +1 -0
  975. package/dist/lifeops/service-mixin-inbox.js +597 -0
  976. package/dist/lifeops/service-mixin-inbox.js.map +1 -0
  977. package/dist/lifeops/service-mixin-relationships.d.ts +65 -0
  978. package/dist/lifeops/service-mixin-relationships.d.ts.map +1 -0
  979. package/dist/lifeops/service-mixin-relationships.js +150 -0
  980. package/dist/lifeops/service-mixin-relationships.js.map +1 -0
  981. package/dist/lifeops/service-mixin-reminders.d.ts +62 -0
  982. package/dist/lifeops/service-mixin-reminders.d.ts.map +1 -0
  983. package/dist/lifeops/service-mixin-reminders.js +4003 -0
  984. package/dist/lifeops/service-mixin-reminders.js.map +1 -0
  985. package/dist/lifeops/service-mixin-scheduling.d.ts +53 -0
  986. package/dist/lifeops/service-mixin-scheduling.d.ts.map +1 -0
  987. package/dist/lifeops/service-mixin-scheduling.js +405 -0
  988. package/dist/lifeops/service-mixin-scheduling.js.map +1 -0
  989. package/dist/lifeops/service-mixin-screentime.d.ts +71 -0
  990. package/dist/lifeops/service-mixin-screentime.d.ts.map +1 -0
  991. package/dist/lifeops/service-mixin-screentime.js +530 -0
  992. package/dist/lifeops/service-mixin-screentime.js.map +1 -0
  993. package/dist/lifeops/service-mixin-signal.d.ts +74 -0
  994. package/dist/lifeops/service-mixin-signal.d.ts.map +1 -0
  995. package/dist/lifeops/service-mixin-signal.js +214 -0
  996. package/dist/lifeops/service-mixin-signal.js.map +1 -0
  997. package/dist/lifeops/service-mixin-sleep.d.ts +68 -0
  998. package/dist/lifeops/service-mixin-sleep.d.ts.map +1 -0
  999. package/dist/lifeops/service-mixin-sleep.js +43 -0
  1000. package/dist/lifeops/service-mixin-sleep.js.map +1 -0
  1001. package/dist/lifeops/service-mixin-status.d.ts +31 -0
  1002. package/dist/lifeops/service-mixin-status.d.ts.map +1 -0
  1003. package/dist/lifeops/service-mixin-status.js +373 -0
  1004. package/dist/lifeops/service-mixin-status.js.map +1 -0
  1005. package/dist/lifeops/service-mixin-subscriptions.d.ts +101 -0
  1006. package/dist/lifeops/service-mixin-subscriptions.d.ts.map +1 -0
  1007. package/dist/lifeops/service-mixin-subscriptions.js +50 -0
  1008. package/dist/lifeops/service-mixin-subscriptions.js.map +1 -0
  1009. package/dist/lifeops/service-mixin-telegram.d.ts +104 -0
  1010. package/dist/lifeops/service-mixin-telegram.d.ts.map +1 -0
  1011. package/dist/lifeops/service-mixin-telegram.js +280 -0
  1012. package/dist/lifeops/service-mixin-telegram.js.map +1 -0
  1013. package/dist/lifeops/service-mixin-travel.d.ts +66 -0
  1014. package/dist/lifeops/service-mixin-travel.d.ts.map +1 -0
  1015. package/dist/lifeops/service-mixin-travel.js +275 -0
  1016. package/dist/lifeops/service-mixin-travel.js.map +1 -0
  1017. package/dist/lifeops/service-mixin-whatsapp.d.ts +96 -0
  1018. package/dist/lifeops/service-mixin-whatsapp.d.ts.map +1 -0
  1019. package/dist/lifeops/service-mixin-whatsapp.js +186 -0
  1020. package/dist/lifeops/service-mixin-whatsapp.js.map +1 -0
  1021. package/dist/lifeops/service-mixin-workflows.d.ts +15 -0
  1022. package/dist/lifeops/service-mixin-workflows.d.ts.map +1 -0
  1023. package/dist/lifeops/service-mixin-workflows.js +710 -0
  1024. package/dist/lifeops/service-mixin-workflows.js.map +1 -0
  1025. package/dist/lifeops/service-mixin-x-read.d.ts +31 -0
  1026. package/dist/lifeops/service-mixin-x-read.d.ts.map +1 -0
  1027. package/dist/lifeops/service-mixin-x-read.js +267 -0
  1028. package/dist/lifeops/service-mixin-x-read.js.map +1 -0
  1029. package/dist/lifeops/service-mixin-x.d.ts +66 -0
  1030. package/dist/lifeops/service-mixin-x.d.ts.map +1 -0
  1031. package/dist/lifeops/service-mixin-x.js +501 -0
  1032. package/dist/lifeops/service-mixin-x.js.map +1 -0
  1033. package/dist/lifeops/service-normalize-connector.d.ts +19 -0
  1034. package/dist/lifeops/service-normalize-connector.d.ts.map +1 -0
  1035. package/dist/lifeops/service-normalize-connector.js +816 -0
  1036. package/dist/lifeops/service-normalize-connector.js.map +1 -0
  1037. package/dist/lifeops/service-normalize-gmail.d.ts +11 -0
  1038. package/dist/lifeops/service-normalize-gmail.d.ts.map +1 -0
  1039. package/dist/lifeops/service-normalize-gmail.js +85 -0
  1040. package/dist/lifeops/service-normalize-gmail.js.map +1 -0
  1041. package/dist/lifeops/service-normalize-task.d.ts +9 -0
  1042. package/dist/lifeops/service-normalize-task.d.ts.map +1 -0
  1043. package/dist/lifeops/service-normalize-task.js +567 -0
  1044. package/dist/lifeops/service-normalize-task.js.map +1 -0
  1045. package/dist/lifeops/service-normalize.d.ts +9 -0
  1046. package/dist/lifeops/service-normalize.d.ts.map +1 -0
  1047. package/dist/lifeops/service-normalize.js +53 -0
  1048. package/dist/lifeops/service-normalize.js.map +1 -0
  1049. package/dist/lifeops/service-types.d.ts +75 -0
  1050. package/dist/lifeops/service-types.d.ts.map +1 -0
  1051. package/dist/lifeops/service-types.js +5 -0
  1052. package/dist/lifeops/service-types.js.map +1 -0
  1053. package/dist/lifeops/service.d.ts +482 -0
  1054. package/dist/lifeops/service.d.ts.map +1 -0
  1055. package/dist/lifeops/service.js +62 -0
  1056. package/dist/lifeops/service.js.map +1 -0
  1057. package/dist/lifeops/signal-runtime-config.d.ts +13 -0
  1058. package/dist/lifeops/signal-runtime-config.d.ts.map +1 -0
  1059. package/dist/lifeops/signal-runtime-config.js +44 -0
  1060. package/dist/lifeops/signal-runtime-config.js.map +1 -0
  1061. package/dist/lifeops/signals/bus.d.ts +78 -0
  1062. package/dist/lifeops/signals/bus.d.ts.map +1 -0
  1063. package/dist/lifeops/signals/bus.js +117 -0
  1064. package/dist/lifeops/signals/bus.js.map +1 -0
  1065. package/dist/lifeops/sql.d.ts +65 -0
  1066. package/dist/lifeops/sql.d.ts.map +1 -0
  1067. package/dist/lifeops/sql.js +182 -0
  1068. package/dist/lifeops/sql.js.map +1 -0
  1069. package/dist/lifeops/stretch-decider.d.ts +73 -0
  1070. package/dist/lifeops/stretch-decider.d.ts.map +1 -0
  1071. package/dist/lifeops/stretch-decider.js +49 -0
  1072. package/dist/lifeops/stretch-decider.js.map +1 -0
  1073. package/dist/lifeops/telemetry-mapping.d.ts +14 -0
  1074. package/dist/lifeops/telemetry-mapping.d.ts.map +1 -0
  1075. package/dist/lifeops/telemetry-mapping.js +115 -0
  1076. package/dist/lifeops/telemetry-mapping.js.map +1 -0
  1077. package/dist/lifeops/telemetry-retention.d.ts +21 -0
  1078. package/dist/lifeops/telemetry-retention.d.ts.map +1 -0
  1079. package/dist/lifeops/telemetry-retention.js +13 -0
  1080. package/dist/lifeops/telemetry-retention.js.map +1 -0
  1081. package/dist/lifeops/time/timezone.d.ts +4 -0
  1082. package/dist/lifeops/time/timezone.d.ts.map +1 -0
  1083. package/dist/lifeops/time/timezone.js +154 -0
  1084. package/dist/lifeops/time/timezone.js.map +1 -0
  1085. package/dist/lifeops/time-util.d.ts +10 -0
  1086. package/dist/lifeops/time-util.d.ts.map +1 -0
  1087. package/dist/lifeops/time-util.js +14 -0
  1088. package/dist/lifeops/time-util.js.map +1 -0
  1089. package/dist/lifeops/time.d.ts +17 -0
  1090. package/dist/lifeops/time.d.ts.map +1 -0
  1091. package/dist/lifeops/time.js +152 -0
  1092. package/dist/lifeops/time.js.map +1 -0
  1093. package/dist/lifeops/travel-booking.types.d.ts +46 -0
  1094. package/dist/lifeops/travel-booking.types.d.ts.map +1 -0
  1095. package/dist/lifeops/travel-booking.types.js +1 -0
  1096. package/dist/lifeops/travel-booking.types.js.map +1 -0
  1097. package/dist/lifeops/triggers/schedule-once.d.ts +19 -0
  1098. package/dist/lifeops/triggers/schedule-once.d.ts.map +1 -0
  1099. package/dist/lifeops/triggers/schedule-once.js +99 -0
  1100. package/dist/lifeops/triggers/schedule-once.js.map +1 -0
  1101. package/dist/lifeops/validate/coding-task-request.d.ts +18 -0
  1102. package/dist/lifeops/validate/coding-task-request.d.ts.map +1 -0
  1103. package/dist/lifeops/validate/coding-task-request.js +16 -0
  1104. package/dist/lifeops/validate/coding-task-request.js.map +1 -0
  1105. package/dist/lifeops/voice/grounded-reply.d.ts +41 -0
  1106. package/dist/lifeops/voice/grounded-reply.d.ts.map +1 -0
  1107. package/dist/lifeops/voice/grounded-reply.js +24 -0
  1108. package/dist/lifeops/voice/grounded-reply.js.map +1 -0
  1109. package/dist/lifeops/voice-affect.d.ts +79 -0
  1110. package/dist/lifeops/voice-affect.d.ts.map +1 -0
  1111. package/dist/lifeops/voice-affect.js +253 -0
  1112. package/dist/lifeops/voice-affect.js.map +1 -0
  1113. package/dist/lifeops/wave1-types.d.ts +125 -0
  1114. package/dist/lifeops/wave1-types.d.ts.map +1 -0
  1115. package/dist/lifeops/wave1-types.js +1 -0
  1116. package/dist/lifeops/wave1-types.js.map +1 -0
  1117. package/dist/lifeops/work-threads/field-evaluator-thread-ops.d.ts +33 -0
  1118. package/dist/lifeops/work-threads/field-evaluator-thread-ops.d.ts.map +1 -0
  1119. package/dist/lifeops/work-threads/field-evaluator-thread-ops.js +226 -0
  1120. package/dist/lifeops/work-threads/field-evaluator-thread-ops.js.map +1 -0
  1121. package/dist/lifeops/work-threads/index.d.ts +3 -0
  1122. package/dist/lifeops/work-threads/index.d.ts.map +1 -0
  1123. package/dist/lifeops/work-threads/index.js +7 -0
  1124. package/dist/lifeops/work-threads/index.js.map +1 -0
  1125. package/dist/lifeops/work-threads/store.d.ts +91 -0
  1126. package/dist/lifeops/work-threads/store.d.ts.map +1 -0
  1127. package/dist/lifeops/work-threads/store.js +245 -0
  1128. package/dist/lifeops/work-threads/store.js.map +1 -0
  1129. package/dist/lifeops/work-threads/types.d.ts +58 -0
  1130. package/dist/lifeops/work-threads/types.d.ts.map +1 -0
  1131. package/dist/lifeops/work-threads/types.js +1 -0
  1132. package/dist/lifeops/work-threads/types.js.map +1 -0
  1133. package/dist/platform/host.d.ts +16 -0
  1134. package/dist/platform/host.d.ts.map +1 -0
  1135. package/dist/platform/host.js +22 -0
  1136. package/dist/platform/host.js.map +1 -0
  1137. package/dist/platform/index.d.ts +3 -0
  1138. package/dist/platform/index.d.ts.map +1 -0
  1139. package/dist/platform/index.js +3 -0
  1140. package/dist/platform/index.js.map +1 -0
  1141. package/dist/platform/lifeops-github.d.ts +15 -0
  1142. package/dist/platform/lifeops-github.d.ts.map +1 -0
  1143. package/dist/platform/lifeops-github.js +146 -0
  1144. package/dist/platform/lifeops-github.js.map +1 -0
  1145. package/dist/plugin.d.ts +106 -0
  1146. package/dist/plugin.d.ts.map +1 -0
  1147. package/dist/plugin.js +989 -0
  1148. package/dist/plugin.js.map +1 -0
  1149. package/dist/provider.d.ts +4 -0
  1150. package/dist/provider.d.ts.map +1 -0
  1151. package/dist/provider.js +108 -0
  1152. package/dist/provider.js.map +1 -0
  1153. package/dist/providers/activity-profile.d.ts +3 -0
  1154. package/dist/providers/activity-profile.d.ts.map +1 -0
  1155. package/dist/providers/activity-profile.js +140 -0
  1156. package/dist/providers/activity-profile.js.map +1 -0
  1157. package/dist/providers/cross-channel-context.d.ts +29 -0
  1158. package/dist/providers/cross-channel-context.d.ts.map +1 -0
  1159. package/dist/providers/cross-channel-context.js +206 -0
  1160. package/dist/providers/cross-channel-context.js.map +1 -0
  1161. package/dist/providers/first-run.d.ts +22 -0
  1162. package/dist/providers/first-run.d.ts.map +1 -0
  1163. package/dist/providers/first-run.js +93 -0
  1164. package/dist/providers/first-run.js.map +1 -0
  1165. package/dist/providers/health.d.ts +2 -0
  1166. package/dist/providers/health.d.ts.map +1 -0
  1167. package/dist/providers/health.js +14 -0
  1168. package/dist/providers/health.js.map +1 -0
  1169. package/dist/providers/inbox-triage.d.ts +3 -0
  1170. package/dist/providers/inbox-triage.d.ts.map +1 -0
  1171. package/dist/providers/inbox-triage.js +134 -0
  1172. package/dist/providers/inbox-triage.js.map +1 -0
  1173. package/dist/providers/lifeops.d.ts +3 -0
  1174. package/dist/providers/lifeops.d.ts.map +1 -0
  1175. package/dist/providers/lifeops.js +548 -0
  1176. package/dist/providers/lifeops.js.map +1 -0
  1177. package/dist/providers/pending-prompts.d.ts +38 -0
  1178. package/dist/providers/pending-prompts.d.ts.map +1 -0
  1179. package/dist/providers/pending-prompts.js +81 -0
  1180. package/dist/providers/pending-prompts.js.map +1 -0
  1181. package/dist/providers/recent-task-states.d.ts +52 -0
  1182. package/dist/providers/recent-task-states.d.ts.map +1 -0
  1183. package/dist/providers/recent-task-states.js +166 -0
  1184. package/dist/providers/recent-task-states.js.map +1 -0
  1185. package/dist/providers/room-policy.d.ts +16 -0
  1186. package/dist/providers/room-policy.d.ts.map +1 -0
  1187. package/dist/providers/room-policy.js +71 -0
  1188. package/dist/providers/room-policy.js.map +1 -0
  1189. package/dist/providers/work-threads.d.ts +3 -0
  1190. package/dist/providers/work-threads.d.ts.map +1 -0
  1191. package/dist/providers/work-threads.js +97 -0
  1192. package/dist/providers/work-threads.js.map +1 -0
  1193. package/dist/public.d.ts +3 -0
  1194. package/dist/public.d.ts.map +1 -0
  1195. package/dist/public.js +17 -0
  1196. package/dist/public.js.map +1 -0
  1197. package/dist/routes/cloud-features-routes.d.ts +9 -0
  1198. package/dist/routes/cloud-features-routes.d.ts.map +1 -0
  1199. package/dist/routes/cloud-features-routes.js +164 -0
  1200. package/dist/routes/cloud-features-routes.js.map +1 -0
  1201. package/dist/routes/entities.d.ts +14 -0
  1202. package/dist/routes/entities.d.ts.map +1 -0
  1203. package/dist/routes/entities.js +203 -0
  1204. package/dist/routes/entities.js.map +1 -0
  1205. package/dist/routes/lifeops-routes.d.ts +20 -0
  1206. package/dist/routes/lifeops-routes.d.ts.map +1 -0
  1207. package/dist/routes/lifeops-routes.js +2337 -0
  1208. package/dist/routes/lifeops-routes.js.map +1 -0
  1209. package/dist/routes/plugin.d.ts +9 -0
  1210. package/dist/routes/plugin.d.ts.map +1 -0
  1211. package/dist/routes/plugin.js +568 -0
  1212. package/dist/routes/plugin.js.map +1 -0
  1213. package/dist/routes/relationships.d.ts +13 -0
  1214. package/dist/routes/relationships.d.ts.map +1 -0
  1215. package/dist/routes/relationships.js +195 -0
  1216. package/dist/routes/relationships.js.map +1 -0
  1217. package/dist/routes/scheduled-tasks.d.ts +102 -0
  1218. package/dist/routes/scheduled-tasks.d.ts.map +1 -0
  1219. package/dist/routes/scheduled-tasks.js +322 -0
  1220. package/dist/routes/scheduled-tasks.js.map +1 -0
  1221. package/dist/routes/sleep-routes.d.ts +3 -0
  1222. package/dist/routes/sleep-routes.d.ts.map +1 -0
  1223. package/dist/routes/sleep-routes.js +33 -0
  1224. package/dist/routes/sleep-routes.js.map +1 -0
  1225. package/dist/routes/travel-provider-relay-routes.d.ts +2 -0
  1226. package/dist/routes/travel-provider-relay-routes.d.ts.map +1 -0
  1227. package/dist/routes/travel-provider-relay-routes.js +7 -0
  1228. package/dist/routes/travel-provider-relay-routes.js.map +1 -0
  1229. package/dist/routes/website-blocker-routes.d.ts +6 -0
  1230. package/dist/routes/website-blocker-routes.d.ts.map +1 -0
  1231. package/dist/routes/website-blocker-routes.js +218 -0
  1232. package/dist/routes/website-blocker-routes.js.map +1 -0
  1233. package/dist/security/action-confirmation.d.ts +12 -0
  1234. package/dist/security/action-confirmation.d.ts.map +1 -0
  1235. package/dist/security/action-confirmation.js +36 -0
  1236. package/dist/security/action-confirmation.js.map +1 -0
  1237. package/dist/service.d.ts +34 -0
  1238. package/dist/service.d.ts.map +1 -0
  1239. package/dist/service.js +111 -0
  1240. package/dist/service.js.map +1 -0
  1241. package/dist/travel-time/calendar-create.d.ts +17 -0
  1242. package/dist/travel-time/calendar-create.d.ts.map +1 -0
  1243. package/dist/travel-time/calendar-create.js +28 -0
  1244. package/dist/travel-time/calendar-create.js.map +1 -0
  1245. package/dist/travel-time/service.d.ts +114 -0
  1246. package/dist/travel-time/service.d.ts.map +1 -0
  1247. package/dist/travel-time/service.js +209 -0
  1248. package/dist/travel-time/service.js.map +1 -0
  1249. package/dist/types/app-blocker-settings-card.d.ts +2 -0
  1250. package/dist/types/app-blocker-settings-card.d.ts.map +1 -0
  1251. package/dist/types/app-blocker-settings-card.js +1 -0
  1252. package/dist/types/app-blocker-settings-card.js.map +1 -0
  1253. package/dist/types/briefing.d.ts +59 -0
  1254. package/dist/types/briefing.d.ts.map +1 -0
  1255. package/dist/types/briefing.js +1 -0
  1256. package/dist/types/briefing.js.map +1 -0
  1257. package/dist/types/document-request.d.ts +41 -0
  1258. package/dist/types/document-request.d.ts.map +1 -0
  1259. package/dist/types/document-request.js +1 -0
  1260. package/dist/types/document-request.js.map +1 -0
  1261. package/dist/types/index.d.ts +5 -0
  1262. package/dist/types/index.d.ts.map +1 -0
  1263. package/dist/types/index.js +1 -0
  1264. package/dist/types/index.js.map +1 -0
  1265. package/dist/types/website-blocker-settings-card.d.ts +2 -0
  1266. package/dist/types/website-blocker-settings-card.d.ts.map +1 -0
  1267. package/dist/types/website-blocker-settings-card.js +1 -0
  1268. package/dist/types/website-blocker-settings-card.js.map +1 -0
  1269. package/dist/ui.d.ts +13 -0
  1270. package/dist/ui.d.ts.map +1 -0
  1271. package/dist/ui.js +25 -0
  1272. package/dist/ui.js.map +1 -0
  1273. package/dist/utils/format-duration.d.ts +2 -0
  1274. package/dist/utils/format-duration.d.ts.map +1 -0
  1275. package/dist/utils/format-duration.js +13 -0
  1276. package/dist/utils/format-duration.js.map +1 -0
  1277. package/dist/utils/index.d.ts +3 -0
  1278. package/dist/utils/index.d.ts.map +1 -0
  1279. package/dist/utils/index.js +3 -0
  1280. package/dist/utils/index.js.map +1 -0
  1281. package/dist/utils/lifeops-url.d.ts +3 -0
  1282. package/dist/utils/lifeops-url.d.ts.map +1 -0
  1283. package/dist/utils/lifeops-url.js +28 -0
  1284. package/dist/utils/lifeops-url.js.map +1 -0
  1285. package/dist/website-blocker/chat-integration/block-activator.d.ts +32 -0
  1286. package/dist/website-blocker/chat-integration/block-activator.d.ts.map +1 -0
  1287. package/dist/website-blocker/chat-integration/block-activator.js +30 -0
  1288. package/dist/website-blocker/chat-integration/block-activator.js.map +1 -0
  1289. package/dist/website-blocker/chat-integration/block-rule-reconciler.d.ts +7 -0
  1290. package/dist/website-blocker/chat-integration/block-rule-reconciler.d.ts.map +1 -0
  1291. package/dist/website-blocker/chat-integration/block-rule-reconciler.js +115 -0
  1292. package/dist/website-blocker/chat-integration/block-rule-reconciler.js.map +1 -0
  1293. package/dist/website-blocker/chat-integration/block-rule-schema.d.ts +39 -0
  1294. package/dist/website-blocker/chat-integration/block-rule-schema.d.ts.map +1 -0
  1295. package/dist/website-blocker/chat-integration/block-rule-schema.js +133 -0
  1296. package/dist/website-blocker/chat-integration/block-rule-schema.js.map +1 -0
  1297. package/dist/website-blocker/chat-integration/block-rule-service.d.ts +21 -0
  1298. package/dist/website-blocker/chat-integration/block-rule-service.d.ts.map +1 -0
  1299. package/dist/website-blocker/chat-integration/block-rule-service.js +230 -0
  1300. package/dist/website-blocker/chat-integration/block-rule-service.js.map +1 -0
  1301. package/dist/website-blocker/chat-integration/harsh-mode-check.d.ts +13 -0
  1302. package/dist/website-blocker/chat-integration/harsh-mode-check.d.ts.map +1 -0
  1303. package/dist/website-blocker/chat-integration/harsh-mode-check.js +22 -0
  1304. package/dist/website-blocker/chat-integration/harsh-mode-check.js.map +1 -0
  1305. package/dist/website-blocker/chat-integration/index.d.ts +5 -0
  1306. package/dist/website-blocker/chat-integration/index.d.ts.map +1 -0
  1307. package/dist/website-blocker/chat-integration/index.js +26 -0
  1308. package/dist/website-blocker/chat-integration/index.js.map +1 -0
  1309. package/dist/website-blocker/proactive-block-bridge.d.ts +75 -0
  1310. package/dist/website-blocker/proactive-block-bridge.d.ts.map +1 -0
  1311. package/dist/website-blocker/proactive-block-bridge.js +154 -0
  1312. package/dist/website-blocker/proactive-block-bridge.js.map +1 -0
  1313. package/dist/website-blocker/public.d.ts +12 -0
  1314. package/dist/website-blocker/public.d.ts.map +1 -0
  1315. package/dist/website-blocker/public.js +51 -0
  1316. package/dist/website-blocker/public.js.map +1 -0
  1317. package/package.json +28 -28
@@ -0,0 +1,4003 @@
1
+ import crypto from "node:crypto";
2
+ import {
3
+ loadOwnerContactRoutingHints,
4
+ loadOwnerContactsConfig,
5
+ registerEscalationChannel,
6
+ resolveOwnerContactWithFallback
7
+ } from "@elizaos/agent";
8
+ import {
9
+ ModelType,
10
+ parseJsonModelRecord,
11
+ resolveOptimizedPromptForRuntime,
12
+ runWithTrajectoryContext,
13
+ ServiceType
14
+ } from "@elizaos/core";
15
+ import {
16
+ getSelfControlStatus,
17
+ startSelfControlBlock,
18
+ stopSelfControlBlock
19
+ } from "@elizaos/plugin-blocker/services/website-blocker/engine";
20
+ import {
21
+ buildSleepRecapFromSchedule,
22
+ deriveSleepWakeEvents,
23
+ normalizeHealthSignal,
24
+ shouldRunMorningCheckinFromSleepCycle,
25
+ shouldRunNightCheckinFromSleepCycle
26
+ } from "@elizaos/plugin-health";
27
+ import {
28
+ readTwilioCredentialsFromEnv,
29
+ sendTwilioSms,
30
+ sendTwilioVoiceCall
31
+ } from "@elizaos/plugin-phone/twilio";
32
+ import { readProfileFromMetadata } from "../activity-profile/profile-metadata.js";
33
+ import {
34
+ LIFEOPS_CHANNEL_TYPES,
35
+ LIFEOPS_CIRCADIAN_STATES,
36
+ LIFEOPS_MANUAL_OVERRIDE_KINDS,
37
+ LIFEOPS_UNCLEAR_REASONS
38
+ } from "../contracts/index.js";
39
+ import {
40
+ buildNativeAppleReminderMetadata,
41
+ createNativeAppleReminderLikeItem,
42
+ deleteNativeAppleReminderLikeItem,
43
+ readNativeAppleReminderMetadata,
44
+ updateNativeAppleReminderLikeItem
45
+ } from "./apple-reminders.js";
46
+ import {
47
+ CheckinService
48
+ } from "./checkin/checkin-service.js";
49
+ import { resolveCheckinSchedule } from "./checkin/schedule-resolver.js";
50
+ import {
51
+ resolveContactRouteCandidates
52
+ } from "./contact-route-policy.js";
53
+ import {
54
+ computeAdaptiveWindowPolicy,
55
+ resolveDefaultTimeZone,
56
+ windowPolicyMatchesDefaults
57
+ } from "./defaults.js";
58
+ import { materializeDefinitionOccurrences } from "./engine.js";
59
+ import { REMINDER_DISPATCH_INSTRUCTIONS } from "./optimized-prompt-instructions.js";
60
+ import { refreshLifeOpsRelativeTime } from "./relative-time.js";
61
+ import {
62
+ createLifeOpsActivitySignal,
63
+ createLifeOpsChannelPolicy,
64
+ createLifeOpsReminderAttempt,
65
+ createLifeOpsReminderPlan,
66
+ createLifeOpsWebsiteAccessGrant
67
+ } from "./repository.js";
68
+ import { refreshLifeOpsScheduleInsight } from "./schedule-insight.js";
69
+ import {
70
+ deriveLocalScheduleObservations,
71
+ isFreshCloudMergedState,
72
+ mergeScheduleObservations,
73
+ preferEffectiveMergedState,
74
+ recordsFromSyncRequest,
75
+ resolveScheduleDeviceIdentity,
76
+ SCHEDULE_CLOUD_SYNC_TTL_MS,
77
+ SCHEDULE_OBSERVATION_LOOKBACK_MS
78
+ } from "./schedule-state.js";
79
+ import { processDueScheduledTasks } from "./scheduled-task/scheduler.js";
80
+ import {
81
+ DEFAULT_REMINDER_INTENSITY,
82
+ DEFAULT_REMINDER_PROCESS_LIMIT,
83
+ DEFAULT_WORKFLOW_PROCESS_LIMIT,
84
+ GLOBAL_REMINDER_PREFERENCE_CHANNEL_REF,
85
+ OVERVIEW_HORIZON_MINUTES,
86
+ PROACTIVE_TASK_QUERY_TAGS,
87
+ REMINDER_ESCALATION_ACTIVITY_ACTIVE_METADATA_KEY,
88
+ REMINDER_ESCALATION_ACTIVITY_PLATFORM_METADATA_KEY,
89
+ REMINDER_ESCALATION_CHANNELS_METADATA_KEY,
90
+ REMINDER_ESCALATION_INDEX_METADATA_KEY,
91
+ REMINDER_ESCALATION_LAST_ATTEMPT_AT_METADATA_KEY,
92
+ REMINDER_ESCALATION_LAST_CHANNEL_METADATA_KEY,
93
+ REMINDER_ESCALATION_LAST_OUTCOME_METADATA_KEY,
94
+ REMINDER_ESCALATION_REASON_METADATA_KEY,
95
+ REMINDER_ESCALATION_RESOLUTION_METADATA_KEY,
96
+ REMINDER_ESCALATION_RESOLUTION_NOTE_METADATA_KEY,
97
+ REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY,
98
+ REMINDER_ESCALATION_STARTED_AT_METADATA_KEY,
99
+ REMINDER_INTENSITY_METADATA_KEY,
100
+ REMINDER_INTENSITY_NOTE_METADATA_KEY,
101
+ REMINDER_INTENSITY_UPDATED_AT_METADATA_KEY,
102
+ REMINDER_LIFECYCLE_METADATA_KEY,
103
+ REMINDER_PREFERENCE_SCOPE_METADATA_KEY,
104
+ REMINDER_REVIEW_AFTER_MINUTES_METADATA_KEY,
105
+ REMINDER_REVIEW_AT_METADATA_KEY,
106
+ REMINDER_REVIEW_CLASSIFIER_SOURCE_METADATA_KEY,
107
+ REMINDER_REVIEW_DECISION_METADATA_KEY,
108
+ REMINDER_REVIEW_ESCALATED_AT_METADATA_KEY,
109
+ REMINDER_REVIEW_ESCALATED_ATTEMPT_ID_METADATA_KEY,
110
+ REMINDER_REVIEW_ESCALATED_CHANNEL_METADATA_KEY,
111
+ REMINDER_REVIEW_REASON_METADATA_KEY,
112
+ REMINDER_REVIEW_RESPONDED_AT_METADATA_KEY,
113
+ REMINDER_REVIEW_RESPONSE_TEXT_METADATA_KEY,
114
+ REMINDER_REVIEW_SEMANTIC_REASON_METADATA_KEY,
115
+ REMINDER_REVIEW_STATUS_METADATA_KEY
116
+ } from "./service-constants.js";
117
+ import {
118
+ buildActiveReminders,
119
+ isReminderChannelAllowedForUrgency,
120
+ isWithinQuietHours as isWithinQuietHoursPolicy
121
+ } from "./service-helpers-misc.js";
122
+ import { computeDefinitionPerformance } from "./service-helpers-occurrence.js";
123
+ import {
124
+ applyReminderIntensityToPlan,
125
+ buildReminderEnforcementState,
126
+ buildReminderResponseClaim,
127
+ classifyReminderOwnerResponse,
128
+ decideReminderReviewTransition,
129
+ isReminderChannel,
130
+ isReminderReviewClosed,
131
+ normalizeActivitySignalSource as normalizeReminderActivitySignalSource,
132
+ normalizeActivitySignalState as normalizeReminderActivitySignalState,
133
+ normalizeReminderIntensityInput,
134
+ normalizeOptionalIdleState as normalizeReminderOptionalIdleState,
135
+ parseReminderOwnerResponseSemanticClassification,
136
+ readReminderAttemptLifecycle,
137
+ readReminderEscalationProfile,
138
+ readReminderPreferenceSettingFromMetadata,
139
+ readReminderReviewAt,
140
+ resolveReminderDeliveryUrgency,
141
+ resolveReminderEscalationDelayMinutes,
142
+ resolveReminderEscalationProfileDecision,
143
+ resolveReminderReviewDelayMinutes,
144
+ shouldDeferReminderUntilComputerActive,
145
+ shouldDeliverReminderForIntensity,
146
+ shouldEscalateImmediately,
147
+ withReminderPreferenceMetadata
148
+ } from "./service-helpers-reminder.js";
149
+ import {
150
+ fail,
151
+ lifeOpsErrorMessage,
152
+ normalizeEnumValue,
153
+ normalizeOptionalString,
154
+ requireNonEmptyString
155
+ } from "./service-normalize.js";
156
+ import {
157
+ DEFAULT_TELEMETRY_RETENTION_DAYS,
158
+ runTelemetryRetention
159
+ } from "./telemetry-retention.js";
160
+ import { addMinutes, getZonedDateParts } from "./time.js";
161
+ import { REMINDER_DISPATCH_INSTRUCTIONS as REMINDER_DISPATCH_INSTRUCTIONS2 } from "./optimized-prompt-instructions.js";
162
+ const LIFEOPS_SCHEDULE_DEVICE_KINDS = [
163
+ "iphone",
164
+ "ipad",
165
+ "mac",
166
+ "watch",
167
+ "cloud",
168
+ "unknown"
169
+ ];
170
+ const DEFAULT_SCHEDULED_TASK_PROCESS_LIMIT = 25;
171
+ function normalizeHour(value) {
172
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
173
+ }
174
+ function hourFromIso(value, timezone) {
175
+ if (!value) {
176
+ return null;
177
+ }
178
+ const date = new Date(value);
179
+ if (!Number.isFinite(date.getTime())) {
180
+ return null;
181
+ }
182
+ const parts = getZonedDateParts(date, timezone);
183
+ return parts.hour + parts.minute / 60;
184
+ }
185
+ function buildAdaptiveWindowProfile(args) {
186
+ const baseline = args.schedule?.baseline ?? null;
187
+ const scheduleWakeHour = normalizeHour(baseline?.medianWakeLocalHour) ?? hourFromIso(
188
+ args.schedule?.wakeAt ?? args.schedule?.firstActiveAt,
189
+ args.timeZone
190
+ );
191
+ const scheduleFirstActiveHour = hourFromIso(args.schedule?.firstActiveAt, args.timeZone) ?? scheduleWakeHour;
192
+ const scheduleLastActiveHour = hourFromIso(
193
+ args.schedule?.lastActiveAt,
194
+ args.timeZone
195
+ );
196
+ const scheduleSleepHour = normalizeHour(baseline?.medianBedtimeLocalHour);
197
+ const adaptiveProfile = {
198
+ typicalWakeHour: scheduleWakeHour ?? args.profile?.typicalWakeHour ?? null,
199
+ typicalFirstActiveHour: scheduleFirstActiveHour ?? args.profile?.typicalFirstActiveHour ?? null,
200
+ typicalLastActiveHour: scheduleLastActiveHour ?? args.profile?.typicalLastActiveHour ?? null,
201
+ typicalSleepHour: scheduleSleepHour ?? args.profile?.typicalSleepHour ?? null
202
+ };
203
+ return Object.values(adaptiveProfile).some((value) => value !== null) ? adaptiveProfile : null;
204
+ }
205
+ function isRecord(value) {
206
+ return typeof value === "object" && value !== null && !Array.isArray(value);
207
+ }
208
+ function mergeMetadata(current, updates) {
209
+ const cloned = updates && typeof updates === "object" && !Array.isArray(updates) ? { ...updates } : {};
210
+ return { ...current, ...cloned };
211
+ }
212
+ function requireRecord(value, field) {
213
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
214
+ fail(400, `${field} must be an object`);
215
+ }
216
+ return { ...value };
217
+ }
218
+ function normalizeOptionalBoolean(value, field) {
219
+ if (value === void 0 || value === null) return null;
220
+ if (typeof value === "boolean") return value;
221
+ if (value === "true") return true;
222
+ if (value === "false") return false;
223
+ fail(400, `${field} must be a boolean`);
224
+ }
225
+ function normalizeIsoString(value, field) {
226
+ if (typeof value !== "string" || value.trim().length === 0) {
227
+ fail(400, `${field} must be an ISO 8601 string`);
228
+ }
229
+ const ms = Date.parse(value);
230
+ if (!Number.isFinite(ms)) {
231
+ fail(400, `${field} must be a valid ISO 8601 string`);
232
+ }
233
+ return value;
234
+ }
235
+ function normalizeOptionalIsoString(value, field) {
236
+ if (value === void 0 || value === null) return null;
237
+ return normalizeIsoString(value, field);
238
+ }
239
+ function normalizePositiveInteger(value, field) {
240
+ const num = typeof value === "string" ? Number(value) : value;
241
+ if (typeof num !== "number" || !Number.isInteger(num) || num < 1) {
242
+ fail(400, `${field} must be a positive integer`);
243
+ }
244
+ return num;
245
+ }
246
+ function normalizeOptionalNonNegativeInteger(value, field) {
247
+ if (value === void 0 || value === null) return null;
248
+ const num = typeof value === "string" ? Number(value) : value;
249
+ if (typeof num !== "number" || !Number.isInteger(num) || num < 0) {
250
+ fail(400, `${field} must be a non-negative integer`);
251
+ }
252
+ return num;
253
+ }
254
+ function normalizeOptionalRecord(value, field) {
255
+ if (value === void 0) return void 0;
256
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
257
+ fail(400, `${field} must be an object`);
258
+ }
259
+ return { ...value };
260
+ }
261
+ const LIFEOPS_PRIVACY_CLASSES = ["public", "private", "shared"];
262
+ function normalizePhoneNumber(value, field) {
263
+ if (typeof value !== "string" || value.trim().length === 0) {
264
+ fail(400, `${field} must be a non-empty phone number string`);
265
+ }
266
+ const cleaned = value.replace(/[\s\-().]/g, "");
267
+ if (!/^\+?\d{7,15}$/.test(cleaned)) {
268
+ fail(400, `${field} is not a valid phone number`);
269
+ }
270
+ return cleaned.startsWith("+") ? cleaned : `+${cleaned}`;
271
+ }
272
+ function normalizePrivacyClass(value, field, fallback) {
273
+ if (value === void 0 || value === null) {
274
+ return fallback ?? "private";
275
+ }
276
+ if (typeof value !== "string" || value.trim().length === 0) {
277
+ if (fallback) return fallback;
278
+ fail(400, `${field ?? "privacyClass"} must be a string`);
279
+ }
280
+ return normalizeEnumValue(
281
+ value.trim(),
282
+ field ?? "privacyClass",
283
+ LIFEOPS_PRIVACY_CLASSES
284
+ );
285
+ }
286
+ const LIFEOPS_OWNER_CONTACTS_LOAD_CONTEXT = {
287
+ boundary: "lifeops.owner_contacts",
288
+ operation: "load_owner_contacts",
289
+ message: "[lifeops] Failed to load owner contacts; using empty owner contacts config."
290
+ };
291
+ const LIFEOPS_SCHEDULE_MEAL_LABELS = ["breakfast", "lunch", "dinner"];
292
+ function normalizeOptionalScheduleMealLabel(value, field) {
293
+ if (value === void 0 || value === null) {
294
+ return null;
295
+ }
296
+ return normalizeEnumValue(value, field, LIFEOPS_SCHEDULE_MEAL_LABELS);
297
+ }
298
+ function normalizeOptionalScheduleObservationSnapshot(value, field) {
299
+ if (value === void 0) {
300
+ return void 0;
301
+ }
302
+ if (value === null) {
303
+ return null;
304
+ }
305
+ return requireRecord(value, field);
306
+ }
307
+ const REMINDER_DELIVERY_RETRY_DELAY_MS = 2e3;
308
+ function isDeliveredReminderOutcome(outcome) {
309
+ return outcome === "delivered" || outcome === "delivered_read" || outcome === "delivered_unread";
310
+ }
311
+ function buildReminderSnoozeClarificationBody(title) {
312
+ return `I can snooze "${title}", but I need a clear time first. Reply with something like "30 minutes", "1 hour", "tonight", or "tomorrow morning".`;
313
+ }
314
+ function readReminderAttemptAnchorMs(attempt) {
315
+ const attempted = attempt.attemptedAt ? Date.parse(attempt.attemptedAt) : NaN;
316
+ if (Number.isFinite(attempted)) {
317
+ return attempted;
318
+ }
319
+ const scheduled = Date.parse(attempt.scheduledFor);
320
+ return Number.isFinite(scheduled) ? scheduled : Number.NEGATIVE_INFINITY;
321
+ }
322
+ function readLatestPendingReminderReviewAttempt(attempts) {
323
+ return attempts.filter(
324
+ (attempt) => isDeliveredReminderOutcome(attempt.outcome) && readReminderReviewAt(attempt) !== null && !isReminderReviewClosed(attempt)
325
+ ).sort(
326
+ (left, right) => readReminderAttemptAnchorMs(left) - readReminderAttemptAnchorMs(right)
327
+ ).at(-1) ?? null;
328
+ }
329
+ function buildReminderBody(args) {
330
+ const parts = [];
331
+ if (args.lifecycle === "escalation") {
332
+ parts.push(`Follow-up reminder: ${args.title}`);
333
+ } else {
334
+ parts.push(`Reminder: ${args.title}`);
335
+ }
336
+ if (args.dueAt) {
337
+ parts.push(`Due: ${new Date(args.dueAt).toLocaleString()}`);
338
+ }
339
+ return parts.join("\n");
340
+ }
341
+ function buildReminderVoiceContext(runtime) {
342
+ if (!runtime.character) return "";
343
+ const parts = [];
344
+ if (runtime.character.name) {
345
+ parts.push(`Name: ${runtime.character.name}`);
346
+ }
347
+ const bio = runtime.character.bio;
348
+ if (typeof bio === "string" && bio.trim().length > 0) {
349
+ parts.push(`Bio: ${bio.trim()}`);
350
+ } else if (Array.isArray(bio)) {
351
+ const bioText = bio.filter((line) => typeof line === "string").map((line) => line.trim()).filter(Boolean).join(" ");
352
+ if (bioText.length > 0) {
353
+ parts.push(`Bio: ${bioText}`);
354
+ }
355
+ }
356
+ return parts.join("\n");
357
+ }
358
+ function formatReminderConversationLine(args) {
359
+ const text = args.memory.content?.text;
360
+ if (!text || typeof text !== "string") return null;
361
+ const isAgent = args.memory.entityId === args.agentId;
362
+ const prefix = isAgent ? args.agentName : "User";
363
+ return `${prefix}: ${text}`;
364
+ }
365
+ function readMemoryCreatedAtMs(memory) {
366
+ if (typeof memory.createdAt === "number" && Number.isFinite(memory.createdAt)) {
367
+ return memory.createdAt;
368
+ }
369
+ if (typeof memory.createdAt === "string") {
370
+ const parsed = Date.parse(memory.createdAt);
371
+ return Number.isFinite(parsed) ? parsed : null;
372
+ }
373
+ return null;
374
+ }
375
+ function normalizeGeneratedReminderBody(value) {
376
+ const cleaned = value.replace(/^["'`]+|["'`]+$/g, "").trim();
377
+ return cleaned.length > 0 ? cleaned : null;
378
+ }
379
+ function normalizeGeneratedWorkflowBody(value) {
380
+ const cleaned = value.replace(/^["'`]+|["'`]+$/g, "").trim();
381
+ return cleaned.length > 0 ? cleaned : null;
382
+ }
383
+ function formatReminderPromptValue(value) {
384
+ if (value === null || value === void 0) {
385
+ return "null";
386
+ }
387
+ const text = value instanceof Date ? value.toISOString() : String(value).trim();
388
+ const normalized = text.replace(/\s+/g, " ").trim();
389
+ return normalized.length > 0 ? normalized : "null";
390
+ }
391
+ function normalizeModelNullString(value) {
392
+ if (typeof value !== "string") {
393
+ return null;
394
+ }
395
+ const trimmed = value.trim();
396
+ if (trimmed.length === 0 || trimmed.toLowerCase() === "null" || trimmed.toLowerCase() === "none") {
397
+ return null;
398
+ }
399
+ return trimmed;
400
+ }
401
+ function normalizeModelNumber(value) {
402
+ if (typeof value === "number" && Number.isFinite(value)) {
403
+ return value;
404
+ }
405
+ if (typeof value !== "string") {
406
+ return null;
407
+ }
408
+ const normalized = normalizeModelNullString(value);
409
+ if (normalized === null) {
410
+ return null;
411
+ }
412
+ const parsed = Number(normalized);
413
+ return Number.isFinite(parsed) ? parsed : null;
414
+ }
415
+ function parseStructuredObjectFromModelText(value) {
416
+ const parsedJson = parseJsonModelRecord(value);
417
+ if (isRecord(parsedJson)) {
418
+ return parsedJson;
419
+ }
420
+ return null;
421
+ }
422
+ function normalizeSemanticClassifierModelRecord(record) {
423
+ const normalized = { ...record };
424
+ const confidence = normalizeModelNumber(normalized.confidence);
425
+ if (confidence !== null) {
426
+ normalized.confidence = confidence;
427
+ }
428
+ const existingSnoozeRequest = normalized.snoozeRequest;
429
+ if (isRecord(existingSnoozeRequest)) {
430
+ const snoozeRequest = { ...existingSnoozeRequest };
431
+ const minutes = normalizeModelNumber(snoozeRequest.minutes);
432
+ if (minutes !== null) {
433
+ snoozeRequest.minutes = minutes;
434
+ }
435
+ const preset = normalizeModelNullString(snoozeRequest.preset);
436
+ if (preset !== null) {
437
+ snoozeRequest.preset = preset;
438
+ }
439
+ normalized.snoozeRequest = snoozeRequest;
440
+ return normalized;
441
+ }
442
+ const snoozeMinutes = normalizeModelNumber(normalized.snoozeMinutes);
443
+ if (snoozeMinutes !== null) {
444
+ normalized.snoozeRequest = { minutes: snoozeMinutes };
445
+ return normalized;
446
+ }
447
+ const snoozePreset = normalizeModelNullString(normalized.snoozePreset);
448
+ normalized.snoozeRequest = snoozePreset !== null ? { preset: snoozePreset } : null;
449
+ return normalized;
450
+ }
451
+ function serializeContactRouteCandidates(candidates) {
452
+ return candidates.map((candidate) => ({
453
+ channel: candidate.channel,
454
+ score: candidate.score,
455
+ evidence: candidate.evidence,
456
+ vetoReasons: candidate.vetoReasons,
457
+ interruptionBudget: candidate.interruptionBudget
458
+ }));
459
+ }
460
+ function formatNearbyReminderTitlesForPrompt(titles) {
461
+ if (titles.length === 0) {
462
+ return "None.";
463
+ }
464
+ return titles.map((title) => `- ${title}`).join("\n");
465
+ }
466
+ function buildReminderDispatchPrompt(args) {
467
+ const instructions = resolveOptimizedPromptForRuntime(
468
+ args.runtime,
469
+ "reminder_dispatch",
470
+ REMINDER_DISPATCH_INSTRUCTIONS
471
+ );
472
+ return [
473
+ instructions,
474
+ "",
475
+ "Character voice:",
476
+ buildReminderVoiceContext(args.runtime) || "No extra character context.",
477
+ "",
478
+ "Current reminder:",
479
+ `- title: ${args.title}`,
480
+ `- due: ${new Date(args.reminderAt).toLocaleString()}`,
481
+ `- channel: ${args.channel}`,
482
+ `- urgency: ${args.urgency}`,
483
+ `- lifecycle: ${args.lifecycle}`,
484
+ "",
485
+ "Recent conversation:",
486
+ args.recentConversation.length > 0 ? args.recentConversation.join("\n") : "No recent conversation available.",
487
+ "",
488
+ "Other reminders around this time:",
489
+ formatNearbyReminderTitlesForPrompt(args.nearbyReminderTitles ?? []),
490
+ "",
491
+ "Reminder text:"
492
+ ].join("\n");
493
+ }
494
+ function normalizeScreenContextFocus(value) {
495
+ switch (value) {
496
+ case "work":
497
+ case "leisure":
498
+ case "transition":
499
+ case "idle":
500
+ case "unknown":
501
+ return value;
502
+ default:
503
+ return null;
504
+ }
505
+ }
506
+ function collectNearbyReminderTitles(args) {
507
+ if (!args.currentAnchorAt) return [];
508
+ const anchorMs = Date.parse(args.currentAnchorAt);
509
+ if (!Number.isFinite(anchorMs)) return [];
510
+ const windowMs = 2 * 60 * 60 * 1e3;
511
+ const titles = [];
512
+ for (const occ of args.occurrences) {
513
+ if (occ.id === args.currentOwnerId) continue;
514
+ const occMs = occ.dueAt ? Date.parse(occ.dueAt) : null;
515
+ if (occMs !== null && Math.abs(occMs - anchorMs) <= windowMs) {
516
+ titles.push(occ.title);
517
+ }
518
+ if (titles.length >= args.limit) return titles;
519
+ }
520
+ for (const event of args.events) {
521
+ if (event.id === args.currentOwnerId) continue;
522
+ const eventMs = Date.parse(event.startAt);
523
+ if (Math.abs(eventMs - anchorMs) <= windowMs) {
524
+ titles.push(event.title);
525
+ }
526
+ if (titles.length >= args.limit) return titles;
527
+ }
528
+ return titles;
529
+ }
530
+ function buildActiveCalendarEventReminders(events, plansByEventId, _ownerEntityId, now) {
531
+ const rows = [];
532
+ for (const event of events) {
533
+ const plan = plansByEventId.get(event.id);
534
+ if (!plan) continue;
535
+ const eventStartAt = new Date(event.startAt);
536
+ for (const [stepIndex, step] of plan.steps.entries()) {
537
+ const scheduledFor = addMinutes(
538
+ eventStartAt,
539
+ -step.offsetMinutes
540
+ ).toISOString();
541
+ if (Date.parse(scheduledFor) > now.getTime()) continue;
542
+ rows.push({
543
+ ownerType: "calendar_event",
544
+ ownerId: event.id,
545
+ eventId: event.id,
546
+ subjectType: "owner",
547
+ title: event.title,
548
+ dueAt: event.startAt,
549
+ channel: step.channel,
550
+ stepIndex,
551
+ scheduledFor
552
+ });
553
+ }
554
+ }
555
+ return rows;
556
+ }
557
+ function normalizeActivitySignalSource(value, field) {
558
+ return normalizeReminderActivitySignalSource(value, field);
559
+ }
560
+ function normalizeActivitySignalState(value, field) {
561
+ return normalizeReminderActivitySignalState(value, field);
562
+ }
563
+ function normalizeOptionalIdleState(value, field) {
564
+ return normalizeReminderOptionalIdleState(value, field);
565
+ }
566
+ function normalizeWebsiteListForComparison(websites) {
567
+ return [
568
+ ...new Set(websites.map((w) => w.toLowerCase().trim()).filter(Boolean))
569
+ ].sort();
570
+ }
571
+ function haveSameWebsiteSet(left, right) {
572
+ const leftSet = normalizeWebsiteListForComparison([...left]);
573
+ const rightSet = normalizeWebsiteListForComparison([...right]);
574
+ if (leftSet.length !== rightSet.length) return false;
575
+ return leftSet.every((v, i) => v === rightSet[i]);
576
+ }
577
+ function isWebsiteAccessGrantActive(grant, now) {
578
+ if (grant.revokedAt) return false;
579
+ if (grant.expiresAt) {
580
+ return Date.parse(grant.expiresAt) > now.getTime();
581
+ }
582
+ return true;
583
+ }
584
+ function withReminders(Base) {
585
+ return class LifeOpsRemindersServiceMixin extends Base {
586
+ /**
587
+ * UTC date key of the last successful telemetry rollup+retention run.
588
+ * Gates the daily maintenance call inside the scheduler tick so it only
589
+ * fires once per day per runtime process.
590
+ */
591
+ telemetryRollupLastRunDate = null;
592
+ emitInAppReminderNudge(args) {
593
+ this.emitAssistantEvent(args.text, "reminder", {
594
+ ownerType: args.ownerType,
595
+ ownerId: args.ownerId,
596
+ subjectType: args.subjectType,
597
+ scheduledFor: args.scheduledFor,
598
+ dueAt: args.dueAt
599
+ });
600
+ const notifier = this.runtime.getService(ServiceType.NOTIFICATION);
601
+ void notifier?.notify?.({
602
+ title: "Reminder",
603
+ body: args.text,
604
+ category: "reminder",
605
+ priority: "normal",
606
+ source: "lifeops",
607
+ deepLink: "/chat",
608
+ groupKey: `reminder:${args.ownerType}:${args.ownerId}`,
609
+ data: {
610
+ ownerType: args.ownerType,
611
+ ownerId: args.ownerId,
612
+ subjectType: args.subjectType,
613
+ scheduledFor: args.scheduledFor,
614
+ dueAt: args.dueAt
615
+ }
616
+ });
617
+ }
618
+ async readRecentReminderConversation(args) {
619
+ if (args.subjectType !== "owner" || typeof this.runtime.getRoomsForParticipants !== "function" || typeof this.runtime.getMemoriesByRoomIds !== "function") {
620
+ return [];
621
+ }
622
+ const ownerEntityId = await this.ownerRoutingEntityId() ?? this.ownerEntityId();
623
+ const agentId = this.agentId();
624
+ try {
625
+ const roomIds = await this.runtime.getRoomsForParticipants([
626
+ ownerEntityId,
627
+ agentId
628
+ ]);
629
+ if (!Array.isArray(roomIds) || roomIds.length === 0) {
630
+ return [];
631
+ }
632
+ const memories = await this.runtime.getMemoriesByRoomIds({
633
+ tableName: "messages",
634
+ roomIds,
635
+ limit: Math.max(6, (args.limit ?? 6) * 2)
636
+ });
637
+ if (!Array.isArray(memories) || memories.length === 0) {
638
+ return [];
639
+ }
640
+ const agentName = typeof this.runtime.character.name === "string" && this.runtime.character.name.trim().length > 0 ? this.runtime.character.name.trim() : "Assistant";
641
+ return memories.slice().sort(
642
+ (left, right) => Number(left.createdAt ?? 0) - Number(right.createdAt ?? 0)
643
+ ).map(
644
+ (memory) => formatReminderConversationLine({
645
+ agentId,
646
+ agentName,
647
+ ownerEntityId,
648
+ memory
649
+ })
650
+ ).filter((line) => typeof line === "string").slice(-(args.limit ?? 6));
651
+ } catch {
652
+ return [];
653
+ }
654
+ }
655
+ async classifyReminderOwnerResponseSemantically(input) {
656
+ if (typeof this.runtime.useModel !== "function") {
657
+ return null;
658
+ }
659
+ const context = input.context ?? {};
660
+ const prompt = [
661
+ "Classify whether the owner reply resolves one specific reminder.",
662
+ "Return JSON only as a single object. Do not include prose, markdown, code fences, or hidden reasoning.",
663
+ "",
664
+ "Allowed decisions:",
665
+ "- explicit_resolution: the reply clearly completes, acknowledges, skips, or snoozes this reminder",
666
+ "- needs_clarification: the owner intends to act but the snooze/meaning is underspecified",
667
+ "- unrelated: the reply is about something else",
668
+ "- abstain: ambiguous, context-heavy, or not confidently bound to this reminder",
669
+ "",
670
+ "Use abstain when the reply is ambiguous, context-heavy, or you cannot confidently bind it to the reminder.",
671
+ "Only resolve standalone replies like done/yes/later when the context says standalone resolution is allowed.",
672
+ "For snoozed, set snoozeMinutes to a positive integer or snoozePreset to 15m, 30m, 1h, tonight, or tomorrow_morning; otherwise ask for clarification.",
673
+ "",
674
+ "Return exactly these JSON fields:",
675
+ "decision: explicit_resolution | needs_clarification | unrelated | abstain",
676
+ "resolution: completed | acknowledged | skipped | snoozed | null",
677
+ "snoozeMinutes: positive integer minutes or null",
678
+ "snoozePreset: 15m | 30m | 1h | tonight | tomorrow_morning | null",
679
+ "confidence: number from 0.0 to 1.0",
680
+ "reason: short_reason",
681
+ "",
682
+ "Reminder context:",
683
+ `title: ${formatReminderPromptValue(context.title ?? null)}`,
684
+ `attemptedAt: ${formatReminderPromptValue(context.attemptedAt ?? null)}`,
685
+ `respondedAt: ${formatReminderPromptValue(
686
+ context.respondedAt instanceof Date ? context.respondedAt.toISOString() : context.respondedAt ?? null
687
+ )}`,
688
+ `channel: ${formatReminderPromptValue(context.channel ?? null)}`,
689
+ `allowStandaloneResolution: ${formatReminderPromptValue(
690
+ context.allowStandaloneResolution ?? null
691
+ )}`,
692
+ "",
693
+ "Owner reply:",
694
+ `text: ${formatReminderPromptValue(input.text)}`
695
+ ].join("\n");
696
+ try {
697
+ const response = await runWithTrajectoryContext(
698
+ { purpose: "lifeops-reminders-classify-reply" },
699
+ () => this.runtime.useModel(ModelType.TEXT_SMALL, {
700
+ prompt
701
+ })
702
+ );
703
+ if (typeof response !== "string") {
704
+ return null;
705
+ }
706
+ const parsed = parseStructuredObjectFromModelText(response);
707
+ return parseReminderOwnerResponseSemanticClassification(
708
+ parsed ? normalizeSemanticClassifierModelRecord(parsed) : null
709
+ );
710
+ } catch {
711
+ return null;
712
+ }
713
+ }
714
+ async reviewOwnerResponseAfterReminderAttempt(args) {
715
+ const noResponse = {
716
+ decision: "no_response",
717
+ resolution: null,
718
+ snoozeRequest: null,
719
+ respondedAt: null,
720
+ responseText: null,
721
+ confidence: 0,
722
+ reason: "no_owner_response",
723
+ classifierSource: "none",
724
+ semanticReason: null
725
+ };
726
+ if (args.subjectType !== "owner" || typeof this.runtime.getRoomsForParticipants !== "function" || typeof this.runtime.getMemoriesByRoomIds !== "function") {
727
+ return noResponse;
728
+ }
729
+ const attemptedAt = args.attempt.attemptedAt ?? args.attempt.scheduledFor;
730
+ const attemptedMs = attemptedAt ? Date.parse(attemptedAt) : Number.NaN;
731
+ if (!Number.isFinite(attemptedMs)) {
732
+ return noResponse;
733
+ }
734
+ const ownerEntityId = await this.ownerRoutingEntityId() ?? this.ownerEntityId();
735
+ const agentId = this.agentId();
736
+ try {
737
+ const roomIds = await this.runtime.getRoomsForParticipants([
738
+ ownerEntityId,
739
+ agentId
740
+ ]);
741
+ if (!Array.isArray(roomIds) || roomIds.length === 0) {
742
+ return noResponse;
743
+ }
744
+ const memories = await this.runtime.getMemoriesByRoomIds({
745
+ tableName: "messages",
746
+ roomIds,
747
+ limit: 50
748
+ });
749
+ if (!Array.isArray(memories) || memories.length === 0) {
750
+ return noResponse;
751
+ }
752
+ const nowMs = args.now.getTime();
753
+ const ownerResponses = memories.filter((memory) => memory.entityId === ownerEntityId).map((memory) => {
754
+ const createdAt = readMemoryCreatedAtMs(memory);
755
+ const text = typeof memory.content.text === "string" ? memory.content.text.trim() : "";
756
+ const roomId = typeof memory.roomId === "string" ? memory.roomId : null;
757
+ return { createdAt, roomId, text };
758
+ }).filter(
759
+ (response) => response.createdAt !== null && response.createdAt > attemptedMs && response.createdAt <= nowMs && response.text.length > 0
760
+ ).sort((left, right) => left.createdAt - right.createdAt);
761
+ if (ownerResponses.length === 0) {
762
+ return noResponse;
763
+ }
764
+ const title = typeof args.attempt.deliveryMetadata.title === "string" ? args.attempt.deliveryMetadata.title : null;
765
+ const competingAttempts = args.competingAttempts && args.competingAttempts.length > 0 ? args.competingAttempts : [args.attempt];
766
+ let latestUnrelated = null;
767
+ for (const response of ownerResponses) {
768
+ const responseClaim = buildReminderResponseClaim({
769
+ attempt: args.attempt,
770
+ competingAttempts,
771
+ response: {
772
+ text: response.text,
773
+ createdAt: response.createdAt,
774
+ roomId: response.roomId
775
+ },
776
+ roomIds
777
+ });
778
+ const classification = await classifyReminderOwnerResponse({
779
+ text: response.text,
780
+ context: {
781
+ title,
782
+ attemptedAt,
783
+ respondedAt: response.createdAt,
784
+ channel: args.attempt.channel,
785
+ allowStandaloneResolution: responseClaim.allowStandaloneResolution
786
+ },
787
+ semanticClassifier: (input) => this.classifyReminderOwnerResponseSemantically(input)
788
+ });
789
+ if (classification.decision === "explicit_resolution") {
790
+ return {
791
+ decision: "explicit_resolution",
792
+ resolution: classification.resolution,
793
+ snoozeRequest: classification.snoozeRequest,
794
+ respondedAt: new Date(response.createdAt).toISOString(),
795
+ responseText: response.text,
796
+ confidence: classification.confidence,
797
+ reason: classification.reason,
798
+ classifierSource: classification.classifierSource,
799
+ semanticReason: classification.semanticReason ?? null
800
+ };
801
+ }
802
+ if (classification.decision === "needs_clarification") {
803
+ return {
804
+ decision: "needs_clarification",
805
+ resolution: null,
806
+ snoozeRequest: null,
807
+ respondedAt: new Date(response.createdAt).toISOString(),
808
+ responseText: response.text,
809
+ confidence: classification.confidence,
810
+ reason: classification.reason,
811
+ classifierSource: classification.classifierSource,
812
+ semanticReason: classification.semanticReason ?? null
813
+ };
814
+ }
815
+ latestUnrelated = {
816
+ decision: "unrelated",
817
+ resolution: null,
818
+ snoozeRequest: null,
819
+ respondedAt: new Date(response.createdAt).toISOString(),
820
+ responseText: response.text,
821
+ confidence: classification.confidence,
822
+ reason: classification.reason,
823
+ classifierSource: classification.classifierSource,
824
+ semanticReason: classification.semanticReason ?? null
825
+ };
826
+ }
827
+ return latestUnrelated ?? {
828
+ decision: "unrelated",
829
+ resolution: null,
830
+ snoozeRequest: null,
831
+ respondedAt: null,
832
+ responseText: null,
833
+ confidence: 0.4,
834
+ reason: "owner_responded_without_explicit_reminder_resolution",
835
+ classifierSource: "none",
836
+ semanticReason: null
837
+ };
838
+ } catch {
839
+ return noResponse;
840
+ }
841
+ }
842
+ async renderReminderBody(args) {
843
+ const fallback = buildReminderBody({
844
+ title: args.title,
845
+ scheduledFor: args.scheduledFor,
846
+ dueAt: args.dueAt,
847
+ channel: args.channel,
848
+ lifecycle: args.lifecycle,
849
+ nearbyReminderTitles: args.nearbyReminderTitles
850
+ });
851
+ if (typeof this.runtime.useModel !== "function") {
852
+ return fallback;
853
+ }
854
+ const recentConversation = await this.readRecentReminderConversation({
855
+ subjectType: args.subjectType,
856
+ limit: 6
857
+ });
858
+ const reminderAt = args.dueAt ?? args.scheduledFor;
859
+ const prompt = buildReminderDispatchPrompt({
860
+ runtime: this.runtime,
861
+ title: args.title,
862
+ reminderAt,
863
+ channel: args.channel,
864
+ lifecycle: args.lifecycle,
865
+ urgency: args.urgency,
866
+ recentConversation,
867
+ nearbyReminderTitles: args.nearbyReminderTitles
868
+ });
869
+ try {
870
+ const response = await runWithTrajectoryContext(
871
+ { purpose: "reminder_dispatch" },
872
+ () => this.runtime.useModel(ModelType.TEXT_SMALL, {
873
+ prompt
874
+ })
875
+ );
876
+ const text = typeof response === "string" ? normalizeGeneratedReminderBody(response) : null;
877
+ return text ?? fallback;
878
+ } catch {
879
+ return fallback;
880
+ }
881
+ }
882
+ async renderWorkflowRunBody(args) {
883
+ const fallback = args.run.status === "success" ? `${args.workflow.title} just ran successfully.` : `${args.workflow.title} ran but hit a problem.`;
884
+ if (args.workflow.subjectType !== "owner" || typeof this.runtime.useModel !== "function") {
885
+ return fallback;
886
+ }
887
+ const recentConversation = await this.readRecentReminderConversation({
888
+ subjectType: "owner",
889
+ limit: 6
890
+ });
891
+ const prompt = [
892
+ `Write a short assistant update about the workflow "${args.workflow.title}".`,
893
+ "This is a user-facing status nudge, not a system log.",
894
+ "",
895
+ "Character voice:",
896
+ buildReminderVoiceContext(this.runtime) || "No extra character context.",
897
+ "",
898
+ "Workflow run:",
899
+ `- title: ${args.workflow.title}`,
900
+ `- status: ${args.run.status}`,
901
+ "",
902
+ "Recent conversation:",
903
+ recentConversation.length > 0 ? recentConversation.join("\n") : "No recent conversation available.",
904
+ "",
905
+ "Rules:",
906
+ "- Return only the message text.",
907
+ "- Sound natural and in character.",
908
+ "- Do not start with 'Workflow' or 'Scheduled workflow'.",
909
+ "- Keep it concise: one short sentence, or two at most.",
910
+ "- For failures, sound calm and direct rather than robotic.",
911
+ "- No markdown, bullets, quotes, labels, or emoji.",
912
+ "",
913
+ "Message text:"
914
+ ].join("\n");
915
+ try {
916
+ const response = await runWithTrajectoryContext(
917
+ { purpose: "lifeops-reminders-workflow-body" },
918
+ () => this.runtime.useModel(ModelType.TEXT_SMALL, {
919
+ prompt
920
+ })
921
+ );
922
+ const text = typeof response === "string" ? normalizeGeneratedWorkflowBody(response) : null;
923
+ return text ?? fallback;
924
+ } catch {
925
+ return fallback;
926
+ }
927
+ }
928
+ async emitWorkflowRunNudge(workflow, run) {
929
+ if (workflow.subjectType !== "owner") {
930
+ return;
931
+ }
932
+ const message = await this.renderWorkflowRunBody({
933
+ workflow,
934
+ run
935
+ });
936
+ const routeMetadata = await this.buildOwnerContactRouteEventMetadata({
937
+ purpose: "workflow",
938
+ urgency: run.status === "success" ? "medium" : "high",
939
+ now: /* @__PURE__ */ new Date()
940
+ });
941
+ this.emitAssistantEvent(message, "workflow", {
942
+ workflowId: workflow.id,
943
+ workflowTitle: workflow.title,
944
+ workflowRunId: run.id,
945
+ status: run.status,
946
+ subjectType: workflow.subjectType,
947
+ ...routeMetadata
948
+ });
949
+ }
950
+ withNativeAppleReminderId(definition, reminderId) {
951
+ const nativeMetadata = readNativeAppleReminderMetadata(
952
+ definition.metadata
953
+ );
954
+ if (!nativeMetadata) {
955
+ return definition;
956
+ }
957
+ return {
958
+ ...definition,
959
+ metadata: mergeMetadata(
960
+ definition.metadata,
961
+ buildNativeAppleReminderMetadata({
962
+ kind: nativeMetadata.kind,
963
+ source: nativeMetadata.source,
964
+ reminderId
965
+ })
966
+ ),
967
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
968
+ };
969
+ }
970
+ async syncNativeAppleReminderForDefinition(args) {
971
+ const previousMetadata = args.previousDefinition ? readNativeAppleReminderMetadata(args.previousDefinition.metadata) : null;
972
+ const nextMetadata = args.definition ? readNativeAppleReminderMetadata(args.definition.metadata) : null;
973
+ const previousReminderId = previousMetadata?.reminderId ?? null;
974
+ if (args.definition === null || nextMetadata === null || args.definition.subjectType !== "owner" || args.definition.domain !== "user_lifeops" || args.definition.cadence.kind !== "once") {
975
+ if (previousReminderId) {
976
+ const deleteResult = await deleteNativeAppleReminderLikeItem(
977
+ previousReminderId,
978
+ { runtime: this.runtime }
979
+ );
980
+ if (deleteResult.ok === false) {
981
+ this.logLifeOpsWarn(
982
+ "native_apple_reminder_sync",
983
+ "[lifeops] Failed to delete a native Apple reminder.",
984
+ {
985
+ definitionId: args.previousDefinition?.id ?? null,
986
+ reminderId: previousReminderId,
987
+ reason: deleteResult.reason,
988
+ detail: deleteResult.reason === "permission" ? `permission ${deleteResult.permission} (canRequest=${deleteResult.canRequest})` : deleteResult.reason === "native_error" ? deleteResult.message : `not_supported on ${deleteResult.platform}`
989
+ }
990
+ );
991
+ }
992
+ }
993
+ if (args.definition && nextMetadata?.reminderId) {
994
+ return this.withNativeAppleReminderId(args.definition, null);
995
+ }
996
+ return args.definition;
997
+ }
998
+ const definition = args.definition;
999
+ const nativeMetadata = nextMetadata;
1000
+ const cadence = definition.cadence.kind === "once" ? definition.cadence : null;
1001
+ if (!cadence) {
1002
+ return definition;
1003
+ }
1004
+ const reminderId = nativeMetadata.reminderId ?? previousReminderId;
1005
+ if (reminderId) {
1006
+ const updateResult = await updateNativeAppleReminderLikeItem({
1007
+ reminderId,
1008
+ kind: nativeMetadata.kind,
1009
+ title: definition.title,
1010
+ dueAt: cadence.dueAt,
1011
+ notes: definition.description,
1012
+ originalIntent: definition.originalIntent,
1013
+ runtime: this.runtime
1014
+ });
1015
+ if (updateResult.ok === true) {
1016
+ return this.withNativeAppleReminderId(
1017
+ definition,
1018
+ updateResult.data.reminderId ?? reminderId
1019
+ );
1020
+ }
1021
+ this.logLifeOpsWarn(
1022
+ "native_apple_reminder_sync",
1023
+ "[lifeops] Failed to update a native Apple reminder.",
1024
+ {
1025
+ definitionId: definition.id,
1026
+ kind: nativeMetadata.kind,
1027
+ reminderId,
1028
+ reason: updateResult.reason,
1029
+ detail: updateResult.reason === "permission" ? `permission ${updateResult.permission} (canRequest=${updateResult.canRequest})` : updateResult.reason === "native_error" ? updateResult.message : `not_supported on ${updateResult.platform}`
1030
+ }
1031
+ );
1032
+ return this.withNativeAppleReminderId(definition, reminderId);
1033
+ }
1034
+ const createResult = await createNativeAppleReminderLikeItem({
1035
+ kind: nativeMetadata.kind,
1036
+ title: definition.title,
1037
+ dueAt: cadence.dueAt,
1038
+ notes: definition.description,
1039
+ originalIntent: definition.originalIntent,
1040
+ runtime: this.runtime
1041
+ });
1042
+ if (createResult.ok === false) {
1043
+ this.logLifeOpsWarn(
1044
+ "native_apple_reminder_sync",
1045
+ "[lifeops] Failed to sync a native Apple reminder.",
1046
+ {
1047
+ definitionId: definition.id,
1048
+ kind: nativeMetadata.kind,
1049
+ reason: createResult.reason,
1050
+ detail: createResult.reason === "permission" ? `permission ${createResult.permission} (canRequest=${createResult.canRequest})` : createResult.reason === "native_error" ? createResult.message : `not_supported on ${createResult.platform}`
1051
+ }
1052
+ );
1053
+ return definition;
1054
+ }
1055
+ return this.withNativeAppleReminderId(
1056
+ definition,
1057
+ createResult.data.reminderId ?? null
1058
+ );
1059
+ }
1060
+ async getDefinitionRecord(definitionId, now = /* @__PURE__ */ new Date()) {
1061
+ const definition = await this.repository.getDefinition(
1062
+ this.agentId(),
1063
+ definitionId
1064
+ );
1065
+ if (!definition) {
1066
+ fail(404, "life-ops definition not found");
1067
+ }
1068
+ const reminderPlan = definition.reminderPlanId ? await this.repository.getReminderPlan(
1069
+ this.agentId(),
1070
+ definition.reminderPlanId
1071
+ ) : null;
1072
+ const occurrences = await this.repository.listOccurrencesForDefinition(
1073
+ this.agentId(),
1074
+ definition.id
1075
+ );
1076
+ return {
1077
+ definition,
1078
+ reminderPlan,
1079
+ performance: computeDefinitionPerformance(definition, occurrences, now)
1080
+ };
1081
+ }
1082
+ async getGoalRecord(goalId) {
1083
+ const goal = await this.repository.getGoal(this.agentId(), goalId);
1084
+ if (!goal) {
1085
+ fail(404, "life-ops goal not found");
1086
+ }
1087
+ const links = await this.repository.listGoalLinksForGoal(
1088
+ this.agentId(),
1089
+ goalId
1090
+ );
1091
+ return { goal, links };
1092
+ }
1093
+ async ensureGoalExists(goalId, ownership) {
1094
+ if (!goalId) return null;
1095
+ const goal = await this.repository.getGoal(this.agentId(), goalId);
1096
+ if (!goal) {
1097
+ fail(404, `goal ${goalId} does not exist`);
1098
+ }
1099
+ if (ownership && (goal.domain !== ownership.domain || goal.subjectType !== ownership.subjectType || goal.subjectId !== ownership.subjectId)) {
1100
+ fail(
1101
+ 400,
1102
+ "goalId must reference a goal in the same owner or agent scope"
1103
+ );
1104
+ }
1105
+ return goal.id;
1106
+ }
1107
+ async syncGoalLink(definition) {
1108
+ await this.repository.deleteGoalLinksForLinked(
1109
+ definition.agentId,
1110
+ "definition",
1111
+ definition.id
1112
+ );
1113
+ if (!definition.goalId) return;
1114
+ await this.repository.upsertGoalLink({
1115
+ id: crypto.randomUUID(),
1116
+ agentId: definition.agentId,
1117
+ goalId: definition.goalId,
1118
+ linkedType: "definition",
1119
+ linkedId: definition.id,
1120
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1121
+ });
1122
+ }
1123
+ async syncReminderPlan(definition, draft) {
1124
+ if (draft === void 0) {
1125
+ return definition.reminderPlanId ? await this.repository.getReminderPlan(
1126
+ definition.agentId,
1127
+ definition.reminderPlanId
1128
+ ) : null;
1129
+ }
1130
+ if (draft === null) {
1131
+ if (definition.reminderPlanId) {
1132
+ await this.repository.deleteReminderPlan(
1133
+ definition.agentId,
1134
+ definition.reminderPlanId
1135
+ );
1136
+ }
1137
+ definition.reminderPlanId = null;
1138
+ return null;
1139
+ }
1140
+ const existingPlan = definition.reminderPlanId ? await this.repository.getReminderPlan(
1141
+ definition.agentId,
1142
+ definition.reminderPlanId
1143
+ ) : null;
1144
+ if (existingPlan) {
1145
+ const nextPlan = {
1146
+ ...existingPlan,
1147
+ steps: draft.steps,
1148
+ mutePolicy: draft.mutePolicy,
1149
+ quietHours: draft.quietHours,
1150
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1151
+ };
1152
+ await this.repository.updateReminderPlan(nextPlan);
1153
+ definition.reminderPlanId = nextPlan.id;
1154
+ return nextPlan;
1155
+ }
1156
+ const createdPlan = createLifeOpsReminderPlan({
1157
+ agentId: definition.agentId,
1158
+ ownerType: "definition",
1159
+ ownerId: definition.id,
1160
+ steps: draft.steps,
1161
+ mutePolicy: draft.mutePolicy,
1162
+ quietHours: draft.quietHours
1163
+ });
1164
+ await this.repository.createReminderPlan(createdPlan);
1165
+ definition.reminderPlanId = createdPlan.id;
1166
+ return createdPlan;
1167
+ }
1168
+ /** @internal — public to satisfy TS4094 on exported anonymous mixin class */
1169
+ serializeScheduleObservationForSync(observation) {
1170
+ const metadata = isRecord(observation.metadata) ? observation.metadata : null;
1171
+ const rawSnapshot = metadata?.snapshot;
1172
+ const snapshot = isRecord(rawSnapshot) ? { ...rawSnapshot } : void 0;
1173
+ const extraMetadata = metadata && typeof metadata === "object" ? Object.fromEntries(
1174
+ Object.entries(metadata).filter(
1175
+ ([key]) => key !== "snapshot" && key !== "source"
1176
+ )
1177
+ ) : {};
1178
+ return {
1179
+ circadianState: observation.circadianState,
1180
+ stateConfidence: observation.stateConfidence,
1181
+ uncertaintyReason: observation.uncertaintyReason,
1182
+ windowStartAt: observation.windowStartAt,
1183
+ windowEndAt: observation.windowEndAt,
1184
+ mealLabel: observation.mealLabel,
1185
+ snapshot,
1186
+ metadata: Object.keys(extraMetadata).length > 0 ? extraMetadata : void 0
1187
+ };
1188
+ }
1189
+ async refreshLocalMergedScheduleState(args) {
1190
+ const timezone = normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone();
1191
+ const now = args?.now ?? /* @__PURE__ */ new Date();
1192
+ const insight = await refreshLifeOpsScheduleInsight({
1193
+ runtime: this.runtime,
1194
+ repository: this.repository,
1195
+ agentId: this.agentId(),
1196
+ timezone,
1197
+ now
1198
+ });
1199
+ const deviceIdentity = resolveScheduleDeviceIdentity();
1200
+ const observations = deriveLocalScheduleObservations({
1201
+ agentId: this.agentId(),
1202
+ deviceId: deviceIdentity.deviceId,
1203
+ deviceKind: deviceIdentity.deviceKind,
1204
+ timezone,
1205
+ observedAt: now.toISOString(),
1206
+ insight
1207
+ });
1208
+ for (const observation of observations) {
1209
+ await this.repository.upsertScheduleObservation(observation);
1210
+ }
1211
+ const sinceAt = new Date(
1212
+ now.getTime() - SCHEDULE_OBSERVATION_LOOKBACK_MS
1213
+ ).toISOString();
1214
+ const recentObservations = await this.repository.listScheduleObservations(
1215
+ this.agentId(),
1216
+ sinceAt,
1217
+ {
1218
+ origin: "local_inference",
1219
+ deviceId: deviceIdentity.deviceId
1220
+ }
1221
+ );
1222
+ const merged = mergeScheduleObservations({
1223
+ agentId: this.agentId(),
1224
+ scope: "local",
1225
+ timezone,
1226
+ now,
1227
+ observations: recentObservations
1228
+ });
1229
+ if (!merged) {
1230
+ const cached = await this.repository.getScheduleMergedState(
1231
+ this.agentId(),
1232
+ "local",
1233
+ timezone
1234
+ );
1235
+ return cached ? refreshLifeOpsRelativeTime(cached, now) : null;
1236
+ }
1237
+ merged.circadianRuleFirings = insight.circadianRuleFirings;
1238
+ await this.repository.upsertScheduleMergedState(merged);
1239
+ const stored = await this.repository.getScheduleMergedState(
1240
+ this.agentId(),
1241
+ "local",
1242
+ timezone
1243
+ ) ?? merged;
1244
+ return refreshLifeOpsRelativeTime(stored, now);
1245
+ }
1246
+ async ingestScheduleObservations(request) {
1247
+ const deviceId = requireNonEmptyString(request.deviceId, "deviceId");
1248
+ const deviceKind = normalizeEnumValue(
1249
+ request.deviceKind,
1250
+ "deviceKind",
1251
+ LIFEOPS_SCHEDULE_DEVICE_KINDS
1252
+ );
1253
+ const timezone = requireNonEmptyString(request.timezone, "timezone");
1254
+ const observedAt = normalizeOptionalIsoString(request.observedAt, "observedAt") ?? (/* @__PURE__ */ new Date()).toISOString();
1255
+ if (!Array.isArray(request.observations) || request.observations.length === 0) {
1256
+ fail(400, "observations must be a non-empty array");
1257
+ }
1258
+ const observations = request.observations.map((input, index) => {
1259
+ const record = requireRecord(input, `observations[${index}]`);
1260
+ const stateConfidence = typeof record.stateConfidence === "string" ? Number(record.stateConfidence) : record.stateConfidence;
1261
+ if (typeof stateConfidence !== "number" || !Number.isFinite(stateConfidence)) {
1262
+ fail(400, `observations[${index}].stateConfidence must be a number`);
1263
+ }
1264
+ return {
1265
+ circadianState: normalizeEnumValue(
1266
+ record.circadianState,
1267
+ `observations[${index}].circadianState`,
1268
+ LIFEOPS_CIRCADIAN_STATES
1269
+ ),
1270
+ stateConfidence,
1271
+ uncertaintyReason: record.uncertaintyReason === void 0 || record.uncertaintyReason === null ? null : normalizeEnumValue(
1272
+ record.uncertaintyReason,
1273
+ `observations[${index}].uncertaintyReason`,
1274
+ LIFEOPS_UNCLEAR_REASONS
1275
+ ),
1276
+ windowStartAt: normalizeIsoString(
1277
+ record.windowStartAt,
1278
+ `observations[${index}].windowStartAt`
1279
+ ),
1280
+ windowEndAt: normalizeOptionalIsoString(
1281
+ record.windowEndAt,
1282
+ `observations[${index}].windowEndAt`
1283
+ ),
1284
+ mealLabel: normalizeOptionalScheduleMealLabel(
1285
+ record.mealLabel,
1286
+ `observations[${index}].mealLabel`
1287
+ ),
1288
+ snapshot: normalizeOptionalScheduleObservationSnapshot(
1289
+ record.snapshot,
1290
+ `observations[${index}].snapshot`
1291
+ ),
1292
+ metadata: record.metadata === void 0 ? void 0 : normalizeOptionalRecord(
1293
+ record.metadata,
1294
+ `observations[${index}].metadata`
1295
+ )
1296
+ };
1297
+ });
1298
+ const normalizedRequest = {
1299
+ deviceId,
1300
+ deviceKind,
1301
+ timezone,
1302
+ observedAt,
1303
+ observations
1304
+ };
1305
+ const records = recordsFromSyncRequest({
1306
+ agentId: this.agentId(),
1307
+ origin: "device_sync",
1308
+ request: normalizedRequest
1309
+ });
1310
+ for (const record of records) {
1311
+ await this.repository.upsertScheduleObservation(record);
1312
+ }
1313
+ const now = new Date(observedAt);
1314
+ const recentObservations = await this.repository.listScheduleObservations(
1315
+ this.agentId(),
1316
+ new Date(
1317
+ now.getTime() - SCHEDULE_OBSERVATION_LOOKBACK_MS
1318
+ ).toISOString()
1319
+ );
1320
+ const merged = mergeScheduleObservations({
1321
+ agentId: this.agentId(),
1322
+ scope: "cloud",
1323
+ timezone,
1324
+ now,
1325
+ observations: recentObservations
1326
+ });
1327
+ if (!merged) {
1328
+ fail(409, "unable to merge schedule observations");
1329
+ }
1330
+ await this.repository.upsertScheduleMergedState(merged);
1331
+ return {
1332
+ acceptedCount: records.length,
1333
+ mergedState: merged
1334
+ };
1335
+ }
1336
+ async fetchCloudMergedScheduleState(args) {
1337
+ const timezone = normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone();
1338
+ const now = /* @__PURE__ */ new Date();
1339
+ const cached = await this.repository.getScheduleMergedState(
1340
+ this.agentId(),
1341
+ "cloud",
1342
+ timezone
1343
+ );
1344
+ if (!this.scheduleSyncClient.configured) {
1345
+ return cached ? refreshLifeOpsRelativeTime(cached, now) : null;
1346
+ }
1347
+ try {
1348
+ const response = await this.scheduleSyncClient.getMergedState(
1349
+ timezone,
1350
+ "cloud"
1351
+ );
1352
+ if (!response.mergedState) {
1353
+ return cached ? refreshLifeOpsRelativeTime(cached, now) : null;
1354
+ }
1355
+ await this.repository.upsertScheduleMergedState(response.mergedState);
1356
+ const stored = await this.repository.getScheduleMergedState(
1357
+ this.agentId(),
1358
+ "cloud",
1359
+ timezone
1360
+ ) ?? response.mergedState;
1361
+ return refreshLifeOpsRelativeTime(stored, now);
1362
+ } catch (error) {
1363
+ this.logLifeOpsWarn(
1364
+ "schedule_fetch_cloud_state",
1365
+ "[lifeops] Failed to fetch merged cloud schedule state; using cached state.",
1366
+ { error: lifeOpsErrorMessage(error) }
1367
+ );
1368
+ return cached ? refreshLifeOpsRelativeTime(cached, now) : null;
1369
+ }
1370
+ }
1371
+ async readEffectiveScheduleState(args) {
1372
+ const timezone = normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone();
1373
+ const now = args?.now ?? /* @__PURE__ */ new Date();
1374
+ const local = await this.repository.getScheduleMergedState(
1375
+ this.agentId(),
1376
+ "local",
1377
+ timezone
1378
+ );
1379
+ const cloud = await this.repository.getScheduleMergedState(
1380
+ this.agentId(),
1381
+ "cloud",
1382
+ timezone
1383
+ );
1384
+ const preferred = preferEffectiveMergedState({
1385
+ now,
1386
+ local,
1387
+ cloud
1388
+ });
1389
+ return preferred ? refreshLifeOpsRelativeTime(preferred, now) : null;
1390
+ }
1391
+ async refreshEffectiveScheduleState(args) {
1392
+ const timezone = normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone();
1393
+ const now = args?.now ?? /* @__PURE__ */ new Date();
1394
+ const local = await this.refreshLocalMergedScheduleState({
1395
+ timezone,
1396
+ now
1397
+ });
1398
+ let cloud = await this.repository.getScheduleMergedState(
1399
+ this.agentId(),
1400
+ "cloud",
1401
+ timezone
1402
+ );
1403
+ if (!this.scheduleSyncClient.configured) {
1404
+ const preferred2 = preferEffectiveMergedState({ now, local, cloud });
1405
+ return preferred2 ? refreshLifeOpsRelativeTime(preferred2, now) : null;
1406
+ }
1407
+ if (!isFreshCloudMergedState(cloud, now)) {
1408
+ const deviceIdentity = resolveScheduleDeviceIdentity();
1409
+ const localObservations = await this.repository.listScheduleObservations(
1410
+ this.agentId(),
1411
+ new Date(
1412
+ now.getTime() - SCHEDULE_OBSERVATION_LOOKBACK_MS
1413
+ ).toISOString(),
1414
+ {
1415
+ origin: "local_inference",
1416
+ deviceId: deviceIdentity.deviceId
1417
+ }
1418
+ );
1419
+ try {
1420
+ if (localObservations.length > 0) {
1421
+ const response = await this.scheduleSyncClient.syncObservations({
1422
+ deviceId: deviceIdentity.deviceId,
1423
+ deviceKind: deviceIdentity.deviceKind,
1424
+ timezone,
1425
+ observedAt: now.toISOString(),
1426
+ observations: localObservations.map(
1427
+ (observation) => this.serializeScheduleObservationForSync(observation)
1428
+ )
1429
+ });
1430
+ await this.repository.upsertScheduleMergedState(
1431
+ response.mergedState
1432
+ );
1433
+ cloud = await this.repository.getScheduleMergedState(
1434
+ this.agentId(),
1435
+ "cloud",
1436
+ timezone
1437
+ ) ?? response.mergedState;
1438
+ } else {
1439
+ cloud = await this.fetchCloudMergedScheduleState({ timezone });
1440
+ }
1441
+ } catch (error) {
1442
+ this.logLifeOpsWarn(
1443
+ "schedule_sync",
1444
+ "[lifeops] Failed to sync coarse schedule observations; using local state.",
1445
+ { error: lifeOpsErrorMessage(error) }
1446
+ );
1447
+ if (!cloud || now.getTime() - Date.parse(cloud.updatedAt) > SCHEDULE_CLOUD_SYNC_TTL_MS) {
1448
+ cloud = await this.fetchCloudMergedScheduleState({ timezone });
1449
+ }
1450
+ }
1451
+ }
1452
+ const preferred = preferEffectiveMergedState({ now, local, cloud });
1453
+ return preferred ? refreshLifeOpsRelativeTime(preferred, now) : null;
1454
+ }
1455
+ async getScheduleMergedState(args) {
1456
+ const timezone = normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone();
1457
+ const scope = args?.scope ?? "effective";
1458
+ if (scope === "effective") {
1459
+ return args?.refresh ? await this.refreshEffectiveScheduleState({
1460
+ timezone,
1461
+ now: args?.now
1462
+ }) : await this.readEffectiveScheduleState({
1463
+ timezone,
1464
+ now: args?.now
1465
+ });
1466
+ }
1467
+ if (scope === "local" && args?.refresh) {
1468
+ return await this.refreshLocalMergedScheduleState({
1469
+ timezone,
1470
+ now: args?.now
1471
+ });
1472
+ }
1473
+ const state = await this.repository.getScheduleMergedState(
1474
+ this.agentId(),
1475
+ scope,
1476
+ timezone
1477
+ );
1478
+ return state ? refreshLifeOpsRelativeTime(state, args?.now ?? /* @__PURE__ */ new Date()) : null;
1479
+ }
1480
+ /** Max age for the cached adaptive window policy (30 minutes). */
1481
+ static ADAPTIVE_POLICY_TTL_MS = 30 * 60 * 1e3;
1482
+ /**
1483
+ * Read the activity profile from the proactive task metadata and return
1484
+ * an adaptive window policy. Result is cached for up to 30 minutes.
1485
+ */
1486
+ async resolveAdaptiveWindowPolicy(timezone, now) {
1487
+ const cached = this.adaptiveWindowPolicyCache;
1488
+ if (cached && now.getTime() - cached.computedAt < LifeOpsRemindersServiceMixin.ADAPTIVE_POLICY_TTL_MS) {
1489
+ return cached.policy;
1490
+ }
1491
+ try {
1492
+ const tasks = await this.runtime.getTasks({
1493
+ agentIds: [this.runtime.agentId],
1494
+ tags: [...PROACTIVE_TASK_QUERY_TAGS]
1495
+ });
1496
+ const proactiveTask = tasks.find((task) => {
1497
+ const metadata = isRecord(task.metadata) ? task.metadata : null;
1498
+ return task.name === "PROACTIVE_AGENT" && isRecord(metadata?.proactiveAgent) && metadata.proactiveAgent.kind === "runtime_runner";
1499
+ });
1500
+ const profile = proactiveTask ? readProfileFromMetadata(
1501
+ isRecord(proactiveTask.metadata) ? proactiveTask.metadata : null
1502
+ ) : null;
1503
+ const schedule = await this.refreshEffectiveScheduleState({
1504
+ timezone,
1505
+ now
1506
+ });
1507
+ const adaptiveProfile = buildAdaptiveWindowProfile({
1508
+ profile,
1509
+ schedule,
1510
+ timeZone: timezone
1511
+ });
1512
+ if (!adaptiveProfile) {
1513
+ this.adaptiveWindowPolicyCache = null;
1514
+ return null;
1515
+ }
1516
+ const policy = computeAdaptiveWindowPolicy(adaptiveProfile, timezone);
1517
+ this.adaptiveWindowPolicyCache = { policy, computedAt: now.getTime() };
1518
+ return policy;
1519
+ } catch (error) {
1520
+ this.logLifeOpsWarn(
1521
+ "adaptive_window_policy",
1522
+ "[lifeops] Failed to resolve adaptive window policy; using defaults.",
1523
+ { error: lifeOpsErrorMessage(error) }
1524
+ );
1525
+ this.adaptiveWindowPolicyCache = null;
1526
+ return null;
1527
+ }
1528
+ }
1529
+ async refreshDefinitionOccurrences(definition, now = /* @__PURE__ */ new Date()) {
1530
+ const existingOccurrences = await this.repository.listOccurrencesForDefinition(
1531
+ definition.agentId,
1532
+ definition.id
1533
+ );
1534
+ let effectiveDefinition = definition;
1535
+ if (windowPolicyMatchesDefaults(definition.windowPolicy)) {
1536
+ const adaptivePolicy = await this.resolveAdaptiveWindowPolicy(
1537
+ definition.timezone,
1538
+ now
1539
+ );
1540
+ if (adaptivePolicy) {
1541
+ effectiveDefinition = { ...definition, windowPolicy: adaptivePolicy };
1542
+ }
1543
+ }
1544
+ const materialized = materializeDefinitionOccurrences(
1545
+ effectiveDefinition,
1546
+ existingOccurrences,
1547
+ { now }
1548
+ );
1549
+ for (const occurrence of materialized) {
1550
+ await this.repository.upsertOccurrence(occurrence);
1551
+ }
1552
+ await this.repository.pruneNonTerminalOccurrences(
1553
+ definition.agentId,
1554
+ definition.id,
1555
+ materialized.map((occurrence) => occurrence.occurrenceKey)
1556
+ );
1557
+ return materialized;
1558
+ }
1559
+ async getFreshOccurrence(occurrenceId, now = /* @__PURE__ */ new Date()) {
1560
+ const occurrence = await this.repository.getOccurrence(
1561
+ this.agentId(),
1562
+ occurrenceId
1563
+ );
1564
+ if (!occurrence) {
1565
+ fail(404, "life-ops occurrence not found");
1566
+ }
1567
+ const definition = await this.repository.getDefinition(
1568
+ this.agentId(),
1569
+ occurrence.definitionId
1570
+ );
1571
+ if (!definition) {
1572
+ fail(404, "life-ops definition not found for occurrence");
1573
+ }
1574
+ if (definition.status === "active") {
1575
+ await this.refreshDefinitionOccurrences(definition, now);
1576
+ }
1577
+ const freshOccurrence = await this.repository.getOccurrence(
1578
+ this.agentId(),
1579
+ occurrenceId
1580
+ );
1581
+ if (!freshOccurrence) {
1582
+ fail(404, "life-ops occurrence not found after refresh");
1583
+ }
1584
+ return {
1585
+ definition,
1586
+ occurrence: freshOccurrence
1587
+ };
1588
+ }
1589
+ async resolvePrimaryChannelPolicy(channelType) {
1590
+ const policies = (await this.repository.listChannelPolicies(this.agentId())).filter((policy) => policy.channelType === channelType);
1591
+ return policies.find((policy) => policy.metadata.isPrimary === true) ?? policies[0] ?? null;
1592
+ }
1593
+ async resolveRuntimeReminderTarget(channel, policy, ownerContacts = loadOwnerContactsConfig(
1594
+ LIFEOPS_OWNER_CONTACTS_LOAD_CONTEXT
1595
+ ), ownerContactHints) {
1596
+ const metadata = policy ? policy.metadata : null;
1597
+ const configuredSource = (metadata && normalizeOptionalString(metadata.source)) ?? (metadata && normalizeOptionalString(metadata.platform)) ?? channel;
1598
+ const hints = ownerContactHints ?? await loadOwnerContactRoutingHints(this.runtime, ownerContacts);
1599
+ const ownerEntityId = await this.ownerRoutingEntityId();
1600
+ const hint = hints[configuredSource] ?? hints[channel] ?? {
1601
+ source: configuredSource,
1602
+ entityId: null,
1603
+ channelId: null,
1604
+ roomId: null,
1605
+ preferredCommunicationChannel: null,
1606
+ platformIdentities: [],
1607
+ lastResponseAt: null,
1608
+ lastResponseChannel: null,
1609
+ resolvedFrom: "config"
1610
+ };
1611
+ const contactResolution = resolveOwnerContactWithFallback({
1612
+ ownerContacts,
1613
+ source: hint.source,
1614
+ ownerEntityId
1615
+ }) ?? resolveOwnerContactWithFallback({
1616
+ ownerContacts,
1617
+ source: channel,
1618
+ ownerEntityId
1619
+ });
1620
+ const contact = contactResolution?.contact ?? ownerContacts[hint.source] ?? ownerContacts[channel];
1621
+ const entityId = (metadata && normalizeOptionalString(metadata.entityId)) ?? normalizeOptionalString(hint.entityId) ?? normalizeOptionalString(contact?.entityId) ?? null;
1622
+ const channelId = (metadata && normalizeOptionalString(metadata.channelId)) ?? normalizeOptionalString(hint.channelId) ?? normalizeOptionalString(contact?.channelId) ?? null;
1623
+ const roomId = (metadata && normalizeOptionalString(metadata.roomId)) ?? normalizeOptionalString(hint.roomId) ?? normalizeOptionalString(contact?.roomId) ?? null;
1624
+ if (!entityId && !channelId && !roomId) {
1625
+ return null;
1626
+ }
1627
+ const targetRef = channelId ?? roomId ?? entityId ?? policy?.channelRef ?? null;
1628
+ return {
1629
+ source: contactResolution?.source ?? hint.source,
1630
+ connectorRef: `runtime:${contactResolution?.source ?? hint.source}:${targetRef}`,
1631
+ target: {
1632
+ source: contactResolution?.source ?? hint.source,
1633
+ entityId,
1634
+ channelId,
1635
+ roomId
1636
+ },
1637
+ resolution: {
1638
+ sourceOfTruth: hint.resolvedFrom,
1639
+ preferredCommunicationChannel: hint.preferredCommunicationChannel,
1640
+ platformIdentities: hint.platformIdentities,
1641
+ lastResponseAt: hint.lastResponseAt,
1642
+ lastResponseChannel: hint.lastResponseChannel
1643
+ }
1644
+ };
1645
+ }
1646
+ async readLifeOpsAttentionContext(args) {
1647
+ try {
1648
+ const now = args?.now ?? /* @__PURE__ */ new Date();
1649
+ const schedule = await this.refreshEffectiveScheduleState({
1650
+ timezone: normalizeOptionalString(args?.timezone) ?? resolveDefaultTimeZone(),
1651
+ now
1652
+ });
1653
+ const tasks = await this.runtime.getTasks({
1654
+ agentIds: [this.runtime.agentId],
1655
+ tags: [...PROACTIVE_TASK_QUERY_TAGS]
1656
+ });
1657
+ const proactiveTask = tasks.find((task) => {
1658
+ const metadata = isRecord(task.metadata) ? task.metadata : null;
1659
+ return task.name === "PROACTIVE_AGENT" && isRecord(metadata?.proactiveAgent) && metadata.proactiveAgent.kind === "runtime_runner";
1660
+ });
1661
+ const profile = proactiveTask && isRecord(proactiveTask.metadata) ? proactiveTask.metadata.activityProfile : null;
1662
+ if (!isRecord(profile) && !schedule) {
1663
+ return null;
1664
+ }
1665
+ const profileLastSeenAt = isRecord(profile) && typeof profile.lastSeenAt === "number" ? profile.lastSeenAt : null;
1666
+ const scheduleLastSeenAt = schedule?.lastActiveAt ? Date.parse(schedule.lastActiveAt) : null;
1667
+ const lastSeenAt = profileLastSeenAt ?? scheduleLastSeenAt;
1668
+ return {
1669
+ source: isRecord(profile) && schedule ? "mixed" : isRecord(profile) ? "proactive_activity_profile" : schedule ? "schedule_state" : "unknown",
1670
+ capturedAt: now.toISOString(),
1671
+ sourceFreshnessMs: lastSeenAt !== null ? Math.max(0, now.getTime() - lastSeenAt) : null,
1672
+ sourceConfidence: schedule?.stateConfidence ?? null,
1673
+ privacyMode: "unknown",
1674
+ socialContext: "unknown",
1675
+ locationSafety: "unknown",
1676
+ primaryPlatform: isRecord(profile) ? normalizeOptionalString(profile.primaryPlatform) ?? null : null,
1677
+ secondaryPlatform: isRecord(profile) ? normalizeOptionalString(profile.secondaryPlatform) ?? null : null,
1678
+ lastSeenPlatform: isRecord(profile) ? normalizeOptionalString(profile.lastSeenPlatform) ?? null : null,
1679
+ isCurrentlyActive: isRecord(profile) && profile.isCurrentlyActive === true,
1680
+ lastSeenAt,
1681
+ circadianState: schedule?.circadianState ?? "unclear",
1682
+ stateConfidence: schedule?.stateConfidence ?? 0,
1683
+ lastSleepEndedAt: schedule?.lastSleepEndedAt ?? null,
1684
+ nextMealLabel: schedule?.nextMealLabel ?? null,
1685
+ nextMealWindowStartAt: schedule?.nextMealWindowStartAt ?? null,
1686
+ nextMealWindowEndAt: schedule?.nextMealWindowEndAt ?? null,
1687
+ calendarBusy: isRecord(profile) && profile.calendarBusy === true,
1688
+ dndActive: isRecord(profile) && profile.dndActive === true,
1689
+ hasCalendarData: isRecord(profile) && typeof profile.hasCalendarData === "boolean" ? profile.hasCalendarData : false,
1690
+ avgWeekdayMeetings: isRecord(profile) && typeof profile.avgWeekdayMeetings === "number" ? profile.avgWeekdayMeetings : null,
1691
+ hasOpenActivityCycle: isRecord(profile) && profile.hasOpenActivityCycle === true,
1692
+ currentActivityCycleStartedAt: isRecord(profile) && typeof profile.currentActivityCycleStartedAt === "number" ? profile.currentActivityCycleStartedAt : null,
1693
+ screenContextFocus: isRecord(profile) ? normalizeScreenContextFocus(profile.screenContextFocus) : null,
1694
+ screenContextBusy: isRecord(profile) && profile.screenContextBusy === true,
1695
+ screenContextAvailable: isRecord(profile) && profile.screenContextAvailable === true,
1696
+ screenContextStale: isRecord(profile) && profile.screenContextStale === true,
1697
+ screenContextConfidence: isRecord(profile) && typeof profile.screenContextConfidence === "number" ? profile.screenContextConfidence : null
1698
+ };
1699
+ } catch (error) {
1700
+ this.logLifeOpsWarn(
1701
+ "reminder_activity_profile",
1702
+ "[lifeops] Failed to read proactive activity profile; using connector order for owner contact routing.",
1703
+ {
1704
+ error: lifeOpsErrorMessage(error)
1705
+ }
1706
+ );
1707
+ return null;
1708
+ }
1709
+ }
1710
+ async readReminderActivityProfileSnapshot(args) {
1711
+ return this.readLifeOpsAttentionContext(args);
1712
+ }
1713
+ /**
1714
+ * Scan recent "delivered" attempts and upgrade to "delivered_read" when the
1715
+ * owner was seen active after the reminder was sent. This gives escalation
1716
+ * better signal about whether the owner is reachable.
1717
+ */
1718
+ async scanReadReceipts(attempts, activityProfile, now) {
1719
+ if (!activityProfile?.lastSeenAt) {
1720
+ return;
1721
+ }
1722
+ const RECEIPT_SCAN_WINDOW_MS = 4 * 60 * 60 * 1e3;
1723
+ const cutoff = now.getTime() - RECEIPT_SCAN_WINDOW_MS;
1724
+ const candidates = attempts.filter((attempt) => {
1725
+ if (attempt.outcome !== "delivered") {
1726
+ return false;
1727
+ }
1728
+ const attemptedMs = attempt.attemptedAt ? Date.parse(attempt.attemptedAt) : 0;
1729
+ return attemptedMs > cutoff;
1730
+ });
1731
+ for (const attempt of candidates) {
1732
+ const attemptedMs = attempt.attemptedAt ? Date.parse(attempt.attemptedAt) : 0;
1733
+ if (activityProfile.lastSeenAt > attemptedMs) {
1734
+ try {
1735
+ await this.repository.updateReminderAttemptOutcome(
1736
+ attempt.id,
1737
+ "delivered_read",
1738
+ { readDetectedAt: now.toISOString() }
1739
+ );
1740
+ attempt.outcome = "delivered_read";
1741
+ } catch (error) {
1742
+ this.logLifeOpsWarn(
1743
+ "read_receipt_scan",
1744
+ `[lifeops] Failed to update read receipt for attempt ${attempt.id}`,
1745
+ { error: lifeOpsErrorMessage(error) }
1746
+ );
1747
+ }
1748
+ }
1749
+ }
1750
+ }
1751
+ buildReminderPlanSchedule(args) {
1752
+ const rows = [];
1753
+ if (args.ownerType === "occurrence") {
1754
+ const anchorIso = args.occurrence?.snoozedUntil ?? args.occurrence?.relevanceStartAt;
1755
+ if (!anchorIso) {
1756
+ return rows;
1757
+ }
1758
+ const anchorDate = new Date(anchorIso);
1759
+ for (const [stepIndex, step] of args.plan.steps.entries()) {
1760
+ rows.push({
1761
+ ownerType: args.ownerType,
1762
+ ownerId: args.ownerId,
1763
+ occurrenceId: args.occurrenceId,
1764
+ title: args.title,
1765
+ channel: step.channel,
1766
+ stepIndex,
1767
+ scheduledFor: addMinutes(
1768
+ anchorDate,
1769
+ step.offsetMinutes
1770
+ ).toISOString()
1771
+ });
1772
+ }
1773
+ return rows;
1774
+ }
1775
+ if (!args.eventStartAt) {
1776
+ return rows;
1777
+ }
1778
+ const eventStartAt = new Date(args.eventStartAt);
1779
+ for (const [stepIndex, step] of args.plan.steps.entries()) {
1780
+ rows.push({
1781
+ ownerType: args.ownerType,
1782
+ ownerId: args.ownerId,
1783
+ occurrenceId: args.occurrenceId,
1784
+ title: args.title,
1785
+ channel: step.channel,
1786
+ stepIndex,
1787
+ scheduledFor: addMinutes(
1788
+ eventStartAt,
1789
+ -step.offsetMinutes
1790
+ ).toISOString()
1791
+ });
1792
+ }
1793
+ return rows;
1794
+ }
1795
+ async resolveOwnerContactRouteCandidates(args) {
1796
+ const ownerContacts = loadOwnerContactsConfig(
1797
+ LIFEOPS_OWNER_CONTACTS_LOAD_CONTEXT
1798
+ );
1799
+ const ownerContactHints = await loadOwnerContactRoutingHints(
1800
+ this.runtime,
1801
+ ownerContacts
1802
+ );
1803
+ return resolveContactRouteCandidates({
1804
+ purpose: args.purpose,
1805
+ activityProfile: args.activityProfile,
1806
+ ownerContactHints,
1807
+ ownerContactSources: Object.keys(ownerContacts),
1808
+ policies: args.policies,
1809
+ urgency: args.urgency,
1810
+ attempts: args.attempts,
1811
+ now: args.now,
1812
+ callbacks: {
1813
+ runtimeTargetSendAvailable: typeof this.runtime.sendMessageToTarget === "function",
1814
+ resolvePrimaryChannelPolicy: (channel) => this.resolvePrimaryChannelPolicy(channel),
1815
+ hasRuntimeTarget: async (channel, policy) => {
1816
+ if (channel === "in_app" || channel === "sms" || channel === "voice") {
1817
+ return false;
1818
+ }
1819
+ return await this.resolveRuntimeReminderTarget(
1820
+ channel,
1821
+ policy,
1822
+ ownerContacts,
1823
+ ownerContactHints
1824
+ ) !== null;
1825
+ }
1826
+ }
1827
+ });
1828
+ }
1829
+ async resolveReminderEscalationRouteCandidates(args) {
1830
+ return this.resolveOwnerContactRouteCandidates({
1831
+ ...args,
1832
+ purpose: "reminder_escalation"
1833
+ });
1834
+ }
1835
+ async buildOwnerContactRouteEventMetadata(args) {
1836
+ try {
1837
+ const [activityProfile, policies] = await Promise.all([
1838
+ this.readReminderActivityProfileSnapshot({ now: args.now }),
1839
+ this.repository.listChannelPolicies(this.agentId())
1840
+ ]);
1841
+ const candidates = await this.resolveOwnerContactRouteCandidates({
1842
+ purpose: args.purpose,
1843
+ activityProfile,
1844
+ policies,
1845
+ urgency: args.urgency,
1846
+ attempts: [],
1847
+ now: args.now
1848
+ });
1849
+ return {
1850
+ contactRoutePurpose: args.purpose,
1851
+ contactRouteCandidates: serializeContactRouteCandidates(candidates)
1852
+ };
1853
+ } catch (error) {
1854
+ this.logLifeOpsWarn(
1855
+ "owner_contact_route_metadata",
1856
+ "[lifeops] Failed to resolve owner contact route metadata.",
1857
+ {
1858
+ purpose: args.purpose,
1859
+ error: lifeOpsErrorMessage(error)
1860
+ }
1861
+ );
1862
+ return {
1863
+ contactRoutePurpose: args.purpose,
1864
+ contactRouteCandidates: [],
1865
+ contactRouteError: lifeOpsErrorMessage(error)
1866
+ };
1867
+ }
1868
+ }
1869
+ async resolveReminderEscalationChannels(args) {
1870
+ const candidates = await this.resolveReminderEscalationRouteCandidates(args);
1871
+ return candidates.filter((candidate) => candidate.vetoReasons.length === 0).map((candidate) => candidate.channel);
1872
+ }
1873
+ async markReminderEscalationStarted(args) {
1874
+ if (args.ownerType === "occurrence") {
1875
+ const occurrence = await this.repository.getOccurrence(
1876
+ this.agentId(),
1877
+ args.ownerId
1878
+ );
1879
+ if (!occurrence) {
1880
+ return;
1881
+ }
1882
+ const channels2 = Array.isArray(
1883
+ occurrence.metadata[REMINDER_ESCALATION_CHANNELS_METADATA_KEY]
1884
+ ) ? occurrence.metadata[REMINDER_ESCALATION_CHANNELS_METADATA_KEY].filter(isReminderChannel) : [];
1885
+ const nextChannels2 = [.../* @__PURE__ */ new Set([...channels2, args.channel])];
1886
+ await this.repository.updateOccurrence({
1887
+ ...occurrence,
1888
+ metadata: {
1889
+ ...occurrence.metadata,
1890
+ [REMINDER_ESCALATION_STARTED_AT_METADATA_KEY]: typeof occurrence.metadata[REMINDER_ESCALATION_STARTED_AT_METADATA_KEY] === "string" ? occurrence.metadata[REMINDER_ESCALATION_STARTED_AT_METADATA_KEY] : args.attemptedAt,
1891
+ [REMINDER_ESCALATION_LAST_ATTEMPT_AT_METADATA_KEY]: args.attemptedAt,
1892
+ [REMINDER_ESCALATION_LAST_CHANNEL_METADATA_KEY]: args.channel,
1893
+ [REMINDER_ESCALATION_LAST_OUTCOME_METADATA_KEY]: args.outcome,
1894
+ [REMINDER_ESCALATION_CHANNELS_METADATA_KEY]: nextChannels2
1895
+ },
1896
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1897
+ });
1898
+ return;
1899
+ }
1900
+ const event = (await this.repository.listCalendarEvents(this.agentId(), "google")).find((candidate) => candidate.id === args.ownerId);
1901
+ if (!event) {
1902
+ return;
1903
+ }
1904
+ const channels = Array.isArray(
1905
+ event.metadata[REMINDER_ESCALATION_CHANNELS_METADATA_KEY]
1906
+ ) ? event.metadata[REMINDER_ESCALATION_CHANNELS_METADATA_KEY].filter(isReminderChannel) : [];
1907
+ const nextChannels = [.../* @__PURE__ */ new Set([...channels, args.channel])];
1908
+ await this.repository.upsertCalendarEvent({
1909
+ ...event,
1910
+ metadata: {
1911
+ ...event.metadata,
1912
+ [REMINDER_ESCALATION_STARTED_AT_METADATA_KEY]: typeof event.metadata[REMINDER_ESCALATION_STARTED_AT_METADATA_KEY] === "string" ? event.metadata[REMINDER_ESCALATION_STARTED_AT_METADATA_KEY] : args.attemptedAt,
1913
+ [REMINDER_ESCALATION_LAST_ATTEMPT_AT_METADATA_KEY]: args.attemptedAt,
1914
+ [REMINDER_ESCALATION_LAST_CHANNEL_METADATA_KEY]: args.channel,
1915
+ [REMINDER_ESCALATION_LAST_OUTCOME_METADATA_KEY]: args.outcome,
1916
+ [REMINDER_ESCALATION_CHANNELS_METADATA_KEY]: nextChannels
1917
+ },
1918
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1919
+ });
1920
+ }
1921
+ async resolveReminderEscalation(args) {
1922
+ const attempts = await this.repository.listReminderAttempts(
1923
+ this.agentId(),
1924
+ {
1925
+ ownerType: args.ownerType,
1926
+ ownerId: args.ownerId
1927
+ }
1928
+ );
1929
+ const escalationAttempts = attempts.filter(
1930
+ (attempt) => readReminderAttemptLifecycle(attempt) === "escalation"
1931
+ );
1932
+ const latestEscalation = escalationAttempts.at(-1) ?? null;
1933
+ if (!latestEscalation) {
1934
+ return;
1935
+ }
1936
+ const latestEscalationAt = Date.parse(
1937
+ latestEscalation.attemptedAt ?? latestEscalation.scheduledFor
1938
+ );
1939
+ if (args.ownerType === "occurrence") {
1940
+ const occurrence = await this.repository.getOccurrence(
1941
+ this.agentId(),
1942
+ args.ownerId
1943
+ );
1944
+ if (!occurrence) {
1945
+ return;
1946
+ }
1947
+ const resolvedAtValue = typeof occurrence.metadata[REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY] === "string" ? occurrence.metadata[REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY] : null;
1948
+ if (resolvedAtValue && Date.parse(resolvedAtValue) >= latestEscalationAt) {
1949
+ return;
1950
+ }
1951
+ await this.repository.updateOccurrence({
1952
+ ...occurrence,
1953
+ metadata: {
1954
+ ...occurrence.metadata,
1955
+ [REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY]: args.resolvedAt,
1956
+ [REMINDER_ESCALATION_RESOLUTION_METADATA_KEY]: args.resolution,
1957
+ [REMINDER_ESCALATION_RESOLUTION_NOTE_METADATA_KEY]: args.note ?? null
1958
+ },
1959
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1960
+ });
1961
+ } else {
1962
+ const event = (await this.repository.listCalendarEvents(this.agentId(), "google")).find((candidate) => candidate.id === args.ownerId);
1963
+ if (!event) {
1964
+ return;
1965
+ }
1966
+ const resolvedAtValue = typeof event.metadata[REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY] === "string" ? event.metadata[REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY] : null;
1967
+ if (resolvedAtValue && Date.parse(resolvedAtValue) >= latestEscalationAt) {
1968
+ return;
1969
+ }
1970
+ await this.repository.upsertCalendarEvent({
1971
+ ...event,
1972
+ metadata: {
1973
+ ...event.metadata,
1974
+ [REMINDER_ESCALATION_RESOLVED_AT_METADATA_KEY]: args.resolvedAt,
1975
+ [REMINDER_ESCALATION_RESOLUTION_METADATA_KEY]: args.resolution,
1976
+ [REMINDER_ESCALATION_RESOLUTION_NOTE_METADATA_KEY]: args.note ?? null
1977
+ },
1978
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1979
+ });
1980
+ }
1981
+ await this.recordReminderAudit(
1982
+ "reminder_escalation_resolved",
1983
+ args.ownerType,
1984
+ args.ownerId,
1985
+ "reminder escalation resolved",
1986
+ {
1987
+ resolution: args.resolution,
1988
+ note: args.note ?? null
1989
+ },
1990
+ {
1991
+ resolvedAt: args.resolvedAt,
1992
+ lastEscalationChannel: latestEscalation.channel,
1993
+ lastEscalationOutcome: latestEscalation.outcome
1994
+ }
1995
+ );
1996
+ }
1997
+ async resolveReminderReviewFromOwnerResponse(args) {
1998
+ if (args.resolution === "snoozed") {
1999
+ if (args.ownerType !== "occurrence" || !args.snoozeRequest) {
2000
+ await this.markReminderReviewObservedResponse({
2001
+ attempt: args.attempt,
2002
+ decision: "needs_clarification",
2003
+ respondedAt: args.respondedAt,
2004
+ responseText: args.responseText,
2005
+ reason: "snooze_resolution_missing_reschedulable_occurrence",
2006
+ classifierSource: args.classifierSource,
2007
+ semanticReason: args.semanticReason
2008
+ });
2009
+ return;
2010
+ }
2011
+ }
2012
+ const reviewMetadata = {
2013
+ [REMINDER_REVIEW_STATUS_METADATA_KEY]: "resolved",
2014
+ [REMINDER_REVIEW_DECISION_METADATA_KEY]: args.resolution,
2015
+ [REMINDER_REVIEW_RESPONDED_AT_METADATA_KEY]: args.respondedAt,
2016
+ [REMINDER_REVIEW_RESPONSE_TEXT_METADATA_KEY]: args.responseText,
2017
+ reviewConfidence: args.confidence,
2018
+ reviewReason: args.reason,
2019
+ [REMINDER_REVIEW_CLASSIFIER_SOURCE_METADATA_KEY]: args.classifierSource ?? null,
2020
+ [REMINDER_REVIEW_SEMANTIC_REASON_METADATA_KEY]: args.semanticReason ?? null
2021
+ };
2022
+ const acknowledgementNote = args.responseText ? `Owner replied: ${args.responseText}` : args.reason;
2023
+ if (args.resolution === "snoozed") {
2024
+ if (!args.snoozeRequest) {
2025
+ throw new Error(
2026
+ "snoozeRequest is required to snooze a reminder occurrence"
2027
+ );
2028
+ }
2029
+ await this.snoozeOccurrence(
2030
+ args.ownerId,
2031
+ args.snoozeRequest,
2032
+ new Date(args.respondedAt ?? args.reviewedAt)
2033
+ );
2034
+ await this.repository.updateReminderAttemptOutcome(
2035
+ args.attempt.id,
2036
+ args.attempt.outcome,
2037
+ reviewMetadata
2038
+ );
2039
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2040
+ args.attempt.reviewStatus = "resolved";
2041
+ return;
2042
+ }
2043
+ await this.repository.updateReminderAttemptOutcome(
2044
+ args.attempt.id,
2045
+ args.attempt.outcome,
2046
+ reviewMetadata
2047
+ );
2048
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2049
+ args.attempt.reviewStatus = "resolved";
2050
+ if (args.ownerType === "occurrence") {
2051
+ const occurrence = await this.repository.getOccurrence(
2052
+ this.agentId(),
2053
+ args.ownerId
2054
+ );
2055
+ if (occurrence) {
2056
+ await this.repository.updateOccurrence({
2057
+ ...occurrence,
2058
+ metadata: {
2059
+ ...occurrence.metadata,
2060
+ reminderAcknowledgedAt: args.respondedAt ?? args.reviewedAt,
2061
+ reminderAcknowledgedNote: acknowledgementNote,
2062
+ reminderAcknowledgedResolution: args.resolution
2063
+ },
2064
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2065
+ });
2066
+ }
2067
+ } else {
2068
+ const event = (await this.repository.listCalendarEvents(this.agentId(), "google")).find((candidate) => candidate.id === args.ownerId);
2069
+ if (event) {
2070
+ await this.repository.upsertCalendarEvent({
2071
+ ...event,
2072
+ metadata: {
2073
+ ...event.metadata,
2074
+ reminderAcknowledgedAt: args.respondedAt ?? args.reviewedAt,
2075
+ reminderAcknowledgedNote: acknowledgementNote,
2076
+ reminderAcknowledgedResolution: args.resolution
2077
+ },
2078
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2079
+ });
2080
+ }
2081
+ }
2082
+ await this.resolveReminderEscalation({
2083
+ ownerType: args.ownerType,
2084
+ ownerId: args.ownerId,
2085
+ resolvedAt: args.respondedAt ?? args.reviewedAt,
2086
+ resolution: args.resolution,
2087
+ note: acknowledgementNote
2088
+ });
2089
+ }
2090
+ async markReminderReviewResolvedFromState(args) {
2091
+ const reviewMetadata = {
2092
+ [REMINDER_REVIEW_STATUS_METADATA_KEY]: "resolved",
2093
+ [REMINDER_REVIEW_DECISION_METADATA_KEY]: args.resolution,
2094
+ reviewReason: args.reason
2095
+ };
2096
+ await this.repository.updateReminderAttemptOutcome(
2097
+ args.attempt.id,
2098
+ args.attempt.outcome,
2099
+ reviewMetadata
2100
+ );
2101
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2102
+ args.attempt.reviewStatus = "resolved";
2103
+ await this.resolveReminderEscalation({
2104
+ ownerType: args.ownerType,
2105
+ ownerId: args.ownerId,
2106
+ resolvedAt: args.resolvedAt,
2107
+ resolution: args.resolution,
2108
+ note: args.reason
2109
+ });
2110
+ }
2111
+ async markReminderReviewEscalated(args) {
2112
+ const reviewMetadata = {
2113
+ [REMINDER_REVIEW_STATUS_METADATA_KEY]: "escalated",
2114
+ [REMINDER_REVIEW_DECISION_METADATA_KEY]: "escalate",
2115
+ [REMINDER_REVIEW_ESCALATED_AT_METADATA_KEY]: args.escalatedAt,
2116
+ [REMINDER_REVIEW_ESCALATED_ATTEMPT_ID_METADATA_KEY]: args.escalatedAttempt.id,
2117
+ [REMINDER_REVIEW_ESCALATED_CHANNEL_METADATA_KEY]: args.escalatedAttempt.channel
2118
+ };
2119
+ await this.repository.updateReminderAttemptOutcome(
2120
+ args.attempt.id,
2121
+ args.attempt.outcome,
2122
+ reviewMetadata
2123
+ );
2124
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2125
+ args.attempt.reviewStatus = "escalated";
2126
+ }
2127
+ async markReminderReviewClarificationRequested(args) {
2128
+ const reviewMetadata = {
2129
+ [REMINDER_REVIEW_STATUS_METADATA_KEY]: "clarification_requested",
2130
+ [REMINDER_REVIEW_DECISION_METADATA_KEY]: "clarify",
2131
+ [REMINDER_REVIEW_ESCALATED_AT_METADATA_KEY]: args.requestedAt,
2132
+ [REMINDER_REVIEW_ESCALATED_ATTEMPT_ID_METADATA_KEY]: args.clarificationAttempt.id,
2133
+ [REMINDER_REVIEW_ESCALATED_CHANNEL_METADATA_KEY]: args.clarificationAttempt.channel
2134
+ };
2135
+ await this.repository.updateReminderAttemptOutcome(
2136
+ args.attempt.id,
2137
+ args.attempt.outcome,
2138
+ reviewMetadata
2139
+ );
2140
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2141
+ args.attempt.reviewStatus = "clarification_requested";
2142
+ }
2143
+ async markReminderReviewObservedResponse(args) {
2144
+ const reviewMetadata = {
2145
+ [REMINDER_REVIEW_STATUS_METADATA_KEY]: args.decision,
2146
+ [REMINDER_REVIEW_DECISION_METADATA_KEY]: args.decision,
2147
+ [REMINDER_REVIEW_RESPONDED_AT_METADATA_KEY]: args.respondedAt,
2148
+ [REMINDER_REVIEW_RESPONSE_TEXT_METADATA_KEY]: args.responseText,
2149
+ reviewReason: args.reason,
2150
+ [REMINDER_REVIEW_CLASSIFIER_SOURCE_METADATA_KEY]: args.classifierSource ?? null,
2151
+ [REMINDER_REVIEW_SEMANTIC_REASON_METADATA_KEY]: args.semanticReason ?? null
2152
+ };
2153
+ await this.repository.updateReminderAttemptOutcome(
2154
+ args.attempt.id,
2155
+ args.attempt.outcome,
2156
+ reviewMetadata
2157
+ );
2158
+ Object.assign(args.attempt.deliveryMetadata, reviewMetadata);
2159
+ args.attempt.reviewStatus = args.decision;
2160
+ }
2161
+ async processDueReminderReviewJobs(args) {
2162
+ if (args.limit <= 0) {
2163
+ return [];
2164
+ }
2165
+ const nowIso = args.now.toISOString();
2166
+ const dueReviewAttempts = typeof this.repository.claimDueReminderReviewAttempts === "function" ? await this.repository.claimDueReminderReviewAttempts(
2167
+ this.agentId(),
2168
+ nowIso,
2169
+ args.limit,
2170
+ crypto.randomUUID()
2171
+ ) : await this.repository.listDueReminderReviewAttempts(
2172
+ this.agentId(),
2173
+ nowIso,
2174
+ args.limit
2175
+ );
2176
+ if (dueReviewAttempts.length === 0) {
2177
+ return [];
2178
+ }
2179
+ const allAttempts = [...args.attempts];
2180
+ const attemptsById = new Map(
2181
+ allAttempts.map((attempt) => [attempt.id, attempt])
2182
+ );
2183
+ for (const attempt of dueReviewAttempts) {
2184
+ if (!attemptsById.has(attempt.id)) {
2185
+ allAttempts.push(attempt);
2186
+ attemptsById.set(attempt.id, attempt);
2187
+ }
2188
+ }
2189
+ const dispatchedAttempts = [];
2190
+ let calendarEvents = null;
2191
+ for (const dueReviewAttempt of dueReviewAttempts) {
2192
+ const reviewAttempt = attemptsById.get(dueReviewAttempt.id) ?? dueReviewAttempt;
2193
+ if (dispatchedAttempts.length >= args.limit) {
2194
+ break;
2195
+ }
2196
+ if (isReminderReviewClosed(reviewAttempt)) {
2197
+ continue;
2198
+ }
2199
+ const plan = await this.repository.getReminderPlan(
2200
+ this.agentId(),
2201
+ reviewAttempt.planId
2202
+ );
2203
+ if (!plan) {
2204
+ continue;
2205
+ }
2206
+ if (reviewAttempt.ownerType === "occurrence") {
2207
+ const occurrence = await this.repository.getOccurrenceView(
2208
+ this.agentId(),
2209
+ reviewAttempt.ownerId
2210
+ );
2211
+ if (!occurrence) {
2212
+ continue;
2213
+ }
2214
+ const stateResolution = occurrence.state === "completed" ? "completed" : occurrence.state === "skipped" ? "skipped" : occurrence.state === "snoozed" ? "snoozed" : occurrence.metadata.reminderAcknowledgedAt ? "acknowledged" : null;
2215
+ if (stateResolution) {
2216
+ await this.markReminderReviewResolvedFromState({
2217
+ ownerType: "occurrence",
2218
+ ownerId: occurrence.id,
2219
+ attempt: reviewAttempt,
2220
+ resolvedAt: nowIso,
2221
+ resolution: stateResolution,
2222
+ reason: `occurrence_state_${occurrence.state}`
2223
+ });
2224
+ continue;
2225
+ }
2226
+ const definition = await this.repository.getDefinition(
2227
+ this.agentId(),
2228
+ occurrence.definitionId
2229
+ );
2230
+ const preference = definition ? await this.getReminderPreference(definition.id) : null;
2231
+ const attempt = await this.dispatchDueReminderEscalation({
2232
+ plan,
2233
+ ownerType: "occurrence",
2234
+ ownerId: occurrence.id,
2235
+ occurrenceId: occurrence.id,
2236
+ subjectType: occurrence.subjectType,
2237
+ title: occurrence.title,
2238
+ dueAt: occurrence.dueAt,
2239
+ urgency: resolveReminderDeliveryUrgency({
2240
+ metadata: occurrence.metadata,
2241
+ priority: occurrence.priority
2242
+ }),
2243
+ intensity: preference?.effective.intensity ?? args.defaultIntensity,
2244
+ quietHours: plan.quietHours,
2245
+ attemptedAt: nowIso,
2246
+ now: args.now,
2247
+ attempts: allAttempts,
2248
+ policies: args.policies,
2249
+ activityProfile: args.activityProfile,
2250
+ occurrence,
2251
+ acknowledged: false,
2252
+ nearbyReminderTitles: [],
2253
+ timezone: args.timezone,
2254
+ definition,
2255
+ reviewAttempt
2256
+ });
2257
+ if (attempt) {
2258
+ dispatchedAttempts.push(attempt);
2259
+ allAttempts.push(attempt);
2260
+ attemptsById.set(attempt.id, attempt);
2261
+ }
2262
+ continue;
2263
+ }
2264
+ if (reviewAttempt.ownerType === "calendar_event") {
2265
+ calendarEvents ??= await this.repository.listCalendarEvents(
2266
+ this.agentId(),
2267
+ "google"
2268
+ );
2269
+ const event = calendarEvents.find(
2270
+ (candidate) => candidate.id === reviewAttempt.ownerId
2271
+ ) ?? null;
2272
+ if (!event) {
2273
+ continue;
2274
+ }
2275
+ if (event.metadata.reminderAcknowledgedAt) {
2276
+ await this.markReminderReviewResolvedFromState({
2277
+ ownerType: "calendar_event",
2278
+ ownerId: event.id,
2279
+ attempt: reviewAttempt,
2280
+ resolvedAt: nowIso,
2281
+ resolution: "acknowledged",
2282
+ reason: "calendar_event_already_acknowledged"
2283
+ });
2284
+ continue;
2285
+ }
2286
+ const attempt = await this.dispatchDueReminderEscalation({
2287
+ plan,
2288
+ ownerType: "calendar_event",
2289
+ ownerId: event.id,
2290
+ occurrenceId: null,
2291
+ subjectType: "owner",
2292
+ title: event.title,
2293
+ dueAt: event.startAt,
2294
+ urgency: resolveReminderDeliveryUrgency({
2295
+ metadata: event.metadata,
2296
+ fallback: "medium"
2297
+ }),
2298
+ intensity: args.defaultIntensity,
2299
+ quietHours: plan.quietHours,
2300
+ attemptedAt: nowIso,
2301
+ now: args.now,
2302
+ attempts: allAttempts,
2303
+ policies: args.policies,
2304
+ activityProfile: args.activityProfile,
2305
+ eventStartAt: event.startAt,
2306
+ acknowledged: false,
2307
+ nearbyReminderTitles: [],
2308
+ timezone: args.timezone,
2309
+ definition: null,
2310
+ reviewAttempt
2311
+ });
2312
+ if (attempt) {
2313
+ dispatchedAttempts.push(attempt);
2314
+ allAttempts.push(attempt);
2315
+ attemptsById.set(attempt.id, attempt);
2316
+ }
2317
+ }
2318
+ }
2319
+ return dispatchedAttempts;
2320
+ }
2321
+ async dispatchDueReminderEscalation(args) {
2322
+ if (!shouldDeliverReminderForIntensity(args.intensity, args.urgency)) {
2323
+ return null;
2324
+ }
2325
+ if (args.acknowledged || args.urgency === "low") {
2326
+ return null;
2327
+ }
2328
+ const ownerAttempts = args.attempts.filter(
2329
+ (attempt2) => attempt2.ownerType === args.ownerType && attempt2.ownerId === args.ownerId
2330
+ );
2331
+ if (ownerAttempts.length === 0) {
2332
+ return null;
2333
+ }
2334
+ const escalationAttempts = ownerAttempts.filter(
2335
+ (attempt2) => readReminderAttemptLifecycle(attempt2) === "escalation"
2336
+ );
2337
+ const schedule = this.buildReminderPlanSchedule({
2338
+ ownerType: args.ownerType,
2339
+ ownerId: args.ownerId,
2340
+ occurrenceId: args.occurrenceId,
2341
+ title: args.title,
2342
+ plan: args.plan,
2343
+ occurrence: args.occurrence ?? null,
2344
+ eventStartAt: args.eventStartAt ?? null
2345
+ });
2346
+ if (schedule.length === 0) {
2347
+ return null;
2348
+ }
2349
+ const lastNormalAttempt = ownerAttempts.filter((attempt2) => readReminderAttemptLifecycle(attempt2) === "plan").at(-1);
2350
+ if (!lastNormalAttempt) {
2351
+ return null;
2352
+ }
2353
+ const lastScheduledPlanEntry = schedule[schedule.length - 1];
2354
+ const lastScheduledPlanTime = Date.parse(
2355
+ lastScheduledPlanEntry.scheduledFor
2356
+ );
2357
+ const nowMs = args.now.getTime();
2358
+ const planExhausted = nowMs >= lastScheduledPlanTime;
2359
+ const reviewAttempt = args.reviewAttempt ?? readLatestPendingReminderReviewAttempt(ownerAttempts);
2360
+ const reviewAt = reviewAttempt ? readReminderReviewAt(reviewAttempt) : null;
2361
+ const reviewDue = reviewAt !== null && Date.parse(reviewAt) <= nowMs;
2362
+ if (!reviewDue && !planExhausted && !shouldEscalateImmediately(lastNormalAttempt.outcome)) {
2363
+ return null;
2364
+ }
2365
+ const lastScheduledPlanAttempt = ownerAttempts.find(
2366
+ (attempt2) => readReminderAttemptLifecycle(attempt2) === "plan" && attempt2.stepIndex === lastScheduledPlanEntry.stepIndex && attempt2.scheduledFor === lastScheduledPlanEntry.scheduledFor
2367
+ );
2368
+ const gatingPlanAttempt = planExhausted ? lastScheduledPlanAttempt : lastNormalAttempt;
2369
+ if (!reviewDue && !gatingPlanAttempt && escalationAttempts.length === 0) {
2370
+ return null;
2371
+ }
2372
+ const previousAttempt = (reviewDue ? reviewAttempt : null) ?? escalationAttempts.at(-1) ?? gatingPlanAttempt ?? lastNormalAttempt;
2373
+ if (!previousAttempt) {
2374
+ return null;
2375
+ }
2376
+ const escalationProfile = readReminderEscalationProfile(args.definition);
2377
+ const enforcementState = buildReminderEnforcementState(
2378
+ args.now,
2379
+ args.timezone,
2380
+ args.definition,
2381
+ { voice: readTwilioCredentialsFromEnv() !== null }
2382
+ );
2383
+ let forceChannel = resolveReminderEscalationProfileDecision({
2384
+ normalDelayMinutes: null,
2385
+ state: enforcementState,
2386
+ urgency: args.urgency,
2387
+ profile: escalationProfile
2388
+ }).forceChannel;
2389
+ let scheduledFor = reviewDue ? reviewAt : null;
2390
+ if (!scheduledFor) {
2391
+ const baseDelayMinutes = resolveReminderEscalationDelayMinutes(
2392
+ args.urgency,
2393
+ previousAttempt.outcome,
2394
+ escalationAttempts.length > 0
2395
+ );
2396
+ if (baseDelayMinutes === null) {
2397
+ return null;
2398
+ }
2399
+ const enforcement = resolveReminderEscalationProfileDecision({
2400
+ normalDelayMinutes: baseDelayMinutes,
2401
+ state: enforcementState,
2402
+ urgency: args.urgency,
2403
+ profile: escalationProfile
2404
+ });
2405
+ forceChannel = forceChannel ?? enforcement.forceChannel;
2406
+ scheduledFor = addMinutes(
2407
+ new Date(previousAttempt.attemptedAt ?? previousAttempt.scheduledFor),
2408
+ enforcement.delayMinutes ?? baseDelayMinutes
2409
+ ).toISOString();
2410
+ }
2411
+ if (Date.parse(scheduledFor) > nowMs) {
2412
+ return null;
2413
+ }
2414
+ if (isDeliveredReminderOutcome(previousAttempt.outcome)) {
2415
+ const responseReview = await this.reviewOwnerResponseAfterReminderAttempt({
2416
+ subjectType: args.subjectType,
2417
+ attempt: previousAttempt,
2418
+ competingAttempts: ownerAttempts,
2419
+ now: args.now
2420
+ });
2421
+ const reviewTransition = decideReminderReviewTransition({
2422
+ reviewDue,
2423
+ ownerType: args.ownerType,
2424
+ responseReview
2425
+ });
2426
+ if (reviewTransition.kind === "resolve") {
2427
+ await this.resolveReminderReviewFromOwnerResponse({
2428
+ ownerType: args.ownerType,
2429
+ ownerId: args.ownerId,
2430
+ attempt: previousAttempt,
2431
+ reviewedAt: args.attemptedAt,
2432
+ resolution: reviewTransition.resolution,
2433
+ responseText: reviewTransition.responseText,
2434
+ respondedAt: reviewTransition.respondedAt,
2435
+ snoozeRequest: reviewTransition.snoozeRequest,
2436
+ confidence: reviewTransition.confidence,
2437
+ reason: reviewTransition.reason,
2438
+ classifierSource: reviewTransition.classifierSource,
2439
+ semanticReason: reviewTransition.semanticReason
2440
+ });
2441
+ return null;
2442
+ }
2443
+ if (reviewTransition.kind === "clarify") {
2444
+ await this.markReminderReviewObservedResponse({
2445
+ attempt: previousAttempt,
2446
+ decision: reviewTransition.observation.decision,
2447
+ respondedAt: reviewTransition.observation.respondedAt,
2448
+ responseText: reviewTransition.observation.responseText,
2449
+ reason: reviewTransition.observation.reason,
2450
+ classifierSource: reviewTransition.observation.classifierSource,
2451
+ semanticReason: reviewTransition.observation.semanticReason
2452
+ });
2453
+ const clarificationAttempt = await this.dispatchReminderAttempt({
2454
+ plan: args.plan,
2455
+ ownerType: args.ownerType,
2456
+ ownerId: args.ownerId,
2457
+ occurrenceId: args.occurrenceId,
2458
+ subjectType: args.subjectType,
2459
+ title: args.title,
2460
+ channel: previousAttempt.channel,
2461
+ stepIndex: args.plan.steps.length + escalationAttempts.length,
2462
+ scheduledFor,
2463
+ dueAt: args.dueAt,
2464
+ urgency: args.urgency,
2465
+ quietHours: args.quietHours,
2466
+ acknowledged: false,
2467
+ attemptedAt: args.attemptedAt,
2468
+ lifecycle: "escalation",
2469
+ escalationIndex: escalationAttempts.length,
2470
+ escalationReason: "snooze_needs_clarification",
2471
+ activityProfile: args.activityProfile,
2472
+ nearbyReminderTitles: args.nearbyReminderTitles,
2473
+ timezone: args.timezone,
2474
+ definition: args.definition,
2475
+ bodyOverride: buildReminderSnoozeClarificationBody(args.title)
2476
+ });
2477
+ if (isDeliveredReminderOutcome(clarificationAttempt.outcome)) {
2478
+ await this.markReminderReviewClarificationRequested({
2479
+ attempt: previousAttempt,
2480
+ clarificationAttempt,
2481
+ requestedAt: args.attemptedAt
2482
+ });
2483
+ }
2484
+ return clarificationAttempt;
2485
+ }
2486
+ if (reviewTransition.kind === "escalate" && reviewTransition.observation) {
2487
+ await this.markReminderReviewObservedResponse({
2488
+ attempt: previousAttempt,
2489
+ decision: reviewTransition.observation.decision,
2490
+ respondedAt: reviewTransition.observation.respondedAt,
2491
+ responseText: reviewTransition.observation.responseText,
2492
+ reason: reviewTransition.observation.reason,
2493
+ classifierSource: reviewTransition.observation.classifierSource,
2494
+ semanticReason: reviewTransition.observation.semanticReason
2495
+ });
2496
+ }
2497
+ }
2498
+ if (shouldDeferReminderUntilComputerActive({
2499
+ channel: "in_app",
2500
+ definition: args.definition,
2501
+ activityProfile: args.activityProfile,
2502
+ urgency: args.urgency
2503
+ })) {
2504
+ return null;
2505
+ }
2506
+ const candidateChannels = await this.resolveReminderEscalationChannels({
2507
+ activityProfile: args.activityProfile,
2508
+ policies: args.policies,
2509
+ urgency: args.urgency,
2510
+ attempts: ownerAttempts,
2511
+ now: args.now
2512
+ });
2513
+ const attemptedChannels = new Set(
2514
+ ownerAttempts.map((attempt2) => attempt2.channel)
2515
+ );
2516
+ const lastEscalationAttempt = escalationAttempts.at(-1) ?? null;
2517
+ let nextChannel = candidateChannels.find((channel) => !attemptedChannels.has(channel)) ?? null;
2518
+ if (!nextChannel && lastEscalationAttempt && isDeliveredReminderOutcome(lastEscalationAttempt.outcome) && candidateChannels.includes(lastEscalationAttempt.channel)) {
2519
+ nextChannel = lastEscalationAttempt.channel;
2520
+ }
2521
+ if (!nextChannel && isDeliveredReminderOutcome(previousAttempt.outcome) && candidateChannels.includes(previousAttempt.channel)) {
2522
+ nextChannel = previousAttempt.channel;
2523
+ }
2524
+ if (forceChannel && nextChannel !== forceChannel && candidateChannels.includes(forceChannel)) {
2525
+ nextChannel = forceChannel;
2526
+ }
2527
+ if (!nextChannel) {
2528
+ return null;
2529
+ }
2530
+ const attempt = await this.dispatchReminderAttempt({
2531
+ plan: args.plan,
2532
+ ownerType: args.ownerType,
2533
+ ownerId: args.ownerId,
2534
+ occurrenceId: args.occurrenceId,
2535
+ subjectType: args.subjectType,
2536
+ title: args.title,
2537
+ channel: nextChannel,
2538
+ stepIndex: args.plan.steps.length + escalationAttempts.length,
2539
+ scheduledFor,
2540
+ dueAt: args.dueAt,
2541
+ urgency: args.urgency,
2542
+ quietHours: args.quietHours,
2543
+ acknowledged: false,
2544
+ attemptedAt: args.attemptedAt,
2545
+ lifecycle: "escalation",
2546
+ escalationIndex: escalationAttempts.length,
2547
+ escalationReason: reviewDue ? "review_due_without_acknowledgement" : escalationAttempts.length > 0 ? "previous_escalation_unacknowledged" : "plan_exhausted_without_acknowledgement",
2548
+ activityProfile: args.activityProfile,
2549
+ nearbyReminderTitles: args.nearbyReminderTitles,
2550
+ timezone: args.timezone,
2551
+ definition: args.definition
2552
+ });
2553
+ if (readReminderReviewAt(previousAttempt) !== null && !isReminderReviewClosed(previousAttempt)) {
2554
+ if (isDeliveredReminderOutcome(attempt.outcome)) {
2555
+ await this.markReminderReviewEscalated({
2556
+ attempt: previousAttempt,
2557
+ escalatedAttempt: attempt,
2558
+ escalatedAt: args.attemptedAt
2559
+ });
2560
+ } else {
2561
+ await this.markReminderReviewObservedResponse({
2562
+ attempt: previousAttempt,
2563
+ decision: "no_response",
2564
+ respondedAt: null,
2565
+ responseText: null,
2566
+ reason: `review_escalation_attempt_${attempt.outcome}`
2567
+ });
2568
+ }
2569
+ }
2570
+ await this.markReminderEscalationStarted({
2571
+ ownerType: args.ownerType,
2572
+ ownerId: args.ownerId,
2573
+ attemptedAt: args.attemptedAt,
2574
+ channel: nextChannel,
2575
+ outcome: attempt.outcome
2576
+ });
2577
+ if (escalationAttempts.length === 0) {
2578
+ await this.recordReminderAudit(
2579
+ "reminder_escalation_started",
2580
+ args.ownerType,
2581
+ args.ownerId,
2582
+ "reminder escalation started",
2583
+ {
2584
+ channel: nextChannel,
2585
+ scheduledFor
2586
+ },
2587
+ {
2588
+ urgency: args.urgency,
2589
+ activityPlatform: args.activityProfile?.lastSeenPlatform ?? null,
2590
+ activityActive: args.activityProfile?.isCurrentlyActive ?? false,
2591
+ outcome: attempt.outcome
2592
+ }
2593
+ );
2594
+ }
2595
+ return attempt;
2596
+ }
2597
+ async awardWebsiteAccessGrant(definition, occurrenceId, now = /* @__PURE__ */ new Date()) {
2598
+ const policy = definition.websiteAccess;
2599
+ if (!policy) {
2600
+ return;
2601
+ }
2602
+ const unlockedAt = now.toISOString();
2603
+ await this.repository.revokeWebsiteAccessGrants(definition.agentId, {
2604
+ groupKey: policy.groupKey,
2605
+ revokedAt: unlockedAt
2606
+ });
2607
+ const expiresAt = policy.unlockMode === "fixed_duration" && typeof policy.unlockDurationMinutes === "number" ? addMinutes(now, policy.unlockDurationMinutes).toISOString() : null;
2608
+ const grant = createLifeOpsWebsiteAccessGrant({
2609
+ agentId: definition.agentId,
2610
+ groupKey: policy.groupKey,
2611
+ definitionId: definition.id,
2612
+ occurrenceId,
2613
+ websites: [...policy.websites],
2614
+ unlockMode: policy.unlockMode,
2615
+ unlockDurationMinutes: policy.unlockMode === "fixed_duration" ? policy.unlockDurationMinutes ?? null : null,
2616
+ callbackKey: policy.callbackKey ?? null,
2617
+ unlockedAt,
2618
+ expiresAt,
2619
+ revokedAt: null,
2620
+ metadata: {
2621
+ definitionTitle: definition.title,
2622
+ reason: policy.reason
2623
+ }
2624
+ });
2625
+ await this.repository.upsertWebsiteAccessGrant(grant);
2626
+ }
2627
+ async syncWebsiteAccessState(now = /* @__PURE__ */ new Date()) {
2628
+ const definitions = (await this.repository.listDefinitions(this.agentId())).filter(
2629
+ (definition) => definition.status === "active" && definition.websiteAccess
2630
+ );
2631
+ const groups = /* @__PURE__ */ new Map();
2632
+ for (const definition of definitions) {
2633
+ const policy = definition.websiteAccess;
2634
+ if (!policy) {
2635
+ continue;
2636
+ }
2637
+ const websites = groups.get(policy.groupKey) ?? /* @__PURE__ */ new Set();
2638
+ for (const website of policy.websites) {
2639
+ websites.add(website.toLowerCase());
2640
+ }
2641
+ groups.set(policy.groupKey, websites);
2642
+ }
2643
+ const activeGrants = (await this.repository.listWebsiteAccessGrants(this.agentId())).filter((grant) => isWebsiteAccessGrantActive(grant, now));
2644
+ const unlockedGroups = new Set(
2645
+ activeGrants.map((grant) => grant.groupKey)
2646
+ );
2647
+ const blockedGroups = [...groups.keys()].filter(
2648
+ (groupKey) => !unlockedGroups.has(groupKey)
2649
+ );
2650
+ const blockedWebsites = normalizeWebsiteListForComparison(
2651
+ blockedGroups.flatMap((groupKey) => [...groups.get(groupKey) ?? []])
2652
+ );
2653
+ let status;
2654
+ try {
2655
+ status = await getSelfControlStatus();
2656
+ } catch (error) {
2657
+ this.logLifeOpsError("website_access_status", error, {
2658
+ blockedGroups
2659
+ });
2660
+ return;
2661
+ }
2662
+ const activeLifeOpsBlock = status.active && status.managedBy === "lifeops";
2663
+ if (status.active && !activeLifeOpsBlock) {
2664
+ if (blockedWebsites.length > 0) {
2665
+ this.logLifeOpsWarn(
2666
+ "website_access_sync",
2667
+ "[lifeops] Website blocker is already active outside LifeOps; skipping blocker sync.",
2668
+ {
2669
+ managedBy: status.managedBy,
2670
+ currentWebsites: status.websites,
2671
+ blockedWebsites
2672
+ }
2673
+ );
2674
+ }
2675
+ return;
2676
+ }
2677
+ if (blockedWebsites.length === 0) {
2678
+ if (!activeLifeOpsBlock) {
2679
+ return;
2680
+ }
2681
+ const stopResult = await stopSelfControlBlock();
2682
+ if (stopResult.success === false) {
2683
+ this.logLifeOpsWarn(
2684
+ "website_access_sync",
2685
+ "[lifeops] Failed to clear the LifeOps-managed website blocker state.",
2686
+ {
2687
+ error: stopResult.error
2688
+ }
2689
+ );
2690
+ }
2691
+ return;
2692
+ }
2693
+ if (activeLifeOpsBlock && haveSameWebsiteSet(status.websites, blockedWebsites)) {
2694
+ return;
2695
+ }
2696
+ if (activeLifeOpsBlock) {
2697
+ const stopResult = await stopSelfControlBlock();
2698
+ if (stopResult.success === false) {
2699
+ this.logLifeOpsWarn(
2700
+ "website_access_sync",
2701
+ "[lifeops] Failed to update the existing LifeOps website block.",
2702
+ {
2703
+ error: stopResult.error,
2704
+ blockedWebsites
2705
+ }
2706
+ );
2707
+ return;
2708
+ }
2709
+ }
2710
+ const startResult = await startSelfControlBlock({
2711
+ websites: blockedWebsites,
2712
+ durationMinutes: null,
2713
+ metadata: {
2714
+ managedBy: "lifeops",
2715
+ blockedGroups,
2716
+ reason: "lifeops_earned_access"
2717
+ }
2718
+ });
2719
+ if (startResult.success === false) {
2720
+ this.logLifeOpsWarn(
2721
+ "website_access_sync",
2722
+ "[lifeops] Failed to apply the LifeOps website block.",
2723
+ {
2724
+ error: startResult.error,
2725
+ blockedWebsites,
2726
+ blockedGroups
2727
+ }
2728
+ );
2729
+ }
2730
+ }
2731
+ async dispatchReminderAttempt(args) {
2732
+ const attemptedAt = args.attemptedAt;
2733
+ const attemptedAtDate = new Date(attemptedAt);
2734
+ const lifecycle = args.lifecycle ?? "plan";
2735
+ const reminderBody = args.bodyOverride ?? await this.renderReminderBody({
2736
+ title: args.title,
2737
+ scheduledFor: args.scheduledFor,
2738
+ dueAt: args.dueAt,
2739
+ channel: args.channel,
2740
+ lifecycle,
2741
+ urgency: args.urgency,
2742
+ subjectType: args.subjectType,
2743
+ nearbyReminderTitles: args.nearbyReminderTitles
2744
+ });
2745
+ let outcome = "delivered";
2746
+ let connectorRef = null;
2747
+ const deliveryMetadata = {
2748
+ title: args.title,
2749
+ urgency: args.urgency,
2750
+ [REMINDER_LIFECYCLE_METADATA_KEY]: lifecycle
2751
+ };
2752
+ if (lifecycle === "escalation") {
2753
+ deliveryMetadata[REMINDER_ESCALATION_INDEX_METADATA_KEY] = args.escalationIndex ?? 0;
2754
+ deliveryMetadata[REMINDER_ESCALATION_REASON_METADATA_KEY] = args.escalationReason ?? "escalation";
2755
+ deliveryMetadata[REMINDER_ESCALATION_ACTIVITY_PLATFORM_METADATA_KEY] = args.activityProfile?.lastSeenPlatform ?? args.activityProfile?.primaryPlatform ?? null;
2756
+ deliveryMetadata[REMINDER_ESCALATION_ACTIVITY_ACTIVE_METADATA_KEY] = args.activityProfile?.isCurrentlyActive ?? false;
2757
+ }
2758
+ await this.recordReminderAudit(
2759
+ "reminder_due",
2760
+ args.ownerType,
2761
+ args.ownerId,
2762
+ "reminder step became due",
2763
+ {
2764
+ planId: args.plan.id,
2765
+ channel: args.channel,
2766
+ stepIndex: args.stepIndex,
2767
+ scheduledFor: args.scheduledFor
2768
+ },
2769
+ {
2770
+ ownerId: args.ownerId
2771
+ }
2772
+ );
2773
+ if (args.acknowledged) {
2774
+ outcome = "blocked_acknowledged";
2775
+ deliveryMetadata.reason = "owner_acknowledged";
2776
+ } else if (!isReminderChannelAllowedForUrgency(args.channel, args.urgency)) {
2777
+ outcome = "blocked_urgency";
2778
+ deliveryMetadata.reason = "urgency_gate";
2779
+ } else if (args.activityProfile?.circadianState === "sleeping" || args.activityProfile?.circadianState === "napping") {
2780
+ outcome = "blocked_quiet_hours";
2781
+ deliveryMetadata.reason = "probable_sleep";
2782
+ deliveryMetadata.stateConfidence = args.activityProfile.stateConfidence;
2783
+ deliveryMetadata.circadianState = args.activityProfile.circadianState;
2784
+ } else if (args.channel !== "in_app" && isWithinQuietHoursPolicy({
2785
+ now: attemptedAtDate,
2786
+ quietHours: args.quietHours,
2787
+ channel: args.channel
2788
+ })) {
2789
+ outcome = "blocked_quiet_hours";
2790
+ deliveryMetadata.reason = "quiet_hours";
2791
+ } else if (args.channel === "in_app") {
2792
+ connectorRef = "system:in_app";
2793
+ deliveryMetadata.message = reminderBody;
2794
+ } else {
2795
+ const policy = await this.resolvePrimaryChannelPolicy(args.channel);
2796
+ const runtimeTarget = args.channel === "sms" || args.channel === "voice" ? null : await this.resolveRuntimeReminderTarget(args.channel, policy);
2797
+ const requiresEscalationPermission = args.stepIndex > 0;
2798
+ if (policy && !policy.allowReminders) {
2799
+ outcome = "blocked_policy";
2800
+ deliveryMetadata.reason = "channel_policy";
2801
+ } else if ((lifecycle === "escalation" || requiresEscalationPermission) && policy && !policy.allowEscalation) {
2802
+ outcome = "blocked_policy";
2803
+ deliveryMetadata.reason = "channel_escalation_policy";
2804
+ } else if ((args.channel === "sms" || args.channel === "voice") && !policy) {
2805
+ outcome = "blocked_policy";
2806
+ deliveryMetadata.reason = "channel_policy";
2807
+ } else if (args.channel === "sms" || args.channel === "voice") {
2808
+ const credentials = readTwilioCredentialsFromEnv();
2809
+ const twilioPolicy = policy;
2810
+ if (!credentials) {
2811
+ outcome = "blocked_connector";
2812
+ deliveryMetadata.reason = "twilio_missing";
2813
+ } else if (!twilioPolicy) {
2814
+ outcome = "blocked_policy";
2815
+ deliveryMetadata.reason = "channel_policy";
2816
+ } else if ((lifecycle === "escalation" || requiresEscalationPermission) && !twilioPolicy.allowEscalation) {
2817
+ outcome = "blocked_policy";
2818
+ deliveryMetadata.reason = "channel_escalation_policy";
2819
+ } else {
2820
+ connectorRef = `twilio:${twilioPolicy.channelRef}`;
2821
+ if (args.channel === "sms") {
2822
+ const result = await sendTwilioSms({
2823
+ credentials,
2824
+ to: twilioPolicy.channelRef,
2825
+ body: reminderBody
2826
+ });
2827
+ if (!result.ok) {
2828
+ outcome = "blocked_connector";
2829
+ deliveryMetadata.error = result.error ?? "sms delivery failed";
2830
+ deliveryMetadata.status = result.status;
2831
+ } else {
2832
+ deliveryMetadata.sid = result.sid ?? null;
2833
+ deliveryMetadata.status = result.status;
2834
+ }
2835
+ } else {
2836
+ const result = await sendTwilioVoiceCall({
2837
+ credentials,
2838
+ to: twilioPolicy.channelRef,
2839
+ message: reminderBody
2840
+ });
2841
+ if (!result.ok) {
2842
+ outcome = "blocked_connector";
2843
+ deliveryMetadata.error = result.error ?? "voice delivery failed";
2844
+ deliveryMetadata.status = result.status;
2845
+ } else {
2846
+ deliveryMetadata.sid = result.sid ?? null;
2847
+ deliveryMetadata.status = result.status;
2848
+ }
2849
+ }
2850
+ }
2851
+ } else if (runtimeTarget) {
2852
+ connectorRef = runtimeTarget.connectorRef;
2853
+ deliveryMetadata.routeSource = runtimeTarget.source;
2854
+ deliveryMetadata.routeResolution = runtimeTarget.resolution;
2855
+ deliveryMetadata.routeEndpoint = runtimeTarget.target.channelId ?? runtimeTarget.target.roomId ?? runtimeTarget.target.entityId ?? null;
2856
+ deliveryMetadata.deliveryRoomId = runtimeTarget.target.roomId ?? null;
2857
+ deliveryMetadata.deliveryChannelId = runtimeTarget.target.channelId ?? null;
2858
+ deliveryMetadata.deliveryEntityId = runtimeTarget.target.entityId ?? null;
2859
+ const sendPayload = {
2860
+ text: reminderBody,
2861
+ source: runtimeTarget.source,
2862
+ metadata: {
2863
+ channelType: args.channel,
2864
+ lifeopsReminder: true,
2865
+ ownerType: args.ownerType,
2866
+ ownerId: args.ownerId,
2867
+ urgency: args.urgency,
2868
+ scheduledFor: args.scheduledFor,
2869
+ routeSource: runtimeTarget.source,
2870
+ routeEndpoint: runtimeTarget.target.channelId ?? runtimeTarget.target.roomId ?? runtimeTarget.target.entityId ?? null,
2871
+ routeResolution: runtimeTarget.resolution
2872
+ }
2873
+ };
2874
+ try {
2875
+ await this.runtime.sendMessageToTarget(
2876
+ runtimeTarget.target,
2877
+ sendPayload
2878
+ );
2879
+ } catch (firstError) {
2880
+ this.logLifeOpsWarn(
2881
+ "reminder_dispatch",
2882
+ `[lifeops] Reminder delivery failed for ${args.channel}, retrying in 2s`,
2883
+ { error: lifeOpsErrorMessage(firstError) }
2884
+ );
2885
+ await new Promise(
2886
+ (r) => setTimeout(r, REMINDER_DELIVERY_RETRY_DELAY_MS)
2887
+ );
2888
+ try {
2889
+ await this.runtime.sendMessageToTarget(
2890
+ runtimeTarget.target,
2891
+ sendPayload
2892
+ );
2893
+ } catch (retryError) {
2894
+ outcome = "blocked_connector";
2895
+ deliveryMetadata.error = lifeOpsErrorMessage(retryError);
2896
+ deliveryMetadata.reason = "runtime_send_failed";
2897
+ }
2898
+ }
2899
+ } else {
2900
+ outcome = "blocked_connector";
2901
+ deliveryMetadata.reason = policy ? "target_missing" : "unconfigured_channel";
2902
+ }
2903
+ }
2904
+ if (outcome === "delivered" && (args.urgency === "high" || args.urgency === "critical")) {
2905
+ const reviewDelayMinutes = resolveReminderReviewDelayMinutes(
2906
+ args.urgency,
2907
+ lifecycle
2908
+ );
2909
+ if (reviewDelayMinutes !== null) {
2910
+ deliveryMetadata[REMINDER_REVIEW_AFTER_MINUTES_METADATA_KEY] = reviewDelayMinutes;
2911
+ deliveryMetadata[REMINDER_REVIEW_AT_METADATA_KEY] = addMinutes(
2912
+ attemptedAtDate,
2913
+ reviewDelayMinutes
2914
+ ).toISOString();
2915
+ deliveryMetadata[REMINDER_REVIEW_REASON_METADATA_KEY] = lifecycle === "escalation" ? "escalation_unacknowledged_review" : "delivery_acknowledgement_review";
2916
+ }
2917
+ }
2918
+ const attempt = createLifeOpsReminderAttempt({
2919
+ agentId: this.agentId(),
2920
+ planId: args.plan.id,
2921
+ ownerType: args.ownerType,
2922
+ ownerId: args.ownerId,
2923
+ occurrenceId: args.occurrenceId,
2924
+ channel: args.channel,
2925
+ stepIndex: args.stepIndex,
2926
+ scheduledFor: args.scheduledFor,
2927
+ attemptedAt,
2928
+ outcome,
2929
+ connectorRef,
2930
+ deliveryMetadata
2931
+ });
2932
+ await this.repository.createReminderAttempt(attempt);
2933
+ await this.recordReminderAudit(
2934
+ outcome === "delivered" ? "reminder_delivered" : "reminder_blocked",
2935
+ args.ownerType,
2936
+ args.ownerId,
2937
+ outcome === "delivered" ? "reminder delivered" : "reminder blocked",
2938
+ {
2939
+ planId: args.plan.id,
2940
+ channel: args.channel,
2941
+ stepIndex: args.stepIndex,
2942
+ scheduledFor: args.scheduledFor
2943
+ },
2944
+ {
2945
+ connectorRef,
2946
+ outcome,
2947
+ ...deliveryMetadata
2948
+ }
2949
+ );
2950
+ if (outcome === "blocked_connector") {
2951
+ this.logLifeOpsWarn(
2952
+ "reminder_dispatch",
2953
+ `[lifeops] Reminder delivery failed for ${args.channel}`,
2954
+ {
2955
+ ownerType: args.ownerType,
2956
+ ownerId: args.ownerId,
2957
+ occurrenceId: args.occurrenceId,
2958
+ channel: args.channel,
2959
+ connectorRef,
2960
+ scheduledFor: args.scheduledFor,
2961
+ stepIndex: args.stepIndex,
2962
+ reason: typeof deliveryMetadata.reason === "string" ? deliveryMetadata.reason : null,
2963
+ status: typeof deliveryMetadata.status === "number" ? deliveryMetadata.status : null,
2964
+ error: typeof deliveryMetadata.error === "string" ? deliveryMetadata.error : null
2965
+ }
2966
+ );
2967
+ }
2968
+ if (outcome === "delivered" && args.channel === "in_app") {
2969
+ this.emitInAppReminderNudge({
2970
+ text: reminderBody,
2971
+ ownerType: args.ownerType,
2972
+ ownerId: args.ownerId,
2973
+ subjectType: args.subjectType,
2974
+ scheduledFor: args.scheduledFor,
2975
+ dueAt: args.dueAt
2976
+ });
2977
+ }
2978
+ return attempt;
2979
+ }
2980
+ resolveGlobalReminderPreferencePolicy(policies) {
2981
+ const candidates = policies.filter(
2982
+ (policy) => policy.channelType === "in_app" && (policy.channelRef === GLOBAL_REMINDER_PREFERENCE_CHANNEL_REF || policy.metadata[REMINDER_PREFERENCE_SCOPE_METADATA_KEY] === "global")
2983
+ );
2984
+ return candidates.find((policy) => policy.metadata.isPrimary === true) ?? candidates[0] ?? null;
2985
+ }
2986
+ buildReminderPreferenceResponse(definition, policies) {
2987
+ const globalPolicy = this.resolveGlobalReminderPreferencePolicy(policies);
2988
+ const globalSetting = readReminderPreferenceSettingFromMetadata(
2989
+ globalPolicy?.metadata,
2990
+ "global_policy"
2991
+ ) ?? {
2992
+ intensity: DEFAULT_REMINDER_INTENSITY,
2993
+ source: "default",
2994
+ updatedAt: null,
2995
+ note: null
2996
+ };
2997
+ const definitionSetting = definition ? readReminderPreferenceSettingFromMetadata(
2998
+ definition.metadata,
2999
+ "definition_metadata"
3000
+ ) : null;
3001
+ return {
3002
+ definitionId: definition?.id ?? null,
3003
+ definitionTitle: definition?.title ?? null,
3004
+ global: globalSetting,
3005
+ definition: definitionSetting,
3006
+ effective: definitionSetting ?? globalSetting
3007
+ };
3008
+ }
3009
+ resolveEffectiveReminderPlan(plan, preference) {
3010
+ if (!plan) {
3011
+ return null;
3012
+ }
3013
+ return applyReminderIntensityToPlan(plan, preference.effective.intensity);
3014
+ }
3015
+ async getReminderPreference(definitionId) {
3016
+ const definition = definitionId ? await this.repository.getDefinition(
3017
+ this.agentId(),
3018
+ requireNonEmptyString(definitionId, "definitionId")
3019
+ ) : null;
3020
+ if (definitionId && !definition) {
3021
+ fail(404, "life-ops definition not found");
3022
+ }
3023
+ const policies = await this.repository.listChannelPolicies(
3024
+ this.agentId()
3025
+ );
3026
+ return this.buildReminderPreferenceResponse(definition, policies);
3027
+ }
3028
+ async setReminderPreference(request) {
3029
+ const intensity = normalizeReminderIntensityInput(
3030
+ request.intensity,
3031
+ "intensity"
3032
+ );
3033
+ const note = normalizeOptionalString(request.note) ?? null;
3034
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3035
+ const definitionId = normalizeOptionalString(request.definitionId) ?? null;
3036
+ if (definitionId) {
3037
+ const definition = await this.repository.getDefinition(
3038
+ this.agentId(),
3039
+ definitionId
3040
+ );
3041
+ if (!definition) {
3042
+ fail(404, "life-ops definition not found");
3043
+ }
3044
+ const nextDefinition = {
3045
+ ...definition,
3046
+ metadata: withReminderPreferenceMetadata(
3047
+ definition.metadata,
3048
+ intensity,
3049
+ updatedAt,
3050
+ note,
3051
+ "definition"
3052
+ ),
3053
+ updatedAt
3054
+ };
3055
+ await this.repository.updateDefinition(nextDefinition);
3056
+ await this.recordAudit(
3057
+ "definition_updated",
3058
+ "definition",
3059
+ definition.id,
3060
+ "reminder preference updated",
3061
+ {
3062
+ request
3063
+ },
3064
+ {
3065
+ reminderIntensity: intensity,
3066
+ note
3067
+ }
3068
+ );
3069
+ const policies = await this.repository.listChannelPolicies(
3070
+ this.agentId()
3071
+ );
3072
+ return this.buildReminderPreferenceResponse(nextDefinition, policies);
3073
+ }
3074
+ await this.upsertChannelPolicy({
3075
+ channelType: "in_app",
3076
+ channelRef: GLOBAL_REMINDER_PREFERENCE_CHANNEL_REF,
3077
+ privacyClass: "private",
3078
+ allowReminders: true,
3079
+ allowEscalation: false,
3080
+ allowPosts: false,
3081
+ requireConfirmationForActions: false,
3082
+ metadata: {
3083
+ isPrimary: true,
3084
+ [REMINDER_PREFERENCE_SCOPE_METADATA_KEY]: "global",
3085
+ [REMINDER_INTENSITY_METADATA_KEY]: intensity,
3086
+ [REMINDER_INTENSITY_UPDATED_AT_METADATA_KEY]: updatedAt,
3087
+ [REMINDER_INTENSITY_NOTE_METADATA_KEY]: note
3088
+ }
3089
+ });
3090
+ return this.getReminderPreference();
3091
+ }
3092
+ async captureActivitySignal(request) {
3093
+ const health = normalizeHealthSignal(request.health, "health");
3094
+ const signal = createLifeOpsActivitySignal({
3095
+ agentId: this.agentId(),
3096
+ source: normalizeActivitySignalSource(request.source, "source"),
3097
+ platform: normalizeOptionalString(request.platform) ?? "client_chat",
3098
+ state: normalizeActivitySignalState(request.state, "state"),
3099
+ observedAt: normalizeOptionalIsoString(request.observedAt, "observedAt") ?? (/* @__PURE__ */ new Date()).toISOString(),
3100
+ idleState: normalizeOptionalIdleState(request.idleState, "idleState"),
3101
+ idleTimeSeconds: normalizeOptionalNonNegativeInteger(
3102
+ request.idleTimeSeconds,
3103
+ "idleTimeSeconds"
3104
+ ),
3105
+ onBattery: normalizeOptionalBoolean(request.onBattery, "onBattery") ?? null,
3106
+ health,
3107
+ metadata: request.metadata !== void 0 ? requireRecord(request.metadata, "metadata") : {}
3108
+ });
3109
+ await this.repository.createActivitySignal(signal);
3110
+ return signal;
3111
+ }
3112
+ async captureManualOverride(request) {
3113
+ const kind = normalizeEnumValue(
3114
+ request.kind,
3115
+ "kind",
3116
+ LIFEOPS_MANUAL_OVERRIDE_KINDS
3117
+ );
3118
+ const occurredAt = normalizeOptionalIsoString(request.occurredAt, "occurredAt") ?? (/* @__PURE__ */ new Date()).toISOString();
3119
+ const note = normalizeOptionalString(request.note);
3120
+ if (note !== void 0 && note.length > 500) {
3121
+ fail(400, "note must be <= 500 characters");
3122
+ }
3123
+ const desiredState = kind === "going_to_bed" ? "sleeping" : "awake";
3124
+ const priorState = await this.repository.readCircadianState(
3125
+ this.agentId()
3126
+ );
3127
+ const signal = createLifeOpsActivitySignal({
3128
+ agentId: this.agentId(),
3129
+ source: "app_lifecycle",
3130
+ platform: "manual_override",
3131
+ state: kind === "going_to_bed" ? "sleeping" : "active",
3132
+ observedAt: occurredAt,
3133
+ idleState: kind === "going_to_bed" ? "idle" : "active",
3134
+ idleTimeSeconds: 0,
3135
+ onBattery: null,
3136
+ health: null,
3137
+ metadata: {
3138
+ userAttested: true,
3139
+ manualOverrideKind: kind,
3140
+ ...note ? { note } : {}
3141
+ }
3142
+ });
3143
+ await this.repository.createActivitySignal(signal);
3144
+ await this.repository.createAuditEventIfNew({
3145
+ id: `lifeops.manual_override:${this.agentId()}:${occurredAt}:${kind}`,
3146
+ agentId: this.agentId(),
3147
+ eventType: "manual_override_accepted",
3148
+ ownerType: "circadian_state",
3149
+ ownerId: `lifeops-manual-override:${this.agentId()}`,
3150
+ reason: `user_attested_${kind}`,
3151
+ inputs: {
3152
+ kind,
3153
+ occurredAt,
3154
+ note: note ?? null,
3155
+ priorCircadianState: priorState?.circadianState ?? null
3156
+ },
3157
+ decision: {
3158
+ desiredCircadianState: desiredState,
3159
+ bypassedStabilityWindow: true
3160
+ },
3161
+ actor: "user",
3162
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3163
+ });
3164
+ const refreshed = await this.refreshEffectiveScheduleState({
3165
+ now: new Date(occurredAt)
3166
+ });
3167
+ return {
3168
+ accepted: true,
3169
+ kind,
3170
+ occurredAt,
3171
+ circadianState: refreshed?.circadianState ?? desiredState,
3172
+ stateConfidence: refreshed?.stateConfidence ?? 0.99
3173
+ };
3174
+ }
3175
+ async listActivitySignals(args = {}) {
3176
+ return this.repository.listActivitySignals(this.agentId(), args);
3177
+ }
3178
+ async upsertChannelPolicy(request) {
3179
+ const channelType = normalizeEnumValue(
3180
+ request.channelType,
3181
+ "channelType",
3182
+ LIFEOPS_CHANNEL_TYPES
3183
+ );
3184
+ const channelRef = channelType === "sms" || channelType === "voice" ? normalizePhoneNumber(request.channelRef, "channelRef") : requireNonEmptyString(request.channelRef, "channelRef");
3185
+ const existing = await this.repository.getChannelPolicy(
3186
+ this.agentId(),
3187
+ channelType,
3188
+ channelRef
3189
+ );
3190
+ const policy = existing ? {
3191
+ ...existing,
3192
+ privacyClass: normalizePrivacyClass(
3193
+ request.privacyClass,
3194
+ "privacyClass",
3195
+ existing.privacyClass
3196
+ ),
3197
+ allowReminders: normalizeOptionalBoolean(
3198
+ request.allowReminders,
3199
+ "allowReminders"
3200
+ ) ?? existing.allowReminders,
3201
+ allowEscalation: normalizeOptionalBoolean(
3202
+ request.allowEscalation,
3203
+ "allowEscalation"
3204
+ ) ?? existing.allowEscalation,
3205
+ allowPosts: normalizeOptionalBoolean(request.allowPosts, "allowPosts") ?? existing.allowPosts,
3206
+ requireConfirmationForActions: normalizeOptionalBoolean(
3207
+ request.requireConfirmationForActions,
3208
+ "requireConfirmationForActions"
3209
+ ) ?? existing.requireConfirmationForActions,
3210
+ metadata: request.metadata !== void 0 ? {
3211
+ ...existing.metadata,
3212
+ ...requireRecord(request.metadata, "metadata")
3213
+ } : existing.metadata,
3214
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3215
+ } : createLifeOpsChannelPolicy({
3216
+ agentId: this.agentId(),
3217
+ channelType,
3218
+ channelRef,
3219
+ privacyClass: normalizePrivacyClass(request.privacyClass),
3220
+ allowReminders: normalizeOptionalBoolean(
3221
+ request.allowReminders,
3222
+ "allowReminders"
3223
+ ) ?? true,
3224
+ allowEscalation: normalizeOptionalBoolean(
3225
+ request.allowEscalation,
3226
+ "allowEscalation"
3227
+ ) ?? false,
3228
+ allowPosts: normalizeOptionalBoolean(request.allowPosts, "allowPosts") ?? false,
3229
+ requireConfirmationForActions: normalizeOptionalBoolean(
3230
+ request.requireConfirmationForActions,
3231
+ "requireConfirmationForActions"
3232
+ ) ?? true,
3233
+ metadata: normalizeOptionalRecord(request.metadata, "metadata") ?? {}
3234
+ });
3235
+ await this.repository.upsertChannelPolicy(policy);
3236
+ await this.recordChannelPolicyAudit(
3237
+ policy.id,
3238
+ "channel policy updated",
3239
+ { request },
3240
+ {
3241
+ channelType: policy.channelType,
3242
+ channelRef: policy.channelRef
3243
+ }
3244
+ );
3245
+ return policy;
3246
+ }
3247
+ async capturePhoneConsent(request) {
3248
+ if (normalizeOptionalBoolean(request.consentGiven, "consentGiven") !== true) {
3249
+ fail(
3250
+ 400,
3251
+ "Explicit consent is required before capturing a phone number."
3252
+ );
3253
+ }
3254
+ const phoneNumber = normalizePhoneNumber(
3255
+ request.phoneNumber,
3256
+ "phoneNumber"
3257
+ );
3258
+ const privacyClass = normalizePrivacyClass(request.privacyClass);
3259
+ const baseMetadata = {
3260
+ ...normalizeOptionalRecord(request.metadata, "metadata"),
3261
+ phoneNumber,
3262
+ consentCapturedAt: (/* @__PURE__ */ new Date()).toISOString(),
3263
+ consentGiven: true,
3264
+ isPrimary: true
3265
+ };
3266
+ const smsPolicy = await this.upsertChannelPolicy({
3267
+ channelType: "sms",
3268
+ channelRef: phoneNumber,
3269
+ privacyClass,
3270
+ allowReminders: normalizeOptionalBoolean(request.allowSms, "allowSms") ?? false,
3271
+ allowEscalation: normalizeOptionalBoolean(request.allowSms, "allowSms") ?? false,
3272
+ allowPosts: false,
3273
+ requireConfirmationForActions: true,
3274
+ metadata: {
3275
+ ...baseMetadata,
3276
+ consentKind: "phone",
3277
+ smsAllowed: normalizeOptionalBoolean(request.allowSms, "allowSms") ?? false,
3278
+ voiceAllowed: normalizeOptionalBoolean(request.allowVoice, "allowVoice") ?? false
3279
+ }
3280
+ });
3281
+ const voicePolicy = await this.upsertChannelPolicy({
3282
+ channelType: "voice",
3283
+ channelRef: phoneNumber,
3284
+ privacyClass,
3285
+ allowReminders: normalizeOptionalBoolean(request.allowVoice, "allowVoice") ?? false,
3286
+ allowEscalation: normalizeOptionalBoolean(request.allowVoice, "allowVoice") ?? false,
3287
+ allowPosts: false,
3288
+ requireConfirmationForActions: true,
3289
+ metadata: {
3290
+ ...baseMetadata,
3291
+ consentKind: "phone",
3292
+ smsAllowed: normalizeOptionalBoolean(request.allowSms, "allowSms") ?? false,
3293
+ voiceAllowed: normalizeOptionalBoolean(request.allowVoice, "allowVoice") ?? false
3294
+ }
3295
+ });
3296
+ const allowSms = normalizeOptionalBoolean(request.allowSms, "allowSms") ?? false;
3297
+ const allowVoice = normalizeOptionalBoolean(request.allowVoice, "allowVoice") ?? false;
3298
+ if (allowSms) {
3299
+ registerEscalationChannel("sms");
3300
+ }
3301
+ if (allowVoice) {
3302
+ registerEscalationChannel("voice");
3303
+ }
3304
+ return {
3305
+ phoneNumber,
3306
+ policies: [smsPolicy, voicePolicy]
3307
+ };
3308
+ }
3309
+ async processDueReminderDeliveries(args) {
3310
+ const {
3311
+ now,
3312
+ limit,
3313
+ ownerTimezone,
3314
+ policies,
3315
+ globalReminderPreference,
3316
+ existingAttempts,
3317
+ activityProfile
3318
+ } = args;
3319
+ const dueAttempts = [];
3320
+ if (limit <= 0) {
3321
+ return dueAttempts;
3322
+ }
3323
+ const definitions = await this.repository.listActiveDefinitions(
3324
+ this.agentId()
3325
+ );
3326
+ for (const definition of definitions) {
3327
+ await this.refreshDefinitionOccurrences(definition, now);
3328
+ }
3329
+ const definitionsById = new Map(
3330
+ definitions.map((definition) => [definition.id, definition])
3331
+ );
3332
+ const horizon = addMinutes(now, OVERVIEW_HORIZON_MINUTES).toISOString();
3333
+ const occurrenceViews = await this.repository.listOccurrenceViewsForOverview(
3334
+ this.agentId(),
3335
+ horizon
3336
+ );
3337
+ const occurrencePlans = await this.repository.listReminderPlansForOwners(
3338
+ this.agentId(),
3339
+ "definition",
3340
+ occurrenceViews.map((occurrence) => occurrence.definitionId)
3341
+ );
3342
+ const definitionPreferencesById = /* @__PURE__ */ new Map();
3343
+ const plansByDefinitionId = /* @__PURE__ */ new Map();
3344
+ for (const plan of occurrencePlans) {
3345
+ const definition = definitionsById.get(plan.ownerId) ?? null;
3346
+ const preference = this.buildReminderPreferenceResponse(
3347
+ definition,
3348
+ policies
3349
+ );
3350
+ definitionPreferencesById.set(plan.ownerId, preference);
3351
+ const effectivePlan = this.resolveEffectiveReminderPlan(
3352
+ plan,
3353
+ preference
3354
+ );
3355
+ if (effectivePlan) {
3356
+ plansByDefinitionId.set(plan.ownerId, effectivePlan);
3357
+ }
3358
+ }
3359
+ const eventWindowEnd = addMinutes(
3360
+ now,
3361
+ OVERVIEW_HORIZON_MINUTES
3362
+ ).toISOString();
3363
+ const calendarEvents = await this.repository.listCalendarEvents(
3364
+ this.agentId(),
3365
+ "google",
3366
+ now.toISOString(),
3367
+ eventWindowEnd
3368
+ );
3369
+ const eventPlans = await this.repository.listReminderPlansForOwners(
3370
+ this.agentId(),
3371
+ "calendar_event",
3372
+ calendarEvents.map((event) => event.id)
3373
+ );
3374
+ const occurrenceUrgencies = /* @__PURE__ */ new Map();
3375
+ for (const occurrence of occurrenceViews) {
3376
+ occurrenceUrgencies.set(
3377
+ occurrence.id,
3378
+ resolveReminderDeliveryUrgency({
3379
+ metadata: occurrence.metadata,
3380
+ priority: occurrence.priority
3381
+ })
3382
+ );
3383
+ }
3384
+ const plansByEventId = /* @__PURE__ */ new Map();
3385
+ for (const plan of eventPlans) {
3386
+ const effectivePlan = this.resolveEffectiveReminderPlan(
3387
+ plan,
3388
+ globalReminderPreference
3389
+ );
3390
+ if (effectivePlan) {
3391
+ plansByEventId.set(plan.ownerId, effectivePlan);
3392
+ }
3393
+ }
3394
+ const eventUrgencies = /* @__PURE__ */ new Map();
3395
+ for (const event of calendarEvents) {
3396
+ eventUrgencies.set(
3397
+ event.id,
3398
+ resolveReminderDeliveryUrgency({
3399
+ metadata: event.metadata,
3400
+ fallback: "medium"
3401
+ })
3402
+ );
3403
+ }
3404
+ const attemptKey = (planId, stepIndex, scheduledFor) => `${planId}:${stepIndex}:${scheduledFor}`;
3405
+ const deliveredAttempts = new Set(
3406
+ existingAttempts.filter((attempt) => isDeliveredReminderOutcome(attempt.outcome)).map(
3407
+ (attempt) => attemptKey(attempt.planId, attempt.stepIndex, attempt.scheduledFor)
3408
+ )
3409
+ );
3410
+ const blockedAckAttempts = new Set(
3411
+ existingAttempts.filter((attempt) => attempt.outcome === "blocked_acknowledged").map(
3412
+ (attempt) => attemptKey(attempt.planId, attempt.stepIndex, attempt.scheduledFor)
3413
+ )
3414
+ );
3415
+ for (const reminder of buildActiveReminders(
3416
+ occurrenceViews,
3417
+ plansByDefinitionId,
3418
+ now
3419
+ )) {
3420
+ if (dueAttempts.length >= limit) break;
3421
+ const plan = reminder.definitionId ? plansByDefinitionId.get(reminder.definitionId) : null;
3422
+ if (!plan) continue;
3423
+ const occurrence = occurrenceViews.find(
3424
+ (candidate) => candidate.id === reminder.ownerId
3425
+ );
3426
+ if (!occurrence) continue;
3427
+ const preference = definitionPreferencesById.get(reminder.definitionId ?? "") ?? globalReminderPreference;
3428
+ const urgency = occurrenceUrgencies.get(reminder.ownerId) ?? "medium";
3429
+ const definition = definitionsById.get(occurrence.definitionId) ?? null;
3430
+ if (!shouldDeliverReminderForIntensity(
3431
+ preference.effective.intensity,
3432
+ urgency
3433
+ )) {
3434
+ continue;
3435
+ }
3436
+ const key = attemptKey(
3437
+ plan.id,
3438
+ reminder.stepIndex,
3439
+ reminder.scheduledFor
3440
+ );
3441
+ const acknowledged = Boolean(
3442
+ occurrence.metadata.reminderAcknowledgedAt || occurrence.state === "completed"
3443
+ );
3444
+ if (deliveredAttempts.has(key) || acknowledged && blockedAckAttempts.has(key)) {
3445
+ continue;
3446
+ }
3447
+ if (shouldDeferReminderUntilComputerActive({
3448
+ channel: reminder.channel,
3449
+ definition,
3450
+ activityProfile,
3451
+ urgency
3452
+ })) {
3453
+ continue;
3454
+ }
3455
+ const attempt = await this.dispatchReminderAttempt({
3456
+ plan,
3457
+ ownerType: "occurrence",
3458
+ ownerId: reminder.ownerId,
3459
+ occurrenceId: reminder.occurrenceId,
3460
+ subjectType: occurrence.subjectType,
3461
+ title: reminder.title,
3462
+ channel: reminder.channel,
3463
+ stepIndex: reminder.stepIndex,
3464
+ scheduledFor: reminder.scheduledFor,
3465
+ dueAt: occurrence.dueAt,
3466
+ urgency,
3467
+ quietHours: plan.quietHours,
3468
+ acknowledged,
3469
+ attemptedAt: now.toISOString(),
3470
+ activityProfile,
3471
+ nearbyReminderTitles: collectNearbyReminderTitles({
3472
+ currentOwnerId: reminder.ownerId,
3473
+ currentAnchorAt: occurrence.dueAt,
3474
+ occurrences: occurrenceViews,
3475
+ events: calendarEvents,
3476
+ limit: 3
3477
+ }),
3478
+ timezone: ownerTimezone,
3479
+ definition
3480
+ });
3481
+ dueAttempts.push(attempt);
3482
+ if (isDeliveredReminderOutcome(attempt.outcome)) {
3483
+ deliveredAttempts.add(key);
3484
+ }
3485
+ }
3486
+ for (const reminder of buildActiveCalendarEventReminders(
3487
+ calendarEvents,
3488
+ plansByEventId,
3489
+ this.ownerEntityId(),
3490
+ now
3491
+ )) {
3492
+ if (dueAttempts.length >= limit) break;
3493
+ const plan = reminder.eventId ? plansByEventId.get(reminder.eventId) : null;
3494
+ if (!plan) continue;
3495
+ const event = calendarEvents.find(
3496
+ (candidate) => candidate.id === reminder.ownerId
3497
+ );
3498
+ if (!event) continue;
3499
+ if (!shouldDeliverReminderForIntensity(
3500
+ globalReminderPreference.effective.intensity,
3501
+ eventUrgencies.get(reminder.ownerId) ?? "medium"
3502
+ )) {
3503
+ continue;
3504
+ }
3505
+ const key = attemptKey(
3506
+ plan.id,
3507
+ reminder.stepIndex,
3508
+ reminder.scheduledFor
3509
+ );
3510
+ const acknowledged = Boolean(event.metadata.reminderAcknowledgedAt);
3511
+ if (deliveredAttempts.has(key) || acknowledged && blockedAckAttempts.has(key)) {
3512
+ continue;
3513
+ }
3514
+ const attempt = await this.dispatchReminderAttempt({
3515
+ plan,
3516
+ ownerType: "calendar_event",
3517
+ ownerId: reminder.ownerId,
3518
+ occurrenceId: null,
3519
+ subjectType: reminder.subjectType,
3520
+ title: reminder.title,
3521
+ channel: reminder.channel,
3522
+ stepIndex: reminder.stepIndex,
3523
+ scheduledFor: reminder.scheduledFor,
3524
+ dueAt: reminder.dueAt,
3525
+ urgency: resolveReminderDeliveryUrgency({
3526
+ metadata: event.metadata,
3527
+ fallback: "medium"
3528
+ }),
3529
+ quietHours: plan.quietHours,
3530
+ acknowledged,
3531
+ attemptedAt: now.toISOString(),
3532
+ activityProfile,
3533
+ nearbyReminderTitles: collectNearbyReminderTitles({
3534
+ currentOwnerId: reminder.ownerId,
3535
+ currentAnchorAt: reminder.dueAt,
3536
+ occurrences: occurrenceViews,
3537
+ events: calendarEvents,
3538
+ limit: 3
3539
+ }),
3540
+ timezone: ownerTimezone,
3541
+ definition: null
3542
+ });
3543
+ dueAttempts.push(attempt);
3544
+ if (isDeliveredReminderOutcome(attempt.outcome)) {
3545
+ deliveredAttempts.add(key);
3546
+ }
3547
+ }
3548
+ const reminderAttemptsForEscalation = [
3549
+ ...existingAttempts,
3550
+ ...dueAttempts
3551
+ ];
3552
+ await this.scanReadReceipts(
3553
+ reminderAttemptsForEscalation,
3554
+ activityProfile,
3555
+ now
3556
+ );
3557
+ for (const occurrence of occurrenceViews) {
3558
+ if (dueAttempts.length >= limit) break;
3559
+ const plan = plansByDefinitionId.get(occurrence.definitionId) ?? null;
3560
+ if (!plan) continue;
3561
+ const acknowledged = Boolean(
3562
+ occurrence.metadata.reminderAcknowledgedAt || occurrence.state === "completed"
3563
+ );
3564
+ const attempt = await this.dispatchDueReminderEscalation({
3565
+ plan,
3566
+ ownerType: "occurrence",
3567
+ ownerId: occurrence.id,
3568
+ occurrenceId: occurrence.id,
3569
+ subjectType: occurrence.subjectType,
3570
+ title: occurrence.title,
3571
+ dueAt: occurrence.dueAt,
3572
+ urgency: resolveReminderDeliveryUrgency({
3573
+ metadata: occurrence.metadata,
3574
+ priority: occurrence.priority
3575
+ }),
3576
+ intensity: definitionPreferencesById.get(occurrence.definitionId)?.effective?.intensity ?? globalReminderPreference.effective.intensity,
3577
+ quietHours: plan.quietHours,
3578
+ attemptedAt: now.toISOString(),
3579
+ now,
3580
+ attempts: reminderAttemptsForEscalation,
3581
+ policies,
3582
+ activityProfile,
3583
+ occurrence,
3584
+ acknowledged,
3585
+ nearbyReminderTitles: collectNearbyReminderTitles({
3586
+ currentOwnerId: occurrence.id,
3587
+ currentAnchorAt: occurrence.dueAt,
3588
+ occurrences: occurrenceViews,
3589
+ events: calendarEvents,
3590
+ limit: 3
3591
+ }),
3592
+ timezone: ownerTimezone,
3593
+ definition: definitionsById.get(occurrence.definitionId) ?? null
3594
+ });
3595
+ if (!attempt) continue;
3596
+ dueAttempts.push(attempt);
3597
+ reminderAttemptsForEscalation.push(attempt);
3598
+ }
3599
+ for (const event of calendarEvents) {
3600
+ if (dueAttempts.length >= limit) break;
3601
+ const plan = plansByEventId.get(event.id) ?? null;
3602
+ if (!plan) continue;
3603
+ const attempt = await this.dispatchDueReminderEscalation({
3604
+ plan,
3605
+ ownerType: "calendar_event",
3606
+ ownerId: event.id,
3607
+ occurrenceId: null,
3608
+ subjectType: "owner",
3609
+ title: event.title,
3610
+ dueAt: event.startAt,
3611
+ urgency: resolveReminderDeliveryUrgency({
3612
+ metadata: event.metadata,
3613
+ fallback: "medium"
3614
+ }),
3615
+ intensity: globalReminderPreference.effective.intensity,
3616
+ quietHours: plan.quietHours,
3617
+ attemptedAt: now.toISOString(),
3618
+ now,
3619
+ attempts: reminderAttemptsForEscalation,
3620
+ policies,
3621
+ activityProfile,
3622
+ eventStartAt: event.startAt,
3623
+ acknowledged: Boolean(event.metadata.reminderAcknowledgedAt),
3624
+ nearbyReminderTitles: collectNearbyReminderTitles({
3625
+ currentOwnerId: event.id,
3626
+ currentAnchorAt: event.startAt,
3627
+ occurrences: occurrenceViews,
3628
+ events: calendarEvents,
3629
+ limit: 3
3630
+ }),
3631
+ timezone: ownerTimezone,
3632
+ definition: null
3633
+ });
3634
+ if (!attempt) continue;
3635
+ dueAttempts.push(attempt);
3636
+ reminderAttemptsForEscalation.push(attempt);
3637
+ }
3638
+ return dueAttempts;
3639
+ }
3640
+ async processReminders(request = {}) {
3641
+ return this.withReminderProcessingLock(async () => {
3642
+ const now = request.now === void 0 ? /* @__PURE__ */ new Date() : new Date(normalizeIsoString(request.now, "now"));
3643
+ const limit = request.limit === void 0 ? DEFAULT_REMINDER_PROCESS_LIMIT : normalizePositiveInteger(request.limit, "limit");
3644
+ const ownerTimezone = resolveDefaultTimeZone();
3645
+ const policies = await this.repository.listChannelPolicies(
3646
+ this.agentId()
3647
+ );
3648
+ const globalReminderPreference = this.buildReminderPreferenceResponse(
3649
+ null,
3650
+ policies
3651
+ );
3652
+ const existingAttempts = await this.repository.listReminderAttempts(
3653
+ this.agentId()
3654
+ );
3655
+ const activityProfile = await this.readReminderActivityProfileSnapshot({
3656
+ now,
3657
+ timezone: ownerTimezone
3658
+ });
3659
+ const dueAttempts = [];
3660
+ dueAttempts.push(
3661
+ ...await this.processDueReminderReviewJobs({
3662
+ now,
3663
+ limit,
3664
+ attempts: existingAttempts,
3665
+ policies,
3666
+ activityProfile,
3667
+ timezone: ownerTimezone,
3668
+ defaultIntensity: globalReminderPreference.effective.intensity
3669
+ })
3670
+ );
3671
+ if (dueAttempts.length >= limit) {
3672
+ return {
3673
+ now: now.toISOString(),
3674
+ attempts: dueAttempts
3675
+ };
3676
+ }
3677
+ dueAttempts.push(
3678
+ ...await this.processDueReminderDeliveries({
3679
+ now,
3680
+ limit: limit - dueAttempts.length,
3681
+ ownerTimezone,
3682
+ policies,
3683
+ globalReminderPreference,
3684
+ existingAttempts: [...existingAttempts, ...dueAttempts],
3685
+ activityProfile
3686
+ })
3687
+ );
3688
+ return {
3689
+ now: now.toISOString(),
3690
+ attempts: dueAttempts
3691
+ };
3692
+ });
3693
+ }
3694
+ async processScheduledWork(request = {}) {
3695
+ const now = request.now === void 0 ? /* @__PURE__ */ new Date() : new Date(normalizeIsoString(request.now, "now"));
3696
+ const reminderLimit = request.reminderLimit === void 0 ? DEFAULT_REMINDER_PROCESS_LIMIT : normalizePositiveInteger(request.reminderLimit, "reminderLimit");
3697
+ const workflowLimit = request.workflowLimit === void 0 ? DEFAULT_WORKFLOW_PROCESS_LIMIT : normalizePositiveInteger(request.workflowLimit, "workflowLimit");
3698
+ const scheduledTaskLimit = request.scheduledTaskLimit === void 0 ? DEFAULT_SCHEDULED_TASK_PROCESS_LIMIT : normalizePositiveInteger(
3699
+ request.scheduledTaskLimit,
3700
+ "scheduledTaskLimit"
3701
+ );
3702
+ await this.syncWebsiteAccessState(now);
3703
+ const previousSchedule = await this.readEffectiveScheduleState({ now });
3704
+ const currentSchedule = await this.refreshEffectiveScheduleState({ now });
3705
+ if (currentSchedule !== null) {
3706
+ const priorState = await this.repository.readCircadianState(
3707
+ this.agentId()
3708
+ );
3709
+ const stateChanged = priorState === null || priorState.circadianState !== currentSchedule.circadianState;
3710
+ await this.repository.upsertCircadianState({
3711
+ agentId: this.agentId(),
3712
+ circadianState: currentSchedule.circadianState,
3713
+ stateConfidence: currentSchedule.stateConfidence,
3714
+ uncertaintyReason: currentSchedule.uncertaintyReason,
3715
+ enteredAt: stateChanged ? now.toISOString() : priorState.enteredAt,
3716
+ sinceSleepDetectedAt: currentSchedule.circadianState === "sleeping" || currentSchedule.circadianState === "napping" ? currentSchedule.currentSleepStartedAt ?? priorState?.sinceSleepDetectedAt ?? null : null,
3717
+ sinceWakeObservedAt: currentSchedule.circadianState === "waking" || currentSchedule.circadianState === "awake" ? currentSchedule.wakeAt ?? priorState?.sinceWakeObservedAt ?? null : null,
3718
+ sinceWakeConfirmedAt: currentSchedule.circadianState === "awake" ? currentSchedule.wakeAt ?? priorState?.sinceWakeConfirmedAt ?? null : priorState?.sinceWakeConfirmedAt ?? null,
3719
+ evidenceRefs: currentSchedule.circadianRuleFirings.map(
3720
+ (firing) => firing.name
3721
+ ),
3722
+ createdAt: priorState?.createdAt ?? now.toISOString(),
3723
+ updatedAt: now.toISOString()
3724
+ });
3725
+ }
3726
+ const derivedEvents = currentSchedule === null ? [] : deriveSleepWakeEvents({
3727
+ previous: previousSchedule,
3728
+ current: currentSchedule,
3729
+ now
3730
+ });
3731
+ const lifeOpsEvents = [];
3732
+ for (const event of derivedEvents) {
3733
+ const inserted = await this.repository.createAuditEventIfNew({
3734
+ id: event.id,
3735
+ agentId: this.agentId(),
3736
+ eventType: "circadian_event_emitted",
3737
+ ownerType: "circadian_state",
3738
+ ownerId: currentSchedule?.id ?? `lifeops-schedule-merged:${this.agentId()}:local:${currentSchedule?.timezone ?? "UTC"}`,
3739
+ reason: event.kind,
3740
+ inputs: {
3741
+ previousStateId: event.payload.previousStateId,
3742
+ currentStateId: event.payload.currentStateId
3743
+ },
3744
+ decision: {
3745
+ kind: event.kind,
3746
+ occurredAt: event.occurredAt,
3747
+ confidence: event.confidence,
3748
+ circadianState: event.payload.circadianState,
3749
+ uncertaintyReason: event.payload.uncertaintyReason
3750
+ },
3751
+ actor: "agent",
3752
+ createdAt: now.toISOString()
3753
+ });
3754
+ if (inserted) {
3755
+ lifeOpsEvents.push(event);
3756
+ const eventPayload = {
3757
+ runtime: this.runtime,
3758
+ occurredAt: event.occurredAt,
3759
+ confidence: event.confidence,
3760
+ payload: event.payload
3761
+ };
3762
+ await this.runtime.emitEvent(event.kind, eventPayload);
3763
+ }
3764
+ }
3765
+ const reminderResult = await this.processReminders({
3766
+ now: now.toISOString(),
3767
+ limit: reminderLimit
3768
+ });
3769
+ const workflowRunner = this;
3770
+ const workflowRuns = await workflowRunner.runDueWorkflows({
3771
+ now: now.toISOString(),
3772
+ limit: workflowLimit
3773
+ });
3774
+ const eventWorkflowRuns = await workflowRunner.runDueEventWorkflows({
3775
+ now: now.toISOString(),
3776
+ limit: workflowLimit,
3777
+ lifeOpsEvents
3778
+ });
3779
+ const scheduledTaskResult = await processDueScheduledTasks({
3780
+ runtime: this.runtime,
3781
+ agentId: this.agentId(),
3782
+ now,
3783
+ limit: scheduledTaskLimit
3784
+ });
3785
+ await this.processSleepCycleCheckins({
3786
+ now,
3787
+ currentSchedule
3788
+ });
3789
+ await this.runTelemetryMaintenanceIfDue(now);
3790
+ return {
3791
+ now: now.toISOString(),
3792
+ reminderAttempts: reminderResult.attempts,
3793
+ workflowRuns: [...workflowRuns, ...eventWorkflowRuns],
3794
+ scheduledTaskFires: scheduledTaskResult.fires.map((fire) => ({
3795
+ ...fire
3796
+ })),
3797
+ scheduledTaskCompletionTimeouts: scheduledTaskResult.completionTimeouts.map((timeout) => ({
3798
+ ...timeout
3799
+ }))
3800
+ };
3801
+ }
3802
+ async processSleepCycleCheckins(args) {
3803
+ const currentSchedule = args.currentSchedule;
3804
+ if (!currentSchedule) {
3805
+ return;
3806
+ }
3807
+ const service = new CheckinService(this.runtime, {
3808
+ sources: this
3809
+ });
3810
+ const timezone = currentSchedule.timezone || resolveDefaultTimeZone();
3811
+ const sleepRecap = buildSleepRecapFromSchedule(currentSchedule);
3812
+ const dispatch = async (kind) => {
3813
+ const alreadySent = await service.hasCheckinForLocalDay({
3814
+ kind,
3815
+ now: args.now,
3816
+ timezone
3817
+ });
3818
+ if (alreadySent) {
3819
+ return;
3820
+ }
3821
+ const report = kind === "morning" ? await service.runMorningCheckin({ now: args.now, timezone }) : await service.runNightCheckin({
3822
+ now: args.now,
3823
+ timezone,
3824
+ sleepRecap
3825
+ });
3826
+ const routeMetadata = await this.buildOwnerContactRouteEventMetadata({
3827
+ purpose: "checkin",
3828
+ urgency: report.escalationLevel >= 2 ? "high" : "medium",
3829
+ now: args.now
3830
+ });
3831
+ this.emitAssistantEvent(report.summaryText, "lifeops-checkin", {
3832
+ checkinKind: kind,
3833
+ reportId: report.reportId,
3834
+ deliveryBasis: "sleep_cycle",
3835
+ circadianState: currentSchedule.circadianState,
3836
+ wakeAt: currentSchedule.wakeAt,
3837
+ bedtimeTargetAt: currentSchedule.relativeTime.bedtimeTargetAt,
3838
+ minutesUntilBedtimeTarget: currentSchedule.relativeTime.minutesUntilBedtimeTarget,
3839
+ ...routeMetadata
3840
+ });
3841
+ };
3842
+ if (shouldRunMorningCheckinFromSleepCycle({
3843
+ state: currentSchedule,
3844
+ now: args.now
3845
+ })) {
3846
+ await dispatch("morning");
3847
+ }
3848
+ const profileSchedule = await resolveCheckinSchedule(this.runtime);
3849
+ if (shouldRunNightCheckinFromSleepCycle({
3850
+ state: currentSchedule,
3851
+ now: args.now,
3852
+ nightFallbackBedtimeLocal: profileSchedule.nightCheckinTime
3853
+ })) {
3854
+ await dispatch("night");
3855
+ }
3856
+ }
3857
+ /**
3858
+ * Daily telemetry maintenance: rolls up yesterday's raw events into
3859
+ * `life_telemetry_rollup_daily`, then prunes raw rows past the retention
3860
+ * window. Gated to one run per UTC day per process via
3861
+ * `telemetryRollupLastRunDate` so a 60-second scheduler tick doesn't thrash.
3862
+ */
3863
+ async runTelemetryMaintenanceIfDue(now) {
3864
+ const dateKey = now.toISOString().slice(0, 10);
3865
+ if (this.telemetryRollupLastRunDate === dateKey) {
3866
+ return;
3867
+ }
3868
+ try {
3869
+ const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
3870
+ await this.repository.upsertTelemetryDailyRollup({
3871
+ agentId: this.agentId(),
3872
+ sinceIso: `${yesterday.toISOString().slice(0, 10)}T00:00:00.000Z`,
3873
+ untilIso: `${dateKey}T00:00:00.000Z`
3874
+ });
3875
+ await runTelemetryRetention({
3876
+ repository: this.repository,
3877
+ agentId: this.agentId(),
3878
+ retentionDays: DEFAULT_TELEMETRY_RETENTION_DAYS
3879
+ });
3880
+ this.telemetryRollupLastRunDate = dateKey;
3881
+ } catch (error) {
3882
+ this.logLifeOpsWarn(
3883
+ "telemetry_maintenance",
3884
+ error instanceof Error ? error.message : String(error)
3885
+ );
3886
+ }
3887
+ }
3888
+ async relockWebsiteAccessGroup(groupKey, now = /* @__PURE__ */ new Date()) {
3889
+ await this.repository.revokeWebsiteAccessGrants(this.agentId(), {
3890
+ groupKey: requireNonEmptyString(groupKey, "groupKey"),
3891
+ revokedAt: now.toISOString()
3892
+ });
3893
+ await this.syncWebsiteAccessState(now);
3894
+ return { ok: true };
3895
+ }
3896
+ async resolveWebsiteAccessCallback(callbackKey, now = /* @__PURE__ */ new Date()) {
3897
+ await this.repository.revokeWebsiteAccessGrants(this.agentId(), {
3898
+ callbackKey: requireNonEmptyString(callbackKey, "callbackKey"),
3899
+ revokedAt: now.toISOString()
3900
+ });
3901
+ await this.syncWebsiteAccessState(now);
3902
+ return { ok: true };
3903
+ }
3904
+ async inspectReminder(ownerType, ownerId) {
3905
+ let plan = null;
3906
+ if (ownerType === "occurrence") {
3907
+ const occurrence = await this.repository.getOccurrence(
3908
+ this.agentId(),
3909
+ ownerId
3910
+ );
3911
+ if (!occurrence) {
3912
+ fail(404, "life-ops occurrence not found");
3913
+ }
3914
+ const definition = await this.repository.getDefinition(
3915
+ this.agentId(),
3916
+ occurrence.definitionId
3917
+ );
3918
+ if (definition?.reminderPlanId) {
3919
+ plan = await this.repository.getReminderPlan(
3920
+ this.agentId(),
3921
+ definition.reminderPlanId
3922
+ );
3923
+ }
3924
+ } else {
3925
+ const plans = await this.repository.listReminderPlansForOwners(
3926
+ this.agentId(),
3927
+ "calendar_event",
3928
+ [ownerId]
3929
+ );
3930
+ plan = plans[0] ?? null;
3931
+ }
3932
+ return {
3933
+ ownerType,
3934
+ ownerId,
3935
+ reminderPlan: plan,
3936
+ attempts: await this.repository.listReminderAttempts(this.agentId(), {
3937
+ ownerType,
3938
+ ownerId
3939
+ }),
3940
+ audits: await this.repository.listAuditEvents(
3941
+ this.agentId(),
3942
+ ownerType,
3943
+ ownerId
3944
+ )
3945
+ };
3946
+ }
3947
+ async acknowledgeReminder(request) {
3948
+ const ownerType = normalizeEnumValue(request.ownerType, "ownerType", [
3949
+ "occurrence",
3950
+ "calendar_event"
3951
+ ]);
3952
+ const ownerId = requireNonEmptyString(request.ownerId, "ownerId");
3953
+ const acknowledgedAt = request.acknowledgedAt === void 0 ? (/* @__PURE__ */ new Date()).toISOString() : normalizeIsoString(request.acknowledgedAt, "acknowledgedAt");
3954
+ const note = normalizeOptionalString(request.note) ?? null;
3955
+ if (ownerType === "occurrence") {
3956
+ const occurrence = await this.repository.getOccurrence(
3957
+ this.agentId(),
3958
+ ownerId
3959
+ );
3960
+ if (!occurrence) {
3961
+ fail(404, "life-ops occurrence not found");
3962
+ }
3963
+ await this.repository.updateOccurrence({
3964
+ ...occurrence,
3965
+ metadata: {
3966
+ ...occurrence.metadata,
3967
+ reminderAcknowledgedAt: acknowledgedAt,
3968
+ reminderAcknowledgedNote: note
3969
+ },
3970
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3971
+ });
3972
+ } else {
3973
+ const event = (await this.repository.listCalendarEvents(this.agentId(), "google")).find((candidate) => candidate.id === ownerId);
3974
+ if (!event) {
3975
+ fail(404, "life-ops calendar event not found");
3976
+ }
3977
+ await this.repository.upsertCalendarEvent({
3978
+ ...event,
3979
+ metadata: {
3980
+ ...event.metadata,
3981
+ reminderAcknowledgedAt: acknowledgedAt,
3982
+ reminderAcknowledgedNote: note
3983
+ },
3984
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3985
+ });
3986
+ }
3987
+ await this.resolveReminderEscalation({
3988
+ ownerType,
3989
+ ownerId,
3990
+ resolvedAt: acknowledgedAt,
3991
+ resolution: "acknowledged",
3992
+ note
3993
+ });
3994
+ return { ok: true };
3995
+ }
3996
+ };
3997
+ }
3998
+ export {
3999
+ REMINDER_DISPATCH_INSTRUCTIONS2 as REMINDER_DISPATCH_INSTRUCTIONS,
4000
+ buildReminderDispatchPrompt,
4001
+ withReminders
4002
+ };
4003
+ //# sourceMappingURL=service-mixin-reminders.js.map