@geminixiang/mikan 1.0.0-beta.76 → 1.0.0-beta.78

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 (535) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/adapters/commands/login.d.ts.map +1 -1
  3. package/dist/adapters/commands/login.js +0 -9
  4. package/dist/adapters/commands/login.js.map +1 -1
  5. package/dist/adapters/commands/manifest.d.ts +0 -19
  6. package/dist/adapters/commands/manifest.d.ts.map +1 -1
  7. package/dist/adapters/commands/manifest.js +0 -34
  8. package/dist/adapters/commands/manifest.js.map +1 -1
  9. package/dist/adapters/commands/model.d.ts +0 -5
  10. package/dist/adapters/commands/model.d.ts.map +1 -1
  11. package/dist/adapters/commands/model.js +0 -5
  12. package/dist/adapters/commands/model.js.map +1 -1
  13. package/dist/adapters/commands/new.d.ts.map +1 -1
  14. package/dist/adapters/commands/new.js +0 -2
  15. package/dist/adapters/commands/new.js.map +1 -1
  16. package/dist/adapters/commands/registry.d.ts +0 -1
  17. package/dist/adapters/commands/registry.d.ts.map +1 -1
  18. package/dist/adapters/commands/registry.js +0 -8
  19. package/dist/adapters/commands/registry.js.map +1 -1
  20. package/dist/adapters/commands/session-view.d.ts.map +1 -1
  21. package/dist/adapters/commands/session-view.js +0 -2
  22. package/dist/adapters/commands/session-view.js.map +1 -1
  23. package/dist/adapters/commands/types.d.ts +0 -29
  24. package/dist/adapters/commands/types.d.ts.map +1 -1
  25. package/dist/adapters/commands/types.js.map +1 -1
  26. package/dist/adapters/commands/utils.d.ts +0 -3
  27. package/dist/adapters/commands/utils.d.ts.map +1 -1
  28. package/dist/adapters/commands/utils.js +0 -3
  29. package/dist/adapters/commands/utils.js.map +1 -1
  30. package/dist/adapters/discord/bot.d.ts +0 -4
  31. package/dist/adapters/discord/bot.d.ts.map +1 -1
  32. package/dist/adapters/discord/bot.js +5 -41
  33. package/dist/adapters/discord/bot.js.map +1 -1
  34. package/dist/adapters/discord/components.d.ts +0 -23
  35. package/dist/adapters/discord/components.d.ts.map +1 -1
  36. package/dist/adapters/discord/components.js +0 -23
  37. package/dist/adapters/discord/components.js.map +1 -1
  38. package/dist/adapters/discord/context.d.ts.map +1 -1
  39. package/dist/adapters/discord/context.js +1 -11
  40. package/dist/adapters/discord/context.js.map +1 -1
  41. package/dist/adapters/discord/format.d.ts +0 -1
  42. package/dist/adapters/discord/format.d.ts.map +1 -1
  43. package/dist/adapters/discord/format.js +0 -37
  44. package/dist/adapters/discord/format.js.map +1 -1
  45. package/dist/adapters/github/bot.d.ts +0 -44
  46. package/dist/adapters/github/bot.d.ts.map +1 -1
  47. package/dist/adapters/github/bot.js +1 -120
  48. package/dist/adapters/github/bot.js.map +1 -1
  49. package/dist/adapters/github/client.d.ts +0 -57
  50. package/dist/adapters/github/client.d.ts.map +1 -1
  51. package/dist/adapters/github/client.js +0 -59
  52. package/dist/adapters/github/client.js.map +1 -1
  53. package/dist/adapters/github/context.d.ts.map +1 -1
  54. package/dist/adapters/github/context.js +1 -8
  55. package/dist/adapters/github/context.js.map +1 -1
  56. package/dist/adapters/github/github-ops.d.ts +0 -55
  57. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  58. package/dist/adapters/github/github-ops.js +0 -59
  59. package/dist/adapters/github/github-ops.js.map +1 -1
  60. package/dist/adapters/github/ids.d.ts +0 -27
  61. package/dist/adapters/github/ids.d.ts.map +1 -1
  62. package/dist/adapters/github/ids.js +0 -29
  63. package/dist/adapters/github/ids.js.map +1 -1
  64. package/dist/adapters/github/repo.d.ts +0 -25
  65. package/dist/adapters/github/repo.d.ts.map +1 -1
  66. package/dist/adapters/github/repo.js +0 -49
  67. package/dist/adapters/github/repo.js.map +1 -1
  68. package/dist/adapters/github/tool-pack.d.ts +0 -10
  69. package/dist/adapters/github/tool-pack.d.ts.map +1 -1
  70. package/dist/adapters/github/tool-pack.js +0 -10
  71. package/dist/adapters/github/tool-pack.js.map +1 -1
  72. package/dist/adapters/github/tools/checks.d.ts +0 -6
  73. package/dist/adapters/github/tools/checks.d.ts.map +1 -1
  74. package/dist/adapters/github/tools/checks.js +0 -7
  75. package/dist/adapters/github/tools/checks.js.map +1 -1
  76. package/dist/adapters/github/tools/issue.d.ts +0 -5
  77. package/dist/adapters/github/tools/issue.d.ts.map +1 -1
  78. package/dist/adapters/github/tools/issue.js +0 -5
  79. package/dist/adapters/github/tools/issue.js.map +1 -1
  80. package/dist/adapters/github/tools/pr.d.ts +0 -7
  81. package/dist/adapters/github/tools/pr.d.ts.map +1 -1
  82. package/dist/adapters/github/tools/pr.js +0 -7
  83. package/dist/adapters/github/tools/pr.js.map +1 -1
  84. package/dist/adapters/github/tools/read.d.ts +0 -6
  85. package/dist/adapters/github/tools/read.d.ts.map +1 -1
  86. package/dist/adapters/github/tools/read.js +0 -8
  87. package/dist/adapters/github/tools/read.js.map +1 -1
  88. package/dist/adapters/github/tools/review-reply.d.ts +0 -5
  89. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
  90. package/dist/adapters/github/tools/review-reply.js +0 -5
  91. package/dist/adapters/github/tools/review-reply.js.map +1 -1
  92. package/dist/adapters/github/tools/sync.d.ts +0 -6
  93. package/dist/adapters/github/tools/sync.d.ts.map +1 -1
  94. package/dist/adapters/github/tools/sync.js +0 -6
  95. package/dist/adapters/github/tools/sync.js.map +1 -1
  96. package/dist/adapters/github/types.d.ts +0 -88
  97. package/dist/adapters/github/types.d.ts.map +1 -1
  98. package/dist/adapters/github/types.js.map +1 -1
  99. package/dist/adapters/github/webhook.d.ts +0 -13
  100. package/dist/adapters/github/webhook.d.ts.map +1 -1
  101. package/dist/adapters/github/webhook.js +0 -16
  102. package/dist/adapters/github/webhook.js.map +1 -1
  103. package/dist/adapters/index.d.ts +3 -4
  104. package/dist/adapters/index.d.ts.map +1 -1
  105. package/dist/adapters/index.js +4 -4
  106. package/dist/adapters/index.js.map +1 -1
  107. package/dist/adapters/intake.d.ts +0 -17
  108. package/dist/adapters/intake.d.ts.map +1 -1
  109. package/dist/adapters/intake.js +6 -32
  110. package/dist/adapters/intake.js.map +1 -1
  111. package/dist/adapters/markdown-tables.d.ts +0 -10
  112. package/dist/adapters/markdown-tables.d.ts.map +1 -1
  113. package/dist/adapters/markdown-tables.js +1 -42
  114. package/dist/adapters/markdown-tables.js.map +1 -1
  115. package/dist/adapters/progressive-renderer.d.ts.map +1 -1
  116. package/dist/adapters/progressive-renderer.js +3 -25
  117. package/dist/adapters/progressive-renderer.js.map +1 -1
  118. package/dist/adapters/shared.d.ts +0 -57
  119. package/dist/adapters/shared.d.ts.map +1 -1
  120. package/dist/adapters/shared.js +0 -71
  121. package/dist/adapters/shared.js.map +1 -1
  122. package/dist/adapters/slack/assistant.d.ts +0 -49
  123. package/dist/adapters/slack/assistant.d.ts.map +1 -1
  124. package/dist/adapters/slack/assistant.js +0 -97
  125. package/dist/adapters/slack/assistant.js.map +1 -1
  126. package/dist/adapters/slack/auto-reply-context.d.ts +0 -7
  127. package/dist/adapters/slack/auto-reply-context.d.ts.map +1 -1
  128. package/dist/adapters/slack/auto-reply-context.js +0 -7
  129. package/dist/adapters/slack/auto-reply-context.js.map +1 -1
  130. package/dist/adapters/slack/blocks.d.ts +0 -9
  131. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  132. package/dist/adapters/slack/blocks.js +0 -20
  133. package/dist/adapters/slack/blocks.js.map +1 -1
  134. package/dist/adapters/slack/bot.d.ts +0 -116
  135. package/dist/adapters/slack/bot.d.ts.map +1 -1
  136. package/dist/adapters/slack/bot.js +7 -231
  137. package/dist/adapters/slack/bot.js.map +1 -1
  138. package/dist/adapters/slack/context.d.ts.map +1 -1
  139. package/dist/adapters/slack/context.js +1 -3
  140. package/dist/adapters/slack/context.js.map +1 -1
  141. package/dist/adapters/slack/jev-context.d.ts +0 -13
  142. package/dist/adapters/slack/jev-context.d.ts.map +1 -1
  143. package/dist/adapters/slack/jev-context.js +0 -12
  144. package/dist/adapters/slack/jev-context.js.map +1 -1
  145. package/dist/adapters/slack/markdown.d.ts +0 -1
  146. package/dist/adapters/slack/markdown.d.ts.map +1 -1
  147. package/dist/adapters/slack/markdown.js +0 -5
  148. package/dist/adapters/slack/markdown.js.map +1 -1
  149. package/dist/adapters/slack/persona.d.ts +0 -9
  150. package/dist/adapters/slack/persona.d.ts.map +1 -1
  151. package/dist/adapters/slack/persona.js +0 -9
  152. package/dist/adapters/slack/persona.js.map +1 -1
  153. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  154. package/dist/adapters/slack/response-lifecycle.js +1 -45
  155. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  156. package/dist/adapters/slack/session.d.ts +2 -1
  157. package/dist/adapters/slack/session.d.ts.map +1 -1
  158. package/dist/adapters/slack/session.js +2 -2
  159. package/dist/adapters/slack/session.js.map +1 -1
  160. package/dist/adapters/slack/stream-limits.d.ts +0 -25
  161. package/dist/adapters/slack/stream-limits.d.ts.map +1 -1
  162. package/dist/adapters/slack/stream-limits.js +0 -34
  163. package/dist/adapters/slack/stream-limits.js.map +1 -1
  164. package/dist/adapters/slack/task-intent.d.ts +0 -13
  165. package/dist/adapters/slack/task-intent.d.ts.map +1 -1
  166. package/dist/adapters/slack/task-intent.js +0 -7
  167. package/dist/adapters/slack/task-intent.js.map +1 -1
  168. package/dist/adapters/slack/task-status.d.ts +0 -1
  169. package/dist/adapters/slack/task-status.d.ts.map +1 -1
  170. package/dist/adapters/slack/task-status.js +1 -9
  171. package/dist/adapters/slack/task-status.js.map +1 -1
  172. package/dist/adapters/slack/tool-pack.d.ts +0 -6
  173. package/dist/adapters/slack/tool-pack.d.ts.map +1 -1
  174. package/dist/adapters/slack/tool-pack.js +0 -6
  175. package/dist/adapters/slack/tool-pack.js.map +1 -1
  176. package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -1
  177. package/dist/adapters/slack/tools/blockkit.js +0 -11
  178. package/dist/adapters/slack/tools/blockkit.js.map +1 -1
  179. package/dist/adapters/slack/types.d.ts +0 -19
  180. package/dist/adapters/slack/types.d.ts.map +1 -1
  181. package/dist/adapters/slack/types.js.map +1 -1
  182. package/dist/adapters/slack/update-diagnostics.d.ts +0 -1
  183. package/dist/adapters/slack/update-diagnostics.d.ts.map +1 -1
  184. package/dist/adapters/slack/update-diagnostics.js +1 -7
  185. package/dist/adapters/slack/update-diagnostics.js.map +1 -1
  186. package/dist/adapters/telegram/bot.d.ts +0 -6
  187. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  188. package/dist/adapters/telegram/bot.js +1 -50
  189. package/dist/adapters/telegram/bot.js.map +1 -1
  190. package/dist/adapters/telegram/context.d.ts.map +1 -1
  191. package/dist/adapters/telegram/context.js +1 -8
  192. package/dist/adapters/telegram/context.js.map +1 -1
  193. package/dist/adapters/types.d.ts +0 -57
  194. package/dist/adapters/types.d.ts.map +1 -1
  195. package/dist/adapters/types.js.map +1 -1
  196. package/dist/adapters/web/admin/client-assets.d.ts +4 -0
  197. package/dist/adapters/web/admin/client-assets.d.ts.map +1 -0
  198. package/dist/adapters/web/admin/client-assets.js +1765 -0
  199. package/dist/adapters/web/admin/client-assets.js.map +1 -0
  200. package/dist/adapters/web/admin/portal.d.ts +0 -10
  201. package/dist/adapters/web/admin/portal.d.ts.map +1 -1
  202. package/dist/adapters/web/admin/portal.js +6 -1909
  203. package/dist/adapters/web/admin/portal.js.map +1 -1
  204. package/dist/adapters/web/admin/types.d.ts +0 -3
  205. package/dist/adapters/web/admin/types.d.ts.map +1 -1
  206. package/dist/adapters/web/admin/types.js.map +1 -1
  207. package/dist/adapters/web/login/oauth.d.ts.map +1 -1
  208. package/dist/adapters/web/login/oauth.js +3 -7
  209. package/dist/adapters/web/login/oauth.js.map +1 -1
  210. package/dist/adapters/web/login/portal.d.ts +0 -10
  211. package/dist/adapters/web/login/portal.d.ts.map +1 -1
  212. package/dist/adapters/web/login/portal.js +4 -37
  213. package/dist/adapters/web/login/portal.js.map +1 -1
  214. package/dist/adapters/web/login/types.d.ts +0 -5
  215. package/dist/adapters/web/login/types.d.ts.map +1 -1
  216. package/dist/adapters/web/login/types.js.map +1 -1
  217. package/dist/adapters/web/portal-shell.d.ts +0 -12
  218. package/dist/adapters/web/portal-shell.d.ts.map +1 -1
  219. package/dist/adapters/web/portal-shell.js +8 -25
  220. package/dist/adapters/web/portal-shell.js.map +1 -1
  221. package/dist/adapters/web/server.d.ts +0 -1
  222. package/dist/adapters/web/server.d.ts.map +1 -1
  223. package/dist/adapters/web/server.js +0 -2
  224. package/dist/adapters/web/server.js.map +1 -1
  225. package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
  226. package/dist/adapters/web/session-view/portal.js +13 -24
  227. package/dist/adapters/web/session-view/portal.js.map +1 -1
  228. package/dist/adapters/web/session-view/types.d.ts.map +1 -1
  229. package/dist/adapters/web/session-view/types.js.map +1 -1
  230. package/dist/adapters/web/token-store.d.ts +0 -2
  231. package/dist/adapters/web/token-store.d.ts.map +1 -1
  232. package/dist/adapters/web/token-store.js +0 -2
  233. package/dist/adapters/web/token-store.js.map +1 -1
  234. package/dist/cli/arg-grammar.d.ts +0 -3
  235. package/dist/cli/arg-grammar.d.ts.map +1 -1
  236. package/dist/cli/arg-grammar.js +0 -3
  237. package/dist/cli/arg-grammar.js.map +1 -1
  238. package/dist/cli/boot.d.ts.map +1 -1
  239. package/dist/cli/boot.js +3 -12
  240. package/dist/cli/boot.js.map +1 -1
  241. package/dist/cli/download.d.ts.map +1 -1
  242. package/dist/cli/download.js +2 -6
  243. package/dist/cli/download.js.map +1 -1
  244. package/dist/cli/office.d.ts.map +1 -1
  245. package/dist/cli/office.js +0 -31
  246. package/dist/cli/office.js.map +1 -1
  247. package/dist/cli/onboard.d.ts +0 -2
  248. package/dist/cli/onboard.d.ts.map +1 -1
  249. package/dist/cli/onboard.js +0 -30
  250. package/dist/cli/onboard.js.map +1 -1
  251. package/dist/cli/process-lifecycle.d.ts +0 -5
  252. package/dist/cli/process-lifecycle.d.ts.map +1 -1
  253. package/dist/cli/process-lifecycle.js +0 -6
  254. package/dist/cli/process-lifecycle.js.map +1 -1
  255. package/dist/cli/sandbox.d.ts +3 -0
  256. package/dist/cli/sandbox.d.ts.map +1 -0
  257. package/dist/cli/sandbox.js +79 -0
  258. package/dist/cli/sandbox.js.map +1 -0
  259. package/dist/cli/sessions.d.ts.map +1 -1
  260. package/dist/cli/sessions.js +0 -11
  261. package/dist/cli/sessions.js.map +1 -1
  262. package/dist/cli/types.d.ts +2 -6
  263. package/dist/cli/types.d.ts.map +1 -1
  264. package/dist/cli/types.js.map +1 -1
  265. package/dist/env-manifest.d.ts +0 -21
  266. package/dist/env-manifest.d.ts.map +1 -1
  267. package/dist/env-manifest.js +0 -11
  268. package/dist/env-manifest.js.map +1 -1
  269. package/dist/events/index.d.ts +0 -51
  270. package/dist/events/index.d.ts.map +1 -1
  271. package/dist/events/index.js +0 -42
  272. package/dist/events/index.js.map +1 -1
  273. package/dist/events/scheduler.d.ts +0 -8
  274. package/dist/events/scheduler.d.ts.map +1 -1
  275. package/dist/events/scheduler.js +0 -8
  276. package/dist/events/scheduler.js.map +1 -1
  277. package/dist/file-guards.d.ts +0 -15
  278. package/dist/file-guards.d.ts.map +1 -1
  279. package/dist/file-guards.js +2 -26
  280. package/dist/file-guards.js.map +1 -1
  281. package/dist/harness/execution-env.d.ts +0 -15
  282. package/dist/harness/execution-env.d.ts.map +1 -1
  283. package/dist/harness/execution-env.js +4 -55
  284. package/dist/harness/execution-env.js.map +1 -1
  285. package/dist/harness/http.d.ts +0 -12
  286. package/dist/harness/http.d.ts.map +1 -1
  287. package/dist/harness/http.js +0 -34
  288. package/dist/harness/http.js.map +1 -1
  289. package/dist/harness/index.d.ts +4 -7
  290. package/dist/harness/index.d.ts.map +1 -1
  291. package/dist/harness/index.js +4 -7
  292. package/dist/harness/index.js.map +1 -1
  293. package/dist/harness/jev.d.ts +0 -28
  294. package/dist/harness/jev.d.ts.map +1 -1
  295. package/dist/harness/jev.js +0 -45
  296. package/dist/harness/jev.js.map +1 -1
  297. package/dist/harness/mcp-result.d.ts +20 -0
  298. package/dist/harness/mcp-result.d.ts.map +1 -0
  299. package/dist/harness/mcp-result.js +171 -0
  300. package/dist/harness/mcp-result.js.map +1 -0
  301. package/dist/harness/mcp.d.ts +0 -19
  302. package/dist/harness/mcp.d.ts.map +1 -1
  303. package/dist/harness/mcp.js +7 -66
  304. package/dist/harness/mcp.js.map +1 -1
  305. package/dist/harness/models.d.ts +0 -19
  306. package/dist/harness/models.d.ts.map +1 -1
  307. package/dist/harness/models.js +0 -52
  308. package/dist/harness/models.js.map +1 -1
  309. package/dist/harness/open-connector.d.ts +0 -12
  310. package/dist/harness/open-connector.d.ts.map +1 -1
  311. package/dist/harness/open-connector.js +0 -22
  312. package/dist/harness/open-connector.js.map +1 -1
  313. package/dist/harness/presenter.d.ts +1 -0
  314. package/dist/harness/presenter.d.ts.map +1 -1
  315. package/dist/harness/presenter.js +16 -66
  316. package/dist/harness/presenter.js.map +1 -1
  317. package/dist/harness/prompt.d.ts +0 -11
  318. package/dist/harness/prompt.d.ts.map +1 -1
  319. package/dist/harness/prompt.js +1 -18
  320. package/dist/harness/prompt.js.map +1 -1
  321. package/dist/harness/runner.d.ts.map +1 -1
  322. package/dist/harness/runner.js +8 -28
  323. package/dist/harness/runner.js.map +1 -1
  324. package/dist/harness/session.d.ts +11 -28
  325. package/dist/harness/session.d.ts.map +1 -1
  326. package/dist/harness/session.js +100 -38
  327. package/dist/harness/session.js.map +1 -1
  328. package/dist/harness/skills.d.ts +0 -22
  329. package/dist/harness/skills.d.ts.map +1 -1
  330. package/dist/harness/skills.js +0 -20
  331. package/dist/harness/skills.js.map +1 -1
  332. package/dist/harness/subagent-profiles.d.ts +0 -4
  333. package/dist/harness/subagent-profiles.d.ts.map +1 -1
  334. package/dist/harness/subagent-profiles.js +0 -29
  335. package/dist/harness/subagent-profiles.js.map +1 -1
  336. package/dist/harness/subagent.d.ts +0 -25
  337. package/dist/harness/subagent.d.ts.map +1 -1
  338. package/dist/harness/subagent.js +1 -70
  339. package/dist/harness/subagent.js.map +1 -1
  340. package/dist/harness/tools/event.d.ts.map +1 -1
  341. package/dist/harness/tools/event.js +0 -9
  342. package/dist/harness/tools/event.js.map +1 -1
  343. package/dist/harness/tools/generate-image.d.ts +0 -6
  344. package/dist/harness/tools/generate-image.d.ts.map +1 -1
  345. package/dist/harness/tools/generate-image.js.map +1 -1
  346. package/dist/harness/tools/host-fn-tool.d.ts +0 -17
  347. package/dist/harness/tools/host-fn-tool.d.ts.map +1 -1
  348. package/dist/harness/tools/host-fn-tool.js +0 -16
  349. package/dist/harness/tools/host-fn-tool.js.map +1 -1
  350. package/dist/harness/tools/index.d.ts +1 -7
  351. package/dist/harness/tools/index.d.ts.map +1 -1
  352. package/dist/harness/tools/index.js +3 -14
  353. package/dist/harness/tools/index.js.map +1 -1
  354. package/dist/harness/tools/jev-browser.d.ts +4 -94
  355. package/dist/harness/tools/jev-browser.d.ts.map +1 -1
  356. package/dist/harness/tools/jev-browser.js +203 -92
  357. package/dist/harness/tools/jev-browser.js.map +1 -1
  358. package/dist/harness/tools/jev.d.ts +0 -8
  359. package/dist/harness/tools/jev.d.ts.map +1 -1
  360. package/dist/harness/tools/jev.js +0 -11
  361. package/dist/harness/tools/jev.js.map +1 -1
  362. package/dist/harness/tools/pi-tools.d.ts +1 -11
  363. package/dist/harness/tools/pi-tools.d.ts.map +1 -1
  364. package/dist/harness/tools/pi-tools.js +1 -30
  365. package/dist/harness/tools/pi-tools.js.map +1 -1
  366. package/dist/harness/tools/react.d.ts +0 -5
  367. package/dist/harness/tools/react.d.ts.map +1 -1
  368. package/dist/harness/tools/react.js +0 -5
  369. package/dist/harness/tools/react.js.map +1 -1
  370. package/dist/harness/tools/secret-redaction.d.ts +0 -25
  371. package/dist/harness/tools/secret-redaction.d.ts.map +1 -1
  372. package/dist/harness/tools/secret-redaction.js +3 -36
  373. package/dist/harness/tools/secret-redaction.js.map +1 -1
  374. package/dist/harness/tools/subagent.d.ts +0 -34
  375. package/dist/harness/tools/subagent.d.ts.map +1 -1
  376. package/dist/harness/tools/subagent.js +0 -92
  377. package/dist/harness/tools/subagent.js.map +1 -1
  378. package/dist/harness/tools/task.d.ts +0 -1
  379. package/dist/harness/tools/task.d.ts.map +1 -1
  380. package/dist/harness/tools/task.js +0 -1
  381. package/dist/harness/tools/task.js.map +1 -1
  382. package/dist/harness/tools/types.d.ts +0 -16
  383. package/dist/harness/tools/types.d.ts.map +1 -1
  384. package/dist/harness/tools/types.js.map +1 -1
  385. package/dist/harness/types.d.ts +1 -77
  386. package/dist/harness/types.d.ts.map +1 -1
  387. package/dist/harness/types.js.map +1 -1
  388. package/dist/index.d.ts.map +1 -1
  389. package/dist/index.js +0 -2
  390. package/dist/index.js.map +1 -1
  391. package/dist/log.d.ts.map +1 -1
  392. package/dist/log.js +0 -13
  393. package/dist/log.js.map +1 -1
  394. package/dist/main.js +7 -52
  395. package/dist/main.js.map +1 -1
  396. package/dist/memory-capture/index.d.ts +16 -0
  397. package/dist/memory-capture/index.d.ts.map +1 -0
  398. package/dist/memory-capture/index.js +194 -0
  399. package/dist/memory-capture/index.js.map +1 -0
  400. package/dist/memory-capture/types.d.ts +27 -0
  401. package/dist/memory-capture/types.d.ts.map +1 -0
  402. package/dist/memory-capture/types.js.map +1 -0
  403. package/dist/observability/index.d.ts +0 -9
  404. package/dist/observability/index.d.ts.map +1 -1
  405. package/dist/observability/index.js +0 -9
  406. package/dist/observability/index.js.map +1 -1
  407. package/dist/observability/instrument.js +0 -5
  408. package/dist/observability/instrument.js.map +1 -1
  409. package/dist/observability/otel.js +0 -1
  410. package/dist/observability/otel.js.map +1 -1
  411. package/dist/observability/sentry.d.ts +0 -18
  412. package/dist/observability/sentry.d.ts.map +1 -1
  413. package/dist/observability/sentry.js +0 -36
  414. package/dist/observability/sentry.js.map +1 -1
  415. package/dist/observability/types.d.ts +1 -10
  416. package/dist/observability/types.d.ts.map +1 -1
  417. package/dist/observability/types.js.map +1 -1
  418. package/dist/office/index.d.ts +0 -76
  419. package/dist/office/index.d.ts.map +1 -1
  420. package/dist/office/index.js +4 -154
  421. package/dist/office/index.js.map +1 -1
  422. package/dist/office/projection.d.ts +0 -29
  423. package/dist/office/projection.d.ts.map +1 -1
  424. package/dist/office/projection.js +5 -41
  425. package/dist/office/projection.js.map +1 -1
  426. package/dist/office/types.d.ts +0 -66
  427. package/dist/office/types.d.ts.map +1 -1
  428. package/dist/office/types.js.map +1 -1
  429. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  430. package/dist/runtime/conversation-runtime.js +22 -83
  431. package/dist/runtime/conversation-runtime.js.map +1 -1
  432. package/dist/runtime/session-lifecycle.d.ts +0 -10
  433. package/dist/runtime/session-lifecycle.d.ts.map +1 -1
  434. package/dist/runtime/session-lifecycle.js +0 -12
  435. package/dist/runtime/session-lifecycle.js.map +1 -1
  436. package/dist/runtime/types.d.ts +2 -29
  437. package/dist/runtime/types.d.ts.map +1 -1
  438. package/dist/runtime/types.js.map +1 -1
  439. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  440. package/dist/sandbox/cloudflare.js +2 -1
  441. package/dist/sandbox/cloudflare.js.map +1 -1
  442. package/dist/sandbox/container.d.ts.map +1 -1
  443. package/dist/sandbox/container.js +21 -15
  444. package/dist/sandbox/container.js.map +1 -1
  445. package/dist/sandbox/host.d.ts.map +1 -1
  446. package/dist/sandbox/host.js +0 -2
  447. package/dist/sandbox/host.js.map +1 -1
  448. package/dist/sandbox/identity.d.ts +0 -28
  449. package/dist/sandbox/identity.d.ts.map +1 -1
  450. package/dist/sandbox/identity.js +0 -28
  451. package/dist/sandbox/identity.js.map +1 -1
  452. package/dist/sandbox/index.d.ts +0 -18
  453. package/dist/sandbox/index.d.ts.map +1 -1
  454. package/dist/sandbox/index.js +2 -19
  455. package/dist/sandbox/index.js.map +1 -1
  456. package/dist/sandbox/layout.d.ts +7 -0
  457. package/dist/sandbox/layout.d.ts.map +1 -0
  458. package/dist/sandbox/layout.js +13 -0
  459. package/dist/sandbox/layout.js.map +1 -0
  460. package/dist/sandbox/provisioner.d.ts +24 -65
  461. package/dist/sandbox/provisioner.d.ts.map +1 -1
  462. package/dist/sandbox/provisioner.js +213 -125
  463. package/dist/sandbox/provisioner.js.map +1 -1
  464. package/dist/sandbox/types.d.ts +0 -39
  465. package/dist/sandbox/types.d.ts.map +1 -1
  466. package/dist/sandbox/types.js.map +1 -1
  467. package/dist/sandbox/utils.d.ts +2 -5
  468. package/dist/sandbox/utils.d.ts.map +1 -1
  469. package/dist/sandbox/utils.js +31 -31
  470. package/dist/sandbox/utils.js.map +1 -1
  471. package/dist/sessions/chat-history-sync.d.ts +0 -6
  472. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  473. package/dist/sessions/chat-history-sync.js +1 -33
  474. package/dist/sessions/chat-history-sync.js.map +1 -1
  475. package/dist/sessions/history-line.d.ts +0 -20
  476. package/dist/sessions/history-line.d.ts.map +1 -1
  477. package/dist/sessions/history-line.js +0 -20
  478. package/dist/sessions/history-line.js.map +1 -1
  479. package/dist/sessions/migrate-common.d.ts +0 -15
  480. package/dist/sessions/migrate-common.d.ts.map +1 -1
  481. package/dist/sessions/migrate-common.js +0 -19
  482. package/dist/sessions/migrate-common.js.map +1 -1
  483. package/dist/sessions/migrate-pi-084.d.ts.map +1 -1
  484. package/dist/sessions/migrate-pi-084.js +0 -7
  485. package/dist/sessions/migrate-pi-084.js.map +1 -1
  486. package/dist/sessions/migrate-v3.d.ts +0 -7
  487. package/dist/sessions/migrate-v3.d.ts.map +1 -1
  488. package/dist/sessions/migrate-v3.js +1 -67
  489. package/dist/sessions/migrate-v3.js.map +1 -1
  490. package/dist/sessions/session-key.d.ts +3 -17
  491. package/dist/sessions/session-key.d.ts.map +1 -1
  492. package/dist/sessions/session-key.js +8 -35
  493. package/dist/sessions/session-key.js.map +1 -1
  494. package/dist/sessions/session-store.d.ts +1 -7
  495. package/dist/sessions/session-store.d.ts.map +1 -1
  496. package/dist/sessions/session-store.js +8 -50
  497. package/dist/sessions/session-store.js.map +1 -1
  498. package/dist/sessions/store.d.ts +0 -60
  499. package/dist/sessions/store.d.ts.map +1 -1
  500. package/dist/sessions/store.js +0 -113
  501. package/dist/sessions/store.js.map +1 -1
  502. package/dist/sessions/types.d.ts +0 -17
  503. package/dist/sessions/types.d.ts.map +1 -1
  504. package/dist/sessions/types.js.map +1 -1
  505. package/dist/settings/apply.d.ts +0 -6
  506. package/dist/settings/apply.d.ts.map +1 -1
  507. package/dist/settings/apply.js +0 -29
  508. package/dist/settings/apply.js.map +1 -1
  509. package/dist/settings/index.d.ts +0 -53
  510. package/dist/settings/index.d.ts.map +1 -1
  511. package/dist/settings/index.js +0 -77
  512. package/dist/settings/index.js.map +1 -1
  513. package/dist/settings/migrate.d.ts +0 -5
  514. package/dist/settings/migrate.d.ts.map +1 -1
  515. package/dist/settings/migrate.js +0 -17
  516. package/dist/settings/migrate.js.map +1 -1
  517. package/dist/types.d.ts +9 -159
  518. package/dist/types.d.ts.map +1 -1
  519. package/dist/types.js.map +1 -1
  520. package/dist/vault/index.d.ts +2 -36
  521. package/dist/vault/index.d.ts.map +1 -1
  522. package/dist/vault/index.js +135 -65
  523. package/dist/vault/index.js.map +1 -1
  524. package/dist/vault/types.d.ts +0 -15
  525. package/dist/vault/types.d.ts.map +1 -1
  526. package/dist/vault/types.js.map +1 -1
  527. package/package.json +1 -1
  528. package/dist/dream/index.d.ts +0 -20
  529. package/dist/dream/index.d.ts.map +0 -1
  530. package/dist/dream/index.js +0 -264
  531. package/dist/dream/index.js.map +0 -1
  532. package/dist/dream/types.d.ts +0 -30
  533. package/dist/dream/types.d.ts.map +0 -1
  534. package/dist/dream/types.js.map +0 -1
  535. /package/dist/{dream → memory-capture}/types.js +0 -0
