@geminixiang/mikan 1.0.0-beta.2 → 1.0.0-beta.21

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 (497) hide show
  1. package/CHANGELOG.md +388 -0
  2. package/README.md +49 -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/buffered-responder.d.ts +60 -0
  7. package/dist/adapters/buffered-responder.d.ts.map +1 -0
  8. package/dist/adapters/buffered-responder.js +201 -0
  9. package/dist/adapters/buffered-responder.js.map +1 -0
  10. package/dist/adapters/discord/bot.d.ts +1 -0
  11. package/dist/adapters/discord/bot.d.ts.map +1 -1
  12. package/dist/adapters/discord/bot.js +36 -67
  13. package/dist/adapters/discord/bot.js.map +1 -1
  14. package/dist/adapters/discord/context.d.ts.map +1 -1
  15. package/dist/adapters/discord/context.js +44 -204
  16. package/dist/adapters/discord/context.js.map +1 -1
  17. package/dist/adapters/github/bot.d.ts +86 -0
  18. package/dist/adapters/github/bot.d.ts.map +1 -0
  19. package/dist/adapters/github/bot.js +640 -0
  20. package/dist/adapters/github/bot.js.map +1 -0
  21. package/dist/adapters/github/client.d.ts +122 -0
  22. package/dist/adapters/github/client.d.ts.map +1 -0
  23. package/dist/adapters/github/client.js +314 -0
  24. package/dist/adapters/github/client.js.map +1 -0
  25. package/dist/adapters/github/cloudbuild.d.ts +24 -0
  26. package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
  27. package/dist/adapters/github/cloudbuild.js +71 -0
  28. package/dist/adapters/github/cloudbuild.js.map +1 -0
  29. package/dist/adapters/github/context.d.ts +9 -0
  30. package/dist/adapters/github/context.d.ts.map +1 -0
  31. package/dist/adapters/github/context.js +103 -0
  32. package/dist/adapters/github/context.js.map +1 -0
  33. package/dist/adapters/github/gcp-auth.d.ts +31 -0
  34. package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
  35. package/dist/adapters/github/gcp-auth.js +196 -0
  36. package/dist/adapters/github/gcp-auth.js.map +1 -0
  37. package/dist/adapters/github/github-ops.d.ts +90 -0
  38. package/dist/adapters/github/github-ops.d.ts.map +1 -0
  39. package/dist/adapters/github/github-ops.js +405 -0
  40. package/dist/adapters/github/github-ops.js.map +1 -0
  41. package/dist/adapters/github/ids.d.ts +34 -0
  42. package/dist/adapters/github/ids.d.ts.map +1 -0
  43. package/dist/adapters/github/ids.js +53 -0
  44. package/dist/adapters/github/ids.js.map +1 -0
  45. package/dist/adapters/github/repo.d.ts +32 -0
  46. package/dist/adapters/github/repo.d.ts.map +1 -0
  47. package/dist/adapters/github/repo.js +141 -0
  48. package/dist/adapters/github/repo.js.map +1 -0
  49. package/dist/adapters/github/tool-pack.d.ts +14 -0
  50. package/dist/adapters/github/tool-pack.d.ts.map +1 -0
  51. package/dist/adapters/github/tool-pack.js +56 -0
  52. package/dist/adapters/github/tool-pack.js.map +1 -0
  53. package/dist/adapters/github/tools/checks.d.ts +24 -0
  54. package/dist/adapters/github/tools/checks.d.ts.map +1 -0
  55. package/dist/adapters/github/tools/checks.js +105 -0
  56. package/dist/adapters/github/tools/checks.js.map +1 -0
  57. package/dist/adapters/github/tools/issue.d.ts +22 -0
  58. package/dist/adapters/github/tools/issue.d.ts.map +1 -0
  59. package/dist/adapters/github/tools/issue.js +48 -0
  60. package/dist/adapters/github/tools/issue.js.map +1 -0
  61. package/dist/adapters/github/tools/pr.d.ts +22 -0
  62. package/dist/adapters/github/tools/pr.d.ts.map +1 -0
  63. package/dist/adapters/github/tools/pr.js +48 -0
  64. package/dist/adapters/github/tools/pr.js.map +1 -0
  65. package/dist/adapters/github/tools/read.d.ts +22 -0
  66. package/dist/adapters/github/tools/read.d.ts.map +1 -0
  67. package/dist/adapters/github/tools/read.js +141 -0
  68. package/dist/adapters/github/tools/read.js.map +1 -0
  69. package/dist/adapters/github/tools/review-reply.d.ts +19 -0
  70. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
  71. package/dist/adapters/github/tools/review-reply.js +38 -0
  72. package/dist/adapters/github/tools/review-reply.js.map +1 -0
  73. package/dist/adapters/github/tools/sync.d.ts +17 -0
  74. package/dist/adapters/github/tools/sync.d.ts.map +1 -0
  75. package/dist/adapters/github/tools/sync.js +34 -0
  76. package/dist/adapters/github/tools/sync.js.map +1 -0
  77. package/dist/adapters/github/types.d.ts +350 -0
  78. package/dist/adapters/github/types.d.ts.map +1 -0
  79. package/dist/adapters/github/types.js +2 -0
  80. package/dist/adapters/github/types.js.map +1 -0
  81. package/dist/adapters/intake.d.ts +16 -5
  82. package/dist/adapters/intake.d.ts.map +1 -1
  83. package/dist/adapters/intake.js +79 -22
  84. package/dist/adapters/intake.js.map +1 -1
  85. package/dist/adapters/slack/bot.d.ts +8 -6
  86. package/dist/adapters/slack/bot.d.ts.map +1 -1
  87. package/dist/adapters/slack/bot.js +82 -134
  88. package/dist/adapters/slack/bot.js.map +1 -1
  89. package/dist/adapters/slack/context.d.ts.map +1 -1
  90. package/dist/adapters/slack/context.js +3 -14
  91. package/dist/adapters/slack/context.js.map +1 -1
  92. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  93. package/dist/adapters/slack/response-lifecycle.js +14 -17
  94. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  95. package/dist/adapters/slack/session.d.ts.map +1 -1
  96. package/dist/adapters/slack/session.js +5 -8
  97. package/dist/adapters/slack/session.js.map +1 -1
  98. package/dist/adapters/streaming.d.ts +4 -0
  99. package/dist/adapters/streaming.d.ts.map +1 -1
  100. package/dist/adapters/streaming.js +11 -0
  101. package/dist/adapters/streaming.js.map +1 -1
  102. package/dist/adapters/telegram/bot.d.ts +1 -2
  103. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  104. package/dist/adapters/telegram/bot.js +27 -62
  105. package/dist/adapters/telegram/bot.js.map +1 -1
  106. package/dist/adapters/telegram/context.d.ts.map +1 -1
  107. package/dist/adapters/telegram/context.js +37 -174
  108. package/dist/adapters/telegram/context.js.map +1 -1
  109. package/dist/adapters/types.d.ts +28 -2
  110. package/dist/adapters/types.d.ts.map +1 -1
  111. package/dist/adapters/types.js.map +1 -1
  112. package/dist/agent.d.ts +37 -14
  113. package/dist/agent.d.ts.map +1 -1
  114. package/dist/agent.js +359 -229
  115. package/dist/agent.js.map +1 -1
  116. package/dist/cli/arg-grammar.d.ts +25 -0
  117. package/dist/cli/arg-grammar.d.ts.map +1 -0
  118. package/dist/cli/arg-grammar.js +59 -0
  119. package/dist/cli/arg-grammar.js.map +1 -0
  120. package/dist/cli/boot.d.ts +16 -0
  121. package/dist/cli/boot.d.ts.map +1 -0
  122. package/dist/cli/boot.js +119 -0
  123. package/dist/cli/boot.js.map +1 -0
  124. package/dist/cli/download.d.ts.map +1 -0
  125. package/dist/cli/download.js.map +1 -0
  126. package/dist/cli/ext-git.d.ts +22 -0
  127. package/dist/cli/ext-git.d.ts.map +1 -0
  128. package/dist/cli/ext-git.js +76 -0
  129. package/dist/cli/ext-git.js.map +1 -0
  130. package/dist/cli/ext.d.ts +2 -0
  131. package/dist/cli/ext.d.ts.map +1 -0
  132. package/dist/cli/ext.js +215 -0
  133. package/dist/cli/ext.js.map +1 -0
  134. package/dist/commands/admin.d.ts.map +1 -1
  135. package/dist/commands/admin.js +2 -1
  136. package/dist/commands/admin.js.map +1 -1
  137. package/dist/commands/auto-reply.d.ts.map +1 -1
  138. package/dist/commands/auto-reply.js +2 -6
  139. package/dist/commands/auto-reply.js.map +1 -1
  140. package/dist/commands/extensions.d.ts.map +1 -1
  141. package/dist/commands/extensions.js +18 -8
  142. package/dist/commands/extensions.js.map +1 -1
  143. package/dist/commands/login.d.ts +2 -1
  144. package/dist/commands/login.d.ts.map +1 -1
  145. package/dist/commands/login.js +35 -3
  146. package/dist/commands/login.js.map +1 -1
  147. package/dist/commands/manifest.d.ts +72 -0
  148. package/dist/commands/manifest.d.ts.map +1 -0
  149. package/dist/commands/manifest.js +121 -0
  150. package/dist/commands/manifest.js.map +1 -0
  151. package/dist/commands/model.d.ts.map +1 -1
  152. package/dist/commands/model.js +11 -9
  153. package/dist/commands/model.js.map +1 -1
  154. package/dist/commands/new.d.ts.map +1 -1
  155. package/dist/commands/new.js +2 -1
  156. package/dist/commands/new.js.map +1 -1
  157. package/dist/commands/sandbox.d.ts.map +1 -1
  158. package/dist/commands/sandbox.js +23 -17
  159. package/dist/commands/sandbox.js.map +1 -1
  160. package/dist/commands/text.d.ts +2 -0
  161. package/dist/commands/text.d.ts.map +1 -0
  162. package/dist/commands/text.js +16 -0
  163. package/dist/commands/text.js.map +1 -0
  164. package/dist/commands/types.d.ts +14 -1
  165. package/dist/commands/types.d.ts.map +1 -1
  166. package/dist/commands/types.js.map +1 -1
  167. package/dist/config.d.ts +1 -3
  168. package/dist/config.d.ts.map +1 -1
  169. package/dist/config.js +98 -95
  170. package/dist/config.js.map +1 -1
  171. package/dist/env-manifest.d.ts +35 -0
  172. package/dist/env-manifest.d.ts.map +1 -0
  173. package/dist/env-manifest.js +225 -0
  174. package/dist/env-manifest.js.map +1 -0
  175. package/dist/events.d.ts.map +1 -1
  176. package/dist/events.js +9 -73
  177. package/dist/events.js.map +1 -1
  178. package/dist/execution-resolver.d.ts +4 -2
  179. package/dist/execution-resolver.d.ts.map +1 -1
  180. package/dist/execution-resolver.js +54 -41
  181. package/dist/execution-resolver.js.map +1 -1
  182. package/dist/harness/event-format.d.ts +66 -0
  183. package/dist/harness/event-format.d.ts.map +1 -0
  184. package/dist/harness/event-format.js +112 -0
  185. package/dist/harness/event-format.js.map +1 -0
  186. package/dist/harness/extensions/loader.d.ts +44 -11
  187. package/dist/harness/extensions/loader.d.ts.map +1 -1
  188. package/dist/harness/extensions/loader.js +273 -84
  189. package/dist/harness/extensions/loader.js.map +1 -1
  190. package/dist/harness/extensions/registry.d.ts +48 -1
  191. package/dist/harness/extensions/registry.d.ts.map +1 -1
  192. package/dist/harness/extensions/registry.js +146 -0
  193. package/dist/harness/extensions/registry.js.map +1 -1
  194. package/dist/harness/extensions/types.d.ts +165 -22
  195. package/dist/harness/extensions/types.d.ts.map +1 -1
  196. package/dist/harness/extensions/types.js.map +1 -1
  197. package/dist/harness/index.d.ts +6 -5
  198. package/dist/harness/index.d.ts.map +1 -1
  199. package/dist/harness/index.js +3 -2
  200. package/dist/harness/index.js.map +1 -1
  201. package/dist/harness/models.d.ts +5 -0
  202. package/dist/harness/models.d.ts.map +1 -1
  203. package/dist/harness/models.js +10 -0
  204. package/dist/harness/models.js.map +1 -1
  205. package/dist/harness/runner.d.ts +37 -2
  206. package/dist/harness/runner.d.ts.map +1 -1
  207. package/dist/harness/runner.js +107 -23
  208. package/dist/harness/runner.js.map +1 -1
  209. package/dist/harness/session-store.d.ts +4 -1
  210. package/dist/harness/session-store.d.ts.map +1 -1
  211. package/dist/harness/session-store.js +11 -2
  212. package/dist/harness/session-store.js.map +1 -1
  213. package/dist/harness/subagent-runner.d.ts +34 -0
  214. package/dist/harness/subagent-runner.d.ts.map +1 -0
  215. package/dist/harness/subagent-runner.js +339 -0
  216. package/dist/harness/subagent-runner.js.map +1 -0
  217. package/dist/harness/types.d.ts +53 -0
  218. package/dist/harness/types.d.ts.map +1 -1
  219. package/dist/harness/types.js.map +1 -1
  220. package/dist/index.d.ts +3 -3
  221. package/dist/index.d.ts.map +1 -1
  222. package/dist/index.js +2 -2
  223. package/dist/index.js.map +1 -1
  224. package/dist/main.js +260 -109
  225. package/dist/main.js.map +1 -1
  226. package/dist/observability/instrument.js +6 -4
  227. package/dist/observability/instrument.js.map +1 -1
  228. package/dist/observability/sentry.d.ts.map +1 -1
  229. package/dist/observability/sentry.js +3 -2
  230. package/dist/observability/sentry.js.map +1 -1
  231. package/dist/provisioner.d.ts.map +1 -1
  232. package/dist/provisioner.js +2 -5
  233. package/dist/provisioner.js.map +1 -1
  234. package/dist/runtime/conversation-runtime.d.ts +1 -1
  235. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  236. package/dist/runtime/conversation-runtime.js +276 -43
  237. package/dist/runtime/conversation-runtime.js.map +1 -1
  238. package/dist/runtime/types.d.ts +36 -5
  239. package/dist/runtime/types.d.ts.map +1 -1
  240. package/dist/runtime/types.js.map +1 -1
  241. package/dist/sandbox/cloudflare.d.ts +3 -0
  242. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  243. package/dist/sandbox/cloudflare.js +10 -0
  244. package/dist/sandbox/cloudflare.js.map +1 -1
  245. package/dist/sandbox/container.d.ts +4 -0
  246. package/dist/sandbox/container.d.ts.map +1 -1
  247. package/dist/sandbox/container.js +11 -2
  248. package/dist/sandbox/container.js.map +1 -1
  249. package/dist/sandbox/firecracker.d.ts +3 -0
  250. package/dist/sandbox/firecracker.d.ts.map +1 -1
  251. package/dist/sandbox/firecracker.js +10 -1
  252. package/dist/sandbox/firecracker.js.map +1 -1
  253. package/dist/sandbox/gondolin-bootstrap.d.ts +26 -0
  254. package/dist/sandbox/gondolin-bootstrap.d.ts.map +1 -0
  255. package/dist/sandbox/gondolin-bootstrap.js +27 -0
  256. package/dist/sandbox/gondolin-bootstrap.js.map +1 -0
  257. package/dist/sandbox/gondolin-contract.d.ts +125 -0
  258. package/dist/sandbox/gondolin-contract.d.ts.map +1 -0
  259. package/dist/sandbox/gondolin-contract.js +155 -0
  260. package/dist/sandbox/gondolin-contract.js.map +1 -0
  261. package/dist/sandbox/gondolin-fleet.d.ts +104 -0
  262. package/dist/sandbox/gondolin-fleet.d.ts.map +1 -0
  263. package/dist/sandbox/gondolin-fleet.js +330 -0
  264. package/dist/sandbox/gondolin-fleet.js.map +1 -0
  265. package/dist/sandbox/gondolin-gateway.d.ts +86 -0
  266. package/dist/sandbox/gondolin-gateway.d.ts.map +1 -0
  267. package/dist/sandbox/gondolin-gateway.js +407 -0
  268. package/dist/sandbox/gondolin-gateway.js.map +1 -0
  269. package/dist/sandbox/gondolin-inventory.d.ts +75 -0
  270. package/dist/sandbox/gondolin-inventory.d.ts.map +1 -0
  271. package/dist/sandbox/gondolin-inventory.js +257 -0
  272. package/dist/sandbox/gondolin-inventory.js.map +1 -0
  273. package/dist/sandbox/gondolin-join.d.ts +62 -0
  274. package/dist/sandbox/gondolin-join.d.ts.map +1 -0
  275. package/dist/sandbox/gondolin-join.js +261 -0
  276. package/dist/sandbox/gondolin-join.js.map +1 -0
  277. package/dist/sandbox/gondolin-nfs-advisory.d.ts +15 -0
  278. package/dist/sandbox/gondolin-nfs-advisory.d.ts.map +1 -0
  279. package/dist/sandbox/gondolin-nfs-advisory.js +60 -0
  280. package/dist/sandbox/gondolin-nfs-advisory.js.map +1 -0
  281. package/dist/sandbox/gondolin-placement.d.ts +30 -0
  282. package/dist/sandbox/gondolin-placement.d.ts.map +1 -0
  283. package/dist/sandbox/gondolin-placement.js +77 -0
  284. package/dist/sandbox/gondolin-placement.js.map +1 -0
  285. package/dist/sandbox/gondolin-recovery.d.ts +33 -0
  286. package/dist/sandbox/gondolin-recovery.d.ts.map +1 -0
  287. package/dist/sandbox/gondolin-recovery.js +39 -0
  288. package/dist/sandbox/gondolin-recovery.js.map +1 -0
  289. package/dist/sandbox/gondolin-remote.d.ts +70 -0
  290. package/dist/sandbox/gondolin-remote.d.ts.map +1 -0
  291. package/dist/sandbox/gondolin-remote.js +325 -0
  292. package/dist/sandbox/gondolin-remote.js.map +1 -0
  293. package/dist/sandbox/gondolin-worker-client.d.ts +135 -0
  294. package/dist/sandbox/gondolin-worker-client.d.ts.map +1 -0
  295. package/dist/sandbox/gondolin-worker-client.js +323 -0
  296. package/dist/sandbox/gondolin-worker-client.js.map +1 -0
  297. package/dist/sandbox/gondolin-worker-main.d.ts +2 -0
  298. package/dist/sandbox/gondolin-worker-main.d.ts.map +1 -0
  299. package/dist/sandbox/gondolin-worker-main.js +22 -0
  300. package/dist/sandbox/gondolin-worker-main.js.map +1 -0
  301. package/dist/sandbox/gondolin-worker.d.ts +17 -0
  302. package/dist/sandbox/gondolin-worker.d.ts.map +1 -0
  303. package/dist/sandbox/gondolin-worker.js +201 -0
  304. package/dist/sandbox/gondolin-worker.js.map +1 -0
  305. package/dist/sandbox/gondolin.d.ts +53 -0
  306. package/dist/sandbox/gondolin.d.ts.map +1 -0
  307. package/dist/sandbox/gondolin.js +429 -0
  308. package/dist/sandbox/gondolin.js.map +1 -0
  309. package/dist/sandbox/host.d.ts +3 -0
  310. package/dist/sandbox/host.d.ts.map +1 -1
  311. package/dist/sandbox/host.js +14 -0
  312. package/dist/sandbox/host.js.map +1 -1
  313. package/dist/sandbox/identity.d.ts +21 -0
  314. package/dist/sandbox/identity.d.ts.map +1 -0
  315. package/dist/sandbox/identity.js +36 -0
  316. package/dist/sandbox/identity.js.map +1 -0
  317. package/dist/sandbox/index.d.ts +13 -4
  318. package/dist/sandbox/index.d.ts.map +1 -1
  319. package/dist/sandbox/index.js +19 -3
  320. package/dist/sandbox/index.js.map +1 -1
  321. package/dist/sandbox/types.d.ts +31 -1
  322. package/dist/sandbox/types.d.ts.map +1 -1
  323. package/dist/sandbox/types.js.map +1 -1
  324. package/dist/sandbox/utils.d.ts +12 -0
  325. package/dist/sandbox/utils.d.ts.map +1 -1
  326. package/dist/sandbox/utils.js +38 -0
  327. package/dist/sandbox/utils.js.map +1 -1
  328. package/dist/sessions/chat-history-sync.d.ts +32 -0
  329. package/dist/sessions/chat-history-sync.d.ts.map +1 -0
  330. package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +40 -113
  331. package/dist/sessions/chat-history-sync.js.map +1 -0
  332. package/dist/sessions/conversation-log.d.ts +13 -0
  333. package/dist/sessions/conversation-log.d.ts.map +1 -0
  334. package/dist/sessions/conversation-log.js +47 -0
  335. package/dist/sessions/conversation-log.js.map +1 -0
  336. package/dist/sessions/history-line.d.ts +20 -0
  337. package/dist/sessions/history-line.d.ts.map +1 -0
  338. package/dist/sessions/history-line.js +24 -0
  339. package/dist/sessions/history-line.js.map +1 -0
  340. package/dist/sessions/policy.d.ts.map +1 -1
  341. package/dist/sessions/policy.js +5 -3
  342. package/dist/sessions/policy.js.map +1 -1
  343. package/dist/sessions/rotation.d.ts +2 -0
  344. package/dist/sessions/rotation.d.ts.map +1 -0
  345. package/dist/sessions/rotation.js +39 -0
  346. package/dist/sessions/rotation.js.map +1 -0
  347. package/dist/sessions/session-key.d.ts +31 -0
  348. package/dist/sessions/session-key.d.ts.map +1 -0
  349. package/dist/sessions/session-key.js +44 -0
  350. package/dist/sessions/session-key.js.map +1 -0
  351. package/dist/sessions/store.d.ts.map +1 -1
  352. package/dist/sessions/store.js +6 -12
  353. package/dist/sessions/store.js.map +1 -1
  354. package/dist/sessions/types.d.ts +2 -2
  355. package/dist/sessions/types.d.ts.map +1 -1
  356. package/dist/sessions/types.js.map +1 -1
  357. package/dist/settings-mutation.d.ts +23 -0
  358. package/dist/settings-mutation.d.ts.map +1 -0
  359. package/dist/settings-mutation.js +42 -0
  360. package/dist/settings-mutation.js.map +1 -0
  361. package/dist/tools/bash.d.ts +3 -1
  362. package/dist/tools/bash.d.ts.map +1 -1
  363. package/dist/tools/bash.js +24 -17
  364. package/dist/tools/bash.js.map +1 -1
  365. package/dist/tools/edit.d.ts.map +1 -1
  366. package/dist/tools/edit.js +9 -12
  367. package/dist/tools/edit.js.map +1 -1
  368. package/dist/tools/event.d.ts +1 -1
  369. package/dist/tools/event.d.ts.map +1 -1
  370. package/dist/tools/event.js +53 -43
  371. package/dist/tools/event.js.map +1 -1
  372. package/dist/tools/generate-image.d.ts +17 -0
  373. package/dist/tools/generate-image.d.ts.map +1 -0
  374. package/dist/tools/generate-image.js +63 -0
  375. package/dist/tools/generate-image.js.map +1 -0
  376. package/dist/tools/host-fn-tool.d.ts +21 -0
  377. package/dist/tools/host-fn-tool.d.ts.map +1 -0
  378. package/dist/tools/host-fn-tool.js +32 -0
  379. package/dist/tools/host-fn-tool.js.map +1 -0
  380. package/dist/tools/index.d.ts +17 -2
  381. package/dist/tools/index.d.ts.map +1 -1
  382. package/dist/tools/index.js +28 -3
  383. package/dist/tools/index.js.map +1 -1
  384. package/dist/tools/react.d.ts +15 -0
  385. package/dist/tools/react.d.ts.map +1 -0
  386. package/dist/tools/react.js +29 -0
  387. package/dist/tools/react.js.map +1 -0
  388. package/dist/tools/read.d.ts.map +1 -1
  389. package/dist/tools/read.js +7 -26
  390. package/dist/tools/read.js.map +1 -1
  391. package/dist/tools/sandbox.d.ts +2 -2
  392. package/dist/tools/sandbox.d.ts.map +1 -1
  393. package/dist/tools/sandbox.js +13 -9
  394. package/dist/tools/sandbox.js.map +1 -1
  395. package/dist/tools/subagent-slots.d.ts +28 -0
  396. package/dist/tools/subagent-slots.d.ts.map +1 -0
  397. package/dist/tools/subagent-slots.js +57 -0
  398. package/dist/tools/subagent-slots.js.map +1 -0
  399. package/dist/tools/subagent.d.ts +74 -0
  400. package/dist/tools/subagent.d.ts.map +1 -0
  401. package/dist/tools/subagent.js +335 -0
  402. package/dist/tools/subagent.js.map +1 -0
  403. package/dist/tools/types.d.ts +40 -6
  404. package/dist/tools/types.d.ts.map +1 -1
  405. package/dist/tools/types.js.map +1 -1
  406. package/dist/tools/write.d.ts.map +1 -1
  407. package/dist/tools/write.js +1 -8
  408. package/dist/tools/write.js.map +1 -1
  409. package/dist/trigger.d.ts.map +1 -1
  410. package/dist/trigger.js +1 -2
  411. package/dist/trigger.js.map +1 -1
  412. package/dist/types.d.ts +144 -31
  413. package/dist/types.d.ts.map +1 -1
  414. package/dist/types.js.map +1 -1
  415. package/dist/utils/date.d.ts +1 -1
  416. package/dist/utils/date.js +1 -1
  417. package/dist/utils/date.js.map +1 -1
  418. package/dist/vault/disabled.d.ts +9 -0
  419. package/dist/vault/disabled.d.ts.map +1 -0
  420. package/dist/vault/disabled.js +22 -0
  421. package/dist/vault/disabled.js.map +1 -0
  422. package/dist/vault/index.d.ts +0 -2
  423. package/dist/vault/index.d.ts.map +1 -1
  424. package/dist/vault/index.js +1 -32
  425. package/dist/vault/index.js.map +1 -1
  426. package/dist/vault/injection.d.ts +20 -0
  427. package/dist/vault/injection.d.ts.map +1 -0
  428. package/dist/vault/injection.js +27 -0
  429. package/dist/vault/injection.js.map +1 -0
  430. package/dist/vault/policy.d.ts +20 -0
  431. package/dist/vault/policy.d.ts.map +1 -0
  432. package/dist/vault/policy.js +20 -0
  433. package/dist/vault/policy.js.map +1 -0
  434. package/dist/vault/types.d.ts +0 -2
  435. package/dist/vault/types.d.ts.map +1 -1
  436. package/dist/vault/types.js.map +1 -1
  437. package/dist/web/admin/portal.d.ts +27 -0
  438. package/dist/web/admin/portal.d.ts.map +1 -1
  439. package/dist/web/admin/portal.js +117 -154
  440. package/dist/web/admin/portal.js.map +1 -1
  441. package/dist/web/admin/types.d.ts +6 -0
  442. package/dist/web/admin/types.d.ts.map +1 -1
  443. package/dist/web/admin/types.js.map +1 -1
  444. package/dist/web/agent-events/portal.d.ts.map +1 -1
  445. package/dist/web/agent-events/portal.js +2 -1
  446. package/dist/web/agent-events/portal.js.map +1 -1
  447. package/dist/web/login/oauth.d.ts +2 -3
  448. package/dist/web/login/oauth.d.ts.map +1 -1
  449. package/dist/web/login/oauth.js +0 -31
  450. package/dist/web/login/oauth.js.map +1 -1
  451. package/dist/web/login/portal.js +1 -1
  452. package/dist/web/login/portal.js.map +1 -1
  453. package/dist/web/login/types.d.ts +0 -11
  454. package/dist/web/login/types.d.ts.map +1 -1
  455. package/dist/web/login/types.js.map +1 -1
  456. package/dist/web/portal-shell.d.ts +4 -0
  457. package/dist/web/portal-shell.d.ts.map +1 -0
  458. package/dist/{portal-shell.js → web/portal-shell.js} +2 -2
  459. package/dist/web/portal-shell.js.map +1 -0
  460. package/dist/web/server.d.ts.map +1 -1
  461. package/dist/web/server.js +7 -0
  462. package/dist/web/server.js.map +1 -1
  463. package/dist/web/session-view/command.d.ts.map +1 -1
  464. package/dist/web/session-view/command.js +4 -1
  465. package/dist/web/session-view/command.js.map +1 -1
  466. package/dist/web/session-view/portal.d.ts.map +1 -1
  467. package/dist/web/session-view/portal.js +4 -3
  468. package/dist/web/session-view/portal.js.map +1 -1
  469. package/dist/web/session-view/service.d.ts.map +1 -1
  470. package/dist/web/session-view/service.js +2 -1
  471. package/dist/web/session-view/service.js.map +1 -1
  472. package/dist/web/session-view/types.d.ts +2 -1
  473. package/dist/web/session-view/types.d.ts.map +1 -1
  474. package/dist/web/session-view/types.js.map +1 -1
  475. package/package.json +7 -4
  476. package/dist/download.d.ts.map +0 -1
  477. package/dist/download.js.map +0 -1
  478. package/dist/model-registry.d.ts +0 -4
  479. package/dist/model-registry.d.ts.map +0 -1
  480. package/dist/model-registry.js +0 -7
  481. package/dist/model-registry.js.map +0 -1
  482. package/dist/portal-shell.d.ts +0 -4
  483. package/dist/portal-shell.d.ts.map +0 -1
  484. package/dist/portal-shell.js.map +0 -1
  485. package/dist/runtime/agent-run-controller.d.ts +0 -31
  486. package/dist/runtime/agent-run-controller.d.ts.map +0 -1
  487. package/dist/runtime/agent-run-controller.js +0 -195
  488. package/dist/runtime/agent-run-controller.js.map +0 -1
  489. package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
  490. package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
  491. package/dist/sessions/agent-memory-file-manager.js.map +0 -1
  492. package/dist/vault/routing.d.ts +0 -3
  493. package/dist/vault/routing.d.ts.map +0 -1
  494. package/dist/vault/routing.js +0 -13
  495. package/dist/vault/routing.js.map +0 -1
  496. /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
  497. /package/dist/{download.js → cli/download.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-format.js","sourceRoot":"","sources":["../../src/harness/event-format.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type, type Static } from \"@sinclair/typebox\";\nimport { parseJsonSchemaValue } from \"../utils/file-guards.js\";\n\n/**\n * Single home for the scheduled-event file format (`events/*.json`, the\n * workspace scheduling bus). Every reader and writer — the EventsWatcher\n * scheduler, the agent `event` tool, and the extension schedule API — must go\n * through this module: one schema, one payload union, one parser, one\n * builder. Per-type field rules (`at` for one-shot, `schedule` + `timezone`\n * for periodic) live here and nowhere else.\n */\n\nexport type EventConversationKind = \"direct\" | \"shared\";\n\nexport type EventType = \"immediate\" | \"one-shot\" | \"periodic\";\n\n/** Typebox union for the `type` field, shared by the file schema and the event tool's parameters. */\nexport const EventTypeSchema = Type.Union([\n Type.Literal(\"immediate\"),\n Type.Literal(\"one-shot\"),\n Type.Literal(\"periodic\"),\n]);\n\ninterface EventPayloadBase {\n /** Target platform; may be omitted when only one platform is running. */\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n /** Self-contained task text; event runs do not inherit conversation history. */\n text: string;\n}\n\nexport interface ImmediateEventPayload extends EventPayloadBase {\n type: \"immediate\";\n}\n\nexport interface OneShotEventPayload extends EventPayloadBase {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n}\n\nexport interface PeriodicEventPayload extends EventPayloadBase {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n}\n\n/**\n * Wire shape of one event file. Platform defaulting and conversation-kind\n * inference happen at read time (EventsWatcher), so both stay optional here.\n */\nexport type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;\n\n/**\n * Lenient file-reading schema: every field optional so shape problems surface\n * as the specific missing-field messages below rather than typebox noise.\n * `channelId` is the legacy alias for `conversationId`.\n */\nconst EventFileSchema = Type.Object({\n type: Type.Optional(EventTypeSchema),\n platform: Type.Optional(Type.String()),\n conversationId: Type.Optional(Type.String()),\n channelId: Type.Optional(Type.String()),\n conversationKind: Type.Optional(Type.Union([Type.Literal(\"direct\"), Type.Literal(\"shared\")])),\n userId: Type.Optional(Type.String()),\n text: Type.Optional(Type.String()),\n at: Type.Optional(Type.String()),\n schedule: Type.Optional(Type.String()),\n timezone: Type.Optional(Type.String()),\n});\n\ntype EventFileData = Static<typeof EventFileSchema>;\n\n/**\n * Resolve an event file's conversation id, honoring the legacy `channelId`\n * alias. Alias knowledge is private to the format module: consumers always\n * see `conversationId` on parsed payloads.\n */\nfunction 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\n/**\n * Parse and validate one event file's content into the canonical payload.\n * `filename` appears in error messages. Throws on malformed JSON, wrong\n * field types, and missing required fields (common and per-type).\n */\nexport function parseEventPayload(content: string, filename: string): EventFilePayload {\n const data: EventFileData = parseJsonSchemaValue(content, EventFileSchema, (detail) =>\n detail === \"unexpected JSON shape\"\n ? `Expected top-level JSON object in ${filename}`\n : `Malformed event file ${filename}: ${detail}`,\n );\n const conversationId = resolveEventConversationId(data);\n const { type, text } = data;\n\n if (!type || !conversationId || !text) {\n throw new Error(`Missing required fields (type, conversationId, text) in ${filename}`);\n }\n\n const base = {\n ...(data.platform !== undefined ? { platform: data.platform } : {}),\n conversationId,\n ...(data.conversationKind !== undefined ? { conversationKind: data.conversationKind } : {}),\n ...(data.userId !== undefined ? { userId: data.userId } : {}),\n text,\n };\n\n switch (type) {\n case \"immediate\":\n return { type, ...base };\n\n case \"one-shot\":\n if (typeof data.at !== \"string\" || data.at.length === 0) {\n throw new Error(`Missing 'at' field for one-shot event in ${filename}`);\n }\n return { type, ...base, at: data.at };\n\n case \"periodic\":\n if (typeof data.schedule !== \"string\" || data.schedule.length === 0) {\n throw new Error(`Missing 'schedule' field for periodic event in ${filename}`);\n }\n if (typeof data.timezone !== \"string\" || data.timezone.length === 0) {\n throw new Error(`Missing 'timezone' field for periodic event in ${filename}`);\n }\n return { type, ...base, schedule: data.schedule, timezone: data.timezone };\n }\n}\n\nexport interface EventPayloadInput {\n type: EventType;\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n/**\n * Validate and assemble a new event payload for writing. Owns the per-type\n * field rules; write-side *policy* beyond the format (e.g. the event tool's\n * requirement that `at` lies in the future) stays with the writer.\n */\nexport function buildEventPayload(input: EventPayloadInput): EventFilePayload {\n const base = {\n ...(input.platform !== undefined ? { platform: input.platform } : {}),\n conversationId: input.conversationId,\n ...(input.conversationKind !== undefined ? { conversationKind: input.conversationKind } : {}),\n ...(input.userId !== undefined ? { userId: input.userId } : {}),\n text: input.text,\n };\n\n switch (input.type) {\n case \"immediate\":\n return { type: \"immediate\", ...base };\n\n case \"one-shot\": {\n if (!input.at) {\n throw new Error(\"`at` is required for one-shot events\");\n }\n if (Number.isNaN(new Date(input.at).getTime())) {\n throw new Error(\"`at` must be a valid ISO 8601 timestamp with UTC offset\");\n }\n return { type: \"one-shot\", ...base, at: input.at };\n }\n\n case \"periodic\":\n if (!input.schedule) {\n throw new Error(\"`schedule` is required for periodic events\");\n }\n if (!input.timezone) {\n throw new Error(\"`timezone` is required for periodic events\");\n }\n return { type: \"periodic\", ...base, schedule: input.schedule, timezone: input.timezone };\n }\n}\n"]}
