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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (661) hide show
  1. package/CHANGELOG.md +714 -0
  2. package/README.md +99 -36
  3. package/dist/adapter.d.ts +11 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +18 -1
  6. package/dist/adapter.js.map +1 -1
  7. package/dist/adapters/discord/bot.d.ts +6 -7
  8. package/dist/adapters/discord/bot.d.ts.map +1 -1
  9. package/dist/adapters/discord/bot.js +88 -122
  10. package/dist/adapters/discord/bot.js.map +1 -1
  11. package/dist/adapters/discord/components.d.ts +33 -0
  12. package/dist/adapters/discord/components.d.ts.map +1 -0
  13. package/dist/adapters/discord/components.js +32 -0
  14. package/dist/adapters/discord/components.js.map +1 -0
  15. package/dist/adapters/discord/context.d.ts +3 -1
  16. package/dist/adapters/discord/context.d.ts.map +1 -1
  17. package/dist/adapters/discord/context.js +66 -217
  18. package/dist/adapters/discord/context.js.map +1 -1
  19. package/dist/adapters/discord/format.d.ts +3 -0
  20. package/dist/adapters/discord/format.d.ts.map +1 -0
  21. package/dist/adapters/discord/format.js +86 -0
  22. package/dist/adapters/discord/format.js.map +1 -0
  23. package/dist/adapters/github/bot.d.ts +89 -0
  24. package/dist/adapters/github/bot.d.ts.map +1 -0
  25. package/dist/adapters/github/bot.js +653 -0
  26. package/dist/adapters/github/bot.js.map +1 -0
  27. package/dist/adapters/github/client.d.ts +122 -0
  28. package/dist/adapters/github/client.d.ts.map +1 -0
  29. package/dist/adapters/github/client.js +314 -0
  30. package/dist/adapters/github/client.js.map +1 -0
  31. package/dist/adapters/github/cloudbuild.d.ts +19 -0
  32. package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
  33. package/dist/adapters/github/cloudbuild.js +71 -0
  34. package/dist/adapters/github/cloudbuild.js.map +1 -0
  35. package/dist/adapters/github/context.d.ts +12 -0
  36. package/dist/adapters/github/context.d.ts.map +1 -0
  37. package/dist/adapters/github/context.js +101 -0
  38. package/dist/adapters/github/context.js.map +1 -0
  39. package/dist/adapters/github/gcp-auth.d.ts +28 -0
  40. package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
  41. package/dist/adapters/github/gcp-auth.js +196 -0
  42. package/dist/adapters/github/gcp-auth.js.map +1 -0
  43. package/dist/adapters/github/github-ops.d.ts +91 -0
  44. package/dist/adapters/github/github-ops.d.ts.map +1 -0
  45. package/dist/adapters/github/github-ops.js +406 -0
  46. package/dist/adapters/github/github-ops.js.map +1 -0
  47. package/dist/adapters/github/ids.d.ts +34 -0
  48. package/dist/adapters/github/ids.d.ts.map +1 -0
  49. package/dist/adapters/github/ids.js +57 -0
  50. package/dist/adapters/github/ids.js.map +1 -0
  51. package/dist/adapters/github/repo.d.ts +33 -0
  52. package/dist/adapters/github/repo.d.ts.map +1 -0
  53. package/dist/adapters/github/repo.js +141 -0
  54. package/dist/adapters/github/repo.js.map +1 -0
  55. package/dist/adapters/github/tool-pack.d.ts +14 -0
  56. package/dist/adapters/github/tool-pack.d.ts.map +1 -0
  57. package/dist/adapters/github/tool-pack.js +56 -0
  58. package/dist/adapters/github/tool-pack.js.map +1 -0
  59. package/dist/adapters/github/tools/checks.d.ts +19 -0
  60. package/dist/adapters/github/tools/checks.d.ts.map +1 -0
  61. package/dist/adapters/github/tools/checks.js +105 -0
  62. package/dist/adapters/github/tools/checks.js.map +1 -0
  63. package/dist/adapters/github/tools/issue.d.ts +21 -0
  64. package/dist/adapters/github/tools/issue.d.ts.map +1 -0
  65. package/dist/adapters/github/tools/issue.js +48 -0
  66. package/dist/adapters/github/tools/issue.js.map +1 -0
  67. package/dist/adapters/github/tools/pr.d.ts +22 -0
  68. package/dist/adapters/github/tools/pr.d.ts.map +1 -0
  69. package/dist/adapters/github/tools/pr.js +48 -0
  70. package/dist/adapters/github/tools/pr.js.map +1 -0
  71. package/dist/adapters/github/tools/read.d.ts +21 -0
  72. package/dist/adapters/github/tools/read.d.ts.map +1 -0
  73. package/dist/adapters/github/tools/read.js +141 -0
  74. package/dist/adapters/github/tools/read.js.map +1 -0
  75. package/dist/adapters/github/tools/review-reply.d.ts +17 -0
  76. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
  77. package/dist/adapters/github/tools/review-reply.js +38 -0
  78. package/dist/adapters/github/tools/review-reply.js.map +1 -0
  79. package/dist/adapters/github/tools/sync.d.ts +17 -0
  80. package/dist/adapters/github/tools/sync.d.ts.map +1 -0
  81. package/dist/adapters/github/tools/sync.js +34 -0
  82. package/dist/adapters/github/tools/sync.js.map +1 -0
  83. package/dist/adapters/github/types.d.ts +373 -0
  84. package/dist/adapters/github/types.d.ts.map +1 -0
  85. package/dist/adapters/github/types.js +2 -0
  86. package/dist/adapters/github/types.js.map +1 -0
  87. package/dist/adapters/intake.d.ts +16 -5
  88. package/dist/adapters/intake.d.ts.map +1 -1
  89. package/dist/adapters/intake.js +86 -23
  90. package/dist/adapters/intake.js.map +1 -1
  91. package/dist/adapters/markdown-tables.d.ts +37 -0
  92. package/dist/adapters/markdown-tables.d.ts.map +1 -0
  93. package/dist/adapters/markdown-tables.js +164 -0
  94. package/dist/adapters/markdown-tables.js.map +1 -0
  95. package/dist/adapters/progressive-renderer.d.ts +7 -0
  96. package/dist/adapters/progressive-renderer.d.ts.map +1 -0
  97. package/dist/adapters/progressive-renderer.js +440 -0
  98. package/dist/adapters/progressive-renderer.js.map +1 -0
  99. package/dist/adapters/shared.d.ts +23 -10
  100. package/dist/adapters/shared.d.ts.map +1 -1
  101. package/dist/adapters/shared.js +60 -22
  102. package/dist/adapters/shared.js.map +1 -1
  103. package/dist/adapters/slack/assistant.d.ts +101 -0
  104. package/dist/adapters/slack/assistant.d.ts.map +1 -0
  105. package/dist/adapters/slack/assistant.js +204 -0
  106. package/dist/adapters/slack/assistant.js.map +1 -0
  107. package/dist/adapters/slack/blocks.d.ts +14 -0
  108. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  109. package/dist/adapters/slack/blocks.js +105 -147
  110. package/dist/adapters/slack/blocks.js.map +1 -1
  111. package/dist/adapters/slack/bot.d.ts +95 -13
  112. package/dist/adapters/slack/bot.d.ts.map +1 -1
  113. package/dist/adapters/slack/bot.js +545 -211
  114. package/dist/adapters/slack/bot.js.map +1 -1
  115. package/dist/adapters/slack/context.d.ts +3 -1
  116. package/dist/adapters/slack/context.d.ts.map +1 -1
  117. package/dist/adapters/slack/context.js +11 -17
  118. package/dist/adapters/slack/context.js.map +1 -1
  119. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  120. package/dist/adapters/slack/response-lifecycle.js +197 -323
  121. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  122. package/dist/adapters/slack/session.d.ts.map +1 -1
  123. package/dist/adapters/slack/session.js +7 -11
  124. package/dist/adapters/slack/session.js.map +1 -1
  125. package/dist/adapters/slack/stream-limits.d.ts +35 -0
  126. package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
  127. package/dist/adapters/slack/stream-limits.js +56 -0
  128. package/dist/adapters/slack/stream-limits.js.map +1 -0
  129. package/dist/adapters/slack/tool-pack.d.ts +11 -0
  130. package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
  131. package/dist/adapters/slack/tool-pack.js +45 -0
  132. package/dist/adapters/slack/tool-pack.js.map +1 -0
  133. package/dist/adapters/slack/tools/attach.js +1 -1
  134. package/dist/adapters/slack/tools/attach.js.map +1 -1
  135. package/dist/adapters/slack/tools/blockkit.d.ts +14 -0
  136. package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
  137. package/dist/adapters/slack/tools/blockkit.js +106 -0
  138. package/dist/adapters/slack/tools/blockkit.js.map +1 -0
  139. package/dist/adapters/slack/types.d.ts +40 -2
  140. package/dist/adapters/slack/types.d.ts.map +1 -1
  141. package/dist/adapters/slack/types.js.map +1 -1
  142. package/dist/adapters/telegram/bot.d.ts +8 -9
  143. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  144. package/dist/adapters/telegram/bot.js +115 -163
  145. package/dist/adapters/telegram/bot.js.map +1 -1
  146. package/dist/adapters/telegram/context.d.ts +2 -0
  147. package/dist/adapters/telegram/context.d.ts.map +1 -1
  148. package/dist/adapters/telegram/context.js +53 -188
  149. package/dist/adapters/telegram/context.js.map +1 -1
  150. package/dist/adapters/types.d.ts +132 -12
  151. package/dist/adapters/types.d.ts.map +1 -1
  152. package/dist/adapters/types.js.map +1 -1
  153. package/dist/agent-events.d.ts +3 -2
  154. package/dist/agent-events.d.ts.map +1 -1
  155. package/dist/agent-events.js +19 -1
  156. package/dist/agent-events.js.map +1 -1
  157. package/dist/agent.d.ts +14 -19
  158. package/dist/agent.d.ts.map +1 -1
  159. package/dist/agent.js +841 -298
  160. package/dist/agent.js.map +1 -1
  161. package/dist/cli/arg-grammar.d.ts +25 -0
  162. package/dist/cli/arg-grammar.d.ts.map +1 -0
  163. package/dist/cli/arg-grammar.js +61 -0
  164. package/dist/cli/arg-grammar.js.map +1 -0
  165. package/dist/cli/boot.d.ts +5 -0
  166. package/dist/cli/boot.d.ts.map +1 -0
  167. package/dist/cli/boot.js +117 -0
  168. package/dist/cli/boot.js.map +1 -0
  169. package/dist/cli/download.d.ts.map +1 -0
  170. package/dist/{download.js → cli/download.js} +2 -0
  171. package/dist/cli/download.js.map +1 -0
  172. package/dist/cli/ext-dev.d.ts +2 -0
  173. package/dist/cli/ext-dev.d.ts.map +1 -0
  174. package/dist/cli/ext-dev.js +188 -0
  175. package/dist/cli/ext-dev.js.map +1 -0
  176. package/dist/cli/ext.d.ts +2 -0
  177. package/dist/cli/ext.d.ts.map +1 -0
  178. package/dist/cli/ext.js +324 -0
  179. package/dist/cli/ext.js.map +1 -0
  180. package/dist/cli/office.d.ts +2 -0
  181. package/dist/cli/office.d.ts.map +1 -0
  182. package/dist/cli/office.js +91 -0
  183. package/dist/cli/office.js.map +1 -0
  184. package/dist/cli/types.d.ts +16 -0
  185. package/dist/cli/types.d.ts.map +1 -0
  186. package/dist/cli/types.js +2 -0
  187. package/dist/cli/types.js.map +1 -0
  188. package/dist/commands/admin.d.ts.map +1 -1
  189. package/dist/commands/admin.js +3 -2
  190. package/dist/commands/admin.js.map +1 -1
  191. package/dist/commands/auto-reply.d.ts.map +1 -1
  192. package/dist/commands/auto-reply.js +5 -9
  193. package/dist/commands/auto-reply.js.map +1 -1
  194. package/dist/commands/extensions.d.ts +18 -6
  195. package/dist/commands/extensions.d.ts.map +1 -1
  196. package/dist/commands/extensions.js +64 -14
  197. package/dist/commands/extensions.js.map +1 -1
  198. package/dist/commands/login.d.ts +2 -1
  199. package/dist/commands/login.d.ts.map +1 -1
  200. package/dist/commands/login.js +40 -5
  201. package/dist/commands/login.js.map +1 -1
  202. package/dist/commands/manifest.d.ts +37 -0
  203. package/dist/commands/manifest.d.ts.map +1 -0
  204. package/dist/commands/manifest.js +151 -0
  205. package/dist/commands/manifest.js.map +1 -0
  206. package/dist/commands/model.d.ts +2 -3
  207. package/dist/commands/model.d.ts.map +1 -1
  208. package/dist/commands/model.js +63 -24
  209. package/dist/commands/model.js.map +1 -1
  210. package/dist/commands/new.d.ts.map +1 -1
  211. package/dist/commands/new.js +15 -3
  212. package/dist/commands/new.js.map +1 -1
  213. package/dist/commands/registry.d.ts +2 -2
  214. package/dist/commands/registry.d.ts.map +1 -1
  215. package/dist/commands/registry.js +1 -2
  216. package/dist/commands/registry.js.map +1 -1
  217. package/dist/commands/sandbox.d.ts.map +1 -1
  218. package/dist/commands/sandbox.js +83 -33
  219. package/dist/commands/sandbox.js.map +1 -1
  220. package/dist/commands/session-view.d.ts.map +1 -1
  221. package/dist/commands/session-view.js +6 -3
  222. package/dist/commands/session-view.js.map +1 -1
  223. package/dist/commands/types.d.ts +79 -7
  224. package/dist/commands/types.d.ts.map +1 -1
  225. package/dist/commands/types.js.map +1 -1
  226. package/dist/config.d.ts +23 -8
  227. package/dist/config.d.ts.map +1 -1
  228. package/dist/config.js +222 -135
  229. package/dist/config.js.map +1 -1
  230. package/dist/env-manifest.d.ts +30 -0
  231. package/dist/env-manifest.d.ts.map +1 -0
  232. package/dist/env-manifest.js +233 -0
  233. package/dist/env-manifest.js.map +1 -0
  234. package/dist/events.d.ts.map +1 -1
  235. package/dist/events.js +20 -81
  236. package/dist/events.js.map +1 -1
  237. package/dist/execution-resolver.d.ts +7 -8
  238. package/dist/execution-resolver.d.ts.map +1 -1
  239. package/dist/execution-resolver.js +106 -110
  240. package/dist/execution-resolver.js.map +1 -1
  241. package/dist/extension-schedules.d.ts +31 -0
  242. package/dist/extension-schedules.d.ts.map +1 -0
  243. package/dist/extension-schedules.js +229 -0
  244. package/dist/extension-schedules.js.map +1 -0
  245. package/dist/harness/auth.d.ts +2 -1
  246. package/dist/harness/auth.d.ts.map +1 -1
  247. package/dist/harness/auth.js +11 -5
  248. package/dist/harness/auth.js.map +1 -1
  249. package/dist/harness/event-format.d.ts +27 -0
  250. package/dist/harness/event-format.d.ts.map +1 -0
  251. package/dist/harness/event-format.js +160 -0
  252. package/dist/harness/event-format.js.map +1 -0
  253. package/dist/harness/extensions/loader.d.ts +27 -49
  254. package/dist/harness/extensions/loader.d.ts.map +1 -1
  255. package/dist/harness/extensions/loader.js +486 -130
  256. package/dist/harness/extensions/loader.js.map +1 -1
  257. package/dist/harness/extensions/registry.d.ts +107 -2
  258. package/dist/harness/extensions/registry.d.ts.map +1 -1
  259. package/dist/harness/extensions/registry.js +316 -0
  260. package/dist/harness/extensions/registry.js.map +1 -1
  261. package/dist/harness/extensions/types.d.ts +482 -42
  262. package/dist/harness/extensions/types.d.ts.map +1 -1
  263. package/dist/harness/extensions/types.js.map +1 -1
  264. package/dist/harness/index.d.ts +18 -8
  265. package/dist/harness/index.d.ts.map +1 -1
  266. package/dist/harness/index.js +7 -4
  267. package/dist/harness/index.js.map +1 -1
  268. package/dist/harness/models.d.ts +7 -4
  269. package/dist/harness/models.d.ts.map +1 -1
  270. package/dist/harness/models.js +46 -24
  271. package/dist/harness/models.js.map +1 -1
  272. package/dist/harness/runner.d.ts +50 -54
  273. package/dist/harness/runner.d.ts.map +1 -1
  274. package/dist/harness/runner.js +232 -46
  275. package/dist/harness/runner.js.map +1 -1
  276. package/dist/harness/session-store.d.ts +11 -5
  277. package/dist/harness/session-store.d.ts.map +1 -1
  278. package/dist/harness/session-store.js +141 -36
  279. package/dist/harness/session-store.js.map +1 -1
  280. package/dist/harness/settings.d.ts +2 -20
  281. package/dist/harness/settings.d.ts.map +1 -1
  282. package/dist/harness/settings.js +12 -1
  283. package/dist/harness/settings.js.map +1 -1
  284. package/dist/harness/skills.d.ts +10 -29
  285. package/dist/harness/skills.d.ts.map +1 -1
  286. package/dist/harness/skills.js +48 -6
  287. package/dist/harness/skills.js.map +1 -1
  288. package/dist/harness/subagent-profiles.d.ts +8 -0
  289. package/dist/harness/subagent-profiles.d.ts.map +1 -0
  290. package/dist/harness/subagent-profiles.js +299 -0
  291. package/dist/harness/subagent-profiles.js.map +1 -0
  292. package/dist/harness/subagent-runner.d.ts +45 -0
  293. package/dist/harness/subagent-runner.d.ts.map +1 -0
  294. package/dist/harness/subagent-runner.js +680 -0
  295. package/dist/harness/subagent-runner.js.map +1 -0
  296. package/dist/harness/types.d.ts +267 -1
  297. package/dist/harness/types.d.ts.map +1 -1
  298. package/dist/harness/types.js.map +1 -1
  299. package/dist/harness/usage.d.ts +6 -0
  300. package/dist/harness/usage.d.ts.map +1 -0
  301. package/dist/harness/usage.js +32 -0
  302. package/dist/harness/usage.js.map +1 -0
  303. package/dist/index.d.ts +36 -8
  304. package/dist/index.d.ts.map +1 -1
  305. package/dist/index.js +22 -6
  306. package/dist/index.js.map +1 -1
  307. package/dist/main.js +391 -127
  308. package/dist/main.js.map +1 -1
  309. package/dist/observability/instrument.js +7 -5
  310. package/dist/observability/instrument.js.map +1 -1
  311. package/dist/observability/sentry.d.ts +2 -0
  312. package/dist/observability/sentry.d.ts.map +1 -1
  313. package/dist/observability/sentry.js +10 -2
  314. package/dist/observability/sentry.js.map +1 -1
  315. package/dist/office/address.d.ts +31 -0
  316. package/dist/office/address.d.ts.map +1 -0
  317. package/dist/office/address.js +113 -0
  318. package/dist/office/address.js.map +1 -0
  319. package/dist/office/index.d.ts +11 -0
  320. package/dist/office/index.d.ts.map +1 -0
  321. package/dist/office/index.js +11 -0
  322. package/dist/office/index.js.map +1 -0
  323. package/dist/office/layout.d.ts +27 -0
  324. package/dist/office/layout.d.ts.map +1 -0
  325. package/dist/office/layout.js +97 -0
  326. package/dist/office/layout.js.map +1 -0
  327. package/dist/office/migration.d.ts +44 -0
  328. package/dist/office/migration.d.ts.map +1 -0
  329. package/dist/office/migration.js +255 -0
  330. package/dist/office/migration.js.map +1 -0
  331. package/dist/office/registry.d.ts +75 -0
  332. package/dist/office/registry.d.ts.map +1 -0
  333. package/dist/office/registry.js +646 -0
  334. package/dist/office/registry.js.map +1 -0
  335. package/dist/office/types.d.ts +71 -0
  336. package/dist/office/types.d.ts.map +1 -0
  337. package/dist/office/types.js +2 -0
  338. package/dist/office/types.js.map +1 -0
  339. package/dist/packages/admin.d.ts +17 -0
  340. package/dist/packages/admin.d.ts.map +1 -0
  341. package/dist/packages/admin.js +98 -0
  342. package/dist/packages/admin.js.map +1 -0
  343. package/dist/packages/index.d.ts +6 -0
  344. package/dist/packages/index.d.ts.map +1 -0
  345. package/dist/packages/index.js +6 -0
  346. package/dist/packages/index.js.map +1 -0
  347. package/dist/packages/inspect.d.ts +11 -0
  348. package/dist/packages/inspect.d.ts.map +1 -0
  349. package/dist/packages/inspect.js +98 -0
  350. package/dist/packages/inspect.js.map +1 -0
  351. package/dist/packages/materialize.d.ts +40 -0
  352. package/dist/packages/materialize.d.ts.map +1 -0
  353. package/dist/packages/materialize.js +297 -0
  354. package/dist/packages/materialize.js.map +1 -0
  355. package/dist/packages/resolve.d.ts +25 -0
  356. package/dist/packages/resolve.d.ts.map +1 -0
  357. package/dist/packages/resolve.js +208 -0
  358. package/dist/packages/resolve.js.map +1 -0
  359. package/dist/packages/source.d.ts +39 -0
  360. package/dist/packages/source.d.ts.map +1 -0
  361. package/dist/packages/source.js +189 -0
  362. package/dist/packages/source.js.map +1 -0
  363. package/dist/packages/types.d.ts +104 -0
  364. package/dist/packages/types.d.ts.map +1 -0
  365. package/dist/packages/types.js +2 -0
  366. package/dist/packages/types.js.map +1 -0
  367. package/dist/provisioner.d.ts +66 -0
  368. package/dist/provisioner.d.ts.map +1 -1
  369. package/dist/provisioner.js +335 -13
  370. package/dist/provisioner.js.map +1 -1
  371. package/dist/runtime/conversation-runtime.d.ts +1 -1
  372. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  373. package/dist/runtime/conversation-runtime.js +562 -118
  374. package/dist/runtime/conversation-runtime.js.map +1 -1
  375. package/dist/runtime/session-lifecycle.d.ts +38 -0
  376. package/dist/runtime/session-lifecycle.d.ts.map +1 -0
  377. package/dist/runtime/session-lifecycle.js +193 -0
  378. package/dist/runtime/session-lifecycle.js.map +1 -0
  379. package/dist/runtime/types.d.ts +66 -7
  380. package/dist/runtime/types.d.ts.map +1 -1
  381. package/dist/runtime/types.js.map +1 -1
  382. package/dist/sandbox/cloudflare.d.ts +3 -0
  383. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  384. package/dist/sandbox/cloudflare.js +13 -1
  385. package/dist/sandbox/cloudflare.js.map +1 -1
  386. package/dist/sandbox/container.d.ts +4 -0
  387. package/dist/sandbox/container.d.ts.map +1 -1
  388. package/dist/sandbox/container.js +13 -3
  389. package/dist/sandbox/container.js.map +1 -1
  390. package/dist/sandbox/firecracker.d.ts +3 -0
  391. package/dist/sandbox/firecracker.d.ts.map +1 -1
  392. package/dist/sandbox/firecracker.js +13 -2
  393. package/dist/sandbox/firecracker.js.map +1 -1
  394. package/dist/sandbox/gondolin.d.ts +57 -0
  395. package/dist/sandbox/gondolin.d.ts.map +1 -0
  396. package/dist/sandbox/gondolin.js +764 -0
  397. package/dist/sandbox/gondolin.js.map +1 -0
  398. package/dist/sandbox/host.d.ts +3 -0
  399. package/dist/sandbox/host.d.ts.map +1 -1
  400. package/dist/sandbox/host.js +18 -3
  401. package/dist/sandbox/host.js.map +1 -1
  402. package/dist/sandbox/identity.d.ts +44 -0
  403. package/dist/sandbox/identity.d.ts.map +1 -0
  404. package/dist/sandbox/identity.js +68 -0
  405. package/dist/sandbox/identity.js.map +1 -0
  406. package/dist/sandbox/image.d.ts.map +1 -1
  407. package/dist/sandbox/image.js +2 -0
  408. package/dist/sandbox/image.js.map +1 -1
  409. package/dist/sandbox/index.d.ts +17 -4
  410. package/dist/sandbox/index.d.ts.map +1 -1
  411. package/dist/sandbox/index.js +37 -3
  412. package/dist/sandbox/index.js.map +1 -1
  413. package/dist/sandbox/types.d.ts +65 -1
  414. package/dist/sandbox/types.d.ts.map +1 -1
  415. package/dist/sandbox/types.js.map +1 -1
  416. package/dist/sandbox/utils.d.ts +14 -0
  417. package/dist/sandbox/utils.d.ts.map +1 -1
  418. package/dist/sandbox/utils.js +68 -1
  419. package/dist/sandbox/utils.js.map +1 -1
  420. package/dist/sessions/chat-history-sync.d.ts +25 -0
  421. package/dist/sessions/chat-history-sync.d.ts.map +1 -0
  422. package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +135 -131
  423. package/dist/sessions/chat-history-sync.js.map +1 -0
  424. package/dist/sessions/conversation-log.d.ts +9 -0
  425. package/dist/sessions/conversation-log.d.ts.map +1 -0
  426. package/dist/sessions/conversation-log.js +50 -0
  427. package/dist/sessions/conversation-log.js.map +1 -0
  428. package/dist/sessions/history-line.d.ts +29 -0
  429. package/dist/sessions/history-line.d.ts.map +1 -0
  430. package/dist/sessions/history-line.js +45 -0
  431. package/dist/sessions/history-line.js.map +1 -0
  432. package/dist/sessions/rotation.d.ts +2 -0
  433. package/dist/sessions/rotation.d.ts.map +1 -0
  434. package/dist/sessions/rotation.js +39 -0
  435. package/dist/sessions/rotation.js.map +1 -0
  436. package/dist/sessions/session-key.d.ts +33 -0
  437. package/dist/sessions/session-key.d.ts.map +1 -0
  438. package/dist/sessions/session-key.js +115 -0
  439. package/dist/sessions/session-key.js.map +1 -0
  440. package/dist/sessions/store.d.ts +15 -7
  441. package/dist/sessions/store.d.ts.map +1 -1
  442. package/dist/sessions/store.js +127 -36
  443. package/dist/sessions/store.js.map +1 -1
  444. package/dist/sessions/types.d.ts +19 -5
  445. package/dist/sessions/types.d.ts.map +1 -1
  446. package/dist/sessions/types.js.map +1 -1
  447. package/dist/settings-mutation.d.ts +40 -0
  448. package/dist/settings-mutation.d.ts.map +1 -0
  449. package/dist/settings-mutation.js +61 -0
  450. package/dist/settings-mutation.js.map +1 -0
  451. package/dist/subagent-progress.d.ts +39 -0
  452. package/dist/subagent-progress.d.ts.map +1 -0
  453. package/dist/subagent-progress.js +225 -0
  454. package/dist/subagent-progress.js.map +1 -0
  455. package/dist/tools/bash.d.ts +3 -1
  456. package/dist/tools/bash.d.ts.map +1 -1
  457. package/dist/tools/bash.js +26 -18
  458. package/dist/tools/bash.js.map +1 -1
  459. package/dist/tools/edit.d.ts.map +1 -1
  460. package/dist/tools/edit.js +14 -13
  461. package/dist/tools/edit.js.map +1 -1
  462. package/dist/tools/event.d.ts +1 -1
  463. package/dist/tools/event.d.ts.map +1 -1
  464. package/dist/tools/event.js +58 -45
  465. package/dist/tools/event.js.map +1 -1
  466. package/dist/tools/generate-image.d.ts +23 -0
  467. package/dist/tools/generate-image.d.ts.map +1 -0
  468. package/dist/tools/generate-image.js +65 -0
  469. package/dist/tools/generate-image.js.map +1 -0
  470. package/dist/tools/host-fn-tool.d.ts +21 -0
  471. package/dist/tools/host-fn-tool.d.ts.map +1 -0
  472. package/dist/tools/host-fn-tool.js +32 -0
  473. package/dist/tools/host-fn-tool.js.map +1 -0
  474. package/dist/tools/index.d.ts +19 -2
  475. package/dist/tools/index.d.ts.map +1 -1
  476. package/dist/tools/index.js +25 -2
  477. package/dist/tools/index.js.map +1 -1
  478. package/dist/tools/react.d.ts +15 -0
  479. package/dist/tools/react.d.ts.map +1 -0
  480. package/dist/tools/react.js +29 -0
  481. package/dist/tools/react.js.map +1 -0
  482. package/dist/tools/read.d.ts +1 -0
  483. package/dist/tools/read.d.ts.map +1 -1
  484. package/dist/tools/read.js +39 -33
  485. package/dist/tools/read.js.map +1 -1
  486. package/dist/tools/sandbox.d.ts +2 -2
  487. package/dist/tools/sandbox.d.ts.map +1 -1
  488. package/dist/tools/sandbox.js +14 -9
  489. package/dist/tools/sandbox.js.map +1 -1
  490. package/dist/tools/subagent-slots.d.ts +28 -0
  491. package/dist/tools/subagent-slots.d.ts.map +1 -0
  492. package/dist/tools/subagent-slots.js +72 -0
  493. package/dist/tools/subagent-slots.js.map +1 -0
  494. package/dist/tools/subagent.d.ts +61 -0
  495. package/dist/tools/subagent.d.ts.map +1 -0
  496. package/dist/tools/subagent.js +434 -0
  497. package/dist/tools/subagent.js.map +1 -0
  498. package/dist/tools/types.d.ts +40 -32
  499. package/dist/tools/types.d.ts.map +1 -1
  500. package/dist/tools/types.js.map +1 -1
  501. package/dist/tools/write.d.ts.map +1 -1
  502. package/dist/tools/write.js +2 -8
  503. package/dist/tools/write.js.map +1 -1
  504. package/dist/trigger.d.ts +2 -1
  505. package/dist/trigger.d.ts.map +1 -1
  506. package/dist/trigger.js +6 -9
  507. package/dist/trigger.js.map +1 -1
  508. package/dist/types.d.ts +411 -59
  509. package/dist/types.d.ts.map +1 -1
  510. package/dist/types.js +2 -2
  511. package/dist/types.js.map +1 -1
  512. package/dist/utils/file-guards.d.ts +9 -0
  513. package/dist/utils/file-guards.d.ts.map +1 -1
  514. package/dist/utils/file-guards.js +44 -1
  515. package/dist/utils/file-guards.js.map +1 -1
  516. package/dist/vault/disabled.d.ts +9 -0
  517. package/dist/vault/disabled.d.ts.map +1 -0
  518. package/dist/vault/disabled.js +25 -0
  519. package/dist/vault/disabled.js.map +1 -0
  520. package/dist/vault/index.d.ts +45 -2
  521. package/dist/vault/index.d.ts.map +1 -1
  522. package/dist/vault/index.js +127 -36
  523. package/dist/vault/index.js.map +1 -1
  524. package/dist/vault/types.d.ts +6 -2
  525. package/dist/vault/types.d.ts.map +1 -1
  526. package/dist/vault/types.js.map +1 -1
  527. package/dist/web/admin/portal.d.ts +31 -3
  528. package/dist/web/admin/portal.d.ts.map +1 -1
  529. package/dist/web/admin/portal.js +850 -345
  530. package/dist/web/admin/portal.js.map +1 -1
  531. package/dist/web/admin/provider-models.js +1 -1
  532. package/dist/web/admin/provider-models.js.map +1 -1
  533. package/dist/web/admin/types.d.ts +23 -3
  534. package/dist/web/admin/types.d.ts.map +1 -1
  535. package/dist/web/admin/types.js.map +1 -1
  536. package/dist/web/login/oauth.d.ts +2 -3
  537. package/dist/web/login/oauth.d.ts.map +1 -1
  538. package/dist/web/login/oauth.js +1 -32
  539. package/dist/web/login/oauth.js.map +1 -1
  540. package/dist/web/login/portal.d.ts +1 -1
  541. package/dist/web/login/portal.d.ts.map +1 -1
  542. package/dist/web/login/portal.js +13 -36
  543. package/dist/web/login/portal.js.map +1 -1
  544. package/dist/web/login/types.d.ts +0 -11
  545. package/dist/web/login/types.d.ts.map +1 -1
  546. package/dist/web/login/types.js.map +1 -1
  547. package/dist/web/portal-shell.d.ts +21 -0
  548. package/dist/web/portal-shell.d.ts.map +1 -0
  549. package/dist/{portal-shell.js → web/portal-shell.js} +67 -2
  550. package/dist/web/portal-shell.js.map +1 -0
  551. package/dist/web/server.d.ts +3 -2
  552. package/dist/web/server.d.ts.map +1 -1
  553. package/dist/web/server.js +11 -4
  554. package/dist/web/server.js.map +1 -1
  555. package/dist/web/session-view/portal.d.ts +1 -1
  556. package/dist/web/session-view/portal.d.ts.map +1 -1
  557. package/dist/web/session-view/portal.js +37 -28
  558. package/dist/web/session-view/portal.js.map +1 -1
  559. package/dist/web/session-view/service.d.ts +1 -1
  560. package/dist/web/session-view/service.d.ts.map +1 -1
  561. package/dist/web/session-view/service.js +61 -18
  562. package/dist/web/session-view/service.js.map +1 -1
  563. package/dist/web/session-view/types.d.ts +0 -3
  564. package/dist/web/session-view/types.d.ts.map +1 -1
  565. package/dist/web/session-view/types.js.map +1 -1
  566. package/dist/web/token-store.js +1 -1
  567. package/dist/web/token-store.js.map +1 -1
  568. package/dist/workspace-projection/index.d.ts +10 -0
  569. package/dist/workspace-projection/index.d.ts.map +1 -0
  570. package/dist/workspace-projection/index.js +120 -0
  571. package/dist/workspace-projection/index.js.map +1 -0
  572. package/dist/workspace-projection/types.d.ts +16 -0
  573. package/dist/workspace-projection/types.d.ts.map +1 -0
  574. package/dist/workspace-projection/types.js +2 -0
  575. package/dist/workspace-projection/types.js.map +1 -0
  576. package/package.json +68 -37
  577. package/dist/adapters/streaming.d.ts +0 -18
  578. package/dist/adapters/streaming.d.ts.map +0 -1
  579. package/dist/adapters/streaming.js +0 -44
  580. package/dist/adapters/streaming.js.map +0 -1
  581. package/dist/adapters/telegram/html.d.ts +0 -3
  582. package/dist/adapters/telegram/html.d.ts.map +0 -1
  583. package/dist/adapters/telegram/html.js +0 -98
  584. package/dist/adapters/telegram/html.js.map +0 -1
  585. package/dist/commands/parse.d.ts +0 -7
  586. package/dist/commands/parse.d.ts.map +0 -1
  587. package/dist/commands/parse.js +0 -14
  588. package/dist/commands/parse.js.map +0 -1
  589. package/dist/download.d.ts.map +0 -1
  590. package/dist/download.js.map +0 -1
  591. package/dist/model-registry.d.ts +0 -4
  592. package/dist/model-registry.d.ts.map +0 -1
  593. package/dist/model-registry.js +0 -7
  594. package/dist/model-registry.js.map +0 -1
  595. package/dist/portal-shell.d.ts +0 -4
  596. package/dist/portal-shell.d.ts.map +0 -1
  597. package/dist/portal-shell.js.map +0 -1
  598. package/dist/runtime/agent-run-controller.d.ts +0 -31
  599. package/dist/runtime/agent-run-controller.d.ts.map +0 -1
  600. package/dist/runtime/agent-run-controller.js +0 -195
  601. package/dist/runtime/agent-run-controller.js.map +0 -1
  602. package/dist/sandbox/path-context.d.ts +0 -3
  603. package/dist/sandbox/path-context.d.ts.map +0 -1
  604. package/dist/sandbox/path-context.js +0 -20
  605. package/dist/sandbox/path-context.js.map +0 -1
  606. package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
  607. package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
  608. package/dist/sessions/agent-memory-file-manager.js.map +0 -1
  609. package/dist/sessions/metadata.d.ts +0 -3
  610. package/dist/sessions/metadata.d.ts.map +0 -1
  611. package/dist/sessions/metadata.js +0 -11
  612. package/dist/sessions/metadata.js.map +0 -1
  613. package/dist/sessions/policy.d.ts +0 -6
  614. package/dist/sessions/policy.d.ts.map +0 -1
  615. package/dist/sessions/policy.js +0 -23
  616. package/dist/sessions/policy.js.map +0 -1
  617. package/dist/store.d.ts +0 -46
  618. package/dist/store.d.ts.map +0 -1
  619. package/dist/store.js +0 -177
  620. package/dist/store.js.map +0 -1
  621. package/dist/tools/truncate.d.ts +0 -33
  622. package/dist/tools/truncate.d.ts.map +0 -1
  623. package/dist/tools/truncate.js +0 -184
  624. package/dist/tools/truncate.js.map +0 -1
  625. package/dist/utils/date.d.ts +0 -10
  626. package/dist/utils/date.d.ts.map +0 -1
  627. package/dist/utils/date.js +0 -23
  628. package/dist/utils/date.js.map +0 -1
  629. package/dist/utils/env.d.ts +0 -3
  630. package/dist/utils/env.d.ts.map +0 -1
  631. package/dist/utils/env.js +0 -12
  632. package/dist/utils/env.js.map +0 -1
  633. package/dist/utils/fs-atomic.d.ts +0 -10
  634. package/dist/utils/fs-atomic.d.ts.map +0 -1
  635. package/dist/utils/fs-atomic.js +0 -45
  636. package/dist/utils/fs-atomic.js.map +0 -1
  637. package/dist/utils/html.d.ts +0 -2
  638. package/dist/utils/html.d.ts.map +0 -1
  639. package/dist/utils/html.js +0 -4
  640. package/dist/utils/html.js.map +0 -1
  641. package/dist/utils/http-body.d.ts +0 -10
  642. package/dist/utils/http-body.d.ts.map +0 -1
  643. package/dist/utils/http-body.js +0 -34
  644. package/dist/utils/http-body.js.map +0 -1
  645. package/dist/vault/routing.d.ts +0 -3
  646. package/dist/vault/routing.d.ts.map +0 -1
  647. package/dist/vault/routing.js +0 -13
  648. package/dist/vault/routing.js.map +0 -1
  649. package/dist/web/agent-events/portal.d.ts +0 -3
  650. package/dist/web/agent-events/portal.d.ts.map +0 -1
  651. package/dist/web/agent-events/portal.js +0 -18
  652. package/dist/web/agent-events/portal.js.map +0 -1
  653. package/dist/web/request.d.ts +0 -3
  654. package/dist/web/request.d.ts.map +0 -1
  655. package/dist/web/request.js +0 -13
  656. package/dist/web/request.js.map +0 -1
  657. package/dist/web/session-view/command.d.ts +0 -4
  658. package/dist/web/session-view/command.d.ts.map +0 -1
  659. package/dist/web/session-view/command.js +0 -7
  660. package/dist/web/session-view/command.js.map +0 -1
  661. /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
