@geminixiang/mikan 1.0.0-beta.3 → 1.0.0-beta.30

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 (545) hide show
  1. package/CHANGELOG.md +563 -0
  2. package/README.md +60 -24
  3. package/dist/adapter.d.ts +1 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts +1 -0
  7. package/dist/adapters/discord/bot.d.ts.map +1 -1
  8. package/dist/adapters/discord/bot.js +47 -65
  9. package/dist/adapters/discord/bot.js.map +1 -1
  10. package/dist/adapters/discord/context.d.ts.map +1 -1
  11. package/dist/adapters/discord/context.js +46 -211
  12. package/dist/adapters/discord/context.js.map +1 -1
  13. package/dist/adapters/github/bot.d.ts +86 -0
  14. package/dist/adapters/github/bot.d.ts.map +1 -0
  15. package/dist/adapters/github/bot.js +640 -0
  16. package/dist/adapters/github/bot.js.map +1 -0
  17. package/dist/adapters/github/client.d.ts +122 -0
  18. package/dist/adapters/github/client.d.ts.map +1 -0
  19. package/dist/adapters/github/client.js +314 -0
  20. package/dist/adapters/github/client.js.map +1 -0
  21. package/dist/adapters/github/cloudbuild.d.ts +19 -0
  22. package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
  23. package/dist/adapters/github/cloudbuild.js +71 -0
  24. package/dist/adapters/github/cloudbuild.js.map +1 -0
  25. package/dist/adapters/github/context.d.ts +9 -0
  26. package/dist/adapters/github/context.d.ts.map +1 -0
  27. package/dist/adapters/github/context.js +98 -0
  28. package/dist/adapters/github/context.js.map +1 -0
  29. package/dist/adapters/github/gcp-auth.d.ts +28 -0
  30. package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
  31. package/dist/adapters/github/gcp-auth.js +196 -0
  32. package/dist/adapters/github/gcp-auth.js.map +1 -0
  33. package/dist/adapters/github/github-ops.d.ts +90 -0
  34. package/dist/adapters/github/github-ops.d.ts.map +1 -0
  35. package/dist/adapters/github/github-ops.js +405 -0
  36. package/dist/adapters/github/github-ops.js.map +1 -0
  37. package/dist/adapters/github/ids.d.ts +34 -0
  38. package/dist/adapters/github/ids.d.ts.map +1 -0
  39. package/dist/adapters/github/ids.js +53 -0
  40. package/dist/adapters/github/ids.js.map +1 -0
  41. package/dist/adapters/github/repo.d.ts +32 -0
  42. package/dist/adapters/github/repo.d.ts.map +1 -0
  43. package/dist/adapters/github/repo.js +141 -0
  44. package/dist/adapters/github/repo.js.map +1 -0
  45. package/dist/adapters/github/tool-pack.d.ts +14 -0
  46. package/dist/adapters/github/tool-pack.d.ts.map +1 -0
  47. package/dist/adapters/github/tool-pack.js +56 -0
  48. package/dist/adapters/github/tool-pack.js.map +1 -0
  49. package/dist/adapters/github/tools/checks.d.ts +19 -0
  50. package/dist/adapters/github/tools/checks.d.ts.map +1 -0
  51. package/dist/adapters/github/tools/checks.js +105 -0
  52. package/dist/adapters/github/tools/checks.js.map +1 -0
  53. package/dist/adapters/github/tools/issue.d.ts +21 -0
  54. package/dist/adapters/github/tools/issue.d.ts.map +1 -0
  55. package/dist/adapters/github/tools/issue.js +48 -0
  56. package/dist/adapters/github/tools/issue.js.map +1 -0
  57. package/dist/adapters/github/tools/pr.d.ts +22 -0
  58. package/dist/adapters/github/tools/pr.d.ts.map +1 -0
  59. package/dist/adapters/github/tools/pr.js +48 -0
  60. package/dist/adapters/github/tools/pr.js.map +1 -0
  61. package/dist/adapters/github/tools/read.d.ts +21 -0
  62. package/dist/adapters/github/tools/read.d.ts.map +1 -0
  63. package/dist/adapters/github/tools/read.js +141 -0
  64. package/dist/adapters/github/tools/read.js.map +1 -0
  65. package/dist/adapters/github/tools/review-reply.d.ts +17 -0
  66. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
  67. package/dist/adapters/github/tools/review-reply.js +38 -0
  68. package/dist/adapters/github/tools/review-reply.js.map +1 -0
  69. package/dist/adapters/github/tools/sync.d.ts +17 -0
  70. package/dist/adapters/github/tools/sync.d.ts.map +1 -0
  71. package/dist/adapters/github/tools/sync.js +34 -0
  72. package/dist/adapters/github/tools/sync.js.map +1 -0
  73. package/dist/adapters/github/types.d.ts +372 -0
  74. package/dist/adapters/github/types.d.ts.map +1 -0
  75. package/dist/adapters/github/types.js +2 -0
  76. package/dist/adapters/github/types.js.map +1 -0
  77. package/dist/adapters/intake.d.ts +16 -5
  78. package/dist/adapters/intake.d.ts.map +1 -1
  79. package/dist/adapters/intake.js +84 -22
  80. package/dist/adapters/intake.js.map +1 -1
  81. package/dist/adapters/progressive-renderer.d.ts +7 -0
  82. package/dist/adapters/progressive-renderer.d.ts.map +1 -0
  83. package/dist/adapters/progressive-renderer.js +383 -0
  84. package/dist/adapters/progressive-renderer.js.map +1 -0
  85. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  86. package/dist/adapters/slack/blocks.js +111 -111
  87. package/dist/adapters/slack/blocks.js.map +1 -1
  88. package/dist/adapters/slack/bot.d.ts +10 -6
  89. package/dist/adapters/slack/bot.d.ts.map +1 -1
  90. package/dist/adapters/slack/bot.js +173 -145
  91. package/dist/adapters/slack/bot.js.map +1 -1
  92. package/dist/adapters/slack/context.d.ts.map +1 -1
  93. package/dist/adapters/slack/context.js +3 -14
  94. package/dist/adapters/slack/context.js.map +1 -1
  95. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  96. package/dist/adapters/slack/response-lifecycle.js +126 -323
  97. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  98. package/dist/adapters/slack/session.d.ts.map +1 -1
  99. package/dist/adapters/slack/session.js +5 -8
  100. package/dist/adapters/slack/session.js.map +1 -1
  101. package/dist/adapters/slack/tool-pack.d.ts +11 -0
  102. package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
  103. package/dist/adapters/slack/tool-pack.js +45 -0
  104. package/dist/adapters/slack/tool-pack.js.map +1 -0
  105. package/dist/adapters/slack/tools/blockkit.d.ts +14 -0
  106. package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
  107. package/dist/adapters/slack/tools/blockkit.js +106 -0
  108. package/dist/adapters/slack/tools/blockkit.js.map +1 -0
  109. package/dist/adapters/slack/types.d.ts +37 -0
  110. package/dist/adapters/slack/types.d.ts.map +1 -1
  111. package/dist/adapters/slack/types.js.map +1 -1
  112. package/dist/adapters/telegram/bot.d.ts +1 -2
  113. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  114. package/dist/adapters/telegram/bot.js +51 -63
  115. package/dist/adapters/telegram/bot.js.map +1 -1
  116. package/dist/adapters/telegram/context.d.ts.map +1 -1
  117. package/dist/adapters/telegram/context.js +55 -182
  118. package/dist/adapters/telegram/context.js.map +1 -1
  119. package/dist/adapters/types.d.ts +86 -10
  120. package/dist/adapters/types.d.ts.map +1 -1
  121. package/dist/adapters/types.js.map +1 -1
  122. package/dist/agent.d.ts +14 -19
  123. package/dist/agent.d.ts.map +1 -1
  124. package/dist/agent.js +745 -243
  125. package/dist/agent.js.map +1 -1
  126. package/dist/cli/arg-grammar.d.ts +25 -0
  127. package/dist/cli/arg-grammar.d.ts.map +1 -0
  128. package/dist/cli/arg-grammar.js +59 -0
  129. package/dist/cli/arg-grammar.js.map +1 -0
  130. package/dist/cli/boot.d.ts +5 -0
  131. package/dist/cli/boot.d.ts.map +1 -0
  132. package/dist/cli/boot.js +112 -0
  133. package/dist/cli/boot.js.map +1 -0
  134. package/dist/cli/download.d.ts.map +1 -0
  135. package/dist/cli/download.js.map +1 -0
  136. package/dist/cli/ext-dev.d.ts +2 -0
  137. package/dist/cli/ext-dev.d.ts.map +1 -0
  138. package/dist/cli/ext-dev.js +177 -0
  139. package/dist/cli/ext-dev.js.map +1 -0
  140. package/dist/cli/ext-git.d.ts +17 -0
  141. package/dist/cli/ext-git.d.ts.map +1 -0
  142. package/dist/cli/ext-git.js +107 -0
  143. package/dist/cli/ext-git.js.map +1 -0
  144. package/dist/cli/ext.d.ts +2 -0
  145. package/dist/cli/ext.d.ts.map +1 -0
  146. package/dist/cli/ext.js +222 -0
  147. package/dist/cli/ext.js.map +1 -0
  148. package/dist/cli/types.d.ts +20 -0
  149. package/dist/cli/types.d.ts.map +1 -0
  150. package/dist/cli/types.js +2 -0
  151. package/dist/cli/types.js.map +1 -0
  152. package/dist/commands/admin.d.ts.map +1 -1
  153. package/dist/commands/admin.js +2 -1
  154. package/dist/commands/admin.js.map +1 -1
  155. package/dist/commands/auto-reply.d.ts.map +1 -1
  156. package/dist/commands/auto-reply.js +2 -6
  157. package/dist/commands/auto-reply.js.map +1 -1
  158. package/dist/commands/extensions.d.ts.map +1 -1
  159. package/dist/commands/extensions.js +18 -8
  160. package/dist/commands/extensions.js.map +1 -1
  161. package/dist/commands/login.d.ts +2 -1
  162. package/dist/commands/login.d.ts.map +1 -1
  163. package/dist/commands/login.js +35 -3
  164. package/dist/commands/login.js.map +1 -1
  165. package/dist/commands/manifest.d.ts +30 -0
  166. package/dist/commands/manifest.d.ts.map +1 -0
  167. package/dist/commands/manifest.js +121 -0
  168. package/dist/commands/manifest.js.map +1 -0
  169. package/dist/commands/model.d.ts +2 -3
  170. package/dist/commands/model.d.ts.map +1 -1
  171. package/dist/commands/model.js +57 -20
  172. package/dist/commands/model.js.map +1 -1
  173. package/dist/commands/new.d.ts.map +1 -1
  174. package/dist/commands/new.js +10 -2
  175. package/dist/commands/new.js.map +1 -1
  176. package/dist/commands/registry.d.ts +2 -2
  177. package/dist/commands/registry.d.ts.map +1 -1
  178. package/dist/commands/registry.js +1 -2
  179. package/dist/commands/registry.js.map +1 -1
  180. package/dist/commands/sandbox.d.ts.map +1 -1
  181. package/dist/commands/sandbox.js +23 -17
  182. package/dist/commands/sandbox.js.map +1 -1
  183. package/dist/commands/text.d.ts +2 -0
  184. package/dist/commands/text.d.ts.map +1 -0
  185. package/dist/commands/text.js +16 -0
  186. package/dist/commands/text.js.map +1 -0
  187. package/dist/commands/types.d.ts +70 -2
  188. package/dist/commands/types.d.ts.map +1 -1
  189. package/dist/commands/types.js.map +1 -1
  190. package/dist/config.d.ts +1 -3
  191. package/dist/config.d.ts.map +1 -1
  192. package/dist/config.js +102 -95
  193. package/dist/config.js.map +1 -1
  194. package/dist/env-manifest.d.ts +28 -0
  195. package/dist/env-manifest.d.ts.map +1 -0
  196. package/dist/env-manifest.js +214 -0
  197. package/dist/env-manifest.js.map +1 -0
  198. package/dist/events.d.ts.map +1 -1
  199. package/dist/events.js +9 -73
  200. package/dist/events.js.map +1 -1
  201. package/dist/execution-resolver.d.ts +7 -6
  202. package/dist/execution-resolver.d.ts.map +1 -1
  203. package/dist/execution-resolver.js +105 -110
  204. package/dist/execution-resolver.js.map +1 -1
  205. package/dist/harness/auth.d.ts +2 -1
  206. package/dist/harness/auth.d.ts.map +1 -1
  207. package/dist/harness/auth.js +6 -0
  208. package/dist/harness/auth.js.map +1 -1
  209. package/dist/harness/event-format.d.ts +25 -0
  210. package/dist/harness/event-format.d.ts.map +1 -0
  211. package/dist/harness/event-format.js +159 -0
  212. package/dist/harness/event-format.js.map +1 -0
  213. package/dist/harness/extensions/blockkit.d.ts +19 -0
  214. package/dist/harness/extensions/blockkit.d.ts.map +1 -0
  215. package/dist/harness/extensions/blockkit.js +42 -0
  216. package/dist/harness/extensions/blockkit.js.map +1 -0
  217. package/dist/harness/extensions/loader.d.ts +25 -48
  218. package/dist/harness/extensions/loader.d.ts.map +1 -1
  219. package/dist/harness/extensions/loader.js +373 -113
  220. package/dist/harness/extensions/loader.js.map +1 -1
  221. package/dist/harness/extensions/registry.d.ts +75 -2
  222. package/dist/harness/extensions/registry.d.ts.map +1 -1
  223. package/dist/harness/extensions/registry.js +239 -0
  224. package/dist/harness/extensions/registry.js.map +1 -1
  225. package/dist/harness/extensions/types.d.ts +318 -25
  226. package/dist/harness/extensions/types.d.ts.map +1 -1
  227. package/dist/harness/extensions/types.js.map +1 -1
  228. package/dist/harness/index.d.ts +18 -8
  229. package/dist/harness/index.d.ts.map +1 -1
  230. package/dist/harness/index.js +7 -4
  231. package/dist/harness/index.js.map +1 -1
  232. package/dist/harness/models.d.ts +7 -4
  233. package/dist/harness/models.d.ts.map +1 -1
  234. package/dist/harness/models.js +10 -0
  235. package/dist/harness/models.js.map +1 -1
  236. package/dist/harness/runner.d.ts +50 -54
  237. package/dist/harness/runner.d.ts.map +1 -1
  238. package/dist/harness/runner.js +230 -44
  239. package/dist/harness/runner.js.map +1 -1
  240. package/dist/harness/session-store.d.ts +9 -5
  241. package/dist/harness/session-store.d.ts.map +1 -1
  242. package/dist/harness/session-store.js +131 -30
  243. package/dist/harness/session-store.js.map +1 -1
  244. package/dist/harness/settings.d.ts +2 -20
  245. package/dist/harness/settings.d.ts.map +1 -1
  246. package/dist/harness/settings.js +11 -0
  247. package/dist/harness/settings.js.map +1 -1
  248. package/dist/harness/skills.d.ts +2 -29
  249. package/dist/harness/skills.d.ts.map +1 -1
  250. package/dist/harness/skills.js.map +1 -1
  251. package/dist/harness/subagent-profiles.d.ts +8 -0
  252. package/dist/harness/subagent-profiles.d.ts.map +1 -0
  253. package/dist/harness/subagent-profiles.js +290 -0
  254. package/dist/harness/subagent-profiles.js.map +1 -0
  255. package/dist/harness/subagent-runner.d.ts +39 -0
  256. package/dist/harness/subagent-runner.d.ts.map +1 -0
  257. package/dist/harness/subagent-runner.js +615 -0
  258. package/dist/harness/subagent-runner.js.map +1 -0
  259. package/dist/harness/types.d.ts +263 -1
  260. package/dist/harness/types.d.ts.map +1 -1
  261. package/dist/harness/types.js.map +1 -1
  262. package/dist/harness/usage.d.ts +6 -0
  263. package/dist/harness/usage.d.ts.map +1 -0
  264. package/dist/harness/usage.js +32 -0
  265. package/dist/harness/usage.js.map +1 -0
  266. package/dist/index.d.ts +33 -8
  267. package/dist/index.d.ts.map +1 -1
  268. package/dist/index.js +20 -6
  269. package/dist/index.js.map +1 -1
  270. package/dist/main.js +253 -109
  271. package/dist/main.js.map +1 -1
  272. package/dist/observability/instrument.js +6 -4
  273. package/dist/observability/instrument.js.map +1 -1
  274. package/dist/observability/sentry.d.ts.map +1 -1
  275. package/dist/observability/sentry.js +3 -2
  276. package/dist/observability/sentry.js.map +1 -1
  277. package/dist/packages/admin.d.ts +17 -0
  278. package/dist/packages/admin.d.ts.map +1 -0
  279. package/dist/packages/admin.js +96 -0
  280. package/dist/packages/admin.js.map +1 -0
  281. package/dist/packages/index.d.ts +6 -0
  282. package/dist/packages/index.d.ts.map +1 -0
  283. package/dist/packages/index.js +6 -0
  284. package/dist/packages/index.js.map +1 -0
  285. package/dist/packages/inspect.d.ts +11 -0
  286. package/dist/packages/inspect.d.ts.map +1 -0
  287. package/dist/packages/inspect.js +100 -0
  288. package/dist/packages/inspect.js.map +1 -0
  289. package/dist/packages/materialize.d.ts +39 -0
  290. package/dist/packages/materialize.d.ts.map +1 -0
  291. package/dist/packages/materialize.js +300 -0
  292. package/dist/packages/materialize.js.map +1 -0
  293. package/dist/packages/resolve.d.ts +25 -0
  294. package/dist/packages/resolve.d.ts.map +1 -0
  295. package/dist/packages/resolve.js +212 -0
  296. package/dist/packages/resolve.js.map +1 -0
  297. package/dist/packages/source.d.ts +33 -0
  298. package/dist/packages/source.d.ts.map +1 -0
  299. package/dist/packages/source.js +177 -0
  300. package/dist/packages/source.js.map +1 -0
  301. package/dist/packages/types.d.ts +104 -0
  302. package/dist/packages/types.d.ts.map +1 -0
  303. package/dist/packages/types.js +2 -0
  304. package/dist/packages/types.js.map +1 -0
  305. package/dist/provisioner.d.ts.map +1 -1
  306. package/dist/provisioner.js +6 -6
  307. package/dist/provisioner.js.map +1 -1
  308. package/dist/runtime/conversation-runtime.d.ts +1 -1
  309. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  310. package/dist/runtime/conversation-runtime.js +481 -98
  311. package/dist/runtime/conversation-runtime.js.map +1 -1
  312. package/dist/runtime/session-lifecycle.d.ts +28 -0
  313. package/dist/runtime/session-lifecycle.d.ts.map +1 -0
  314. package/dist/runtime/session-lifecycle.js +161 -0
  315. package/dist/runtime/session-lifecycle.js.map +1 -0
  316. package/dist/runtime/types.d.ts +45 -5
  317. package/dist/runtime/types.d.ts.map +1 -1
  318. package/dist/runtime/types.js.map +1 -1
  319. package/dist/sandbox/cloudflare.d.ts +3 -0
  320. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  321. package/dist/sandbox/cloudflare.js +11 -0
  322. package/dist/sandbox/cloudflare.js.map +1 -1
  323. package/dist/sandbox/container.d.ts +4 -0
  324. package/dist/sandbox/container.d.ts.map +1 -1
  325. package/dist/sandbox/container.js +12 -2
  326. package/dist/sandbox/container.js.map +1 -1
  327. package/dist/sandbox/firecracker.d.ts +3 -0
  328. package/dist/sandbox/firecracker.d.ts.map +1 -1
  329. package/dist/sandbox/firecracker.js +11 -1
  330. package/dist/sandbox/firecracker.js.map +1 -1
  331. package/dist/sandbox/gondolin.d.ts +57 -0
  332. package/dist/sandbox/gondolin.d.ts.map +1 -0
  333. package/dist/sandbox/gondolin.js +764 -0
  334. package/dist/sandbox/gondolin.js.map +1 -0
  335. package/dist/sandbox/host.d.ts +4 -0
  336. package/dist/sandbox/host.d.ts.map +1 -1
  337. package/dist/sandbox/host.js +52 -0
  338. package/dist/sandbox/host.js.map +1 -1
  339. package/dist/sandbox/identity.d.ts +16 -0
  340. package/dist/sandbox/identity.d.ts.map +1 -0
  341. package/dist/sandbox/identity.js +42 -0
  342. package/dist/sandbox/identity.js.map +1 -0
  343. package/dist/sandbox/image.d.ts.map +1 -1
  344. package/dist/sandbox/image.js +1 -0
  345. package/dist/sandbox/image.js.map +1 -1
  346. package/dist/sandbox/index.d.ts +15 -4
  347. package/dist/sandbox/index.d.ts.map +1 -1
  348. package/dist/sandbox/index.js +25 -3
  349. package/dist/sandbox/index.js.map +1 -1
  350. package/dist/sandbox/path-context.js +18 -8
  351. package/dist/sandbox/path-context.js.map +1 -1
  352. package/dist/sandbox/types.d.ts +65 -1
  353. package/dist/sandbox/types.d.ts.map +1 -1
  354. package/dist/sandbox/types.js.map +1 -1
  355. package/dist/sandbox/utils.d.ts +12 -0
  356. package/dist/sandbox/utils.d.ts.map +1 -1
  357. package/dist/sandbox/utils.js +38 -0
  358. package/dist/sandbox/utils.js.map +1 -1
  359. package/dist/sessions/chat-history-sync.d.ts +25 -0
  360. package/dist/sessions/chat-history-sync.d.ts.map +1 -0
  361. package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +98 -124
  362. package/dist/sessions/chat-history-sync.js.map +1 -0
  363. package/dist/sessions/conversation-log.d.ts +9 -0
  364. package/dist/sessions/conversation-log.d.ts.map +1 -0
  365. package/dist/sessions/conversation-log.js +47 -0
  366. package/dist/sessions/conversation-log.js.map +1 -0
  367. package/dist/sessions/history-line.d.ts +20 -0
  368. package/dist/sessions/history-line.d.ts.map +1 -0
  369. package/dist/sessions/history-line.js +24 -0
  370. package/dist/sessions/history-line.js.map +1 -0
  371. package/dist/sessions/policy.d.ts.map +1 -1
  372. package/dist/sessions/policy.js +5 -3
  373. package/dist/sessions/policy.js.map +1 -1
  374. package/dist/sessions/rotation.d.ts +2 -0
  375. package/dist/sessions/rotation.d.ts.map +1 -0
  376. package/dist/sessions/rotation.js +39 -0
  377. package/dist/sessions/rotation.js.map +1 -0
  378. package/dist/sessions/session-key.d.ts +40 -0
  379. package/dist/sessions/session-key.d.ts.map +1 -0
  380. package/dist/sessions/session-key.js +92 -0
  381. package/dist/sessions/session-key.js.map +1 -0
  382. package/dist/sessions/store.d.ts.map +1 -1
  383. package/dist/sessions/store.js +40 -18
  384. package/dist/sessions/store.js.map +1 -1
  385. package/dist/sessions/types.d.ts +17 -4
  386. package/dist/sessions/types.d.ts.map +1 -1
  387. package/dist/sessions/types.js.map +1 -1
  388. package/dist/settings-mutation.d.ts +8 -0
  389. package/dist/settings-mutation.d.ts.map +1 -0
  390. package/dist/settings-mutation.js +43 -0
  391. package/dist/settings-mutation.js.map +1 -0
  392. package/dist/subagent-progress.d.ts +43 -0
  393. package/dist/subagent-progress.d.ts.map +1 -0
  394. package/dist/subagent-progress.js +220 -0
  395. package/dist/subagent-progress.js.map +1 -0
  396. package/dist/tools/bash.d.ts +3 -1
  397. package/dist/tools/bash.d.ts.map +1 -1
  398. package/dist/tools/bash.js +25 -17
  399. package/dist/tools/bash.js.map +1 -1
  400. package/dist/tools/edit.d.ts.map +1 -1
  401. package/dist/tools/edit.js +10 -12
  402. package/dist/tools/edit.js.map +1 -1
  403. package/dist/tools/event.d.ts +1 -1
  404. package/dist/tools/event.d.ts.map +1 -1
  405. package/dist/tools/event.js +53 -43
  406. package/dist/tools/event.js.map +1 -1
  407. package/dist/tools/generate-image.d.ts +17 -0
  408. package/dist/tools/generate-image.d.ts.map +1 -0
  409. package/dist/tools/generate-image.js +63 -0
  410. package/dist/tools/generate-image.js.map +1 -0
  411. package/dist/tools/host-fn-tool.d.ts +21 -0
  412. package/dist/tools/host-fn-tool.d.ts.map +1 -0
  413. package/dist/tools/host-fn-tool.js +32 -0
  414. package/dist/tools/host-fn-tool.js.map +1 -0
  415. package/dist/tools/index.d.ts +14 -2
  416. package/dist/tools/index.d.ts.map +1 -1
  417. package/dist/tools/index.js +28 -3
  418. package/dist/tools/index.js.map +1 -1
  419. package/dist/tools/react.d.ts +15 -0
  420. package/dist/tools/react.d.ts.map +1 -0
  421. package/dist/tools/react.js +29 -0
  422. package/dist/tools/react.js.map +1 -0
  423. package/dist/tools/read.d.ts +1 -0
  424. package/dist/tools/read.d.ts.map +1 -1
  425. package/dist/tools/read.js +37 -31
  426. package/dist/tools/read.js.map +1 -1
  427. package/dist/tools/sandbox.d.ts +2 -2
  428. package/dist/tools/sandbox.d.ts.map +1 -1
  429. package/dist/tools/sandbox.js +14 -9
  430. package/dist/tools/sandbox.js.map +1 -1
  431. package/dist/tools/subagent-slots.d.ts +28 -0
  432. package/dist/tools/subagent-slots.d.ts.map +1 -0
  433. package/dist/tools/subagent-slots.js +72 -0
  434. package/dist/tools/subagent-slots.js.map +1 -0
  435. package/dist/tools/subagent.d.ts +54 -0
  436. package/dist/tools/subagent.d.ts.map +1 -0
  437. package/dist/tools/subagent.js +401 -0
  438. package/dist/tools/subagent.js.map +1 -0
  439. package/dist/tools/types.d.ts +40 -6
  440. package/dist/tools/types.d.ts.map +1 -1
  441. package/dist/tools/types.js.map +1 -1
  442. package/dist/tools/write.d.ts.map +1 -1
  443. package/dist/tools/write.js +2 -8
  444. package/dist/tools/write.js.map +1 -1
  445. package/dist/trigger.d.ts.map +1 -1
  446. package/dist/trigger.js +1 -2
  447. package/dist/trigger.js.map +1 -1
  448. package/dist/types.d.ts +232 -32
  449. package/dist/types.d.ts.map +1 -1
  450. package/dist/types.js.map +1 -1
  451. package/dist/utils/date.d.ts +1 -1
  452. package/dist/utils/date.js +1 -1
  453. package/dist/utils/date.js.map +1 -1
  454. package/dist/vault/disabled.d.ts +9 -0
  455. package/dist/vault/disabled.d.ts.map +1 -0
  456. package/dist/vault/disabled.js +22 -0
  457. package/dist/vault/disabled.js.map +1 -0
  458. package/dist/vault/index.d.ts +0 -2
  459. package/dist/vault/index.d.ts.map +1 -1
  460. package/dist/vault/index.js +30 -33
  461. package/dist/vault/index.js.map +1 -1
  462. package/dist/vault/injection.d.ts +10 -0
  463. package/dist/vault/injection.d.ts.map +1 -0
  464. package/dist/vault/injection.js +30 -0
  465. package/dist/vault/injection.js.map +1 -0
  466. package/dist/vault/policy.d.ts +20 -0
  467. package/dist/vault/policy.d.ts.map +1 -0
  468. package/dist/vault/policy.js +20 -0
  469. package/dist/vault/policy.js.map +1 -0
  470. package/dist/vault/types.d.ts +4 -2
  471. package/dist/vault/types.d.ts.map +1 -1
  472. package/dist/vault/types.js.map +1 -1
  473. package/dist/web/admin/portal.d.ts +17 -2
  474. package/dist/web/admin/portal.d.ts.map +1 -1
  475. package/dist/web/admin/portal.js +385 -155
  476. package/dist/web/admin/portal.js.map +1 -1
  477. package/dist/web/admin/types.d.ts +18 -0
  478. package/dist/web/admin/types.d.ts.map +1 -1
  479. package/dist/web/admin/types.js.map +1 -1
  480. package/dist/web/agent-events/portal.d.ts.map +1 -1
  481. package/dist/web/agent-events/portal.js +2 -1
  482. package/dist/web/agent-events/portal.js.map +1 -1
  483. package/dist/web/login/oauth.d.ts +2 -3
  484. package/dist/web/login/oauth.d.ts.map +1 -1
  485. package/dist/web/login/oauth.js +0 -31
  486. package/dist/web/login/oauth.js.map +1 -1
  487. package/dist/web/login/portal.js +1 -1
  488. package/dist/web/login/portal.js.map +1 -1
  489. package/dist/web/login/types.d.ts +0 -11
  490. package/dist/web/login/types.d.ts.map +1 -1
  491. package/dist/web/login/types.js.map +1 -1
  492. package/dist/web/portal-shell.d.ts +4 -0
  493. package/dist/web/portal-shell.d.ts.map +1 -0
  494. package/dist/{portal-shell.js → web/portal-shell.js} +2 -2
  495. package/dist/web/portal-shell.js.map +1 -0
  496. package/dist/web/server.d.ts.map +1 -1
  497. package/dist/web/server.js +7 -0
  498. package/dist/web/server.js.map +1 -1
  499. package/dist/web/session-view/command.d.ts.map +1 -1
  500. package/dist/web/session-view/command.js +4 -1
  501. package/dist/web/session-view/command.js.map +1 -1
  502. package/dist/web/session-view/portal.d.ts.map +1 -1
  503. package/dist/web/session-view/portal.js +4 -3
  504. package/dist/web/session-view/portal.js.map +1 -1
  505. package/dist/web/session-view/service.d.ts.map +1 -1
  506. package/dist/web/session-view/service.js +2 -1
  507. package/dist/web/session-view/service.js.map +1 -1
  508. package/dist/web/session-view/types.d.ts +2 -1
  509. package/dist/web/session-view/types.d.ts.map +1 -1
  510. package/dist/web/session-view/types.js.map +1 -1
  511. package/dist/workspace-projection/index.d.ts +5 -0
  512. package/dist/workspace-projection/index.d.ts.map +1 -0
  513. package/dist/workspace-projection/index.js +71 -0
  514. package/dist/workspace-projection/index.js.map +1 -0
  515. package/dist/workspace-projection/types.d.ts +7 -0
  516. package/dist/workspace-projection/types.d.ts.map +1 -0
  517. package/dist/workspace-projection/types.js +2 -0
  518. package/dist/workspace-projection/types.js.map +1 -0
  519. package/package.json +28 -15
  520. package/dist/adapters/streaming.d.ts +0 -18
  521. package/dist/adapters/streaming.d.ts.map +0 -1
  522. package/dist/adapters/streaming.js +0 -44
  523. package/dist/adapters/streaming.js.map +0 -1
  524. package/dist/download.d.ts.map +0 -1
  525. package/dist/download.js.map +0 -1
  526. package/dist/model-registry.d.ts +0 -4
  527. package/dist/model-registry.d.ts.map +0 -1
  528. package/dist/model-registry.js +0 -7
  529. package/dist/model-registry.js.map +0 -1
  530. package/dist/portal-shell.d.ts +0 -4
  531. package/dist/portal-shell.d.ts.map +0 -1
  532. package/dist/portal-shell.js.map +0 -1
  533. package/dist/runtime/agent-run-controller.d.ts +0 -31
  534. package/dist/runtime/agent-run-controller.d.ts.map +0 -1
  535. package/dist/runtime/agent-run-controller.js +0 -195
  536. package/dist/runtime/agent-run-controller.js.map +0 -1
  537. package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
  538. package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
  539. package/dist/sessions/agent-memory-file-manager.js.map +0 -1
  540. package/dist/vault/routing.d.ts +0 -3
  541. package/dist/vault/routing.d.ts.map +0 -1
  542. package/dist/vault/routing.js +0 -13
  543. package/dist/vault/routing.js.map +0 -1
  544. /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
  545. /package/dist/{download.js → cli/download.js} +0 -0