@@ -4,11 +4,11 @@ import { type MikanSkill } from "../skills.js";
4
4
  import { ExtensionRegistry } from "./registry.js";
5
5
  import type { ExtensionHostServices, ExtensionLoadError, LoadedExtension } from "./types.js";
6
6
  /**
7
- * Canonical host-only extension directories for a conversation:
8
- * `<stateDir>/extensions/global` (all conversations) and
9
- * `<stateDir>/extensions/<conversationId>` (that conversation only).
10
- * `global` is reserved as a scope name; platform conversation ids never
11
- * take that value.
7
+ * Canonical host-only extension code directories for a conversation, in load
8
+ * order: `<stateDir>/global/extensions` (all conversations) then
9
+ * `<stateDir>/conversations/<conversationId>/extensions` (that conversation
10
+ * only). `global` and `conversations` are the two sibling scopes; see
11
+ * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).
12
12
  */
13
13
  export declare function defaultExtensionDirs(conversationId: string, stateDir?: string): string[];
14
14
  /** Discovery-only view of an installed extension (module is not imported). */
@@ -48,15 +48,48 @@ 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
- * Filesystem-safe identifier for an extension, derived from its install
54
- * location (directory name for `<name>/index.mjs`, file basename otherwise).
55
- * The slug keys the extension's data dir, secrets vault, and schedule
56
- * ownership — installing the same extension globally and per-conversation
57
- * shares one slug and therefore one data dir.
59
+ * Filesystem-safe identifier for an extension, derived from its root (the
60
+ * install directory, or the file path for a bare-file extension). The slug
61
+ * keys the extension's data dir, secrets vault, and schedule ownership —
62
+ * installing the same extension globally and per-conversation shares one
63
+ * slug and therefore one shared data dir. This is the only slug derivation:
64
+ * a second one keyed off a different input (e.g. the entrypoint, which for
65
+ * package.json-form extensions can live under dist/) would silently split an
66
+ * extension's identity.
58
67
  */
