@geminixiang/mikan 1.0.0-beta.13 → 1.0.0-beta.15

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 (303) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +42 -16
  3. package/dist/adapter.d.ts +1 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +26 -67
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +17 -43
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/github/bot.d.ts +69 -1
  13. package/dist/adapters/github/bot.d.ts.map +1 -1
  14. package/dist/adapters/github/bot.js +428 -57
  15. package/dist/adapters/github/bot.js.map +1 -1
  16. package/dist/adapters/github/client.d.ts +32 -1
  17. package/dist/adapters/github/client.d.ts.map +1 -1
  18. package/dist/adapters/github/client.js +79 -0
  19. package/dist/adapters/github/client.js.map +1 -1
  20. package/dist/adapters/github/cloudbuild.d.ts +24 -0
  21. package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
  22. package/dist/adapters/github/cloudbuild.js +71 -0
  23. package/dist/adapters/github/cloudbuild.js.map +1 -0
  24. package/dist/adapters/github/context.d.ts.map +1 -1
  25. package/dist/adapters/github/context.js +34 -31
  26. package/dist/adapters/github/context.js.map +1 -1
  27. package/dist/adapters/github/gcp-auth.d.ts +31 -0
  28. package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
  29. package/dist/adapters/github/gcp-auth.js +196 -0
  30. package/dist/adapters/github/gcp-auth.js.map +1 -0
  31. package/dist/adapters/github/ids.d.ts +9 -0
  32. package/dist/adapters/github/ids.d.ts.map +1 -1
  33. package/dist/adapters/github/ids.js +14 -0
  34. package/dist/adapters/github/ids.js.map +1 -1
  35. package/dist/adapters/github/repo.d.ts +13 -2
  36. package/dist/adapters/github/repo.d.ts.map +1 -1
  37. package/dist/adapters/github/repo.js +80 -2
  38. package/dist/adapters/github/repo.js.map +1 -1
  39. package/dist/adapters/github/tool-pack.d.ts +3 -1
  40. package/dist/adapters/github/tool-pack.d.ts.map +1 -1
  41. package/dist/adapters/github/tool-pack.js +30 -4
  42. package/dist/adapters/github/tool-pack.js.map +1 -1
  43. package/dist/{tools/github-checks.d.ts → adapters/github/tools/checks.d.ts} +4 -2
  44. package/dist/adapters/github/tools/checks.d.ts.map +1 -0
  45. package/dist/{tools/github-checks.js → adapters/github/tools/checks.js} +28 -11
  46. package/dist/adapters/github/tools/checks.js.map +1 -0
  47. package/dist/adapters/github/tools/issue.d.ts +22 -0
  48. package/dist/adapters/github/tools/issue.d.ts.map +1 -0
  49. package/dist/adapters/github/tools/issue.js +59 -0
  50. package/dist/adapters/github/tools/issue.js.map +1 -0
  51. package/dist/{tools/github-pr.d.ts → adapters/github/tools/pr.d.ts} +2 -2
  52. package/dist/adapters/github/tools/pr.d.ts.map +1 -0
  53. package/dist/{tools/github-pr.js → adapters/github/tools/pr.js} +8 -4
  54. package/dist/adapters/github/tools/pr.js.map +1 -0
  55. package/dist/adapters/github/tools/read.d.ts +22 -0
  56. package/dist/adapters/github/tools/read.d.ts.map +1 -0
  57. package/dist/adapters/github/tools/read.js +152 -0
  58. package/dist/adapters/github/tools/read.js.map +1 -0
  59. package/dist/adapters/github/tools/review-reply.d.ts +19 -0
  60. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
  61. package/dist/adapters/github/tools/review-reply.js +49 -0
  62. package/dist/adapters/github/tools/review-reply.js.map +1 -0
  63. package/dist/adapters/github/tools/sync.d.ts +17 -0
  64. package/dist/adapters/github/tools/sync.d.ts.map +1 -0
  65. package/dist/adapters/github/tools/sync.js +45 -0
  66. package/dist/adapters/github/tools/sync.js.map +1 -0
  67. package/dist/adapters/github/types.d.ts +174 -1
  68. package/dist/adapters/github/types.d.ts.map +1 -1
  69. package/dist/adapters/github/types.js.map +1 -1
  70. package/dist/adapters/intake.d.ts +16 -5
  71. package/dist/adapters/intake.d.ts.map +1 -1
  72. package/dist/adapters/intake.js +79 -22
  73. package/dist/adapters/intake.js.map +1 -1
  74. package/dist/adapters/slack/bot.d.ts +7 -6
  75. package/dist/adapters/slack/bot.d.ts.map +1 -1
  76. package/dist/adapters/slack/bot.js +65 -135
  77. package/dist/adapters/slack/bot.js.map +1 -1
  78. package/dist/adapters/slack/context.d.ts.map +1 -1
  79. package/dist/adapters/slack/context.js +3 -15
  80. package/dist/adapters/slack/context.js.map +1 -1
  81. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  82. package/dist/adapters/slack/response-lifecycle.js +7 -16
  83. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  84. package/dist/adapters/slack/session.d.ts.map +1 -1
  85. package/dist/adapters/slack/session.js +5 -8
  86. package/dist/adapters/slack/session.js.map +1 -1
  87. package/dist/adapters/streaming.d.ts +4 -0
  88. package/dist/adapters/streaming.d.ts.map +1 -1
  89. package/dist/adapters/streaming.js +11 -0
  90. package/dist/adapters/streaming.js.map +1 -1
  91. package/dist/adapters/telegram/bot.d.ts +0 -2
  92. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  93. package/dist/adapters/telegram/bot.js +16 -62
  94. package/dist/adapters/telegram/bot.js.map +1 -1
  95. package/dist/adapters/telegram/context.d.ts.map +1 -1
  96. package/dist/adapters/telegram/context.js +8 -28
  97. package/dist/adapters/telegram/context.js.map +1 -1
  98. package/dist/adapters/types.d.ts +28 -2
  99. package/dist/adapters/types.d.ts.map +1 -1
  100. package/dist/adapters/types.js.map +1 -1
  101. package/dist/agent.d.ts +23 -5
  102. package/dist/agent.d.ts.map +1 -1
  103. package/dist/agent.js +86 -28
  104. package/dist/agent.js.map +1 -1
  105. package/dist/commands/admin.d.ts.map +1 -1
  106. package/dist/commands/admin.js +2 -1
  107. package/dist/commands/admin.js.map +1 -1
  108. package/dist/commands/auto-reply.d.ts.map +1 -1
  109. package/dist/commands/auto-reply.js +2 -6
  110. package/dist/commands/auto-reply.js.map +1 -1
  111. package/dist/commands/extensions.d.ts.map +1 -1
  112. package/dist/commands/extensions.js +2 -1
  113. package/dist/commands/extensions.js.map +1 -1
  114. package/dist/commands/login.d.ts +2 -1
  115. package/dist/commands/login.d.ts.map +1 -1
  116. package/dist/commands/login.js +30 -1
  117. package/dist/commands/login.js.map +1 -1
  118. package/dist/commands/manifest.d.ts +72 -0
  119. package/dist/commands/manifest.d.ts.map +1 -0
  120. package/dist/commands/manifest.js +121 -0
  121. package/dist/commands/manifest.js.map +1 -0
  122. package/dist/commands/model.d.ts.map +1 -1
  123. package/dist/commands/model.js +2 -1
  124. package/dist/commands/model.js.map +1 -1
  125. package/dist/commands/new.d.ts.map +1 -1
  126. package/dist/commands/new.js +2 -1
  127. package/dist/commands/new.js.map +1 -1
  128. package/dist/commands/sandbox.d.ts.map +1 -1
  129. package/dist/commands/sandbox.js +3 -2
  130. package/dist/commands/sandbox.js.map +1 -1
  131. package/dist/commands/text.d.ts +2 -0
  132. package/dist/commands/text.d.ts.map +1 -0
  133. package/dist/commands/text.js +16 -0
  134. package/dist/commands/text.js.map +1 -0
  135. package/dist/commands/types.d.ts +12 -1
  136. package/dist/commands/types.d.ts.map +1 -1
  137. package/dist/commands/types.js.map +1 -1
  138. package/dist/config.d.ts +1 -1
  139. package/dist/config.d.ts.map +1 -1
  140. package/dist/config.js +49 -54
  141. package/dist/config.js.map +1 -1
  142. package/dist/events.d.ts +10 -0
  143. package/dist/events.d.ts.map +1 -1
  144. package/dist/events.js +14 -5
  145. package/dist/events.js.map +1 -1
  146. package/dist/execution-resolver.d.ts.map +1 -1
  147. package/dist/execution-resolver.js +3 -3
  148. package/dist/execution-resolver.js.map +1 -1
  149. package/dist/harness/extensions/loader.d.ts +6 -0
  150. package/dist/harness/extensions/loader.d.ts.map +1 -1
  151. package/dist/harness/extensions/loader.js +24 -4
  152. package/dist/harness/extensions/loader.js.map +1 -1
  153. package/dist/harness/extensions/registry.d.ts +48 -1
  154. package/dist/harness/extensions/registry.d.ts.map +1 -1
  155. package/dist/harness/extensions/registry.js +146 -0
  156. package/dist/harness/extensions/registry.js.map +1 -1
  157. package/dist/harness/extensions/types.d.ts +123 -12
  158. package/dist/harness/extensions/types.d.ts.map +1 -1
  159. package/dist/harness/extensions/types.js.map +1 -1
  160. package/dist/harness/index.d.ts +3 -3
  161. package/dist/harness/index.d.ts.map +1 -1
  162. package/dist/harness/index.js +1 -1
  163. package/dist/harness/index.js.map +1 -1
  164. package/dist/harness/runner.d.ts +13 -2
  165. package/dist/harness/runner.d.ts.map +1 -1
  166. package/dist/harness/runner.js +59 -16
  167. package/dist/harness/runner.js.map +1 -1
  168. package/dist/index.d.ts +1 -1
  169. package/dist/index.d.ts.map +1 -1
  170. package/dist/index.js.map +1 -1
  171. package/dist/main.js +36 -13
  172. package/dist/main.js.map +1 -1
  173. package/dist/provisioner.d.ts.map +1 -1
  174. package/dist/provisioner.js +2 -5
  175. package/dist/provisioner.js.map +1 -1
  176. package/dist/runtime/conversation-runtime.d.ts +1 -1
  177. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  178. package/dist/runtime/conversation-runtime.js +262 -41
  179. package/dist/runtime/conversation-runtime.js.map +1 -1
  180. package/dist/runtime/types.d.ts +22 -5
  181. package/dist/runtime/types.d.ts.map +1 -1
  182. package/dist/runtime/types.js.map +1 -1
  183. package/dist/sandbox/cloudflare.d.ts +2 -0
  184. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  185. package/dist/sandbox/cloudflare.js +7 -0
  186. package/dist/sandbox/cloudflare.js.map +1 -1
  187. package/dist/sandbox/container.d.ts +2 -0
  188. package/dist/sandbox/container.d.ts.map +1 -1
  189. package/dist/sandbox/container.js +7 -1
  190. package/dist/sandbox/container.js.map +1 -1
  191. package/dist/sandbox/firecracker.d.ts +2 -0
  192. package/dist/sandbox/firecracker.d.ts.map +1 -1
  193. package/dist/sandbox/firecracker.js +7 -1
  194. package/dist/sandbox/firecracker.js.map +1 -1
  195. package/dist/sandbox/host.d.ts +2 -0
  196. package/dist/sandbox/host.d.ts.map +1 -1
  197. package/dist/sandbox/host.js +11 -0
  198. package/dist/sandbox/host.js.map +1 -1
  199. package/dist/sandbox/identity.d.ts +21 -0
  200. package/dist/sandbox/identity.d.ts.map +1 -0
  201. package/dist/sandbox/identity.js +35 -0
  202. package/dist/sandbox/identity.js.map +1 -0
  203. package/dist/sandbox/types.d.ts +12 -0
  204. package/dist/sandbox/types.d.ts.map +1 -1
  205. package/dist/sandbox/types.js.map +1 -1
  206. package/dist/sandbox/utils.d.ts +11 -0
  207. package/dist/sandbox/utils.d.ts.map +1 -1
  208. package/dist/sandbox/utils.js +35 -0
  209. package/dist/sandbox/utils.js.map +1 -1
  210. package/dist/sessions/agent-memory-file-manager.d.ts.map +1 -1
  211. package/dist/sessions/agent-memory-file-manager.js +16 -30
  212. package/dist/sessions/agent-memory-file-manager.js.map +1 -1
  213. package/dist/sessions/history-line.d.ts +20 -0
  214. package/dist/sessions/history-line.d.ts.map +1 -0
  215. package/dist/sessions/history-line.js +24 -0
  216. package/dist/sessions/history-line.js.map +1 -0
  217. package/dist/sessions/policy.d.ts.map +1 -1
  218. package/dist/sessions/policy.js +4 -3
  219. package/dist/sessions/policy.js.map +1 -1
  220. package/dist/sessions/session-key.d.ts +31 -0
  221. package/dist/sessions/session-key.d.ts.map +1 -0
  222. package/dist/sessions/session-key.js +44 -0
  223. package/dist/sessions/session-key.js.map +1 -0
  224. package/dist/sessions/store.d.ts.map +1 -1
  225. package/dist/sessions/store.js +2 -2
  226. package/dist/sessions/store.js.map +1 -1
  227. package/dist/tools/bash.d.ts +3 -1
  228. package/dist/tools/bash.d.ts.map +1 -1
  229. package/dist/tools/bash.js +24 -17
  230. package/dist/tools/bash.js.map +1 -1
  231. package/dist/tools/edit.d.ts.map +1 -1
  232. package/dist/tools/edit.js +9 -12
  233. package/dist/tools/edit.js.map +1 -1
  234. package/dist/tools/event.d.ts +1 -1
  235. package/dist/tools/event.d.ts.map +1 -1
  236. package/dist/tools/event.js +33 -4
  237. package/dist/tools/event.js.map +1 -1
  238. package/dist/tools/generate-image.d.ts +17 -0
  239. package/dist/tools/generate-image.d.ts.map +1 -0
  240. package/dist/tools/generate-image.js +63 -0
  241. package/dist/tools/generate-image.js.map +1 -0
  242. package/dist/tools/index.d.ts +5 -1
  243. package/dist/tools/index.d.ts.map +1 -1
  244. package/dist/tools/index.js +11 -3
  245. package/dist/tools/index.js.map +1 -1
  246. package/dist/tools/types.d.ts +6 -1
  247. package/dist/tools/types.d.ts.map +1 -1
  248. package/dist/tools/types.js.map +1 -1
  249. package/dist/tools/write.d.ts.map +1 -1
  250. package/dist/tools/write.js +1 -8
  251. package/dist/tools/write.js.map +1 -1
  252. package/dist/types.d.ts +32 -6
  253. package/dist/types.d.ts.map +1 -1
  254. package/dist/types.js.map +1 -1
  255. package/dist/vault/disabled.d.ts +9 -0
  256. package/dist/vault/disabled.d.ts.map +1 -0
  257. package/dist/vault/disabled.js +23 -0
  258. package/dist/vault/disabled.js.map +1 -0
  259. package/dist/vault/index.d.ts.map +1 -1
  260. package/dist/vault/index.js +3 -24
  261. package/dist/vault/index.js.map +1 -1
  262. package/dist/vault/routing.d.ts +1 -0
  263. package/dist/vault/routing.d.ts.map +1 -1
  264. package/dist/vault/routing.js +3 -10
  265. package/dist/vault/routing.js.map +1 -1
  266. package/dist/web/admin/portal.d.ts +27 -0
  267. package/dist/web/admin/portal.d.ts.map +1 -1
  268. package/dist/web/admin/portal.js +87 -126
  269. package/dist/web/admin/portal.js.map +1 -1
  270. package/dist/web/admin/types.d.ts +3 -0
  271. package/dist/web/admin/types.d.ts.map +1 -1
  272. package/dist/web/admin/types.js.map +1 -1
  273. package/dist/web/login/oauth.d.ts +2 -3
  274. package/dist/web/login/oauth.d.ts.map +1 -1
  275. package/dist/web/login/oauth.js +0 -31
  276. package/dist/web/login/oauth.js.map +1 -1
  277. package/dist/web/login/types.d.ts +0 -11
  278. package/dist/web/login/types.d.ts.map +1 -1
  279. package/dist/web/login/types.js.map +1 -1
  280. package/dist/web/server.d.ts.map +1 -1
  281. package/dist/web/server.js +7 -0
  282. package/dist/web/server.js.map +1 -1
  283. package/dist/web/session-view/command.d.ts.map +1 -1
  284. package/dist/web/session-view/command.js +4 -1
  285. package/dist/web/session-view/command.js.map +1 -1
  286. package/dist/web/session-view/portal.d.ts.map +1 -1
  287. package/dist/web/session-view/portal.js +3 -2
  288. package/dist/web/session-view/portal.js.map +1 -1
  289. package/dist/web/session-view/service.d.ts.map +1 -1
  290. package/dist/web/session-view/service.js +2 -1
  291. package/dist/web/session-view/service.js.map +1 -1
  292. package/dist/web/session-view/types.d.ts +2 -1
  293. package/dist/web/session-view/types.d.ts.map +1 -1
  294. package/dist/web/session-view/types.js.map +1 -1
  295. package/package.json +1 -1
  296. package/dist/runtime/agent-run-controller.d.ts +0 -31
  297. package/dist/runtime/agent-run-controller.d.ts.map +0 -1
  298. package/dist/runtime/agent-run-controller.js +0 -195
  299. package/dist/runtime/agent-run-controller.js.map +0 -1
  300. package/dist/tools/github-checks.d.ts.map +0 -1
  301. package/dist/tools/github-checks.js.map +0 -1
  302. package/dist/tools/github-pr.d.ts.map +0 -1
  303. package/dist/tools/github-pr.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type, type Static } from \"@sinclair/typebox\";\nimport { Cron } from \"croner\";\nimport {\n existsSync,\n type FSWatcher,\n readdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n watch,\n} from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { join } from \"path\";\nimport type { MessagingBot, ConversationEvent, ConversationKind } from \"./adapter.js\";\nimport { ensureDirExists, parseJsonSchemaValue } from \"./utils/file-guards.js\";\nimport * as log from \"./log.js\";\nimport { reportUserFacingError } from \"./observability/sentry.js\";\nimport { inferConversationKind } from \"./sessions/policy.js\";\n\nexport type {\n ImmediateEvent,\n MikanEvent,\n OneShotEvent,\n PeriodicEvent,\n PeriodicEventInfo,\n} from \"./types.js\";\nimport type { ImmediateEvent, MikanEvent, OneShotEvent, PeriodicEvent } from \"./types.js\";\n\nconst EventFileSchema = Type.Object({\n type: Type.Optional(\n Type.Union([Type.Literal(\"immediate\"), Type.Literal(\"one-shot\"), Type.Literal(\"periodic\")]),\n ),\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\nimport type { PeriodicEventInfo } from \"./types.js\";\n\nconst DEBOUNCE_MS = 100;\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 100;\n\nexport class EventsWatcher {\n private timers: Map<string, NodeJS.Timeout> = new Map();\n private crons: Map<string, Cron> = new Map();\n private debounceTimers: Map<string, NodeJS.Timeout> = new Map();\n private startTime: number;\n private watcher: FSWatcher | null = null;\n private knownFiles: Set<string> = new Set();\n\n constructor(\n private eventsDir: string,\n private botsByPlatform: Record<string, MessagingBot>,\n ) {\n this.startTime = Date.now();\n }\n\n /**\n * Start watching for events. Call this after platform bots are initialized.\n */\n start(): void {\n // Ensure events directory exists\n ensureDirExists(this.eventsDir);\n\n log.logInfo(`Events watcher starting, dir: ${this.eventsDir}`);\n\n // Scan existing files\n this.scanExisting();\n\n // Watch for changes\n this.watcher = watch(this.eventsDir, (eventType, filename) => {\n if (!filename || !filename.endsWith(\".json\")) return;\n log.logInfo(\n `Events watcher fs event: ${String(eventType)} ${filename} (exists=${existsSync(join(this.eventsDir, filename))})`,\n );\n this.debounce(filename, () => this.handleFileChange(filename));\n });\n\n log.logInfo(`Events watcher started, tracking ${this.knownFiles.size} files`);\n }\n\n /**\n * Stop watching and cancel all scheduled events.\n */\n stop(): void {\n // Stop fs watcher\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n\n // Cancel all debounce timers\n for (const timer of this.debounceTimers.values()) {\n clearTimeout(timer);\n }\n this.debounceTimers.clear();\n\n // Cancel all scheduled timers\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.timers.clear();\n\n // Cancel all cron jobs\n for (const cron of this.crons.values()) {\n cron.stop();\n }\n this.crons.clear();\n\n this.knownFiles.clear();\n log.logInfo(\"Events watcher stopped\");\n }\n\n /**\n * Return all active periodic (cron) events with their next run time.\n */\n getPeriodicEvents(): PeriodicEventInfo[] {\n const results: PeriodicEventInfo[] = [];\n for (const [filename, cron] of this.crons) {\n const filePath = join(this.eventsDir, filename);\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const data = this.parseEvent(content, filename);\n if (!data || data.type !== \"periodic\") {\n continue;\n }\n const next = cron.nextRun();\n results.push({\n filename,\n platform: data.platform,\n conversationId: data.conversationId,\n conversationKind: data.conversationKind,\n text: data.text,\n schedule: data.schedule,\n timezone: data.timezone,\n nextRun: next?.toISOString() ?? null,\n });\n } catch {\n // File may have been deleted or corrupted, skip\n }\n }\n return results;\n }\n\n private debounce(filename: string, fn: () => void): void {\n const existing = this.debounceTimers.get(filename);\n if (existing) {\n clearTimeout(existing);\n }\n this.debounceTimers.set(\n filename,\n setTimeout(() => {\n this.debounceTimers.delete(filename);\n fn();\n }, DEBOUNCE_MS),\n );\n }\n\n private scanExisting(): void {\n let files: string[];\n try {\n files = readdirSync(this.eventsDir).filter((f) => f.endsWith(\".json\"));\n } catch (err) {\n log.logWarning(\"Failed to read events directory\", String(err));\n return;\n }\n\n for (const filename of files) {\n this.handleFile(filename);\n }\n }\n\n private handleFileChange(filename: string): void {\n const filePath = join(this.eventsDir, filename);\n const exists = existsSync(filePath);\n const known = this.knownFiles.has(filename);\n log.logInfo(`Handling event file change: ${filename} (exists=${exists}, known=${known})`);\n\n if (!exists) {\n // fs.watch can briefly report a file as missing during create/rename churn.\n // Confirm deletion before canceling scheduled events.\n void this.handleDelete(filename);\n } else if (known) {\n // File was modified - cancel existing and re-schedule\n this.cancelScheduled(filename, \"file-modified\");\n void this.handleFile(filename);\n } else {\n // New file\n void this.handleFile(filename);\n }\n }\n\n private async handleDelete(filename: string): Promise<void> {\n if (!this.knownFiles.has(filename)) return;\n\n const filePath = join(this.eventsDir, filename);\n for (let i = 0; i < MAX_RETRIES; i++) {\n const delay = RETRY_BASE_MS * 2 ** i;\n await new Promise((resolve) => setTimeout(resolve, delay));\n const exists = existsSync(filePath);\n log.logInfo(`Confirming event deletion: ${filename} after ${delay}ms (exists=${exists})`);\n if (exists) {\n return;\n }\n }\n\n if (this.timers.has(filename)) {\n log.logInfo(\n `Ignoring deleted one-shot file after scheduling: ${filename} (timer remains active)`,\n );\n return;\n }\n\n log.logInfo(`Event file deleted: ${filename}`);\n this.cancelScheduled(filename, \"confirmed-delete\");\n this.knownFiles.delete(filename);\n }\n\n private cancelScheduled(filename: string, reason = \"unspecified\"): void {\n const timer = this.timers.get(filename);\n const cron = this.crons.get(filename);\n log.logInfo(\n `Canceling scheduled event: ${filename} (reason=${reason}, timer=${Boolean(timer)}, cron=${Boolean(cron)})`,\n );\n if (timer) {\n clearTimeout(timer);\n this.timers.delete(filename);\n }\n\n if (cron) {\n cron.stop();\n this.crons.delete(filename);\n }\n }\n\n private async handleFile(filename: string): Promise<void> {\n const filePath = join(this.eventsDir, filename);\n log.logInfo(`Loading event file: ${filename} from ${filePath}`);\n\n // Parse with retries\n let event: MikanEvent | null = null;\n let lastError: Error | null = null;\n\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n event = this.parseEvent(content, filename);\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (i < MAX_RETRIES - 1) {\n await new Promise((resolve) => setTimeout(resolve, RETRY_BASE_MS * 2 ** i));\n }\n }\n }\n\n if (!event) {\n log.logWarning(\n `Failed to parse event file after ${MAX_RETRIES} retries: ${filename}`,\n lastError?.message,\n );\n this.deleteFile(filename, \"parse-failed\");\n return;\n }\n\n this.knownFiles.add(filename);\n log.logInfo(\n `Parsed event file: ${filename} (${event.type} for ${event.platform}/${event.conversationId})`,\n );\n\n // Schedule based on type\n switch (event.type) {\n case \"immediate\":\n this.handleImmediate(filename, event);\n break;\n case \"one-shot\":\n this.handleOneShot(filename, event);\n break;\n case \"periodic\":\n this.handlePeriodic(filename, event);\n break;\n }\n }\n\n private parseEvent(content: string, filename: string): MikanEvent | null {\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 = typeof data.type === \"string\" ? data.type : undefined;\n const text = typeof data.text === \"string\" ? data.text : undefined;\n\n if (!type || !conversationId || !text) {\n throw new Error(`Missing required fields (type, conversationId, text) in ${filename}`);\n }\n\n const platform = this.resolvePlatform(data.platform, filename);\n const conversationKind = this.resolveConversationKind(\n platform,\n conversationId,\n data.conversationKind,\n );\n const userId = typeof data.userId === \"string\" ? data.userId : undefined;\n switch (type) {\n case \"immediate\":\n return {\n type: \"immediate\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n };\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 return {\n type: \"one-shot\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n at: data.at,\n };\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 {\n type: \"periodic\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n schedule: data.schedule,\n timezone: data.timezone,\n };\n\n default:\n throw new Error(`Unknown event type '${type}' in ${filename}`);\n }\n }\n\n private resolvePlatform(platformValue: unknown, filename: string): string {\n const availablePlatforms = Object.keys(this.botsByPlatform);\n\n if (typeof platformValue === \"string\" && platformValue.trim().length > 0) {\n const platform = platformValue.trim().toLowerCase();\n if (!this.botsByPlatform[platform]) {\n throw new Error(\n `Unknown platform '${platformValue}' in ${filename}. Expected one of: ${availablePlatforms.join(\", \")}`,\n );\n }\n return platform;\n }\n\n if (availablePlatforms.length === 1) {\n return availablePlatforms[0];\n }\n\n throw new Error(\n `Missing required field 'platform' in ${filename}. Available platforms: ${availablePlatforms.join(\", \")}`,\n );\n }\n\n private resolveConversationKind(\n platform: string,\n conversationId: string,\n conversationKindValue: unknown,\n ): ConversationKind {\n if (conversationKindValue === \"direct\" || conversationKindValue === \"shared\") {\n return conversationKindValue;\n }\n\n return inferConversationKind(platform, conversationId);\n }\n\n private handleImmediate(filename: string, event: ImmediateEvent): void {\n const filePath = join(this.eventsDir, filename);\n\n // Check if stale (created before harness started)\n try {\n const stat = statSync(filePath);\n if (stat.mtimeMs < this.startTime) {\n log.logInfo(`Stale immediate event, deleting: ${filename}`);\n this.deleteFile(filename, \"stale-immediate\");\n return;\n }\n } catch {\n // File may have been deleted\n return;\n }\n\n log.logInfo(`Executing immediate event: ${filename}`);\n this.execute(filename, event);\n }\n\n private handleOneShot(filename: string, event: OneShotEvent): void {\n const atTime = new Date(event.at).getTime();\n const now = Date.now();\n\n if (atTime <= now) {\n // Past - delete without executing\n log.logInfo(`One-shot event in the past, deleting: ${filename}`);\n this.deleteFile(filename, \"one-shot-in-past\");\n return;\n }\n\n const delay = atTime - now;\n log.logInfo(\n `Scheduling one-shot event: ${filename} in ${Math.round(delay / 1000)}s (at=${event.at}, now=${new Date(now).toISOString()})`,\n );\n\n const timer = setTimeout(() => {\n this.timers.delete(filename);\n log.logInfo(`Executing one-shot event: ${filename}`);\n this.execute(filename, event);\n }, delay);\n\n this.timers.set(filename, timer);\n log.logInfo(`Stored one-shot timer: ${filename} (active timers=${this.timers.size})`);\n }\n\n private handlePeriodic(filename: string, event: PeriodicEvent): void {\n try {\n const cron = new Cron(event.schedule, { timezone: event.timezone }, () => {\n log.logInfo(`Executing periodic event: ${filename}`);\n this.execute(filename, event, false); // Don't delete periodic events\n });\n\n this.crons.set(filename, cron);\n\n const next = cron.nextRun();\n log.logInfo(\n `Scheduled periodic event: ${filename}, next run: ${next?.toISOString() ?? \"unknown\"}`,\n );\n } catch (err) {\n log.logWarning(`Invalid cron schedule for ${filename}: ${event.schedule}`, String(err));\n this.deleteFile(filename, \"invalid-cron\");\n }\n }\n\n private execute(filename: string, event: MikanEvent, deleteAfter: boolean = true): void {\n const message = this.buildEventPrompt(event);\n const bot = this.botsByPlatform[event.platform];\n\n if (!bot) {\n log.logWarning(`No bot configured for event platform '${event.platform}'`, filename);\n this.reportEventDeliveryFailure(filename, event, deleteAfter, \"missing_bot\");\n if (deleteAfter) {\n this.deleteFile(filename, \"missing-bot\");\n }\n return;\n }\n\n const eventId = filename.replace(/\\.json$/i, \"\");\n const botEvent: ConversationEvent = {\n type: \"mention\",\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n user: event.userId ?? \"EVENT\",\n text: message,\n ts: `event:${eventId}`,\n };\n\n // Enqueue for processing\n const enqueued = bot.enqueueEvent(botEvent);\n\n if (enqueued && deleteAfter) {\n // Delete file after successful enqueue (immediate and one-shot)\n this.deleteFile(filename, \"executed-and-enqueued\");\n } else if (!enqueued) {\n log.logWarning(`Event queue full, discarded: ${filename}`);\n this.reportEventDeliveryFailure(filename, event, deleteAfter, \"queue_full\");\n // Still delete immediate/one-shot even if discarded\n if (deleteAfter) {\n this.deleteFile(filename, \"queue-full-discarded\");\n }\n }\n }\n\n private reportEventDeliveryFailure(\n filename: string,\n event: MikanEvent,\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: event.platform,\n context: {\n failure,\n filename,\n eventType: event.type,\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n deleteAfter,\n triggeredByEventFile: true,\n textLength: event.text.length,\n },\n });\n }\n\n private 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\n private deleteFile(filename: string, reason = \"unspecified\"): void {\n const filePath = join(this.eventsDir, filename);\n log.logInfo(`Deleting event file: ${filename} (reason=${reason})`);\n try {\n unlinkSync(filePath);\n } catch (err) {\n // ENOENT is fine (file already deleted), other errors are warnings\n if (err instanceof Error && \"code\" in err && err.code !== \"ENOENT\") {\n log.logWarning(`Failed to delete event file: ${filename}`, String(err));\n }\n }\n this.knownFiles.delete(filename);\n }\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type, type Static } from \"@sinclair/typebox\";\nimport { Cron } from \"croner\";\nimport {\n existsSync,\n type FSWatcher,\n readdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n watch,\n} from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { join } from \"path\";\nimport type { MessagingBot, ConversationEvent, ConversationKind } from \"./adapter.js\";\nimport { ensureDirExists, parseJsonSchemaValue } from \"./utils/file-guards.js\";\nimport * as log from \"./log.js\";\nimport { reportUserFacingError } from \"./observability/sentry.js\";\nimport { inferConversationKind } from \"./sessions/policy.js\";\n\nexport type {\n ImmediateEvent,\n MikanEvent,\n OneShotEvent,\n PeriodicEvent,\n PeriodicEventInfo,\n} from \"./types.js\";\nimport type { ImmediateEvent, MikanEvent, OneShotEvent, PeriodicEvent } from \"./types.js\";\n\nconst EventFileSchema = Type.Object({\n type: Type.Optional(\n Type.Union([Type.Literal(\"immediate\"), Type.Literal(\"one-shot\"), Type.Literal(\"periodic\")]),\n ),\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\n/**\n * Resolve an event file's conversation id, honoring the legacy `channelId`\n * alias. This is the single owner of the alias; consumers reading event files\n * (EventsWatcher, HostEventStore) must normalize through it instead of\n * re-implementing the fallback.\n */\nexport function resolveEventConversationId(data: {\n conversationId?: unknown;\n channelId?: unknown;\n}): string | undefined {\n if (typeof data.conversationId === \"string\") return data.conversationId;\n if (typeof data.channelId === \"string\") return data.channelId;\n return undefined;\n}\n\nimport type { PeriodicEventInfo } from \"./types.js\";\n\nconst DEBOUNCE_MS = 100;\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 100;\n\nexport class EventsWatcher {\n private timers: Map<string, NodeJS.Timeout> = new Map();\n private crons: Map<string, Cron> = new Map();\n private debounceTimers: Map<string, NodeJS.Timeout> = new Map();\n private startTime: number;\n private watcher: FSWatcher | null = null;\n private knownFiles: Set<string> = new Set();\n\n constructor(\n private eventsDir: string,\n private botsByPlatform: Record<string, MessagingBot>,\n ) {\n this.startTime = Date.now();\n }\n\n /**\n * Start watching for events. Call this after platform bots are initialized.\n */\n start(): void {\n // Ensure events directory exists\n ensureDirExists(this.eventsDir);\n\n log.logInfo(`Events watcher starting, dir: ${this.eventsDir}`);\n\n // Scan existing files\n this.scanExisting();\n\n // Watch for changes\n this.watcher = watch(this.eventsDir, (eventType, filename) => {\n if (!filename || !filename.endsWith(\".json\")) return;\n log.logInfo(\n `Events watcher fs event: ${String(eventType)} ${filename} (exists=${existsSync(join(this.eventsDir, filename))})`,\n );\n this.debounce(filename, () => this.handleFileChange(filename));\n });\n\n log.logInfo(`Events watcher started, tracking ${this.knownFiles.size} files`);\n }\n\n /**\n * Stop watching and cancel all scheduled events.\n */\n stop(): void {\n // Stop fs watcher\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n\n // Cancel all debounce timers\n for (const timer of this.debounceTimers.values()) {\n clearTimeout(timer);\n }\n this.debounceTimers.clear();\n\n // Cancel all scheduled timers\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.timers.clear();\n\n // Cancel all cron jobs\n for (const cron of this.crons.values()) {\n cron.stop();\n }\n this.crons.clear();\n\n this.knownFiles.clear();\n log.logInfo(\"Events watcher stopped\");\n }\n\n /**\n * Return all active periodic (cron) events with their next run time.\n */\n getPeriodicEvents(): PeriodicEventInfo[] {\n const results: PeriodicEventInfo[] = [];\n for (const [filename, cron] of this.crons) {\n const filePath = join(this.eventsDir, filename);\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const data = this.parseEvent(content, filename);\n if (!data || data.type !== \"periodic\") {\n continue;\n }\n const next = cron.nextRun();\n results.push({\n filename,\n platform: data.platform,\n conversationId: data.conversationId,\n conversationKind: data.conversationKind,\n text: data.text,\n schedule: data.schedule,\n timezone: data.timezone,\n nextRun: next?.toISOString() ?? null,\n });\n } catch {\n // File may have been deleted or corrupted, skip\n }\n }\n return results;\n }\n\n private debounce(filename: string, fn: () => void): void {\n const existing = this.debounceTimers.get(filename);\n if (existing) {\n clearTimeout(existing);\n }\n this.debounceTimers.set(\n filename,\n setTimeout(() => {\n this.debounceTimers.delete(filename);\n fn();\n }, DEBOUNCE_MS),\n );\n }\n\n private scanExisting(): void {\n let files: string[];\n try {\n files = readdirSync(this.eventsDir).filter((f) => f.endsWith(\".json\"));\n } catch (err) {\n log.logWarning(\"Failed to read events directory\", String(err));\n return;\n }\n\n for (const filename of files) {\n this.handleFile(filename);\n }\n }\n\n private handleFileChange(filename: string): void {\n const filePath = join(this.eventsDir, filename);\n const exists = existsSync(filePath);\n const known = this.knownFiles.has(filename);\n log.logInfo(`Handling event file change: ${filename} (exists=${exists}, known=${known})`);\n\n if (!exists) {\n // fs.watch can briefly report a file as missing during create/rename churn.\n // Confirm deletion before canceling scheduled events.\n void this.handleDelete(filename);\n } else if (known) {\n // File was modified - cancel existing and re-schedule\n this.cancelScheduled(filename, \"file-modified\");\n void this.handleFile(filename);\n } else {\n // New file\n void this.handleFile(filename);\n }\n }\n\n private async handleDelete(filename: string): Promise<void> {\n if (!this.knownFiles.has(filename)) return;\n\n const filePath = join(this.eventsDir, filename);\n for (let i = 0; i < MAX_RETRIES; i++) {\n const delay = RETRY_BASE_MS * 2 ** i;\n await new Promise((resolve) => setTimeout(resolve, delay));\n const exists = existsSync(filePath);\n log.logInfo(`Confirming event deletion: ${filename} after ${delay}ms (exists=${exists})`);\n if (exists) {\n return;\n }\n }\n\n if (this.timers.has(filename)) {\n log.logInfo(\n `Ignoring deleted one-shot file after scheduling: ${filename} (timer remains active)`,\n );\n return;\n }\n\n log.logInfo(`Event file deleted: ${filename}`);\n this.cancelScheduled(filename, \"confirmed-delete\");\n this.knownFiles.delete(filename);\n }\n\n private cancelScheduled(filename: string, reason = \"unspecified\"): void {\n const timer = this.timers.get(filename);\n const cron = this.crons.get(filename);\n log.logInfo(\n `Canceling scheduled event: ${filename} (reason=${reason}, timer=${Boolean(timer)}, cron=${Boolean(cron)})`,\n );\n if (timer) {\n clearTimeout(timer);\n this.timers.delete(filename);\n }\n\n if (cron) {\n cron.stop();\n this.crons.delete(filename);\n }\n }\n\n private async handleFile(filename: string): Promise<void> {\n const filePath = join(this.eventsDir, filename);\n log.logInfo(`Loading event file: ${filename} from ${filePath}`);\n\n // Parse with retries\n let event: MikanEvent | null = null;\n let lastError: Error | null = null;\n\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n event = this.parseEvent(content, filename);\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (i < MAX_RETRIES - 1) {\n await new Promise((resolve) => setTimeout(resolve, RETRY_BASE_MS * 2 ** i));\n }\n }\n }\n\n if (!event) {\n log.logWarning(\n `Failed to parse event file after ${MAX_RETRIES} retries: ${filename}`,\n lastError?.message,\n );\n this.deleteFile(filename, \"parse-failed\");\n return;\n }\n\n this.knownFiles.add(filename);\n log.logInfo(\n `Parsed event file: ${filename} (${event.type} for ${event.platform}/${event.conversationId})`,\n );\n\n // Schedule based on type\n switch (event.type) {\n case \"immediate\":\n this.handleImmediate(filename, event);\n break;\n case \"one-shot\":\n this.handleOneShot(filename, event);\n break;\n case \"periodic\":\n this.handlePeriodic(filename, event);\n break;\n }\n }\n\n private parseEvent(content: string, filename: string): MikanEvent | null {\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 = resolveEventConversationId(data);\n const type = typeof data.type === \"string\" ? data.type : undefined;\n const text = typeof data.text === \"string\" ? data.text : undefined;\n\n if (!type || !conversationId || !text) {\n throw new Error(`Missing required fields (type, conversationId, text) in ${filename}`);\n }\n\n const platform = this.resolvePlatform(data.platform, filename);\n const conversationKind = this.resolveConversationKind(\n platform,\n conversationId,\n data.conversationKind,\n );\n const userId = typeof data.userId === \"string\" ? data.userId : undefined;\n switch (type) {\n case \"immediate\":\n return {\n type: \"immediate\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n };\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 return {\n type: \"one-shot\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n at: data.at,\n };\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 {\n type: \"periodic\",\n platform,\n conversationId,\n conversationKind,\n userId,\n text,\n schedule: data.schedule,\n timezone: data.timezone,\n };\n\n default:\n throw new Error(`Unknown event type '${type}' in ${filename}`);\n }\n }\n\n private resolvePlatform(platformValue: unknown, filename: string): string {\n const availablePlatforms = Object.keys(this.botsByPlatform);\n\n if (typeof platformValue === \"string\" && platformValue.trim().length > 0) {\n const platform = platformValue.trim().toLowerCase();\n if (!this.botsByPlatform[platform]) {\n throw new Error(\n `Unknown platform '${platformValue}' in ${filename}. Expected one of: ${availablePlatforms.join(\", \")}`,\n );\n }\n return platform;\n }\n\n if (availablePlatforms.length === 1) {\n return availablePlatforms[0];\n }\n\n throw new Error(\n `Missing required field 'platform' in ${filename}. Available platforms: ${availablePlatforms.join(\", \")}`,\n );\n }\n\n private resolveConversationKind(\n platform: string,\n conversationId: string,\n conversationKindValue: unknown,\n ): ConversationKind {\n if (conversationKindValue === \"direct\" || conversationKindValue === \"shared\") {\n return conversationKindValue;\n }\n\n return inferConversationKind(platform, conversationId);\n }\n\n private handleImmediate(filename: string, event: ImmediateEvent): void {\n const filePath = join(this.eventsDir, filename);\n\n // Check if stale (created before harness started)\n try {\n const stat = statSync(filePath);\n if (stat.mtimeMs < this.startTime) {\n log.logInfo(`Stale immediate event, deleting: ${filename}`);\n this.deleteFile(filename, \"stale-immediate\");\n return;\n }\n } catch {\n // File may have been deleted\n return;\n }\n\n log.logInfo(`Executing immediate event: ${filename}`);\n this.execute(filename, event);\n }\n\n private handleOneShot(filename: string, event: OneShotEvent): void {\n const atTime = new Date(event.at).getTime();\n const now = Date.now();\n\n if (atTime <= now) {\n // Past - delete without executing\n log.logInfo(`One-shot event in the past, deleting: ${filename}`);\n this.deleteFile(filename, \"one-shot-in-past\");\n return;\n }\n\n const delay = atTime - now;\n log.logInfo(\n `Scheduling one-shot event: ${filename} in ${Math.round(delay / 1000)}s (at=${event.at}, now=${new Date(now).toISOString()})`,\n );\n\n const timer = setTimeout(() => {\n this.timers.delete(filename);\n log.logInfo(`Executing one-shot event: ${filename}`);\n this.execute(filename, event);\n }, delay);\n\n this.timers.set(filename, timer);\n log.logInfo(`Stored one-shot timer: ${filename} (active timers=${this.timers.size})`);\n }\n\n private handlePeriodic(filename: string, event: PeriodicEvent): void {\n try {\n const cron = new Cron(event.schedule, { timezone: event.timezone }, () => {\n log.logInfo(`Executing periodic event: ${filename}`);\n this.execute(filename, event, false); // Don't delete periodic events\n });\n\n this.crons.set(filename, cron);\n\n const next = cron.nextRun();\n log.logInfo(\n `Scheduled periodic event: ${filename}, next run: ${next?.toISOString() ?? \"unknown\"}`,\n );\n } catch (err) {\n log.logWarning(`Invalid cron schedule for ${filename}: ${event.schedule}`, String(err));\n this.deleteFile(filename, \"invalid-cron\");\n }\n }\n\n private execute(filename: string, event: MikanEvent, deleteAfter: boolean = true): void {\n const message = this.buildEventPrompt(event);\n const bot = this.botsByPlatform[event.platform];\n\n if (!bot) {\n log.logWarning(`No bot configured for event platform '${event.platform}'`, filename);\n this.reportEventDeliveryFailure(filename, event, deleteAfter, \"missing_bot\");\n if (deleteAfter) {\n this.deleteFile(filename, \"missing-bot\");\n }\n return;\n }\n\n const eventId = filename.replace(/\\.json$/i, \"\");\n const botEvent: ConversationEvent = {\n type: \"mention\",\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n user: event.userId ?? \"EVENT\",\n text: message,\n ts: `event:${eventId}`,\n };\n\n // Enqueue for processing\n const enqueued = bot.enqueueEvent(botEvent);\n\n if (enqueued && deleteAfter) {\n // Delete file after successful enqueue (immediate and one-shot)\n this.deleteFile(filename, \"executed-and-enqueued\");\n } else if (!enqueued) {\n log.logWarning(`Event queue full, discarded: ${filename}`);\n this.reportEventDeliveryFailure(filename, event, deleteAfter, \"queue_full\");\n // Still delete immediate/one-shot even if discarded\n if (deleteAfter) {\n this.deleteFile(filename, \"queue-full-discarded\");\n }\n }\n }\n\n private reportEventDeliveryFailure(\n filename: string,\n event: MikanEvent,\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: event.platform,\n context: {\n failure,\n filename,\n eventType: event.type,\n conversationId: event.conversationId,\n conversationKind: event.conversationKind,\n deleteAfter,\n triggeredByEventFile: true,\n textLength: event.text.length,\n },\n });\n }\n\n private 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\n private deleteFile(filename: string, reason = \"unspecified\"): void {\n const filePath = join(this.eventsDir, filename);\n log.logInfo(`Deleting event file: ${filename} (reason=${reason})`);\n try {\n unlinkSync(filePath);\n } catch (err) {\n // ENOENT is fine (file already deleted), other errors are warnings\n if (err instanceof Error && \"code\" in err && err.code !== \"ENOENT\") {\n log.logWarning(`Failed to delete event file: ${filename}`, String(err));\n }\n }\n this.knownFiles.delete(filename);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"execution-resolver.d.ts","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvF,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKnG,YAAY,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAExE,wBAAgB,kCAAkC,CAChD,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,cAAc,EAAE,MAAM,GACrB,uBAAuB,CAiBzB;AAiCD,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW,CAAC;IACpB,OAAO,CAAC,YAAY,CAAC;IANvB,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAqB;IAE7D,YACU,UAAU,EAAE,aAAa,EACzB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,EAAE,sBAAsB,YAAA,EACpC,YAAY,CAAC,EAAE,MAAM,YAAA,EAC3B;IAEE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAatD;IAED,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,wBAAwB;IA4ChC,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,uBAAuB;CAsBhC"}
