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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/adapters/commands/login.d.ts.map +1 -1
  3. package/dist/adapters/commands/login.js +0 -9
  4. package/dist/adapters/commands/login.js.map +1 -1
  5. package/dist/adapters/commands/manifest.d.ts +0 -19
  6. package/dist/adapters/commands/manifest.d.ts.map +1 -1
  7. package/dist/adapters/commands/manifest.js +0 -34
  8. package/dist/adapters/commands/manifest.js.map +1 -1
  9. package/dist/adapters/commands/model.d.ts +0 -5
  10. package/dist/adapters/commands/model.d.ts.map +1 -1
  11. package/dist/adapters/commands/model.js +0 -5
  12. package/dist/adapters/commands/model.js.map +1 -1
  13. package/dist/adapters/commands/new.d.ts.map +1 -1
  14. package/dist/adapters/commands/new.js +0 -2
  15. package/dist/adapters/commands/new.js.map +1 -1
  16. package/dist/adapters/commands/registry.d.ts +0 -1
  17. package/dist/adapters/commands/registry.d.ts.map +1 -1
  18. package/dist/adapters/commands/registry.js +0 -8
  19. package/dist/adapters/commands/registry.js.map +1 -1
  20. package/dist/adapters/commands/session-view.d.ts.map +1 -1
  21. package/dist/adapters/commands/session-view.js +0 -2
  22. package/dist/adapters/commands/session-view.js.map +1 -1
  23. package/dist/adapters/commands/types.d.ts +0 -29
  24. package/dist/adapters/commands/types.d.ts.map +1 -1
  25. package/dist/adapters/commands/types.js.map +1 -1
  26. package/dist/adapters/commands/utils.d.ts +0 -3
  27. package/dist/adapters/commands/utils.d.ts.map +1 -1
  28. package/dist/adapters/commands/utils.js +0 -3
  29. package/dist/adapters/commands/utils.js.map +1 -1
  30. package/dist/adapters/discord/bot.d.ts +0 -4
  31. package/dist/adapters/discord/bot.d.ts.map +1 -1
  32. package/dist/adapters/discord/bot.js +5 -41
  33. package/dist/adapters/discord/bot.js.map +1 -1
  34. package/dist/adapters/discord/components.d.ts +0 -23
  35. package/dist/adapters/discord/components.d.ts.map +1 -1
  36. package/dist/adapters/discord/components.js +0 -23
  37. package/dist/adapters/discord/components.js.map +1 -1
  38. package/dist/adapters/discord/context.d.ts.map +1 -1
  39. package/dist/adapters/discord/context.js +1 -11
  40. package/dist/adapters/discord/context.js.map +1 -1
  41. package/dist/adapters/discord/format.d.ts +0 -1
  42. package/dist/adapters/discord/format.d.ts.map +1 -1
  43. package/dist/adapters/discord/format.js +0 -37
  44. package/dist/adapters/discord/format.js.map +1 -1
  45. package/dist/adapters/github/bot.d.ts +0 -44
  46. package/dist/adapters/github/bot.d.ts.map +1 -1
  47. package/dist/adapters/github/bot.js +1 -120
  48. package/dist/adapters/github/bot.js.map +1 -1
  49. package/dist/adapters/github/client.d.ts +0 -57
  50. package/dist/adapters/github/client.d.ts.map +1 -1
  51. package/dist/adapters/github/client.js +0 -59
  52. package/dist/adapters/github/client.js.map +1 -1
  53. package/dist/adapters/github/context.d.ts.map +1 -1
  54. package/dist/adapters/github/context.js +1 -8
  55. package/dist/adapters/github/context.js.map +1 -1
  56. package/dist/adapters/github/github-ops.d.ts +0 -55
  57. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  58. package/dist/adapters/github/github-ops.js +0 -59
  59. package/dist/adapters/github/github-ops.js.map +1 -1
  60. package/dist/adapters/github/ids.d.ts +0 -27
  61. package/dist/adapters/github/ids.d.ts.map +1 -1
  62. package/dist/adapters/github/ids.js +0 -29
  63. package/dist/adapters/github/ids.js.map +1 -1
  64. package/dist/adapters/github/repo.d.ts +0 -25
  65. package/dist/adapters/github/repo.d.ts.map +1 -1
  66. package/dist/adapters/github/repo.js +0 -49
  67. package/dist/adapters/github/repo.js.map +1 -1
  68. package/dist/adapters/github/tool-pack.d.ts +0 -10
  69. package/dist/adapters/github/tool-pack.d.ts.map +1 -1
  70. package/dist/adapters/github/tool-pack.js +0 -10
  71. package/dist/adapters/github/tool-pack.js.map +1 -1
  72. package/dist/adapters/github/tools/checks.d.ts +0 -6
  73. package/dist/adapters/github/tools/checks.d.ts.map +1 -1
  74. package/dist/adapters/github/tools/checks.js +0 -7
  75. package/dist/adapters/github/tools/checks.js.map +1 -1
  76. package/dist/adapters/github/tools/issue.d.ts +0 -5
  77. package/dist/adapters/github/tools/issue.d.ts.map +1 -1
  78. package/dist/adapters/github/tools/issue.js +0 -5
  79. package/dist/adapters/github/tools/issue.js.map +1 -1
  80. package/dist/adapters/github/tools/pr.d.ts +0 -7
  81. package/dist/adapters/github/tools/pr.d.ts.map +1 -1
  82. package/dist/adapters/github/tools/pr.js +0 -7
  83. package/dist/adapters/github/tools/pr.js.map +1 -1
  84. package/dist/adapters/github/tools/read.d.ts +0 -6
  85. package/dist/adapters/github/tools/read.d.ts.map +1 -1
  86. package/dist/adapters/github/tools/read.js +0 -8
  87. package/dist/adapters/github/tools/read.js.map +1 -1
  88. package/dist/adapters/github/tools/review-reply.d.ts +0 -5
  89. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
  90. package/dist/adapters/github/tools/review-reply.js +0 -5
  91. package/dist/adapters/github/tools/review-reply.js.map +1 -1
  92. package/dist/adapters/github/tools/sync.d.ts +0 -6
  93. package/dist/adapters/github/tools/sync.d.ts.map +1 -1
  94. package/dist/adapters/github/tools/sync.js +0 -6
  95. package/dist/adapters/github/tools/sync.js.map +1 -1
  96. package/dist/adapters/github/types.d.ts +0 -88
  97. package/dist/adapters/github/types.d.ts.map +1 -1
  98. package/dist/adapters/github/types.js.map +1 -1
  99. package/dist/adapters/github/webhook.d.ts +0 -13
  100. package/dist/adapters/github/webhook.d.ts.map +1 -1
  101. package/dist/adapters/github/webhook.js +0 -16
  102. package/dist/adapters/github/webhook.js.map +1 -1
  103. package/dist/adapters/index.d.ts +3 -4
  104. package/dist/adapters/index.d.ts.map +1 -1
  105. package/dist/adapters/index.js +4 -4
  106. package/dist/adapters/index.js.map +1 -1
  107. package/dist/adapters/intake.d.ts +0 -17
  108. package/dist/adapters/intake.d.ts.map +1 -1
  109. package/dist/adapters/intake.js +6 -32
  110. package/dist/adapters/intake.js.map +1 -1
  111. package/dist/adapters/markdown-tables.d.ts +0 -10
  112. package/dist/adapters/markdown-tables.d.ts.map +1 -1
  113. package/dist/adapters/markdown-tables.js +1 -42
  114. package/dist/adapters/markdown-tables.js.map +1 -1
  115. package/dist/adapters/progressive-renderer.d.ts.map +1 -1
  116. package/dist/adapters/progressive-renderer.js +3 -25
  117. package/dist/adapters/progressive-renderer.js.map +1 -1
  118. package/dist/adapters/shared.d.ts +0 -57
  119. package/dist/adapters/shared.d.ts.map +1 -1
  120. package/dist/adapters/shared.js +0 -71
  121. package/dist/adapters/shared.js.map +1 -1
  122. package/dist/adapters/slack/assistant.d.ts +0 -49
  123. package/dist/adapters/slack/assistant.d.ts.map +1 -1
  124. package/dist/adapters/slack/assistant.js +0 -97
  125. package/dist/adapters/slack/assistant.js.map +1 -1
  126. package/dist/adapters/slack/auto-reply-context.d.ts +0 -7
  127. package/dist/adapters/slack/auto-reply-context.d.ts.map +1 -1
  128. package/dist/adapters/slack/auto-reply-context.js +0 -7
  129. package/dist/adapters/slack/auto-reply-context.js.map +1 -1
  130. package/dist/adapters/slack/blocks.d.ts +0 -9
  131. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  132. package/dist/adapters/slack/blocks.js +0 -20
  133. package/dist/adapters/slack/blocks.js.map +1 -1
  134. package/dist/adapters/slack/bot.d.ts +0 -116
  135. package/dist/adapters/slack/bot.d.ts.map +1 -1
  136. package/dist/adapters/slack/bot.js +7 -231
  137. package/dist/adapters/slack/bot.js.map +1 -1
  138. package/dist/adapters/slack/context.d.ts.map +1 -1
  139. package/dist/adapters/slack/context.js +1 -3
  140. package/dist/adapters/slack/context.js.map +1 -1
  141. package/dist/adapters/slack/jev-context.d.ts +0 -13
  142. package/dist/adapters/slack/jev-context.d.ts.map +1 -1
  143. package/dist/adapters/slack/jev-context.js +0 -12
  144. package/dist/adapters/slack/jev-context.js.map +1 -1
  145. package/dist/adapters/slack/markdown.d.ts +0 -1
  146. package/dist/adapters/slack/markdown.d.ts.map +1 -1
  147. package/dist/adapters/slack/markdown.js +0 -5
  148. package/dist/adapters/slack/markdown.js.map +1 -1
  149. package/dist/adapters/slack/persona.d.ts +0 -9
  150. package/dist/adapters/slack/persona.d.ts.map +1 -1
  151. package/dist/adapters/slack/persona.js +0 -9
  152. package/dist/adapters/slack/persona.js.map +1 -1
  153. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  154. package/dist/adapters/slack/response-lifecycle.js +1 -45
  155. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  156. package/dist/adapters/slack/session.d.ts +2 -1
  157. package/dist/adapters/slack/session.d.ts.map +1 -1
  158. package/dist/adapters/slack/session.js +2 -2
  159. package/dist/adapters/slack/session.js.map +1 -1
  160. package/dist/adapters/slack/stream-limits.d.ts +0 -25
  161. package/dist/adapters/slack/stream-limits.d.ts.map +1 -1
  162. package/dist/adapters/slack/stream-limits.js +0 -34
  163. package/dist/adapters/slack/stream-limits.js.map +1 -1
  164. package/dist/adapters/slack/task-intent.d.ts +0 -13
  165. package/dist/adapters/slack/task-intent.d.ts.map +1 -1
  166. package/dist/adapters/slack/task-intent.js +0 -7
  167. package/dist/adapters/slack/task-intent.js.map +1 -1
  168. package/dist/adapters/slack/task-status.d.ts +0 -1
  169. package/dist/adapters/slack/task-status.d.ts.map +1 -1
  170. package/dist/adapters/slack/task-status.js +1 -9
  171. package/dist/adapters/slack/task-status.js.map +1 -1
  172. package/dist/adapters/slack/tool-pack.d.ts +0 -6
  173. package/dist/adapters/slack/tool-pack.d.ts.map +1 -1
  174. package/dist/adapters/slack/tool-pack.js +0 -6
  175. package/dist/adapters/slack/tool-pack.js.map +1 -1
  176. package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -1
  177. package/dist/adapters/slack/tools/blockkit.js +0 -11
  178. package/dist/adapters/slack/tools/blockkit.js.map +1 -1
  179. package/dist/adapters/slack/types.d.ts +0 -19
  180. package/dist/adapters/slack/types.d.ts.map +1 -1
  181. package/dist/adapters/slack/types.js.map +1 -1
  182. package/dist/adapters/slack/update-diagnostics.d.ts +0 -1
  183. package/dist/adapters/slack/update-diagnostics.d.ts.map +1 -1
  184. package/dist/adapters/slack/update-diagnostics.js +1 -7
  185. package/dist/adapters/slack/update-diagnostics.js.map +1 -1
  186. package/dist/adapters/telegram/bot.d.ts +0 -6
  187. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  188. package/dist/adapters/telegram/bot.js +1 -50
  189. package/dist/adapters/telegram/bot.js.map +1 -1
  190. package/dist/adapters/telegram/context.d.ts.map +1 -1
  191. package/dist/adapters/telegram/context.js +1 -8
  192. package/dist/adapters/telegram/context.js.map +1 -1
  193. package/dist/adapters/types.d.ts +0 -57
  194. package/dist/adapters/types.d.ts.map +1 -1
  195. package/dist/adapters/types.js.map +1 -1
  196. package/dist/adapters/web/admin/client-assets.d.ts +4 -0
  197. package/dist/adapters/web/admin/client-assets.d.ts.map +1 -0
  198. package/dist/adapters/web/admin/client-assets.js +1765 -0
  199. package/dist/adapters/web/admin/client-assets.js.map +1 -0
  200. package/dist/adapters/web/admin/portal.d.ts +0 -10
  201. package/dist/adapters/web/admin/portal.d.ts.map +1 -1
  202. package/dist/adapters/web/admin/portal.js +6 -1909
  203. package/dist/adapters/web/admin/portal.js.map +1 -1
  204. package/dist/adapters/web/admin/types.d.ts +0 -3
  205. package/dist/adapters/web/admin/types.d.ts.map +1 -1
  206. package/dist/adapters/web/admin/types.js.map +1 -1
  207. package/dist/adapters/web/login/oauth.d.ts.map +1 -1
  208. package/dist/adapters/web/login/oauth.js +3 -7
  209. package/dist/adapters/web/login/oauth.js.map +1 -1
  210. package/dist/adapters/web/login/portal.d.ts +0 -10
  211. package/dist/adapters/web/login/portal.d.ts.map +1 -1
  212. package/dist/adapters/web/login/portal.js +4 -37
  213. package/dist/adapters/web/login/portal.js.map +1 -1
  214. package/dist/adapters/web/login/types.d.ts +0 -5
  215. package/dist/adapters/web/login/types.d.ts.map +1 -1
  216. package/dist/adapters/web/login/types.js.map +1 -1
  217. package/dist/adapters/web/portal-shell.d.ts +0 -12
  218. package/dist/adapters/web/portal-shell.d.ts.map +1 -1
  219. package/dist/adapters/web/portal-shell.js +8 -25
  220. package/dist/adapters/web/portal-shell.js.map +1 -1
  221. package/dist/adapters/web/server.d.ts +0 -1
  222. package/dist/adapters/web/server.d.ts.map +1 -1
  223. package/dist/adapters/web/server.js +0 -2
  224. package/dist/adapters/web/server.js.map +1 -1
  225. package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
  226. package/dist/adapters/web/session-view/portal.js +13 -24
  227. package/dist/adapters/web/session-view/portal.js.map +1 -1
  228. package/dist/adapters/web/session-view/types.d.ts.map +1 -1
  229. package/dist/adapters/web/session-view/types.js.map +1 -1
  230. package/dist/adapters/web/token-store.d.ts +0 -2
  231. package/dist/adapters/web/token-store.d.ts.map +1 -1
  232. package/dist/adapters/web/token-store.js +0 -2
  233. package/dist/adapters/web/token-store.js.map +1 -1
  234. package/dist/cli/arg-grammar.d.ts +0 -3
  235. package/dist/cli/arg-grammar.d.ts.map +1 -1
  236. package/dist/cli/arg-grammar.js +0 -3
  237. package/dist/cli/arg-grammar.js.map +1 -1
  238. package/dist/cli/boot.d.ts.map +1 -1
  239. package/dist/cli/boot.js +3 -12
  240. package/dist/cli/boot.js.map +1 -1
  241. package/dist/cli/download.d.ts.map +1 -1
  242. package/dist/cli/download.js +2 -6
  243. package/dist/cli/download.js.map +1 -1
  244. package/dist/cli/office.d.ts.map +1 -1
  245. package/dist/cli/office.js +0 -31
  246. package/dist/cli/office.js.map +1 -1
  247. package/dist/cli/onboard.d.ts +0 -2
  248. package/dist/cli/onboard.d.ts.map +1 -1
  249. package/dist/cli/onboard.js +0 -30
  250. package/dist/cli/onboard.js.map +1 -1
  251. package/dist/cli/process-lifecycle.d.ts +0 -5
  252. package/dist/cli/process-lifecycle.d.ts.map +1 -1
  253. package/dist/cli/process-lifecycle.js +0 -6
  254. package/dist/cli/process-lifecycle.js.map +1 -1
  255. package/dist/cli/sandbox.d.ts +3 -0
  256. package/dist/cli/sandbox.d.ts.map +1 -0
  257. package/dist/cli/sandbox.js +79 -0
  258. package/dist/cli/sandbox.js.map +1 -0
  259. package/dist/cli/sessions.d.ts.map +1 -1
  260. package/dist/cli/sessions.js +0 -11
  261. package/dist/cli/sessions.js.map +1 -1
  262. package/dist/cli/types.d.ts +2 -6
  263. package/dist/cli/types.d.ts.map +1 -1
  264. package/dist/cli/types.js.map +1 -1
  265. package/dist/env-manifest.d.ts +0 -21
  266. package/dist/env-manifest.d.ts.map +1 -1
  267. package/dist/env-manifest.js +0 -11
  268. package/dist/env-manifest.js.map +1 -1
  269. package/dist/events/index.d.ts +0 -51
  270. package/dist/events/index.d.ts.map +1 -1
  271. package/dist/events/index.js +0 -42
  272. package/dist/events/index.js.map +1 -1
  273. package/dist/events/scheduler.d.ts +0 -8
  274. package/dist/events/scheduler.d.ts.map +1 -1
  275. package/dist/events/scheduler.js +0 -8
  276. package/dist/events/scheduler.js.map +1 -1
  277. package/dist/file-guards.d.ts +0 -15
  278. package/dist/file-guards.d.ts.map +1 -1
  279. package/dist/file-guards.js +2 -26
  280. package/dist/file-guards.js.map +1 -1
  281. package/dist/harness/execution-env.d.ts +0 -15
  282. package/dist/harness/execution-env.d.ts.map +1 -1
  283. package/dist/harness/execution-env.js +4 -55
  284. package/dist/harness/execution-env.js.map +1 -1
  285. package/dist/harness/http.d.ts +0 -12
  286. package/dist/harness/http.d.ts.map +1 -1
  287. package/dist/harness/http.js +0 -34
  288. package/dist/harness/http.js.map +1 -1
  289. package/dist/harness/index.d.ts +4 -7
  290. package/dist/harness/index.d.ts.map +1 -1
  291. package/dist/harness/index.js +4 -7
  292. package/dist/harness/index.js.map +1 -1
  293. package/dist/harness/jev.d.ts +0 -28
  294. package/dist/harness/jev.d.ts.map +1 -1
  295. package/dist/harness/jev.js +0 -45
  296. package/dist/harness/jev.js.map +1 -1
  297. package/dist/harness/mcp-result.d.ts +20 -0
  298. package/dist/harness/mcp-result.d.ts.map +1 -0
  299. package/dist/harness/mcp-result.js +171 -0
  300. package/dist/harness/mcp-result.js.map +1 -0
  301. package/dist/harness/mcp.d.ts +0 -19
  302. package/dist/harness/mcp.d.ts.map +1 -1
  303. package/dist/harness/mcp.js +7 -66
  304. package/dist/harness/mcp.js.map +1 -1
  305. package/dist/harness/models.d.ts +0 -19
  306. package/dist/harness/models.d.ts.map +1 -1
  307. package/dist/harness/models.js +0 -52
  308. package/dist/harness/models.js.map +1 -1
  309. package/dist/harness/open-connector.d.ts +0 -12
  310. package/dist/harness/open-connector.d.ts.map +1 -1
  311. package/dist/harness/open-connector.js +0 -22
  312. package/dist/harness/open-connector.js.map +1 -1
  313. package/dist/harness/presenter.d.ts +1 -0
  314. package/dist/harness/presenter.d.ts.map +1 -1
  315. package/dist/harness/presenter.js +16 -66
  316. package/dist/harness/presenter.js.map +1 -1
  317. package/dist/harness/prompt.d.ts +0 -11
  318. package/dist/harness/prompt.d.ts.map +1 -1
  319. package/dist/harness/prompt.js +1 -18
  320. package/dist/harness/prompt.js.map +1 -1
  321. package/dist/harness/runner.d.ts.map +1 -1
  322. package/dist/harness/runner.js +8 -28
  323. package/dist/harness/runner.js.map +1 -1
  324. package/dist/harness/session.d.ts +11 -28
  325. package/dist/harness/session.d.ts.map +1 -1
  326. package/dist/harness/session.js +100 -38
  327. package/dist/harness/session.js.map +1 -1
  328. package/dist/harness/skills.d.ts +0 -22
  329. package/dist/harness/skills.d.ts.map +1 -1
  330. package/dist/harness/skills.js +0 -20
  331. package/dist/harness/skills.js.map +1 -1
  332. package/dist/harness/subagent-profiles.d.ts +0 -4
  333. package/dist/harness/subagent-profiles.d.ts.map +1 -1
  334. package/dist/harness/subagent-profiles.js +0 -29
  335. package/dist/harness/subagent-profiles.js.map +1 -1
  336. package/dist/harness/subagent.d.ts +0 -25
  337. package/dist/harness/subagent.d.ts.map +1 -1
  338. package/dist/harness/subagent.js +1 -70
  339. package/dist/harness/subagent.js.map +1 -1
  340. package/dist/harness/tools/event.d.ts.map +1 -1
  341. package/dist/harness/tools/event.js +0 -9
  342. package/dist/harness/tools/event.js.map +1 -1
  343. package/dist/harness/tools/generate-image.d.ts +0 -6
  344. package/dist/harness/tools/generate-image.d.ts.map +1 -1
  345. package/dist/harness/tools/generate-image.js.map +1 -1
  346. package/dist/harness/tools/host-fn-tool.d.ts +0 -17
  347. package/dist/harness/tools/host-fn-tool.d.ts.map +1 -1
  348. package/dist/harness/tools/host-fn-tool.js +0 -16
  349. package/dist/harness/tools/host-fn-tool.js.map +1 -1
  350. package/dist/harness/tools/index.d.ts +1 -7
  351. package/dist/harness/tools/index.d.ts.map +1 -1
  352. package/dist/harness/tools/index.js +3 -14
  353. package/dist/harness/tools/index.js.map +1 -1
  354. package/dist/harness/tools/jev-browser.d.ts +4 -94
  355. package/dist/harness/tools/jev-browser.d.ts.map +1 -1
  356. package/dist/harness/tools/jev-browser.js +203 -92
  357. package/dist/harness/tools/jev-browser.js.map +1 -1
  358. package/dist/harness/tools/jev.d.ts +0 -8
  359. package/dist/harness/tools/jev.d.ts.map +1 -1
  360. package/dist/harness/tools/jev.js +0 -11
  361. package/dist/harness/tools/jev.js.map +1 -1
  362. package/dist/harness/tools/pi-tools.d.ts +1 -11
  363. package/dist/harness/tools/pi-tools.d.ts.map +1 -1
  364. package/dist/harness/tools/pi-tools.js +1 -30
  365. package/dist/harness/tools/pi-tools.js.map +1 -1
  366. package/dist/harness/tools/react.d.ts +0 -5
  367. package/dist/harness/tools/react.d.ts.map +1 -1
  368. package/dist/harness/tools/react.js +0 -5
  369. package/dist/harness/tools/react.js.map +1 -1
  370. package/dist/harness/tools/secret-redaction.d.ts +0 -25
  371. package/dist/harness/tools/secret-redaction.d.ts.map +1 -1
  372. package/dist/harness/tools/secret-redaction.js +3 -36
  373. package/dist/harness/tools/secret-redaction.js.map +1 -1
  374. package/dist/harness/tools/subagent.d.ts +0 -34
  375. package/dist/harness/tools/subagent.d.ts.map +1 -1
  376. package/dist/harness/tools/subagent.js +0 -92
  377. package/dist/harness/tools/subagent.js.map +1 -1
  378. package/dist/harness/tools/task.d.ts +0 -1
  379. package/dist/harness/tools/task.d.ts.map +1 -1
  380. package/dist/harness/tools/task.js +0 -1
  381. package/dist/harness/tools/task.js.map +1 -1
  382. package/dist/harness/tools/types.d.ts +0 -16
  383. package/dist/harness/tools/types.d.ts.map +1 -1
  384. package/dist/harness/tools/types.js.map +1 -1
  385. package/dist/harness/types.d.ts +1 -77
  386. package/dist/harness/types.d.ts.map +1 -1
  387. package/dist/harness/types.js.map +1 -1
  388. package/dist/index.d.ts.map +1 -1
  389. package/dist/index.js +0 -2
  390. package/dist/index.js.map +1 -1
  391. package/dist/log.d.ts.map +1 -1
  392. package/dist/log.js +0 -13
  393. package/dist/log.js.map +1 -1
  394. package/dist/main.js +7 -52
  395. package/dist/main.js.map +1 -1
  396. package/dist/memory-capture/index.d.ts +16 -0
  397. package/dist/memory-capture/index.d.ts.map +1 -0
  398. package/dist/memory-capture/index.js +194 -0
  399. package/dist/memory-capture/index.js.map +1 -0
  400. package/dist/memory-capture/types.d.ts +27 -0
  401. package/dist/memory-capture/types.d.ts.map +1 -0
  402. package/dist/memory-capture/types.js.map +1 -0
  403. package/dist/observability/index.d.ts +0 -9
  404. package/dist/observability/index.d.ts.map +1 -1
  405. package/dist/observability/index.js +0 -9
  406. package/dist/observability/index.js.map +1 -1
  407. package/dist/observability/instrument.js +0 -5
  408. package/dist/observability/instrument.js.map +1 -1
  409. package/dist/observability/otel.js +0 -1
  410. package/dist/observability/otel.js.map +1 -1
  411. package/dist/observability/sentry.d.ts +0 -18
  412. package/dist/observability/sentry.d.ts.map +1 -1
  413. package/dist/observability/sentry.js +0 -36
  414. package/dist/observability/sentry.js.map +1 -1
  415. package/dist/observability/types.d.ts +1 -10
  416. package/dist/observability/types.d.ts.map +1 -1
  417. package/dist/observability/types.js.map +1 -1
  418. package/dist/office/index.d.ts +0 -76
  419. package/dist/office/index.d.ts.map +1 -1
  420. package/dist/office/index.js +4 -154
  421. package/dist/office/index.js.map +1 -1
  422. package/dist/office/projection.d.ts +0 -29
  423. package/dist/office/projection.d.ts.map +1 -1
  424. package/dist/office/projection.js +5 -41
  425. package/dist/office/projection.js.map +1 -1
  426. package/dist/office/types.d.ts +0 -66
  427. package/dist/office/types.d.ts.map +1 -1
  428. package/dist/office/types.js.map +1 -1
  429. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  430. package/dist/runtime/conversation-runtime.js +22 -83
  431. package/dist/runtime/conversation-runtime.js.map +1 -1
  432. package/dist/runtime/session-lifecycle.d.ts +0 -10
  433. package/dist/runtime/session-lifecycle.d.ts.map +1 -1
  434. package/dist/runtime/session-lifecycle.js +0 -12
  435. package/dist/runtime/session-lifecycle.js.map +1 -1
  436. package/dist/runtime/types.d.ts +2 -29
  437. package/dist/runtime/types.d.ts.map +1 -1
  438. package/dist/runtime/types.js.map +1 -1
  439. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  440. package/dist/sandbox/cloudflare.js +2 -1
  441. package/dist/sandbox/cloudflare.js.map +1 -1
  442. package/dist/sandbox/container.d.ts.map +1 -1
  443. package/dist/sandbox/container.js +21 -15
  444. package/dist/sandbox/container.js.map +1 -1
  445. package/dist/sandbox/host.d.ts.map +1 -1
  446. package/dist/sandbox/host.js +0 -2
  447. package/dist/sandbox/host.js.map +1 -1
  448. package/dist/sandbox/identity.d.ts +0 -28
  449. package/dist/sandbox/identity.d.ts.map +1 -1
  450. package/dist/sandbox/identity.js +0 -28
  451. package/dist/sandbox/identity.js.map +1 -1
  452. package/dist/sandbox/index.d.ts +0 -18
  453. package/dist/sandbox/index.d.ts.map +1 -1
  454. package/dist/sandbox/index.js +2 -19
  455. package/dist/sandbox/index.js.map +1 -1
  456. package/dist/sandbox/layout.d.ts +7 -0
  457. package/dist/sandbox/layout.d.ts.map +1 -0
  458. package/dist/sandbox/layout.js +13 -0
  459. package/dist/sandbox/layout.js.map +1 -0
  460. package/dist/sandbox/provisioner.d.ts +24 -65
  461. package/dist/sandbox/provisioner.d.ts.map +1 -1
  462. package/dist/sandbox/provisioner.js +213 -125
  463. package/dist/sandbox/provisioner.js.map +1 -1
  464. package/dist/sandbox/types.d.ts +0 -39
  465. package/dist/sandbox/types.d.ts.map +1 -1
  466. package/dist/sandbox/types.js.map +1 -1
  467. package/dist/sandbox/utils.d.ts +2 -5
  468. package/dist/sandbox/utils.d.ts.map +1 -1
  469. package/dist/sandbox/utils.js +31 -31
  470. package/dist/sandbox/utils.js.map +1 -1
  471. package/dist/sessions/chat-history-sync.d.ts +0 -6
  472. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  473. package/dist/sessions/chat-history-sync.js +1 -33
  474. package/dist/sessions/chat-history-sync.js.map +1 -1
  475. package/dist/sessions/history-line.d.ts +0 -20
  476. package/dist/sessions/history-line.d.ts.map +1 -1
  477. package/dist/sessions/history-line.js +0 -20
  478. package/dist/sessions/history-line.js.map +1 -1
  479. package/dist/sessions/migrate-common.d.ts +0 -15
  480. package/dist/sessions/migrate-common.d.ts.map +1 -1
  481. package/dist/sessions/migrate-common.js +0 -19
  482. package/dist/sessions/migrate-common.js.map +1 -1
  483. package/dist/sessions/migrate-pi-084.d.ts.map +1 -1
  484. package/dist/sessions/migrate-pi-084.js +0 -7
  485. package/dist/sessions/migrate-pi-084.js.map +1 -1
  486. package/dist/sessions/migrate-v3.d.ts +0 -7
  487. package/dist/sessions/migrate-v3.d.ts.map +1 -1
  488. package/dist/sessions/migrate-v3.js +1 -67
  489. package/dist/sessions/migrate-v3.js.map +1 -1
  490. package/dist/sessions/session-key.d.ts +3 -17
  491. package/dist/sessions/session-key.d.ts.map +1 -1
  492. package/dist/sessions/session-key.js +8 -35
  493. package/dist/sessions/session-key.js.map +1 -1
  494. package/dist/sessions/session-store.d.ts +1 -7
  495. package/dist/sessions/session-store.d.ts.map +1 -1
  496. package/dist/sessions/session-store.js +8 -50
  497. package/dist/sessions/session-store.js.map +1 -1
  498. package/dist/sessions/store.d.ts +0 -60
  499. package/dist/sessions/store.d.ts.map +1 -1
  500. package/dist/sessions/store.js +0 -113
  501. package/dist/sessions/store.js.map +1 -1
  502. package/dist/sessions/types.d.ts +0 -17
  503. package/dist/sessions/types.d.ts.map +1 -1
  504. package/dist/sessions/types.js.map +1 -1
  505. package/dist/settings/apply.d.ts +0 -6
  506. package/dist/settings/apply.d.ts.map +1 -1
  507. package/dist/settings/apply.js +0 -29
  508. package/dist/settings/apply.js.map +1 -1
  509. package/dist/settings/index.d.ts +0 -53
  510. package/dist/settings/index.d.ts.map +1 -1
  511. package/dist/settings/index.js +0 -77
  512. package/dist/settings/index.js.map +1 -1
  513. package/dist/settings/migrate.d.ts +0 -5
  514. package/dist/settings/migrate.d.ts.map +1 -1
  515. package/dist/settings/migrate.js +0 -17
  516. package/dist/settings/migrate.js.map +1 -1
  517. package/dist/types.d.ts +9 -159
  518. package/dist/types.d.ts.map +1 -1
  519. package/dist/types.js.map +1 -1
  520. package/dist/vault/index.d.ts +2 -36
  521. package/dist/vault/index.d.ts.map +1 -1
  522. package/dist/vault/index.js +135 -65
  523. package/dist/vault/index.js.map +1 -1
  524. package/dist/vault/types.d.ts +0 -15
  525. package/dist/vault/types.d.ts.map +1 -1
  526. package/dist/vault/types.js.map +1 -1
  527. package/package.json +1 -1
  528. package/dist/dream/index.d.ts +0 -20
  529. package/dist/dream/index.d.ts.map +0 -1
  530. package/dist/dream/index.js +0 -264
  531. package/dist/dream/index.js.map +0 -1
  532. package/dist/dream/types.d.ts +0 -30
  533. package/dist/dream/types.d.ts.map +0 -1
  534. package/dist/dream/types.js.map +0 -1
  535. /package/dist/{dream → memory-capture}/types.js +0 -0