59
- export declare function extensionSlug(entrypoint: string): string;
68
+ export declare function extensionSlug(rootDir: string): string;
60
69
  /** Load and activate all extensions found in the given directories. */
61
70
  export declare function loadExtensions(options: LoadExtensionsOptions): Promise<LoadExtensionsResult>;
71
+ export interface ExtensionValidation {
72
+ ok: boolean;
73
+ /** Slug the extension would install as (from the source dir/file name). */
74
+ slug: string;
75
+ /** Display name (manifest name, else slug). */
76
+ name: string;
77
+ version?: string;
78
+ description?: string;
79
+ /** Resolved entrypoint that would be imported. */
80
+ entrypoint?: string;
81
+ /** Skill names shipped alongside the extension. */
82
+ skillNames: string[];
83
+ errors: string[];
84
+ warnings: string[];
85
+ }
86
+ /**
87
+ * Validate an extension source path (a directory or a single file) WITHOUT
88
+ * activating it: resolves the entrypoint (package.json `mikan.extensions`,
89
+ * index file, or the file itself), imports it, and checks it exports an
90
+ * `activate` function. Used by `mikan ext install` as a preflight and by
91
+ * `mikan ext validate`. Importing runs top-level module code but not
92
+ * `activate`, so there are no schedule/tool side effects.
93
+ */
94
+ export declare function validateExtension(sourcePath: string): Promise<ExtensionValidation>;
62
95
  //# sourceMappingURL=loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"AA0BA,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;AAIpB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,MAAkC,GAC3C,MAAM,EAAE,CAEV;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;AA+BD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAUxD;AAkMD,uEAAuE;AACvE,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAmD/B"}
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;AAGxD,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;AA2HD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIrD;AAmPD,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"}
@@ -12,31 +12,49 @@
12
12
  * under mikan's state dir.