@@ -1,4 +1,5 @@
1
- export type SandboxConfig = HostSandboxConfig | ContainerSandboxConfig | ImageSandboxConfig | FirecrackerSandboxConfig | CloudflareSandboxConfig;
1
+ import type { ResourceLimits } from "../types.js";
2
+ export type SandboxConfig = HostSandboxConfig | ContainerSandboxConfig | ImageSandboxConfig | GondolinSandboxConfig | FirecrackerSandboxConfig | CloudflareSandboxConfig;
2
3
  export interface HostSandboxConfig {
3
4
  type: "host";
4
5
  }
@@ -10,6 +11,41 @@ export interface ImageSandboxConfig {
10
11
  type: "image";
11
12
  image: string;
12
13
  }
14
+ export interface GondolinSandboxConfig {
15
+ type: "gondolin";
16
+ profile: "default";
17
+ /** Local-only runtime details supplied after actor/workspace resolution. */
18
+ image?: string;
19
+ workspacePath?: string;
20
+ mounts?: Array<{
21
+ source: string;
22
+ target: string;
23
+ readOnly?: boolean;
24
+ }>;
25
+ instanceId?: string;
26
+ resourceKey?: string;
27
+ }
28
+ export interface GondolinBootstrapOptions {
29
+ /** Default per-runtime resource limits. */
30
+ limits?: ResourceLimits;
31
+ /** Boosted limits applied while a runtime holds a boost. */
32
+ boostLimits?: ResourceLimits;
33
+ }
34
+ export interface SessionClientCallbacks {
35
+ onJson: (message: {
36
+ type: string;
37
+ id?: number;
38
+ exit_code?: number | null;
39
+ code?: string;
40
+ message?: string;
41
+ }) => void;
42
+ onBinary: (frame: Buffer) => void;
43
+ onClose: (error?: Error) => void;
44
+ }
45
+ export interface SessionClient {
46
+ send(message: object): void;
47
+ close(): void;
48
+ }
13
49
  export interface FirecrackerSandboxConfig {
14
50
  type: "firecracker";
15
51
  vmId: string;
@@ -26,6 +62,29 @@ export interface Executor {
26
62
  * Execute a bash command.
27
63
  */
28
64
  exec(command: string, options?: ExecOptions): Promise<ExecResult>;
65
+ /**
66
+ * Read a runtime file as UTF-8 text. The executor owns the transport, so
67
+ * file contents never pass through shell argv or extra shell parse layers.
68
+ */
69
+ readFile(path: string, options?: ExecOptions): Promise<string>;
70
+ /**
71
+ * Read a runtime file as base64 (for binary content, e.g. images). Same
72
+ * transport ownership as readFile.
73
+ */
74
+ readFileBase64(path: string, options?: ExecOptions): Promise<string>;
75
+ /**
76
+ * Read an attachment without following any symlink in the path. Executors
77
+ * that cannot provide this atomically must omit the capability; attachment
78
+ * uploads then fail closed.
79
+ */
80
+ readFileBase64NoSymlinks?(path: string, options?: ExecOptions): Promise<string>;
81
+ /**
82
+ * Write a runtime file, creating parent directories and replacing via a
83
+ * staging file so an aborted write never truncates the target. Like
84
+ * readFile, transport is the executor's concern — content must survive
85
+ * arbitrary quoting and ARG_MAX limits.
86
+ */
87
+ writeFile(path: string, content: string, options?: ExecOptions): Promise<void>;
29
88
  /**
30
89
  * Get the workspace path prefix for this executor.
31
90
  * Host: returns the actual path.
@@ -58,8 +117,13 @@ export interface ExecResult {
58
117
  stderr: string;
59
118
  code: number;
60
119
  }
120
+ export interface SandboxCredentialCapabilities {
121
+ env: boolean;
122
+ fileMounts: boolean;
123
+ }
61
124
  export interface SandboxAdapter<TConfig extends SandboxConfig = SandboxConfig> {
62
125
  type: TConfig["type"];
126
+ credentials: SandboxCredentialCapabilities;
63
127
  parse(value: string): TConfig | undefined;
64
128
  validate?(config: TConfig): Promise<void>;
65
129
  createExecutor?(config: TConfig, env?: Record<string, string>, ensureReady?: () => Promise<void>): Executor;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,sBAAsB,GACtB,kBAAkB,GAClB,wBAAwB,GACxB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAElE;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3C;;OAEG;IACH,cAAc,CAAC,iBAAiB,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAE9D;;OAEG;IACH,gBAAgB,IAAI,aAAa,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc,CAAC,OAAO,SAAS,aAAa,GAAG,aAAa;IAC3E,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACtB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,CACb,MAAM,EAAE,OAAO,EACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAChC,QAAQ,CAAC;CACb"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"","sourcesContent":["export type SandboxConfig =\n | HostSandboxConfig\n | ContainerSandboxConfig\n | ImageSandboxConfig\n | FirecrackerSandboxConfig\n | CloudflareSandboxConfig;\n\nexport interface HostSandboxConfig {\n type: \"host\";\n}\n\nexport interface ContainerSandboxConfig {\n type: \"container\";\n container: string;\n}\n\nexport interface ImageSandboxConfig {\n type: \"image\";\n image: string;\n}\n\nexport interface FirecrackerSandboxConfig {\n type: \"firecracker\";\n vmId: string;\n hostPath: string;\n sshUser?: string;\n sshPort?: number;\n}\n\nexport interface CloudflareSandboxConfig {\n type: \"cloudflare\";\n sandboxId: string;\n}\n\nexport interface Executor {\n /**\n * Execute a bash command.\n */\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n /**\n * Get the workspace path prefix for this executor.\n * Host: returns the actual path.\n * Container/Firecracker: returns /workspace.\n */\n getWorkspacePath(hostPath: string): string;\n\n /**\n * Return explicit host/control-plane/runtime path semantics for this executor.\n */\n getPathContext(hostWorkspaceRoot: string): RuntimePathContext;\n\n /**\n * Get the current sandbox config used by this executor.\n */\n getSandboxConfig(): SandboxConfig;\n}\n\nexport interface RuntimePathContext {\n /** Host-side workspace root used by mikan's control plane. */\n hostWorkspaceRoot: string;\n /** Workspace root as seen by bash/read/write/edit inside the runtime. */\n runtimeWorkspaceRoot: string;\n /** Translate a runtime path back to a host path when the runtime is host-backed. */\n runtimeToHostPath?: (runtimePath: string) => string;\n}\n\nexport interface ExecOptions {\n timeout?: number;\n signal?: AbortSignal;\n}\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport interface SandboxAdapter<TConfig extends SandboxConfig = SandboxConfig> {\n type: TConfig[\"type\"];\n parse(value: string): TConfig | undefined;\n validate?(config: TConfig): Promise<void>;\n createExecutor?(\n config: TConfig,\n env?: Record<string, string>,\n ensureReady?: () => Promise<void>,\n ): Executor;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ResourceLimits } from \"../types.js\";\n\nexport type SandboxConfig =\n | HostSandboxConfig\n | ContainerSandboxConfig\n | ImageSandboxConfig\n | GondolinSandboxConfig\n | FirecrackerSandboxConfig\n | CloudflareSandboxConfig;\n\nexport interface HostSandboxConfig {\n type: \"host\";\n}\n\nexport interface ContainerSandboxConfig {\n type: \"container\";\n container: string;\n}\n\nexport interface ImageSandboxConfig {\n type: \"image\";\n image: string;\n}\n\nexport interface GondolinSandboxConfig {\n type: \"gondolin\";\n profile: \"default\";\n /** Local-only runtime details supplied after actor/workspace resolution. */\n image?: string;\n workspacePath?: string;\n mounts?: Array<{ source: string; target: string; readOnly?: boolean }>;\n instanceId?: string;\n resourceKey?: string;\n}\n\nexport interface GondolinBootstrapOptions {\n /** Default per-runtime resource limits. */\n limits?: ResourceLimits;\n /** Boosted limits applied while a runtime holds a boost. */\n boostLimits?: ResourceLimits;\n}\n\nexport interface SessionClientCallbacks {\n onJson: (message: {\n type: string;\n id?: number;\n exit_code?: number | null;\n code?: string;\n message?: string;\n }) => void;\n onBinary: (frame: Buffer) => void;\n onClose: (error?: Error) => void;\n}\n\nexport interface SessionClient {\n send(message: object): void;\n close(): void;\n}\n\nexport interface FirecrackerSandboxConfig {\n type: \"firecracker\";\n vmId: string;\n hostPath: string;\n sshUser?: string;\n sshPort?: number;\n}\n\nexport interface CloudflareSandboxConfig {\n type: \"cloudflare\";\n sandboxId: string;\n}\n\nexport interface Executor {\n /**\n * Execute a bash command.\n */\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n /**\n * Read a runtime file as UTF-8 text. The executor owns the transport, so\n * file contents never pass through shell argv or extra shell parse layers.\n */\n readFile(path: string, options?: ExecOptions): Promise<string>;\n\n /**\n * Read a runtime file as base64 (for binary content, e.g. images). Same\n * transport ownership as readFile.\n */\n readFileBase64(path: string, options?: ExecOptions): Promise<string>;\n\n /**\n * Read an attachment without following any symlink in the path. Executors\n * that cannot provide this atomically must omit the capability; attachment\n * uploads then fail closed.\n */\n readFileBase64NoSymlinks?(path: string, options?: ExecOptions): Promise<string>;\n\n /**\n * Write a runtime file, creating parent directories and replacing via a\n * staging file so an aborted write never truncates the target. Like\n * readFile, transport is the executor's concern — content must survive\n * arbitrary quoting and ARG_MAX limits.\n */\n writeFile(path: string, content: string, options?: ExecOptions): Promise<void>;\n\n /**\n * Get the workspace path prefix for this executor.\n * Host: returns the actual path.\n * Container/Firecracker: returns /workspace.\n */\n getWorkspacePath(hostPath: string): string;\n\n /**\n * Return explicit host/control-plane/runtime path semantics for this executor.\n */\n getPathContext(hostWorkspaceRoot: string): RuntimePathContext;\n\n /**\n * Get the current sandbox config used by this executor.\n */\n getSandboxConfig(): SandboxConfig;\n}\n\nexport interface RuntimePathContext {\n /** Host-side workspace root used by mikan's control plane. */\n hostWorkspaceRoot: string;\n /** Workspace root as seen by bash/read/write/edit inside the runtime. */\n runtimeWorkspaceRoot: string;\n /** Translate a runtime path back to a host path when the runtime is host-backed. */\n runtimeToHostPath?: (runtimePath: string) => string;\n}\n\nexport interface ExecOptions {\n timeout?: number;\n signal?: AbortSignal;\n}\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport interface SandboxCredentialCapabilities {\n env: boolean;\n fileMounts: boolean;\n}\n\nexport interface SandboxAdapter<TConfig extends SandboxConfig = SandboxConfig> {\n type: TConfig[\"type\"];\n credentials: SandboxCredentialCapabilities;\n parse(value: string): TConfig | undefined;\n validate?(config: TConfig): Promise<void>;\n createExecutor?(\n config: TConfig,\n env?: Record<string, string>,\n ensureReady?: () => Promise<void>,\n ): Executor;\n}\n"]}
@@ -1,4 +1,16 @@
1
1
  export declare function execSimple(cmd: string, args: string[]): Promise<string>;
2
2
  export declare function killProcessTree(pid: number): void;
3
3
  export declare function shellEscape(s: string): string;
4
+ interface ExecLikeResult {
5
+ stdout: string;
6
+ stderr: string;
7
+ code: number;
8
+ }
9
+ interface ExecLike<TOptions> {
10
+ exec(command: string, options?: TOptions): Promise<ExecLikeResult>;
11
+ }
12
+ export declare function execReadFileBase64<TOptions>(executor: ExecLike<TOptions>, path: string, options?: TOptions): Promise<string>;
13
+ export declare function execReadFile<TOptions>(executor: ExecLike<TOptions>, path: string, options?: TOptions): Promise<string>;
14
+ export declare function execWriteFile<TOptions>(executor: ExecLike<TOptions>, path: string, content: string, options?: TOptions): Promise<void>;
15
+ export {};
4
16
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/sandbox/utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBvE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAqBjD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/sandbox/utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBvE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAqBjD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7C;AAWD,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,QAAQ,CAAC,QAAQ;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACpE;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAC/C,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,YAAY,CAAC,QAAQ,EACzC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAC1C,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
@@ -48,4 +48,42 @@ export function shellEscape(s) {
48
48
  // Escape for passing to sh -c
49
49
  return `'${s.replace(/'/g, "'\\''")}'`;
50
50
  }
51
+ /**
52
+ * Shared exec-backed file transport for executors whose only channel into the
53
+ * runtime is `exec` (docker exec, ssh, HTTP). Contents travel base64-encoded —
54
+ * the base64 alphabet is inert under every shell parse layer — and writes are
55
+ * chunked so no single command approaches the per-argument ARG_MAX limit,
56
+ * staged, then moved into place so an aborted write never truncates the file.
57
+ */
58
+ const WRITE_CHUNK_CHARS = 65536;
59
+ export async function execReadFileBase64(executor, path, options) {
60
+ const result = await executor.exec(`base64 < ${shellEscape(path)}`, options);
61
+ if (result.code !== 0) {
62
+ throw new Error(result.stderr.trim() || `Failed to read file: ${path}`);
63
+ }
64
+ return result.stdout.replace(/\s+/g, "");
65
+ }
66
+ export async function execReadFile(executor, path, options) {
67
+ return Buffer.from(await execReadFileBase64(executor, path, options), "base64").toString("utf-8");
68
+ }
69
+ export async function execWriteFile(executor, path, content, options) {
70
+ const encoded = Buffer.from(content, "utf-8").toString("base64");
71
+ const escapedPath = shellEscape(path);
72
+ const stage = shellEscape(`${path}.mikan-stage`);
73
+ const stageB64 = shellEscape(`${path}.mikan-stage.b64`);
74
+ const run = async (command) => {
75
+ const result = await executor.exec(command, options);
76
+ if (result.code !== 0) {
77
+ await executor.exec(`rm -f ${stage} ${stageB64}`, options).catch(() => { });
78
+ throw new Error(result.stderr.trim() || `Failed to write file: ${path}`);
79
+ }
80
+ };
81
+ const dir = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) || "/" : ".";
82
+ await run(`mkdir -p ${shellEscape(dir)} && : > ${stageB64}`);
83
+ for (let offset = 0; offset === 0 || offset < encoded.length; offset += WRITE_CHUNK_CHARS) {
84
+ const chunk = encoded.slice(offset, offset + WRITE_CHUNK_CHARS);
85
+ await run(`printf '%s' ${shellEscape(chunk)} >> ${stageB64}`);
86
+ }
87
+ await run(`base64 -d < ${stageB64} > ${stage} && mv ${stage} ${escapedPath} && rm -f ${stageB64}`);
88
+ }
51
89
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/sandbox/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,IAAc;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACtE,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YAC7B,MAAM,IAAI,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YAC7B,MAAM,IAAI,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,CAAC,MAAM,CAAC,CAAC;;gBAC3B,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;gBACnD,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,8BAA8B;IAC9B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACzC,CAAC","sourcesContent":["import { spawn } from \"child_process\";\n\nexport function execSimple(cmd: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.on(\"data\", (d) => {\n stdout += d;\n });\n child.stderr?.on(\"data\", (d) => {\n stderr += d;\n });\n child.on(\"close\", (code) => {\n if (code === 0) resolve(stdout);\n else reject(new Error(stderr || `Exit code ${code}`));\n });\n });\n}\n\nexport function killProcessTree(pid: number): void {\n if (process.platform === \"win32\") {\n try {\n spawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n stdio: \"ignore\",\n detached: true,\n });\n } catch {\n // Ignore errors\n }\n } else {\n try {\n process.kill(-pid, \"SIGKILL\");\n } catch {\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // Process already dead\n }\n }\n }\n}\n\nexport function shellEscape(s: string): string {\n // Escape for passing to sh -c\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/sandbox/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"child_process\";\n\nexport function execSimple(cmd: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.on(\"data\", (d) => {\n stdout += d;\n });\n child.stderr?.on(\"data\", (d) => {\n stderr += d;\n });\n child.on(\"close\", (code) => {\n if (code === 0) resolve(stdout);\n else reject(new Error(stderr || `Exit code ${code}`));\n });\n });\n}\n\nexport function killProcessTree(pid: number): void {\n if (process.platform === \"win32\") {\n try {\n spawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n stdio: \"ignore\",\n detached: true,\n });\n } catch {\n // Ignore errors\n }\n } else {\n try {\n process.kill(-pid, \"SIGKILL\");\n } catch {\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // Process already dead\n }\n }\n }\n}\n\nexport function shellEscape(s: string): string {\n // Escape for passing to sh -c\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n\n/**\n * Shared exec-backed file transport for executors whose only channel into the\n * runtime is `exec` (docker exec, ssh, HTTP). Contents travel base64-encoded —\n * the base64 alphabet is inert under every shell parse layer — and writes are\n * chunked so no single command approaches the per-argument ARG_MAX limit,\n * staged, then moved into place so an aborted write never truncates the file.\n */\nconst WRITE_CHUNK_CHARS = 65536;\n\ninterface ExecLikeResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\ninterface ExecLike<TOptions> {\n exec(command: string, options?: TOptions): Promise<ExecLikeResult>;\n}\n\nexport async function execReadFileBase64<TOptions>(\n executor: ExecLike<TOptions>,\n path: string,\n options?: TOptions,\n): Promise<string> {\n const result = await executor.exec(`base64 < ${shellEscape(path)}`, options);\n if (result.code !== 0) {\n throw new Error(result.stderr.trim() || `Failed to read file: ${path}`);\n }\n return result.stdout.replace(/\\s+/g, \"\");\n}\n\nexport async function execReadFile<TOptions>(\n executor: ExecLike<TOptions>,\n path: string,\n options?: TOptions,\n): Promise<string> {\n return Buffer.from(await execReadFileBase64(executor, path, options), \"base64\").toString(\"utf-8\");\n}\n\nexport async function execWriteFile<TOptions>(\n executor: ExecLike<TOptions>,\n path: string,\n content: string,\n options?: TOptions,\n): Promise<void> {\n const encoded = Buffer.from(content, \"utf-8\").toString(\"base64\");\n const escapedPath = shellEscape(path);\n const stage = shellEscape(`${path}.mikan-stage`);\n const stageB64 = shellEscape(`${path}.mikan-stage.b64`);\n\n const run = async (command: string) => {\n const result = await executor.exec(command, options);\n if (result.code !== 0) {\n await executor.exec(`rm -f ${stage} ${stageB64}`, options).catch(() => {});\n throw new Error(result.stderr.trim() || `Failed to write file: ${path}`);\n }\n };\n\n const dir = path.includes(\"/\") ? path.slice(0, path.lastIndexOf(\"/\")) || \"/\" : \".\";\n await run(`mkdir -p ${shellEscape(dir)} && : > ${stageB64}`);\n for (let offset = 0; offset === 0 || offset < encoded.length; offset += WRITE_CHUNK_CHARS) {\n const chunk = encoded.slice(offset, offset + WRITE_CHUNK_CHARS);\n await run(`printf '%s' ${shellEscape(chunk)} >> ${stageB64}`);\n }\n await run(\n `base64 -d < ${stageB64} > ${stage} && mv ${stage} ${escapedPath} && rm -f ${stageB64}`,\n );\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { type ResolvedSessionScope } from "./store.js";
2
+ export type { ChatHistorySyncOptions, HasMaterializedSessionOptions, RegisterThreadSessionOptions, ResetChatSessionOptions, ResolveChatSessionScopeOptions, SyncChatSessionOptions, ThreadBootstrapWaitOptions, ChatSyncReport, } from "./types.js";
3
+ import type { ChatHistorySyncOptions, HasMaterializedSessionOptions, RegisterThreadSessionOptions, ResetChatSessionOptions, ResolveChatSessionScopeOptions, SyncChatSessionOptions, ThreadBootstrapWaitOptions, ChatSyncReport } from "./types.js";
4
+ export declare function hasMaterializedChatSession(options: HasMaterializedSessionOptions): boolean;
5
+ export declare function registerThreadSession(options: RegisterThreadSessionOptions): string | null;
6
+ export declare function waitForThreadSessionBootstrap(options: ThreadBootstrapWaitOptions): Promise<boolean>;
7
+ /**
8
+ * Syncs the platform chat transcript (log.jsonl) into managed session files:
9
+ * resolves which session file a message belongs to (top-level vs thread,
10
+ * with biweekly rotation), bootstraps new sessions from recent history, and
11
+ * incrementally appends log messages the session does not yet represent.
12
+ */
13
+ export declare class ChatHistorySync {
14
+ private readonly recentDays;
15
+ private readonly maxTopLevelMessages;
16
+ private readonly now;
17
+ constructor(options?: ChatHistorySyncOptions);
18
+ resolveSessionScope(options: ResolveChatSessionScopeOptions): Promise<ResolvedSessionScope>;
19
+ syncSessionManager(options: SyncChatSessionOptions): ChatSyncReport;
20
+ resetSession(options: ResetChatSessionOptions): string;
21
+ private resolveTopLevelSessionFile;
22
+ private historyWindow;
23
+ private resolveThreadSessionScope;
24
+ }
25
+ //# sourceMappingURL=chat-history-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-history-sync.d.ts","sourceRoot":"","sources":["../../src/sessions/chat-history-sync.ts"],"names":[],"mappings":"AASA,OAAO,EAUL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAQpB,YAAY,EACV,sBAAsB,EACtB,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,sBAAsB,EACtB,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,EAEf,MAAM,YAAY,CAAC;AAEpB,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAQ1F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,GAAG,IAAI,CAQ1F;AAED,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IAEjC,YAAY,OAAO,GAAE,sBAA2B,EAI/C;IAEK,mBAAmB,CACvB,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAsB/B;IAED,kBAAkB,CAAC,OAAO,EAAE,sBAAsB,GAAG,cAAc,CAUlE;IAED,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAmBrD;IAED,OAAO,CAAC,0BAA0B;IA2ClC,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,yBAAyB;CA4ClC"}
@@ -1,24 +1,23 @@
1
- import { join } from "path";
2
- import { isRecord, parseJsonValue, readTextFileIfExists } from "../utils/file-guards.js";
3
- import { formatLocalTimestamp } from "../utils/date.js";
4
- import { atomicWritePrivateFile } from "../utils/fs-atomic.js";
5
- import * as log from "../log.js";
1
+ import { isRecord } from "../utils/file-guards.js";
2
+ import { isCommandText } from "../commands/text.js";
3
+ import { readConversationLog } from "./conversation-log.js";
4
+ import { formatHistoryLine, stripHistoryLinePrefix } from "./history-line.js";
6
5
  import { isPlatformHistorySession } from "./metadata.js";