1
+ {"version":3,"file":"execution-resolver.d.ts","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvF,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKnG,YAAY,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAExE,wBAAgB,kCAAkC,CAChD,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,cAAc,EAAE,MAAM,GACrB,uBAAuB,CAmBzB;AAiCD,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW,CAAC;IACpB,OAAO,CAAC,YAAY,CAAC;IANvB,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAqB;IAE7D,YACU,UAAU,EAAE,aAAa,EACzB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,EAAE,sBAAsB,YAAA,EACpC,YAAY,CAAC,EAAE,MAAM,YAAA,EAC3B;IAEE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAatD;IAED,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,wBAAwB;IA4ChC,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,uBAAuB;CAsBhC"}
@@ -16,7 +16,7 @@ export function readConversationWorkspaceMountMode(workspaceDir, conversationId)
16
16
  }
17
17
  const conversationDir = join(workspaceDir, conversationId);
18
18
  try {
19
- return resolveConversationSettings(conversationDir).sandboxImageWorkspaceMount ?? globalDefault;
19
+ return (resolveConversationSettings(conversationDir).sandbox?.image?.workspaceMount ?? globalDefault);
20
20
  }
21
21
  catch (err) {
22
22
  log.logWarning("Falling back while resolving conversation workspace mount", err instanceof Error ? err.message : String(err));
@@ -26,7 +26,7 @@ export function readConversationWorkspaceMountMode(workspaceDir, conversationId)
26
26
  }