13
13
  *
14
14
  * Directories are scanned in order; all discovered extensions activate.
15
- * Accepted layouts:
15
+ * Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):
16
16
  *
17
- * - `extensions/<name>.mjs` / `extensions/<name>.js`
18
- * - `extensions/<name>/index.mjs` / `extensions/<name>/index.js`
17
+ * - `extensions/<name>.<ext>` (bare file)
18
+ * - `extensions/<name>/index.<ext>` (directory + index)
19
+ * - `extensions/<name>/package.json` (mikan.extensions entrypoint;
20
+ * may carry npm dependencies in node_modules)
19
21
  *
20
- * Modules are imported with a cache-busting query so edited extensions are
21
- * picked up when a new harness instance is created for a conversation.
22
+ * Modules are imported with a fresh jiti instance (no cache) so edited
23
+ * extensions are picked up when a new harness instance is created.
22
24
  */
23
25
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "fs";
24
26
  import { homedir } from "os";
25
- import { basename, dirname, join } from "path";
26
- import { pathToFileURL } from "url";
27
+ import { basename, join } from "path";
28
+ import { createJiti } from "jiti";
27
29
  import * as log from "../../log.js";
30
+ import { buildEventPayload } from "../event-format.js";
28
31
  import { loadSkillsFromDir } from "../skills.js";