6
+ import { shouldRotateTopLevelSession } from "./rotation.js";
7
+ import { isThreadSessionKey } from "./session-key.js";
7
8
  import { createManagedSessionFile, createManagedSessionFileAtPath, extractSessionSuffix, getChannelSessionDir, getThreadSessionFile, openManagedSession, resolveChannelSessionFile, tryResolveCurrentSession, tryResolveThreadSession, } from "./store.js";
8
9
  const DEFAULT_RECENT_DAYS = 14;
9
10
  const DEFAULT_MAX_TOP_LEVEL_MESSAGES = 200;
10
11
  const CHAT_SYNC_CUSTOM_TYPE = "mikan.chat_sync";
11
- const BIWEEKLY_ROTATION_ANCHOR = new Date(2026, 0, 4); // Sunday
12
- const BIWEEKLY_MS = 14 * 24 * 60 * 60 * 1000;
13
12
  export function hasMaterializedChatSession(options) {
14
- if (!options.sessionKey.includes(":")) {
13
+ if (!isThreadSessionKey(options.sessionKey)) {
15
14
  return resolveChannelSessionFile(options.conversationDir) !== null;
16
15
  }
17
16
  return (tryResolveThreadSession(getThreadSessionFile(options.conversationDir, options.sessionKey)) !==
18
17
  null);
19
18
  }
20
19
  export function registerThreadSession(options) {
21
- if (!options.sessionKey.includes(":"))
20
+ if (!isThreadSessionKey(options.sessionKey))
22
21
  return null;
23
22
  const threadFile = getThreadSessionFile(options.conversationDir, options.sessionKey);
24
23
  return (tryResolveThreadSession(threadFile) ??
@@ -26,7 +25,7 @@ export function registerThreadSession(options) {
26
25
  }
27
26
  export async function waitForThreadSessionBootstrap(options) {
28
27
  const { parentSessionKey, sessionKey, hasThreadSession, isParentRunning, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), pollMs = 100, } = options;
29
- if (!sessionKey.includes(":"))
28
+ if (!isThreadSessionKey(sessionKey))
30
29
  return false;
31
30
  if (sessionKey === parentSessionKey)
32
31
  return false;
@@ -39,7 +38,13 @@ export async function waitForThreadSessionBootstrap(options) {
39
38
  }
40
39
  return waited;
41
40
  }
42
- export class AgentMemoryFileManager {
41
+ /**
42
+ * Syncs the platform chat transcript (log.jsonl) into managed session files:
43
+ * resolves which session file a message belongs to (top-level vs thread,
44
+ * with biweekly rotation), bootstraps new sessions from recent history, and
45
+ * incrementally appends log messages the session does not yet represent.
46
+ */
47
+ export class ChatHistorySync {
43
48
  constructor(options = {}) {
44
49
  this.recentDays = options.recentDays ?? DEFAULT_RECENT_DAYS;
45
50
  this.maxTopLevelMessages = options.maxTopLevelMessages ?? DEFAULT_MAX_TOP_LEVEL_MESSAGES;
@@ -48,7 +53,7 @@ export class AgentMemoryFileManager {
48
53
  async resolveSessionScope(options) {
49
54
  const cwd = options.cwd ?? options.conversationDir;
50
55
  const sessionDir = getChannelSessionDir(options.conversationDir);
51
- if (!options.sessionKey.includes(":")) {
56
+ if (!isThreadSessionKey(options.sessionKey)) {
52
57
  const contextFile = this.resolveTopLevelSessionFile({
53
58
  conversationDir: options.conversationDir,
54
59
  sessionDir,
@@ -68,17 +73,27 @@ export class AgentMemoryFileManager {
68
73
  }
69
74
  syncSessionManager(options) {
70
75
  const records = readConversationLog(options.conversationDir);
71
- syncSessionManagerFromLog(options.sessionManager, selectExistingSessionSyncMessages(records, {
72
- sessionKey: options.sessionKey.includes(":") ? options.sessionKey : null,
76
+ return syncSessionManagerFromLog(options.sessionManager, selectExistingSessionSyncMessages(records, {
77
+ sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,
73
78
  excludeMessageId: options.currentMessageId,
74
79
  }), this.historyWindow());
75
80
  }
76
81
  resetSession(options) {
77
82
  const cwd = options.cwd ?? options.conversationDir;
78
- if (options.sessionKey.includes(":")) {
79
- return createManagedSessionFileAtPath(getThreadSessionFile(options.conversationDir, options.sessionKey), cwd);
80
- }
81
- return createManagedSessionFile(getChannelSessionDir(options.conversationDir), cwd);
83
+ const sessionFile = isThreadSessionKey(options.sessionKey)
84
+ ? createManagedSessionFileAtPath(getThreadSessionFile(options.conversationDir, options.sessionKey), cwd)
85
+ : createManagedSessionFile(getChannelSessionDir(options.conversationDir), cwd);
86
+ const records = readConversationLog(options.conversationDir);
87
+ const lastMessageId = latestSyncMessageId(records, {
88
+ sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,
89
+ });
90
+ openManagedSession(sessionFile, cwd).appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {
91
+ source: "log.jsonl",
92
+ messageCount: 0,
93
+ resetAt: this.now().toISOString(),
94
+ ...(lastMessageId ? { lastMessageId } : {}),
95
+ });
96
+ return sessionFile;
82
97
  }
83
98
  resolveTopLevelSessionFile(options) {
84
99
  const records = readConversationLog(options.conversationDir);
@@ -135,74 +150,6 @@ export class AgentMemoryFileManager {
135
150
  return { sessionDir: options.sessionDir, contextFile: threadFile, threadRootMessage };
136
151
  }
137
152
  }
138
- function shouldRotateTopLevelSession(sessionFile, now) {
139
- const timestamp = readSessionTimestamp(sessionFile);
140
- return timestamp !== null && biweeklyBucket(timestamp) !== biweeklyBucket(now);
141
- }
142
- function readSessionTimestamp(sessionFile) {
143
- const raw = readTextFileIfExists(sessionFile);
144
- if (raw === undefined)
145
- return null;
146
- const firstLine = raw.split("\n").find((line) => line.trim());
147
- if (!firstLine)
148
- return null;
149
- try {
150
- const header = parseJsonValue(firstLine, (value) => isRecord(value), (detail) => (detail === "unexpected JSON shape" ? "expected a JSON object" : detail));
151
- if (typeof header.timestamp !== "string")
152
- return null;
153
- const date = new Date(header.timestamp);
154
- return Number.isFinite(date.getTime()) ? date : null;
155
- }
156
- catch {
157
- return null;
158
- }
159
- }
160
- function biweeklyBucket(date) {
161
- const weekStart = sundayStart(date).getTime();
162
- const anchor = sundayStart(BIWEEKLY_ROTATION_ANCHOR).getTime();
163
- return Math.floor((weekStart - anchor) / BIWEEKLY_MS);
164
- }
165
- function sundayStart(date) {
166
- return new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay());
167
- }
168
- function readConversationLog(conversationDir) {
169
- const logFile = join(conversationDir, "log.jsonl");
170
- const raw = readTextFileIfExists(logFile);
171
- if (raw === undefined)
172
- return [];
173
- const lines = raw.trim().split("\n").filter(Boolean);
174
- const records = [];
175
- for (let i = 0; i < lines.length; i++) {
176
- try {
177
- const message = parseJsonValue(lines[i], (value) => isRecord(value), (detail) => (detail === "unexpected JSON shape" ? "expected a JSON object" : detail));
178
- records.push({ message, index: i });
179
- }
180
- catch (err) {
181
- log.logWarning(`Skipping malformed log entry at ${logFile}:${i + 1}`, err instanceof Error ? err.message : String(err));
182
- }
183
- }
184
- return coalesceMessagingBotLogChunks(records);
185
- }
186
- function coalesceMessagingBotLogChunks(records) {
187
- const coalesced = [];
188
- for (const record of records) {
189
- const previous = coalesced.at(-1);
190
- if (previous && canCoalesceMessagingBotLogChunk(previous.message, record.message)) {
191
- previous.message.text = `${previous.message.text ?? ""}${record.message.text ?? ""}`;
192
- continue;
193
- }
194
- coalesced.push({ ...record, message: { ...record.message } });
195
- }
196
- return coalesced;
197
- }
198
- function canCoalesceMessagingBotLogChunk(previous, current) {
199
- return (previous.isMessagingBot === true &&
200
- current.isMessagingBot === true &&
201
- !!previous.ts &&
202
- previous.ts === current.ts &&
203
- previous.threadTs === current.threadTs &&
204
- previous.user === current.user);
205
- }
206
153
  function findLogRecordById(records, messageId) {
207
154
  for (let i = records.length - 1; i >= 0; i--) {
208
155
  if (records[i].message.ts === messageId)
@@ -211,7 +158,7 @@ function findLogRecordById(records, messageId) {
211
158
  return undefined;
212
159
  }
213
160
  function selectRecentTopLevelMessages(records, options) {
214
- return selectRecentMessages(records.filter((record) => isTopLevelHistoryMessage(record.message, options.excludeMessageId)), options);
161
+ return selectRecentMessages(recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) => isTopLevelHistoryMessage(record.message, options.excludeMessageId)), options);
215
162
  }
216
163
  function selectRecentMessages(records, options) {
217
164
  const sinceMs = options.now.getTime() - options.recentDays * 24 * 60 * 60 * 1000;
@@ -220,17 +167,18 @@ function selectRecentMessages(records, options) {
220
167
  .slice(-options.maxMessages);
221
168
  }
222
169
  function selectThreadBootstrapMessages(records, threadId, options) {
223
- const rootRecord = findLogRecordById(records, threadId);
170
+ const scopedRecords = recordsBeforeCurrentMessage(records, options.excludeMessageId);
171
+ const rootRecord = findLogRecordById(scopedRecords, threadId);
224
172
  const topLevelSource = rootRecord
225
- ? records.filter((record) => record.index <= rootRecord.index)
226
- : records;
173
+ ? scopedRecords.filter((record) => record.index <= rootRecord.index)
174
+ : scopedRecords;
227
175
  const topLevelRecords = selectRecentTopLevelMessages(topLevelSource, {
228
176
  recentDays: options.recentDays,
229
177
  maxMessages: options.maxTopLevelMessages,
230
178
  now: options.now,
231
179
  excludeMessageId: options.excludeMessageId,
232
180
  });
233
- const threadRecords = records.filter((record) => isRenderableConversationMessage(record.message, options.excludeMessageId) &&
181
+ const threadRecords = scopedRecords.filter((record) => isRenderableConversationMessage(record.message, options.excludeMessageId) &&
234
182
  (record.message.ts === threadId || record.message.threadTs === threadId));
235
183
  return dedupeAndSortRecords([...topLevelRecords, ...threadRecords]);
236
184
  }
@@ -247,7 +195,7 @@ function isRecentHistoryMessage(message, sinceMs) {
247
195
  }
248
196
  function selectExistingSessionSyncMessages(records, options) {
249
197
  const threadId = options.sessionKey ? extractSessionSuffix(options.sessionKey) : null;
250
- return dedupeAndSortRecords(records.filter((record) => {
198
+ return dedupeAndSortRecords(recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) => {
251
199
  if (!isRenderableConversationMessage(record.message, options.excludeMessageId))
252
200
  return false;
253
201
  if (!threadId)
@@ -255,6 +203,19 @@ function selectExistingSessionSyncMessages(records, options) {
255
203
  return record.message.ts === threadId || record.message.threadTs === threadId;
256
204
  }));
257
205
  }
206
+ /**
207
+ * Slack logs messages before enqueueing them, so a later queued turn may
208
+ * already be present while the current turn is being prepared. Chat history
209
+ * must stop at the current record rather than merely removing that one id.
210
+ */
211
+ function recordsBeforeCurrentMessage(records, currentMessageId) {
212
+ if (!currentMessageId)
213
+ return records;
214
+ const currentRecord = findLogRecordById(records, currentMessageId);
215
+ if (!currentRecord)
216
+ return records;
217
+ return records.filter((record) => record.index < currentRecord.index);
218
+ }
258
219
  function latestSyncMessageId(records, options) {
259
220
  return selectExistingSessionSyncMessages(records, options).at(-1)?.message.ts;
260
221
  }
@@ -266,9 +227,7 @@ function isRenderableConversationMessage(message, excludeMessageId) {
266
227
  return !!message.text?.trim();
267
228
  }
268
229
  function isChatCommandMessage(message) {
269
- const text = message.text?.trim() ?? "";
270
- return (!message.isMessagingBot &&
271
- /^\/(?:pi-[\w-]+|login|session|new|stop|model|sandbox|admin|auto-reply)(?:@\w+)?(?:\s|$)/i.test(text));
230
+ return !message.isMessagingBot && isCommandText(message.text ?? "");
272
231
  }
273
232
  function dedupeAndSortRecords(records) {
274
233
  const byKey = new Map();
@@ -306,36 +265,44 @@ function bootstrapSessionFromLog(sessionFile, cwd, records, lastMessageId = reco
306
265
  messageCount: records.length,
307
266
  lastMessageId,
308
267
  });
309
- forceRewriteSession(sessionManager, sessionFile);
310
268
  }
311
269
  function syncSessionFromLog(sessionFile, cwd, records, historyWindow) {
312
270
  if (records.length === 0)
313
- return;
314
- syncSessionManagerFromLog(openManagedSession(sessionFile, cwd), records, historyWindow);
271
+ return { appended: 0 };
272
+ return syncSessionManagerFromLog(openManagedSession(sessionFile, cwd), records, historyWindow);
315
273
  }
316
274
  function syncSessionManagerFromLog(sessionManager, records, historyWindow) {
317
275
  if (records.length === 0)
318
- return;
276
+ return { appended: 0 };
319
277
  const existingEntries = sessionManager.getEntries();
278
+ const resetAt = getLatestChatSyncResetAt(existingEntries);
279
+ const eligibleRecords = resetAt
280
+ ? records.filter((record) => isAfterReset(record, resetAt))
281
+ : records;
320
282
  const lastSyncedMessageId = getLatestChatSyncMessageId(existingEntries);
321
283
  const lastSyncedIndex = lastSyncedMessageId
322
- ? records.findIndex((record) => record.message.ts === lastSyncedMessageId)
284
+ ? eligibleRecords.findIndex((record) => record.message.ts === lastSyncedMessageId)
323
285
  : -1;
324
- if (lastSyncedMessageId && lastSyncedIndex === -1)
325
- return;
326
- const syncCandidates = selectRecentMessages(records.slice(lastSyncedIndex + 1), historyWindow);
286
+ // A truncated or rebuilt log may no longer contain the watermark. Replay the
287
+ // current bounded history; represented-message matching below prevents duplicates.
288
+ const syncCandidates = selectRecentMessages(eligibleRecords.slice(lastSyncedIndex + 1), historyWindow);
327
289
  if (syncCandidates.length === 0)
328
- return;
290
+ return { appended: 0 };
329
291
  const represented = buildRepresentedMessageCounts(existingEntries);
330
292
  const newRecords = syncCandidates.filter((record) => !consumeRepresentedLogMessage(record, represented));
331
293
  if (newRecords.length === 0)
332
- return;
294
+ return { appended: 0 };
295
+ const lastMessageId = syncCandidates.at(-1)?.message.ts;
333
296
  appendLogRecordsToSession(sessionManager, newRecords);
334
297
  sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {
335
298
  source: "log.jsonl",
336
299
  messageCount: newRecords.length,
337
- lastMessageId: syncCandidates.at(-1)?.message.ts,
300
+ lastMessageId,
338
301
  });
302
+ return {
303
+ appended: newRecords.length,
304
+ ...(lastMessageId !== undefined ? { lastMessageId } : {}),
305
+ };
339
306
  }
340
307
  function appendLogRecordsToSession(sessionManager, records) {
341
308
  for (const record of records) {
@@ -344,14 +311,24 @@ function appendLogRecordsToSession(sessionManager, records) {
344
311
  sessionManager.appendMessage(message);
345
312
  }
346
313
  }
347
- function forceRewriteSession(sessionManager, sessionFile) {
348
- const header = sessionManager.getHeader();
349
- if (!header)
350
- return;
351
- const content = [header, ...sessionManager.getEntries()]
352
- .map((entry) => JSON.stringify(entry))
353
- .join("\n");
354
- atomicWritePrivateFile(sessionFile, `${content}\n`);
314
+ function getLatestChatSyncResetAt(entries) {
315
+ for (let i = entries.length - 1; i >= 0; i--) {
316
+ const entry = entries[i];
317
+ if (entry.type !== "custom" || entry.customType !== CHAT_SYNC_CUSTOM_TYPE)
318
+ continue;
319
+ if (!isRecord(entry.data) || typeof entry.data.resetAt !== "string")
320
+ continue;
321
+ const resetAt = new Date(entry.data.resetAt).getTime();
322
+ if (Number.isFinite(resetAt))
323
+ return resetAt;
324
+ }
325
+ return undefined;
326
+ }
327
+ function isAfterReset(record, resetAt) {
328
+ if (!record.message.date)
329
+ return false;
330
+ const messageTime = new Date(record.message.date).getTime();
331
+ return Number.isFinite(messageTime) && messageTime >= resetAt;
355
332
  }
356
333
  function getLatestChatSyncMessageId(entries) {
357
334
  for (let i = entries.length - 1; i >= 0; i--) {
@@ -413,11 +390,7 @@ function getSessionMessageText(entry) {
413
390
  .map((part) => (part.type === "text" && "text" in part ? part.text : ""))
414
391
  .join("\n");
415
392
  }
416
- function normalizeComparableText(text) {
417
- return text
418
- .replace(/^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[+-][0-9]{2}:[0-9]{2}\]\s+\[[^\]]+\](?:\s+\[in-thread:[^\]]+\])?:\s*/, "")
419
- .trim();
420
- }
393
+ const normalizeComparableText = stripHistoryLinePrefix;
421
394
  function buildHistorySessionMessage(message) {
422
395
  const text = message.text?.trim();
423
396
  if (!text)
@@ -466,10 +439,11 @@ function parseMessageTimestamp(message) {
466
439
  return undefined;
467
440
  }
468
441
  function formatHistoryMessage(message) {
469
- const text = message.text?.trim() ?? "";
470
- const userLabel = message.userName || message.user || "unknown";
471
- const timestamp = message.date ? formatLocalTimestamp(new Date(message.date)) : null;
472
- return timestamp ? `[${timestamp}] [${userLabel}]: ${text}` : `[${userLabel}]: ${text}`;
442
+ return formatHistoryLine({
443
+ date: message.date ? new Date(message.date) : undefined,
444
+ userName: message.userName || message.user,
445
+ text: message.text?.trim() ?? "",
446
+ });
473
447
  }
474
448
  function zeroUsage() {
475
449
  return {
@@ -481,4 +455,4 @@ function zeroUsage() {
481
455
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
482
456
  };
483
457
  }
484
- //# sourceMappingURL=agent-memory-file-manager.js.map
458
+ //# sourceMappingURL=chat-history-sync.js.map