@@ -1,15 +1,14 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { createWriteStream } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
2
  import { Type } from "@sinclair/typebox";
6
- import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateTail, } from "./truncate.js";
3
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateTail, } from "@earendil-works/pi-agent-core";
7
4
  /**
8
- * Generate a unique temp file path for bash output
5
+ * Spill path for oversized bash output, inside the runtime workspace so the
6
+ * model can actually read the file it is pointed at (a host tmpdir path is a
7
+ * dead pointer inside sandbox containers — see src/sandbox/README.md).
9
8
  */
10
- function getTempFilePath() {
9
+ function getSpillPath(runtimeWorkspaceRoot) {
11
10
  const id = randomBytes(8).toString("hex");
12
- return join(tmpdir(), `mikan-bash-${id}.log`);
11
+ return `${runtimeWorkspaceRoot.replace(/\/+$/, "")}/.mikan/bash-output/${id}.log`;
13
12
  }
14
13
  const bashSchema = Type.Object({
15
14
  label: Type.String({
@@ -18,16 +17,15 @@ const bashSchema = Type.Object({
18
17
  command: Type.String({ description: "Bash command to execute" }),
19
18
  timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
20
19
  });
21
- export function createBashTool(executor) {
20
+ export function createBashTool(executor, options) {
22
21
  return {
23
22
  name: "bash",
24
23
  label: "bash",
24
+ executionMode: "sequential",
25
25
  description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
26
26
  parameters: bashSchema,
27
27
  execute: async (_toolCallId, { command, timeout }, signal) => {
28
- // Track output for potential temp file writing
29
28
  let tempFilePath;
30
- let tempFileStream;
31
29
  const result = await executor.exec(command, { timeout, signal });
32
30
  let output = "";
33
31
  if (result.stdout)
@@ -38,12 +36,19 @@ export function createBashTool(executor) {
38
36
  output += result.stderr;
39
37
  }
40
38
  const totalBytes = Buffer.byteLength(output, "utf-8");
41
- // Write to temp file if output exceeds limit
39
+ // Spill the full output into the runtime workspace when it exceeds the
40
+ // limit; the executor owns transport, so the advertised path is valid
41
+ // where the model's follow-up read/bash actually runs.
42
42
  if (totalBytes > DEFAULT_MAX_BYTES) {
43
- tempFilePath = getTempFilePath();
44
- tempFileStream = createWriteStream(tempFilePath);
45
- tempFileStream.write(output);
46
- tempFileStream.end();
43
+ const runtimeRoot = executor.getPathContext(options?.hostWorkspaceRoot ?? process.cwd()).runtimeWorkspaceRoot;
44
+ const spillPath = getSpillPath(runtimeRoot);
45
+ try {
46
+ await executor.writeFile(spillPath, output, { signal });
47
+ tempFilePath = spillPath;
48
+ }
49
+ catch {
50
+ tempFilePath = undefined;
51
+ }
47
52
  }
48
53
  // Apply tail truncation
49
54
  const truncation = truncateTail(output);
@@ -58,16 +63,19 @@ export function createBashTool(executor) {
58
63
  // Build actionable notice
59
64
  const startLine = truncation.totalLines - truncation.outputLines + 1;
60
65
  const endLine = truncation.totalLines;
66
+ const fullOutputNote = tempFilePath
67
+ ? ` Full output: ${tempFilePath}`
68
+ : " Full output unavailable (spill failed).";
61
69
  if (truncation.lastLinePartial) {
62
70
  // Edge case: last line alone > 50KB
63
71
  const lastLineSize = formatSize(Buffer.byteLength(output.split("\n").pop() || "", "utf-8"));
64
- outputText += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${tempFilePath}]`;
72
+ outputText += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}).${fullOutputNote}]`;
65
73
  }
66
74
  else if (truncation.truncatedBy === "lines") {
67
- outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${tempFilePath}]`;
75
+ outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}.${fullOutputNote}]`;
68
76
  }
69
77
  else {
70
- outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${tempFilePath}]`;
78
+ outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit).${fullOutputNote}]`;
71
79
  }
72
80
  }
73
81
  if (result.code !== 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { Executor } from \"../sandbox/index.js\";\nimport {\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_LINES,\n formatSize,\n type TruncationResult,\n truncateTail,\n} from \"./truncate.js\";\n\n/**\n * Generate a unique temp file path for bash output\n */\nfunction getTempFilePath(): string {\n const id = randomBytes(8).toString(\"hex\");\n return join(tmpdir(), `mikan-bash-${id}.log`);\n}\n\nconst bashSchema = Type.Object({\n label: Type.String({\n description: \"Brief description of what this command does (shown to user)\",\n }),\n command: Type.String({ description: \"Bash command to execute\" }),\n timeout: Type.Optional(\n Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" }),\n ),\n});\n\ninterface BashToolDetails {\n truncation?: TruncationResult;\n fullOutputPath?: string;\n}\n\nexport function createBashTool(executor: Executor): AgentTool<typeof bashSchema> {\n return {\n name: \"bash\",\n label: \"bash\",\n description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n parameters: bashSchema,\n execute: async (\n _toolCallId: string,\n { command, timeout }: { label: string; command: string; timeout?: number },\n signal?: AbortSignal,\n ) => {\n // Track output for potential temp file writing\n let tempFilePath: string | undefined;\n let tempFileStream: ReturnType<typeof createWriteStream> | undefined;\n\n const result = await executor.exec(command, { timeout, signal });\n let output = \"\";\n if (result.stdout) output += result.stdout;\n if (result.stderr) {\n if (output) output += \"\\n\";\n output += result.stderr;\n }\n\n const totalBytes = Buffer.byteLength(output, \"utf-8\");\n\n // Write to temp file if output exceeds limit\n if (totalBytes > DEFAULT_MAX_BYTES) {\n tempFilePath = getTempFilePath();\n tempFileStream = createWriteStream(tempFilePath);\n tempFileStream.write(output);\n tempFileStream.end();\n }\n\n // Apply tail truncation\n const truncation = truncateTail(output);\n let outputText = truncation.content || \"(no output)\";\n\n // Build details with truncation info\n let details: BashToolDetails | undefined;\n\n if (truncation.truncated) {\n details = {\n truncation,\n fullOutputPath: tempFilePath,\n };\n\n // Build actionable notice\n const startLine = truncation.totalLines - truncation.outputLines + 1;\n const endLine = truncation.totalLines;\n\n if (truncation.lastLinePartial) {\n // Edge case: last line alone > 50KB\n const lastLineSize = formatSize(\n Buffer.byteLength(output.split(\"\\n\").pop() || \"\", \"utf-8\"),\n );\n outputText += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${tempFilePath}]`;\n } else if (truncation.truncatedBy === \"lines\") {\n outputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${tempFilePath}]`;\n } else {\n outputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${tempFilePath}]`;\n }\n }\n\n if (result.code !== 0) {\n throw new Error(`${outputText}\\n\\nCommand exited with code ${result.code}`.trim());\n }\n\n return { content: [{ type: \"text\", text: outputText }], details };\n },\n };\n}\n"]}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { Executor } from \"../sandbox/index.js\";\nimport {\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_LINES,\n formatSize,\n type TruncationResult,\n truncateTail,\n} from \"@earendil-works/pi-agent-core\";\n\n/**\n * Spill path for oversized bash output, inside the runtime workspace so the\n * model can actually read the file it is pointed at (a host tmpdir path is a\n * dead pointer inside sandbox containers — see src/sandbox/README.md).\n */\nfunction getSpillPath(runtimeWorkspaceRoot: string): string {\n const id = randomBytes(8).toString(\"hex\");\n return `${runtimeWorkspaceRoot.replace(/\\/+$/, \"\")}/.mikan/bash-output/${id}.log`;\n}\n\nconst bashSchema = Type.Object({\n label: Type.String({\n description: \"Brief description of what this command does (shown to user)\",\n }),\n command: Type.String({ description: \"Bash command to execute\" }),\n timeout: Type.Optional(\n Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" }),\n ),\n});\n\ninterface BashToolDetails {\n truncation?: TruncationResult;\n fullOutputPath?: string;\n}\n\nexport function createBashTool(\n executor: Executor,\n options?: { hostWorkspaceRoot?: string },\n): AgentTool<typeof bashSchema> {\n return {\n name: \"bash\",\n label: \"bash\",\n executionMode: \"sequential\",\n description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n parameters: bashSchema,\n execute: async (\n _toolCallId: string,\n { command, timeout }: { label: string; command: string; timeout?: number },\n signal?: AbortSignal,\n ) => {\n let tempFilePath: string | undefined;\n\n const result = await executor.exec(command, { timeout, signal });\n let output = \"\";\n if (result.stdout) output += result.stdout;\n if (result.stderr) {\n if (output) output += \"\\n\";\n output += result.stderr;\n }\n\n const totalBytes = Buffer.byteLength(output, \"utf-8\");\n\n // Spill the full output into the runtime workspace when it exceeds the\n // limit; the executor owns transport, so the advertised path is valid\n // where the model's follow-up read/bash actually runs.\n if (totalBytes > DEFAULT_MAX_BYTES) {\n const runtimeRoot = executor.getPathContext(\n options?.hostWorkspaceRoot ?? process.cwd(),\n ).runtimeWorkspaceRoot;\n const spillPath = getSpillPath(runtimeRoot);\n try {\n await executor.writeFile(spillPath, output, { signal });\n tempFilePath = spillPath;\n } catch {\n tempFilePath = undefined;\n }\n }\n\n // Apply tail truncation\n const truncation = truncateTail(output);\n let outputText = truncation.content || \"(no output)\";\n\n // Build details with truncation info\n let details: BashToolDetails | undefined;\n\n if (truncation.truncated) {\n details = {\n truncation,\n fullOutputPath: tempFilePath,\n };\n\n // Build actionable notice\n const startLine = truncation.totalLines - truncation.outputLines + 1;\n const endLine = truncation.totalLines;\n const fullOutputNote = tempFilePath\n ? ` Full output: ${tempFilePath}`\n : \" Full output unavailable (spill failed).\";\n\n if (truncation.lastLinePartial) {\n // Edge case: last line alone > 50KB\n const lastLineSize = formatSize(\n Buffer.byteLength(output.split(\"\\n\").pop() || \"\", \"utf-8\"),\n );\n outputText += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}).${fullOutputNote}]`;\n } else if (truncation.truncatedBy === \"lines\") {\n outputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}.${fullOutputNote}]`;\n } else {\n outputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit).${fullOutputNote}]`;\n }\n }\n\n if (result.code !== 0) {\n throw new Error(`${outputText}\\n\\nCommand exited with code ${result.code}`.trim());\n }\n\n return { content: [{ type: \"text\", text: outputText }], details };\n },\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAsFpD,QAAA,MAAM,UAAU;;;;;EAOd,CAAC;AAEH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAqE/E"}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAuFpD,QAAA,MAAM,UAAU;;;;;EAOd,CAAC;AAEH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAkE/E"}
@@ -1,6 +1,5 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import * as Diff from "diff";
3
- import { shellEscape } from "../sandbox/utils.js";
4
3
  /**
5
4
  * Generate a unified diff string with line numbers and context
6
5
  */
@@ -16,6 +15,8 @@ function generateDiffString(oldContent, newContent, contextLines = 4) {
16
15
  let lastWasChange = false;
17
16
  for (let i = 0; i < parts.length; i++) {
18
17
  const part = parts[i];
18
+ if (part === undefined)
19
+ continue;
19
20
  const raw = part.value.split("\n");
20
21
  if (raw[raw.length - 1] === "") {
21
22
  raw.pop();
@@ -36,7 +37,8 @@ function generateDiffString(oldContent, newContent, contextLines = 4) {
36
37
  lastWasChange = true;
37
38
  }
38
39
  else {
39
- const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);
40
+ const nextPart = parts[i + 1];
41
+ const nextPartIsChange = nextPart !== undefined && (nextPart.added || nextPart.removed);
40
42
  if (lastWasChange || nextPartIsChange) {
41
43
  let linesToShow = raw;
42
44
  let skipStart = 0;
@@ -85,15 +87,19 @@ export function createEditTool(executor) {
85
87
  return {
86
88
  name: "edit",
87
89
  label: "edit",
90
+ executionMode: "sequential",
88
91
  description: "Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.",
89
92
  parameters: editSchema,
90
93
  execute: async (_toolCallId, { path, oldText, newText }, signal) => {
91
- // Read the file
92
- const readResult = await executor.exec(`cat ${shellEscape(path)}`, { signal });
93
- if (readResult.code !== 0) {
94
- throw new Error(readResult.stderr || `File not found: ${path}`);
94
+ let content;
95
+ try {
96
+ content = await executor.readFile(path, { signal });
97
+ }
98
+ catch (err) {
99
+ throw new Error(err instanceof Error && err.message ? err.message : `File not found: ${path}`, {
100
+ cause: err,
101
+ });
95
102
  }
96
- const content = readResult.stdout;
97
103
  // Check if old text exists
98
104
  if (!content.includes(oldText)) {
99
105
  throw new Error(`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`);
@@ -110,12 +116,7 @@ export function createEditTool(executor) {
110
116
  throw new Error(`No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`);
111
117
  }
112
118
  // Write the file back
113
- const writeResult = await executor.exec(`printf '%s' ${shellEscape(newContent)} > ${shellEscape(path)}`, {
114
- signal,
115
- });
116
- if (writeResult.code !== 0) {
117
- throw new Error(writeResult.stderr || `Failed to write file: ${path}`);
118
- }
119
+ await executor.writeFile(path, newContent, { signal });
119
120
  return {
120
121
  content: [
121
122
  {
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD;;GAEG;AACH,SAAS,kBAAkB,CAAC,UAAkB,EAAE,UAAkB,EAAE,YAAY,GAAG,CAAC;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAE/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;gBACvB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACf,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;oBAC/D,MAAM,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;oBACnC,UAAU,EAAE,CAAC;gBACf,CAAC;qBAAM,CAAC;oBACN,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;oBAC/D,MAAM,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;oBACnC,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;YACD,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,gBAAgB,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAE9F,IAAI,aAAa,IAAI,gBAAgB,EAAE,CAAC;gBACtC,IAAI,WAAW,GAAG,GAAG,CAAC;gBACtB,IAAI,SAAS,GAAG,CAAC,CAAC;gBAClB,IAAI,OAAO,GAAG,CAAC,CAAC;gBAEhB,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;oBACnD,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACrC,CAAC;gBAED,IAAI,CAAC,gBAAgB,IAAI,WAAW,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;oBAC3D,OAAO,GAAG,WAAW,CAAC,MAAM,GAAG,YAAY,CAAC;oBAC5C,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBACnD,CAAC;gBAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;oBAClB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxD,CAAC;gBAED,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;oBAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;oBAC/D,MAAM,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;oBACnC,UAAU,EAAE,CAAC;oBACb,UAAU,EAAE,CAAC;gBACf,CAAC;gBAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;oBAChB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxD,CAAC;gBAED,UAAU,IAAI,SAAS,GAAG,OAAO,CAAC;gBAClC,UAAU,IAAI,SAAS,GAAG,OAAO,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC;gBACzB,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC;YAC3B,CAAC;YAED,aAAa,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC7B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QACjB,WAAW,EAAE,6DAA6D;KAC3E,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;IACrF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qDAAqD,EAAE,CAAC;IAC5F,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,uCAAuC,EAAE,CAAC;CAC/E,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc,CAAC,QAAkB;IAC/C,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,MAAM;QACb,WAAW,EACT,mIAAmI;QACrI,UAAU,EAAE,UAAU;QACtB,OAAO,EAAE,KAAK,EACZ,WAAmB,EACnB,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAqE,EAC7F,MAAoB,EACpB,EAAE;YACF,gBAAgB;YAChB,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/E,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,mBAAmB,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC;YAElC,2BAA2B;YAC3B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,oCAAoC,IAAI,0EAA0E,CACnH,CAAC;YACJ,CAAC;YAED,oBAAoB;YACpB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAEtD,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CACb,SAAS,WAAW,+BAA+B,IAAI,2EAA2E,CACnI,CAAC;YACJ,CAAC;YAED,sBAAsB;YACtB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACvC,MAAM,UAAU,GACd,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAEpF,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,sBAAsB,IAAI,0IAA0I,CACrK,CAAC;YACJ,CAAC;YAED,sBAAsB;YACtB,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,CACrC,eAAe,WAAW,CAAC,UAAU,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,EAAE,EAC/D;gBACE,MAAM;aACP,CACF,CAAC;YACF,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,IAAI,yBAAyB,IAAI,EAAE,CAAC,CAAC;YACzE,CAAC;YAED,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,iCAAiC,IAAI,aAAa,OAAO,CAAC,MAAM,kBAAkB,OAAO,CAAC,MAAM,cAAc;qBACrH;iBACF;gBACD,OAAO,EAAE,EAAE,IAAI,EAAE,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport * as Diff from \"diff\";\nimport type { Executor } from \"../sandbox/index.js\";\nimport { shellEscape } from \"../sandbox/utils.js\";\n\n/**\n * Generate a unified diff string with line numbers and context\n */\nfunction generateDiffString(oldContent: string, newContent: string, contextLines = 4): string {\n const parts = Diff.diffLines(oldContent, newContent);\n const output: string[] = [];\n\n const oldLines = oldContent.split(\"\\n\");\n const newLines = newContent.split(\"\\n\");\n const maxLineNum = Math.max(oldLines.length, newLines.length);\n const lineNumWidth = String(maxLineNum).length;\n\n let oldLineNum = 1;\n let newLineNum = 1;\n let lastWasChange = false;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const raw = part.value.split(\"\\n\");\n if (raw[raw.length - 1] === \"\") {\n raw.pop();\n }\n\n if (part.added || part.removed) {\n for (const line of raw) {\n if (part.added) {\n const lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\n output.push(`+${lineNum} ${line}`);\n newLineNum++;\n } else {\n const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n output.push(`-${lineNum} ${line}`);\n oldLineNum++;\n }\n }\n lastWasChange = true;\n } else {\n const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);\n\n if (lastWasChange || nextPartIsChange) {\n let linesToShow = raw;\n let skipStart = 0;\n let skipEnd = 0;\n\n if (!lastWasChange) {\n skipStart = Math.max(0, raw.length - contextLines);\n linesToShow = raw.slice(skipStart);\n }\n\n if (!nextPartIsChange && linesToShow.length > contextLines) {\n skipEnd = linesToShow.length - contextLines;\n linesToShow = linesToShow.slice(0, contextLines);\n }\n\n if (skipStart > 0) {\n output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n }\n\n for (const line of linesToShow) {\n const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n output.push(` ${lineNum} ${line}`);\n oldLineNum++;\n newLineNum++;\n }\n\n if (skipEnd > 0) {\n output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n }\n\n oldLineNum += skipStart + skipEnd;\n newLineNum += skipStart + skipEnd;\n } else {\n oldLineNum += raw.length;\n newLineNum += raw.length;\n }\n\n lastWasChange = false;\n }\n }\n\n return output.join(\"\\n\");\n}\n\nconst editSchema = Type.Object({\n label: Type.String({\n description: \"Brief description of the edit you're making (shown to user)\",\n }),\n path: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n oldText: Type.String({ description: \"Exact text to find and replace (must match exactly)\" }),\n newText: Type.String({ description: \"New text to replace the old text with\" }),\n});\n\nexport function createEditTool(executor: Executor): AgentTool<typeof editSchema> {\n return {\n name: \"edit\",\n label: \"edit\",\n description:\n \"Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.\",\n parameters: editSchema,\n execute: async (\n _toolCallId: string,\n { path, oldText, newText }: { label: string; path: string; oldText: string; newText: string },\n signal?: AbortSignal,\n ) => {\n // Read the file\n const readResult = await executor.exec(`cat ${shellEscape(path)}`, { signal });\n if (readResult.code !== 0) {\n throw new Error(readResult.stderr || `File not found: ${path}`);\n }\n\n const content = readResult.stdout;\n\n // Check if old text exists\n if (!content.includes(oldText)) {\n throw new Error(\n `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\n );\n }\n\n // Count occurrences\n const occurrences = content.split(oldText).length - 1;\n\n if (occurrences > 1) {\n throw new Error(\n `Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\n );\n }\n\n // Perform replacement\n const index = content.indexOf(oldText);\n const newContent =\n content.substring(0, index) + newText + content.substring(index + oldText.length);\n\n if (content === newContent) {\n throw new Error(\n `No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`,\n );\n }\n\n // Write the file back\n const writeResult = await executor.exec(\n `printf '%s' ${shellEscape(newContent)} > ${shellEscape(path)}`,\n {\n signal,\n },\n );\n if (writeResult.code !== 0) {\n throw new Error(writeResult.stderr || `Failed to write file: ${path}`);\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully replaced text in ${path}. Changed ${oldText.length} characters to ${newText.length} characters.`,\n },\n ],\n details: { diff: generateDiffString(content, newContent) },\n };\n },\n };\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport * as Diff from \"diff\";\nimport type { Executor } from \"../sandbox/index.js\";\n\n/**\n * Generate a unified diff string with line numbers and context\n */\nfunction generateDiffString(oldContent: string, newContent: string, contextLines = 4): string {\n const parts = Diff.diffLines(oldContent, newContent);\n const output: string[] = [];\n\n const oldLines = oldContent.split(\"\\n\");\n const newLines = newContent.split(\"\\n\");\n const maxLineNum = Math.max(oldLines.length, newLines.length);\n const lineNumWidth = String(maxLineNum).length;\n\n let oldLineNum = 1;\n let newLineNum = 1;\n let lastWasChange = false;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n const raw = part.value.split(\"\\n\");\n if (raw[raw.length - 1] === \"\") {\n raw.pop();\n }\n\n if (part.added || part.removed) {\n for (const line of raw) {\n if (part.added) {\n const lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\n output.push(`+${lineNum} ${line}`);\n newLineNum++;\n } else {\n const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n output.push(`-${lineNum} ${line}`);\n oldLineNum++;\n }\n }\n lastWasChange = true;\n } else {\n const nextPart = parts[i + 1];\n const nextPartIsChange = nextPart !== undefined && (nextPart.added || nextPart.removed);\n\n if (lastWasChange || nextPartIsChange) {\n let linesToShow = raw;\n let skipStart = 0;\n let skipEnd = 0;\n\n if (!lastWasChange) {\n skipStart = Math.max(0, raw.length - contextLines);\n linesToShow = raw.slice(skipStart);\n }\n\n if (!nextPartIsChange && linesToShow.length > contextLines) {\n skipEnd = linesToShow.length - contextLines;\n linesToShow = linesToShow.slice(0, contextLines);\n }\n\n if (skipStart > 0) {\n output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n }\n\n for (const line of linesToShow) {\n const lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n output.push(` ${lineNum} ${line}`);\n oldLineNum++;\n newLineNum++;\n }\n\n if (skipEnd > 0) {\n output.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n }\n\n oldLineNum += skipStart + skipEnd;\n newLineNum += skipStart + skipEnd;\n } else {\n oldLineNum += raw.length;\n newLineNum += raw.length;\n }\n\n lastWasChange = false;\n }\n }\n\n return output.join(\"\\n\");\n}\n\nconst editSchema = Type.Object({\n label: Type.String({\n description: \"Brief description of the edit you're making (shown to user)\",\n }),\n path: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n oldText: Type.String({ description: \"Exact text to find and replace (must match exactly)\" }),\n newText: Type.String({ description: \"New text to replace the old text with\" }),\n});\n\nexport function createEditTool(executor: Executor): AgentTool<typeof editSchema> {\n return {\n name: \"edit\",\n label: \"edit\",\n executionMode: \"sequential\",\n description:\n \"Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.\",\n parameters: editSchema,\n execute: async (\n _toolCallId: string,\n { path, oldText, newText }: { label: string; path: string; oldText: string; newText: string },\n signal?: AbortSignal,\n ) => {\n let content: string;\n try {\n content = await executor.readFile(path, { signal });\n } catch (err) {\n throw new Error(\n err instanceof Error && err.message ? err.message : `File not found: ${path}`,\n {\n cause: err,\n },\n );\n }\n\n // Check if old text exists\n if (!content.includes(oldText)) {\n throw new Error(\n `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\n );\n }\n\n // Count occurrences\n const occurrences = content.split(oldText).length - 1;\n\n if (occurrences > 1) {\n throw new Error(\n `Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\n );\n }\n\n // Perform replacement\n const index = content.indexOf(oldText);\n const newContent =\n content.substring(0, index) + newText + content.substring(index + oldText.length);\n\n if (content === newContent) {\n throw new Error(\n `No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`,\n );\n }\n\n // Write the file back\n await executor.writeFile(path, newContent, { signal });\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully replaced text in ${path}. Changed ${oldText.length} characters to ${newText.length} characters.`,\n },\n ],\n details: { diff: generateDiffString(content, newContent) },\n };\n },\n };\n}\n"]}
@@ -30,7 +30,7 @@ export declare class HostEventStore implements EventStore {
30
30
  }>;
31
31
  list(): Promise<Array<{
32
32
  filename: string;
33
- payload: EventPayload;
33
+ payload: EventPayload | null;
34
34
  size: number;
35
35
  mtimeMs: number;
36
36
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/tools/event.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItD,QAAA,MAAM,WAAW;;;;;;;;;;;EA0Df,CAAC;AAEH,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAeD,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,qBAAa,cAAe,YAAW,UAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAtC,YAA6B,SAAS,EAAE,MAAM,EAAI;IAElD,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,CAE5D;IAEK,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAE5F;IAEK,IAAI,IAAI,OAAO,CACnB,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAClF,CASA;IAEK,IAAI,CACR,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAWrF;IAEK,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAE7F;IAEK,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAI5D;YAEa,YAAY;CAe3B;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG;IACvD,IAAI,EAAE,SAAS,CAAC,OAAO,WAAW,CAAC,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACtD,CAuGA"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/tools/event.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKtD,QAAA,MAAM,WAAW;;;;;;;;;;;EAwDf,CAAC;AAEH,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAeD,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,qBAAa,cAAe,YAAW,UAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAtC,YAA6B,SAAS,EAAE,MAAM,EAAI;IAElD,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,CAE5D;IAEK,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAE5F;IAEK,IAAI,IAAI,OAAO,CACnB,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CACzF,CA6BA;IAEK,IAAI,CACR,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAcrF;IAEK,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAE7F;IAEK,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAI5D;YAEa,YAAY;CAe3B;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG;IACvD,IAAI,EAAE,SAAS,CAAC,OAAO,WAAW,CAAC,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACtD,CA6GA"}
@@ -1,8 +1,9 @@
1
1
  import { mkdir, readdir, readFile, rm, stat } from "node:fs/promises";
2
2
  import { basename, join } from "node:path";
3
3
  import { Type } from "@sinclair/typebox";
4
+ import { buildEventPayload, EventTypeSchema, parseEventPayload } from "../harness/event-format.js";
4
5
  import * as log from "../log.js";
5
- import { atomicWritePrivateFile } from "../utils/fs-atomic.js";
6
+ import { atomicWritePrivateFile } from "../utils/file-guards.js";
6
7
  const eventSchema = Type.Object({
7
8
  action: Type.Optional(Type.Union([
8
9
  Type.Literal("create"),
@@ -20,7 +21,7 @@ const eventSchema = Type.Object({
20
21
  label: Type.Optional(Type.String({
21
22
  description: "Brief description of the event you're scheduling (shown to user)",
22
23
  })),
23
- type: Type.Optional(Type.Union([Type.Literal("immediate"), Type.Literal("one-shot"), Type.Literal("periodic")])),
24
+ type: Type.Optional(EventTypeSchema),
24
25
  text: Type.Optional(Type.String({
25
26
  description: "A self-contained task for the future run. Include the necessary context, tone, and constraints in the text itself because events do not inherit normal conversation history.",
26
27
  })),
@@ -52,17 +53,42 @@ export class HostEventStore {
52
53
  const entries = await readdir(this.eventsDir, { withFileTypes: true });
53
54
  const events = await Promise.all(entries
54
55
  .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
55
- .map(async (entry) => this.read(entry.name)));
56
- return events.toSorted((a, b) => a.filename.localeCompare(b.filename));
56
+ .map(async (entry) => {
57
+ try {
58
+ return await this.read(entry.name);
59
+ }
60
+ catch {
61
+ // Keep unparseable files visible (payload: null) so consumers can
62
+ // surface and delete them; skip files that vanished mid-listing.
63
+ try {
64
+ const fileStat = await stat(join(this.eventsDir, entry.name));
65
+ return {
66
+ filename: entry.name,
67
+ payload: null,
68
+ size: fileStat.size,
69
+ mtimeMs: fileStat.mtimeMs,
70
+ };
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ }));
77
+ return events
78
+ .filter((event) => event !== null)
79
+ .toSorted((a, b) => a.filename.localeCompare(b.filename));
57
80
  }
58
81
  async read(filename) {
59
82
  const safeFilename = validateEventFilename(filename);
60
83
  const filePath = join(this.eventsDir, safeFilename);
61
84
  const [raw, fileStat] = await Promise.all([readFile(filePath, "utf-8"), stat(filePath)]);
62
- const parsed = JSON.parse(raw);
85
+ // Validation (shape, per-type fields, channelId alias) is owned by the
86
+ // event-format module; files that fail it surface as payload:null in
87
+ // list() and as errors here.
88
+ const payload = parseEventPayload(raw, safeFilename);
63
89
  return {
64
90
  filename: safeFilename,
65
- payload: parsed,
91
+ payload,
66
92
  size: fileStat.size,
67
93
  mtimeMs: fileStat.mtimeMs,
68
94
  };
@@ -104,10 +130,13 @@ export function createEventTool(eventStore) {
104
130
  const action = params.action ?? "create";
105
131
  if (action === "list") {
106
132
  const events = await eventStore.list();
107
- const conversationId = eventContext.conversationId;
133
+ const { conversationId, platform } = eventContext;
108
134
  const scopedEvents = params.scope === "all"
109
135
  ? events
110
- : events.filter((event) => event.payload.conversationId === conversationId);
136
+ : events.filter((event) => event.payload?.conversationId === conversationId &&
137
+ // Same raw id on another platform is another office. Files
138
+ // written before payloads carried a platform stay visible.
139
+ (event.payload.platform === undefined || event.payload.platform === platform));
111
140
  return {
112
141
  content: [
113
142
  {
@@ -138,7 +167,7 @@ export function createEventTool(eventStore) {
138
167
  details: undefined,
139
168
  };
140
169
  }
141
- const payload = buildEventPayload(params, eventContext);
170
+ const payload = buildToolEventPayload(params, eventContext);
142
171
  const filename = action === "update"
143
172
  ? requireFilename(params)
144
173
  : `${sanitizeFileSegment(params.filenamePrefix || payload.type || "event")}-${Date.now()}.json`;
@@ -166,63 +195,47 @@ export function createEventTool(eventStore) {
166
195
  },
167
196
  };
168
197
  }
169
- function buildEventPayload(params, context) {
198
+ function buildToolEventPayload(params, context) {
170
199
  if (!params.type) {
171
200
  throw new Error("`type` is required for create and update actions");
172
201
  }
173
202
  if (!params.text) {
174
203
  throw new Error("`text` is required for create and update actions");
175
204
  }
176
- const base = {
205
+ // Per-type field rules live in the event-format module. No sessionKey or
206
+ // threadTs in the payload: reminders should fire as top-level messages,
207
+ // not buried in old threads.
208
+ const payload = buildEventPayload({
209
+ type: params.type,
177
210
  platform: context.platform,
178
211
  conversationId: context.conversationId,
179
212
  conversationKind: context.conversationKind,
180
213
  userId: context.userId,
181
214
  text: params.text,
182
- };
183
- if (params.type === "immediate") {
184
- return {
185
- ...base,
186
- type: "immediate",
187
- };
188
- }
189
- if (params.type === "one-shot") {
190
- if (!params.at) {
191
- throw new Error("`at` is required for one-shot events");
192
- }
193
- const atTime = new Date(params.at).getTime();
194
- if (Number.isNaN(atTime)) {
195
- throw new Error("`at` must be a valid ISO 8601 timestamp with UTC offset");
196
- }
197
- if (atTime <= Date.now()) {
198
- throw new Error(`\`at\` must be in the future; got ${params.at} (now=${new Date().toISOString()}). Check the timezone offset.`);
199
- }
200
- // No sessionKey or threadTs: reminders should fire as top-level messages, not buried in old threads
201
- return { ...base, type: "one-shot", at: params.at };
202
- }
203
- if (!params.schedule) {
204
- throw new Error("`schedule` is required for periodic events");
205
- }
206
- if (!params.timezone) {
207
- throw new Error("`timezone` is required for periodic events");
208
- }
209
- return {
210
- ...base,
211
- type: "periodic",
215
+ at: params.at,
212
216
  schedule: params.schedule,
213
217
  timezone: params.timezone,
214
- };
218
+ });
219
+ // Tool-side write policy, not format knowledge: a reminder in the past
220
+ // would be deleted unfired by the watcher, so reject it here.
221
+ if (payload.type === "one-shot" && new Date(payload.at).getTime() <= Date.now()) {
222
+ throw new Error(`\`at\` must be in the future; got ${payload.at} (now=${new Date().toISOString()}). Check the timezone offset.`);
223
+ }
224
+ return payload;
215
225
  }
216
226
  function formatEventWriteResult(action, filename, payload) {
217
227
  const scheduledVerb = action === "update" ? "Updated" : "Scheduled";
218
228
  const immediateVerb = action === "update" ? "Updated" : "Queued";
229
+ const target = payload.platform
230
+ ? `${payload.platform}/${payload.conversationId}`
231
+ : payload.conversationId;
219
232
  switch (payload.type) {
220
233
  case "periodic":
221
- return `${scheduledVerb} periodic event ${filename} for ${payload.platform}/${payload.conversationId} (${payload.schedule} ${payload.timezone})`;
234
+ return `${scheduledVerb} periodic event ${filename} for ${target} (${payload.schedule} ${payload.timezone})`;
222
235
  case "one-shot":
223
- return `${scheduledVerb} one-shot event ${filename} for ${payload.platform}/${payload.conversationId} at ${payload.at}`;
236
+ return `${scheduledVerb} one-shot event ${filename} for ${target} at ${payload.at}`;
224
237
  case "immediate":
225
- return `${immediateVerb} immediate event ${filename} for ${payload.platform}/${payload.conversationId}`;
238
+ return `${immediateVerb} immediate event ${filename} for ${target}`;
226
239
  }
227
240
  }
228
241
  function requireFilename(params) {
@@ -1 +1 @@
1
- {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/tools/event.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { ConversationKind } from \"../adapter.js\";\nimport * as log from \"../log.js\";\nimport { atomicWritePrivateFile } from \"../utils/fs-atomic.js\";\n\nconst eventSchema = Type.Object({\n action: Type.Optional(\n Type.Union(\n [\n Type.Literal(\"create\"),\n Type.Literal(\"list\"),\n Type.Literal(\"read\"),\n Type.Literal(\"update\"),\n Type.Literal(\"delete\"),\n ],\n { description: \"CRUD action. Defaults to create for backward compatibility.\" },\n ),\n ),\n filename: Type.Optional(\n Type.String({\n description: \"Event filename for read, update, or delete actions\",\n }),\n ),\n scope: Type.Optional(\n Type.Union([Type.Literal(\"conversation\"), Type.Literal(\"all\")], {\n description:\n \"List scope. Defaults to conversation, which only shows events for the current conversation. Use all only when the user explicitly asks for all events.\",\n }),\n ),\n label: Type.Optional(\n Type.String({\n description: \"Brief description of the event you're scheduling (shown to user)\",\n }),\n ),\n type: Type.Optional(\n Type.Union([Type.Literal(\"immediate\"), Type.Literal(\"one-shot\"), Type.Literal(\"periodic\")]),\n ),\n text: Type.Optional(\n Type.String({\n description:\n \"A self-contained task for the future run. Include the necessary context, tone, and constraints in the text itself because events do not inherit normal conversation history.\",\n }),\n ),\n at: Type.Optional(\n Type.String({\n description: \"ISO 8601 timestamp with offset, required for one-shot events\",\n }),\n ),\n schedule: Type.Optional(\n Type.String({\n description: \"Cron schedule, required for periodic events\",\n }),\n ),\n timezone: Type.Optional(\n Type.String({\n description: \"IANA timezone, required for periodic events\",\n }),\n ),\n filenamePrefix: Type.Optional(\n Type.String({\n description: \"Optional filename prefix for the event file\",\n }),\n ),\n});\n\ninterface EventToolContext {\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n userId: string;\n}\n\ntype EventToolParams = {\n action?: \"create\" | \"list\" | \"read\" | \"update\" | \"delete\";\n filename?: string;\n scope?: \"conversation\" | \"all\";\n label?: string;\n type?: \"immediate\" | \"one-shot\" | \"periodic\";\n text?: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n filenamePrefix?: string;\n};\n\nexport type { EventPayload, EventStore } from \"./types.js\";\nimport type { EventPayload, EventStore } from \"./types.js\";\n\nexport class HostEventStore implements EventStore {\n constructor(private readonly eventsDir: string) {}\n\n static fromWorkspaceDir(workspaceDir: string): HostEventStore {\n return new HostEventStore(join(workspaceDir, \"events\"));\n }\n\n async write(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n return this.writePayload(filename, payload);\n }\n\n async list(): Promise<\n Array<{ filename: string; payload: EventPayload; size: number; mtimeMs: number }>\n > {\n await mkdir(this.eventsDir, { recursive: true });\n const entries = await readdir(this.eventsDir, { withFileTypes: true });\n const events = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".json\"))\n .map(async (entry) => this.read(entry.name)),\n );\n return events.toSorted((a, b) => a.filename.localeCompare(b.filename));\n }\n\n async read(\n filename: string,\n ): Promise<{ filename: string; payload: EventPayload; size: number; mtimeMs: number }> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n const [raw, fileStat] = await Promise.all([readFile(filePath, \"utf-8\"), stat(filePath)]);\n const parsed = JSON.parse(raw) as EventPayload;\n return {\n filename: safeFilename,\n payload: parsed,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n }\n\n async update(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n return this.writePayload(filename, payload, true);\n }\n\n async delete(filename: string): Promise<{ deleted: boolean }> {\n const safeFilename = validateEventFilename(filename);\n await rm(join(this.eventsDir, safeFilename), { force: true });\n return { deleted: true };\n }\n\n private async writePayload(\n filename: string,\n payload: EventPayload,\n requireExisting = false,\n ): Promise<{ path: string; size: number }> {\n await mkdir(this.eventsDir, { recursive: true });\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (requireExisting) {\n await stat(filePath);\n }\n atomicWritePrivateFile(filePath, JSON.stringify(payload) + \"\\n\");\n const fileStat = await stat(filePath);\n return { path: filePath, size: fileStat.size };\n }\n}\n\nexport function createEventTool(eventStore: EventStore): {\n tool: AgentTool<typeof eventSchema>;\n setEventContext: (context: EventToolContext) => void;\n} {\n let eventContext: EventToolContext | null = null;\n\n const tool: AgentTool<typeof eventSchema> = {\n name: \"event\",\n label: \"event\",\n description:\n \"CRUD tool for scheduled events. Create immediate, one-shot, or periodic events for the current conversation. List defaults to events for the current conversation only; use scope=all only when the user explicitly asks to list all events. Event text must be self-contained because events do not inherit normal conversation history.\",\n parameters: eventSchema,\n execute: async (_toolCallId: string, params: EventToolParams, signal?: AbortSignal) => {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (!eventContext) {\n throw new Error(\"Event context not configured\");\n }\n\n const action = params.action ?? \"create\";\n\n if (action === \"list\") {\n const events = await eventStore.list();\n const conversationId = eventContext.conversationId;\n const scopedEvents =\n params.scope === \"all\"\n ? events\n : events.filter((event) => event.payload.conversationId === conversationId);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n scope: params.scope ?? \"conversation\",\n conversationId: params.scope === \"all\" ? undefined : conversationId,\n events: scopedEvents,\n },\n null,\n 2,\n ),\n },\n ],\n details: undefined,\n };\n }\n\n if (action === \"read\") {\n const filename = requireFilename(params);\n const event = await eventStore.read(filename);\n return {\n content: [{ type: \"text\", text: JSON.stringify(event, null, 2) }],\n details: undefined,\n };\n }\n\n if (action === \"delete\") {\n const filename = requireFilename(params);\n await eventStore.delete(filename);\n return {\n content: [{ type: \"text\", text: `Deleted event ${filename}` }],\n details: undefined,\n };\n }\n\n const payload = buildEventPayload(params, eventContext);\n const filename =\n action === \"update\"\n ? requireFilename(params)\n : `${sanitizeFileSegment(params.filenamePrefix || payload.type || \"event\")}-${Date.now()}.json`;\n\n log.logInfo(\n `${action === \"update\" ? \"Updating\" : \"Writing\"} event file via control plane store: ${filename} (type=${payload.type}, platform=${payload.platform}, conversation=${payload.conversationId})`,\n );\n\n try {\n const result =\n action === \"update\"\n ? await eventStore.update(filename, payload)\n : await eventStore.write(filename, payload);\n log.logInfo(\n `${action === \"update\" ? \"Updated\" : \"Wrote\"} event file via control plane store: ${result.path} (${result.size} bytes)`,\n );\n } catch (err) {\n log.logWarning(\n `Failed to ${action === \"update\" ? \"update\" : \"write\"} event file via control plane store: ${filename}`,\n String(err),\n );\n throw err;\n }\n\n return {\n content: [{ type: \"text\", text: formatEventWriteResult(action, filename, payload) }],\n details: undefined,\n };\n },\n };\n\n return {\n tool,\n setEventContext: (context: EventToolContext) => {\n eventContext = context;\n },\n };\n}\n\nfunction buildEventPayload(params: EventToolParams, context: EventToolContext): EventPayload {\n if (!params.type) {\n throw new Error(\"`type` is required for create and update actions\");\n }\n if (!params.text) {\n throw new Error(\"`text` is required for create and update actions\");\n }\n\n const base = {\n platform: context.platform,\n conversationId: context.conversationId,\n conversationKind: context.conversationKind,\n userId: context.userId,\n text: params.text,\n };\n\n if (params.type === \"immediate\") {\n return {\n ...base,\n type: \"immediate\",\n };\n }\n\n if (params.type === \"one-shot\") {\n if (!params.at) {\n throw new Error(\"`at` is required for one-shot events\");\n }\n\n const atTime = new Date(params.at).getTime();\n if (Number.isNaN(atTime)) {\n throw new Error(\"`at` must be a valid ISO 8601 timestamp with UTC offset\");\n }\n if (atTime <= Date.now()) {\n throw new Error(\n `\\`at\\` must be in the future; got ${params.at} (now=${new Date().toISOString()}). Check the timezone offset.`,\n );\n }\n\n // No sessionKey or threadTs: reminders should fire as top-level messages, not buried in old threads\n return { ...base, type: \"one-shot\", at: params.at };\n }\n\n if (!params.schedule) {\n throw new Error(\"`schedule` is required for periodic events\");\n }\n if (!params.timezone) {\n throw new Error(\"`timezone` is required for periodic events\");\n }\n return {\n ...base,\n type: \"periodic\",\n schedule: params.schedule,\n timezone: params.timezone,\n };\n}\n\nfunction formatEventWriteResult(\n action: \"create\" | \"update\",\n filename: string,\n payload: EventPayload,\n): string {\n const scheduledVerb = action === \"update\" ? \"Updated\" : \"Scheduled\";\n const immediateVerb = action === \"update\" ? \"Updated\" : \"Queued\";\n switch (payload.type) {\n case \"periodic\":\n return `${scheduledVerb} periodic event ${filename} for ${payload.platform}/${payload.conversationId} (${payload.schedule} ${payload.timezone})`;\n case \"one-shot\":\n return `${scheduledVerb} one-shot event ${filename} for ${payload.platform}/${payload.conversationId} at ${payload.at}`;\n case \"immediate\":\n return `${immediateVerb} immediate event ${filename} for ${payload.platform}/${payload.conversationId}`;\n }\n}\n\nfunction requireFilename(params: EventToolParams): string {\n if (!params.filename) {\n throw new Error(\"`filename` is required for read, update, and delete actions\");\n }\n return validateEventFilename(params.filename);\n}\n\nfunction validateEventFilename(filename: string): string {\n const trimmed = filename.trim();\n if (\n !trimmed ||\n trimmed !== basename(trimmed) ||\n trimmed.includes(\"..\") ||\n !trimmed.endsWith(\".json\")\n ) {\n throw new Error(\"Invalid event filename\");\n }\n return trimmed;\n}\n\nfunction sanitizeFileSegment(value: string): string {\n const sanitized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return sanitized || \"event\";\n}\n"]}
1
+ {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/tools/event.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { ConversationKind } from \"../adapter.js\";\nimport { buildEventPayload, EventTypeSchema, parseEventPayload } from \"../harness/event-format.js\";\nimport * as log from \"../log.js\";\nimport { atomicWritePrivateFile } from \"../utils/file-guards.js\";\n\nconst eventSchema = Type.Object({\n action: Type.Optional(\n Type.Union(\n [\n Type.Literal(\"create\"),\n Type.Literal(\"list\"),\n Type.Literal(\"read\"),\n Type.Literal(\"update\"),\n Type.Literal(\"delete\"),\n ],\n { description: \"CRUD action. Defaults to create for backward compatibility.\" },\n ),\n ),\n filename: Type.Optional(\n Type.String({\n description: \"Event filename for read, update, or delete actions\",\n }),\n ),\n scope: Type.Optional(\n Type.Union([Type.Literal(\"conversation\"), Type.Literal(\"all\")], {\n description:\n \"List scope. Defaults to conversation, which only shows events for the current conversation. Use all only when the user explicitly asks for all events.\",\n }),\n ),\n label: Type.Optional(\n Type.String({\n description: \"Brief description of the event you're scheduling (shown to user)\",\n }),\n ),\n type: Type.Optional(EventTypeSchema),\n text: Type.Optional(\n Type.String({\n description:\n \"A self-contained task for the future run. Include the necessary context, tone, and constraints in the text itself because events do not inherit normal conversation history.\",\n }),\n ),\n at: Type.Optional(\n Type.String({\n description: \"ISO 8601 timestamp with offset, required for one-shot events\",\n }),\n ),\n schedule: Type.Optional(\n Type.String({\n description: \"Cron schedule, required for periodic events\",\n }),\n ),\n timezone: Type.Optional(\n Type.String({\n description: \"IANA timezone, required for periodic events\",\n }),\n ),\n filenamePrefix: Type.Optional(\n Type.String({\n description: \"Optional filename prefix for the event file\",\n }),\n ),\n});\n\ninterface EventToolContext {\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n userId: string;\n}\n\ntype EventToolParams = {\n action?: \"create\" | \"list\" | \"read\" | \"update\" | \"delete\";\n filename?: string;\n scope?: \"conversation\" | \"all\";\n label?: string;\n type?: \"immediate\" | \"one-shot\" | \"periodic\";\n text?: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n filenamePrefix?: string;\n};\n\nexport type { EventPayload, EventStore } from \"./types.js\";\nimport type { EventPayload, EventStore } from \"./types.js\";\n\nexport class HostEventStore implements EventStore {\n constructor(private readonly eventsDir: string) {}\n\n static fromWorkspaceDir(workspaceDir: string): HostEventStore {\n return new HostEventStore(join(workspaceDir, \"events\"));\n }\n\n async write(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n return this.writePayload(filename, payload);\n }\n\n async list(): Promise<\n Array<{ filename: string; payload: EventPayload | null; size: number; mtimeMs: number }>\n > {\n await mkdir(this.eventsDir, { recursive: true });\n const entries = await readdir(this.eventsDir, { withFileTypes: true });\n const events = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".json\"))\n .map(async (entry) => {\n try {\n return await this.read(entry.name);\n } catch {\n // Keep unparseable files visible (payload: null) so consumers can\n // surface and delete them; skip files that vanished mid-listing.\n try {\n const fileStat = await stat(join(this.eventsDir, entry.name));\n return {\n filename: entry.name,\n payload: null,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n } catch {\n return null;\n }\n }\n }),\n );\n return events\n .filter((event) => event !== null)\n .toSorted((a, b) => a.filename.localeCompare(b.filename));\n }\n\n async read(\n filename: string,\n ): Promise<{ filename: string; payload: EventPayload; size: number; mtimeMs: number }> {\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n const [raw, fileStat] = await Promise.all([readFile(filePath, \"utf-8\"), stat(filePath)]);\n // Validation (shape, per-type fields, channelId alias) is owned by the\n // event-format module; files that fail it surface as payload:null in\n // list() and as errors here.\n const payload = parseEventPayload(raw, safeFilename);\n return {\n filename: safeFilename,\n payload,\n size: fileStat.size,\n mtimeMs: fileStat.mtimeMs,\n };\n }\n\n async update(filename: string, payload: EventPayload): Promise<{ path: string; size: number }> {\n return this.writePayload(filename, payload, true);\n }\n\n async delete(filename: string): Promise<{ deleted: boolean }> {\n const safeFilename = validateEventFilename(filename);\n await rm(join(this.eventsDir, safeFilename), { force: true });\n return { deleted: true };\n }\n\n private async writePayload(\n filename: string,\n payload: EventPayload,\n requireExisting = false,\n ): Promise<{ path: string; size: number }> {\n await mkdir(this.eventsDir, { recursive: true });\n const safeFilename = validateEventFilename(filename);\n const filePath = join(this.eventsDir, safeFilename);\n if (requireExisting) {\n await stat(filePath);\n }\n atomicWritePrivateFile(filePath, JSON.stringify(payload) + \"\\n\");\n const fileStat = await stat(filePath);\n return { path: filePath, size: fileStat.size };\n }\n}\n\nexport function createEventTool(eventStore: EventStore): {\n tool: AgentTool<typeof eventSchema>;\n setEventContext: (context: EventToolContext) => void;\n} {\n let eventContext: EventToolContext | null = null;\n\n const tool: AgentTool<typeof eventSchema> = {\n name: \"event\",\n label: \"event\",\n description:\n \"CRUD tool for scheduled events. Create immediate, one-shot, or periodic events for the current conversation. List defaults to events for the current conversation only; use scope=all only when the user explicitly asks to list all events. Event text must be self-contained because events do not inherit normal conversation history.\",\n parameters: eventSchema,\n execute: async (_toolCallId: string, params: EventToolParams, signal?: AbortSignal) => {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (!eventContext) {\n throw new Error(\"Event context not configured\");\n }\n\n const action = params.action ?? \"create\";\n\n if (action === \"list\") {\n const events = await eventStore.list();\n const { conversationId, platform } = eventContext;\n const scopedEvents =\n params.scope === \"all\"\n ? events\n : events.filter(\n (event) =>\n event.payload?.conversationId === conversationId &&\n // Same raw id on another platform is another office. Files\n // written before payloads carried a platform stay visible.\n (event.payload.platform === undefined || event.payload.platform === platform),\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n scope: params.scope ?? \"conversation\",\n conversationId: params.scope === \"all\" ? undefined : conversationId,\n events: scopedEvents,\n },\n null,\n 2,\n ),\n },\n ],\n details: undefined,\n };\n }\n\n if (action === \"read\") {\n const filename = requireFilename(params);\n const event = await eventStore.read(filename);\n return {\n content: [{ type: \"text\", text: JSON.stringify(event, null, 2) }],\n details: undefined,\n };\n }\n\n if (action === \"delete\") {\n const filename = requireFilename(params);\n await eventStore.delete(filename);\n return {\n content: [{ type: \"text\", text: `Deleted event ${filename}` }],\n details: undefined,\n };\n }\n\n const payload = buildToolEventPayload(params, eventContext);\n const filename =\n action === \"update\"\n ? requireFilename(params)\n : `${sanitizeFileSegment(params.filenamePrefix || payload.type || \"event\")}-${Date.now()}.json`;\n\n log.logInfo(\n `${action === \"update\" ? \"Updating\" : \"Writing\"} event file via control plane store: ${filename} (type=${payload.type}, platform=${payload.platform}, conversation=${payload.conversationId})`,\n );\n\n try {\n const result =\n action === \"update\"\n ? await eventStore.update(filename, payload)\n : await eventStore.write(filename, payload);\n log.logInfo(\n `${action === \"update\" ? \"Updated\" : \"Wrote\"} event file via control plane store: ${result.path} (${result.size} bytes)`,\n );\n } catch (err) {\n log.logWarning(\n `Failed to ${action === \"update\" ? \"update\" : \"write\"} event file via control plane store: ${filename}`,\n String(err),\n );\n throw err;\n }\n\n return {\n content: [{ type: \"text\", text: formatEventWriteResult(action, filename, payload) }],\n details: undefined,\n };\n },\n };\n\n return {\n tool,\n setEventContext: (context: EventToolContext) => {\n eventContext = context;\n },\n };\n}\n\nfunction buildToolEventPayload(params: EventToolParams, context: EventToolContext): EventPayload {\n if (!params.type) {\n throw new Error(\"`type` is required for create and update actions\");\n }\n if (!params.text) {\n throw new Error(\"`text` is required for create and update actions\");\n }\n\n // Per-type field rules live in the event-format module. No sessionKey or\n // threadTs in the payload: reminders should fire as top-level messages,\n // not buried in old threads.\n const payload = buildEventPayload({\n type: params.type,\n platform: context.platform,\n conversationId: context.conversationId,\n conversationKind: context.conversationKind,\n userId: context.userId,\n text: params.text,\n at: params.at,\n schedule: params.schedule,\n timezone: params.timezone,\n });\n\n // Tool-side write policy, not format knowledge: a reminder in the past\n // would be deleted unfired by the watcher, so reject it here.\n if (payload.type === \"one-shot\" && new Date(payload.at).getTime() <= Date.now()) {\n throw new Error(\n `\\`at\\` must be in the future; got ${payload.at} (now=${new Date().toISOString()}). Check the timezone offset.`,\n );\n }\n\n return payload;\n}\n\nfunction formatEventWriteResult(\n action: \"create\" | \"update\",\n filename: string,\n payload: EventPayload,\n): string {\n const scheduledVerb = action === \"update\" ? \"Updated\" : \"Scheduled\";\n const immediateVerb = action === \"update\" ? \"Updated\" : \"Queued\";\n const target = payload.platform\n ? `${payload.platform}/${payload.conversationId}`\n : payload.conversationId;\n switch (payload.type) {\n case \"periodic\":\n return `${scheduledVerb} periodic event ${filename} for ${target} (${payload.schedule} ${payload.timezone})`;\n case \"one-shot\":\n return `${scheduledVerb} one-shot event ${filename} for ${target} at ${payload.at}`;\n case \"immediate\":\n return `${immediateVerb} immediate event ${filename} for ${target}`;\n }\n}\n\nfunction requireFilename(params: EventToolParams): string {\n if (!params.filename) {\n throw new Error(\"`filename` is required for read, update, and delete actions\");\n }\n return validateEventFilename(params.filename);\n}\n\nfunction validateEventFilename(filename: string): string {\n const trimmed = filename.trim();\n if (\n !trimmed ||\n trimmed !== basename(trimmed) ||\n trimmed.includes(\"..\") ||\n !trimmed.endsWith(\".json\")\n ) {\n throw new Error(\"Invalid event filename\");\n }\n return trimmed;\n}\n\nfunction sanitizeFileSegment(value: string): string {\n const sanitized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return sanitized || \"event\";\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
+ import type { Api, Model } from "@earendil-works/pi-ai";
3
+ declare const schema: import("@sinclair/typebox").TObject<{
4
+ prompt: import("@sinclair/typebox").TString;
5
+ size: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
6
+ quality: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ }>;
8
+ export declare function createGenerateImageTool(options: {
9
+ model: Model<Api>;
10
+ getApiKey: () => Promise<string | undefined>;
11
+ /** Host directory the generated image is written into. Must be the
12
+ * conversation's own office dir so the agent can also reach the file
13
+ * from inside the sandbox; the workspace base is NOT guest-visible. */
14
+ outputDir: string;
15
+ }): {
16
+ tool: AgentTool<typeof schema>;
17
+ /** The callback receives the HOST path of the generated file. The image is
18
+ * written host-side, so upload must not stage it through the sandbox the
19
+ * way the attach tool does — the file may not be mounted there. */
20
+ setUploadFunction: (fn: (hostPath: string, title?: string) => Promise<void>) => void;
21
+ };
22
+ export {};
23
+ //# sourceMappingURL=generate-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.d.ts","sourceRoot":"","sources":["../../src/tools/generate-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAMxD,QAAA,MAAM,MAAM;;;;EAMV,CAAC;AAOH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C;;4EAEwE;IACxE,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG;IACF,IAAI,EAAE,SAAS,CAAC,OAAO,MAAM,CAAC,CAAC;IAC/B;;wEAEoE;IACpE,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;CACtF,CA6DA"}