29
32
  import { ExtensionRegistry } from "./registry.js";
30
- const EXTENSION_FILE_PATTERN = /\.(mjs|js)$/;
33
+ const EXTENSION_FILE_PATTERN = /\.(mjs|js|ts|mts)$/;
34
+ const INDEX_FILE_PATTERN = /^index\.(mjs|js|ts|mts)$/;
35
+ const INDEX_CANDIDATES = ["index.mjs", "index.js", "index.ts", "index.mts"];
31
36
  /**
32
- * Canonical host-only extension directories for a conversation:
33
- * `<stateDir>/extensions/global` (all conversations) and
34
- * `<stateDir>/extensions/<conversationId>` (that conversation only).
35
- * `global` is reserved as a scope name; platform conversation ids never
36
- * take that value.
37
+ * Import an extension entrypoint through jiti so it can be TypeScript and can
38
+ * use node_modules dependencies, transparently compiling on the fly. A fresh
39
+ * jiti instance with caching disabled is used per load so edited extensions
40
+ * are picked up when a new harness instance is created for a conversation.
41
+ */
42
+ async function importExtensionModule(entrypoint) {
43
+ const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });
44
+ return jiti.import(entrypoint);
45
+ }
46
+ /**
47
+ * Canonical host-only extension code directories for a conversation, in load
48
+ * order: `<stateDir>/global/extensions` (all conversations) then
49
+ * `<stateDir>/conversations/<conversationId>/extensions` (that conversation
50
+ * only). `global` and `conversations` are the two sibling scopes; see
51
+ * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).
37
52
  */