@@ -1,5 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { legacyConversationResourceKey, sanitizeIdentitySegment } from "./identity.js";
3
+ import { GUEST_HOME, GUEST_PUBLIC_OFFICES_DIR } from "./layout.js";
3
4
  import { createHash } from "node:crypto";
4
5
  import { readFileSync, statSync } from "node:fs";
5
6
  import { promisify } from "node:util";
@@ -19,7 +20,6 @@ function isDockerNotFoundError(err) {
19
20
  /network [^\n]+ not found/.test(haystack) ||
20
21
  /error: no such [^\n]+/.test(haystack));
21
22
  }
22
- /** Parse `src:dst[:ro]` back into a ContainerMount for signature computation. */
23
23
  function bindSpecToMount(bindSpec) {
24
24
  const readOnly = bindSpec.endsWith(":ro");
25
25
  const spec = readOnly ? bindSpec.slice(0, -3) : bindSpec;
@@ -43,6 +43,7 @@ export class DockerContainerManager {
43
43
  this.state = new Map();
44
44
  this.inflight = new Map();
45
45
  this.layoutMigrations = new Map();
46
+ this.keyQueues = new Map();
46
47
  this.boostedKeys = new Set();
47
48
  this.overrideLimits = new Map();
48
49
  this.limits = options.limits;
@@ -58,11 +59,25 @@ export class DockerContainerManager {
58
59
  static networkName(containerKey) {
59
60
  return `mikan-sandbox-net-${containerKey}`;
60
61
  }
62
+ static homeVolumeName(containerKey) {
63
+ return `mikan-home-${containerKey}`;
64
+ }
65
+ serialize(containerKey, task) {
66
+ const previous = this.keyQueues.get(containerKey) ?? Promise.resolve();
67
+ const next = previous.then(task, task);
68
+ const settled = next.catch(() => undefined);
69
+ this.keyQueues.set(containerKey, settled);
70
+ void settled.then(() => {
71
+ if (this.keyQueues.get(containerKey) === settled)
72
+ this.keyQueues.delete(containerKey);
73
+ });
74
+ return next;
75
+ }
61
76
  async provision(containerKey, options = {}) {
62
77
  const existing = this.inflight.get(containerKey);
63
78
  if (existing)
64
79
  return existing;
65
- const pending = this.provisionInner(containerKey, options).finally(() => {
80
+ const pending = this.serialize(containerKey, () => this.provisionInner(containerKey, options)).finally(() => {
66
81
  this.inflight.delete(containerKey);
67
82
  });
68
83
  this.inflight.set(containerKey, pending);
@@ -71,15 +86,25 @@ export class DockerContainerManager {
71
86
  async provisionInner(containerKey, options) {
72
87
  const containerName = options.containerName ?? DockerContainerManager.containerName(containerKey);
73
88
  const mounts = options.mounts ?? [];
74
- // A container still on the pre-office layout must move its writable layer
75
- // to the new mounts before the drift check below would recreate it from
76
- // the base image and discard everything installed inside.
77
89
  await this.migrateContainerLayout(containerName);
78
90
  const status = await this.inspectStatus(containerName);
79
91
  try {
80
- if (status !== "missing" &&
81
- (await this.hasRuntimeDrift(containerKey, containerName, mounts))) {
82
- log.logInfo(`Container ${containerName} configuration changed; recreating container`);
92
+ const binds = status === "missing" ? [] : await this.inspectBindMounts(containerName);
93
+ const homeVolume = this.hasHomeVolumeBind(containerKey, binds);
94
+ const drift = status === "missing"
95
+ ? undefined
96
+ : await this.runtimeDrift(containerKey, containerName, mounts, {
97
+ binds,
98
+ status,
99
+ homeVolume,
100
+ });
101
+ if (drift && homeVolume) {
102
+ log.logInfo(`Container ${containerName} is out of date (${drift}); replacing container`);
103
+ await this.replaceHomeVolumeContainer(containerKey, containerName, mounts, options);
104
+ log.logInfo(`Container ${containerName} replaced from image ${this.image}`);
105
+ }
106
+ else if (drift) {
107
+ log.logInfo(`Container ${containerName} configuration changed (${drift}); recreating container`);
83
108
  await this.recreateContainerPreservingContents(containerKey, containerName, mounts);
84
109
  log.logInfo(`Container ${containerName} recreated`);
85
110
  }
@@ -131,7 +156,10 @@ export class DockerContainerManager {
131
156
  getBoostLimits() {
132
157
  return this.boostLimits;
133
158
  }
134
- async stop(containerKey) {
159
+ stop(containerKey) {
160
+ return this.serialize(containerKey, () => this.stopInner(containerKey));
161
+ }
162
+ async stopInner(containerKey) {
135
163
  const containerName = this.getContainerName(containerKey);
136
164
  try {
137
165
  await this.execFileImpl("docker", ["stop", containerName]);
@@ -144,14 +172,14 @@ export class DockerContainerManager {
144
172
  log.logWarning(`Failed to stop container ${containerName}`, err instanceof Error ? err.message : String(err));
145
173
  }
146
174
  }
147
- async remove(containerKey) {
175
+ remove(containerKey, options = {}) {
176
+ return this.serialize(containerKey, () => this.removeInner(containerKey, options));
177
+ }
178
+ async removeInner(containerKey, options) {
148
179
  const containerName = this.getContainerName(containerKey);
149
180
  const networkName = DockerContainerManager.networkName(containerKey);
150
181
  const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed`, `Failed to remove container ${containerName}`);
151
182
  if (!removed) {
152
- // The container may still be running with its old mounts. Keeping the
153
- // ownership state (and throwing) is the honest outcome: callers such
154
- // as credential refresh must not report a teardown that did not happen.
155
183
  throw new Error(`Failed to remove container ${containerName}`);
156
184
  }
157
185
  try {
@@ -162,6 +190,8 @@ export class DockerContainerManager {
162
190
  log.logWarning(`Failed to remove network ${networkName}`, err instanceof Error ? err.message : String(err));
163
191
  }
164
192
  await this.removeMigrateSnapshot(containerName);
193
+ if (options.purgeHome)
194
+ await this.removeHomeVolume(containerKey);
165
195
  this.state.delete(containerKey);
166
196
  this.boostedKeys.delete(containerKey);
167
197
  this.overrideLimits.delete(containerKey);
@@ -176,12 +206,6 @@ export class DockerContainerManager {
176
206
  }
177
207
  await Promise.all(toStop.map((containerKey) => this.stop(containerKey)));
178
208
  }
179
- /**
180
- * Force-remove every managed container belonging to the given conversation
181
- * ids. The office layout migration renames the host directories a
182
- * container's workspace mount points at, so a surviving container would keep
183
- * writing through stale mounts while the runtime works in the new location.
184
- */
185
209
  async removeContainersForConversations(conversationIds) {
186
210
  if (conversationIds.size === 0)
187
211
  return;
@@ -190,33 +214,20 @@ export class DockerContainerManager {
190
214
  const details = await this.inspectContainerDetails(containerName);
191
215
  if (!details?.conversationId || !conversationIds.has(details.conversationId))
192
216
  return;
193
- await this.forceRemoveContainer(containerName, `Removed container ${containerName} after office migration`, `Failed to remove container ${containerName} after office migration`);
217
+ const removed = await this.forceRemoveContainer(containerName, `Removed container ${containerName} after office migration`, `Failed to remove container ${containerName} after office migration`);
218
+ const containerKey = this.containerKeyFromContainerName(containerName);
219
+ if (removed && containerKey)
220
+ await this.removeHomeVolume(containerKey);
194
221
  }));
195
222
  }
196
- /**
197
- * Arm the office-layout container migration. Containers whose binds still
198
- * reference legacy raw-id paths are moved to the office-key layout without
199
- * losing their writable layer: commit → remove → create with translated
200
- * binds, preserving everything installed inside. Idempotent per container
201
- * and resumable — the pre-removal binds ride on the snapshot image label,
202
- * so a crash between commit and create resumes from the snapshot.
203
- */
204
223
  armContainerLayoutMigration(translator) {
205
224
  this.bindTranslator = translator;
206
225
  }
207
- /**
208
- * Sweep every managed container through the layout migration, serially and
209
- * with a small gap, so the one-time cost never lands on the boot path or on
210
- * a message. Safe to fire-and-forget; each unit is idempotent.
211
- */
212
226
  async sweepContainerLayoutMigration(delayMs = 2000) {
213
227
  if (!this.bindTranslator)
214
228
  return;
215
229
  let names;
216
230
  try {
217
- // Include snapshot names: a crash between commit and create leaves a
218
- // snapshot with no container, which must resume before the GC below
219
- // could mistake it for an orphan.
220
231
  const containers = await this.listContainerNamesByLabel();
221
232
  const snapshots = await this.listMigrateSnapshotContainerNames();
222
233
  names = Array.from(new Set([...containers, ...snapshots]));
@@ -234,11 +245,8 @@ export class DockerContainerManager {
234
245
  }
235
246
  await new Promise((resolve) => setTimeout(resolve, delayMs));
236
247
  }
237
- // Snapshot images whose container has since been recreated from the base
238
- // image are no longer referenced; reclaim them.
239
248
  await this.removeDanglingMigrateImages();
240
249
  }
241
- /** Move one container to the office-key layout; no-op when already there. */
242
250
  migrateContainerLayout(containerName) {
243
251
  const translator = this.bindTranslator;
244
252
  if (!translator)
@@ -257,9 +265,6 @@ export class DockerContainerManager {
257
265
  let originalBinds;
258
266
  const status = await this.inspectStatus(containerName);
259
267
  if (status === "missing") {
260
- // Resume path: a previous run committed and removed the container but
261
- // died before creating the replacement. The snapshot carries the
262
- // pre-removal binds on its label.
263
268
  const labeled = await this.readMigrateImageBinds(snapshotImage);
264
269
  if (labeled === undefined)
265
270
  return;
@@ -269,7 +274,7 @@ export class DockerContainerManager {
269
274
  originalBinds = await this.inspectBindMounts(containerName);
270
275
  const translated = originalBinds.map(translator);
271
276
  if (this.sameBinds(translated.toSorted(), originalBinds.slice().toSorted())) {
272
- return; // already on the office layout
277
+ return;
273
278
  }
274
279
  log.logInfo(`Migrating container ${containerName} to the office layout`);
275
280
  await this.execFileImpl("docker", [
@@ -282,25 +287,11 @@ export class DockerContainerManager {
282
287
  await this.execFileImpl("docker", ["rm", "-f", containerName]);
283
288
  }
284
289
  await this.createContainerFromSnapshot(containerName, originalBinds.map(translator));
285
- // The snapshot's only job was bridging commit → create; the new container
286
- // already owns that content in its own writable layer; untagging it now
287
- // (rather than waiting for a "natural recreation from the base image"
288
- // that never happens — every recreation path here targets this same
289
- // snapshot family) is what makes migration actually one-time instead of
290
- // repeating on every future sweep that still finds the tag.
291
290
  await this.removeMigrateSnapshot(containerName);
292
291
  log.logInfo(`Container ${containerName} migrated to the office layout`);
293
292
  }
294
- /**
295
- * Create `containerName` from its layout snapshot with `bindSpecs`,
296
- * restoring the managed labels and recomputing the mount signature.
297
- * `create`, not `run`: idle containers stay stopped exactly as they were;
298
- * callers that need the container running start it themselves.
299
- */
300
293
  async createContainerFromSnapshot(containerName, bindSpecs, knownContainerKey) {
301
294
  const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
302
- // The sweep has only the container name and derives the key; the drift
303
- // path knows the real key (container names can be caller-supplied).
304
295
  const containerKey = knownContainerKey ?? this.containerKeyFromContainerName(containerName) ?? containerName;
305
296
  const networkName = await this.ensureNetwork(containerKey);
306
297
  const conversationId = await this.readImageLabel(snapshotImage, DockerContainerManager.CONVERSATION_ID_LABEL_KEY);
@@ -336,21 +327,14 @@ export class DockerContainerManager {
336
327
  "infinity",
337
328
  ]);
338
329
  }
339
- /**
340
- * `docker commit` captures the empty directories Docker created as bind
341
- * targets, so a public office that stopped being mounted would linger in
342
- * the snapshot as an empty `/workspace/public/<key>`. Remove any entry
343
- * there that no current bind targets; only empty directories are removed,
344
- * so a real file could never be deleted by this pass.
345
- */
346
330
  async removeStaleMountpoints(containerName, bindSpecs) {
347
331
  const keep = new Set(bindSpecs
348
332
  .map((bind) => bindSpecToMount(bind).target)
349
- .filter((target) => target.startsWith("/workspace/public/"))
350
- .map((target) => target.slice("/workspace/public/".length)));
333
+ .filter((target) => target.startsWith(`${GUEST_PUBLIC_OFFICES_DIR}/`))
334
+ .map((target) => target.slice(GUEST_PUBLIC_OFFICES_DIR.length + 1)));
351
335
  const script = [
352
- "[ -d /workspace/public ] || exit 0",
353
- "for d in /workspace/public/*; do",
336
+ `cd ${GUEST_PUBLIC_OFFICES_DIR} 2>/dev/null || exit 0`,
337
+ "for d in *; do",
354
338
  ' [ -e "$d" ] || continue',
355
339
  ' case " $KEEP " in *" ${d##*/} "*) continue;; esac',
356
340
  ' rmdir "$d" 2>/dev/null || true',
@@ -371,15 +355,6 @@ export class DockerContainerManager {
371
355
  log.logWarning(`Could not clean stale mountpoints in ${containerName}`, String(err));
372
356
  }
373
357
  }
374
- /**
375
- * Recreate a drifted container with the desired mounts while keeping its
376
- * writable layer: commit — the new binds ride the snapshot label, so a
377
- * crash at any point resumes through the layout-migration path — then
378
- * remove, create from the snapshot, and start. The snapshot is untagged
379
- * once the new container is confirmed up: its only job was bridging
380
- * commit → create, and the container now owns that content in its own
381
- * writable layer, so nothing still needs the tag.
382
- */
383
358
  async recreateContainerPreservingContents(containerKey, containerName, mounts) {
384
359
  const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
385
360
  const bindSpecs = mounts.map((mount) => this.toBindSpec(mount));
@@ -396,7 +371,6 @@ export class DockerContainerManager {
396
371
  await this.removeStaleMountpoints(containerName, bindSpecs);
397
372
  await this.removeMigrateSnapshot(containerName);
398
373
  }
399
- /** Binds recorded on a snapshot image, or undefined when no snapshot exists. */
400
374
  async readMigrateImageBinds(snapshotImage) {
401
375
  const raw = await this.readImageLabel(snapshotImage, DockerContainerManager.MIGRATE_BINDS_LABEL_KEY);
402
376
  if (raw === undefined)
@@ -421,11 +395,6 @@ export class DockerContainerManager {
421
395
  return undefined;
422
396
  }
423
397
  }
424
- /**
425
- * Delete a container's layout snapshot after an intentional removal, so a
426
- * missing container plus a surviving snapshot can only mean a crash in the
427
- * middle of the layout migration (the resume discriminator).
428
- */
429
398
  async removeMigrateSnapshot(containerName) {
430
399
  try {
431
400
  await this.execFileImpl("docker", [
@@ -433,9 +402,7 @@ export class DockerContainerManager {
433
402
  `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`,
434
403
  ]);
435
404
  }
436
- catch {
437
- // No snapshot for this container — the common case.
438
- }
405
+ catch { }
439
406
  }
440
407
  async listMigrateSnapshotContainerNames() {
441
408
  try {
@@ -451,17 +418,6 @@ export class DockerContainerManager {
451
418
  return [];
452
419
  }
453
420
  }
454
- /**
455
- * Catch-up pass for snapshots the success path in
456
- * `migrateContainerLayoutInner` did not get to remove itself — e.g. a
457
- * crash between `createContainerFromSnapshot` and its own cleanup. A
458
- * snapshot is only still needed while its container remains "missing"
459
- * (the resume path in `migrateContainerLayoutInner` reads pre-removal
460
- * binds off it); once the container exists again in any state, the
461
- * snapshot has done its job regardless of whether that container's
462
- * `Config.Image` still points at it — removing a tag never deletes
463
- * layers a live container still uses.
464
- */
465
421
  async removeDanglingMigrateImages() {
466
422
  let stdout;
467
423
  try {
@@ -479,7 +435,7 @@ export class DockerContainerManager {
479
435
  const containerName = image.slice(DockerContainerManager.MIGRATE_IMAGE_PREFIX.length + 1);
480
436
  const status = await this.inspectStatus(containerName);
481
437
  if (status === "missing")
482
- continue; // still needed for a future resume
438
+ continue;
483
439
  try {
484
440
  await this.execFileImpl("docker", ["rmi", image]);
485
441
  log.logInfo(`Removed layout-migration snapshot image ${image}`);
@@ -515,9 +471,6 @@ export class DockerContainerManager {
515
471
  log.logWarning(`Skipping unmanaged-style container without container key`, containerName);
516
472
  continue;
517
473
  }
518
- // Containers keyed under the pre-office raw-conversation resource key
519
- // are unreachable now that resource identity is the office key: no
520
- // provision will ever address them again, so reap rather than adopt.
521
474
  if (containerKey === legacyConversationResourceKey(details.conversationId)) {
522
475
  legacyRemovals.push(this.forceRemoveContainer(containerName, `Removed container ${containerName} keyed by pre-office resource identity`, `Failed to remove legacy-keyed container ${containerName}`).then(() => undefined));
523
476
  continue;
@@ -542,13 +495,11 @@ export class DockerContainerManager {
542
495
  return mounts.flatMap((mount) => ["-v", this.toBindSpec(mount)]);
543
496
  }
544
497
  toBindSpec(mount) {
545
- // The `:ro` suffix is part of the bind spec, so it also flows into
546
- // expectedBinds/mountSignature — flipping a mount's writability is drift
547
- // and recreates the container rather than leaving a stale writable bind.
548
498
  return `${mount.source}:${mount.target}${mount.readOnly ? ":ro" : ""}`;
549
499
  }
550
500
  async runContainer(containerKey, containerName, mounts, options) {
551
501
  const networkName = await this.ensureNetwork(containerKey);
502
+ const homeVolume = await this.ensureHomeVolume(containerKey);
552
503
  log.logInfo(`Creating container ${containerName} from image ${this.image}`);
553
504
  const labels = [
554
505
  "--label",
@@ -579,6 +530,8 @@ export class DockerContainerManager {
579
530
  "1024",
580
531
  ...labels,
581
532
  ...this.resourceLimitArgs(this.effectiveLimits(containerKey)),
533
+ "-v",
534
+ `${homeVolume}:${GUEST_HOME}`,
582
535
  ...this.mountArgs(mounts),
583
536
  this.image,
584
537
  "sleep",
@@ -599,9 +552,6 @@ export class DockerContainerManager {
599
552
  args.push("--cpus", limits.cpus);
600
553
  if (limits?.memory) {
601
554
  args.push("--memory", limits.memory);
602
- // Keep Docker's no-extra-swap semantics explicit. Docker requires
603
- // memory-swap to be updated together when raising an existing memory
604
- // limit above the current swap limit.
605
555
  args.push("--memory-swap", limits.memory);
606
556
  }
607
557
  return args;
@@ -631,18 +581,22 @@ export class DockerContainerManager {
631
581
  });
632
582
  }
633
583
  }
634
- async hasRuntimeDrift(containerKey, containerName, mounts) {
635
- if (await this.hasBindMountDrift(containerName, mounts)) {
636
- return true;
637
- }
638
- if (await this.hasMountSignatureDrift(containerName, mounts)) {
639
- return true;
584
+ async runtimeDrift(containerKey, containerName, mounts, current) {
585
+ const { binds, status, homeVolume } = current;
586
+ if (this.hasBindMountDrift(binds, mounts))
587
+ return "binds";
588
+ if (await this.hasMountSignatureDrift(containerName, mounts))
589
+ return "mount-content";
590
+ if (await this.hasNetworkModeDrift(containerKey, containerName))
591
+ return "network";
592
+ if (homeVolume && status === "stopped" && (await this.hasImageDrift(containerName))) {
593
+ return "image";
640
594
  }
641
- return this.hasNetworkModeDrift(containerKey, containerName);
595
+ return undefined;
642
596
  }
643
- async hasBindMountDrift(containerName, mounts) {
597
+ hasBindMountDrift(binds, mounts) {
644
598
  const expected = this.expectedBinds(mounts);
645
- const actual = await this.inspectBindMounts(containerName);
599
+ const actual = binds.filter((bind) => !this.isHomeVolumeBind(bind));
646
600
  return !this.sameBinds(expected, actual);
647
601
  }
648
602
  expectedBinds(mounts) {
@@ -684,16 +638,8 @@ export class DockerContainerManager {
684
638
  try {
685
639
  const stat = statSync(source);
686
640
  if (stat.isFile()) {
687
- // Files are atomically replaced (rename), which leaves the container
688
- // holding a stale inode — content changes must recreate the mount.
689
641
  return createHash("sha256").update(readFileSync(source)).digest("hex");
690
642
  }
691
- // Directories: a bind mount follows changes inside the directory live,
692
- // so only replacing the directory itself makes the mount stale.
693
- // Size/mtime churn from ordinary activity — event files coming and
694
- // going, children being created — must not read as drift. Identity is
695
- // dev:ino plus birth time, because ext4 recycles inode numbers
696
- // immediately and a same-path replacement can reuse the old one.
697
643
  return `${stat.isDirectory() ? "dir" : "other"}:${stat.dev}:${stat.ino}:${stat.birthtimeMs}`;
698
644
  }
699
645
  catch {
@@ -717,6 +663,149 @@ export class DockerContainerManager {
717
663
  }
718
664
  return [...parsed].toSorted();
719
665
  }
666
+ isHomeVolumeBind(bind) {
667
+ const separator = bind.indexOf(":");
668
+ if (separator === -1)
669
+ return false;
670
+ const source = bind.slice(0, separator);
671
+ const target = bind.slice(separator + 1).replace(/:r[ow]$/, "");
672
+ return source.startsWith(DockerContainerManager.homeVolumeName("")) && target === GUEST_HOME;
673
+ }
674
+ hasHomeVolumeBind(containerKey, binds) {
675
+ const expected = `${DockerContainerManager.homeVolumeName(containerKey)}:${GUEST_HOME}`;
676
+ return binds.includes(expected);
677
+ }
678
+ async hasHomeVolume(containerKey, containerName) {
679
+ return this.hasHomeVolumeBind(containerKey, await this.inspectBindMounts(containerName));
680
+ }
681
+ async hasImageDrift(containerName) {
682
+ const desired = await this.localImageId();
683
+ if (!desired)
684
+ return false;
685
+ const { stdout } = await this.execFileImpl("docker", [
686
+ "inspect",
687
+ "-f",
688
+ "{{.Image}}",
689
+ containerName,
690
+ ]);
691
+ return stdout.trim() !== desired;
692
+ }
693
+ async localImageId() {
694
+ try {
695
+ const { stdout } = await this.execFileImpl("docker", [
696
+ "image",
697
+ "inspect",
698
+ "-f",
699
+ "{{.Id}}",
700
+ this.image,
701
+ ]);
702
+ return this.normalizeDockerValue(stdout.trim());
703
+ }
704
+ catch {
705
+ return undefined;
706
+ }
707
+ }
708
+ async ensureHomeVolume(containerKey) {
709
+ const volumeName = DockerContainerManager.homeVolumeName(containerKey);
710
+ await this.execFileImpl("docker", [
711
+ "volume",
712
+ "create",
713
+ "--label",
714
+ DockerContainerManager.MANAGED_LABEL,
715
+ "--label",
716
+ `${DockerContainerManager.VAULT_ID_LABEL_KEY}=${containerKey}`,
717
+ volumeName,
718
+ ]);
719
+ return volumeName;
720
+ }
721
+ async removeHomeVolume(containerKey) {
722
+ const volumeName = DockerContainerManager.homeVolumeName(containerKey);
723
+ try {
724
+ await this.execFileImpl("docker", ["volume", "rm", volumeName]);
725
+ log.logInfo(`Home volume ${volumeName} removed`);
726
+ }
727
+ catch (err) {
728
+ if (isDockerNotFoundError(err))
729
+ return;
730
+ log.logWarning(`Failed to remove home volume ${volumeName}`, err instanceof Error ? err.message : String(err));
731
+ }
732
+ }
733
+ async replaceHomeVolumeContainer(containerKey, containerName, mounts, options) {
734
+ const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed for replacement`, `Failed to remove container ${containerName} for replacement`);
735
+ if (!removed)
736
+ throw new Error(`Failed to remove container ${containerName} for replacement`);
737
+ await this.runContainer(containerKey, containerName, mounts, options);
738
+ }
739
+ async inventory() {
740
+ const names = await this.listContainerNamesByLabel();
741
+ const entries = [];
742
+ for (const containerName of names) {
743
+ const containerKey = this.containerKeyFromContainerName(containerName);
744
+ const status = await this.inspectStatus(containerName);
745
+ if (status === "missing")
746
+ continue;
747
+ const homeVolume = containerKey
748
+ ? await this.hasHomeVolume(containerKey, containerName)
749
+ : false;
750
+ entries.push({
751
+ containerName,
752
+ ...(containerKey ? { containerKey } : {}),
753
+ running: status === "running",
754
+ homeVolume,
755
+ imageStale: await this.hasImageDrift(containerName),
756
+ });
757
+ }
758
+ return entries;
759
+ }
760
+ async systemChanges(containerName) {
761
+ const { stdout } = await this.execFileImpl("docker", ["diff", containerName]);
762
+ return this.parseNameLines(stdout).filter((line) => {
763
+ const path = line.slice(2);
764
+ return !this.isUnderGuestPath(path, GUEST_HOME) && !this.isUnderGuestPath(path, "/workspace");
765
+ });
766
+ }
767
+ isUnderGuestPath(path, root) {
768
+ return path === root || path.startsWith(`${root}/`);
769
+ }
770
+ migrateToHomeVolume(containerKey) {
771
+ return this.serialize(containerKey, () => this.migrateToHomeVolumeInner(containerKey));
772
+ }
773
+ async migrateToHomeVolumeInner(containerKey) {
774
+ const containerName = DockerContainerManager.containerName(containerKey);
775
+ const status = await this.inspectStatus(containerName);
776
+ if (status === "missing")
777
+ return "missing";
778
+ if (await this.hasHomeVolume(containerKey, containerName))
779
+ return "already-migrated";
780
+ const details = await this.inspectContainerDetails(containerName);
781
+ const mounts = (await this.inspectBindMounts(containerName))
782
+ .filter((bind) => !this.isHomeVolumeBind(bind))
783
+ .map(bindSpecToMount);
784
+ const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
785
+ log.logInfo(`Migrating container ${containerName} to a home volume`);
786
+ await this.execFileImpl("docker", ["commit", containerName, snapshotImage]);
787
+ const homeVolume = await this.ensureHomeVolume(containerKey);
788
+ await this.execFileImpl("docker", [
789
+ "run",
790
+ "--rm",
791
+ "--network",
792
+ "none",
793
+ "-v",
794
+ `${homeVolume}:${GUEST_HOME}`,
795
+ snapshotImage,
796
+ "true",
797
+ ]);
798
+ const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed for home-volume migration`, `Failed to remove container ${containerName} for home-volume migration`);
799
+ if (!removed)
800
+ throw new Error(`Failed to remove container ${containerName}`);
801
+ await this.runContainer(containerKey, containerName, mounts, details?.conversationId ? { conversationId: details.conversationId } : {});
802
+ if (status === "stopped")
803
+ await this.execFileImpl("docker", ["stop", containerName]);
804
+ await this.removeMigrateSnapshot(containerName);
805
+ this.setState(containerKey, status === "stopped" ? "stopped" : "running", containerName);
806
+ log.logInfo(`Container ${containerName} migrated to home volume ${homeVolume}`);
807
+ return "migrated";
808
+ }
720
809
  async hasNetworkModeDrift(containerKey, containerName) {
721
810
  const expected = DockerContainerManager.networkName(containerKey);
722
811
  const { stdout } = await this.execFileImpl("docker", [
@@ -849,7 +938,6 @@ export class DockerContainerManager {
849
938
  const containerKey = containerName.slice(prefix.length);
850
939
  return containerKey.length > 0 ? containerKey : undefined;
851
940
  }
852
- /** @returns true when the container is gone (removed or already missing). */
853
941
  async forceRemoveContainer(containerName, successLog, failureLog) {
854
942
  try {
855
943
  await this.execFileImpl("docker", ["rm", "-f", containerName]);