@geminixiang/mikan 1.0.0-beta.4 → 1.0.0-beta.41

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 (661) hide show
  1. package/CHANGELOG.md +714 -0
  2. package/README.md +99 -36
  3. package/dist/adapter.d.ts +11 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +18 -1
  6. package/dist/adapter.js.map +1 -1
  7. package/dist/adapters/discord/bot.d.ts +6 -7
  8. package/dist/adapters/discord/bot.d.ts.map +1 -1
  9. package/dist/adapters/discord/bot.js +88 -122
  10. package/dist/adapters/discord/bot.js.map +1 -1
  11. package/dist/adapters/discord/components.d.ts +33 -0
  12. package/dist/adapters/discord/components.d.ts.map +1 -0
  13. package/dist/adapters/discord/components.js +32 -0
  14. package/dist/adapters/discord/components.js.map +1 -0
  15. package/dist/adapters/discord/context.d.ts +3 -1
  16. package/dist/adapters/discord/context.d.ts.map +1 -1
  17. package/dist/adapters/discord/context.js +66 -217
  18. package/dist/adapters/discord/context.js.map +1 -1
  19. package/dist/adapters/discord/format.d.ts +3 -0
  20. package/dist/adapters/discord/format.d.ts.map +1 -0
  21. package/dist/adapters/discord/format.js +86 -0
  22. package/dist/adapters/discord/format.js.map +1 -0
  23. package/dist/adapters/github/bot.d.ts +89 -0
  24. package/dist/adapters/github/bot.d.ts.map +1 -0
  25. package/dist/adapters/github/bot.js +653 -0
  26. package/dist/adapters/github/bot.js.map +1 -0
  27. package/dist/adapters/github/client.d.ts +122 -0
  28. package/dist/adapters/github/client.d.ts.map +1 -0
  29. package/dist/adapters/github/client.js +314 -0
  30. package/dist/adapters/github/client.js.map +1 -0
  31. package/dist/adapters/github/cloudbuild.d.ts +19 -0
  32. package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
  33. package/dist/adapters/github/cloudbuild.js +71 -0
  34. package/dist/adapters/github/cloudbuild.js.map +1 -0
  35. package/dist/adapters/github/context.d.ts +12 -0
  36. package/dist/adapters/github/context.d.ts.map +1 -0
  37. package/dist/adapters/github/context.js +101 -0
  38. package/dist/adapters/github/context.js.map +1 -0
  39. package/dist/adapters/github/gcp-auth.d.ts +28 -0
  40. package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
  41. package/dist/adapters/github/gcp-auth.js +196 -0
  42. package/dist/adapters/github/gcp-auth.js.map +1 -0
  43. package/dist/adapters/github/github-ops.d.ts +91 -0
  44. package/dist/adapters/github/github-ops.d.ts.map +1 -0
  45. package/dist/adapters/github/github-ops.js +406 -0
  46. package/dist/adapters/github/github-ops.js.map +1 -0
  47. package/dist/adapters/github/ids.d.ts +34 -0
  48. package/dist/adapters/github/ids.d.ts.map +1 -0
  49. package/dist/adapters/github/ids.js +57 -0
  50. package/dist/adapters/github/ids.js.map +1 -0
  51. package/dist/adapters/github/repo.d.ts +33 -0
  52. package/dist/adapters/github/repo.d.ts.map +1 -0
  53. package/dist/adapters/github/repo.js +141 -0
  54. package/dist/adapters/github/repo.js.map +1 -0
  55. package/dist/adapters/github/tool-pack.d.ts +14 -0
  56. package/dist/adapters/github/tool-pack.d.ts.map +1 -0
  57. package/dist/adapters/github/tool-pack.js +56 -0
  58. package/dist/adapters/github/tool-pack.js.map +1 -0
  59. package/dist/adapters/github/tools/checks.d.ts +19 -0
  60. package/dist/adapters/github/tools/checks.d.ts.map +1 -0
  61. package/dist/adapters/github/tools/checks.js +105 -0
  62. package/dist/adapters/github/tools/checks.js.map +1 -0
  63. package/dist/adapters/github/tools/issue.d.ts +21 -0
  64. package/dist/adapters/github/tools/issue.d.ts.map +1 -0
  65. package/dist/adapters/github/tools/issue.js +48 -0
  66. package/dist/adapters/github/tools/issue.js.map +1 -0
  67. package/dist/adapters/github/tools/pr.d.ts +22 -0
  68. package/dist/adapters/github/tools/pr.d.ts.map +1 -0
  69. package/dist/adapters/github/tools/pr.js +48 -0
  70. package/dist/adapters/github/tools/pr.js.map +1 -0
  71. package/dist/adapters/github/tools/read.d.ts +21 -0
  72. package/dist/adapters/github/tools/read.d.ts.map +1 -0
  73. package/dist/adapters/github/tools/read.js +141 -0
  74. package/dist/adapters/github/tools/read.js.map +1 -0
  75. package/dist/adapters/github/tools/review-reply.d.ts +17 -0
  76. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
  77. package/dist/adapters/github/tools/review-reply.js +38 -0
  78. package/dist/adapters/github/tools/review-reply.js.map +1 -0
  79. package/dist/adapters/github/tools/sync.d.ts +17 -0
  80. package/dist/adapters/github/tools/sync.d.ts.map +1 -0
  81. package/dist/adapters/github/tools/sync.js +34 -0
  82. package/dist/adapters/github/tools/sync.js.map +1 -0
  83. package/dist/adapters/github/types.d.ts +373 -0
  84. package/dist/adapters/github/types.d.ts.map +1 -0
  85. package/dist/adapters/github/types.js +2 -0
  86. package/dist/adapters/github/types.js.map +1 -0
  87. package/dist/adapters/intake.d.ts +16 -5
  88. package/dist/adapters/intake.d.ts.map +1 -1
  89. package/dist/adapters/intake.js +86 -23
  90. package/dist/adapters/intake.js.map +1 -1
  91. package/dist/adapters/markdown-tables.d.ts +37 -0
  92. package/dist/adapters/markdown-tables.d.ts.map +1 -0
  93. package/dist/adapters/markdown-tables.js +164 -0
  94. package/dist/adapters/markdown-tables.js.map +1 -0
  95. package/dist/adapters/progressive-renderer.d.ts +7 -0
  96. package/dist/adapters/progressive-renderer.d.ts.map +1 -0
  97. package/dist/adapters/progressive-renderer.js +440 -0
  98. package/dist/adapters/progressive-renderer.js.map +1 -0
  99. package/dist/adapters/shared.d.ts +23 -10
  100. package/dist/adapters/shared.d.ts.map +1 -1
  101. package/dist/adapters/shared.js +60 -22
  102. package/dist/adapters/shared.js.map +1 -1
  103. package/dist/adapters/slack/assistant.d.ts +101 -0
  104. package/dist/adapters/slack/assistant.d.ts.map +1 -0
  105. package/dist/adapters/slack/assistant.js +204 -0
  106. package/dist/adapters/slack/assistant.js.map +1 -0
  107. package/dist/adapters/slack/blocks.d.ts +14 -0
  108. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  109. package/dist/adapters/slack/blocks.js +105 -147
  110. package/dist/adapters/slack/blocks.js.map +1 -1
  111. package/dist/adapters/slack/bot.d.ts +95 -13
  112. package/dist/adapters/slack/bot.d.ts.map +1 -1
  113. package/dist/adapters/slack/bot.js +545 -211
  114. package/dist/adapters/slack/bot.js.map +1 -1
  115. package/dist/adapters/slack/context.d.ts +3 -1
  116. package/dist/adapters/slack/context.d.ts.map +1 -1
  117. package/dist/adapters/slack/context.js +11 -17
  118. package/dist/adapters/slack/context.js.map +1 -1
  119. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  120. package/dist/adapters/slack/response-lifecycle.js +197 -323
  121. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  122. package/dist/adapters/slack/session.d.ts.map +1 -1
  123. package/dist/adapters/slack/session.js +7 -11
  124. package/dist/adapters/slack/session.js.map +1 -1
  125. package/dist/adapters/slack/stream-limits.d.ts +35 -0
  126. package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
  127. package/dist/adapters/slack/stream-limits.js +56 -0
  128. package/dist/adapters/slack/stream-limits.js.map +1 -0
  129. package/dist/adapters/slack/tool-pack.d.ts +11 -0
  130. package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
  131. package/dist/adapters/slack/tool-pack.js +45 -0
  132. package/dist/adapters/slack/tool-pack.js.map +1 -0
  133. package/dist/adapters/slack/tools/attach.js +1 -1
  134. package/dist/adapters/slack/tools/attach.js.map +1 -1
  135. package/dist/adapters/slack/tools/blockkit.d.ts +14 -0
  136. package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
  137. package/dist/adapters/slack/tools/blockkit.js +106 -0
  138. package/dist/adapters/slack/tools/blockkit.js.map +1 -0
  139. package/dist/adapters/slack/types.d.ts +40 -2
  140. package/dist/adapters/slack/types.d.ts.map +1 -1
  141. package/dist/adapters/slack/types.js.map +1 -1
  142. package/dist/adapters/telegram/bot.d.ts +8 -9
  143. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  144. package/dist/adapters/telegram/bot.js +115 -163
  145. package/dist/adapters/telegram/bot.js.map +1 -1
  146. package/dist/adapters/telegram/context.d.ts +2 -0
  147. package/dist/adapters/telegram/context.d.ts.map +1 -1
  148. package/dist/adapters/telegram/context.js +53 -188
  149. package/dist/adapters/telegram/context.js.map +1 -1
  150. package/dist/adapters/types.d.ts +132 -12
  151. package/dist/adapters/types.d.ts.map +1 -1
  152. package/dist/adapters/types.js.map +1 -1
  153. package/dist/agent-events.d.ts +3 -2
  154. package/dist/agent-events.d.ts.map +1 -1
  155. package/dist/agent-events.js +19 -1
  156. package/dist/agent-events.js.map +1 -1
  157. package/dist/agent.d.ts +14 -19
  158. package/dist/agent.d.ts.map +1 -1
  159. package/dist/agent.js +841 -298
  160. package/dist/agent.js.map +1 -1
  161. package/dist/cli/arg-grammar.d.ts +25 -0
  162. package/dist/cli/arg-grammar.d.ts.map +1 -0
  163. package/dist/cli/arg-grammar.js +61 -0
  164. package/dist/cli/arg-grammar.js.map +1 -0
  165. package/dist/cli/boot.d.ts +5 -0
  166. package/dist/cli/boot.d.ts.map +1 -0
  167. package/dist/cli/boot.js +117 -0
  168. package/dist/cli/boot.js.map +1 -0
  169. package/dist/cli/download.d.ts.map +1 -0
  170. package/dist/{download.js → cli/download.js} +2 -0
  171. package/dist/cli/download.js.map +1 -0
  172. package/dist/cli/ext-dev.d.ts +2 -0
  173. package/dist/cli/ext-dev.d.ts.map +1 -0
  174. package/dist/cli/ext-dev.js +188 -0
  175. package/dist/cli/ext-dev.js.map +1 -0
  176. package/dist/cli/ext.d.ts +2 -0
  177. package/dist/cli/ext.d.ts.map +1 -0
  178. package/dist/cli/ext.js +324 -0
  179. package/dist/cli/ext.js.map +1 -0
  180. package/dist/cli/office.d.ts +2 -0
  181. package/dist/cli/office.d.ts.map +1 -0
  182. package/dist/cli/office.js +91 -0
  183. package/dist/cli/office.js.map +1 -0
  184. package/dist/cli/types.d.ts +16 -0
  185. package/dist/cli/types.d.ts.map +1 -0
  186. package/dist/cli/types.js +2 -0
  187. package/dist/cli/types.js.map +1 -0
  188. package/dist/commands/admin.d.ts.map +1 -1
  189. package/dist/commands/admin.js +3 -2
  190. package/dist/commands/admin.js.map +1 -1
  191. package/dist/commands/auto-reply.d.ts.map +1 -1
  192. package/dist/commands/auto-reply.js +5 -9
  193. package/dist/commands/auto-reply.js.map +1 -1
  194. package/dist/commands/extensions.d.ts +18 -6
  195. package/dist/commands/extensions.d.ts.map +1 -1
  196. package/dist/commands/extensions.js +64 -14
  197. package/dist/commands/extensions.js.map +1 -1
  198. package/dist/commands/login.d.ts +2 -1
  199. package/dist/commands/login.d.ts.map +1 -1
  200. package/dist/commands/login.js +40 -5
  201. package/dist/commands/login.js.map +1 -1
  202. package/dist/commands/manifest.d.ts +37 -0
  203. package/dist/commands/manifest.d.ts.map +1 -0
  204. package/dist/commands/manifest.js +151 -0
  205. package/dist/commands/manifest.js.map +1 -0
  206. package/dist/commands/model.d.ts +2 -3
  207. package/dist/commands/model.d.ts.map +1 -1
  208. package/dist/commands/model.js +63 -24
  209. package/dist/commands/model.js.map +1 -1
  210. package/dist/commands/new.d.ts.map +1 -1
  211. package/dist/commands/new.js +15 -3
  212. package/dist/commands/new.js.map +1 -1
  213. package/dist/commands/registry.d.ts +2 -2
  214. package/dist/commands/registry.d.ts.map +1 -1
  215. package/dist/commands/registry.js +1 -2
  216. package/dist/commands/registry.js.map +1 -1
  217. package/dist/commands/sandbox.d.ts.map +1 -1
  218. package/dist/commands/sandbox.js +83 -33
  219. package/dist/commands/sandbox.js.map +1 -1
  220. package/dist/commands/session-view.d.ts.map +1 -1
  221. package/dist/commands/session-view.js +6 -3
  222. package/dist/commands/session-view.js.map +1 -1
  223. package/dist/commands/types.d.ts +79 -7
  224. package/dist/commands/types.d.ts.map +1 -1
  225. package/dist/commands/types.js.map +1 -1
  226. package/dist/config.d.ts +23 -8
  227. package/dist/config.d.ts.map +1 -1
  228. package/dist/config.js +222 -135
  229. package/dist/config.js.map +1 -1
  230. package/dist/env-manifest.d.ts +30 -0
  231. package/dist/env-manifest.d.ts.map +1 -0
  232. package/dist/env-manifest.js +233 -0
  233. package/dist/env-manifest.js.map +1 -0
  234. package/dist/events.d.ts.map +1 -1
  235. package/dist/events.js +20 -81
  236. package/dist/events.js.map +1 -1
  237. package/dist/execution-resolver.d.ts +7 -8
  238. package/dist/execution-resolver.d.ts.map +1 -1
  239. package/dist/execution-resolver.js +106 -110
  240. package/dist/execution-resolver.js.map +1 -1
  241. package/dist/extension-schedules.d.ts +31 -0
  242. package/dist/extension-schedules.d.ts.map +1 -0
  243. package/dist/extension-schedules.js +229 -0
  244. package/dist/extension-schedules.js.map +1 -0
  245. package/dist/harness/auth.d.ts +2 -1
  246. package/dist/harness/auth.d.ts.map +1 -1
  247. package/dist/harness/auth.js +11 -5
  248. package/dist/harness/auth.js.map +1 -1
  249. package/dist/harness/event-format.d.ts +27 -0
  250. package/dist/harness/event-format.d.ts.map +1 -0
  251. package/dist/harness/event-format.js +160 -0
  252. package/dist/harness/event-format.js.map +1 -0
  253. package/dist/harness/extensions/loader.d.ts +27 -49
  254. package/dist/harness/extensions/loader.d.ts.map +1 -1
  255. package/dist/harness/extensions/loader.js +486 -130
  256. package/dist/harness/extensions/loader.js.map +1 -1
  257. package/dist/harness/extensions/registry.d.ts +107 -2
  258. package/dist/harness/extensions/registry.d.ts.map +1 -1
  259. package/dist/harness/extensions/registry.js +316 -0
  260. package/dist/harness/extensions/registry.js.map +1 -1
  261. package/dist/harness/extensions/types.d.ts +482 -42
  262. package/dist/harness/extensions/types.d.ts.map +1 -1
  263. package/dist/harness/extensions/types.js.map +1 -1
  264. package/dist/harness/index.d.ts +18 -8
  265. package/dist/harness/index.d.ts.map +1 -1
  266. package/dist/harness/index.js +7 -4
  267. package/dist/harness/index.js.map +1 -1
  268. package/dist/harness/models.d.ts +7 -4
  269. package/dist/harness/models.d.ts.map +1 -1
  270. package/dist/harness/models.js +46 -24
  271. package/dist/harness/models.js.map +1 -1
  272. package/dist/harness/runner.d.ts +50 -54
  273. package/dist/harness/runner.d.ts.map +1 -1
  274. package/dist/harness/runner.js +232 -46
  275. package/dist/harness/runner.js.map +1 -1
  276. package/dist/harness/session-store.d.ts +11 -5
  277. package/dist/harness/session-store.d.ts.map +1 -1
  278. package/dist/harness/session-store.js +141 -36
  279. package/dist/harness/session-store.js.map +1 -1
  280. package/dist/harness/settings.d.ts +2 -20
  281. package/dist/harness/settings.d.ts.map +1 -1
  282. package/dist/harness/settings.js +12 -1
  283. package/dist/harness/settings.js.map +1 -1
  284. package/dist/harness/skills.d.ts +10 -29
  285. package/dist/harness/skills.d.ts.map +1 -1
  286. package/dist/harness/skills.js +48 -6
  287. package/dist/harness/skills.js.map +1 -1
  288. package/dist/harness/subagent-profiles.d.ts +8 -0
  289. package/dist/harness/subagent-profiles.d.ts.map +1 -0
  290. package/dist/harness/subagent-profiles.js +299 -0
  291. package/dist/harness/subagent-profiles.js.map +1 -0
  292. package/dist/harness/subagent-runner.d.ts +45 -0
  293. package/dist/harness/subagent-runner.d.ts.map +1 -0
  294. package/dist/harness/subagent-runner.js +680 -0
  295. package/dist/harness/subagent-runner.js.map +1 -0
  296. package/dist/harness/types.d.ts +267 -1
  297. package/dist/harness/types.d.ts.map +1 -1
  298. package/dist/harness/types.js.map +1 -1
  299. package/dist/harness/usage.d.ts +6 -0
  300. package/dist/harness/usage.d.ts.map +1 -0
  301. package/dist/harness/usage.js +32 -0
  302. package/dist/harness/usage.js.map +1 -0
  303. package/dist/index.d.ts +36 -8
  304. package/dist/index.d.ts.map +1 -1
  305. package/dist/index.js +22 -6
  306. package/dist/index.js.map +1 -1
  307. package/dist/main.js +391 -127
  308. package/dist/main.js.map +1 -1
  309. package/dist/observability/instrument.js +7 -5
  310. package/dist/observability/instrument.js.map +1 -1
  311. package/dist/observability/sentry.d.ts +2 -0
  312. package/dist/observability/sentry.d.ts.map +1 -1
  313. package/dist/observability/sentry.js +10 -2
  314. package/dist/observability/sentry.js.map +1 -1
  315. package/dist/office/address.d.ts +31 -0
  316. package/dist/office/address.d.ts.map +1 -0
  317. package/dist/office/address.js +113 -0
  318. package/dist/office/address.js.map +1 -0
  319. package/dist/office/index.d.ts +11 -0
  320. package/dist/office/index.d.ts.map +1 -0
  321. package/dist/office/index.js +11 -0
  322. package/dist/office/index.js.map +1 -0
  323. package/dist/office/layout.d.ts +27 -0
  324. package/dist/office/layout.d.ts.map +1 -0
  325. package/dist/office/layout.js +97 -0
  326. package/dist/office/layout.js.map +1 -0
  327. package/dist/office/migration.d.ts +44 -0
  328. package/dist/office/migration.d.ts.map +1 -0
  329. package/dist/office/migration.js +255 -0
  330. package/dist/office/migration.js.map +1 -0
  331. package/dist/office/registry.d.ts +75 -0
  332. package/dist/office/registry.d.ts.map +1 -0
  333. package/dist/office/registry.js +646 -0
  334. package/dist/office/registry.js.map +1 -0
  335. package/dist/office/types.d.ts +71 -0
  336. package/dist/office/types.d.ts.map +1 -0
  337. package/dist/office/types.js +2 -0
  338. package/dist/office/types.js.map +1 -0
  339. package/dist/packages/admin.d.ts +17 -0
  340. package/dist/packages/admin.d.ts.map +1 -0
  341. package/dist/packages/admin.js +98 -0
  342. package/dist/packages/admin.js.map +1 -0
  343. package/dist/packages/index.d.ts +6 -0
  344. package/dist/packages/index.d.ts.map +1 -0
  345. package/dist/packages/index.js +6 -0
  346. package/dist/packages/index.js.map +1 -0
  347. package/dist/packages/inspect.d.ts +11 -0
  348. package/dist/packages/inspect.d.ts.map +1 -0
  349. package/dist/packages/inspect.js +98 -0
  350. package/dist/packages/inspect.js.map +1 -0
  351. package/dist/packages/materialize.d.ts +40 -0
  352. package/dist/packages/materialize.d.ts.map +1 -0
  353. package/dist/packages/materialize.js +297 -0
  354. package/dist/packages/materialize.js.map +1 -0
  355. package/dist/packages/resolve.d.ts +25 -0
  356. package/dist/packages/resolve.d.ts.map +1 -0
  357. package/dist/packages/resolve.js +208 -0
  358. package/dist/packages/resolve.js.map +1 -0
  359. package/dist/packages/source.d.ts +39 -0
  360. package/dist/packages/source.d.ts.map +1 -0
  361. package/dist/packages/source.js +189 -0
  362. package/dist/packages/source.js.map +1 -0
  363. package/dist/packages/types.d.ts +104 -0
  364. package/dist/packages/types.d.ts.map +1 -0
  365. package/dist/packages/types.js +2 -0
  366. package/dist/packages/types.js.map +1 -0
  367. package/dist/provisioner.d.ts +66 -0
  368. package/dist/provisioner.d.ts.map +1 -1
  369. package/dist/provisioner.js +335 -13
  370. package/dist/provisioner.js.map +1 -1
  371. package/dist/runtime/conversation-runtime.d.ts +1 -1
  372. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  373. package/dist/runtime/conversation-runtime.js +562 -118
  374. package/dist/runtime/conversation-runtime.js.map +1 -1
  375. package/dist/runtime/session-lifecycle.d.ts +38 -0
  376. package/dist/runtime/session-lifecycle.d.ts.map +1 -0
  377. package/dist/runtime/session-lifecycle.js +193 -0
  378. package/dist/runtime/session-lifecycle.js.map +1 -0
  379. package/dist/runtime/types.d.ts +66 -7
  380. package/dist/runtime/types.d.ts.map +1 -1
  381. package/dist/runtime/types.js.map +1 -1
  382. package/dist/sandbox/cloudflare.d.ts +3 -0
  383. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  384. package/dist/sandbox/cloudflare.js +13 -1
  385. package/dist/sandbox/cloudflare.js.map +1 -1
  386. package/dist/sandbox/container.d.ts +4 -0
  387. package/dist/sandbox/container.d.ts.map +1 -1
  388. package/dist/sandbox/container.js +13 -3
  389. package/dist/sandbox/container.js.map +1 -1
  390. package/dist/sandbox/firecracker.d.ts +3 -0
  391. package/dist/sandbox/firecracker.d.ts.map +1 -1
  392. package/dist/sandbox/firecracker.js +13 -2
  393. package/dist/sandbox/firecracker.js.map +1 -1
  394. package/dist/sandbox/gondolin.d.ts +57 -0
  395. package/dist/sandbox/gondolin.d.ts.map +1 -0
  396. package/dist/sandbox/gondolin.js +764 -0
  397. package/dist/sandbox/gondolin.js.map +1 -0
  398. package/dist/sandbox/host.d.ts +3 -0
  399. package/dist/sandbox/host.d.ts.map +1 -1
  400. package/dist/sandbox/host.js +18 -3
  401. package/dist/sandbox/host.js.map +1 -1
  402. package/dist/sandbox/identity.d.ts +44 -0
  403. package/dist/sandbox/identity.d.ts.map +1 -0
  404. package/dist/sandbox/identity.js +68 -0
  405. package/dist/sandbox/identity.js.map +1 -0
  406. package/dist/sandbox/image.d.ts.map +1 -1
  407. package/dist/sandbox/image.js +2 -0
  408. package/dist/sandbox/image.js.map +1 -1
  409. package/dist/sandbox/index.d.ts +17 -4
  410. package/dist/sandbox/index.d.ts.map +1 -1
  411. package/dist/sandbox/index.js +37 -3
  412. package/dist/sandbox/index.js.map +1 -1
  413. package/dist/sandbox/types.d.ts +65 -1
  414. package/dist/sandbox/types.d.ts.map +1 -1
  415. package/dist/sandbox/types.js.map +1 -1
  416. package/dist/sandbox/utils.d.ts +14 -0
  417. package/dist/sandbox/utils.d.ts.map +1 -1
  418. package/dist/sandbox/utils.js +68 -1
  419. package/dist/sandbox/utils.js.map +1 -1
  420. package/dist/sessions/chat-history-sync.d.ts +25 -0
  421. package/dist/sessions/chat-history-sync.d.ts.map +1 -0
  422. package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +135 -131
  423. package/dist/sessions/chat-history-sync.js.map +1 -0
  424. package/dist/sessions/conversation-log.d.ts +9 -0
  425. package/dist/sessions/conversation-log.d.ts.map +1 -0
  426. package/dist/sessions/conversation-log.js +50 -0
  427. package/dist/sessions/conversation-log.js.map +1 -0
  428. package/dist/sessions/history-line.d.ts +29 -0
  429. package/dist/sessions/history-line.d.ts.map +1 -0
  430. package/dist/sessions/history-line.js +45 -0
  431. package/dist/sessions/history-line.js.map +1 -0
  432. package/dist/sessions/rotation.d.ts +2 -0
  433. package/dist/sessions/rotation.d.ts.map +1 -0
  434. package/dist/sessions/rotation.js +39 -0
  435. package/dist/sessions/rotation.js.map +1 -0
  436. package/dist/sessions/session-key.d.ts +33 -0
  437. package/dist/sessions/session-key.d.ts.map +1 -0
  438. package/dist/sessions/session-key.js +115 -0
  439. package/dist/sessions/session-key.js.map +1 -0
  440. package/dist/sessions/store.d.ts +15 -7
  441. package/dist/sessions/store.d.ts.map +1 -1
  442. package/dist/sessions/store.js +127 -36
  443. package/dist/sessions/store.js.map +1 -1
  444. package/dist/sessions/types.d.ts +19 -5
  445. package/dist/sessions/types.d.ts.map +1 -1
  446. package/dist/sessions/types.js.map +1 -1
  447. package/dist/settings-mutation.d.ts +40 -0
  448. package/dist/settings-mutation.d.ts.map +1 -0
  449. package/dist/settings-mutation.js +61 -0
  450. package/dist/settings-mutation.js.map +1 -0
  451. package/dist/subagent-progress.d.ts +39 -0
  452. package/dist/subagent-progress.d.ts.map +1 -0
  453. package/dist/subagent-progress.js +225 -0
  454. package/dist/subagent-progress.js.map +1 -0
  455. package/dist/tools/bash.d.ts +3 -1
  456. package/dist/tools/bash.d.ts.map +1 -1
  457. package/dist/tools/bash.js +26 -18
  458. package/dist/tools/bash.js.map +1 -1
  459. package/dist/tools/edit.d.ts.map +1 -1
  460. package/dist/tools/edit.js +14 -13
  461. package/dist/tools/edit.js.map +1 -1
  462. package/dist/tools/event.d.ts +1 -1
  463. package/dist/tools/event.d.ts.map +1 -1
  464. package/dist/tools/event.js +58 -45
  465. package/dist/tools/event.js.map +1 -1
  466. package/dist/tools/generate-image.d.ts +23 -0
  467. package/dist/tools/generate-image.d.ts.map +1 -0
  468. package/dist/tools/generate-image.js +65 -0
  469. package/dist/tools/generate-image.js.map +1 -0
  470. package/dist/tools/host-fn-tool.d.ts +21 -0
  471. package/dist/tools/host-fn-tool.d.ts.map +1 -0
  472. package/dist/tools/host-fn-tool.js +32 -0
  473. package/dist/tools/host-fn-tool.js.map +1 -0
  474. package/dist/tools/index.d.ts +19 -2
  475. package/dist/tools/index.d.ts.map +1 -1
  476. package/dist/tools/index.js +25 -2
  477. package/dist/tools/index.js.map +1 -1
  478. package/dist/tools/react.d.ts +15 -0
  479. package/dist/tools/react.d.ts.map +1 -0
  480. package/dist/tools/react.js +29 -0
  481. package/dist/tools/react.js.map +1 -0
  482. package/dist/tools/read.d.ts +1 -0
  483. package/dist/tools/read.d.ts.map +1 -1
  484. package/dist/tools/read.js +39 -33
  485. package/dist/tools/read.js.map +1 -1
  486. package/dist/tools/sandbox.d.ts +2 -2
  487. package/dist/tools/sandbox.d.ts.map +1 -1
  488. package/dist/tools/sandbox.js +14 -9
  489. package/dist/tools/sandbox.js.map +1 -1
  490. package/dist/tools/subagent-slots.d.ts +28 -0
  491. package/dist/tools/subagent-slots.d.ts.map +1 -0
  492. package/dist/tools/subagent-slots.js +72 -0
  493. package/dist/tools/subagent-slots.js.map +1 -0
  494. package/dist/tools/subagent.d.ts +61 -0
  495. package/dist/tools/subagent.d.ts.map +1 -0
  496. package/dist/tools/subagent.js +434 -0
  497. package/dist/tools/subagent.js.map +1 -0
  498. package/dist/tools/types.d.ts +40 -32
  499. package/dist/tools/types.d.ts.map +1 -1
  500. package/dist/tools/types.js.map +1 -1
  501. package/dist/tools/write.d.ts.map +1 -1
  502. package/dist/tools/write.js +2 -8
  503. package/dist/tools/write.js.map +1 -1
  504. package/dist/trigger.d.ts +2 -1
  505. package/dist/trigger.d.ts.map +1 -1
  506. package/dist/trigger.js +6 -9
  507. package/dist/trigger.js.map +1 -1
  508. package/dist/types.d.ts +411 -59
  509. package/dist/types.d.ts.map +1 -1
  510. package/dist/types.js +2 -2
  511. package/dist/types.js.map +1 -1
  512. package/dist/utils/file-guards.d.ts +9 -0
  513. package/dist/utils/file-guards.d.ts.map +1 -1
  514. package/dist/utils/file-guards.js +44 -1
  515. package/dist/utils/file-guards.js.map +1 -1
  516. package/dist/vault/disabled.d.ts +9 -0
  517. package/dist/vault/disabled.d.ts.map +1 -0
  518. package/dist/vault/disabled.js +25 -0
  519. package/dist/vault/disabled.js.map +1 -0
  520. package/dist/vault/index.d.ts +45 -2
  521. package/dist/vault/index.d.ts.map +1 -1
  522. package/dist/vault/index.js +127 -36
  523. package/dist/vault/index.js.map +1 -1
  524. package/dist/vault/types.d.ts +6 -2
  525. package/dist/vault/types.d.ts.map +1 -1
  526. package/dist/vault/types.js.map +1 -1
  527. package/dist/web/admin/portal.d.ts +31 -3
  528. package/dist/web/admin/portal.d.ts.map +1 -1
  529. package/dist/web/admin/portal.js +850 -345
  530. package/dist/web/admin/portal.js.map +1 -1
  531. package/dist/web/admin/provider-models.js +1 -1
  532. package/dist/web/admin/provider-models.js.map +1 -1
  533. package/dist/web/admin/types.d.ts +23 -3
  534. package/dist/web/admin/types.d.ts.map +1 -1
  535. package/dist/web/admin/types.js.map +1 -1
  536. package/dist/web/login/oauth.d.ts +2 -3
  537. package/dist/web/login/oauth.d.ts.map +1 -1
  538. package/dist/web/login/oauth.js +1 -32
  539. package/dist/web/login/oauth.js.map +1 -1
  540. package/dist/web/login/portal.d.ts +1 -1
  541. package/dist/web/login/portal.d.ts.map +1 -1
  542. package/dist/web/login/portal.js +13 -36
  543. package/dist/web/login/portal.js.map +1 -1
  544. package/dist/web/login/types.d.ts +0 -11
  545. package/dist/web/login/types.d.ts.map +1 -1
  546. package/dist/web/login/types.js.map +1 -1
  547. package/dist/web/portal-shell.d.ts +21 -0
  548. package/dist/web/portal-shell.d.ts.map +1 -0
  549. package/dist/{portal-shell.js → web/portal-shell.js} +67 -2
  550. package/dist/web/portal-shell.js.map +1 -0
  551. package/dist/web/server.d.ts +3 -2
  552. package/dist/web/server.d.ts.map +1 -1
  553. package/dist/web/server.js +11 -4
  554. package/dist/web/server.js.map +1 -1
  555. package/dist/web/session-view/portal.d.ts +1 -1
  556. package/dist/web/session-view/portal.d.ts.map +1 -1
  557. package/dist/web/session-view/portal.js +37 -28
  558. package/dist/web/session-view/portal.js.map +1 -1
  559. package/dist/web/session-view/service.d.ts +1 -1
  560. package/dist/web/session-view/service.d.ts.map +1 -1
  561. package/dist/web/session-view/service.js +61 -18
  562. package/dist/web/session-view/service.js.map +1 -1
  563. package/dist/web/session-view/types.d.ts +0 -3
  564. package/dist/web/session-view/types.d.ts.map +1 -1
  565. package/dist/web/session-view/types.js.map +1 -1
  566. package/dist/web/token-store.js +1 -1
  567. package/dist/web/token-store.js.map +1 -1
  568. package/dist/workspace-projection/index.d.ts +10 -0
  569. package/dist/workspace-projection/index.d.ts.map +1 -0
  570. package/dist/workspace-projection/index.js +120 -0
  571. package/dist/workspace-projection/index.js.map +1 -0
  572. package/dist/workspace-projection/types.d.ts +16 -0
  573. package/dist/workspace-projection/types.d.ts.map +1 -0
  574. package/dist/workspace-projection/types.js +2 -0
  575. package/dist/workspace-projection/types.js.map +1 -0
  576. package/package.json +68 -37
  577. package/dist/adapters/streaming.d.ts +0 -18
  578. package/dist/adapters/streaming.d.ts.map +0 -1
  579. package/dist/adapters/streaming.js +0 -44
  580. package/dist/adapters/streaming.js.map +0 -1
  581. package/dist/adapters/telegram/html.d.ts +0 -3
  582. package/dist/adapters/telegram/html.d.ts.map +0 -1
  583. package/dist/adapters/telegram/html.js +0 -98
  584. package/dist/adapters/telegram/html.js.map +0 -1
  585. package/dist/commands/parse.d.ts +0 -7
  586. package/dist/commands/parse.d.ts.map +0 -1
  587. package/dist/commands/parse.js +0 -14
  588. package/dist/commands/parse.js.map +0 -1
  589. package/dist/download.d.ts.map +0 -1
  590. package/dist/download.js.map +0 -1
  591. package/dist/model-registry.d.ts +0 -4
  592. package/dist/model-registry.d.ts.map +0 -1
  593. package/dist/model-registry.js +0 -7
  594. package/dist/model-registry.js.map +0 -1
  595. package/dist/portal-shell.d.ts +0 -4
  596. package/dist/portal-shell.d.ts.map +0 -1
  597. package/dist/portal-shell.js.map +0 -1
  598. package/dist/runtime/agent-run-controller.d.ts +0 -31
  599. package/dist/runtime/agent-run-controller.d.ts.map +0 -1
  600. package/dist/runtime/agent-run-controller.js +0 -195
  601. package/dist/runtime/agent-run-controller.js.map +0 -1
  602. package/dist/sandbox/path-context.d.ts +0 -3
  603. package/dist/sandbox/path-context.d.ts.map +0 -1
  604. package/dist/sandbox/path-context.js +0 -20
  605. package/dist/sandbox/path-context.js.map +0 -1
  606. package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
  607. package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
  608. package/dist/sessions/agent-memory-file-manager.js.map +0 -1
  609. package/dist/sessions/metadata.d.ts +0 -3
  610. package/dist/sessions/metadata.d.ts.map +0 -1
  611. package/dist/sessions/metadata.js +0 -11
  612. package/dist/sessions/metadata.js.map +0 -1
  613. package/dist/sessions/policy.d.ts +0 -6
  614. package/dist/sessions/policy.d.ts.map +0 -1
  615. package/dist/sessions/policy.js +0 -23
  616. package/dist/sessions/policy.js.map +0 -1
  617. package/dist/store.d.ts +0 -46
  618. package/dist/store.d.ts.map +0 -1
  619. package/dist/store.js +0 -177
  620. package/dist/store.js.map +0 -1
  621. package/dist/tools/truncate.d.ts +0 -33
  622. package/dist/tools/truncate.d.ts.map +0 -1
  623. package/dist/tools/truncate.js +0 -184
  624. package/dist/tools/truncate.js.map +0 -1
  625. package/dist/utils/date.d.ts +0 -10
  626. package/dist/utils/date.d.ts.map +0 -1
  627. package/dist/utils/date.js +0 -23
  628. package/dist/utils/date.js.map +0 -1
  629. package/dist/utils/env.d.ts +0 -3
  630. package/dist/utils/env.d.ts.map +0 -1
  631. package/dist/utils/env.js +0 -12
  632. package/dist/utils/env.js.map +0 -1
  633. package/dist/utils/fs-atomic.d.ts +0 -10
  634. package/dist/utils/fs-atomic.d.ts.map +0 -1
  635. package/dist/utils/fs-atomic.js +0 -45
  636. package/dist/utils/fs-atomic.js.map +0 -1
  637. package/dist/utils/html.d.ts +0 -2
  638. package/dist/utils/html.d.ts.map +0 -1
  639. package/dist/utils/html.js +0 -4
  640. package/dist/utils/html.js.map +0 -1
  641. package/dist/utils/http-body.d.ts +0 -10
  642. package/dist/utils/http-body.d.ts.map +0 -1
  643. package/dist/utils/http-body.js +0 -34
  644. package/dist/utils/http-body.js.map +0 -1
  645. package/dist/vault/routing.d.ts +0 -3
  646. package/dist/vault/routing.d.ts.map +0 -1
  647. package/dist/vault/routing.js +0 -13
  648. package/dist/vault/routing.js.map +0 -1
  649. package/dist/web/agent-events/portal.d.ts +0 -3
  650. package/dist/web/agent-events/portal.d.ts.map +0 -1
  651. package/dist/web/agent-events/portal.js +0 -18
  652. package/dist/web/agent-events/portal.js.map +0 -1
  653. package/dist/web/request.d.ts +0 -3
  654. package/dist/web/request.d.ts.map +0 -1
  655. package/dist/web/request.js +0 -13
  656. package/dist/web/request.js.map +0 -1
  657. package/dist/web/session-view/command.d.ts +0 -4
  658. package/dist/web/session-view/command.d.ts.map +0 -1
  659. package/dist/web/session-view/command.js +0 -7
  660. package/dist/web/session-view/command.js.map +0 -1
  661. /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Turning a parsed source into a directory on the host.