38
53
  export function defaultExtensionDirs(conversationId, stateDir = join(homedir(), ".mikan")) {
39
- return [join(stateDir, "extensions", "global"), join(stateDir, "extensions", conversationId)];
54
+ return [
55
+ join(stateDir, "global", "extensions"),
56
+ join(stateDir, "conversations", conversationId, "extensions"),
57
+ ];
40
58
  }
41
59
  /**
42
60
  * List installed extensions without importing or activating them — safe for
@@ -46,9 +64,9 @@ export function defaultExtensionDirs(conversationId, stateDir = join(homedir(),
46
64
  export function listInstalledExtensions(dirs) {
47
65
  const infos = [];
48
66
  for (const dir of dirs) {
49
- for (const entrypoint of discoverExtensionEntrypoints(dir)) {
50
- const slug = extensionSlug(entrypoint);
51
- const manifest = readManifest(entrypoint);
67
+ for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {
68
+ const slug = extensionSlug(rootDir);
69
+ const manifest = readManifest(rootDir);
52
70
  infos.push({
53
71
  name: manifest.name ?? slug,
54
72
  slug,
@@ -56,7 +74,7 @@ export function listInstalledExtensions(dirs) {
56
74
  dir,
57
75
  version: manifest.version,
58
76
  description: manifest.description,
59
- skillNames: loadExtensionSkills(entrypoint, slug).map((skill) => skill.name),
77
+ skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),
60
78
  });
61
79
  }
62
80
  }
@@ -65,10 +83,18 @@ export function listInstalledExtensions(dirs) {
65
83
  function discoverExtensionEntrypoints(dir) {
66
84
  if (!existsSync(dir))
67
85
  return [];
68
- const entrypoints = [];
86
+ const found = [];
69
87
  for (const name of readdirSync(dir).toSorted()) {
70
88
  if (name.startsWith("."))
71
89
  continue;
90
+ if (INDEX_FILE_PATTERN.test(name)) {
91
+ // An index file at the scan root means the extension's contents were
92
+ // copied into the scope directory itself; the slug would degenerate to
93
+ // the scope name (e.g. the conversation id), mis-keying its data dir,
94
+ // secrets, and schedules. Require a named form instead.
95
+ log.logWarning(`Ignoring extension index file at scope root: ${join(dir, name)}`, "install into a named subdirectory (e.g. extensions/<scope>/my-ext/index.mjs)");
96
+ continue;
97
+ }
72
98
  const fullPath = join(dir, name);
73
99
  let stats;
74
100
  try {
@@ -78,55 +104,126 @@ function discoverExtensionEntrypoints(dir) {
78
104
  continue;
79
105
  }
80
106
  if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {
81
- entrypoints.push(fullPath);
107
+ // Bare-file form: the file is both entrypoint and (its own) root.
108
+ found.push({ entrypoint: fullPath, rootDir: fullPath });
82
109
  continue;
83
110
  }
84
111
  if (stats.isDirectory()) {
85
- for (const candidate of ["index.mjs", "index.js"]) {
86
- const indexPath = join(fullPath, candidate);
87
- if (existsSync(indexPath)) {
88
- entrypoints.push(indexPath);
89
- break;
90
- }
91
- }
112
+ const entrypoint = resolveDirectoryEntrypoint(fullPath);
113
+ if (entrypoint)
114
+ found.push({ entrypoint, rootDir: fullPath });
92
115
  }
93
116
  }
94
- return entrypoints;
117
+ return found;
95
118
  }
96
119
  /**
97
- * Filesystem-safe identifier for an extension, derived from its install
98
- * location (directory name for `<name>/index.mjs`, file basename otherwise).
99
- * The slug keys the extension's data dir, secrets vault, and schedule
100
- * ownership installing the same extension globally and per-conversation
101
- * shares one slug and therefore one data dir.
120
+ * Resolve a directory-form extension's entrypoint. A `package.json` with a
121
+ * `mikan.extensions` array (first entry, relative to the dir) wins — this is
122
+ * how an extension declares a TypeScript entry and pulls in npm dependencies.
123
+ * Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined
124
+ * when neither is present.
102
125
  */