27
27
  function readGlobalWorkspaceMountMode() {
28
28
  try {
29
- return loadGlobalSettings().sandboxImageWorkspaceMount ?? "private";
29
+ return loadGlobalSettings().sandbox?.image?.workspaceMount ?? "private";
30
30
  }
31
31
  catch (err) {
32
32
  log.logWarning("Using default workspace mount because global settings could not be read", err instanceof Error ? err.message : String(err));
@@ -69,7 +69,7 @@ export class ActorExecutionResolver {
69
69
  return;
70
70
  let profile;
71
71
  try {
72
- profile = loadGlobalSettings().defaultSharedVault;
72
+ profile = loadGlobalSettings().sandbox?.defaultSharedVault;
73
73
  }
74
74
  catch {
75
75
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"execution-resolver.js","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n conversationSettingsPath,\n loadGlobalSettings,\n resolveConversationSettings,\n} from \"./config.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./utils/file-guards.js\";\nimport { DockerContainerManager, type ContainerMount } from \"./provisioner.js\";\nimport { createExecutor, type Executor, type SandboxConfig } from \"./sandbox/index.js\";\nimport { reportUserFacingError } from \"./observability/sentry.js\";\nimport { normalizeSharedVaultName, type ResolvedVault, type VaultManager } from \"./vault/index.js\";\nimport { allowsAmbientDefaultSharedVault } from \"./vault/policy.js\";\nimport { resolveActorVaultKey } from \"./vault/routing.js\";\nimport * as log from \"./log.js\";\n\nexport type { ActorContext, ImageWorkspaceMountMode } from \"./types.js\";\nimport type { ActorContext, ImageWorkspaceMountMode } from \"./types.js\";\n\nexport function readConversationWorkspaceMountMode(\n workspaceDir: string | undefined,\n conversationId: string,\n): ImageWorkspaceMountMode {\n const globalDefault = readGlobalWorkspaceMountMode();\n if (!workspaceDir) {\n return globalDefault;\n }\n\n const conversationDir = join(workspaceDir, conversationId);\n try {\n return resolveConversationSettings(conversationDir).sandboxImageWorkspaceMount ?? globalDefault;\n } catch (err) {\n log.logWarning(\n \"Falling back while resolving conversation workspace mount\",\n err instanceof Error ? err.message : String(err),\n );\n const raw = readConversationSettingsFallback(conversationSettingsPath(conversationDir));\n return raw?.sandbox?.image?.workspaceMount ?? globalDefault;\n }\n}\n\nfunction readGlobalWorkspaceMountMode(): ImageWorkspaceMountMode {\n try {\n return loadGlobalSettings().sandboxImageWorkspaceMount ?? \"private\";\n } catch (err) {\n log.logWarning(\n \"Using default workspace mount because global settings could not be read\",\n err instanceof Error ? err.message : String(err),\n );\n return \"private\";\n }\n}\n\nfunction readConversationSettingsFallback(\n settingsPath: string,\n): { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } | undefined {\n try {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } =>\n isRecord(value),\n () => \"Ignoring malformed conversation settings file while resolving workspace mount\",\n );\n } catch (err) {\n log.logWarning(\n \"Ignoring malformed conversation settings fallback while resolving workspace mount\",\n err instanceof Error ? err.message : String(err),\n );\n return undefined;\n }\n}\n\nexport class ActorExecutionResolver {\n private readonly ensuredConversationDirs = new Set<string>();\n\n constructor(\n private baseConfig: SandboxConfig,\n private vaultManager: VaultManager,\n private provisioner?: DockerContainerManager,\n private workspaceDir?: string,\n ) {}\n\n async resolve(context: ActorContext): Promise<Executor> {\n const vaultKey = resolveActorVaultKey(this.baseConfig, context.userId, context.conversationId);\n this.ensureDefaultSharedVault(vaultKey, context.trustModel);\n\n const vault = this.vaultManager.resolve(vaultKey);\n const config = this.resolveSandboxConfig(vaultKey);\n const env =\n config.type !== \"host\" && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return createExecutor(\n config,\n env,\n this.buildEnsureReadyCallback(vaultKey, context.conversationId, config, vault),\n );\n }\n\n private ensureDefaultSharedVault(vaultKey: string, trustModel: ActorContext[\"trustModel\"]): void {\n if (\n !allowsAmbientDefaultSharedVault({\n trustModel,\n sandboxType: this.baseConfig.type,\n })\n ) {\n return;\n }\n if (this.vaultManager.hasEntry(vaultKey)) return;\n\n let profile: string | undefined;\n try {\n profile = loadGlobalSettings().defaultSharedVault;\n } catch {\n return;\n }\n if (!profile || normalizeSharedVaultName(profile) !== profile) return;\n\n this.vaultManager.copySharedVaultTo(profile, vaultKey);\n }\n\n private resolveSandboxConfig(vaultKey: string): SandboxConfig {\n const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);\n if (this.baseConfig.type !== \"image\") {\n return config;\n }\n\n if (config.type === \"container\") {\n return config;\n }\n\n return {\n type: \"container\",\n container: DockerContainerManager.containerName(vaultKey),\n };\n }\n\n private buildEnsureReadyCallback(\n vaultKey: string,\n conversationId: string,\n config: SandboxConfig,\n vault?: ResolvedVault,\n ): (() => Promise<void>) | undefined {\n if (this.baseConfig.type !== \"image\" || config.type !== \"container\") {\n return undefined;\n }\n\n return async () => {\n const expected = config.container || DockerContainerManager.containerName(vaultKey);\n let actual: string | undefined;\n try {\n actual = await this.provisioner?.provision(vaultKey, {\n containerName: expected,\n mounts: this.resolveMounts(conversationId, vault),\n conversationId,\n });\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"ensure_image_container_ready\",\n severity: \"error\",\n context: {\n sandboxType: \"image\",\n resolvedSandboxType: config.type,\n conversationId,\n vaultKey,\n expectedContainer: expected,\n hasVault: Boolean(vault),\n },\n });\n throw err;\n }\n if (actual && actual !== expected) {\n throw new Error(\n `Provisioner returned container \"${actual}\" for container key \"${vaultKey}\", expected \"${expected}\"`,\n );\n }\n };\n }\n\n private resolveMounts(conversationId: string, vault?: ResolvedVault): ContainerMount[] {\n const mountsByTarget = new Map<string, ContainerMount>();\n for (const mount of this.buildImageSandboxMounts(conversationId)) {\n mountsByTarget.set(mount.target, mount);\n }\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mountsByTarget.set(mount.target, { source: mount.source, target: mount.target });\n }\n return [...mountsByTarget.values()];\n }\n\n private buildImageSandboxMounts(conversationId: string): ContainerMount[] {\n if (!this.workspaceDir) {\n return [];\n }\n\n if (readConversationWorkspaceMountMode(this.workspaceDir, conversationId) === \"full\") {\n return [{ source: this.workspaceDir, target: \"/workspace\" }];\n }\n\n const conversationDir = join(this.workspaceDir, conversationId);\n if (!this.ensuredConversationDirs.has(conversationId)) {\n ensureDirExists(conversationDir);\n this.ensuredConversationDirs.add(conversationId);\n }\n\n return [\n { source: join(this.workspaceDir, \"MEMORY.md\"), target: \"/workspace/MEMORY.md\" },\n { source: join(this.workspaceDir, \"skills\"), target: \"/workspace/skills\" },\n { source: join(this.workspaceDir, \"events\"), target: \"/workspace/events\" },\n { source: conversationDir, target: `/workspace/${conversationId}` },\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"execution-resolver.js","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n conversationSettingsPath,\n loadGlobalSettings,\n resolveConversationSettings,\n} from \"./config.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./utils/file-guards.js\";\nimport { DockerContainerManager, type ContainerMount } from \"./provisioner.js\";\nimport { createExecutor, type Executor, type SandboxConfig } from \"./sandbox/index.js\";\nimport { reportUserFacingError } from \"./observability/sentry.js\";\nimport { normalizeSharedVaultName, type ResolvedVault, type VaultManager } from \"./vault/index.js\";\nimport { allowsAmbientDefaultSharedVault } from \"./vault/policy.js\";\nimport { resolveActorVaultKey } from \"./vault/routing.js\";\nimport * as log from \"./log.js\";\n\nexport type { ActorContext, ImageWorkspaceMountMode } from \"./types.js\";\nimport type { ActorContext, ImageWorkspaceMountMode } from \"./types.js\";\n\nexport function readConversationWorkspaceMountMode(\n workspaceDir: string | undefined,\n conversationId: string,\n): ImageWorkspaceMountMode {\n const globalDefault = readGlobalWorkspaceMountMode();\n if (!workspaceDir) {\n return globalDefault;\n }\n\n const conversationDir = join(workspaceDir, conversationId);\n try {\n return (\n resolveConversationSettings(conversationDir).sandbox?.image?.workspaceMount ?? globalDefault\n );\n } catch (err) {\n log.logWarning(\n \"Falling back while resolving conversation workspace mount\",\n err instanceof Error ? err.message : String(err),\n );\n const raw = readConversationSettingsFallback(conversationSettingsPath(conversationDir));\n return raw?.sandbox?.image?.workspaceMount ?? globalDefault;\n }\n}\n\nfunction readGlobalWorkspaceMountMode(): ImageWorkspaceMountMode {\n try {\n return loadGlobalSettings().sandbox?.image?.workspaceMount ?? \"private\";\n } catch (err) {\n log.logWarning(\n \"Using default workspace mount because global settings could not be read\",\n err instanceof Error ? err.message : String(err),\n );\n return \"private\";\n }\n}\n\nfunction readConversationSettingsFallback(\n settingsPath: string,\n): { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } | undefined {\n try {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } =>\n isRecord(value),\n () => \"Ignoring malformed conversation settings file while resolving workspace mount\",\n );\n } catch (err) {\n log.logWarning(\n \"Ignoring malformed conversation settings fallback while resolving workspace mount\",\n err instanceof Error ? err.message : String(err),\n );\n return undefined;\n }\n}\n\nexport class ActorExecutionResolver {\n private readonly ensuredConversationDirs = new Set<string>();\n\n constructor(\n private baseConfig: SandboxConfig,\n private vaultManager: VaultManager,\n private provisioner?: DockerContainerManager,\n private workspaceDir?: string,\n ) {}\n\n async resolve(context: ActorContext): Promise<Executor> {\n const vaultKey = resolveActorVaultKey(this.baseConfig, context.userId, context.conversationId);\n this.ensureDefaultSharedVault(vaultKey, context.trustModel);\n\n const vault = this.vaultManager.resolve(vaultKey);\n const config = this.resolveSandboxConfig(vaultKey);\n const env =\n config.type !== \"host\" && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return createExecutor(\n config,\n env,\n this.buildEnsureReadyCallback(vaultKey, context.conversationId, config, vault),\n );\n }\n\n private ensureDefaultSharedVault(vaultKey: string, trustModel: ActorContext[\"trustModel\"]): void {\n if (\n !allowsAmbientDefaultSharedVault({\n trustModel,\n sandboxType: this.baseConfig.type,\n })\n ) {\n return;\n }\n if (this.vaultManager.hasEntry(vaultKey)) return;\n\n let profile: string | undefined;\n try {\n profile = loadGlobalSettings().sandbox?.defaultSharedVault;\n } catch {\n return;\n }\n if (!profile || normalizeSharedVaultName(profile) !== profile) return;\n\n this.vaultManager.copySharedVaultTo(profile, vaultKey);\n }\n\n private resolveSandboxConfig(vaultKey: string): SandboxConfig {\n const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);\n if (this.baseConfig.type !== \"image\") {\n return config;\n }\n\n if (config.type === \"container\") {\n return config;\n }\n\n return {\n type: \"container\",\n container: DockerContainerManager.containerName(vaultKey),\n };\n }\n\n private buildEnsureReadyCallback(\n vaultKey: string,\n conversationId: string,\n config: SandboxConfig,\n vault?: ResolvedVault,\n ): (() => Promise<void>) | undefined {\n if (this.baseConfig.type !== \"image\" || config.type !== \"container\") {\n return undefined;\n }\n\n return async () => {\n const expected = config.container || DockerContainerManager.containerName(vaultKey);\n let actual: string | undefined;\n try {\n actual = await this.provisioner?.provision(vaultKey, {\n containerName: expected,\n mounts: this.resolveMounts(conversationId, vault),\n conversationId,\n });\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"ensure_image_container_ready\",\n severity: \"error\",\n context: {\n sandboxType: \"image\",\n resolvedSandboxType: config.type,\n conversationId,\n vaultKey,\n expectedContainer: expected,\n hasVault: Boolean(vault),\n },\n });\n throw err;\n }\n if (actual && actual !== expected) {\n throw new Error(\n `Provisioner returned container \"${actual}\" for container key \"${vaultKey}\", expected \"${expected}\"`,\n );\n }\n };\n }\n\n private resolveMounts(conversationId: string, vault?: ResolvedVault): ContainerMount[] {\n const mountsByTarget = new Map<string, ContainerMount>();\n for (const mount of this.buildImageSandboxMounts(conversationId)) {\n mountsByTarget.set(mount.target, mount);\n }\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mountsByTarget.set(mount.target, { source: mount.source, target: mount.target });\n }\n return [...mountsByTarget.values()];\n }\n\n private buildImageSandboxMounts(conversationId: string): ContainerMount[] {\n if (!this.workspaceDir) {\n return [];\n }\n\n if (readConversationWorkspaceMountMode(this.workspaceDir, conversationId) === \"full\") {\n return [{ source: this.workspaceDir, target: \"/workspace\" }];\n }\n\n const conversationDir = join(this.workspaceDir, conversationId);\n if (!this.ensuredConversationDirs.has(conversationId)) {\n ensureDirExists(conversationDir);\n this.ensuredConversationDirs.add(conversationId);\n }\n\n return [\n { source: join(this.workspaceDir, \"MEMORY.md\"), target: \"/workspace/MEMORY.md\" },\n { source: join(this.workspaceDir, \"skills\"), target: \"/workspace/skills\" },\n { source: join(this.workspaceDir, \"events\"), target: \"/workspace/events\" },\n { source: conversationDir, target: `/workspace/${conversationId}` },\n ];\n }\n}\n"]}
@@ -48,6 +48,12 @@ export interface LoadExtensionsResult {
48
48
  errors: ExtensionLoadError[];
49
49
  /** Skills contributed by extensions (inline: bodies ride in the prompt). */
50
50
  skills: MikanSkill[];
51
+ /**
52
+ * Run extension disposers (from `api.onDispose` and `activate` return
53
+ * values). Call when the harness instance owning these extensions is
54
+ * discarded. Idempotent; disposer errors are logged, never thrown.
55
+ */
56
+ dispose(): Promise<void>;
51
57
  }
52
58
  /**
53
59
  * Filesystem-safe identifier for an extension, derived from its install
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EACV,qBAAqB,EACrB,kBAAkB,EAKlB,eAAe,EAIhB,MAAM,YAAY,CAAC;AAiBpB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,MAAkC,GAC3C,MAAM,EAAE,CAKV;AAED,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,sBAAsB,EAAE,CAkBhF;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE;QACP,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAClB,aAAa,EAAE,aAAa,CAAC;KAC9B,CAAC;IACF,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAuHD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQxD;AA0OD,uEAAuE;AACvE,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAkD/B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsDxF"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAGV,qBAAqB,EACrB,kBAAkB,EAKlB,eAAe,EAIhB,MAAM,YAAY,CAAC;AAiBpB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,MAAkC,GAC3C,MAAM,EAAE,CAKV;AAED,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,sBAAsB,EAAE,CAkBhF;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE;QACP,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAClB,aAAa,EAAE,aAAa,CAAC;KAC9B,CAAC;IACF,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAuHD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQxD;AA6PD,uEAAuE;AACvE,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAmD/B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsDxF"}
@@ -328,6 +328,8 @@ function buildExtensionApi(params) {
328
328
  return {
329
329
  on: (hook, handler) => registry.register(name, hook, handler),
330
330
  registerTool: (tool) => registry.registerTool(tool),
331
+ registerCommand: (command) => registry.registerCommand(name, command),
332
+ onDispose: (disposer) => registry.registerDisposer(name, disposer),
331
333
  log: (message) => log.logInfo(`[extension:${name}] ${message}`),
332
334
  context,
333
335
  paths: {
@@ -377,11 +379,11 @@ function buildExtensionApi(params) {
377
379
  return infos;
378
380
  },
379
381
  },
380
- notify: async (text) => {
382
+ notify: async (text, options) => {
381
383
  if (!services.postMessage) {
382
384
  throw new Error("api.notify is unavailable: this context provides no platform messaging");
383
385
  }
384
- await services.postMessage(conversationId, text);
386
+ await services.postMessage(options?.conversationId ?? conversationId, text);
385
387
  },
386
388
  react: async (messageTs, emoji) => {
387
389
  if (!services.addReaction) {
@@ -389,8 +391,24 @@ function buildExtensionApi(params) {
389
391
  }
390
392
  await services.addReaction(conversationId, messageTs, emoji);
391
393
  },
394
+ uploadFile: async (filePath, title) => {
395
+ if (!services.uploadFile) {
396
+ throw new Error("api.uploadFile is unavailable: this context provides no file uploads");
397
+ }
398
+ await services.uploadFile(conversationId, filePath, title);
399
+ },
400
+ triggerRun: async (text) => {
401
+ const store = requireScheduleStore();
402
+ // Distinct "extrun." namespace: run files must never surface in
403
+ // api.schedules.list(), whose ownership filter is the "ext." prefix.
404
+ // The embedder's watcher fires and deletes the file immediately.
405
+ const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;
406
+ await store.write(filename, { type: "immediate", conversationId, text });
407
+ },
392
408
  };
393
409
  }
410
+ /** Monotonic suffix so rapid triggerRun calls in one process never collide. */
411
+ let runCounter = 0;
394
412
  function resolveActivate(moduleExports) {
395
413
  if (!moduleExports || typeof moduleExports !== "object")
396
414
  return undefined;
@@ -442,7 +460,9 @@ export async function loadExtensions(options) {
442
460
  context: options.context,
443
461
  services,
444
462
  });
445
- await extension.activate(api);
463
+ const disposer = await extension.activate(api);
464
+ if (typeof disposer === "function")
465
+ registry.registerDisposer(name, disposer);
446
466
  const extensionSkills = loadExtensionSkills(rootDir, slug);
447
467
  skills.push(...extensionSkills);
448
468
  extensions.push({
@@ -462,7 +482,7 @@ export async function loadExtensions(options) {
462
482
  }
463
483
  }
464
484
  }
465
- return { registry, extensions, errors, skills };
485
+ return { registry, extensions, errors, skills, dispose: () => registry.dispose() };
466
486
  }