3
+ *
4
+ * Materialization is an explicit, reported step — it happens when a human adds
5
+ * or updates a package, not lazily while a conversation is waiting for a
6
+ * reply. Failures (bad URL, missing ref, no such subpath) therefore surface in
7
+ * front of the person who typed the source instead of as a silently absent
8
+ * feature in a chat.
9
+ *
10
+ * Everything lands under the host-only state dir, never the workspace: this
11
+ * code is imported into the mikan process, so a mounted location would let
12
+ * sandboxed code write what the host executes.
13
+ */
14
+ import { execFileSync } from "node:child_process";
15
+ import { createHash } from "node:crypto";
16
+ import { cpSync, existsSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
17
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
18
+ import { ensureDirExists, readTextFileIfExists } from "../utils/file-guards.js";
19
+ import * as log from "../log.js";
20
+ import { gitRepoPath, parseSource, sourceIdentity } from "./source.js";
21
+ import { officeStateDir } from "../office/index.js";
22
+ /** Git operations get a bounded wall clock so a hung remote cannot wedge a save. */
23
+ const GIT_TIMEOUT_MS = 120_000;
24
+ const NPM_TIMEOUT_MS = 300_000;
25
+ const MATERIALIZED_REF_FILE = "mikan-ref";
26
+ /**
27
+ * How far materialization may go to produce the package's files.
28
+ *
29
+ * - `offline`: use what is already on disk; never touch the network. This is
30
+ * what a conversation load uses, so no chat reply can ever wait on a remote.
31
+ * - `fetch`: clone a package that is not on disk yet, reuse an existing clone
32
+ * when it already has the requested ref, or switch it to a new ref. What the
33
+ * portal uses when a source is added.
34
+ * - `refresh`: additionally re-fetch an existing clone, resetting and cleaning
35
+ * it first. What the portal's Update action uses.
36
+ *
37
+ * One mode rather than two booleans: "re-fetch an existing clone but refuse to
38
+ * create a missing one" is not a state any caller wants, and expressing it
39
+ * should not be possible.
40
+ */
41
+ /**
42
+ * Root of a scope's host-only assets: `<stateDir>/global` or
43
+ * `<stateDir>/conversations/<id>`. The two are isomorphic by design — both
44
+ * hold `extensions/`, `extension-data/`, and now `git/`. See
45
+ * `src/harness/extensions/LAYOUT.md`.
46
+ */
47
+ export function packageScopeDir(scope, address, stateDir) {
48
+ if (scope === "global")
49
+ return join(stateDir, "global");
50
+ if (!address)
51
+ throw new Error("A conversation-scoped package needs an office address");
52
+ return officeStateDir(stateDir, address);
53
+ }
54
+ /**
55
+ * Where a git checkout lives.
56
+ *
57
+ * The unpinned checkout keeps the original path for compatibility. Explicit
58
+ * refs get a sibling keyed by the ref, so two refs can never reset each
59
+ * other's working tree; subpaths of one ref therefore still share a checkout.
60
+ */
61
+ export function gitCloneDir(url, scopeDir, ref) {
62
+ const repoPath = gitRepoPath(url).split("/");
63
+ const repoName = repoPath[repoPath.length - 1] ?? "repo";
64
+ const parent = repoPath.slice(0, -1);
65
+ const checkoutName = ref === undefined || ref === "HEAD"
66
+ ? repoName
67
+ : `${repoName}.mikan-${createHash("sha256").update(ref).digest("hex")}`;
68
+ return join(scopeDir, "git", ...parent, checkoutName);
69
+ }
70
+ /**
71
+ * Materialize one source and return where its files ended up. Throws with a
72
+ * message meant to be shown to a human — callers render it next to the input
73
+ * that produced it.
74
+ */
75
+ export function materializeSource(source, options) {
76
+ const parsed = parseSource(source);
77
+ const scopeDir = packageScopeDir(options.scope, options.address, options.stateDir);
78
+ const dir = parsed.type === "local"
79
+ ? materializeLocal(parsed)
80
+ : materializeGit(parsed, scopeDir, options.mode ?? "fetch");
81
+ return {
82
+ source,
83
+ parsed,
84
+ identity: sourceIdentity(parsed),
85
+ dir,
86
+ scope: options.scope,
87
+ };
88
+ }
89
+ function materializeLocal(parsed) {
90
+ if (!existsSync(parsed.path)) {
91
+ throw new Error(`Path does not exist on the mikan host: ${parsed.path}`);
92
+ }
93
+ if (!statSync(parsed.path).isDirectory()) {
94
+ throw new Error(`Package path must be a directory: ${parsed.path}`);
95
+ }
96
+ return parsed.path;
97
+ }
98
+ function materializeGit(parsed, scopeDir, mode) {
99
+ const requestedRef = parsed.ref ?? "HEAD";
100
+ const cloneDir = gitCloneDir(parsed.url, scopeDir, requestedRef);
101
+ migrateLegacyCheckout(parsed.url, scopeDir, cloneDir, requestedRef);
102
+ const alreadyCloned = existsSync(join(cloneDir, ".git"));
103
+ const markerPath = join(cloneDir, ".git", MATERIALIZED_REF_FILE);
104
+ const recordedRef = alreadyCloned ? readTextFileIfExists(markerPath)?.trim() : undefined;
105
+ const canReuse = alreadyCloned &&
106
+ mode !== "refresh" &&
107
+ (recordedRef === requestedRef ||
108
+ (mode === "offline" &&
109
+ recordedRef === undefined &&
110
+ markerlessCheckoutMatchesRef(cloneDir, requestedRef)));
111
+ if (canReuse) {
112
+ return resolveSubpath(cloneDir, parsed);
113
+ }
114
+ if (mode === "offline") {
115
+ throw new Error(`Not fetched on this host yet: ${describeRef(parsed)}`);
116
+ }
117
+ // An incomplete checkout must not retain a marker from an earlier attempt:
118
+ // otherwise a retry could mistake a failed dependency install for success.
119
+ if (alreadyCloned)
120
+ rmSync(markerPath, { force: true });
121
+ if (!alreadyCloned) {
122
+ // A leftover directory without .git means a previous attempt died partway.
123
+ if (existsSync(cloneDir))
124
+ rmSync(cloneDir, { recursive: true, force: true });
125
+ ensureDirExists(cloneDir);
126
+ git(cloneDir, ["init", "-q"]);
127
+ git(cloneDir, ["remote", "add", "origin", parsed.url]);
128
+ }
129
+ else {
130
+ // Reconcile: drop anything a previous checkout left behind so the new ref
131
+ // lands on a clean tree.
132
+ git(cloneDir, ["remote", "set-url", "origin", parsed.url]);
133
+ git(cloneDir, ["reset", "--hard", "-q"]);
134
+ git(cloneDir, ["clean", "-qfd"]);
135
+ }
136
+ // One fetch shape for every kind of ref — tag, branch, or commit sha — and
137
+ // `HEAD` for "whatever the remote's default branch is now".
138
+ try {
139
+ git(cloneDir, ["fetch", "--depth", "1", "origin", requestedRef]);
140
+ }
141
+ catch (err) {
142
+ if (!alreadyCloned)
143
+ rmSync(cloneDir, { recursive: true, force: true });
144
+ throw new Error(`Could not fetch ${describeRef(parsed)}: ${gitErrorText(err)}`, { cause: err });
145
+ }
146
+ git(cloneDir, ["checkout", "-q", "--detach", "FETCH_HEAD"]);
147
+ const dir = resolveSubpath(cloneDir, parsed);
148
+ installDependencies(dir);
149
+ // This is the completion marker, not merely a fetched-ref marker. Write it
150
+ // last so a failed npm install is retried by the next materialization.
151
+ writeFileSync(markerPath, `${requestedRef}\n`);
152
+ return dir;
153
+ }
154
+ /**
155
+ * Before keyed checkout paths existed, every ref used the legacy repo path.
156
+ * Copy a matching complete checkout on first use of its keyed path so offline
157
+ * loads keep working. Markerless legacy checkouts are accepted only when git
158
+ * can prove the requested ref is the checked-out commit; a different or
159
+ * unprovable pinned ref is rebuilt by fetch/refresh instead.
160
+ */
161
+ function migrateLegacyCheckout(url, scopeDir, cloneDir, requestedRef) {
162
+ const legacyDir = gitCloneDir(url, scopeDir);
163
+ if (cloneDir === legacyDir || existsSync(cloneDir))
164
+ return;
165
+ const legacyMarker = join(legacyDir, ".git", MATERIALIZED_REF_FILE);
166
+ if (!existsSync(join(legacyDir, ".git")))
167
+ return;
168
+ const recordedRef = readTextFileIfExists(legacyMarker)?.trim();
169
+ if (recordedRef !== requestedRef) {
170
+ if (recordedRef !== undefined || !markerlessCheckoutMatchesRef(legacyDir, requestedRef)) {
171
+ return;
172
+ }
173
+ }
174
+ ensureDirExists(dirname(cloneDir));
175
+ cpSync(legacyDir, cloneDir, { recursive: true });
176
+ }
177
+ /**
178
+ * Legacy checkouts have no completion marker. Accept them offline only when
179
+ * the checkout is clean and the local git metadata identifies the requested
180
+ * commit/ref; never infer a pinned ref from HEAD alone.
181
+ */
182
+ function markerlessCheckoutMatchesRef(cloneDir, requestedRef) {
183
+ let head;
184
+ try {
185
+ head = git(cloneDir, ["rev-parse", "--verify", "HEAD"]).trim();
186
+ if (!head || git(cloneDir, ["status", "--porcelain", "--untracked-files=no"]).trim()) {
187
+ return false;
188
+ }
189
+ }
190
+ catch {
191
+ return false;
192
+ }
193
+ if (requestedRef === "HEAD")
194
+ return true;
195
+ try {
196
+ if (git(cloneDir, ["rev-parse", "--verify", `${requestedRef}^{commit}`]).trim() === head) {
197
+ return true;
198
+ }
199
+ }
200
+ catch {
201
+ // A shallow legacy fetch may retain only FETCH_HEAD, not a local ref.
202
+ }
203
+ try {
204
+ if (git(cloneDir, ["symbolic-ref", "--quiet", "--short", "HEAD"]).trim() === requestedRef) {
205
+ return true;
206
+ }
207
+ }
208
+ catch {
209
+ // Detached checkouts do not have a symbolic branch.
210
+ }
211
+ const fetchHead = readTextFileIfExists(join(cloneDir, ".git", "FETCH_HEAD"));
212
+ if (!fetchHead)
213
+ return false;
214
+ return fetchHead.split("\n").some((line) => {
215
+ const match = /^(\w+)\s+.*(?:branch|tag) '([^']+)'/.exec(line);
216
+ return match?.[1] === head && match[2] === requestedRef;
217
+ });
218
+ }
219
+ function resolveSubpath(cloneDir, parsed) {
220
+ if (!parsed.subpath)
221
+ return cloneDir;
222
+ const dir = join(cloneDir, parsed.subpath);
223
+ if (!existsSync(dir)) {
224
+ throw new Error(`Subpath not found in repository: ${parsed.subpath}`);
225
+ }
226
+ // A symlink inside the repository must not select files outside the clone:
227
+ // the returned directory is imported (extensions) or mounted, so follow
228
+ // links before deciding the subpath stayed inside.
229
+ const relation = relative(realpathSync(cloneDir), realpathSync(dir));
230
+ if (isAbsolute(relation) || relation === ".." || relation.startsWith(`..${sep}`)) {
231
+ throw new Error(`Subpath escapes repository: ${parsed.subpath}`);
232
+ }
233
+ return dir;
234
+ }
235
+ /**
236
+ * Install runtime dependencies when the package declares any. This runs npm
237
+ * on the host against code that was just fetched from a remote, which is the
238
+ * same trust level as importing the package itself — but it is worth being
239
+ * explicit that it happens, because it also runs the dependencies' install
240
+ * scripts.
241
+ */
242
+ function installDependencies(dir) {
243
+ if (!hasDependencies(dir))
244
+ return;
245
+ log.logInfo(`Installing package dependencies in ${dir}`);
246
+ try {
247
+ execFileSync("npm", ["install", "--omit=dev", "--no-audit", "--no-fund"], {
248
+ cwd: dir,
249
+ timeout: NPM_TIMEOUT_MS,
250
+ encoding: "utf-8",
251
+ stdio: ["ignore", "pipe", "pipe"],
252
+ });
253
+ }
254
+ catch (err) {
255
+ throw new Error(`npm install failed for the package: ${gitErrorText(err)}`, { cause: err });
256
+ }
257
+ }
258
+ function hasDependencies(dir) {
259
+ const raw = readTextFileIfExists(join(dir, "package.json"));
260
+ if (raw === undefined)
261
+ return false;
262
+ try {
263
+ const pkg = JSON.parse(raw);
264
+ return Boolean(pkg.dependencies && Object.keys(pkg.dependencies).length > 0);
265
+ }
266
+ catch {
267
+ return false;
268
+ }
269
+ }
270
+ function git(cwd, args) {
271
+ return execFileSync("git", args, {
272
+ cwd,
273
+ timeout: GIT_TIMEOUT_MS,
274
+ encoding: "utf-8",
275
+ stdio: ["ignore", "pipe", "pipe"],
276
+ env: {
277
+ ...process.env,
278
+ // Never block a portal save on an interactive credential prompt.
279
+ GIT_TERMINAL_PROMPT: "0",
280
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes -o ConnectTimeout=10",
281
+ },
282
+ });
283
+ }
284
+ function describeRef(parsed) {
285
+ return parsed.ref ? `${parsed.url} at ${parsed.ref}` : parsed.url;
286
+ }
287
+ /** Prefer git's stderr over the generic "Command failed" wrapper. */
288
+ function gitErrorText(err) {
289
+ if (err && typeof err === "object" && "stderr" in err) {
290
+ const stderr = err.stderr;
291
+ const text = typeof stderr === "string" ? stderr.trim() : "";
292
+ if (text)
293
+ return text.split("\n").slice(-3).join(" ");
294
+ }
295
+ return err instanceof Error ? err.message : String(err);
296
+ }
297
+ //# sourceMappingURL=materialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materialize.js","sourceRoot":"","sources":["../../src/packages/materialize.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turning a parsed source into a directory on the host.\n *\n * Materialization is an explicit, reported step — it happens when a human adds\n * or updates a package, not lazily while a conversation is waiting for a\n * reply. Failures (bad URL, missing ref, no such subpath) therefore surface in\n * front of the person who typed the source instead of as a silently absent\n * feature in a chat.\n *\n * Everything lands under the host-only state dir, never the workspace: this\n * code is imported into the mikan process, so a mounted location would let\n * sandboxed code write what the host executes.\n */\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { cpSync, existsSync, realpathSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, sep } from \"node:path\";\nimport { ensureDirExists, readTextFileIfExists } from \"../utils/file-guards.js\";\nimport * as log from \"../log.js\";\nimport { gitRepoPath, parseSource, sourceIdentity } from \"./source.js\";\nimport { officeStateDir } from \"../office/index.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport type {\n MaterializeMode,\n MaterializeOptions,\n MaterializedPackage,\n PackageScope,\n PackageSourceString,\n ParsedSource,\n} from \"./types.js\";\n\nexport type { MaterializeOptions } from \"./types.js\";\n\n/** Git operations get a bounded wall clock so a hung remote cannot wedge a save. */\nconst GIT_TIMEOUT_MS = 120_000;\nconst NPM_TIMEOUT_MS = 300_000;\nconst MATERIALIZED_REF_FILE = \"mikan-ref\";\n\n/**\n * How far materialization may go to produce the package's files.\n *\n * - `offline`: use what is already on disk; never touch the network. This is\n * what a conversation load uses, so no chat reply can ever wait on a remote.\n * - `fetch`: clone a package that is not on disk yet, reuse an existing clone\n * when it already has the requested ref, or switch it to a new ref. What the\n * portal uses when a source is added.\n * - `refresh`: additionally re-fetch an existing clone, resetting and cleaning\n * it first. What the portal's Update action uses.\n *\n * One mode rather than two booleans: \"re-fetch an existing clone but refuse to\n * create a missing one\" is not a state any caller wants, and expressing it\n * should not be possible.\n */\n/**\n * Root of a scope's host-only assets: `<stateDir>/global` or\n * `<stateDir>/conversations/<id>`. The two are isomorphic by design — both\n * hold `extensions/`, `extension-data/`, and now `git/`. See\n * `src/harness/extensions/LAYOUT.md`.\n */\nexport function packageScopeDir(\n scope: PackageScope,\n address: OfficeAddress | undefined,\n stateDir: string,\n): string {\n if (scope === \"global\") return join(stateDir, \"global\");\n if (!address) throw new Error(\"A conversation-scoped package needs an office address\");\n return officeStateDir(stateDir, address);\n}\n\n/**\n * Where a git checkout lives.\n *\n * The unpinned checkout keeps the original path for compatibility. Explicit\n * refs get a sibling keyed by the ref, so two refs can never reset each\n * other's working tree; subpaths of one ref therefore still share a checkout.\n */\nexport function gitCloneDir(url: string, scopeDir: string, ref?: string): string {\n const repoPath = gitRepoPath(url).split(\"/\");\n const repoName = repoPath[repoPath.length - 1] ?? \"repo\";\n const parent = repoPath.slice(0, -1);\n const checkoutName =\n ref === undefined || ref === \"HEAD\"\n ? repoName\n : `${repoName}.mikan-${createHash(\"sha256\").update(ref).digest(\"hex\")}`;\n return join(scopeDir, \"git\", ...parent, checkoutName);\n}\n\n/**\n * Materialize one source and return where its files ended up. Throws with a\n * message meant to be shown to a human — callers render it next to the input\n * that produced it.\n */\nexport function materializeSource(\n source: PackageSourceString,\n options: MaterializeOptions,\n): MaterializedPackage {\n const parsed = parseSource(source);\n const scopeDir = packageScopeDir(options.scope, options.address, options.stateDir);\n const dir =\n parsed.type === \"local\"\n ? materializeLocal(parsed)\n : materializeGit(parsed, scopeDir, options.mode ?? \"fetch\");\n\n return {\n source,\n parsed,\n identity: sourceIdentity(parsed),\n dir,\n scope: options.scope,\n };\n}\n\nfunction materializeLocal(parsed: Extract<ParsedSource, { type: \"local\" }>): string {\n if (!existsSync(parsed.path)) {\n throw new Error(`Path does not exist on the mikan host: ${parsed.path}`);\n }\n if (!statSync(parsed.path).isDirectory()) {\n throw new Error(`Package path must be a directory: ${parsed.path}`);\n }\n return parsed.path;\n}\n\nfunction materializeGit(\n parsed: Extract<ParsedSource, { type: \"git\" }>,\n scopeDir: string,\n mode: MaterializeMode,\n): string {\n const requestedRef = parsed.ref ?? \"HEAD\";\n const cloneDir = gitCloneDir(parsed.url, scopeDir, requestedRef);\n migrateLegacyCheckout(parsed.url, scopeDir, cloneDir, requestedRef);\n const alreadyCloned = existsSync(join(cloneDir, \".git\"));\n const markerPath = join(cloneDir, \".git\", MATERIALIZED_REF_FILE);\n const recordedRef = alreadyCloned ? readTextFileIfExists(markerPath)?.trim() : undefined;\n const canReuse =\n alreadyCloned &&\n mode !== \"refresh\" &&\n (recordedRef === requestedRef ||\n (mode === \"offline\" &&\n recordedRef === undefined &&\n markerlessCheckoutMatchesRef(cloneDir, requestedRef)));\n\n if (canReuse) {\n return resolveSubpath(cloneDir, parsed);\n }\n if (mode === \"offline\") {\n throw new Error(`Not fetched on this host yet: ${describeRef(parsed)}`);\n }\n\n // An incomplete checkout must not retain a marker from an earlier attempt:\n // otherwise a retry could mistake a failed dependency install for success.\n if (alreadyCloned) rmSync(markerPath, { force: true });\n\n if (!alreadyCloned) {\n // A leftover directory without .git means a previous attempt died partway.\n if (existsSync(cloneDir)) rmSync(cloneDir, { recursive: true, force: true });\n ensureDirExists(cloneDir);\n git(cloneDir, [\"init\", \"-q\"]);\n git(cloneDir, [\"remote\", \"add\", \"origin\", parsed.url]);\n } else {\n // Reconcile: drop anything a previous checkout left behind so the new ref\n // lands on a clean tree.\n git(cloneDir, [\"remote\", \"set-url\", \"origin\", parsed.url]);\n git(cloneDir, [\"reset\", \"--hard\", \"-q\"]);\n git(cloneDir, [\"clean\", \"-qfd\"]);\n }\n\n // One fetch shape for every kind of ref — tag, branch, or commit sha — and\n // `HEAD` for \"whatever the remote's default branch is now\".\n try {\n git(cloneDir, [\"fetch\", \"--depth\", \"1\", \"origin\", requestedRef]);\n } catch (err) {\n if (!alreadyCloned) rmSync(cloneDir, { recursive: true, force: true });\n throw new Error(`Could not fetch ${describeRef(parsed)}: ${gitErrorText(err)}`, { cause: err });\n }\n git(cloneDir, [\"checkout\", \"-q\", \"--detach\", \"FETCH_HEAD\"]);\n\n const dir = resolveSubpath(cloneDir, parsed);\n installDependencies(dir);\n // This is the completion marker, not merely a fetched-ref marker. Write it\n // last so a failed npm install is retried by the next materialization.\n writeFileSync(markerPath, `${requestedRef}\\n`);\n return dir;\n}\n\n/**\n * Before keyed checkout paths existed, every ref used the legacy repo path.\n * Copy a matching complete checkout on first use of its keyed path so offline\n * loads keep working. Markerless legacy checkouts are accepted only when git\n * can prove the requested ref is the checked-out commit; a different or\n * unprovable pinned ref is rebuilt by fetch/refresh instead.\n */\nfunction migrateLegacyCheckout(\n url: string,\n scopeDir: string,\n cloneDir: string,\n requestedRef: string,\n): void {\n const legacyDir = gitCloneDir(url, scopeDir);\n if (cloneDir === legacyDir || existsSync(cloneDir)) return;\n const legacyMarker = join(legacyDir, \".git\", MATERIALIZED_REF_FILE);\n if (!existsSync(join(legacyDir, \".git\"))) return;\n const recordedRef = readTextFileIfExists(legacyMarker)?.trim();\n if (recordedRef !== requestedRef) {\n if (recordedRef !== undefined || !markerlessCheckoutMatchesRef(legacyDir, requestedRef)) {\n return;\n }\n }\n\n ensureDirExists(dirname(cloneDir));\n cpSync(legacyDir, cloneDir, { recursive: true });\n}\n\n/**\n * Legacy checkouts have no completion marker. Accept them offline only when\n * the checkout is clean and the local git metadata identifies the requested\n * commit/ref; never infer a pinned ref from HEAD alone.\n */\nfunction markerlessCheckoutMatchesRef(cloneDir: string, requestedRef: string): boolean {\n let head: string;\n try {\n head = git(cloneDir, [\"rev-parse\", \"--verify\", \"HEAD\"]).trim();\n if (!head || git(cloneDir, [\"status\", \"--porcelain\", \"--untracked-files=no\"]).trim()) {\n return false;\n }\n } catch {\n return false;\n }\n\n if (requestedRef === \"HEAD\") return true;\n\n try {\n if (git(cloneDir, [\"rev-parse\", \"--verify\", `${requestedRef}^{commit}`]).trim() === head) {\n return true;\n }\n } catch {\n // A shallow legacy fetch may retain only FETCH_HEAD, not a local ref.\n }\n\n try {\n if (git(cloneDir, [\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]).trim() === requestedRef) {\n return true;\n }\n } catch {\n // Detached checkouts do not have a symbolic branch.\n }\n\n const fetchHead = readTextFileIfExists(join(cloneDir, \".git\", \"FETCH_HEAD\"));\n if (!fetchHead) return false;\n return fetchHead.split(\"\\n\").some((line) => {\n const match = /^(\\w+)\\s+.*(?:branch|tag) '([^']+)'/.exec(line);\n return match?.[1] === head && match[2] === requestedRef;\n });\n}\n\nfunction resolveSubpath(cloneDir: string, parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n if (!parsed.subpath) return cloneDir;\n const dir = join(cloneDir, parsed.subpath);\n if (!existsSync(dir)) {\n throw new Error(`Subpath not found in repository: ${parsed.subpath}`);\n }\n // A symlink inside the repository must not select files outside the clone:\n // the returned directory is imported (extensions) or mounted, so follow\n // links before deciding the subpath stayed inside.\n const relation = relative(realpathSync(cloneDir), realpathSync(dir));\n if (isAbsolute(relation) || relation === \"..\" || relation.startsWith(`..${sep}`)) {\n throw new Error(`Subpath escapes repository: ${parsed.subpath}`);\n }\n return dir;\n}\n\n/**\n * Install runtime dependencies when the package declares any. This runs npm\n * on the host against code that was just fetched from a remote, which is the\n * same trust level as importing the package itself — but it is worth being\n * explicit that it happens, because it also runs the dependencies' install\n * scripts.\n */\nfunction installDependencies(dir: string): void {\n if (!hasDependencies(dir)) return;\n log.logInfo(`Installing package dependencies in ${dir}`);\n try {\n execFileSync(\"npm\", [\"install\", \"--omit=dev\", \"--no-audit\", \"--no-fund\"], {\n cwd: dir,\n timeout: NPM_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch (err) {\n throw new Error(`npm install failed for the package: ${gitErrorText(err)}`, { cause: err });\n }\n}\n\nfunction hasDependencies(dir: string): boolean {\n const raw = readTextFileIfExists(join(dir, \"package.json\"));\n if (raw === undefined) return false;\n try {\n const pkg = JSON.parse(raw) as { dependencies?: Record<string, string> };\n return Boolean(pkg.dependencies && Object.keys(pkg.dependencies).length > 0);\n } catch {\n return false;\n }\n}\n\nfunction git(cwd: string, args: string[]): string {\n return execFileSync(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n // Never block a portal save on an interactive credential prompt.\n GIT_TERMINAL_PROMPT: \"0\",\n GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? \"ssh -o BatchMode=yes -o ConnectTimeout=10\",\n },\n });\n}\n\nfunction describeRef(parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n return parsed.ref ? `${parsed.url} at ${parsed.ref}` : parsed.url;\n}\n\n/** Prefer git's stderr over the generic \"Command failed\" wrapper. */\nfunction gitErrorText(err: unknown): string {\n if (err && typeof err === \"object\" && \"stderr\" in err) {\n const stderr = (err as { stderr?: unknown }).stderr;\n const text = typeof stderr === \"string\" ? stderr.trim() : \"\";\n if (text) return text.split(\"\\n\").slice(-3).join(\" \");\n }\n return err instanceof Error ? err.message : String(err);\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { ResolvePackagesOptions, ResolvedPackages } from "./types.js";
2
+ export type { ResolvePackagesOptions, ResolvedPackages } from "./types.js";
3
+ /** Runtime path a package's skills directory is mounted at. */
4
+ export declare function packageSkillRuntimeDir(slug: string): string;
5
+ /**
6
+ * Read-only mounts exposing every resolved package's skills to the sandbox.
7
+ *
8
+ * Read-only rather than read-write because the host owns these files: the
9
+ * directory is a git checkout that an update replaces wholesale, so an agent
10
+ * edit would be silently discarded on the next refresh. Making the filesystem
11
+ * refuse the write turns a confusing data-loss bug into an obvious error.
12
+ *
13
+ * Resolution is offline, so building the mount list never reaches the network.
14
+ */
15
+ export declare function conversationPackageSkillMounts(options: ResolvePackagesOptions): Array<{
16
+ source: string;
17
+ target: string;
18
+ readOnly: true;
19
+ }>;
20
+ /**
21
+ * Resolve the package set for one conversation. Reads both scopes' settings,
22
+ * dedups, and reports the directories to load from.
23
+ */
24
+ export declare function resolveConversationPackages(options: ResolvePackagesOptions): ResolvedPackages;
25
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/packages/resolve.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAKV,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAwB3E,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,sBAAsB,GAC9B,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC,CAM3D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,sBAAsB,GAAG,gBAAgB,CAkC7F"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * What a conversation actually loads: the two scopes' declared packages
3
+ * combined, collisions resolved, and each surviving package turned into the
4
+ * directories the extension loader and the skill loader consume.
5
+ *
6
+ * Two rules do all the work here:
7
+ *
8
+ * - **Additive scopes.** `global` packages load for every conversation; a
9
+ * conversation's packages load on top. Neither list replaces the other.
10
+ * - **Narrower scope wins.** When both scopes declare the same package
11
+ * ({@link sourceIdentity}, which ignores the ref), only the conversation's
12
+ * copy loads. That is what makes "pin this one channel to v2 while everyone
13
+ * else stays on v1" work, and it is why the same package installed twice
14
+ * cannot activate twice.
15
+ *
16
+ * Resolution never throws. A conversation with one malformed or unfetchable
17
+ * source still loads every other package, and the failure is reported through
18
+ * {@link ResolvedPackages.errors} for the portal and the logs. The alternative
19
+ * — one bad string in settings taking a conversation offline — is a far worse
20
+ * failure mode than a missing feature.
21
+ */
22
+ import { createHash } from "node:crypto";
23
+ import { existsSync, statSync } from "node:fs";
24
+ import { join } from "node:path";
25
+ import { loadGlobalSettings, resolveConversationSettings } from "../config.js";
26
+ import * as log from "../log.js";
27
+ import { materializeSource, packageScopeDir } from "./materialize.js";
28
+ import { parseSource, sourceIdentity } from "./source.js";
29
+ /** Conventional resource directories inside a package, mirroring pi's layout. */
30
+ const EXTENSIONS_SUBDIR = "extensions";
31
+ const SKILLS_SUBDIR = "skills";
32
+ /** Slug length cap; long identities keep a digest tail instead of colliding. */
33
+ const SLUG_MAX_LENGTH = 96;
34
+ /**
35
+ * Where package resources appear inside the sandbox.
36
+ *
37
+ * Deliberately OUTSIDE `/workspace`. In `full` workspace-mount mode
38
+ * `/workspace` is the entire working directory, so a `/workspace/packages`
39
+ * mount would shadow a real `packages/` directory in the user's tree — mikan's
40
+ * own repository has one. Living outside also keeps
41
+ * `translateMountedRuntimePathToHost` correct by construction: it maps only
42
+ * the `/workspace` prefix and returns everything else untouched, so a package
43
+ * path can never be mistranslated into a host path that does not exist.
44
+ *
45
+ * Skills are referenced by absolute path in the system prompt, so the location
46
+ * costs nothing in usability.
47
+ */
48
+ const PACKAGE_RUNTIME_ROOT = "/mikan/packages";
49
+ /** Runtime path a package's skills directory is mounted at. */
50
+ export function packageSkillRuntimeDir(slug) {
51
+ return `${PACKAGE_RUNTIME_ROOT}/${slug}/${SKILLS_SUBDIR}`;
52
+ }
53
+ /**
54
+ * Read-only mounts exposing every resolved package's skills to the sandbox.
55
+ *
56
+ * Read-only rather than read-write because the host owns these files: the
57
+ * directory is a git checkout that an update replaces wholesale, so an agent
58
+ * edit would be silently discarded on the next refresh. Making the filesystem
59
+ * refuse the write turns a confusing data-loss bug into an obvious error.
60
+ *
61
+ * Resolution is offline, so building the mount list never reaches the network.
62
+ */
63
+ export function conversationPackageSkillMounts(options) {
64
+ return resolveConversationPackages(options).skillDirs.map(({ slug, dir }) => ({
65
+ source: dir,
66
+ target: packageSkillRuntimeDir(slug),
67
+ readOnly: true,
68
+ }));
69
+ }
70
+ /**
71
+ * Resolve the package set for one conversation. Reads both scopes' settings,
72
+ * dedups, and reports the directories to load from.
73
+ */
74
+ export function resolveConversationPackages(options) {
75
+ const declarations = [...readScope("global", options), ...readScope("conversation", options)];
76
+ const errors = [];
77
+ const byIdentity = new Map();
78
+ for (const declaration of declarations) {
79
+ let identity;
80
+ try {
81
+ identity = sourceIdentity(parseSource(declaration.source));
82
+ }
83
+ catch (err) {
84
+ errors.push({ source: declaration.source, message: messageOf(err) });
85
+ continue;
86
+ }
87
+ // Later scopes overwrite earlier ones: global is read first, so a
88
+ // conversation declaring the same package shadows it.
89
+ const existing = byIdentity.get(identity);
90
+ if (existing && existing.scope !== declaration.scope) {
91
+ log.logInfo(`Package ${identity} declared in both scopes; using the conversation's copy`);
92
+ }
93
+ const materialized = materialize(declaration, options, errors);
94
+ if (materialized)
95
+ byIdentity.set(identity, materialized);
96
+ else
97
+ byIdentity.delete(identity);
98
+ }
99
+ const packages = [...byIdentity.values()].toSorted(scopeOrder);
100
+ const targets = packages.map(packageExtensionTargets);
101
+ return {
102
+ packages,
103
+ extensionDirs: [...scopeConventionDirs(options), ...targets.flatMap((target) => target.dirs)],
104
+ extensionRoots: targets.flatMap((target) => target.roots),
105
+ skillDirs: packages.flatMap(packageSkillDir),
106
+ errors,
107
+ };
108
+ }
109
+ function readScope(scope, options) {
110
+ try {
111
+ const sources = scope === "global"
112
+ ? loadGlobalSettings().packages
113
+ : resolveConversationSettings(options.office).packages;
114
+ return (sources ?? []).map((source) => ({ source, scope }));
115
+ }
116
+ catch (err) {
117
+ // Unreadable settings must not take the conversation down; the other
118
+ // scope, and the convention directories, still load.
119
+ log.logWarning(`Could not read ${scope} package list`, messageOf(err));
120
+ return [];
121
+ }
122
+ }
123
+ function materialize(declaration, options, errors) {
124
+ try {
125
+ return materializeSource(declaration.source, {
126
+ scope: declaration.scope,
127
+ address: options.office.address,
128
+ stateDir: options.office.workspace.stateDir,
129
+ mode: options.fetchMissing ? "fetch" : "offline",
130
+ });
131
+ }
132
+ catch (err) {
133
+ errors.push({ source: declaration.source, message: messageOf(err) });
134
+ return undefined;
135
+ }
136
+ }
137
+ /**
138
+ * The convention directories that need no declaration:
139
+ * `<stateDir>/global/extensions` and
140
+ * `<stateDir>/conversations/<id>/extensions`. These are the directories
141
+ * `mikan ext install` writes into, so CLI installs and portal-declared
142
+ * packages coexist.
143
+ */
144
+ function scopeConventionDirs(options) {
145
+ return [
146
+ join(packageScopeDir("global", undefined, options.office.workspace.stateDir), EXTENSIONS_SUBDIR),
147
+ join(options.office.stateDir, EXTENSIONS_SUBDIR),
148
+ ];
149
+ }
150
+ /**
151
+ * How a package contributes extensions. Two shapes are accepted, and which one
152
+ * applies is decided by the package's own layout rather than by configuration:
153
+ *
154
+ * - **Collection**: an `extensions/` subdirectory, scanned for named children.
155
+ * This is the shape a repository shipping several extensions has.
156
+ * - **Single extension**: no `extensions/` subdirectory, but the package root
157
+ * is itself a loadable extension (an index file, or a `package.json` with
158
+ * `mikan.extensions`). This is what a one-extension repo looks like, and it
159
+ * is what a developer's working copy looks like — so `mikan ext dev` needs
160
+ * no special case.
161
+ *
162
+ * The slug comes from the package directory name in the single-extension
163
+ * shape, so a repo named for its extension gets the identity its author
164
+ * expects.
165
+ */
166
+ function packageExtensionTargets(pkg) {
167
+ const collection = join(pkg.dir, EXTENSIONS_SUBDIR);
168
+ if (existsSync(collection))
169
+ return { dirs: [collection], roots: [] };
170
+ return { dirs: [], roots: [pkg.dir] };
171
+ }
172
+ function packageSkillDir(pkg) {
173
+ const dir = join(pkg.dir, SKILLS_SUBDIR);
174
+ if (!existsSync(dir) || !statSync(dir).isDirectory())
175
+ return [];
176
+ return [{ slug: packageSlug(pkg), dir }];
177
+ }
178
+ /**
179
+ * Filesystem-safe, collision-resistant name for a package, used as the mount
180
+ * path segment for its skills. Derived from the identity rather than the
181
+ * source string so the same package spelled two ways gets one name.
182
+ */
183
+ function packageSlug(pkg) {
184
+ const readable = pkg.identity
185
+ .replace(/^(git|local):/, "")
186
+ .toLowerCase()
187
+ .replace(/[^a-z0-9._-]+/g, "-")
188
+ .replace(/^-+|-+$/g, "");
189
+ if (readable.length <= SLUG_MAX_LENGTH)
190
+ return readable;
191
+ // Truncation alone would let two long identities sharing a prefix (deeply
192
+ // nested self-hosted groups, file:// paths) land on the same slug — and
193
+ // therefore the same mount target, where one package's skills would quietly
194
+ // replace the other's. The digest makes the tail collision-resistant.
195
+ const digest = createHash("sha256").update(pkg.identity).digest("hex").slice(0, 8);
196
+ return `${readable.slice(0, SLUG_MAX_LENGTH - digest.length - 1)}-${digest}`;
197
+ }
198
+ /** Global packages load before conversation ones. */
199
+ function scopeRank(scope) {
200
+ return scope === "global" ? 0 : 1;
201
+ }
202
+ function scopeOrder(a, b) {
203
+ return scopeRank(a.scope) - scopeRank(b.scope);
204
+ }
205
+ function messageOf(err) {
206
+ return err instanceof Error ? err.message : String(err);
207
+ }
208
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/packages/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a conversation actually loads: the two scopes' declared packages\n * combined, collisions resolved, and each surviving package turned into the\n * directories the extension loader and the skill loader consume.\n *\n * Two rules do all the work here:\n *\n * - **Additive scopes.** `global` packages load for every conversation; a\n * conversation's packages load on top. Neither list replaces the other.\n * - **Narrower scope wins.** When both scopes declare the same package\n * ({@link sourceIdentity}, which ignores the ref), only the conversation's\n * copy loads. That is what makes \"pin this one channel to v2 while everyone\n * else stays on v1\" work, and it is why the same package installed twice\n * cannot activate twice.\n *\n * Resolution never throws. A conversation with one malformed or unfetchable\n * source still loads every other package, and the failure is reported through\n * {@link ResolvedPackages.errors} for the portal and the logs. The alternative\n * — one bad string in settings taking a conversation offline — is a far worse\n * failure mode than a missing feature.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadGlobalSettings, resolveConversationSettings } from \"../config.js\";\nimport * as log from \"../log.js\";\nimport { materializeSource, packageScopeDir } from \"./materialize.js\";\nimport { parseSource, sourceIdentity } from \"./source.js\";\nimport type {\n MaterializedPackage,\n PackageError,\n PackageScope,\n PackageSkillDir,\n ResolvePackagesOptions,\n ResolvedPackages,\n} from \"./types.js\";\n\nexport type { ResolvePackagesOptions, ResolvedPackages } from \"./types.js\";\n\n/** Conventional resource directories inside a package, mirroring pi's layout. */\nconst EXTENSIONS_SUBDIR = \"extensions\";\nconst SKILLS_SUBDIR = \"skills\";\n/** Slug length cap; long identities keep a digest tail instead of colliding. */\nconst SLUG_MAX_LENGTH = 96;\n\n/**\n * Where package resources appear inside the sandbox.\n *\n * Deliberately OUTSIDE `/workspace`. In `full` workspace-mount mode\n * `/workspace` is the entire working directory, so a `/workspace/packages`\n * mount would shadow a real `packages/` directory in the user's tree — mikan's\n * own repository has one. Living outside also keeps\n * `translateMountedRuntimePathToHost` correct by construction: it maps only\n * the `/workspace` prefix and returns everything else untouched, so a package\n * path can never be mistranslated into a host path that does not exist.\n *\n * Skills are referenced by absolute path in the system prompt, so the location\n * costs nothing in usability.\n */\nconst PACKAGE_RUNTIME_ROOT = \"/mikan/packages\";\n\n/** Runtime path a package's skills directory is mounted at. */\nexport function packageSkillRuntimeDir(slug: string): string {\n return `${PACKAGE_RUNTIME_ROOT}/${slug}/${SKILLS_SUBDIR}`;\n}\n\n/**\n * Read-only mounts exposing every resolved package's skills to the sandbox.\n *\n * Read-only rather than read-write because the host owns these files: the\n * directory is a git checkout that an update replaces wholesale, so an agent\n * edit would be silently discarded on the next refresh. Making the filesystem\n * refuse the write turns a confusing data-loss bug into an obvious error.\n *\n * Resolution is offline, so building the mount list never reaches the network.\n */\nexport function conversationPackageSkillMounts(\n options: ResolvePackagesOptions,\n): Array<{ source: string; target: string; readOnly: true }> {\n return resolveConversationPackages(options).skillDirs.map(({ slug, dir }) => ({\n source: dir,\n target: packageSkillRuntimeDir(slug),\n readOnly: true,\n }));\n}\n\n/**\n * Resolve the package set for one conversation. Reads both scopes' settings,\n * dedups, and reports the directories to load from.\n */\nexport function resolveConversationPackages(options: ResolvePackagesOptions): ResolvedPackages {\n const declarations = [...readScope(\"global\", options), ...readScope(\"conversation\", options)];\n\n const errors: PackageError[] = [];\n const byIdentity = new Map<string, MaterializedPackage>();\n\n for (const declaration of declarations) {\n let identity: string;\n try {\n identity = sourceIdentity(parseSource(declaration.source));\n } catch (err) {\n errors.push({ source: declaration.source, message: messageOf(err) });\n continue;\n }\n // Later scopes overwrite earlier ones: global is read first, so a\n // conversation declaring the same package shadows it.\n const existing = byIdentity.get(identity);\n if (existing && existing.scope !== declaration.scope) {\n log.logInfo(`Package ${identity} declared in both scopes; using the conversation's copy`);\n }\n const materialized = materialize(declaration, options, errors);\n if (materialized) byIdentity.set(identity, materialized);\n else byIdentity.delete(identity);\n }\n\n const packages = [...byIdentity.values()].toSorted(scopeOrder);\n const targets = packages.map(packageExtensionTargets);\n return {\n packages,\n extensionDirs: [...scopeConventionDirs(options), ...targets.flatMap((target) => target.dirs)],\n extensionRoots: targets.flatMap((target) => target.roots),\n skillDirs: packages.flatMap(packageSkillDir),\n errors,\n };\n}\n\ninterface Declaration {\n source: string;\n scope: PackageScope;\n}\n\nfunction readScope(scope: PackageScope, options: ResolvePackagesOptions): Declaration[] {\n try {\n const sources =\n scope === \"global\"\n ? loadGlobalSettings().packages\n : resolveConversationSettings(options.office).packages;\n return (sources ?? []).map((source) => ({ source, scope }));\n } catch (err) {\n // Unreadable settings must not take the conversation down; the other\n // scope, and the convention directories, still load.\n log.logWarning(`Could not read ${scope} package list`, messageOf(err));\n return [];\n }\n}\n\nfunction materialize(\n declaration: Declaration,\n options: ResolvePackagesOptions,\n errors: PackageError[],\n): MaterializedPackage | undefined {\n try {\n return materializeSource(declaration.source, {\n scope: declaration.scope,\n address: options.office.address,\n stateDir: options.office.workspace.stateDir,\n mode: options.fetchMissing ? \"fetch\" : \"offline\",\n });\n } catch (err) {\n errors.push({ source: declaration.source, message: messageOf(err) });\n return undefined;\n }\n}\n\n/**\n * The convention directories that need no declaration:\n * `<stateDir>/global/extensions` and\n * `<stateDir>/conversations/<id>/extensions`. These are the directories\n * `mikan ext install` writes into, so CLI installs and portal-declared\n * packages coexist.\n */\nfunction scopeConventionDirs(options: ResolvePackagesOptions): string[] {\n return [\n join(\n packageScopeDir(\"global\", undefined, options.office.workspace.stateDir),\n EXTENSIONS_SUBDIR,\n ),\n join(options.office.stateDir, EXTENSIONS_SUBDIR),\n ];\n}\n\n/**\n * How a package contributes extensions. Two shapes are accepted, and which one\n * applies is decided by the package's own layout rather than by configuration:\n *\n * - **Collection**: an `extensions/` subdirectory, scanned for named children.\n * This is the shape a repository shipping several extensions has.\n * - **Single extension**: no `extensions/` subdirectory, but the package root\n * is itself a loadable extension (an index file, or a `package.json` with\n * `mikan.extensions`). This is what a one-extension repo looks like, and it\n * is what a developer's working copy looks like — so `mikan ext dev` needs\n * no special case.\n *\n * The slug comes from the package directory name in the single-extension\n * shape, so a repo named for its extension gets the identity its author\n * expects.\n */\nfunction packageExtensionTargets(pkg: MaterializedPackage): { dirs: string[]; roots: string[] } {\n const collection = join(pkg.dir, EXTENSIONS_SUBDIR);\n if (existsSync(collection)) return { dirs: [collection], roots: [] };\n return { dirs: [], roots: [pkg.dir] };\n}\n\nfunction packageSkillDir(pkg: MaterializedPackage): PackageSkillDir[] {\n const dir = join(pkg.dir, SKILLS_SUBDIR);\n if (!existsSync(dir) || !statSync(dir).isDirectory()) return [];\n return [{ slug: packageSlug(pkg), dir }];\n}\n\n/**\n * Filesystem-safe, collision-resistant name for a package, used as the mount\n * path segment for its skills. Derived from the identity rather than the\n * source string so the same package spelled two ways gets one name.\n */\nfunction packageSlug(pkg: MaterializedPackage): string {\n const readable = pkg.identity\n .replace(/^(git|local):/, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n if (readable.length <= SLUG_MAX_LENGTH) return readable;\n // Truncation alone would let two long identities sharing a prefix (deeply\n // nested self-hosted groups, file:// paths) land on the same slug — and\n // therefore the same mount target, where one package's skills would quietly\n // replace the other's. The digest makes the tail collision-resistant.\n const digest = createHash(\"sha256\").update(pkg.identity).digest(\"hex\").slice(0, 8);\n return `${readable.slice(0, SLUG_MAX_LENGTH - digest.length - 1)}-${digest}`;\n}\n\n/** Global packages load before conversation ones. */\nfunction scopeRank(scope: PackageScope): number {\n return scope === \"global\" ? 0 : 1;\n}\n\nfunction scopeOrder(a: MaterializedPackage, b: MaterializedPackage): number {\n return scopeRank(a.scope) - scopeRank(b.scope);\n}\n\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import type { PackageIdentity, ParsedSource } from "./types.js";
2
+ /**
3
+ * Whether a source string spells a git source (vs a local path) — the one
4
+ * home of the prefix rule. Classification only; `parseSource` still owns
5
+ * validation and error messages.
6
+ */
7
+ export declare function isGitSourceString(source: string): boolean;
8
+ /**
9
+ * Parse a source string. Throws with a user-facing message rather than
10
+ * returning undefined: every caller (portal, settings load, CLI) needs to tell
11
+ * the human what was wrong with what they typed.
12
+ */
13
+ export declare function parseSource(source: string): ParsedSource;
14
+ /**
15
+ * Identity of the package a source refers to — the key for deduplication and
16
+ * for letting a conversation's copy shadow the global one.
17
+ *
18
+ * Deliberate choices:
19
+ * - The ref is excluded: the same repo pinned to two refs in two scopes is one
20
+ * package installed twice, and the narrower scope wins.
21
+ * - The subpath is included: two extensions living at different paths in one
22
+ * monorepo are two packages.
23
+ * - Transport is excluded: `git@github.com:o/r`, `https://github.com/o/r.git`
24
+ * and `ssh://git@github.com/o/r` all identify the same package, so mixing
25
+ * SSH and HTTPS spellings across scopes still dedups.
26
+ */
27
+ export declare function sourceIdentity(parsed: ParsedSource): PackageIdentity;
28
+ /**
29
+ * Transport-independent `<host>/<path>` of a git URL, lowercased host, no
30
+ * `.git` suffix, no credentials. It is the base of the on-disk clone layout,
31
+ * so it must stay free of anything that is not a safe path segment.
32
+ */
33
+ export declare function gitRepoPath(url: string): string;
34
+ /**
35
+ * Canonical string form, used when writing settings so the stored value is
36
+ * stable regardless of how the human spelled it.
37
+ */
38
+ export declare function formatSource(parsed: ParsedSource): string;
39
+ //# sourceMappingURL=source.d.ts.map