103
- export function extensionSlug(entrypoint) {
104
- const base = /^index\.(mjs|js)$/.test(basename(entrypoint))
105
- ? basename(dirname(entrypoint))
106
- : basename(entrypoint).replace(EXTENSION_FILE_PATTERN, "");
107
- const slug = base
126
+ function resolveDirectoryEntrypoint(dir) {
127
+ const declared = readMikanManifestEntrypoints(dir)[0];
128
+ if (declared) {
129
+ const resolved = join(dir, declared);
130
+ if (existsSync(resolved))
131
+ return resolved;
132
+ log.logWarning(`Extension package.json declares a missing entrypoint: ${resolved}`, "falling back to an index file");
133
+ }
134
+ for (const candidate of INDEX_CANDIDATES) {
135
+ const indexPath = join(dir, candidate);
136
+ if (existsSync(indexPath))
137
+ return indexPath;
138
+ }
139
+ return undefined;
140
+ }
141
+ /** Read and shape a directory's package.json; undefined when absent/malformed. */
142
+ function readPackageJson(dir) {
143
+ const packageJsonPath = join(dir, "package.json");
144
+ if (!existsSync(packageJsonPath))
145
+ return undefined;
146
+ try {
147
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
148
+ if (!parsed || typeof parsed !== "object")
149
+ return undefined;
150
+ const record = parsed;
151
+ const mikanRaw = record.mikan;
152
+ return {
153
+ name: typeof record.name === "string" ? record.name : undefined,
154
+ version: typeof record.version === "string" ? record.version : undefined,
155
+ description: typeof record.description === "string" ? record.description : undefined,
156
+ mikan: {
157
+ extensions: Array.isArray(mikanRaw?.extensions)
158
+ ? mikanRaw.extensions.filter((entry) => typeof entry === "string")
159
+ : undefined,
160
+ displayName: typeof mikanRaw?.displayName === "string" ? mikanRaw.displayName : undefined,
161
+ },
162
+ };
163
+ }
164
+ catch (err) {
165
+ log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));
166
+ return undefined;
167
+ }
168
+ }
169
+ /** Read the `mikan.extensions` entrypoint list from a directory's package.json. */
170
+ function readMikanManifestEntrypoints(dir) {
171
+ return readPackageJson(dir)?.mikan?.extensions ?? [];
172
+ }
173
+ /** The one filesystem-safe segment sanitizer for extension identity and schedule names. */
174
+ function sanitizeSegment(value) {
175
+ return value
108
176
  .toLowerCase()
109
177
  .replace(/[^a-z0-9_-]+/g, "-")
110
178
  .replace(/^-+|-+$/g, "")
111
179
  .slice(0, 64);
112
- return slug || "extension";
180
+ }
181
+ function sanitizeSlug(base) {
182
+ return sanitizeSegment(base) || "extension";
183
+ }
184
+ /**
185
+ * Filesystem-safe identifier for an extension, derived from its root (the
186
+ * install directory, or the file path for a bare-file extension). The slug
187
+ * keys the extension's data dir, secrets vault, and schedule ownership —
188
+ * installing the same extension globally and per-conversation shares one
189
+ * slug and therefore one shared data dir. This is the only slug derivation:
190
+ * a second one keyed off a different input (e.g. the entrypoint, which for
191
+ * package.json-form extensions can live under dist/) would silently split an
192
+ * extension's identity.
193
+ */
194
+ export function extensionSlug(rootDir) {
195
+ return EXTENSION_FILE_PATTERN.test(basename(rootDir))
196
+ ? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, ""))
197
+ : sanitizeSlug(basename(rootDir));
113
198
  }
114
199
  /** Sanitize an extension-chosen schedule name into a filename segment. */
115
200
  function scheduleNameSegment(name) {
116
- const segment = name
117
- .toLowerCase()
118
- .replace(/[^a-z0-9_-]+/g, "-")
119
- .replace(/^-+|-+$/g, "")
120
- .slice(0, 64);
201
+ const segment = sanitizeSegment(name);
121
202
  if (!segment)
122
203
  throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);
123
204
  return segment;
124
205
  }