467
487
  /**
468
488
  * Validate an extension source path (a directory or a single file) WITHOUT
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension discovery and activation.\n *\n * Extension modules execute inside the mikan host process with its full\n * privileges (platform tokens, vault, host filesystem). They must therefore\n * only ever load from host-controlled directories: installing an extension\n * is an administrator action. In particular, extension directories must not\n * live under paths mounted into sandbox containers (workspace and\n * conversation dirs in image mode), or code written from inside the sandbox\n * would be imported into the host process — a sandbox escape.\n * {@link defaultExtensionDirs} returns the canonical host-only locations\n * under mikan's state dir.\n *\n * Directories are scanned in order; all discovered extensions activate.\n * Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):\n *\n * - `extensions/<name>.<ext>` (bare file)\n * - `extensions/<name>/index.<ext>` (directory + index)\n * - `extensions/<name>/package.json` (mikan.extensions entrypoint;\n * may carry npm dependencies in node_modules)\n *\n * Modules are imported with a fresh jiti instance (no cache) so edited\n * extensions are picked up when a new harness instance is created.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join } from \"path\";\nimport { createJiti } from \"jiti\";\nimport type { AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport * as log from \"../../log.js\";\nimport { loadSkillsFromDir, type MikanSkill } from \"../skills.js\";\nimport { ExtensionRegistry } from \"./registry.js\";\nimport type {\n ExtensionHostServices,\n ExtensionLoadError,\n ExtensionManifest,\n ExtensionSchedulePayload,\n ExtensionScheduleInfo,\n ExtensionScheduleSpec,\n LoadedExtension,\n MikanExtensionActivate,\n MikanExtensionApi,\n MikanExtensionModule,\n} from \"./types.js\";\n\nconst EXTENSION_FILE_PATTERN = /\\.(mjs|js|ts|mts)$/;\nconst INDEX_FILE_PATTERN = /^index\\.(mjs|js|ts|mts)$/;\nconst INDEX_CANDIDATES = [\"index.mjs\", \"index.js\", \"index.ts\", \"index.mts\"];\n\n/**\n * Import an extension entrypoint through jiti so it can be TypeScript and can\n * use node_modules dependencies, transparently compiling on the fly. A fresh\n * jiti instance with caching disabled is used per load so edited extensions\n * are picked up when a new harness instance is created for a conversation.\n */\nasync function importExtensionModule(entrypoint: string): Promise<unknown> {\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n return jiti.import(entrypoint);\n}\n\n/**\n * Canonical host-only extension code directories for a conversation, in load\n * order: `<stateDir>/global/extensions` (all conversations) then\n * `<stateDir>/conversations/<conversationId>/extensions` (that conversation\n * only). `global` and `conversations` are the two sibling scopes; see\n * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).\n */\nexport function defaultExtensionDirs(\n conversationId: string,\n stateDir: string = join(homedir(), \".mikan\"),\n): string[] {\n return [\n join(stateDir, \"global\", \"extensions\"),\n join(stateDir, \"conversations\", conversationId, \"extensions\"),\n ];\n}\n\n/** Discovery-only view of an installed extension (module is not imported). */\nexport interface InstalledExtensionInfo {\n /** Display name: manifest name, falling back to the slug. */\n name: string;\n slug: string;\n path: string;\n /** Scan directory the extension was found in. */\n dir: string;\n version?: string;\n description?: string;\n /** Names of skills shipped in the extension's skills/ directory. */\n skillNames: string[];\n}\n\n/**\n * List installed extensions without importing or activating them — safe for\n * inventory surfaces (commands, portal). Activation side effects (schedule\n * upserts, tool registration) only happen in {@link loadExtensions}.\n */\nexport function listInstalledExtensions(dirs: string[]): InstalledExtensionInfo[] {\n const infos: InstalledExtensionInfo[] = [];\n for (const dir of dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n infos.push({\n name: manifest.name ?? slug,\n slug,\n path: entrypoint,\n dir,\n version: manifest.version,\n description: manifest.description,\n skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),\n });\n }\n }\n return infos;\n}\n\nexport interface LoadExtensionsOptions {\n /** Directories to scan for extensions. Missing directories are skipped. */\n dirs: string[];\n context: {\n conversationId: string;\n workspaceDir: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n };\n /** Embedder-provided services backing the v2 api surface. */\n services?: ExtensionHostServices;\n}\n\nexport interface LoadExtensionsResult {\n registry: ExtensionRegistry;\n extensions: LoadedExtension[];\n errors: ExtensionLoadError[];\n /** Skills contributed by extensions (inline: bodies ride in the prompt). */\n skills: MikanSkill[];\n}\n\n/**\n * A discovered extension: its entrypoint (module to import) and root dir\n * (used for slug, manifest.json, and skills/ — which sit at the extension\n * root, not necessarily next to a nested entrypoint).\n */\ninterface DiscoveredExtension {\n entrypoint: string;\n rootDir: string;\n}\n\nfunction discoverExtensionEntrypoints(dir: string): DiscoveredExtension[] {\n if (!existsSync(dir)) return [];\n const found: DiscoveredExtension[] = [];\n for (const name of readdirSync(dir).toSorted()) {\n if (name.startsWith(\".\")) continue;\n if (INDEX_FILE_PATTERN.test(name)) {\n // An index file at the scan root means the extension's contents were\n // copied into the scope directory itself; the slug would degenerate to\n // the scope name (e.g. the conversation id), mis-keying its data dir,\n // secrets, and schedules. Require a named form instead.\n log.logWarning(\n `Ignoring extension index file at scope root: ${join(dir, name)}`,\n \"install into a named subdirectory (e.g. extensions/<scope>/my-ext/index.mjs)\",\n );\n continue;\n }\n const fullPath = join(dir, name);\n let stats;\n try {\n stats = statSync(fullPath);\n } catch {\n continue;\n }\n if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {\n // Bare-file form: the file is both entrypoint and (its own) root.\n found.push({ entrypoint: fullPath, rootDir: fullPath });\n continue;\n }\n if (stats.isDirectory()) {\n const entrypoint = resolveDirectoryEntrypoint(fullPath);\n if (entrypoint) found.push({ entrypoint, rootDir: fullPath });\n }\n }\n return found;\n}\n\n/**\n * Resolve a directory-form extension's entrypoint. A `package.json` with a\n * `mikan.extensions` array (first entry, relative to the dir) wins — this is\n * how an extension declares a TypeScript entry and pulls in npm dependencies.\n * Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined\n * when neither is present.\n */\nfunction resolveDirectoryEntrypoint(dir: string): string | undefined {\n const declared = readMikanManifestEntrypoints(dir)[0];\n if (declared) {\n const resolved = join(dir, declared);\n if (existsSync(resolved)) return resolved;\n log.logWarning(\n `Extension package.json declares a missing entrypoint: ${resolved}`,\n \"falling back to an index file\",\n );\n }\n for (const candidate of INDEX_CANDIDATES) {\n const indexPath = join(dir, candidate);\n if (existsSync(indexPath)) return indexPath;\n }\n return undefined;\n}\n\ninterface ExtensionPackageJson {\n name?: string;\n version?: string;\n description?: string;\n mikan?: { extensions?: string[]; displayName?: string };\n}\n\n/** Read and shape a directory's package.json; undefined when absent/malformed. */\nfunction readPackageJson(dir: string): ExtensionPackageJson | undefined {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return undefined;\n const record = parsed as Record<string, unknown>;\n const mikanRaw = record.mikan as { extensions?: unknown; displayName?: unknown } | undefined;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n mikan: {\n extensions: Array.isArray(mikanRaw?.extensions)\n ? mikanRaw.extensions.filter((entry): entry is string => typeof entry === \"string\")\n : undefined,\n displayName: typeof mikanRaw?.displayName === \"string\" ? mikanRaw.displayName : undefined,\n },\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));\n return undefined;\n }\n}\n\n/** Read the `mikan.extensions` entrypoint list from a directory's package.json. */\nfunction readMikanManifestEntrypoints(dir: string): string[] {\n return readPackageJson(dir)?.mikan?.extensions ?? [];\n}\n\nfunction sanitizeSlug(base: string): string {\n const slug = base\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n return slug || \"extension\";\n}\n\n/**\n * Filesystem-safe identifier for an extension, derived from its install\n * location: the directory name for a directory-form extension, or the file\n * basename for a bare file. The slug keys the extension's data dir, secrets\n * vault, and schedule ownership — installing the same extension globally and\n * per-conversation shares one slug and therefore one shared data dir.\n */\nexport function extensionSlug(entrypoint: string): string {\n // Bare-file form (rootDir === entrypoint, a *.mjs/.ts file) → file basename.\n // Directory form → directory name. Detect the directory form structurally:\n // an entrypoint whose parent holds a package.json or is an index file.\n if (INDEX_FILE_PATTERN.test(basename(entrypoint))) {\n return sanitizeSlug(basename(dirname(entrypoint)));\n }\n return sanitizeSlug(basename(entrypoint).replace(EXTENSION_FILE_PATTERN, \"\"));\n}\n\n/** Slug from a discovered extension's root dir (directory or bare file path). */\nfunction slugForRoot(rootDir: string): string {\n return EXTENSION_FILE_PATTERN.test(basename(rootDir))\n ? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, \"\"))\n : sanitizeSlug(basename(rootDir));\n}\n\n/** Sanitize an extension-chosen schedule name into a filename segment. */\nfunction scheduleNameSegment(name: string): string {\n const segment = name\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n if (!segment) throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);\n return segment;\n}\n\n/**\n * Read display metadata (name/version/description) for a directory-form\n * extension. `package.json` is the primary source — its standard `name`,\n * `version`, `description`, plus an optional `mikan.displayName` that\n * overrides the npm name for the user-facing label (npm names are\n * lowercase/scoped; display names can be arbitrary). A `manifest.json` is a\n * fallback for extensions that ship no package.json.\n */\nfunction readManifest(rootDir: string): ExtensionManifest {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return {};\n\n const pkg = readPackageJson(rootDir);\n if (pkg && (pkg.mikan?.displayName ?? pkg.name ?? pkg.version ?? pkg.description)) {\n return {\n name: pkg.mikan?.displayName ?? pkg.name,\n version: pkg.version,\n description: pkg.description,\n };\n }\n\n const manifestPath = join(rootDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return {};\n try {\n const parsed: unknown = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\") return {};\n const record = parsed as Record<string, unknown>;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed extension manifest: ${manifestPath}`, String(err));\n return {};\n }\n}\n\n/**\n * Skills shipped inside a directory-form extension (`<dir>/skills/`).\n * Marked inline: extension files live under the host-only state dir, which\n * sandbox containers cannot read, so skill bodies must ride in the prompt.\n */\nfunction loadExtensionSkills(rootDir: string, slug: string): MikanSkill[] {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return [];\n const skillsDir = join(rootDir, \"skills\");\n if (!existsSync(skillsDir)) return [];\n const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });\n for (const diagnostic of result.diagnostics) {\n log.logWarning(`Extension skill warning (${slug}): ${diagnostic.message}`, diagnostic.path);\n }\n for (const skill of result.skills) skill.inline = true;\n return result.skills;\n}\n\nconst SCHEDULE_FILE_SUFFIX = \".json\";\n\nfunction schedulePrefix(slug: string, conversationId: string): string {\n return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;\n}\n\nfunction payloadFromSpec(\n spec: ExtensionScheduleSpec,\n conversationId: string,\n): ExtensionSchedulePayload {\n if (spec.type === \"periodic\") {\n if (!spec.schedule || !spec.timezone) {\n throw new Error(\"periodic schedule requires schedule and timezone\");\n }\n return {\n type: \"periodic\",\n conversationId,\n text: spec.text,\n schedule: spec.schedule,\n timezone: spec.timezone,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n }\n if (!spec.at) throw new Error(\"one-shot schedule requires at\");\n return {\n type: \"one-shot\",\n conversationId,\n text: spec.text,\n at: spec.at,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n}\n\nfunction specFromPayload(payload: ExtensionSchedulePayload): ExtensionScheduleSpec {\n if (payload.type === \"periodic\") {\n return {\n type: \"periodic\",\n schedule: payload.schedule ?? \"\",\n timezone: payload.timezone ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n }\n return {\n type: \"one-shot\",\n at: payload.at ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n}\n\n/** Build the v2 api surface for one extension over the injected services. */\nfunction buildExtensionApi(params: {\n name: string;\n slug: string;\n registry: ExtensionRegistry;\n context: LoadExtensionsOptions[\"context\"];\n services: ExtensionHostServices;\n}): MikanExtensionApi {\n const { name, slug, registry, context, services } = params;\n const stateDir = services.stateDir ?? join(homedir(), \".mikan\");\n const conversationId = context.conversationId;\n\n const requireScheduleStore = () => {\n if (!services.scheduleStore) {\n throw new Error(\"api.schedules is unavailable: this context provides no schedule store\");\n }\n return services.scheduleStore;\n };\n\n return {\n on: (hook, handler) => registry.register(name, hook, handler),\n registerTool: (tool: AgentTool) => registry.registerTool(tool),\n log: (message: string) => log.logInfo(`[extension:${name}] ${message}`),\n context,\n paths: {\n get dataDir(): string {\n // This conversation's own data, co-located with the conversation's\n // other host-only assets; removed when the conversation is deleted.\n const dir = join(stateDir, \"conversations\", conversationId, \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n get sharedDataDir(): string {\n // Cross-conversation data under the sibling `global` scope.\n const dir = join(stateDir, \"global\", \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n },\n secrets: {\n get: (key: string) => services.resolveSecrets?.(slug)[key],\n list: () => Object.keys(services.resolveSecrets?.(slug) ?? {}),\n },\n schedules: {\n upsert: async (scheduleName, spec) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, payloadFromSpec(spec, conversationId));\n },\n delete: async (scheduleName) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n return store.delete(filename);\n },\n list: async () => {\n const store = requireScheduleStore();\n const prefix = schedulePrefix(slug, conversationId);\n const infos: ExtensionScheduleInfo[] = [];\n for (const entry of await store.list()) {\n if (!entry.filename.startsWith(prefix)) continue;\n if (!entry.filename.endsWith(SCHEDULE_FILE_SUFFIX)) continue;\n infos.push({\n name: entry.filename.slice(prefix.length, -SCHEDULE_FILE_SUFFIX.length),\n spec: specFromPayload(entry.payload),\n });\n }\n return infos;\n },\n },\n notify: async (text: string) => {\n if (!services.postMessage) {\n throw new Error(\"api.notify is unavailable: this context provides no platform messaging\");\n }\n await services.postMessage(conversationId, text);\n },\n react: async (messageTs: string, emoji: string) => {\n if (!services.addReaction) {\n throw new Error(\"api.react is unavailable: this context provides no reaction support\");\n }\n await services.addReaction(conversationId, messageTs, emoji);\n },\n };\n}\n\nfunction resolveActivate(moduleExports: unknown): MikanExtensionModule | undefined {\n if (!moduleExports || typeof moduleExports !== \"object\") return undefined;\n const candidates: unknown[] = [(moduleExports as { default?: unknown }).default, moduleExports];\n for (const candidate of candidates) {\n if (typeof candidate === \"function\") {\n return { activate: candidate as MikanExtensionActivate };\n }\n if (candidate && typeof candidate === \"object\") {\n const activate = (candidate as { activate?: unknown }).activate;\n if (typeof activate === \"function\") {\n return {\n name:\n typeof (candidate as { name?: unknown }).name === \"string\"\n ? (candidate as { name: string }).name\n : undefined,\n activate: activate as MikanExtensionActivate,\n };\n }\n }\n }\n return undefined;\n}\n\n/** Load and activate all extensions found in the given directories. */\nexport async function loadExtensions(\n options: LoadExtensionsOptions,\n): Promise<LoadExtensionsResult> {\n const registry = new ExtensionRegistry();\n const extensions: LoadedExtension[] = [];\n const errors: ExtensionLoadError[] = [];\n const skills: MikanSkill[] = [];\n const services = options.services ?? {};\n\n for (const dir of options.dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n const extension = resolveActivate(moduleExports);\n if (!extension) {\n errors.push({\n path: entrypoint,\n error: \"extension must export an activate function (default or named)\",\n });\n continue;\n }\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const name = manifest.name ?? extension.name ?? slug;\n const api = buildExtensionApi({\n name,\n slug,\n registry,\n context: options.context,\n services,\n });\n await extension.activate(api);\n const extensionSkills = loadExtensionSkills(rootDir, slug);\n skills.push(...extensionSkills);\n extensions.push({\n name,\n path: entrypoint,\n slug,\n version: manifest.version,\n description: manifest.description,\n skills: extensionSkills,\n });\n } catch (err) {\n errors.push({\n path: entrypoint,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n return { registry, extensions, errors, skills };\n}\n\nexport interface ExtensionValidation {\n ok: boolean;\n /** Slug the extension would install as (from the source dir/file name). */\n slug: string;\n /** Display name (manifest name, else slug). */\n name: string;\n version?: string;\n description?: string;\n /** Resolved entrypoint that would be imported. */\n entrypoint?: string;\n /** Skill names shipped alongside the extension. */\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate an extension source path (a directory or a single file) WITHOUT\n * activating it: resolves the entrypoint (package.json `mikan.extensions`,\n * index file, or the file itself), imports it, and checks it exports an\n * `activate` function. Used by `mikan ext install` as a preflight and by\n * `mikan ext validate`. Importing runs top-level module code but not\n * `activate`, so there are no schedule/tool side effects.\n */\nexport async function validateExtension(sourcePath: string): Promise<ExtensionValidation> {\n const errors: string[] = [];\n const warnings: string[] = [];\n const rootDir = sourcePath.replace(/[/\\\\]+$/, \"\");\n const base = basename(rootDir);\n\n if (INDEX_FILE_PATTERN.test(base)) {\n warnings.push(\n \"Entry is a bare index file; install into a named directory so the slug is stable.\",\n );\n }\n\n let entrypoint: string | undefined;\n if (!existsSync(rootDir)) {\n errors.push(`Path does not exist: ${rootDir}`);\n } else if (statSync(rootDir).isDirectory()) {\n entrypoint = resolveDirectoryEntrypoint(rootDir);\n if (!entrypoint) {\n errors.push(\n \"No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.\",\n );\n }\n } else if (EXTENSION_FILE_PATTERN.test(base)) {\n entrypoint = rootDir;\n } else {\n errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);\n }\n\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);\n\n if (entrypoint) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n if (!resolveActivate(moduleExports)) {\n errors.push(\"Module does not export an activate function (default or named).\");\n }\n } catch (err) {\n errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n ok: errors.length === 0,\n slug,\n name: manifest.name ?? slug,\n version: manifest.version,\n description: manifest.description,\n entrypoint,\n skillNames,\n errors,\n warnings,\n };\n}\n"]}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension discovery and activation.\n *\n * Extension modules execute inside the mikan host process with its full\n * privileges (platform tokens, vault, host filesystem). They must therefore\n * only ever load from host-controlled directories: installing an extension\n * is an administrator action. In particular, extension directories must not\n * live under paths mounted into sandbox containers (workspace and\n * conversation dirs in image mode), or code written from inside the sandbox\n * would be imported into the host process — a sandbox escape.\n * {@link defaultExtensionDirs} returns the canonical host-only locations\n * under mikan's state dir.\n *\n * Directories are scanned in order; all discovered extensions activate.\n * Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):\n *\n * - `extensions/<name>.<ext>` (bare file)\n * - `extensions/<name>/index.<ext>` (directory + index)\n * - `extensions/<name>/package.json` (mikan.extensions entrypoint;\n * may carry npm dependencies in node_modules)\n *\n * Modules are imported with a fresh jiti instance (no cache) so edited\n * extensions are picked up when a new harness instance is created.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join } from \"path\";\nimport { createJiti } from \"jiti\";\nimport type { AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport * as log from \"../../log.js\";\nimport { loadSkillsFromDir, type MikanSkill } from \"../skills.js\";\nimport { ExtensionRegistry } from \"./registry.js\";\nimport type {\n ExtensionCommand,\n ExtensionDisposer,\n ExtensionHostServices,\n ExtensionLoadError,\n ExtensionManifest,\n ExtensionSchedulePayload,\n ExtensionScheduleInfo,\n ExtensionScheduleSpec,\n LoadedExtension,\n MikanExtensionActivate,\n MikanExtensionApi,\n MikanExtensionModule,\n} from \"./types.js\";\n\nconst EXTENSION_FILE_PATTERN = /\\.(mjs|js|ts|mts)$/;\nconst INDEX_FILE_PATTERN = /^index\\.(mjs|js|ts|mts)$/;\nconst INDEX_CANDIDATES = [\"index.mjs\", \"index.js\", \"index.ts\", \"index.mts\"];\n\n/**\n * Import an extension entrypoint through jiti so it can be TypeScript and can\n * use node_modules dependencies, transparently compiling on the fly. A fresh\n * jiti instance with caching disabled is used per load so edited extensions\n * are picked up when a new harness instance is created for a conversation.\n */\nasync function importExtensionModule(entrypoint: string): Promise<unknown> {\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n return jiti.import(entrypoint);\n}\n\n/**\n * Canonical host-only extension code directories for a conversation, in load\n * order: `<stateDir>/global/extensions` (all conversations) then\n * `<stateDir>/conversations/<conversationId>/extensions` (that conversation\n * only). `global` and `conversations` are the two sibling scopes; see\n * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).\n */\nexport function defaultExtensionDirs(\n conversationId: string,\n stateDir: string = join(homedir(), \".mikan\"),\n): string[] {\n return [\n join(stateDir, \"global\", \"extensions\"),\n join(stateDir, \"conversations\", conversationId, \"extensions\"),\n ];\n}\n\n/** Discovery-only view of an installed extension (module is not imported). */\nexport interface InstalledExtensionInfo {\n /** Display name: manifest name, falling back to the slug. */\n name: string;\n slug: string;\n path: string;\n /** Scan directory the extension was found in. */\n dir: string;\n version?: string;\n description?: string;\n /** Names of skills shipped in the extension's skills/ directory. */\n skillNames: string[];\n}\n\n/**\n * List installed extensions without importing or activating them — safe for\n * inventory surfaces (commands, portal). Activation side effects (schedule\n * upserts, tool registration) only happen in {@link loadExtensions}.\n */\nexport function listInstalledExtensions(dirs: string[]): InstalledExtensionInfo[] {\n const infos: InstalledExtensionInfo[] = [];\n for (const dir of dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n infos.push({\n name: manifest.name ?? slug,\n slug,\n path: entrypoint,\n dir,\n version: manifest.version,\n description: manifest.description,\n skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),\n });\n }\n }\n return infos;\n}\n\nexport interface LoadExtensionsOptions {\n /** Directories to scan for extensions. Missing directories are skipped. */\n dirs: string[];\n context: {\n conversationId: string;\n workspaceDir: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n };\n /** Embedder-provided services backing the v2 api surface. */\n services?: ExtensionHostServices;\n}\n\nexport interface LoadExtensionsResult {\n registry: ExtensionRegistry;\n extensions: LoadedExtension[];\n errors: ExtensionLoadError[];\n /** Skills contributed by extensions (inline: bodies ride in the prompt). */\n skills: MikanSkill[];\n /**\n * Run extension disposers (from `api.onDispose` and `activate` return\n * values). Call when the harness instance owning these extensions is\n * discarded. Idempotent; disposer errors are logged, never thrown.\n */\n dispose(): Promise<void>;\n}\n\n/**\n * A discovered extension: its entrypoint (module to import) and root dir\n * (used for slug, manifest.json, and skills/ — which sit at the extension\n * root, not necessarily next to a nested entrypoint).\n */\ninterface DiscoveredExtension {\n entrypoint: string;\n rootDir: string;\n}\n\nfunction discoverExtensionEntrypoints(dir: string): DiscoveredExtension[] {\n if (!existsSync(dir)) return [];\n const found: DiscoveredExtension[] = [];\n for (const name of readdirSync(dir).toSorted()) {\n if (name.startsWith(\".\")) continue;\n if (INDEX_FILE_PATTERN.test(name)) {\n // An index file at the scan root means the extension's contents were\n // copied into the scope directory itself; the slug would degenerate to\n // the scope name (e.g. the conversation id), mis-keying its data dir,\n // secrets, and schedules. Require a named form instead.\n log.logWarning(\n `Ignoring extension index file at scope root: ${join(dir, name)}`,\n \"install into a named subdirectory (e.g. extensions/<scope>/my-ext/index.mjs)\",\n );\n continue;\n }\n const fullPath = join(dir, name);\n let stats;\n try {\n stats = statSync(fullPath);\n } catch {\n continue;\n }\n if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {\n // Bare-file form: the file is both entrypoint and (its own) root.\n found.push({ entrypoint: fullPath, rootDir: fullPath });\n continue;\n }\n if (stats.isDirectory()) {\n const entrypoint = resolveDirectoryEntrypoint(fullPath);\n if (entrypoint) found.push({ entrypoint, rootDir: fullPath });\n }\n }\n return found;\n}\n\n/**\n * Resolve a directory-form extension's entrypoint. A `package.json` with a\n * `mikan.extensions` array (first entry, relative to the dir) wins — this is\n * how an extension declares a TypeScript entry and pulls in npm dependencies.\n * Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined\n * when neither is present.\n */\nfunction resolveDirectoryEntrypoint(dir: string): string | undefined {\n const declared = readMikanManifestEntrypoints(dir)[0];\n if (declared) {\n const resolved = join(dir, declared);\n if (existsSync(resolved)) return resolved;\n log.logWarning(\n `Extension package.json declares a missing entrypoint: ${resolved}`,\n \"falling back to an index file\",\n );\n }\n for (const candidate of INDEX_CANDIDATES) {\n const indexPath = join(dir, candidate);\n if (existsSync(indexPath)) return indexPath;\n }\n return undefined;\n}\n\ninterface ExtensionPackageJson {\n name?: string;\n version?: string;\n description?: string;\n mikan?: { extensions?: string[]; displayName?: string };\n}\n\n/** Read and shape a directory's package.json; undefined when absent/malformed. */\nfunction readPackageJson(dir: string): ExtensionPackageJson | undefined {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return undefined;\n const record = parsed as Record<string, unknown>;\n const mikanRaw = record.mikan as { extensions?: unknown; displayName?: unknown } | undefined;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n mikan: {\n extensions: Array.isArray(mikanRaw?.extensions)\n ? mikanRaw.extensions.filter((entry): entry is string => typeof entry === \"string\")\n : undefined,\n displayName: typeof mikanRaw?.displayName === \"string\" ? mikanRaw.displayName : undefined,\n },\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));\n return undefined;\n }\n}\n\n/** Read the `mikan.extensions` entrypoint list from a directory's package.json. */\nfunction readMikanManifestEntrypoints(dir: string): string[] {\n return readPackageJson(dir)?.mikan?.extensions ?? [];\n}\n\nfunction sanitizeSlug(base: string): string {\n const slug = base\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n return slug || \"extension\";\n}\n\n/**\n * Filesystem-safe identifier for an extension, derived from its install\n * location: the directory name for a directory-form extension, or the file\n * basename for a bare file. The slug keys the extension's data dir, secrets\n * vault, and schedule ownership — installing the same extension globally and\n * per-conversation shares one slug and therefore one shared data dir.\n */\nexport function extensionSlug(entrypoint: string): string {\n // Bare-file form (rootDir === entrypoint, a *.mjs/.ts file) → file basename.\n // Directory form → directory name. Detect the directory form structurally:\n // an entrypoint whose parent holds a package.json or is an index file.\n if (INDEX_FILE_PATTERN.test(basename(entrypoint))) {\n return sanitizeSlug(basename(dirname(entrypoint)));\n }\n return sanitizeSlug(basename(entrypoint).replace(EXTENSION_FILE_PATTERN, \"\"));\n}\n\n/** Slug from a discovered extension's root dir (directory or bare file path). */\nfunction slugForRoot(rootDir: string): string {\n return EXTENSION_FILE_PATTERN.test(basename(rootDir))\n ? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, \"\"))\n : sanitizeSlug(basename(rootDir));\n}\n\n/** Sanitize an extension-chosen schedule name into a filename segment. */\nfunction scheduleNameSegment(name: string): string {\n const segment = name\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n if (!segment) throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);\n return segment;\n}\n\n/**\n * Read display metadata (name/version/description) for a directory-form\n * extension. `package.json` is the primary source — its standard `name`,\n * `version`, `description`, plus an optional `mikan.displayName` that\n * overrides the npm name for the user-facing label (npm names are\n * lowercase/scoped; display names can be arbitrary). A `manifest.json` is a\n * fallback for extensions that ship no package.json.\n */\nfunction readManifest(rootDir: string): ExtensionManifest {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return {};\n\n const pkg = readPackageJson(rootDir);\n if (pkg && (pkg.mikan?.displayName ?? pkg.name ?? pkg.version ?? pkg.description)) {\n return {\n name: pkg.mikan?.displayName ?? pkg.name,\n version: pkg.version,\n description: pkg.description,\n };\n }\n\n const manifestPath = join(rootDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return {};\n try {\n const parsed: unknown = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\") return {};\n const record = parsed as Record<string, unknown>;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed extension manifest: ${manifestPath}`, String(err));\n return {};\n }\n}\n\n/**\n * Skills shipped inside a directory-form extension (`<dir>/skills/`).\n * Marked inline: extension files live under the host-only state dir, which\n * sandbox containers cannot read, so skill bodies must ride in the prompt.\n */\nfunction loadExtensionSkills(rootDir: string, slug: string): MikanSkill[] {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return [];\n const skillsDir = join(rootDir, \"skills\");\n if (!existsSync(skillsDir)) return [];\n const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });\n for (const diagnostic of result.diagnostics) {\n log.logWarning(`Extension skill warning (${slug}): ${diagnostic.message}`, diagnostic.path);\n }\n for (const skill of result.skills) skill.inline = true;\n return result.skills;\n}\n\nconst SCHEDULE_FILE_SUFFIX = \".json\";\n\nfunction schedulePrefix(slug: string, conversationId: string): string {\n return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;\n}\n\nfunction payloadFromSpec(\n spec: ExtensionScheduleSpec,\n conversationId: string,\n): ExtensionSchedulePayload {\n if (spec.type === \"periodic\") {\n if (!spec.schedule || !spec.timezone) {\n throw new Error(\"periodic schedule requires schedule and timezone\");\n }\n return {\n type: \"periodic\",\n conversationId,\n text: spec.text,\n schedule: spec.schedule,\n timezone: spec.timezone,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n }\n if (!spec.at) throw new Error(\"one-shot schedule requires at\");\n return {\n type: \"one-shot\",\n conversationId,\n text: spec.text,\n at: spec.at,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n}\n\nfunction specFromPayload(payload: ExtensionSchedulePayload): ExtensionScheduleSpec {\n if (payload.type === \"periodic\") {\n return {\n type: \"periodic\",\n schedule: payload.schedule ?? \"\",\n timezone: payload.timezone ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n }\n return {\n type: \"one-shot\",\n at: payload.at ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n}\n\n/** Build the v2 api surface for one extension over the injected services. */\nfunction buildExtensionApi(params: {\n name: string;\n slug: string;\n registry: ExtensionRegistry;\n context: LoadExtensionsOptions[\"context\"];\n services: ExtensionHostServices;\n}): MikanExtensionApi {\n const { name, slug, registry, context, services } = params;\n const stateDir = services.stateDir ?? join(homedir(), \".mikan\");\n const conversationId = context.conversationId;\n\n const requireScheduleStore = () => {\n if (!services.scheduleStore) {\n throw new Error(\"api.schedules is unavailable: this context provides no schedule store\");\n }\n return services.scheduleStore;\n };\n\n return {\n on: (hook, handler) => registry.register(name, hook, handler),\n registerTool: (tool: AgentTool) => registry.registerTool(tool),\n registerCommand: (command: ExtensionCommand) => registry.registerCommand(name, command),\n onDispose: (disposer: ExtensionDisposer) => registry.registerDisposer(name, disposer),\n log: (message: string) => log.logInfo(`[extension:${name}] ${message}`),\n context,\n paths: {\n get dataDir(): string {\n // This conversation's own data, co-located with the conversation's\n // other host-only assets; removed when the conversation is deleted.\n const dir = join(stateDir, \"conversations\", conversationId, \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n get sharedDataDir(): string {\n // Cross-conversation data under the sibling `global` scope.\n const dir = join(stateDir, \"global\", \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n },\n secrets: {\n get: (key: string) => services.resolveSecrets?.(slug)[key],\n list: () => Object.keys(services.resolveSecrets?.(slug) ?? {}),\n },\n schedules: {\n upsert: async (scheduleName, spec) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, payloadFromSpec(spec, conversationId));\n },\n delete: async (scheduleName) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n return store.delete(filename);\n },\n list: async () => {\n const store = requireScheduleStore();\n const prefix = schedulePrefix(slug, conversationId);\n const infos: ExtensionScheduleInfo[] = [];\n for (const entry of await store.list()) {\n if (!entry.filename.startsWith(prefix)) continue;\n if (!entry.filename.endsWith(SCHEDULE_FILE_SUFFIX)) continue;\n infos.push({\n name: entry.filename.slice(prefix.length, -SCHEDULE_FILE_SUFFIX.length),\n spec: specFromPayload(entry.payload),\n });\n }\n return infos;\n },\n },\n notify: async (text: string, options?: { conversationId?: string }) => {\n if (!services.postMessage) {\n throw new Error(\"api.notify is unavailable: this context provides no platform messaging\");\n }\n await services.postMessage(options?.conversationId ?? conversationId, text);\n },\n react: async (messageTs: string, emoji: string) => {\n if (!services.addReaction) {\n throw new Error(\"api.react is unavailable: this context provides no reaction support\");\n }\n await services.addReaction(conversationId, messageTs, emoji);\n },\n uploadFile: async (filePath: string, title?: string) => {\n if (!services.uploadFile) {\n throw new Error(\"api.uploadFile is unavailable: this context provides no file uploads\");\n }\n await services.uploadFile(conversationId, filePath, title);\n },\n triggerRun: async (text: string) => {\n const store = requireScheduleStore();\n // Distinct \"extrun.\" namespace: run files must never surface in\n // api.schedules.list(), whose ownership filter is the \"ext.\" prefix.\n // The embedder's watcher fires and deletes the file immediately.\n const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, { type: \"immediate\", conversationId, text });\n },\n };\n}\n\n/** Monotonic suffix so rapid triggerRun calls in one process never collide. */\nlet runCounter = 0;\n\nfunction resolveActivate(moduleExports: unknown): MikanExtensionModule | undefined {\n if (!moduleExports || typeof moduleExports !== \"object\") return undefined;\n const candidates: unknown[] = [(moduleExports as { default?: unknown }).default, moduleExports];\n for (const candidate of candidates) {\n if (typeof candidate === \"function\") {\n return { activate: candidate as MikanExtensionActivate };\n }\n if (candidate && typeof candidate === \"object\") {\n const activate = (candidate as { activate?: unknown }).activate;\n if (typeof activate === \"function\") {\n return {\n name:\n typeof (candidate as { name?: unknown }).name === \"string\"\n ? (candidate as { name: string }).name\n : undefined,\n activate: activate as MikanExtensionActivate,\n };\n }\n }\n }\n return undefined;\n}\n\n/** Load and activate all extensions found in the given directories. */\nexport async function loadExtensions(\n options: LoadExtensionsOptions,\n): Promise<LoadExtensionsResult> {\n const registry = new ExtensionRegistry();\n const extensions: LoadedExtension[] = [];\n const errors: ExtensionLoadError[] = [];\n const skills: MikanSkill[] = [];\n const services = options.services ?? {};\n\n for (const dir of options.dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n const extension = resolveActivate(moduleExports);\n if (!extension) {\n errors.push({\n path: entrypoint,\n error: \"extension must export an activate function (default or named)\",\n });\n continue;\n }\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const name = manifest.name ?? extension.name ?? slug;\n const api = buildExtensionApi({\n name,\n slug,\n registry,\n context: options.context,\n services,\n });\n const disposer = await extension.activate(api);\n if (typeof disposer === \"function\") registry.registerDisposer(name, disposer);\n const extensionSkills = loadExtensionSkills(rootDir, slug);\n skills.push(...extensionSkills);\n extensions.push({\n name,\n path: entrypoint,\n slug,\n version: manifest.version,\n description: manifest.description,\n skills: extensionSkills,\n });\n } catch (err) {\n errors.push({\n path: entrypoint,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n return { registry, extensions, errors, skills, dispose: () => registry.dispose() };\n}\n\nexport interface ExtensionValidation {\n ok: boolean;\n /** Slug the extension would install as (from the source dir/file name). */\n slug: string;\n /** Display name (manifest name, else slug). */\n name: string;\n version?: string;\n description?: string;\n /** Resolved entrypoint that would be imported. */\n entrypoint?: string;\n /** Skill names shipped alongside the extension. */\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate an extension source path (a directory or a single file) WITHOUT\n * activating it: resolves the entrypoint (package.json `mikan.extensions`,\n * index file, or the file itself), imports it, and checks it exports an\n * `activate` function. Used by `mikan ext install` as a preflight and by\n * `mikan ext validate`. Importing runs top-level module code but not\n * `activate`, so there are no schedule/tool side effects.\n */\nexport async function validateExtension(sourcePath: string): Promise<ExtensionValidation> {\n const errors: string[] = [];\n const warnings: string[] = [];\n const rootDir = sourcePath.replace(/[/\\\\]+$/, \"\");\n const base = basename(rootDir);\n\n if (INDEX_FILE_PATTERN.test(base)) {\n warnings.push(\n \"Entry is a bare index file; install into a named directory so the slug is stable.\",\n );\n }\n\n let entrypoint: string | undefined;\n if (!existsSync(rootDir)) {\n errors.push(`Path does not exist: ${rootDir}`);\n } else if (statSync(rootDir).isDirectory()) {\n entrypoint = resolveDirectoryEntrypoint(rootDir);\n if (!entrypoint) {\n errors.push(\n \"No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.\",\n );\n }\n } else if (EXTENSION_FILE_PATTERN.test(base)) {\n entrypoint = rootDir;\n } else {\n errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);\n }\n\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);\n\n if (entrypoint) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n if (!resolveActivate(moduleExports)) {\n errors.push(\"Module does not export an activate function (default or named).\");\n }\n } catch (err) {\n errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n ok: errors.length === 0,\n slug,\n name: manifest.name ?? slug,\n version: manifest.version,\n description: manifest.description,\n entrypoint,\n skillNames,\n errors,\n warnings,\n };\n}\n"]}