@@ -6,23 +6,12 @@ export interface EventRecord {
6
6
  size: number;
7
7
  mtimeMs: number;
8
8
  }
9
- /**
10
- * One office's admitted scheduled work. Every method is confined to that
11
- * office: filenames of other offices read as "not found", and payloads must
12
- * address the store's own office.
13
- */
14
9
  export interface EventStore {
15
10
  readonly address: OfficeAddress;
16
- /** Create a new record; an existing filename is an error, never overwritten. */
17
11
  create(filename: string, payload: EventFilePayload): Promise<{
18
12
  path: string;
19
13
  size: number;
20
14
  }>;
21
- /**
22
- * List this office's records. Entries whose JSON cannot be parsed or fail
23
- * format validation are kept with a `null` payload so operators can still
24
- * surface and delete them; files that disappear mid-listing are skipped.
25
- */
26
15
  list(): Promise<Array<Omit<EventRecord, "payload"> & {
27
16
  payload: EventFilePayload | null;
28
17
  }>>;
@@ -35,7 +24,6 @@ export interface EventStore {
35
24
  deleted: boolean;
36
25
  }>;
37
26
  }
38
- /** Scheduler hooks the store calls after each admitted mutation. */
39
27
  export interface EventScheduleSink {
40
28
  scheduleRecord(address: OfficeAddress, record: EventRecord): void;
41
29
  cancelRecord(address: OfficeAddress, filename: string): void;
@@ -43,12 +31,10 @@ export interface EventScheduleSink {
43
31
  export type EventConversationKind = "direct" | "shared";
44
32
  export type EventType = "immediate" | "one-shot" | "periodic";
45
33
  interface EventPayloadBase {
46
- /** Target platform; may be omitted when only one platform is running. */
47
34
  platform?: string;
48
35
  conversationId: string;
49
36
  conversationKind?: EventConversationKind;
50
37
  userId?: string;
51
- /** Self-contained task text; event runs do not inherit conversation history. */
52
38
  text: string;
53
39
  }
54
40
  export interface ImmediateEventPayload extends EventPayloadBase {
@@ -56,17 +42,13 @@ export interface ImmediateEventPayload extends EventPayloadBase {
56
42
  }
57
43
  export interface OneShotEventPayload extends EventPayloadBase {
58
44
  type: "one-shot";
59
- /** ISO 8601 timestamp with offset. */
60
45
  at: string;
61
46
  }
62
47
  export interface PeriodicEventPayload extends EventPayloadBase {
63
48
  type: "periodic";
64
- /** Cron expression (croner syntax). */
65
49
  schedule: string;
66
- /** IANA timezone, e.g. "Asia/Taipei". */
67
50
  timezone: string;
68
51
  }
69
- /** Wire shape of one event file. */
70
52
  export type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;
71
53
  export interface EventPayloadInput {
72
54
  type: EventType;
@@ -94,38 +76,11 @@ export interface PeriodicEventInfo {
94
76
  timezone: string;
95
77
  nextRun: string | null;
96
78
  }
97
- /**
98
- * Single home for the scheduled-event file format (`events/*.json`, the
99
- * workspace scheduling bus). Every reader and writer — the EventsWatcher
100
- * scheduler and the agent `event` tool — must go
101
- * through this module: one schema, one payload union, one parser, one
102
- * builder. Per-type field rules (`at` for one-shot, `schedule` + `timezone`
103
- * for periodic) live here and nowhere else.
104
- */
105
- /** Typebox union for the `type` field, shared by the file schema and the event tool's parameters. */
106
79
  export declare const EventTypeSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"immediate">, import("@sinclair/typebox").TLiteral<"one-shot">, import("@sinclair/typebox").TLiteral<"periodic">]>;
107
- /** True for a complete ISO 8601 timestamp that carries an explicit UTC offset. */
108
- /**
109
- * Validate an untrusted event filename: a bare `*.json` basename with no
110
- * path traversal. Every surface that touches the events bus by filename
111
- * (the event tool's store, the admin portal's file endpoints) validates
112
- * through this single rule.
113
- */
114
80
  export declare function validateEventFilename(filename: string): string;
115
- /**
116
- * Parse and validate one event file's content into the canonical payload.
117
- * `filename` appears in error messages. Throws on malformed JSON, wrong
118
- * field types, and missing required fields (common and per-type).
119
- */
120
81
  export declare function parseEventPayload(content: string, filename: string): EventFilePayload;
121
- /**
122
- * Validate and assemble a new event payload for writing. Owns the per-type
123
- * field rules; write-side *policy* beyond the format (e.g. the event tool's
124
- * requirement that `at` lies in the future) stays with the writer.
125
- */
126
82
  export declare function buildEventPayload(input: EventPayloadInput): EventFilePayload;
127
83
  import type { Office, Workspace } from "../office/index.js";
128
- /** Host-only per-office events directory: `<office state dir>/events`. */
129
84
  export declare function officeEventsDir(office: Office): string;
130
85
  export declare class OfficeEventStore implements EventStore {
131
86
  private readonly office;
@@ -161,12 +116,6 @@ export interface LegacyEventMigrationReport {
161
116
  reason: string;
162
117
  }[];
163
118
  }
164
- /**
165
- * One-time move of legacy `<workspace>/events/*.json` records into the owning
166
- * office's host-only state. Only records with an explicit platform matching a
167
- * registered office move; everything else stays for an operator to inspect.
168
- * Run with the daemon stopped.
169
- */
170
119
  export declare function migrateLegacyWorkspaceEvents(workspace: Workspace): LegacyEventMigrationReport;
171
120
  export {};
172
121
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"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"}
@@ -1,24 +1,10 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import { parseJsonSchemaValue } from "../file-guards.js";
3
- /**
4
- * Single home for the scheduled-event file format (`events/*.json`, the
5
- * workspace scheduling bus). Every reader and writer — the EventsWatcher
6
- * scheduler and the agent `event` tool — must go
7
- * through this module: one schema, one payload union, one parser, one
8
- * builder. Per-type field rules (`at` for one-shot, `schedule` + `timezone`
9
- * for periodic) live here and nowhere else.
10
- */
11
- /** Typebox union for the `type` field, shared by the file schema and the event tool's parameters. */
12
3
  export const EventTypeSchema = Type.Union([
13
4
  Type.Literal("immediate"),
14
5
  Type.Literal("one-shot"),
15
6
  Type.Literal("periodic"),
16
7
  ]);
17
- /**
18
- * Lenient file-reading schema: every field optional so shape problems surface
19
- * as the specific missing-field messages below rather than typebox noise.
20
- * `channelId` is the legacy alias for `conversationId`.
21
- */
22
8
  const EventFileSchema = Type.Object({
23
9
  type: Type.Optional(EventTypeSchema),
24
10
  platform: Type.Optional(Type.String()),
@@ -39,13 +25,6 @@ function daysInMonth(year, month) {
39
25
  }
40
26
  return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;
41
27
  }
42
- /** True for a complete ISO 8601 timestamp that carries an explicit UTC offset. */
43
- /**
44
- * Validate an untrusted event filename: a bare `*.json` basename with no
45
- * path traversal. Every surface that touches the events bus by filename
46
- * (the event tool's store, the admin portal's file endpoints) validates
47
- * through this single rule.
48
- */
49
28
  export function validateEventFilename(filename) {
50
29
  const trimmed = filename.trim();
51
30
  if (!trimmed ||
@@ -85,17 +64,10 @@ function isValidIsoTimestampWithOffset(value) {
85
64
  offsetMinute <= 59 &&
86
65
  Number.isFinite(Date.parse(value)));
87
66
  }
88
- /**
89
- * Parse and validate one event file's content into the canonical payload.
90
- * `filename` appears in error messages. Throws on malformed JSON, wrong
91
- * field types, and missing required fields (common and per-type).
92
- */
93
67
  export function parseEventPayload(content, filename) {
94
68
  const data = parseJsonSchemaValue(content, EventFileSchema, (detail) => detail === "unexpected JSON shape"
95
69
  ? `Expected top-level JSON object in ${filename}`
96
70
  : `Malformed event file ${filename}: ${detail}`);
97
- // `channelId` is the legacy alias; parsed payloads expose only the
98
- // canonical `conversationId` field.
99
71
  const conversationId = typeof data.conversationId === "string"
100
72
  ? data.conversationId
101
73
  : typeof data.channelId === "string"
@@ -133,11 +105,6 @@ export function parseEventPayload(content, filename) {
133
105
  return { type, ...base, schedule: data.schedule, timezone: data.timezone };
134
106
  }
135
107
  }
136
- /**
137
- * Validate and assemble a new event payload for writing. Owns the per-type
138
- * field rules; write-side *policy* beyond the format (e.g. the event tool's
139
- * requirement that `at` lies in the future) stays with the writer.
140
- */
141
108
  export function buildEventPayload(input) {
142
109
  const base = {
143
110
  ...(input.platform !== undefined ? { platform: input.platform } : {}),
@@ -173,7 +140,6 @@ import { mkdir, readdir, readFile, rm, stat } from "node:fs/promises";
173
140
  import { join } from "node:path";
174
141
  import { atomicWritePrivateFile } from "../file-guards.js";
175
142
  import { createOfficeAddress, listRegisteredOffices, officeKey } from "../office/index.js";
176
- /** Host-only per-office events directory: `<office state dir>/events`. */
177
143
  export function officeEventsDir(office) {
178
144
  return join(office.stateDir, "events");
179
145
  }
@@ -250,7 +216,6 @@ export class OfficeEventStore {
250
216
  if (!existsSync(filePath)) {
251
217
  throw new Error(`Event ${safeFilename} not found in the current office`);
252
218
  }
253
- // Cancel before removing so no timer can fire for a record being deleted.
254
219
  this.scheduler?.cancelRecord(this.address, safeFilename);
255
220
  await rm(filePath, { force: true });
256
221
  return { deleted: true };
@@ -275,12 +240,6 @@ export class OfficeEventStore {
275
240
  return { path: filePath, size: fileStat.size };
276
241
  }
277
242
  }
278
- /**
279
- * One-time move of legacy `<workspace>/events/*.json` records into the owning
280
- * office's host-only state. Only records with an explicit platform matching a
281
- * registered office move; everything else stays for an operator to inspect.
282
- * Run with the daemon stopped.
283
- */
284
243
  export function migrateLegacyWorkspaceEvents(workspace) {
285
244
  const report = { migrated: [], skipped: [] };
286
245
  const legacyDir = join(workspace.root, "events");
@@ -330,7 +289,6 @@ export function migrateLegacyWorkspaceEvents(workspace) {
330
289
  report.skipped.push({ filename, reason: `already exists in ${key}` });
331
290
  continue;
332
291
  }
333
- // Rewrite instead of rename so the record gets host-private permissions.
334
292
  atomicWritePrivateFile(target, JSON.stringify(payload) + "\n");
335
293
  rmSync(source);
336
294
  report.migrated.push({ filename, key });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OfficeAddress, OfficeKey } from \"../types.js\";\n\nexport type EventPayload = EventFilePayload;\n\nexport interface EventRecord {\n filename: string;\n payload: EventFilePayload;\n size: number;\n mtimeMs: number;\n}\n\n/**\n * One office's admitted scheduled work. Every method is confined to that\n * office: filenames of other offices read as \"not found\", and payloads must\n * address the store's own office.\n */\nexport interface EventStore {\n readonly address: OfficeAddress;\n /** Create a new record; an existing filename is an error, never overwritten. */\n create(filename: string, payload: EventFilePayload): Promise<{ path: string; size: number }>;\n /**\n * List this office's records. Entries whose JSON cannot be parsed or fail\n * format validation are kept with a `null` payload so operators can still\n * surface and delete them; files that disappear mid-listing are skipped.\n */\n list(): Promise<Array<Omit<EventRecord, \"payload\"> & { payload: EventFilePayload | null }>>;\n read(filename: string): Promise<EventRecord>;\n update(filename: string, payload: EventFilePayload): Promise<{ path: string; size: number }>;\n delete(filename: string): Promise<{ deleted: boolean }>;\n}\n\n/** Scheduler hooks the store calls after each admitted mutation. */\nexport interface EventScheduleSink {\n scheduleRecord(address: OfficeAddress, record: EventRecord): void;\n cancelRecord(address: OfficeAddress, filename: string): void;\n}\n\nexport type EventConversationKind = \"direct\" | \"shared\";\n\nexport type EventType = \"immediate\" | \"one-shot\" | \"periodic\";\n\ninterface EventPayloadBase {\n /** Target platform; may be omitted when only one platform is running. */\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n /** Self-contained task text; event runs do not inherit conversation history. */\n text: string;\n}\n\nexport interface ImmediateEventPayload extends EventPayloadBase {\n type: \"immediate\";\n}\n\nexport interface OneShotEventPayload extends EventPayloadBase {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n}\n\nexport interface PeriodicEventPayload extends EventPayloadBase {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n}\n\n/** Wire shape of one event file. */\nexport type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;\n\nexport interface EventPayloadInput {\n type: EventType;\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n// Resolved runtime shapes: the watcher fills in the platform default and\n// infers the conversation kind before an event reaches a bot.\ninterface ResolvedEventFields {\n platform: string;\n conversationKind: EventConversationKind;\n}\n\nexport type MikanEvent =\n | (ImmediateEventPayload & ResolvedEventFields)\n | (OneShotEventPayload & ResolvedEventFields)\n | (PeriodicEventPayload & ResolvedEventFields);\n\nexport interface PeriodicEventInfo {\n filename: string;\n platform: string;\n conversationId: string;\n conversationKind: EventConversationKind;\n text: string;\n schedule: string;\n timezone: string;\n nextRun: string | null;\n}\n\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { parseJsonSchemaValue } from \"../file-guards.js\";\n\n/**\n * Single home for the scheduled-event file format (`events/*.json`, the\n * workspace scheduling bus). Every reader and writer — the EventsWatcher\n * scheduler and the agent `event` tool — must go\n * through this module: one schema, one payload union, one parser, one\n * builder. Per-type field rules (`at` for one-shot, `schedule` + `timezone`\n * for periodic) live here and nowhere else.\n */\n\n/** Typebox union for the `type` field, shared by the file schema and the event tool's parameters. */\nexport const EventTypeSchema = Type.Union([\n Type.Literal(\"immediate\"),\n Type.Literal(\"one-shot\"),\n Type.Literal(\"periodic\"),\n]);\n\n/**\n * Lenient file-reading schema: every field optional so shape problems surface\n * as the specific missing-field messages below rather than typebox noise.\n * `channelId` is the legacy alias for `conversationId`.\n */\nconst EventFileSchema = Type.Object({\n type: Type.Optional(EventTypeSchema),\n platform: Type.Optional(Type.String()),\n conversationId: Type.Optional(Type.String()),\n channelId: Type.Optional(Type.String()),\n conversationKind: Type.Optional(Type.Union([Type.Literal(\"direct\"), Type.Literal(\"shared\")])),\n userId: Type.Optional(Type.String()),\n text: Type.Optional(Type.String()),\n at: Type.Optional(Type.String()),\n schedule: Type.Optional(Type.String()),\n timezone: Type.Optional(Type.String()),\n});\n\ntype EventFileData = Static<typeof EventFileSchema>;\n\nconst ISO_TIMESTAMP_WITH_OFFSET =\n /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?(Z|[+-](\\d{2}):(\\d{2}))$/;\n\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return leapYear ? 29 : 28;\n }\n return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;\n}\n\n/** True for a complete ISO 8601 timestamp that carries an explicit UTC offset. */\n/**\n * Validate an untrusted event filename: a bare `*.json` basename with no\n * path traversal. Every surface that touches the events bus by filename\n * (the event tool's store, the admin portal's file endpoints) validates\n * through this single rule.\n */\nexport function validateEventFilename(filename: string): string {\n const trimmed = filename.trim();\n if (\n !trimmed ||\n trimmed.includes(\"/\") ||\n trimmed.includes(\"\\\\\") ||\n trimmed.includes(\"..\") ||\n !trimmed.endsWith(\".json\")\n ) {\n throw new Error(\"Invalid event filename\");\n }\n return trimmed;\n}\n\nfunction isValidIsoTimestampWithOffset(value: string): boolean {\n const match = ISO_TIMESTAMP_WITH_OFFSET.exec(value);\n if (!match) return false;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = match[6] === undefined ? 0 : Number(match[6]);\n const offsetHour = match[8] === undefined ? 0 : Number(match[8]);\n const offsetMinute = match[9] === undefined ? 0 : Number(match[9]);\n\n return (\n month >= 1 &&\n month <= 12 &&\n day >= 1 &&\n day <= daysInMonth(year, month) &&\n hour >= 0 &&\n hour <= 23 &&\n minute >= 0 &&\n minute <= 59 &&\n second >= 0 &&\n second <= 59 &&\n offsetHour >= 0 &&\n offsetHour <= 23 &&\n offsetMinute >= 0 &&\n offsetMinute <= 59 &&\n Number.isFinite(Date.parse(value))\n );\n}\n\n/**\n * Parse and validate one event file's content into the canonical payload.\n * `filename` appears in error messages. Throws on malformed JSON, wrong\n * field types, and missing required fields (common and per-type).\n */\nexport function parseEventPayload(content: string, filename: string): EventFilePayload {\n const data: EventFileData = parseJsonSchemaValue(content, EventFileSchema, (detail) =>\n detail === \"unexpected JSON shape\"\n ? `Expected top-level JSON object in ${filename}`\n : `Malformed event file ${filename}: ${detail}`,\n );\n // `channelId` is the legacy alias; parsed payloads expose only the\n // canonical `conversationId` field.\n const conversationId =\n typeof data.conversationId === \"string\"\n ? data.conversationId\n : typeof data.channelId === \"string\"\n ? data.channelId\n : undefined;\n const { type, text } = data;\n\n if (!type || !conversationId || !text) {\n throw new Error(`Missing required fields (type, conversationId, text) in ${filename}`);\n }\n\n const base = {\n ...(data.platform !== undefined ? { platform: data.platform } : {}),\n conversationId,\n ...(data.conversationKind !== undefined ? { conversationKind: data.conversationKind } : {}),\n ...(data.userId !== undefined ? { userId: data.userId } : {}),\n text,\n };\n\n switch (type) {\n case \"immediate\":\n return { type, ...base };\n\n case \"one-shot\":\n if (typeof data.at !== \"string\" || data.at.length === 0) {\n throw new Error(`Missing 'at' field for one-shot event in ${filename}`);\n }\n if (!isValidIsoTimestampWithOffset(data.at)) {\n throw new Error(\n `Invalid 'at' field for one-shot event in ${filename}: expected a valid ISO 8601 timestamp with UTC offset`,\n );\n }\n return { type, ...base, at: data.at };\n\n case \"periodic\":\n if (typeof data.schedule !== \"string\" || data.schedule.length === 0) {\n throw new Error(`Missing 'schedule' field for periodic event in ${filename}`);\n }\n if (typeof data.timezone !== \"string\" || data.timezone.length === 0) {\n throw new Error(`Missing 'timezone' field for periodic event in ${filename}`);\n }\n return { type, ...base, schedule: data.schedule, timezone: data.timezone };\n }\n}\n\n/**\n * Validate and assemble a new event payload for writing. Owns the per-type\n * field rules; write-side *policy* beyond the format (e.g. the event tool's\n * requirement that `at` lies in the future) stays with the writer.\n */\nexport function buildEventPayload(input: EventPayloadInput): EventFilePayload {\n const base = {\n ...(input.platform !== undefined ? { platform: input.platform } : {}),\n conversationId: input.conversationId,\n ...(input.conversationKind !== undefined ? { conversationKind: input.conversationKind } : {}),\n ...(input.userId !== undefined ? { userId: input.userId } : {}),\n text: input.text,\n };\n\n switch (input.type) {\n case \"immediate\":\n return { type: \"immediate\", ...base };\n\n case \"one-shot\": {\n if (!input.at) {\n throw new Error(\"`at` is required for one-shot events\");\n }\n if (!isValidIsoTimestampWithOffset(input.at)) {\n throw new Error(\"`at` must be a valid ISO 8601 timestamp with UTC offset\");\n }\n return { type: \"one-shot\", ...base, at: input.at };\n }\n\n case \"periodic\":\n if (!input.schedule) {\n throw new Error(\"`schedule` is required for periodic events\");\n }\n if (!input.timezone) {\n throw new Error(\"`timezone` is required for periodic events\");\n }\n return { type: \"periodic\", ...base, schedule: input.schedule, timezone: input.timezone };\n }\n}\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { atomicWritePrivateFile } from \"../file-guards.js\";\nimport type { Office, Workspace } from \"../office/index.js\";\nimport { createOfficeAddress, listRegisteredOffices, officeKey } from \"../office/index.js\";\n\n/** Host-only per-office events directory: `<office state dir>/events`. */\nexport function officeEventsDir(office: Office): string {\n return join(office.stateDir, \"events\");\n}\n\nexport class OfficeEventStore implements EventStore {\n readonly address: OfficeAddress;\n private readonly eventsDir: string;\n\n constructor(\n private readonly office: Office,\n private readonly scheduler?: EventScheduleSink,\n ) {\n this.address = office.address;\n this.eventsDir = officeEventsDir(office);\n }\n\n async create(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n const safeFilename = validateEventFilename(filename);\n this.assertOwnPayload(payload);\n const filePath = join(this.eventsDir, safeFilename);\n if (existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} already exists`);\n }\n return this.writeRecord(safeFilename, payload);\n }\n\n async list(): Promise<Array<Omit<EventRecord, \"payload\"> & { payload: EventPayload | null }>> {\n if (!existsSync(this.eventsDir)) return [];\n const entries = await readdir(this.eventsDir, { withFileTypes: true });\n const events = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".json\"))\n .map(async (entry) => {\n try {\n return await this.read(entry.name);\n } catch {\n try {\n const fileStat = await stat(join(this.eventsDir, entry.name));\n return {\n filename: entry.name,\n payload: null,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n } catch {\n return null;\n }\n }\n }),\n );\n return events\n .filter((event) => event !== null)\n .toSorted((a, b) => a.filename.localeCompare(b.filename));\n }\n\n async read(filename: string): Promise<EventRecord> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (!existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n const [raw, fileStat] = await Promise.all([readFile(filePath, \"utf-8\"), stat(filePath)]);\n return {\n filename: safeFilename,\n payload: parseEventPayload(raw, safeFilename),\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n }\n\n async update(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n const safeFilename = validateEventFilename(filename);\n this.assertOwnPayload(payload);\n if (!existsSync(join(this.eventsDir, safeFilename))) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n return this.writeRecord(safeFilename, payload);\n }\n\n async delete(filename: string): Promise<{ deleted: boolean }> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (!existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n // Cancel before removing so no timer can fire for a record being deleted.\n this.scheduler?.cancelRecord(this.address, safeFilename);\n await rm(filePath, { force: true });\n return { deleted: true };\n }\n\n private assertOwnPayload(payload: EventPayload): void {\n if (\n payload.platform !== this.address.platform ||\n payload.conversationId !== this.address.conversationId\n ) {\n throw new Error(\"Event payload must address the current office\");\n }\n }\n\n private async writeRecord(\n safeFilename: string,\n payload: EventPayload,\n ): Promise<{ path: string; size: number }> {\n await mkdir(this.eventsDir, { recursive: true });\n const filePath = join(this.eventsDir, safeFilename);\n atomicWritePrivateFile(filePath, JSON.stringify(payload) + \"\\n\");\n const fileStat = await stat(filePath);\n this.scheduler?.scheduleRecord(this.address, {\n filename: safeFilename,\n payload,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n });\n return { path: filePath, size: fileStat.size };\n }\n}\n\nexport interface LegacyEventMigrationReport {\n migrated: { filename: string; key: OfficeKey }[];\n skipped: { filename: string; reason: string }[];\n}\n\n/**\n * One-time move of legacy `<workspace>/events/*.json` records into the owning\n * office's host-only state. Only records with an explicit platform matching a\n * registered office move; everything else stays for an operator to inspect.\n * Run with the daemon stopped.\n */\nexport function migrateLegacyWorkspaceEvents(workspace: Workspace): LegacyEventMigrationReport {\n const report: LegacyEventMigrationReport = { migrated: [], skipped: [] };\n const legacyDir = join(workspace.root, \"events\");\n if (!existsSync(legacyDir)) return report;\n const registered = new Set(\n listRegisteredOffices(workspace.stateDir).map((record) => officeKey(record)),\n );\n for (const filename of readdirSync(legacyDir).filter((name) => name.endsWith(\".json\"))) {\n const source = join(legacyDir, filename);\n if (!statSync(source).isFile()) continue;\n let payload: EventFilePayload;\n try {\n payload = parseEventPayload(readFileSync(source, \"utf-8\"), filename);\n } catch (error) {\n report.skipped.push({\n filename,\n reason: error instanceof Error ? error.message : String(error),\n });\n continue;\n }\n if (!payload.platform) {\n report.skipped.push({ filename, reason: \"no platform; owner cannot be attributed\" });\n continue;\n }\n let address: OfficeAddress;\n try {\n address = createOfficeAddress(\n payload.platform as OfficeAddress[\"platform\"],\n payload.conversationId,\n );\n } catch (error) {\n report.skipped.push({\n filename,\n reason: error instanceof Error ? error.message : String(error),\n });\n continue;\n }\n const key = officeKey(address);\n if (!registered.has(key)) {\n report.skipped.push({ filename, reason: `office ${key} is not registered` });\n continue;\n }\n const office = workspace.office(address);\n const targetDir = officeEventsDir(office);\n mkdirSync(targetDir, { recursive: true });\n const target = join(targetDir, filename);\n if (existsSync(target)) {\n report.skipped.push({ filename, reason: `already exists in ${key}` });\n continue;\n }\n // Rewrite instead of rename so the record gets host-private permissions.\n atomicWritePrivateFile(target, JSON.stringify(payload) + \"\\n\");\n rmSync(source);\n report.migrated.push({ filename, key });\n }\n return report;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAuFA,OAAO,EAAe,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC;IACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;IACzB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;IACpC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5C,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACvC,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC7F,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAClC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;CACvC,CAAC,CAAC;AAIH,MAAM,yBAAyB,GAC7B,yFAAyF,CAAC;AAE5F,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa;IAC9C,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC;QAC1E,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,IACE,CAAC,OAAO;QACR,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC1B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAa;IAClD,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnE,OAAO,CACL,KAAK,IAAI,CAAC;QACV,KAAK,IAAI,EAAE;QACX,GAAG,IAAI,CAAC;QACR,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC;QAC/B,IAAI,IAAI,CAAC;QACT,IAAI,IAAI,EAAE;QACV,MAAM,IAAI,CAAC;QACX,MAAM,IAAI,EAAE;QACZ,MAAM,IAAI,CAAC;QACX,MAAM,IAAI,EAAE;QACZ,UAAU,IAAI,CAAC;QACf,UAAU,IAAI,EAAE;QAChB,YAAY,IAAI,CAAC;QACjB,YAAY,IAAI,EAAE;QAClB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,QAAgB;IACjE,MAAM,IAAI,GAAkB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,MAAM,EAAE,EAAE,CACpF,MAAM,KAAK,uBAAuB;QAChC,CAAC,CAAC,qCAAqC,QAAQ,EAAE;QACjD,CAAC,CAAC,wBAAwB,QAAQ,KAAK,MAAM,EAAE,CAClD,CAAC;IACF,MAAM,cAAc,GAClB,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;QACrC,CAAC,CAAC,IAAI,CAAC,cAAc;QACrB,CAAC,CAAC,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;YAClC,CAAC,CAAC,IAAI,CAAC,SAAS;YAChB,CAAC,CAAC,SAAS,CAAC;IAClB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IAE5B,IAAI,CAAC,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,2DAA2D,QAAQ,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,cAAc;QACd,GAAG,CAAC,IAAI,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAI;KACL,CAAC;IAEF,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW;YACd,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QAE3B,KAAK,UAAU;YACb,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;YAC1E,CAAC;YACD,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CACb,4CAA4C,QAAQ,uDAAuD,CAC5G,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;QAExC,KAAK,UAAU;YACb,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpE,MAAM,IAAI,KAAK,CAAC,kDAAkD,QAAQ,EAAE,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpE,MAAM,IAAI,KAAK,CAAC,kDAAkD,QAAQ,EAAE,CAAC,CAAC;YAChF,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC/E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAwB;IACxD,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;IAEF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC;QAExC,KAAK,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YACD,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC7E,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACrD,CAAC;QAED,KAAK,UAAU;YACb,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC7F,CAAC;AACH,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE3F,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,OAAO,gBAAgB;IAI3B,YACmB,MAAc,EACd,SAA6B;sBAD7B,MAAM;yBACN,SAAS;QAE1B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,OAAqB;QAClD,MAAM,YAAY,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,iBAAiB,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,OAAO,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,OAAO;aACJ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aACjE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACnB,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC9D,OAAO;wBACL,QAAQ,EAAE,KAAK,CAAC,IAAI;wBACpB,OAAO,EAAE,IAAI;wBACb,IAAI,EAAE,QAAQ,CAAC,IAAI;wBACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;qBAC1B,CAAC;gBACJ,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CACL,CAAC;QACF,OAAO,MAAM;aACV,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC;aACjC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAgB;QACzB,MAAM,YAAY,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,kCAAkC,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACzF,OAAO;YACL,QAAQ,EAAE,YAAY;YACtB,OAAO,EAAE,iBAAiB,CAAC,GAAG,EAAE,YAAY,CAAC;YAC7C,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;SAC1B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,OAAqB;QAClD,MAAM,YAAY,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,kCAAkC,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,MAAM,YAAY,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,kCAAkC,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAEO,gBAAgB,CAAC,OAAqB;QAC5C,IACE,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ;YAC1C,OAAO,CAAC,cAAc,KAAK,IAAI,CAAC,OAAO,CAAC,cAAc,EACtD,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CACvB,YAAoB,EACpB,OAAqB;QAErB,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpD,sBAAsB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE;YAC3C,QAAQ,EAAE,YAAY;YACtB,OAAO;YACP,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;SAC1B,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjD,CAAC;CACF;AAOD,MAAM,UAAU,4BAA4B,CAAC,SAAoB;IAC/D,MAAM,MAAM,GAA+B,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,qBAAqB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAC7E,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACvF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE;YAAE,SAAS;QACzC,IAAI,OAAyB,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClB,QAAQ;gBACR,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC/D,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QACD,IAAI,OAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,GAAG,mBAAmB,CAC3B,OAAO,CAAC,QAAqC,EAC7C,OAAO,CAAC,cAAc,CACvB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClB,QAAQ;gBACR,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC/D,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,oBAAoB,EAAE,CAAC,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAC1C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,qBAAqB,GAAG,EAAE,EAAE,CAAC,CAAC;YACtE,SAAS;QACX,CAAC;QACD,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,CAAC;QACf,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type { OfficeAddress, OfficeKey } from \"../types.js\";\n\nexport type EventPayload = EventFilePayload;\n\nexport interface EventRecord {\n filename: string;\n payload: EventFilePayload;\n size: number;\n mtimeMs: number;\n}\n\nexport interface EventStore {\n readonly address: OfficeAddress;\n create(filename: string, payload: EventFilePayload): Promise<{ path: string; size: number }>;\n list(): Promise<Array<Omit<EventRecord, \"payload\"> & { payload: EventFilePayload | null }>>;\n read(filename: string): Promise<EventRecord>;\n update(filename: string, payload: EventFilePayload): Promise<{ path: string; size: number }>;\n delete(filename: string): Promise<{ deleted: boolean }>;\n}\n\nexport interface EventScheduleSink {\n scheduleRecord(address: OfficeAddress, record: EventRecord): void;\n cancelRecord(address: OfficeAddress, filename: string): void;\n}\n\nexport type EventConversationKind = \"direct\" | \"shared\";\n\nexport type EventType = \"immediate\" | \"one-shot\" | \"periodic\";\n\ninterface EventPayloadBase {\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n}\n\nexport interface ImmediateEventPayload extends EventPayloadBase {\n type: \"immediate\";\n}\n\nexport interface OneShotEventPayload extends EventPayloadBase {\n type: \"one-shot\";\n at: string;\n}\n\nexport interface PeriodicEventPayload extends EventPayloadBase {\n type: \"periodic\";\n schedule: string;\n timezone: string;\n}\n\nexport type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;\n\nexport interface EventPayloadInput {\n type: EventType;\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\ninterface ResolvedEventFields {\n platform: string;\n conversationKind: EventConversationKind;\n}\n\nexport type MikanEvent =\n | (ImmediateEventPayload & ResolvedEventFields)\n | (OneShotEventPayload & ResolvedEventFields)\n | (PeriodicEventPayload & ResolvedEventFields);\n\nexport interface PeriodicEventInfo {\n filename: string;\n platform: string;\n conversationId: string;\n conversationKind: EventConversationKind;\n text: string;\n schedule: string;\n timezone: string;\n nextRun: string | null;\n}\n\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { parseJsonSchemaValue } from \"../file-guards.js\";\n\nexport const EventTypeSchema = Type.Union([\n Type.Literal(\"immediate\"),\n Type.Literal(\"one-shot\"),\n Type.Literal(\"periodic\"),\n]);\n\nconst EventFileSchema = Type.Object({\n type: Type.Optional(EventTypeSchema),\n platform: Type.Optional(Type.String()),\n conversationId: Type.Optional(Type.String()),\n channelId: Type.Optional(Type.String()),\n conversationKind: Type.Optional(Type.Union([Type.Literal(\"direct\"), Type.Literal(\"shared\")])),\n userId: Type.Optional(Type.String()),\n text: Type.Optional(Type.String()),\n at: Type.Optional(Type.String()),\n schedule: Type.Optional(Type.String()),\n timezone: Type.Optional(Type.String()),\n});\n\ntype EventFileData = Static<typeof EventFileSchema>;\n\nconst ISO_TIMESTAMP_WITH_OFFSET =\n /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?(Z|[+-](\\d{2}):(\\d{2}))$/;\n\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return leapYear ? 29 : 28;\n }\n return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;\n}\n\nexport function validateEventFilename(filename: string): string {\n const trimmed = filename.trim();\n if (\n !trimmed ||\n trimmed.includes(\"/\") ||\n trimmed.includes(\"\\\\\") ||\n trimmed.includes(\"..\") ||\n !trimmed.endsWith(\".json\")\n ) {\n throw new Error(\"Invalid event filename\");\n }\n return trimmed;\n}\n\nfunction isValidIsoTimestampWithOffset(value: string): boolean {\n const match = ISO_TIMESTAMP_WITH_OFFSET.exec(value);\n if (!match) return false;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = match[6] === undefined ? 0 : Number(match[6]);\n const offsetHour = match[8] === undefined ? 0 : Number(match[8]);\n const offsetMinute = match[9] === undefined ? 0 : Number(match[9]);\n\n return (\n month >= 1 &&\n month <= 12 &&\n day >= 1 &&\n day <= daysInMonth(year, month) &&\n hour >= 0 &&\n hour <= 23 &&\n minute >= 0 &&\n minute <= 59 &&\n second >= 0 &&\n second <= 59 &&\n offsetHour >= 0 &&\n offsetHour <= 23 &&\n offsetMinute >= 0 &&\n offsetMinute <= 59 &&\n Number.isFinite(Date.parse(value))\n );\n}\n\nexport function parseEventPayload(content: string, filename: string): EventFilePayload {\n const data: EventFileData = parseJsonSchemaValue(content, EventFileSchema, (detail) =>\n detail === \"unexpected JSON shape\"\n ? `Expected top-level JSON object in ${filename}`\n : `Malformed event file ${filename}: ${detail}`,\n );\n const conversationId =\n typeof data.conversationId === \"string\"\n ? data.conversationId\n : typeof data.channelId === \"string\"\n ? data.channelId\n : undefined;\n const { type, text } = data;\n\n if (!type || !conversationId || !text) {\n throw new Error(`Missing required fields (type, conversationId, text) in ${filename}`);\n }\n\n const base = {\n ...(data.platform !== undefined ? { platform: data.platform } : {}),\n conversationId,\n ...(data.conversationKind !== undefined ? { conversationKind: data.conversationKind } : {}),\n ...(data.userId !== undefined ? { userId: data.userId } : {}),\n text,\n };\n\n switch (type) {\n case \"immediate\":\n return { type, ...base };\n\n case \"one-shot\":\n if (typeof data.at !== \"string\" || data.at.length === 0) {\n throw new Error(`Missing 'at' field for one-shot event in ${filename}`);\n }\n if (!isValidIsoTimestampWithOffset(data.at)) {\n throw new Error(\n `Invalid 'at' field for one-shot event in ${filename}: expected a valid ISO 8601 timestamp with UTC offset`,\n );\n }\n return { type, ...base, at: data.at };\n\n case \"periodic\":\n if (typeof data.schedule !== \"string\" || data.schedule.length === 0) {\n throw new Error(`Missing 'schedule' field for periodic event in ${filename}`);\n }\n if (typeof data.timezone !== \"string\" || data.timezone.length === 0) {\n throw new Error(`Missing 'timezone' field for periodic event in ${filename}`);\n }\n return { type, ...base, schedule: data.schedule, timezone: data.timezone };\n }\n}\n\nexport function buildEventPayload(input: EventPayloadInput): EventFilePayload {\n const base = {\n ...(input.platform !== undefined ? { platform: input.platform } : {}),\n conversationId: input.conversationId,\n ...(input.conversationKind !== undefined ? { conversationKind: input.conversationKind } : {}),\n ...(input.userId !== undefined ? { userId: input.userId } : {}),\n text: input.text,\n };\n\n switch (input.type) {\n case \"immediate\":\n return { type: \"immediate\", ...base };\n\n case \"one-shot\": {\n if (!input.at) {\n throw new Error(\"`at` is required for one-shot events\");\n }\n if (!isValidIsoTimestampWithOffset(input.at)) {\n throw new Error(\"`at` must be a valid ISO 8601 timestamp with UTC offset\");\n }\n return { type: \"one-shot\", ...base, at: input.at };\n }\n\n case \"periodic\":\n if (!input.schedule) {\n throw new Error(\"`schedule` is required for periodic events\");\n }\n if (!input.timezone) {\n throw new Error(\"`timezone` is required for periodic events\");\n }\n return { type: \"periodic\", ...base, schedule: input.schedule, timezone: input.timezone };\n }\n}\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { atomicWritePrivateFile } from \"../file-guards.js\";\nimport type { Office, Workspace } from \"../office/index.js\";\nimport { createOfficeAddress, listRegisteredOffices, officeKey } from \"../office/index.js\";\n\nexport function officeEventsDir(office: Office): string {\n return join(office.stateDir, \"events\");\n}\n\nexport class OfficeEventStore implements EventStore {\n readonly address: OfficeAddress;\n private readonly eventsDir: string;\n\n constructor(\n private readonly office: Office,\n private readonly scheduler?: EventScheduleSink,\n ) {\n this.address = office.address;\n this.eventsDir = officeEventsDir(office);\n }\n\n async create(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n const safeFilename = validateEventFilename(filename);\n this.assertOwnPayload(payload);\n const filePath = join(this.eventsDir, safeFilename);\n if (existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} already exists`);\n }\n return this.writeRecord(safeFilename, payload);\n }\n\n async list(): Promise<Array<Omit<EventRecord, \"payload\"> & { payload: EventPayload | null }>> {\n if (!existsSync(this.eventsDir)) return [];\n const entries = await readdir(this.eventsDir, { withFileTypes: true });\n const events = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".json\"))\n .map(async (entry) => {\n try {\n return await this.read(entry.name);\n } catch {\n try {\n const fileStat = await stat(join(this.eventsDir, entry.name));\n return {\n filename: entry.name,\n payload: null,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n } catch {\n return null;\n }\n }\n }),\n );\n return events\n .filter((event) => event !== null)\n .toSorted((a, b) => a.filename.localeCompare(b.filename));\n }\n\n async read(filename: string): Promise<EventRecord> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (!existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n const [raw, fileStat] = await Promise.all([readFile(filePath, \"utf-8\"), stat(filePath)]);\n return {\n filename: safeFilename,\n payload: parseEventPayload(raw, safeFilename),\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n }\n\n async update(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n const safeFilename = validateEventFilename(filename);\n this.assertOwnPayload(payload);\n if (!existsSync(join(this.eventsDir, safeFilename))) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n return this.writeRecord(safeFilename, payload);\n }\n\n async delete(filename: string): Promise<{ deleted: boolean }> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (!existsSync(filePath)) {\n throw new Error(`Event ${safeFilename} not found in the current office`);\n }\n this.scheduler?.cancelRecord(this.address, safeFilename);\n await rm(filePath, { force: true });\n return { deleted: true };\n }\n\n private assertOwnPayload(payload: EventPayload): void {\n if (\n payload.platform !== this.address.platform ||\n payload.conversationId !== this.address.conversationId\n ) {\n throw new Error(\"Event payload must address the current office\");\n }\n }\n\n private async writeRecord(\n safeFilename: string,\n payload: EventPayload,\n ): Promise<{ path: string; size: number }> {\n await mkdir(this.eventsDir, { recursive: true });\n const filePath = join(this.eventsDir, safeFilename);\n atomicWritePrivateFile(filePath, JSON.stringify(payload) + \"\\n\");\n const fileStat = await stat(filePath);\n this.scheduler?.scheduleRecord(this.address, {\n filename: safeFilename,\n payload,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n });\n return { path: filePath, size: fileStat.size };\n }\n}\n\nexport interface LegacyEventMigrationReport {\n migrated: { filename: string; key: OfficeKey }[];\n skipped: { filename: string; reason: string }[];\n}\n\nexport function migrateLegacyWorkspaceEvents(workspace: Workspace): LegacyEventMigrationReport {\n const report: LegacyEventMigrationReport = { migrated: [], skipped: [] };\n const legacyDir = join(workspace.root, \"events\");\n if (!existsSync(legacyDir)) return report;\n const registered = new Set(\n listRegisteredOffices(workspace.stateDir).map((record) => officeKey(record)),\n );\n for (const filename of readdirSync(legacyDir).filter((name) => name.endsWith(\".json\"))) {\n const source = join(legacyDir, filename);\n if (!statSync(source).isFile()) continue;\n let payload: EventFilePayload;\n try {\n payload = parseEventPayload(readFileSync(source, \"utf-8\"), filename);\n } catch (error) {\n report.skipped.push({\n filename,\n reason: error instanceof Error ? error.message : String(error),\n });\n continue;\n }\n if (!payload.platform) {\n report.skipped.push({ filename, reason: \"no platform; owner cannot be attributed\" });\n continue;\n }\n let address: OfficeAddress;\n try {\n address = createOfficeAddress(\n payload.platform as OfficeAddress[\"platform\"],\n payload.conversationId,\n );\n } catch (error) {\n report.skipped.push({\n filename,\n reason: error instanceof Error ? error.message : String(error),\n });\n continue;\n }\n const key = officeKey(address);\n if (!registered.has(key)) {\n report.skipped.push({ filename, reason: `office ${key} is not registered` });\n continue;\n }\n const office = workspace.office(address);\n const targetDir = officeEventsDir(office);\n mkdirSync(targetDir, { recursive: true });\n const target = join(targetDir, filename);\n if (existsSync(target)) {\n report.skipped.push({ filename, reason: `already exists in ${key}` });\n continue;\n }\n atomicWritePrivateFile(target, JSON.stringify(payload) + \"\\n\");\n rmSync(source);\n report.migrated.push({ filename, key });\n }\n return report;\n}\n"]}
@@ -3,13 +3,6 @@ import { type Workspace } from "../office/index.js";
3
3
  import type { OfficeAddress } from "../types.js";
4
4
  import { type EventRecord, type EventScheduleSink, type MikanEvent, type PeriodicEventInfo } from "./index.js";
5
5
  export type { MikanEvent, PeriodicEventInfo } from "./index.js";
6
- /**
7
- * In-memory timer/cron owner for every office's admitted events. Records are
8
- * loaded once from each registered office's host-only events directory at
9
- * start; afterwards the only inputs are {@link OfficeEventStore} mutations
10
- * through {@link EventScheduleSink}. There is no filesystem watcher: files
11
- * edited by hand take effect on the next start.
12
- */
13
6
  export declare class EventScheduler implements EventScheduleSink {
14
7
  private readonly workspace;
15
8
  private readonly botsByPlatform;
@@ -19,7 +12,6 @@ export declare class EventScheduler implements EventScheduleSink {
19
12
  start(): void;
20
13
  stop(): void;
21
14
  scheduledCount(): number;
22
- /** Active periodic events of one office with their next run. */
23
15
  periodicEvents(address: OfficeAddress): PeriodicEventInfo[];
24
16
  scheduleRecord(address: OfficeAddress, record: EventRecord): void;
25
17
  cancelRecord(address: OfficeAddress, filename: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/events/scheduler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoB,YAAY,EAAgB,MAAM,aAAa,CAAC;AAEhF,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAUhE;;;;;;GAMG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IAKpD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IALjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,SAAS,CAAc;IAE/B,YACmB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC3D;IAEJ,KAAK,IAAI,IAAI,CAuBZ;IAED,IAAI,IAAI,IAAI,CAOX;IAED,cAAc,IAAI,MAAM,CAEvB;IAED,gEAAgE;IAChE,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,iBAAiB,EAAE,CAiB1D;IAED,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CA6ChE;IAED,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE3D;IAED,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,OAAO;IAcf,OAAO,CAAC,OAAO;IA0Bf,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,UAAU;CAUnB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAwB1D"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/events/scheduler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoB,YAAY,EAAgB,MAAM,aAAa,CAAC;AAEhF,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAUhE,qBAAa,cAAe,YAAW,iBAAiB;IAKpD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IALjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,SAAS,CAAc;IAE/B,YACmB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC3D;IAEJ,KAAK,IAAI,IAAI,CAuBZ;IAED,IAAI,IAAI,IAAI,CAOX;IAED,cAAc,IAAI,MAAM,CAEvB;IAED,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,iBAAiB,EAAE,CAiB1D;IAED,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CA6ChE;IAED,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE3D;IAED,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,OAAO;IAcf,OAAO,CAAC,OAAO;IA0Bf,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,UAAU;CAUnB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAwB1D"}
@@ -7,13 +7,6 @@ import { listRegisteredOffices, officeKey } from "../office/index.js";
7
7
  import { reportUserFacingError } from "../observability/index.js";
8
8
  import { inferConversationKind } from "../sessions/session-key.js";
9
9
  import { officeEventsDir, parseEventPayload, } from "./index.js";
10
- /**
11
- * In-memory timer/cron owner for every office's admitted events. Records are
12
- * loaded once from each registered office's host-only events directory at
13
- * start; afterwards the only inputs are {@link OfficeEventStore} mutations
14
- * through {@link EventScheduleSink}. There is no filesystem watcher: files
15
- * edited by hand take effect on the next start.
16
- */
17
10
  export class EventScheduler {
18
11
  constructor(workspace, botsByPlatform) {
19
12
  this.workspace = workspace;
@@ -56,7 +49,6 @@ export class EventScheduler {
56
49
  scheduledCount() {
57
50
  return this.scheduled.size;
58
51
  }
59
- /** Active periodic events of one office with their next run. */
60
52
  periodicEvents(address) {
61
53
  const prefix = `${officeKey(address)}/`;
62
54
  const results = [];
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/events/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Cron } from \"croner\";\nimport { existsSync, readdirSync, readFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createConversationEvent } from \"../adapters/index.js\";\nimport type { ConversationKind, MessagingBot, PlatformName } from \"../types.js\";\nimport * as log from \"../log.js\";\nimport { listRegisteredOffices, officeKey, type Workspace } from \"../office/index.js\";\nimport { reportUserFacingError } from \"../observability/index.js\";\nimport { inferConversationKind } from \"../sessions/session-key.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport {\n officeEventsDir,\n parseEventPayload,\n type EventRecord,\n type EventScheduleSink,\n type MikanEvent,\n type PeriodicEventInfo,\n} from \"./index.js\";\n\nexport type { MikanEvent, PeriodicEventInfo } from \"./index.js\";\n\ninterface Scheduled {\n address: OfficeAddress;\n filename: string;\n event: MikanEvent;\n timer?: NodeJS.Timeout;\n cron?: Cron;\n}\n\n/**\n * In-memory timer/cron owner for every office's admitted events. Records are\n * loaded once from each registered office's host-only events directory at\n * start; afterwards the only inputs are {@link OfficeEventStore} mutations\n * through {@link EventScheduleSink}. There is no filesystem watcher: files\n * edited by hand take effect on the next start.\n */\nexport class EventScheduler implements EventScheduleSink {\n private readonly scheduled = new Map<string, Scheduled>();\n private startTime = Date.now();\n\n constructor(\n private readonly workspace: Workspace,\n private readonly botsByPlatform: Record<string, MessagingBot>,\n ) {}\n\n start(): void {\n this.startTime = Date.now();\n let loaded = 0;\n for (const record of listRegisteredOffices(this.workspace.stateDir)) {\n const office = this.workspace.office(record);\n const dir = officeEventsDir(office);\n if (!existsSync(dir)) continue;\n for (const filename of readdirSync(dir).filter((name) => name.endsWith(\".json\"))) {\n const path = join(dir, filename);\n try {\n const payload = parseEventPayload(readFileSync(path, \"utf-8\"), filename);\n this.scheduleRecord(office.address, { filename, payload, size: 0, mtimeMs: 0 });\n loaded++;\n } catch (error) {\n log.logWarning(\n `Removing unparseable event file ${filename} for ${office.key}`,\n error instanceof Error ? error.message : String(error),\n );\n this.removeFile(office.address, filename);\n }\n }\n }\n log.logInfo(`Event scheduler started, tracking ${loaded} records`);\n }\n\n stop(): void {\n for (const entry of this.scheduled.values()) {\n if (entry.timer) clearTimeout(entry.timer);\n entry.cron?.stop();\n }\n this.scheduled.clear();\n log.logInfo(\"Event scheduler stopped\");\n }\n\n scheduledCount(): number {\n return this.scheduled.size;\n }\n\n /** Active periodic events of one office with their next run. */\n periodicEvents(address: OfficeAddress): PeriodicEventInfo[] {\n const prefix = `${officeKey(address)}/`;\n const results: PeriodicEventInfo[] = [];\n for (const [key, entry] of this.scheduled) {\n if (!key.startsWith(prefix) || entry.event.type !== \"periodic\" || !entry.cron) continue;\n results.push({\n filename: entry.filename,\n platform: entry.event.platform,\n conversationId: entry.event.conversationId,\n conversationKind: entry.event.conversationKind,\n text: entry.event.text,\n schedule: entry.event.schedule,\n timezone: entry.event.timezone,\n nextRun: entry.cron.nextRun()?.toISOString() ?? null,\n });\n }\n return results;\n }\n\n scheduleRecord(address: OfficeAddress, record: EventRecord): void {\n const key = this.key(address, record.filename);\n this.cancelKey(key);\n let event: MikanEvent;\n try {\n event = this.resolve(record, address);\n } catch (error) {\n log.logWarning(\n `Rejecting event ${record.filename}`,\n error instanceof Error ? error.message : String(error),\n );\n this.removeFile(address, record.filename);\n return;\n }\n const entry: Scheduled = { address, filename: record.filename, event };\n switch (event.type) {\n case \"immediate\":\n this.execute(entry);\n return;\n case \"one-shot\": {\n const delay = new Date(event.at).getTime() - Date.now();\n if (delay <= 0) {\n log.logInfo(`One-shot event in the past, deleting: ${record.filename}`);\n this.removeFile(address, record.filename);\n return;\n }\n entry.timer = setTimeout(() => {\n this.scheduled.delete(key);\n this.execute(entry);\n }, delay);\n this.scheduled.set(key, entry);\n return;\n }\n case \"periodic\":\n try {\n entry.cron = new Cron(event.schedule, { timezone: event.timezone }, () =>\n this.execute(entry, false),\n );\n } catch (error) {\n log.logWarning(`Invalid cron schedule for ${record.filename}`, String(error));\n this.removeFile(address, record.filename);\n return;\n }\n this.scheduled.set(key, entry);\n }\n }\n\n cancelRecord(address: OfficeAddress, filename: string): void {\n this.cancelKey(this.key(address, filename));\n }\n\n private key(address: OfficeAddress, filename: string): string {\n return `${officeKey(address)}/${filename}`;\n }\n\n private cancelKey(key: string): void {\n const entry = this.scheduled.get(key);\n if (!entry) return;\n if (entry.timer) clearTimeout(entry.timer);\n entry.cron?.stop();\n this.scheduled.delete(key);\n }\n\n private resolve(record: EventRecord, address: OfficeAddress): MikanEvent {\n const { payload } = record;\n const platform = (payload.platform ?? address.platform).toLowerCase();\n if (platform !== address.platform || payload.conversationId !== address.conversationId) {\n throw new Error(\"event payload does not address its owning office\");\n }\n if (!this.botsByPlatform[platform]) {\n throw new Error(`no bot configured for platform '${platform}'`);\n }\n const conversationKind: ConversationKind =\n payload.conversationKind ?? inferConversationKind(platform, payload.conversationId);\n return { ...payload, platform, conversationKind };\n }\n\n private execute(entry: Scheduled, deleteAfter = true): void {\n const { event, filename, address } = entry;\n const bot = this.botsByPlatform[event.platform];\n if (!bot) {\n this.reportFailure(entry, deleteAfter, \"missing_bot\");\n if (deleteAfter) this.removeFile(address, filename);\n return;\n }\n const enqueued = bot.enqueueEvent(\n createConversationEvent({\n platform: event.platform as PlatformName,\n type: \"mention\",\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n user: event.userId ?? \"EVENT\",\n text: buildEventPrompt(event),\n ts: `event:${filename.replace(/\\.json$/i, \"\")}`,\n }),\n );\n if (!enqueued) {\n log.logWarning(`Event queue full, discarded: ${filename}`);\n this.reportFailure(entry, deleteAfter, \"queue_full\");\n }\n if (deleteAfter) this.removeFile(address, filename);\n }\n\n private reportFailure(\n entry: Scheduled,\n deleteAfter: boolean,\n failure: \"missing_bot\" | \"queue_full\",\n ): void {\n const reason = failure === \"missing_bot\" ? \"missing bot\" : \"queue full\";\n reportUserFacingError(new Error(`Scheduled event delivery failed: ${reason}`), {\n domain: \"events\",\n surface: \"event_delivery\",\n operation: \"event_execute\",\n severity: \"error\",\n platform: entry.event.platform,\n context: {\n failure,\n filename: entry.filename,\n eventType: entry.event.type,\n conversationId: entry.event.conversationId,\n conversationKind: entry.event.conversationKind,\n deleteAfter,\n triggeredByEventFile: true,\n textLength: entry.event.text.length,\n },\n });\n }\n\n private removeFile(address: OfficeAddress, filename: string): void {\n const path = join(officeEventsDir(this.workspace.office(address)), filename);\n try {\n unlinkSync(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code !== \"ENOENT\") {\n log.logWarning(`Failed to delete event file: ${filename}`, String(error));\n }\n }\n }\n}\n\nexport function buildEventPrompt(event: MikanEvent): string {\n switch (event.type) {\n case \"one-shot\":\n return [\n \"Please deliver the following reminder to the user in a short, natural way.\",\n \"Do not greet, do not introduce yourself, and do not ask generic follow-up questions.\",\n \"\",\n `Reminder: ${event.text}`,\n ].join(\"\\n\");\n case \"periodic\":\n return [\n \"Handle the following recurring task.\",\n \"Respond concisely. If there is nothing actionable to report, reply with [SILENT].\",\n \"\",\n `Task: ${event.text}`,\n ].join(\"\\n\");\n case \"immediate\":\n return [\n \"Handle the following event/update in a concise, context-appropriate way.\",\n \"If it reads like a reminder or follow-up, deliver it directly without greeting or generic offers to help.\",\n \"\",\n `Event: ${event.text}`,\n ].join(\"\\n\");\n }\n}\n"]}
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/events/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Cron } from \"croner\";\nimport { existsSync, readdirSync, readFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createConversationEvent } from \"../adapters/index.js\";\nimport type { ConversationKind, MessagingBot, PlatformName } from \"../types.js\";\nimport * as log from \"../log.js\";\nimport { listRegisteredOffices, officeKey, type Workspace } from \"../office/index.js\";\nimport { reportUserFacingError } from \"../observability/index.js\";\nimport { inferConversationKind } from \"../sessions/session-key.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport {\n officeEventsDir,\n parseEventPayload,\n type EventRecord,\n type EventScheduleSink,\n type MikanEvent,\n type PeriodicEventInfo,\n} from \"./index.js\";\n\nexport type { MikanEvent, PeriodicEventInfo } from \"./index.js\";\n\ninterface Scheduled {\n address: OfficeAddress;\n filename: string;\n event: MikanEvent;\n timer?: NodeJS.Timeout;\n cron?: Cron;\n}\n\nexport class EventScheduler implements EventScheduleSink {\n private readonly scheduled = new Map<string, Scheduled>();\n private startTime = Date.now();\n\n constructor(\n private readonly workspace: Workspace,\n private readonly botsByPlatform: Record<string, MessagingBot>,\n ) {}\n\n start(): void {\n this.startTime = Date.now();\n let loaded = 0;\n for (const record of listRegisteredOffices(this.workspace.stateDir)) {\n const office = this.workspace.office(record);\n const dir = officeEventsDir(office);\n if (!existsSync(dir)) continue;\n for (const filename of readdirSync(dir).filter((name) => name.endsWith(\".json\"))) {\n const path = join(dir, filename);\n try {\n const payload = parseEventPayload(readFileSync(path, \"utf-8\"), filename);\n this.scheduleRecord(office.address, { filename, payload, size: 0, mtimeMs: 0 });\n loaded++;\n } catch (error) {\n log.logWarning(\n `Removing unparseable event file ${filename} for ${office.key}`,\n error instanceof Error ? error.message : String(error),\n );\n this.removeFile(office.address, filename);\n }\n }\n }\n log.logInfo(`Event scheduler started, tracking ${loaded} records`);\n }\n\n stop(): void {\n for (const entry of this.scheduled.values()) {\n if (entry.timer) clearTimeout(entry.timer);\n entry.cron?.stop();\n }\n this.scheduled.clear();\n log.logInfo(\"Event scheduler stopped\");\n }\n\n scheduledCount(): number {\n return this.scheduled.size;\n }\n\n periodicEvents(address: OfficeAddress): PeriodicEventInfo[] {\n const prefix = `${officeKey(address)}/`;\n const results: PeriodicEventInfo[] = [];\n for (const [key, entry] of this.scheduled) {\n if (!key.startsWith(prefix) || entry.event.type !== \"periodic\" || !entry.cron) continue;\n results.push({\n filename: entry.filename,\n platform: entry.event.platform,\n conversationId: entry.event.conversationId,\n conversationKind: entry.event.conversationKind,\n text: entry.event.text,\n schedule: entry.event.schedule,\n timezone: entry.event.timezone,\n nextRun: entry.cron.nextRun()?.toISOString() ?? null,\n });\n }\n return results;\n }\n\n scheduleRecord(address: OfficeAddress, record: EventRecord): void {\n const key = this.key(address, record.filename);\n this.cancelKey(key);\n let event: MikanEvent;\n try {\n event = this.resolve(record, address);\n } catch (error) {\n log.logWarning(\n `Rejecting event ${record.filename}`,\n error instanceof Error ? error.message : String(error),\n );\n this.removeFile(address, record.filename);\n return;\n }\n const entry: Scheduled = { address, filename: record.filename, event };\n switch (event.type) {\n case \"immediate\":\n this.execute(entry);\n return;\n case \"one-shot\": {\n const delay = new Date(event.at).getTime() - Date.now();\n if (delay <= 0) {\n log.logInfo(`One-shot event in the past, deleting: ${record.filename}`);\n this.removeFile(address, record.filename);\n return;\n }\n entry.timer = setTimeout(() => {\n this.scheduled.delete(key);\n this.execute(entry);\n }, delay);\n this.scheduled.set(key, entry);\n return;\n }\n case \"periodic\":\n try {\n entry.cron = new Cron(event.schedule, { timezone: event.timezone }, () =>\n this.execute(entry, false),\n );\n } catch (error) {\n log.logWarning(`Invalid cron schedule for ${record.filename}`, String(error));\n this.removeFile(address, record.filename);\n return;\n }\n this.scheduled.set(key, entry);\n }\n }\n\n cancelRecord(address: OfficeAddress, filename: string): void {\n this.cancelKey(this.key(address, filename));\n }\n\n private key(address: OfficeAddress, filename: string): string {\n return `${officeKey(address)}/${filename}`;\n }\n\n private cancelKey(key: string): void {\n const entry = this.scheduled.get(key);\n if (!entry) return;\n if (entry.timer) clearTimeout(entry.timer);\n entry.cron?.stop();\n this.scheduled.delete(key);\n }\n\n private resolve(record: EventRecord, address: OfficeAddress): MikanEvent {\n const { payload } = record;\n const platform = (payload.platform ?? address.platform).toLowerCase();\n if (platform !== address.platform || payload.conversationId !== address.conversationId) {\n throw new Error(\"event payload does not address its owning office\");\n }\n if (!this.botsByPlatform[platform]) {\n throw new Error(`no bot configured for platform '${platform}'`);\n }\n const conversationKind: ConversationKind =\n payload.conversationKind ?? inferConversationKind(platform, payload.conversationId);\n return { ...payload, platform, conversationKind };\n }\n\n private execute(entry: Scheduled, deleteAfter = true): void {\n const { event, filename, address } = entry;\n const bot = this.botsByPlatform[event.platform];\n if (!bot) {\n this.reportFailure(entry, deleteAfter, \"missing_bot\");\n if (deleteAfter) this.removeFile(address, filename);\n return;\n }\n const enqueued = bot.enqueueEvent(\n createConversationEvent({\n platform: event.platform as PlatformName,\n type: \"mention\",\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n user: event.userId ?? \"EVENT\",\n text: buildEventPrompt(event),\n ts: `event:${filename.replace(/\\.json$/i, \"\")}`,\n }),\n );\n if (!enqueued) {\n log.logWarning(`Event queue full, discarded: ${filename}`);\n this.reportFailure(entry, deleteAfter, \"queue_full\");\n }\n if (deleteAfter) this.removeFile(address, filename);\n }\n\n private reportFailure(\n entry: Scheduled,\n deleteAfter: boolean,\n failure: \"missing_bot\" | \"queue_full\",\n ): void {\n const reason = failure === \"missing_bot\" ? \"missing bot\" : \"queue full\";\n reportUserFacingError(new Error(`Scheduled event delivery failed: ${reason}`), {\n domain: \"events\",\n surface: \"event_delivery\",\n operation: \"event_execute\",\n severity: \"error\",\n platform: entry.event.platform,\n context: {\n failure,\n filename: entry.filename,\n eventType: entry.event.type,\n conversationId: entry.event.conversationId,\n conversationKind: entry.event.conversationKind,\n deleteAfter,\n triggeredByEventFile: true,\n textLength: entry.event.text.length,\n },\n });\n }\n\n private removeFile(address: OfficeAddress, filename: string): void {\n const path = join(officeEventsDir(this.workspace.office(address)), filename);\n try {\n unlinkSync(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code !== \"ENOENT\") {\n log.logWarning(`Failed to delete event file: ${filename}`, String(error));\n }\n }\n }\n}\n\nexport function buildEventPrompt(event: MikanEvent): string {\n switch (event.type) {\n case \"one-shot\":\n return [\n \"Please deliver the following reminder to the user in a short, natural way.\",\n \"Do not greet, do not introduce yourself, and do not ask generic follow-up questions.\",\n \"\",\n `Reminder: ${event.text}`,\n ].join(\"\\n\");\n case \"periodic\":\n return [\n \"Handle the following recurring task.\",\n \"Respond concisely. If there is nothing actionable to report, reply with [SILENT].\",\n \"\",\n `Task: ${event.text}`,\n ].join(\"\\n\");\n case \"immediate\":\n return [\n \"Handle the following event/update in a concise, context-appropriate way.\",\n \"If it reads like a reminder or follow-up, deliver it directly without greeting or generic offers to help.\",\n \"\",\n `Event: ${event.text}`,\n ].join(\"\\n\");\n }\n}\n"]}
@@ -6,21 +6,6 @@ export declare function readJsonSchemaFileIfExists<T extends TSchema>(path: stri
6
6
  export declare function parseJsonValue<T>(raw: string, validate: (value: unknown) => value is T, malformedMessage: (detail: string) => string): T;
7
7
  export declare function parseJsonSchemaValue<T extends TSchema>(raw: string, schema: T, malformedMessage: (detail: string) => string): Static<T>;
8
8
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
9
- /**
10
- * Write `content` to `targetPath` with mode 0600, even when `targetPath`
11
- * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel
12
- * guarantees permissions at creation, not after a racy chmod) and then
13
- * rename(2) into place for atomicity. Readers never see a torn write,
14
- * and a crash mid-write leaves either the old file or a stray .tmp
15
- * (cleaned by the next attempt or manually) — never a half-written target.
16
- */
17
9
  export declare function atomicWritePrivateFile(targetPath: string, content: string): void;
18
- /**
19
- * The state dir (settings, office records, vaults) must never live inside
20
- * the working dir: conversation opt-in "full" mode mounts the entire working
21
- * dir read-write into sandbox containers, which would expose host-authoritative
22
- * state and credentials. Fatal under sandboxed modes; host mode has no mounts,
23
- * so only warn about the bad hygiene.
24
- */
25
10
  export declare function assertStateDirOutsideWorkspace(stateDir: string, workingDir: string, sandboxType: string): void;
26
11
  //# sourceMappingURL=file-guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-guards.d.ts","sourceRoot":"","sources":["../src/file-guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAiBzD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,GAAG,SAAS,CAGf;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,OAAO,EAC1D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAGvB;AAWD,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,CAMH;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EACpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,CAeX;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAID;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAiChF;AAaD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,IAAI,CAWN"}
1
+ {"version":3,"file":"file-guards.d.ts","sourceRoot":"","sources":["../src/file-guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAiBzD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,GAAG,SAAS,CAGf;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,OAAO,EAC1D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAGvB;AAWD,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,CAMH;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EACpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,CAeX;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAID,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA6BhF;AAQD,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,IAAI,CAWN"}
@@ -61,14 +61,6 @@ export function isRecord(value) {
61
61
  return typeof value === "object" && value !== null && !Array.isArray(value);
62
62
  }
63
63
  const PRIVATE_FILE_MODE = 0o600;
64
- /**
65
- * Write `content` to `targetPath` with mode 0600, even when `targetPath`
66
- * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel
67
- * guarantees permissions at creation, not after a racy chmod) and then
68
- * rename(2) into place for atomicity. Readers never see a torn write,
69
- * and a crash mid-write leaves either the old file or a stray .tmp
70
- * (cleaned by the next attempt or manually) — never a half-written target.
71
- */
72
64
  export function atomicWritePrivateFile(targetPath, content) {
73
65
  const dir = dirname(targetPath);
74
66
  const tmpPath = join(dir, `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
@@ -80,9 +72,7 @@ export function atomicWritePrivateFile(targetPath, content) {
80
72
  try {
81
73
  unlinkSync(tmpPath);
82
74
  }
83
- catch {
84
- // ignore — original error is more informative
85
- }
75
+ catch { }
86
76
  throw err;
87
77
  }
88
78
  finally {
@@ -95,29 +85,15 @@ export function atomicWritePrivateFile(targetPath, content) {
95
85
  try {
96
86
  unlinkSync(tmpPath);
97
87
  }
98
- catch {
99
- // ignore
100
- }
88
+ catch { }
101
89
  throw err;
102
90
  }
103
91
  }
104
- /**
105
- * True when `child` is `parent` or a path inside it. Purely lexical (no
106
- * symlink resolution) — used for configuration sanity checks, not as the
107
- * final security boundary.
108
- */
109
92
  function isPathInside(child, parent) {
110
93
  const parentPath = resolve(parent);
111
94
  const childPath = resolve(child);
112
95
  return childPath === parentPath || childPath.startsWith(parentPath + "/");
113
96
  }
114
- /**
115
- * The state dir (settings, office records, vaults) must never live inside
116
- * the working dir: conversation opt-in "full" mode mounts the entire working
117
- * dir read-write into sandbox containers, which would expose host-authoritative
118
- * state and credentials. Fatal under sandboxed modes; host mode has no mounts,
119
- * so only warn about the bad hygiene.
120
- */
121
97
  export function assertStateDirOutsideWorkspace(stateDir, workingDir, sandboxType) {
122
98
  if (!isPathInside(stateDir, workingDir))
123
99
  return;