125
- /** Read `manifest.json` next to a directory-form extension's entrypoint. */
126
- function readManifest(entrypoint) {
127
- if (!/^index\.(mjs|js)$/.test(basename(entrypoint)))
206
+ /**
207
+ * Read display metadata (name/version/description) for a directory-form
208
+ * extension. `package.json` is the primary source — its standard `name`,
209
+ * `version`, `description`, plus an optional `mikan.displayName` that
210
+ * overrides the npm name for the user-facing label (npm names are
211
+ * lowercase/scoped; display names can be arbitrary). A `manifest.json` is a
212
+ * fallback for extensions that ship no package.json.
213
+ */
214
+ function readManifest(rootDir) {
215
+ // Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.
216
+ if (EXTENSION_FILE_PATTERN.test(basename(rootDir)))
128
217
  return {};
129
- const manifestPath = join(dirname(entrypoint), "manifest.json");
218
+ const pkg = readPackageJson(rootDir);
219
+ if (pkg && (pkg.mikan?.displayName ?? pkg.name ?? pkg.version ?? pkg.description)) {
220
+ return {
221
+ name: pkg.mikan?.displayName ?? pkg.name,
222
+ version: pkg.version,
223
+ description: pkg.description,
224
+ };
225
+ }
226
+ const manifestPath = join(rootDir, "manifest.json");
130
227
  if (!existsSync(manifestPath))
131
228
  return {};
132
229
  try {
@@ -150,10 +247,11 @@ function readManifest(entrypoint) {
150
247
  * Marked inline: extension files live under the host-only state dir, which
151
248
  * sandbox containers cannot read, so skill bodies must ride in the prompt.
152
249
  */
153
- function loadExtensionSkills(entrypoint, slug) {
154
- if (!/^index\.(mjs|js)$/.test(basename(entrypoint)))
250
+ function loadExtensionSkills(rootDir, slug) {
251
+ // Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.
252
+ if (EXTENSION_FILE_PATTERN.test(basename(rootDir)))
155
253
  return [];
156
- const skillsDir = join(dirname(entrypoint), "skills");
254
+ const skillsDir = join(rootDir, "skills");
157
255
  if (!existsSync(skillsDir))
158
256
  return [];
159
257
  const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });
@@ -169,42 +267,34 @@ function schedulePrefix(slug, conversationId) {
169
267
  return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;
170
268
  }
171
269
  function payloadFromSpec(spec, conversationId) {
172
- if (spec.type === "periodic") {
173
- if (!spec.schedule || !spec.timezone) {
174
- throw new Error("periodic schedule requires schedule and timezone");
175
- }
176
- return {
177
- type: "periodic",
178
- conversationId,
179
- text: spec.text,
180
- schedule: spec.schedule,
181
- timezone: spec.timezone,
182
- ...(spec.platform ? { platform: spec.platform } : {}),
183
- };
184
- }
185
- if (!spec.at)
186
- throw new Error("one-shot schedule requires at");
187
- return {
188
- type: "one-shot",
270
+ // Per-type validation (schedule/timezone for periodic, at for one-shot)
271
+ // is owned by the event-format builder.
272
+ return buildEventPayload({
273
+ type: spec.type,
189
274
  conversationId,
190
275
  text: spec.text,
191
- at: spec.at,
192
276
  ...(spec.platform ? { platform: spec.platform } : {}),
193
- };
277
+ ...(spec.type === "periodic"
278
+ ? { schedule: spec.schedule, timezone: spec.timezone }
279
+ : { at: spec.at }),
280
+ });
194
281
  }
195
282
  function specFromPayload(payload) {
196
283
  if (payload.type === "periodic") {
197
284
  return {
198
285
  type: "periodic",
199
- schedule: payload.schedule ?? "",
200
- timezone: payload.timezone ?? "",
286
+ schedule: payload.schedule,
287
+ timezone: payload.timezone,
201
288
  text: payload.text,
202
289
  ...(payload.platform ? { platform: payload.platform } : {}),
203
290
  };
204
291
  }
292
+ // `immediate` payloads never appear under the schedules namespace (they
293
+ // live under "extrun."); tolerate them as an empty one-shot rather than
294
+ // widening the spec union.
205
295
  return {
206
296
  type: "one-shot",
207
- at: payload.at ?? "",
297
+ at: payload.type === "one-shot" ? payload.at : "",
208
298
  text: payload.text,
209
299
  ...(payload.platform ? { platform: payload.platform } : {}),
210
300
  };
@@ -223,11 +313,21 @@ function buildExtensionApi(params) {
223
313
  return {
224
314
  on: (hook, handler) => registry.register(name, hook, handler),
225
315
  registerTool: (tool) => registry.registerTool(tool),
316
+ registerCommand: (command) => registry.registerCommand(name, command),
317
+ onDispose: (disposer) => registry.registerDisposer(name, disposer),
226
318
  log: (message) => log.logInfo(`[extension:${name}] ${message}`),
227
319
  context,
228
320
  paths: {
229
321
  get dataDir() {
230
- const dir = join(stateDir, "extension-data", slug);
322
+ // This conversation's own data, co-located with the conversation's
323
+ // other host-only assets; removed when the conversation is deleted.
324
+ const dir = join(stateDir, "conversations", conversationId, "extension-data", slug);
325
+ mkdirSync(dir, { recursive: true });
326
+ return dir;
327
+ },
328
+ get sharedDataDir() {
329
+ // Cross-conversation data under the sibling `global` scope.
330
+ const dir = join(stateDir, "global", "extension-data", slug);
231
331
  mkdirSync(dir, { recursive: true });
232
332
  return dir;
233
333
  },
@@ -264,14 +364,44 @@ function buildExtensionApi(params) {
264
364
  return infos;
265
365
  },
266
366
  },
267
- notify: async (text) => {
367
+ subagent: {
368
+ run: async (request) => {
369
+ if (!services.runSubagent) {
370
+ throw new Error("api.subagent is unavailable: this context provides no subagent runner");
371
+ }
372
+ return services.runSubagent(request, registry.getContributedTools());
373
+ },
374
+ },
375
+ notify: async (text, options) => {
268
376
  if (!services.postMessage) {
269
377
  throw new Error("api.notify is unavailable: this context provides no platform messaging");
270
378
  }
271
- await services.postMessage(conversationId, text);
379
+ await services.postMessage(options?.conversationId ?? conversationId, text);
380
+ },
381
+ react: async (messageTs, emoji) => {
382
+ if (!services.addReaction) {
383
+ throw new Error("api.react is unavailable: this context provides no reaction support");
384
+ }
385
+ await services.addReaction(conversationId, messageTs, emoji);
386
+ },
387
+ uploadFile: async (filePath, title) => {
388
+ if (!services.uploadFile) {
389
+ throw new Error("api.uploadFile is unavailable: this context provides no file uploads");
390
+ }
391
+ await services.uploadFile(conversationId, filePath, title);
392
+ },
393
+ triggerRun: async (text) => {
394
+ const store = requireScheduleStore();
395
+ // Distinct "extrun." namespace: run files must never surface in
396
+ // api.schedules.list(), whose ownership filter is the "ext." prefix.
397
+ // The embedder's watcher fires and deletes the file immediately.
398
+ const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;
399
+ await store.write(filename, { type: "immediate", conversationId, text });
272
400
  },
273
401
  };
274
402
  }
403
+ /** Monotonic suffix so rapid triggerRun calls in one process never collide. */
404
+ let runCounter = 0;
275
405
  function resolveActivate(moduleExports) {
276
406
  if (!moduleExports || typeof moduleExports !== "object")
277
407
  return undefined;
@@ -302,10 +432,9 @@ export async function loadExtensions(options) {
302
432
  const skills = [];
303
433
  const services = options.services ?? {};
304
434
  for (const dir of options.dirs) {
305
- for (const entrypoint of discoverExtensionEntrypoints(dir)) {
435
+ for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {
306
436
  try {
307
- const moduleUrl = `${pathToFileURL(entrypoint).href}?t=${Date.now()}`;
308
- const moduleExports = await import(moduleUrl);
437
+ const moduleExports = await importExtensionModule(entrypoint);
309
438
  const extension = resolveActivate(moduleExports);
310
439
  if (!extension) {
311
440
  errors.push({
@@ -314,8 +443,8 @@ export async function loadExtensions(options) {
314
443
  });
315
444
  continue;
316
445
  }
317
- const slug = extensionSlug(entrypoint);
318
- const manifest = readManifest(entrypoint);
446
+ const slug = extensionSlug(rootDir);
447
+ const manifest = readManifest(rootDir);
319
448
  const name = manifest.name ?? extension.name ?? slug;
320
449
  const api = buildExtensionApi({
321
450
  name,
@@ -324,8 +453,10 @@ export async function loadExtensions(options) {
324
453
  context: options.context,
325
454
  services,
326
455
  });
327
- await extension.activate(api);
328
- const extensionSkills = loadExtensionSkills(entrypoint, slug);
456
+ const disposer = await extension.activate(api);
457
+ if (typeof disposer === "function")
458
+ registry.registerDisposer(name, disposer);
459
+ const extensionSkills = loadExtensionSkills(rootDir, slug);
329
460
  skills.push(...extensionSkills);
330
461
  extensions.push({
331
462
  name,
@@ -344,6 +475,64 @@ export async function loadExtensions(options) {
344
475
  }
345
476
  }
346
477
  }
347
- return { registry, extensions, errors, skills };
478
+ return { registry, extensions, errors, skills, dispose: () => registry.dispose() };
479
+ }
480
+ /**
481
+ * Validate an extension source path (a directory or a single file) WITHOUT
482
+ * activating it: resolves the entrypoint (package.json `mikan.extensions`,
483
+ * index file, or the file itself), imports it, and checks it exports an
484
+ * `activate` function. Used by `mikan ext install` as a preflight and by
485
+ * `mikan ext validate`. Importing runs top-level module code but not
486
+ * `activate`, so there are no schedule/tool side effects.
487
+ */
488
+ export async function validateExtension(sourcePath) {
489
+ const errors = [];
490
+ const warnings = [];
491
+ const rootDir = sourcePath.replace(/[/\\]+$/, "");
492
+ const base = basename(rootDir);
493
+ if (INDEX_FILE_PATTERN.test(base)) {
494
+ warnings.push("Entry is a bare index file; install into a named directory so the slug is stable.");
495
+ }
496
+ let entrypoint;
497
+ if (!existsSync(rootDir)) {
498
+ errors.push(`Path does not exist: ${rootDir}`);
499
+ }
500
+ else if (statSync(rootDir).isDirectory()) {
501
+ entrypoint = resolveDirectoryEntrypoint(rootDir);
502
+ if (!entrypoint) {
503
+ errors.push("No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.");
504
+ }
505
+ }
506
+ else if (EXTENSION_FILE_PATTERN.test(base)) {
507
+ entrypoint = rootDir;
508
+ }
509
+ else {
510
+ errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);
511
+ }
512
+ const slug = extensionSlug(rootDir);
513
+ const manifest = readManifest(rootDir);
514
+ const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);
515
+ if (entrypoint) {
516
+ try {
517
+ const moduleExports = await importExtensionModule(entrypoint);
518
+ if (!resolveActivate(moduleExports)) {
519
+ errors.push("Module does not export an activate function (default or named).");
520
+ }
521
+ }
522
+ catch (err) {
523
+ errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);
524
+ }
525
+ }
526
+ return {
527
+ ok: errors.length === 0,
528
+ slug,
529
+ name: manifest.name ?? slug,
530
+ version: manifest.version,
531
+ description: manifest.description,
532
+ entrypoint,
533
+ skillNames,
534
+ errors,
535
+ warnings,
536
+ };
348
537
  }
349
538
  //# sourceMappingURL=loader.js.map