@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
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport { execFile } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execFileAsync = promisify(execFile);\ntype ExecFileAsync = typeof execFileAsync;\n\n// ── adapter ───────────────────────────────────────────────────────────────────\n\nexport type ConversationKind = \"direct\" | \"shared\";\n\nexport type PlatformName = \"slack\" | \"discord\" | \"telegram\";\n\nexport interface ConversationMessage {\n id: string;\n sessionKey: string;\n conversationKind: ConversationKind;\n userId: string;\n userName?: string;\n text: string;\n attachments?: { name: string; localPath: string }[];\n threadTs?: string;\n}\n\nexport interface ChatToolResult {\n toolName: string;\n label?: string;\n args?: Record<string, unknown>;\n result: string;\n isError: boolean;\n durationMs: number;\n}\n\nexport interface ConversationResponder {\n respond(text: string): Promise<void>;\n appendResponseDelta?(delta: string): Promise<void>;\n finishResponse?(finalText?: string): Promise<void>;\n replaceResponse(text: string, options?: { createOverflowLink?: () => string }): Promise<void>;\n respondDiagnostic(text: string, options?: { style?: \"muted\" | \"error\" }): Promise<void>;\n respondToolResult(result: ChatToolResult): Promise<void>;\n setTyping(isTyping: boolean): Promise<void>;\n setWorking(working: boolean): Promise<void>;\n uploadFile(filePath: string, title?: string): Promise<void>;\n deleteResponse(): Promise<void>;\n}\n\nexport interface MessagingInfo {\n name: string;\n formattingGuide: string;\n channels: { id: string; name: string }[];\n users: { id: string; userName: string; displayName: string }[];\n diagnostics?: {\n showUsageSummary?: boolean;\n };\n}\n\nexport interface ChatAdapter {\n start(): Promise<void>;\n stop(): Promise<void>;\n getMessagingInfo(): MessagingInfo;\n}\n\nexport type AgentEventPayload =\n | { kind: \"sessionStart\" }\n | { kind: \"responseDelta\"; delta: string }\n | { kind: \"responseFinal\"; text: string }\n | { kind: \"diagnostic\"; text: string }\n | { kind: \"toolStart\"; toolId: string; toolName: string; input?: unknown }\n | { kind: \"toolEnd\"; toolId: string }\n | { kind: \"turnEnd\"; awaitingInput?: boolean }\n | { kind: \"sessionEnd\"; reason?: string };\n\nexport interface AgentEventEnvelope {\n source: \"mikan\";\n sessionId: string;\n actorName: string;\n event: AgentEventPayload;\n}\n\n/**\n * A platform-agnostic event (message/mention) that triggers the agent.\n */\nexport interface ConversationEvent {\n type: string;\n /** Platform-specific raw conversation/channel/chat identifier */\n conversationId: string;\n /** Optional alternate conversation identity used for vault routing. */\n vaultConversationId?: string;\n /** Cross-platform conversation shape: direct message vs shared space */\n conversationKind: ConversationKind;\n /** Message timestamp or ID as string */\n ts: string;\n /** Parent message ID for threaded replies (optional) */\n thread_ts?: string;\n /** User ID */\n user: string;\n /** Message text (already stripped of bot mentions) */\n text: string;\n /** Downloaded attachments */\n attachments?: { name: string; localPath: string }[];\n /** Platform-computed session key; overrides default conversationId:thread_ts computation */\n sessionKey?: string;\n}\n\n/**\n * Minimum interface that every platform bot must implement,\n * used by the central handler in main.ts and by EventsWatcher.\n */\nexport interface MessagingBot {\n start(): Promise<void>;\n postMessage(channel: string, text: string): Promise<string>;\n updateMessage(channel: string, ts: string, text: string): Promise<void>;\n enqueueEvent(event: ConversationEvent): boolean;\n getMessagingInfo(): MessagingInfo;\n postPrivate?(conversationId: string, userId: string, text: string): Promise<void>;\n postPrivateDiagnostic?(\n conversationId: string,\n userId: string,\n text: string,\n options?: { style?: \"muted\" | \"error\" },\n ): Promise<void>;\n}\n\n/**\n * Post a plain message to a conversation without triggering an agent run.\n * Backs extension `api.notify`; implemented in main.ts over the platform bots.\n * `platform` is required only when more than one platform is running.\n */\nexport type PlatformNotifier = (\n conversationId: string,\n text: string,\n platform?: string,\n) => Promise<void>;\n\n/** Normalized platform data and reply hook for one event. */\nexport interface ConversationContext {\n message: ConversationMessage;\n responder: ConversationResponder;\n platform: MessagingInfo;\n}\n\nexport interface RunningSession {\n sessionKey: string;\n startedAt: number;\n lastActivityAt?: number;\n currentTool?: string;\n}\n\nexport interface MessagingEventHandler {\n isRunning(sessionKey: string): boolean;\n getRunningSessions(): RunningSession[];\n handleEvent(\n event: ConversationEvent,\n bot: MessagingBot,\n context: ConversationContext,\n ): Promise<void>;\n handleStop(sessionKey: string, conversationId: string, bot: MessagingBot): Promise<void>;\n forceStop(sessionKey: string): void;\n handleNewCommand(sessionKey: string, conversationId: string, bot: MessagingBot): Promise<void>;\n}\n\n// ── agent ─────────────────────────────────────────────────────────────────────\n\nexport interface PiAgentWrapper {\n syncChatHistory(currentMessageId?: string): void;\n run(\n message: ConversationMessage,\n responder: ConversationResponder,\n platform: MessagingInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }>;\n abort(): void;\n getCurrentStep(): { toolName?: string; label?: string } | undefined;\n}\n\n// ── config ────────────────────────────────────────────────────────────────────\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel: ThinkingLevel;\n sentryDsn?: string;\n sandboxCpus?: string;\n sandboxMemory?: string;\n sandboxBoostCpus?: string;\n sandboxBoostMemory?: string;\n sandboxImageWorkspaceMount?: \"private\" | \"full\";\n defaultSharedVault?: string;\n slack?: {\n replyMode?: \"top-level\" | \"thread\";\n };\n}\n\n/**\n * @deprecated Auto-reply is kept for compatibility while its future is undecided.\n */\nexport interface AutoReplyConfig {\n enabled: boolean;\n rules: string[];\n}\n\nexport interface JudgeModelConfig {\n provider: string;\n model: string;\n}\n\n// ── context ───────────────────────────────────────────────────────────────────\n\n/**\n * Platform conversation history entry from log.jsonl.\n */\nexport interface ConversationLogMessage {\n date?: string;\n ts?: string;\n threadTs?: string;\n user?: string;\n userName?: string;\n text?: string;\n isMessagingBot?: boolean;\n}\n\n// ── events ────────────────────────────────────────────────────────────────────\n\nexport interface ImmediateEvent {\n type: \"immediate\";\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n userId?: string;\n text: string;\n}\n\nexport interface OneShotEvent {\n type: \"one-shot\";\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n userId?: string;\n text: string;\n at: string;\n}\n\nexport interface PeriodicEvent {\n type: \"periodic\";\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n userId?: string;\n text: string;\n schedule: string;\n timezone: string;\n}\n\nexport type MikanEvent = ImmediateEvent | OneShotEvent | PeriodicEvent;\n\nexport interface PeriodicEventInfo {\n filename: string;\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n text: string;\n schedule: string;\n timezone: string;\n nextRun: string | null;\n}\n\n// ── execution-resolver ────────────────────────────────────────────────────────\n\nexport interface ActorContext {\n platform: string;\n userId: string;\n conversationId: string;\n}\n\nexport type ImageWorkspaceMountMode = \"private\" | \"full\";\n\n// ── log ───────────────────────────────────────────────────────────────────────\n\nexport interface LogContext {\n conversationId: string;\n userName?: string;\n conversationName?: string;\n sessionId?: string;\n}\n\n// ── portal-shell ──────────────────────────────────────────────────────────────\n\ntype PortalView = \"admin\" | \"session\" | \"vault\";\n\nexport interface PortalShellOptions {\n activeView: PortalView;\n pageTitle: string;\n identity?: {\n primary: string;\n secondary?: string;\n };\n conversationSwitcher?: {\n currentId: string;\n options?: Array<{ id: string; label: string; running?: boolean }>;\n };\n navLinks?: Partial<Record<PortalView, string>>;\n body: string;\n extraStyles?: string;\n inlineScript?: string;\n extraHead?: string;\n bodyAttributes?: Record<string, string>;\n}\n\n// ── provisioner ───────────────────────────────────────────────────────────────\n\nexport interface ContainerMount {\n source: string;\n target: string;\n}\n\nexport interface ResourceLimits {\n cpus?: string;\n memory?: string;\n}\n\nexport interface SandboxLimitStatus {\n limits?: ResourceLimits;\n boosted: boolean;\n}\n\nexport interface ProvisionOptions {\n containerName?: string;\n mounts?: ContainerMount[];\n conversationId?: string;\n}\n\nexport interface DockerContainerManagerOptions {\n limits?: ResourceLimits;\n boostLimits?: ResourceLimits;\n execFileImpl?: ExecFileAsync;\n}\n\n// ── store ─────────────────────────────────────────────────────────────────────\n\nexport interface Attachment {\n original: string;\n localPath: string;\n}\n\nexport interface LoggedMessage {\n date: string;\n ts: string;\n user: string;\n userName?: string;\n displayName?: string;\n text: string;\n attachments: Attachment[];\n isMessagingBot: boolean;\n threadTs?: string;\n}\n\nexport interface ChannelStoreConfig {\n workingDir: string;\n botToken: string;\n}\n\n// ── trigger ───────────────────────────────────────────────────────────────────\n\nexport type TriggerIntent = \"mention\" | \"direct\" | \"thread-continuation\" | \"auto-reply-candidate\";\n\nexport type TriggerResult = { trigger: true; reason: string } | { trigger: false; reason: string };\n\n/**\n * @deprecated Auto-reply is kept for compatibility while its future is undecided.\n */\nexport type AutoReplyJudge = (input: {\n event: ConversationEvent;\n rules: string[];\n conversationDir: string;\n}) => Promise<boolean>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAsBtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type {\n ImmediateEventPayload,\n OneShotEventPayload,\n PeriodicEventPayload,\n} from \"./harness/event-format.js\";\nimport type {\n ExtensionBlockAction,\n ExtensionScheduleCallbackEvent,\n ExtensionScheduleCallbackFire,\n ExtensionScheduleEngine,\n} from \"./harness/extensions/types.js\";\nimport type { SubagentRunStatus } from \"./harness/types.js\";\nimport type { SessionViewTokenStoreLike } from \"./commands/types.js\";\nimport type { MikanModels } from \"./harness/models.js\";\nimport type { Office } from \"./office/types.js\";\nimport type { DockerContainerManager } from \"./provisioner.js\";\nimport type { SandboxConfig } from \"./sandbox/types.js\";\nimport type { ResolvedSessionScope } from \"./sessions/types.js\";\nimport type { PlatformToolPackFactory } from \"./tools/types.js\";\nimport type { VaultManager } from \"./vault/types.js\";\n\nconst execFileAsync = promisify(execFile);\ntype ExecFileAsync = typeof execFileAsync;\n\n// ── adapter ───────────────────────────────────────────────────────────────────\n\nexport type ConversationKind = \"direct\" | \"shared\";\n\nexport type PlatformName = \"slack\" | \"discord\" | \"telegram\" | \"github\";\n\n/** Canonical platform-plus-raw identifier for one conversation office. */\nexport interface OfficeAddress {\n readonly platform: PlatformName;\n readonly conversationId: string;\n}\n\n/** Stable, filesystem-safe identity derived from an OfficeAddress. */\nexport type OfficeKey = string & { readonly __brand: \"OfficeKey\" };\n\nexport type OfficeMigrationStatus = \"needs-owner\" | \"prepared\" | \"moving\" | \"committed\" | \"failed\";\n\nexport interface OfficeMigrationRecord {\n readonly rawConversationId: string;\n readonly sourceDir: string;\n readonly workspaceRoot: string;\n readonly ownerPlatform?: PlatformName;\n readonly targetDir?: string;\n readonly status: OfficeMigrationStatus;\n readonly error?: string;\n readonly updatedAt: string;\n}\n\n/**\n * Directory entry for one conversation office. The workspace dir name stops\n * carrying the raw platform id once the ADR 0005 layout migration lands, so\n * the registry is the durable raw-id ↔ office mapping used for enumeration.\n */\nexport interface OfficeRecord {\n readonly platform: PlatformName;\n readonly conversationId: string;\n readonly recordedAt: string;\n}\n\nexport interface OfficeRegistryState {\n readonly version: 1;\n readonly enabledPlatforms: readonly PlatformName[];\n readonly offices: readonly OfficeRecord[];\n readonly migrations: readonly OfficeMigrationRecord[];\n}\n\nexport interface OfficeMigrationPreparation {\n readonly rawConversationId: string;\n readonly sourceDir: string;\n readonly workspaceRoot: string;\n readonly ownerPlatform?: PlatformName;\n}\n\n/**\n * Who can drive conversations on a platform — gates ambient credential policy.\n *\n * - `membership`: only invited workspace/server members (Slack/Discord/Telegram).\n * Safe to copy `sandbox.defaultSharedVault` into new conversation vaults.\n * - `open-trigger`: broader trigger surface (e.g. GitHub repo writers on public\n * issues/PRs). Ambient shared vault must not apply; use host-side platform\n * identity or an explicitly provisioned vault.\n */\nexport type PlatformTrustModel = \"membership\" | \"open-trigger\";\n\nexport interface ConversationMessage {\n id: string;\n /** Canonical identity of the conversation office. */\n address: OfficeAddress;\n /** @deprecated Use address.conversationId except at platform I/O seams. */\n conversationId?: string;\n sessionKey: string;\n conversationKind: ConversationKind;\n userId: string;\n userName?: string;\n text: string;\n attachments?: { name: string; localPath: string }[];\n threadTs?: string;\n}\n\nexport interface ChatToolResult {\n toolName: string;\n label?: string;\n args?: Record<string, unknown>;\n result: string;\n isError: boolean;\n durationMs: number;\n}\n\n/**\n * Derived from the run status rather than restated, so a new terminal status\n * in the harness reaches the dashboard instead of silently rendering as a\n * status the marker tables never learned about.\n */\nexport type SubagentProgressStatus = SubagentRunStatus | \"pending\" | \"running\" | \"skipped\";\n\nexport interface SubagentProgressNode {\n id: string;\n label: string;\n status: SubagentProgressStatus;\n /** Profile the node ran under; the first thing to check when a run is ungrounded. */\n profile?: string;\n turns?: number;\n toolCalls?: number;\n toolCallCounts?: Record<string, number>;\n tokens?: number;\n costUsd?: number;\n durationMs?: number;\n /**\n * What the node is doing right now, for running nodes only.\n *\n * Without it a node reports nothing between \"started\" and \"finished\", so a\n * step that legitimately takes minutes is indistinguishable from a hang —\n * and when it does finish, there is no record of how it got there.\n */\n activity?: string;\n reason?: string;\n cleanupPending?: boolean;\n}\n\nexport interface SubagentProgressSnapshot {\n mode: \"single\" | \"parallel\" | \"dag\";\n nodes: SubagentProgressNode[];\n}\n\nexport interface ConversationResponder {\n respond(text: string): Promise<void>;\n appendResponseDelta?(delta: string): Promise<void>;\n finishResponse?(finalText?: string): Promise<void>;\n replaceResponse(text: string, options?: { createOverflowLink?: () => string }): Promise<void>;\n /**\n * Override only to convert the subagent dashboard for a pipeline that is\n * not response-source Markdown (Telegram HTML). Absent, the harness composes\n * the Markdown dashboard — optionally followed by the final answer — through\n * `replaceResponse`.\n */\n replaceSubagentProgress?(progress: SubagentProgressSnapshot, finalText?: string): Promise<void>;\n respondDiagnostic(text: string, options?: { style?: \"muted\" | \"error\" }): Promise<void>;\n respondToolResult(result: ChatToolResult): Promise<void>;\n setTyping(isTyping: boolean): Promise<void>;\n setWorking(working: boolean): Promise<void>;\n uploadFile(filePath: string, title?: string): Promise<void>;\n /**\n * React to the message that triggered this run with an emoji short name\n * (no colons). Optional: platforms/contexts without reaction support omit\n * it, and callers must handle its absence.\n */\n react?(emoji: string): Promise<void>;\n deleteResponse(): Promise<void>;\n}\n\nexport interface MessagingInfo {\n name: string;\n formattingGuide: string;\n channels: { id: string; name: string }[];\n users: { id: string; userName: string; displayName: string }[];\n /**\n * Trust boundary for ambient credentials. Defaults to `membership` when\n * omitted (closed chat platforms). Open-trigger platforms must set this\n * explicitly so vault policy does not key off platform name strings.\n */\n trustModel?: PlatformTrustModel;\n diagnostics?: {\n showUsageSummary?: boolean;\n };\n}\n\nexport interface ChatAdapter {\n start(): Promise<void>;\n stop(): Promise<void>;\n getMessagingInfo(): MessagingInfo;\n}\n\nexport type AgentEventPayload =\n | { kind: \"sessionStart\" }\n | { kind: \"responseDelta\"; delta: string }\n | { kind: \"responseFinal\"; text: string }\n | { kind: \"diagnostic\"; text: string }\n | { kind: \"toolStart\"; toolId: string; toolName: string; input?: unknown }\n | { kind: \"toolEnd\"; toolId: string }\n | { kind: \"turnEnd\"; awaitingInput?: boolean }\n | { kind: \"sessionEnd\"; reason?: string };\n\nexport interface AgentEventEnvelope {\n source: \"mikan\";\n sessionId: string;\n actorName: string;\n event: AgentEventPayload;\n}\n\n/**\n * A platform-agnostic event (message/mention) that triggers the agent.\n */\nexport interface ConversationEvent {\n type: string;\n /** Canonical identity created by the platform adapter at intake. */\n address: OfficeAddress;\n /** @deprecated Raw platform identifier; valid only at adapter I/O seams. */\n conversationId: string;\n /** Optional alternate conversation identity used for vault routing. */\n vaultConversationId?: string;\n /** Cross-platform conversation shape: direct message vs shared space */\n conversationKind: ConversationKind;\n /** Message timestamp or ID as string */\n ts: string;\n /** Parent message ID for threaded replies (optional) */\n thread_ts?: string;\n /** User ID */\n user: string;\n /** Message text (already stripped of bot mentions) */\n text: string;\n /** Downloaded attachments */\n attachments?: { name: string; localPath: string }[];\n /** Platform-computed session key; overrides default conversationId:thread_ts computation */\n sessionKey?: string;\n}\n\n/**\n * Minimum interface that every platform bot must implement,\n * used by the central handler in main.ts and by EventsWatcher.\n */\nexport interface MessagingBot {\n start(): Promise<void>;\n postMessage(channel: string, text: string): Promise<string>;\n updateMessage(channel: string, ts: string, text: string): Promise<void>;\n /**\n * Add an emoji reaction to a message. `emoji` is a platform-agnostic short\n * name without colons (e.g. \"eyes\", \"white_check_mark\"). Optional so\n * adapters adopt it incrementally; callers must handle its absence.\n */\n addReaction?(channel: string, messageTs: string, emoji: string): Promise<void>;\n /**\n * Upload a host-side file into a conversation. Optional so adapters adopt\n * it incrementally; callers must handle its absence. Existing adapter\n * implementations (Slack/Discord/Telegram) already match this shape.\n */\n uploadFile?(channel: string, filePath: string, title?: string): Promise<void>;\n /**\n * Post into a platform thread. Optional so adapters adopt it incrementally;\n * callers must handle its absence.\n */\n postInThread?(channel: string, threadTs: string, text: string): Promise<string>;\n /**\n * Open (or resolve) the direct-message conversation with a user, returning\n * its conversation id — usable with `postMessage`. Optional capability.\n */\n openDirectConversation?(userId: string): Promise<string>;\n /**\n * Fetch recent messages from a conversation, oldest first. Optional\n * capability; adapters may cap `limit` below what the caller asks for.\n */\n fetchHistory?(\n channel: string,\n options?: PlatformHistoryOptions,\n ): Promise<PlatformHistoryMessage[]>;\n /** List the platform workspace's active users. Optional capability. */\n listUsers?(): Promise<PlatformUserInfo[]>;\n enqueueEvent(event: ConversationEvent): boolean;\n getMessagingInfo(): MessagingInfo;\n postPrivate?(conversationId: string, userId: string, text: string): Promise<void>;\n postPrivateDiagnostic?(\n conversationId: string,\n userId: string,\n text: string,\n options?: { style?: \"muted\" | \"error\" },\n ): Promise<void>;\n}\n\n/** Filters for a platform conversation-history fetch. */\nexport interface PlatformHistoryOptions {\n /** Only messages strictly newer than this platform message id/timestamp. */\n oldest?: string;\n /** Maximum number of messages to return (adapters may cap this lower). */\n limit?: number;\n /**\n * Read the replies inside this thread instead of the conversation's\n * top-level messages. The thread parent itself is not returned — the result\n * is the replies to it. Adapters without threads ignore this.\n */\n threadTs?: string;\n}\n\n/** One platform message returned by a history fetch. */\nexport interface PlatformHistoryMessage {\n ts: string;\n threadTs?: string;\n userId?: string;\n userName?: string;\n text: string;\n isBot: boolean;\n}\n\n/** One platform user returned by a workspace user listing. */\nexport interface PlatformUserInfo {\n id: string;\n userName: string;\n displayName: string;\n isBot: boolean;\n}\n\n/**\n * Post a plain message to a conversation without triggering an agent run,\n * resolving to the platform message id of what was posted. Backs extension\n * `api.notify`; implemented in main.ts over the platform bots. `platform` is\n * required only when more than one platform is running; `threadTs` targets a\n * platform thread on adapters that support it.\n */\nexport type PlatformNotifier = (\n conversationId: string,\n text: string,\n options?: { platform?: string; threadTs?: string },\n) => Promise<string>;\n\n/**\n * Open the direct-message conversation with a platform user, returning its\n * conversation id. Backs extension `api.openDm`; implemented in main.ts over\n * the platform bots.\n */\nexport type PlatformDmOpener = (userId: string, platform?: string) => Promise<string>;\n\n/**\n * Fetch recent messages from a conversation without triggering an agent run.\n * Backs extension `api.fetchHistory`; implemented in main.ts over the\n * platform bots.\n */\nexport type PlatformHistoryFetcher = (\n conversationId: string,\n options?: PlatformHistoryOptions & { platform?: string },\n) => Promise<PlatformHistoryMessage[]>;\n\n/**\n * List a platform workspace's active users. Backs extension `api.listUsers`;\n * implemented in main.ts over the platform bots.\n */\nexport type PlatformUserLister = (platform?: string) => Promise<PlatformUserInfo[]>;\n\n/**\n * Add an emoji reaction to a message without triggering an agent run. Backs\n * extension `api.react`; implemented in main.ts over the platform bots.\n */\nexport type PlatformReactor = (\n conversationId: string,\n messageTs: string,\n emoji: string,\n platform?: string,\n) => Promise<void>;\n\n/**\n * Upload a host-side file into a conversation without triggering an agent\n * run. Backs extension `api.uploadFile`; implemented in main.ts over the\n * platform bots. `platform` is required only when more than one is running.\n */\nexport type PlatformUploader = (\n conversationId: string,\n filePath: string,\n title?: string,\n platform?: string,\n) => Promise<void>;\n\n/**\n * Post and update interactive Block Kit messages without triggering an agent\n * run. Backs extension `api.blockkit`; implemented in main.ts over the\n * platform bots (Slack-only today — other platforms throw).\n */\nexport interface PlatformBlockKit {\n postBlocks(\n conversationId: string,\n message: { text: string; blocks: object[]; threadTs?: string },\n platform?: string,\n ): Promise<{ ts: string }>;\n updateBlocks(\n conversationId: string,\n messageTs: string,\n message: { text: string; blocks: object[] },\n platform?: string,\n ): Promise<void>;\n}\n\n/** Normalized platform data and reply hook for one event. */\nexport interface ConversationContext {\n /** Canonical identity for the office handling this turn. */\n address: OfficeAddress;\n message: ConversationMessage;\n responder: ConversationResponder;\n platform: MessagingInfo;\n}\n\nexport interface RunningSession {\n /** The office this run belongs to; two platforms may share a raw id. */\n address: OfficeAddress;\n sessionKey: string;\n startedAt: number;\n lastActivityAt?: number;\n currentTool?: string;\n}\n\n/**\n * Runtime state is addressed by an office plus that office's platform session\n * reference. The session key alone is a platform value and is not unique\n * across platforms, so every session-scoped call carries its `OfficeAddress`.\n */\nexport interface MessagingEventHandler {\n isRunning(address: OfficeAddress, sessionKey: string): boolean;\n getRunningSessions(): RunningSession[];\n handleEvent(\n event: ConversationEvent,\n bot: MessagingBot,\n context: ConversationContext,\n ): Promise<void>;\n handleStop(address: OfficeAddress, sessionKey: string, bot: MessagingBot): Promise<void>;\n forceStop(address: OfficeAddress, sessionKey: string): void;\n handleNewCommand(\n sessionKey: string,\n conversationId: string,\n bot: MessagingBot,\n message: ConversationMessage,\n responder: ConversationResponder,\n platform: MessagingInfo,\n ): Promise<void>;\n /**\n * Dispatch an extension-owned interactive block action (`ext:<slug>:`\n * namespaced) to its onAction handler — deterministic, no agent run. The\n * extension decides whether to involve the model (`triggerRun`). Returns\n * true when an extension consumed the action; namespaced actions never\n * fall through to the model, so the adapter drops unconsumed ones.\n */\n handleExtensionAction(params: {\n address: OfficeAddress;\n sessionKey: string;\n conversationKind: ConversationKind;\n slug: string;\n action: ExtensionBlockAction;\n }): Promise<boolean>;\n /**\n * Dispatch a fired extension callback schedule to its registered\n * `onCallback` handler — deterministic, no agent run, no model call.\n * Returns true when a handler consumed the fire; false when nothing is\n * registered (e.g. the extension was removed but its schedule remains).\n */\n handleExtensionScheduleCallback(fire: ExtensionScheduleCallbackFire): Promise<boolean>;\n}\n\n// ── agent ─────────────────────────────────────────────────────────────────────\n\nexport interface PiAgentWrapper {\n syncChatHistory(currentMessageId?: string): void;\n run(\n message: ConversationMessage,\n responder: ConversationResponder,\n platform: MessagingInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }>;\n /** Run a hidden Session Dream against the current session before resetting or rotating it. */\n dreamSessionMemory(\n message: ConversationMessage,\n platform: MessagingInfo,\n ): Promise<{ stopReason: string; errorMessage?: string }>;\n abort(): void;\n getCurrentStep(): { toolName?: string; label?: string } | undefined;\n /**\n * Dispatch a leading-slash message to an extension-registered command.\n * Returns true when a command consumed the message (no agent run follows).\n */\n tryExtensionCommand(\n message: ConversationMessage,\n responder: ConversationResponder,\n ): Promise<boolean>;\n /**\n * Dispatch an extension-owned interactive block action to its onAction\n * handler. Returns true when a handler consumed it (no agent run follows).\n */\n tryExtensionAction(slug: string, action: ExtensionBlockAction): Promise<boolean>;\n /** Run an extension's registered schedule callback; false when unregistered. */\n tryExtensionScheduleCallback(\n slug: string,\n callback: string,\n event: ExtensionScheduleCallbackEvent,\n ): Promise<boolean>;\n /** Run extension disposers. Call once when this wrapper is discarded. */\n dispose(): Promise<void>;\n}\n\n// ── config ────────────────────────────────────────────────────────────────────\n\nexport type WorkspaceDoorPolicy = \"isolated\" | \"trusted\";\nexport type WorkspaceLayout = \"conversation\" | \"shared-support\" | \"full\";\n\ninterface WorkspaceSettings {\n doorPolicy?: WorkspaceDoorPolicy;\n layout?: WorkspaceLayout;\n}\n\nexport interface SandboxSettings {\n cpus?: string;\n memory?: string;\n boost?: { cpus?: string; memory?: string };\n /** Legacy image-specific workspace setting; new installations use workspace. */\n image?: { workspaceMount?: \"private\" | \"full\" };\n /** Backend-neutral office data policy and layout. */\n workspace?: WorkspaceSettings;\n defaultSharedVault?: string;\n}\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel: ThinkingLevel;\n sentryDsn?: string;\n sandbox?: SandboxSettings;\n slack?: {\n replyMode?: \"top-level\" | \"thread\";\n };\n /**\n * Package sources (see `src/packages`) declared by ONE scope. Unlike every\n * other key here, packages are additive across scopes rather than\n * overriding: a conversation's list does not replace the global list, it\n * extends it. `resolveConversationSettings` therefore reports only the\n * conversation's own entries — combining the two scopes (and resolving\n * same-package collisions in the conversation's favour) is\n * `resolveConversationPackages`'s job.\n */\n packages?: string[];\n}\n\n/**\n * @deprecated Auto-reply is kept for compatibility while its future is undecided.\n */\nexport interface AutoReplyConfig {\n enabled: boolean;\n rules: string[];\n}\n\nexport interface JudgeModelConfig {\n provider: string;\n model: string;\n}\n\n// ── context ───────────────────────────────────────────────────────────────────\n\n/**\n * Platform conversation history entry from log.jsonl.\n */\nexport interface ConversationLogMessage {\n date?: string;\n ts?: string;\n threadTs?: string;\n user?: string;\n userName?: string;\n text?: string;\n isMessagingBot?: boolean;\n}\n\n// ── events ────────────────────────────────────────────────────────────────────\n// The wire format (payload union, schema, parser, builder) is owned by\n// src/harness/event-format.ts. These are the *resolved* runtime shapes: the\n// EventsWatcher fills in the platform default and infers the conversation\n// kind before an event reaches a bot.\n\ninterface ResolvedEventFields {\n platform: string;\n conversationKind: ConversationKind;\n}\n\nexport type ImmediateEvent = ImmediateEventPayload & ResolvedEventFields;\n\nexport type OneShotEvent = OneShotEventPayload & ResolvedEventFields;\n\nexport type PeriodicEvent = PeriodicEventPayload & ResolvedEventFields;\n\nexport type MikanEvent = ImmediateEvent | OneShotEvent | PeriodicEvent;\n\nexport interface PeriodicEventInfo {\n filename: string;\n platform: string;\n conversationId: string;\n conversationKind: ConversationKind;\n text: string;\n schedule: string;\n timezone: string;\n nextRun: string | null;\n}\n\n// ── execution-resolver ────────────────────────────────────────────────────────\n\nexport interface ActorContext {\n /** Canonical office identity; vault and package keys use its raw id. */\n address: OfficeAddress;\n userId: string;\n /** From MessagingInfo.trustModel; vault policy uses this, not platform name. */\n trustModel?: PlatformTrustModel;\n}\n\nexport type ImageWorkspaceMountMode = \"private\" | \"full\";\n\n// ── log ───────────────────────────────────────────────────────────────────────\n\nexport interface LogContext {\n conversationId: string;\n userName?: string;\n conversationName?: string;\n sessionId?: string;\n}\n\n// ── portal shell (src/web/portal-shell.ts) ────────────────────────────────────\n\ntype PortalView = \"admin\" | \"session\" | \"vault\";\n\nexport interface PortalShellOptions {\n activeView: PortalView;\n pageTitle: string;\n identity?: {\n primary: string;\n secondary?: string;\n };\n conversationSwitcher?: {\n currentId: string;\n options?: Array<{ id: string; label: string; running?: boolean }>;\n };\n navLinks?: Partial<Record<PortalView, string>>;\n body: string;\n extraStyles?: string;\n inlineScript?: string;\n extraHead?: string;\n bodyAttributes?: Record<string, string>;\n}\n\n// ── provisioner ───────────────────────────────────────────────────────────────\n\nexport interface ContainerMount {\n source: string;\n target: string;\n /**\n * Mount without write access. Used for content the host owns and the agent\n * must not edit — package-provided skills, whose host copy is a git checkout\n * that a reinstall replaces wholesale. Absent means read-write, which is the\n * right default for everything the agent is meant to author.\n */\n readOnly?: boolean;\n}\n\nexport interface ResourceLimits {\n cpus?: string;\n memory?: string;\n}\n\nexport interface SandboxLimitStatus {\n limits?: ResourceLimits;\n boosted: boolean;\n}\n\nexport interface SandboxResourceController {\n boost(key: string): Promise<SandboxLimitStatus>;\n setLimits(key: string, limits: ResourceLimits): Promise<SandboxLimitStatus>;\n getLimitStatus(key: string): SandboxLimitStatus;\n getDefaultLimits(): ResourceLimits | undefined;\n getBoostLimits(): ResourceLimits | undefined;\n}\n\nexport interface ProvisionOptions {\n containerName?: string;\n mounts?: ContainerMount[];\n conversationId?: string;\n}\n\nexport interface DockerContainerManagerOptions {\n limits?: ResourceLimits;\n boostLimits?: ResourceLimits;\n execFileImpl?: ExecFileAsync;\n}\n\nexport interface ExecutionPlan {\n credentialKey: string;\n resourceKey: string;\n sandboxConfig: SandboxConfig;\n env?: Record<string, string>;\n mounts: ContainerMount[];\n}\n\n// ── store ─────────────────────────────────────────────────────────────────────\n\nexport interface Attachment {\n original: string;\n localPath: string;\n}\n\n// ── trigger ───────────────────────────────────────────────────────────────────\n\nexport type TriggerIntent = \"mention\" | \"direct\" | \"thread-continuation\" | \"auto-reply-candidate\";\n\nexport type TriggerResult = { trigger: true; reason: string } | { trigger: false; reason: string };\n\n/**\n * @deprecated Auto-reply is kept for compatibility while its future is undecided.\n */\nexport type AutoReplyJudge = (input: {\n event: ConversationEvent;\n rules: string[];\n office: Office;\n}) => Promise<boolean>;\n\n// ── shared implementation contracts ─────────────────────────────────────────\n\ninterface EnvVarSpec {\n name: string;\n required?: boolean;\n secret?: boolean;\n deploy?: boolean;\n doc: string;\n}\n\nexport interface EnvGroup {\n key: string;\n title: string;\n kind: \"platform\" | \"feature\";\n vars: EnvVarSpec[];\n anyOf?: readonly string[];\n doc?: string;\n}\n\nexport interface RunnerCacheControl {\n switchConversationModel(address: OfficeAddress, provider: string, model: string): boolean;\n /** Clear the office's cached runner for a non-model settings change; false while busy. */\n refreshConversationEnvironment(address: OfficeAddress): boolean;\n}\n\nexport interface GlobalRunnerCacheControl {\n refreshAllConversations(): { busy: OfficeAddress[] };\n}\n\nexport type SettingsApplyResult =\n | { ok: true; runtimeSwitched: boolean | null }\n | { ok: false; reason: \"busy\" };\n\nexport interface CreateRunnerOptions {\n sandboxConfig: SandboxConfig;\n sessionKey: string;\n /** The Conversation office this runner serves; identity and layout derive from it. */\n office: Office;\n sessionScope: ResolvedSessionScope;\n vaultManager?: VaultManager;\n provisioner?: DockerContainerManager;\n resourceController?: SandboxResourceController;\n sessionView?: {\n tokenStore: SessionViewTokenStoreLike;\n portalBaseUrl?: string;\n };\n platformNotifier?: PlatformNotifier;\n platformReactor?: PlatformReactor;\n platformUploader?: PlatformUploader;\n platformBlockKit?: PlatformBlockKit;\n platformDmOpener?: PlatformDmOpener;\n platformHistoryFetcher?: PlatformHistoryFetcher;\n platformUserLister?: PlatformUserLister;\n /** Host-authoritative callback-schedule engine (`api.schedules` callbacks). */\n extensionScheduleEngine?: ExtensionScheduleEngine;\n platformToolPackFactories?: readonly PlatformToolPackFactory[];\n models?: MikanModels;\n}\n"]}
@@ -6,4 +6,13 @@ export declare function readJsonSchemaFileIfExists<T extends TSchema>(path: stri
6
6
  export declare function parseJsonValue<T>(raw: string, validate: (value: unknown) => value is T, malformedMessage: (detail: string) => string): T;
7
7
  export declare function parseJsonSchemaValue<T extends TSchema>(raw: string, schema: T, malformedMessage: (detail: string) => string): Static<T>;
8
8
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
9
+ /**
10
+ * Write `content` to `targetPath` with mode 0600, even when `targetPath`
11
+ * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel
12
+ * guarantees permissions at creation, not after a racy chmod) and then
13
+ * rename(2) into place for atomicity. Readers never see a torn write,
14
+ * and a crash mid-write leaves either the old file or a stray .tmp
15
+ * (cleaned by the next attempt or manually) — never a half-written target.
16
+ */
17
+ export declare function atomicWritePrivateFile(targetPath: string, content: string): void;
9
18
  //# sourceMappingURL=file-guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-guards.d.ts","sourceRoot":"","sources":["../../src/utils/file-guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAIzD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,GAAG,SAAS,CAGf;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,OAAO,EAC1D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAGvB;AAWD,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,CAMH;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EACpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,CAeX;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
1
+ {"version":3,"file":"file-guards.d.ts","sourceRoot":"","sources":["../../src/utils/file-guards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAezD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,GAAG,SAAS,CAGf;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,OAAO,EAC1D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAGvB;AAWD,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,EACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,CAAC,CAMH;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EACpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,EACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAAC,CAAC,CAAC,CAeX;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAID;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAiChF"}
@@ -1,5 +1,7 @@
1
1
  import { Value } from "@sinclair/typebox/value";
2
- import { mkdirSync, readFileSync } from "fs";
2
+ import { closeSync, constants as fsConstants, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from "node:fs";
3
+ import { randomBytes } from "node:crypto";
4
+ import { basename, dirname, join } from "node:path";
3
5
  export function ensureDirExists(dir) {
4
6
  mkdirSync(dir, { recursive: true });
5
7
  }
@@ -56,4 +58,45 @@ export function parseJsonSchemaValue(raw, schema, malformedMessage) {
56
58
  export function isRecord(value) {
57
59
  return typeof value === "object" && value !== null && !Array.isArray(value);
58
60
  }
61
+ const PRIVATE_FILE_MODE = 0o600;
62
+ /**
63
+ * Write `content` to `targetPath` with mode 0600, even when `targetPath`
64
+ * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel
65
+ * guarantees permissions at creation, not after a racy chmod) and then
66
+ * rename(2) into place for atomicity. Readers never see a torn write,
67
+ * and a crash mid-write leaves either the old file or a stray .tmp
68
+ * (cleaned by the next attempt or manually) — never a half-written target.
69
+ */
70
+ export function atomicWritePrivateFile(targetPath, content) {
71
+ const dir = dirname(targetPath);
72
+ const tmpPath = join(dir, `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
73
+ const fd = openSync(tmpPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, PRIVATE_FILE_MODE);
74
+ try {
75
+ writeSync(fd, content);
76
+ }
77
+ catch (err) {
78
+ try {
79
+ unlinkSync(tmpPath);
80
+ }
81
+ catch {
82
+ // ignore — original error is more informative
83
+ }
84
+ throw err;
85
+ }
86
+ finally {
87
+ closeSync(fd);
88
+ }
89
+ try {
90
+ renameSync(tmpPath, targetPath);
91
+ }
92
+ catch (err) {
93
+ try {
94
+ unlinkSync(tmpPath);
95
+ }
96
+ catch {
97
+ // ignore
98
+ }
99
+ throw err;
100
+ }
101
+ }
59
102
  //# sourceMappingURL=file-guards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-guards.js","sourceRoot":"","sources":["../../src/utils/file-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Static, TSchema } from \"@sinclair/typebox\";\nimport { Value } from \"@sinclair/typebox/value\";\nimport { mkdirSync, readFileSync } from \"fs\";\n\nexport function ensureDirExists(dir: string): void {\n mkdirSync(dir, { recursive: true });\n}\n\nexport function readTextFileIfExists(path: string): string | undefined {\n try {\n return readFileSync(path, \"utf-8\");\n } catch (err) {\n if (err instanceof Error && \"code\" in err && err.code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport function readJsonFileIfExists<T>(\n path: string,\n validate: (value: unknown) => value is T,\n malformedMessage: (detail: string) => string,\n): T | undefined {\n const raw = readTextFileIfExists(path);\n return raw === undefined ? undefined : parseJsonValue(raw, validate, malformedMessage);\n}\n\nexport function readJsonSchemaFileIfExists<T extends TSchema>(\n path: string,\n schema: T,\n malformedMessage: (detail: string) => string,\n): Static<T> | undefined {\n const raw = readTextFileIfExists(path);\n return raw === undefined ? undefined : parseJsonSchemaValue(raw, schema, malformedMessage);\n}\n\nfunction parseJson(raw: string, malformedMessage: (detail: string) => string): unknown {\n try {\n return JSON.parse(raw);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(malformedMessage(detail), { cause: err });\n }\n}\n\nexport function parseJsonValue<T>(\n raw: string,\n validate: (value: unknown) => value is T,\n malformedMessage: (detail: string) => string,\n): T {\n const parsed = parseJson(raw, malformedMessage);\n if (!validate(parsed)) {\n throw new Error(malformedMessage(\"unexpected JSON shape\"));\n }\n return parsed;\n}\n\nexport function parseJsonSchemaValue<T extends TSchema>(\n raw: string,\n schema: T,\n malformedMessage: (detail: string) => string,\n): Static<T> {\n const parsed = parseJson(raw, malformedMessage);\n if (!Value.Check(schema, parsed)) {\n let firstError: { path: string; message: string } | undefined;\n for (const err of Value.Errors(schema, parsed)) {\n firstError = err;\n break;\n }\n const detail =\n !firstError || firstError.path === \"\" || firstError.path === \"/\"\n ? \"unexpected JSON shape\"\n : `${firstError.path}: ${firstError.message}`;\n throw new Error(malformedMessage(detail));\n }\n return parsed;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"]}
1
+ {"version":3,"file":"file-guards.js","sourceRoot":"","sources":["../../src/utils/file-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Static, TSchema } from \"@sinclair/typebox\";\nimport { Value } from \"@sinclair/typebox/value\";\nimport {\n closeSync,\n constants as fsConstants,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeSync,\n} from \"node:fs\";\nimport { randomBytes } from \"node:crypto\";\nimport { basename, dirname, join } from \"node:path\";\n\nexport function ensureDirExists(dir: string): void {\n mkdirSync(dir, { recursive: true });\n}\n\nexport function readTextFileIfExists(path: string): string | undefined {\n try {\n return readFileSync(path, \"utf-8\");\n } catch (err) {\n if (err instanceof Error && \"code\" in err && err.code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n}\n\nexport function readJsonFileIfExists<T>(\n path: string,\n validate: (value: unknown) => value is T,\n malformedMessage: (detail: string) => string,\n): T | undefined {\n const raw = readTextFileIfExists(path);\n return raw === undefined ? undefined : parseJsonValue(raw, validate, malformedMessage);\n}\n\nexport function readJsonSchemaFileIfExists<T extends TSchema>(\n path: string,\n schema: T,\n malformedMessage: (detail: string) => string,\n): Static<T> | undefined {\n const raw = readTextFileIfExists(path);\n return raw === undefined ? undefined : parseJsonSchemaValue(raw, schema, malformedMessage);\n}\n\nfunction parseJson(raw: string, malformedMessage: (detail: string) => string): unknown {\n try {\n return JSON.parse(raw);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(malformedMessage(detail), { cause: err });\n }\n}\n\nexport function parseJsonValue<T>(\n raw: string,\n validate: (value: unknown) => value is T,\n malformedMessage: (detail: string) => string,\n): T {\n const parsed = parseJson(raw, malformedMessage);\n if (!validate(parsed)) {\n throw new Error(malformedMessage(\"unexpected JSON shape\"));\n }\n return parsed;\n}\n\nexport function parseJsonSchemaValue<T extends TSchema>(\n raw: string,\n schema: T,\n malformedMessage: (detail: string) => string,\n): Static<T> {\n const parsed = parseJson(raw, malformedMessage);\n if (!Value.Check(schema, parsed)) {\n let firstError: { path: string; message: string } | undefined;\n for (const err of Value.Errors(schema, parsed)) {\n firstError = err;\n break;\n }\n const detail =\n !firstError || firstError.path === \"\" || firstError.path === \"/\"\n ? \"unexpected JSON shape\"\n : `${firstError.path}: ${firstError.message}`;\n throw new Error(malformedMessage(detail));\n }\n return parsed;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst PRIVATE_FILE_MODE = 0o600;\n\n/**\n * Write `content` to `targetPath` with mode 0600, even when `targetPath`\n * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel\n * guarantees permissions at creation, not after a racy chmod) and then\n * rename(2) into place for atomicity. Readers never see a torn write,\n * and a crash mid-write leaves either the old file or a stray .tmp\n * (cleaned by the next attempt or manually) — never a half-written target.\n */\nexport function atomicWritePrivateFile(targetPath: string, content: string): void {\n const dir = dirname(targetPath);\n const tmpPath = join(\n dir,\n `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString(\"hex\")}.tmp`,\n );\n const fd = openSync(\n tmpPath,\n fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,\n PRIVATE_FILE_MODE,\n );\n try {\n writeSync(fd, content);\n } catch (err) {\n try {\n unlinkSync(tmpPath);\n } catch {\n // ignore — original error is more informative\n }\n throw err;\n } finally {\n closeSync(fd);\n }\n try {\n renameSync(tmpPath, targetPath);\n } catch (err) {\n try {\n unlinkSync(tmpPath);\n } catch {\n // ignore\n }\n throw err;\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { VaultManager } from "./types.js";
2
+ /**
3
+ * Inert VaultManager for embedders that run the conversation runtime without
4
+ * a credential vault. Read paths report an empty, disabled vault; write paths
5
+ * fail loudly so misconfiguration surfaces instead of silently dropping
6
+ * secrets.
7
+ */
8
+ export declare const disabledVaultManager: VaultManager;
9
+ //# sourceMappingURL=disabled.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled.d.ts","sourceRoot":"","sources":["../../src/vault/disabled.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,YAiBlC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Inert VaultManager for embedders that run the conversation runtime without
3
+ * a credential vault. Read paths report an empty, disabled vault; write paths
4
+ * fail loudly so misconfiguration surfaces instead of silently dropping
5
+ * secrets.
6
+ */
7
+ export const disabledVaultManager = {
8
+ isEnabled: () => false,
9
+ hasEntry: () => false,
10
+ resolve: () => undefined,
11
+ list: () => [],
12
+ listSharedVaults: () => [],
13
+ deleteSharedVault: () => false,
14
+ copySharedVaultTo: () => ({ filesCopied: 0, envKeysCopied: 0 }),
15
+ upsertEnv: () => {
16
+ throw new Error("Vault not configured");
17
+ },
18
+ deleteEnvKey: () => {
19
+ throw new Error("Vault not configured");
20
+ },
21
+ upsertFile: () => {
22
+ throw new Error("Vault not configured");
23
+ },
24
+ };
25
+ //# sourceMappingURL=disabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled.js","sourceRoot":"","sources":["../../src/vault/disabled.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAiB;IAChD,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK;IACtB,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;IACrB,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS;IACxB,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;IACd,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE;IAC1B,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK;IAC9B,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;IAC/D,SAAS,EAAE,GAAG,EAAE;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,YAAY,EAAE,GAAG,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,UAAU,EAAE,GAAG,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC","sourcesContent":["import type { VaultManager } from \"./types.js\";\n\n/**\n * Inert VaultManager for embedders that run the conversation runtime without\n * a credential vault. Read paths report an empty, disabled vault; write paths\n * fail loudly so misconfiguration surfaces instead of silently dropping\n * secrets.\n */\nexport const disabledVaultManager: VaultManager = {\n isEnabled: () => false,\n hasEntry: () => false,\n resolve: () => undefined,\n list: () => [],\n listSharedVaults: () => [],\n deleteSharedVault: () => false,\n copySharedVaultTo: () => ({ filesCopied: 0, envKeysCopied: 0 }),\n upsertEnv: () => {\n throw new Error(\"Vault not configured\");\n },\n deleteEnvKey: () => {\n throw new Error(\"Vault not configured\");\n },\n upsertFile: () => {\n throw new Error(\"Vault not configured\");\n },\n};\n"]}
@@ -1,4 +1,6 @@
1
- import type { SandboxConfig } from "../sandbox/index.js";
1
+ import type { OfficeAddress } from "../types.js";
2
+ import type { SandboxConfig, SandboxCredentialCapabilities } from "../sandbox/types.js";
3
+ import type { PlatformTrustModel } from "../types.js";
2
4
  export declare function normalizeSharedVaultName(name: string): string | undefined;
3
5
  export declare function sharedVaultKey(name: string): string | undefined;
4
6
  export type { ResolvedVault, VaultManager } from "./types.js";
@@ -24,11 +26,52 @@ export declare class FileVaultManager implements VaultManager {
24
26
  envKeysCopied: number;
25
27
  };
26
28
  resolve(userId: string): ResolvedVault | undefined;
27
- getSandboxConfig(userId: string, baseConfig: SandboxConfig): SandboxConfig;
28
29
  list(): ResolvedVault[];
29
30
  upsertEnv(key: string, env: Record<string, string>): void;
31
+ deleteEnvKey(key: string, envKey: string): boolean;
30
32
  upsertFile(key: string, relativePath: string, content: string, targetPath?: string): void;
31
33
  private buildResolved;
32
34
  }
33
35
  export declare function defaultVaultTargetPath(relativePath: string): string;
36
+ /**
37
+ * Rename legacy raw-id conversation vault directories to office keys, driven
38
+ * by the office registry's inventory (the only raw-id ↔ office authority).
39
+ * Shared, user-keyed, and unrecognized directories are never touched. A
40
+ * conflict — both the legacy and the office-key directory exist — is reported
41
+ * for manual merge, never clobbered; callers treat it as fatal for boot so a
42
+ * conversation cannot silently run with half its credentials.
43
+ */
44
+ export declare function migrateConversationVaultKeys(options: {
45
+ stateDir: string;
46
+ offices: readonly OfficeAddress[];
47
+ }): {
48
+ migrated: string[];
49
+ conflicts: string[];
50
+ };
51
+ /**
52
+ * Decide whether a new conversation vault may inherit `sandbox.defaultSharedVault`.
53
+ *
54
+ * Ambient copy is a membership-trust convenience: only appropriate when the
55
+ * people who can drive the agent are already gated by platform membership
56
+ * (Slack/Discord/Telegram). Open-trigger surfaces (GitHub issue/PR comments)
57
+ * must not inherit ambient credentials — host-side platform identity or an
58
+ * explicitly provisioned vault only.
59
+ *
60
+ * Topology: only isolated sandboxes (`image` / `cloudflare`) auto-provision
61
+ * per-conversation vaults that receive the copy. `host` / `container` /
62
+ * `firecracker` do not use this ambient path.
63
+ */
64
+ export declare function allowsAmbientDefaultSharedVault(options: {
65
+ trustModel?: PlatformTrustModel;
66
+ sandboxType: SandboxConfig["type"];
67
+ }): boolean;
68
+ export type { VaultInjection } from "./types.js";
69
+ import type { VaultInjection } from "./types.js";
70
+ export declare function resolveVaultInjection(options: {
71
+ vault: ResolvedVault | undefined;
72
+ capabilities: SandboxCredentialCapabilities;
73
+ sandboxType: SandboxConfig["type"];
74
+ /** Diagnostic identity for error reports only; no injection decision reads it. */
75
+ address: OfficeAddress;
76
+ }): VaultInjection;
34
77
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAazD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/D;AAWD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAsB,YAAY,EAAE,MAAM,YAAY,CAAC;AAIlF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BpE;AAID,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,QAAQ,EAAE,MAAM,EAE3B;IAED,SAAS,IAAI,OAAO,CAEnB;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7B;IAED,gBAAgB,IAAI,MAAM,EAAE,CAO3B;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOvC;IAED,iBAAiB,CACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAUhD;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAIjD;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,GAAG,aAAa,CAQzE;IAED,IAAI,IAAI,aAAa,EAAE,CAOtB;IAED,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAcxD;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAcxF;IAID,OAAO,CAAC,aAAa;CA6BtB;AAuFD,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,aAAa,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAWtD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAsB,YAAY,EAAE,MAAM,YAAY,CAAC;AAIlF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BpE;AAID,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,QAAQ,EAAE,MAAM,EAE3B;IAED,SAAS,IAAI,OAAO,CAEnB;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG7B;IAED,gBAAgB,IAAI,MAAM,EAAE,CAO3B;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOvC;IAED,iBAAiB,CACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAWhD;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAKjD;IAED,IAAI,IAAI,aAAa,EAAE,CAatB;IAED,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAexD;IAED,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAejD;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAexF;IAID,OAAO,CAAC,aAAa;CAetB;AAyGD,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGnE;AAyBD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CACnC,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAkB9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE;IACvD,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACpC,GAAG,OAAO,CAIV;AAED,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,YAAY,EAAE,6BAA6B,CAAC;IAC5C,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,kFAAkF;IAClF,OAAO,EAAE,aAAa,CAAC;CACxB,GAAG,cAAc,CA6BjB"}
@@ -1,7 +1,8 @@
1
- import { chmodSync, copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from "fs";
2
- import { dirname, isAbsolute, join, normalize, sep } from "path";
3
- import { readTextFileIfExists } from "../utils/file-guards.js";
4
- import { atomicWritePrivateFile } from "../utils/fs-atomic.js";
1
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync, } from "node:fs";
2
+ import { dirname, isAbsolute, join, normalize, sep } from "node:path";
3
+ import { officeKey } from "../office/index.js";
4
+ import { legacyConversationCredentialKey } from "../sandbox/identity.js";
5
+ import { atomicWritePrivateFile, readTextFileIfExists } from "../utils/file-guards.js";
5
6
  import { reportUserFacingError } from "../observability/sentry.js";
6
7
  const PRIVATE_DIR_MODE = 0o700;
7
8
  const SHARED_VAULT_DIR = "shared";
@@ -21,12 +22,6 @@ export function sharedVaultKey(name) {
21
22
  const normalized = normalizeSharedVaultName(name);
22
23
  return normalized ? `${SHARED_VAULT_DIR}/${normalized}` : undefined;
23
24
  }
24
- function sanitizeCloudflareSandboxId(value) {
25
- return (value
26
- .toLowerCase()
27
- .replace(/[^a-z0-9-]+/g, "-")
28
- .replace(/^-+|-+$/g, "") || "unknown");
29
- }
30
25
  // ── parseEnvFile ───────────────────────────────────────────────────────────────
31
26
  /**
32
27
  * Parse a KEY=VALUE env file. Supports:
@@ -67,6 +62,8 @@ export class FileVaultManager {
67
62
  return existsSync(this.vaultsDir);
68
63
  }
69
64
  hasEntry(key) {
65
+ if (!isSafeVaultKey(key))
66
+ return false;
70
67
  return existsSync(join(this.vaultsDir, key));
71
68
  }
72
69
  listSharedVaults() {
@@ -88,6 +85,8 @@ export class FileVaultManager {
88
85
  return existed;
89
86
  }
90
87
  copySharedVaultTo(name, targetKey) {
88
+ if (!isSafeVaultKey(targetKey))
89
+ throw new Error(`vault: invalid vault key: ${targetKey}`);
91
90
  const sourceKey = sharedVaultKey(name);
92
91
  if (!sourceKey)
93
92
  throw new Error(`vault: invalid shared login name: ${name}`);
@@ -100,31 +99,29 @@ export class FileVaultManager {
100
99
  return copyVaultDir(sourceDir, targetDir);
101
100
  }
102
101
  resolve(userId) {
102
+ if (!isSafeVaultKey(userId))
103
+ return undefined;
103
104
  const dir = join(this.vaultsDir, userId);
104
105
  if (!existsSync(dir))
105
106
  return undefined;
106
107
  return this.buildResolved(userId);
107
108
  }
108
- getSandboxConfig(userId, baseConfig) {
109
- if (baseConfig.type === "cloudflare") {
110
- return {
111
- type: "cloudflare",
112
- sandboxId: `${baseConfig.sandboxId}-${sanitizeCloudflareSandboxId(userId)}`,
113
- };
114
- }
115
- return baseConfig;
116
- }
117
109
  list() {
118
110
  if (!existsSync(this.vaultsDir))
119
111
  return [];
120
112
  const keys = new Set();
121
113
  for (const entry of readdirSync(this.vaultsDir, { withFileTypes: true })) {
122
- if (entry.isDirectory() && !RESERVED_VAULT_DIRS.has(entry.name))
114
+ if (entry.isDirectory() &&
115
+ !RESERVED_VAULT_DIRS.has(entry.name) &&
116
+ isSafeVaultKey(entry.name)) {
123
117
  keys.add(entry.name);
118
+ }
124
119
  }
125
120
  return Array.from(keys, (key) => this.buildResolved(key));
126
121
  }
127
122
  upsertEnv(key, env) {
123
+ if (!isSafeVaultKey(key))
124
+ throw new Error(`vault: invalid vault key: ${key}`);
128
125
  const dir = join(this.vaultsDir, key);
129
126
  const envPath = join(dir, "env");
130
127
  ensurePrivateDir(this.vaultsDir);
@@ -138,7 +135,27 @@ export class FileVaultManager {
138
135
  .join("\n") + "\n";
139
136
  atomicWritePrivateFile(envPath, content);
140
137
  }
138
+ deleteEnvKey(key, envKey) {
139
+ if (!isSafeVaultKey(key))
140
+ throw new Error(`vault: invalid vault key: ${key}`);
141
+ const envPath = join(this.vaultsDir, key, "env");
142
+ const existingContent = readTextFileIfExists(envPath);
143
+ if (existingContent === undefined)
144
+ return false;
145
+ const existing = parseEnvFile(existingContent);
146
+ if (!(envKey in existing))
147
+ return false;
148
+ delete existing[envKey];
149
+ const content = Object.entries(existing)
150
+ .toSorted(([left], [right]) => left.localeCompare(right))
151
+ .map(([name, value]) => `${name}=${value}`)
152
+ .join("\n") + "\n";
153
+ atomicWritePrivateFile(envPath, content);
154
+ return true;
155
+ }
141
156
  upsertFile(key, relativePath, content, targetPath) {
157
+ if (!isSafeVaultKey(key))
158
+ throw new Error(`vault: invalid vault key: ${key}`);
142
159
  const normalizedPath = normalizeVaultRelativePath(relativePath);
143
160
  if (!normalizedPath || (targetPath !== undefined && !normalizeVaultTargetPath(targetPath))) {
144
161
  throw new Error(`vault: invalid relative secret file path for "${key}": ${relativePath}`);
@@ -156,23 +173,8 @@ export class FileVaultManager {
156
173
  buildResolved(key) {
157
174
  const dir = join(this.vaultsDir, key);
158
175
  const mounts = inferMountsFromDir(dir);
159
- let env = {};
160
176
  const envContent = readTextFileIfExists(join(dir, "env"));
161
- if (envContent !== undefined) {
162
- try {
163
- env = parseEnvFile(envContent);
164
- }
165
- catch (err) {
166
- console.error(`vault: failed to parse env file for "${key}":`, err);
167
- reportUserFacingError(err, {
168
- domain: "sandbox",
169
- surface: "vault_injection",
170
- operation: "parse_env",
171
- severity: "warning",
172
- context: { vaultKey: key, fatal: false },
173
- });
174
- }
175
- }
177
+ const env = envContent === undefined ? {} : parseEnvFile(envContent);
176
178
  return {
177
179
  userId: key,
178
180
  displayName: key,
@@ -234,6 +236,21 @@ function copyVaultDir(sourceDir, targetDir) {
234
236
  }
235
237
  return { filesCopied, envKeysCopied };
236
238
  }
239
+ function isSafeVaultKey(key) {
240
+ if (typeof key !== "string" || !key || isAbsolute(key))
241
+ return false;
242
+ if (/^[A-Za-z]:[\\/]/.test(key))
243
+ return false;
244
+ return key.split(/[\\/]/).every((segment) => {
245
+ return (segment !== "" && segment !== "." && segment !== ".." && !hasUnsafeControlCharacter(segment));
246
+ });
247
+ }
248
+ function hasUnsafeControlCharacter(value) {
249
+ return Array.from(value).some((character) => {
250
+ const code = character.codePointAt(0) ?? 0;
251
+ return (code >= 0 && code <= 31) || (code >= 127 && code <= 159);
252
+ });
253
+ }
237
254
  function normalizeVaultRelativePath(relativePath) {
238
255
  const trimmed = relativePath.trim();
239
256
  if (!trimmed || isAbsolute(trimmed))
@@ -278,4 +295,78 @@ function inferredVaultTargetPath(relativePath) {
278
295
  }
279
296
  return defaultVaultTargetPath(normalized);
280
297
  }
298
+ /**
299
+ * Rename legacy raw-id conversation vault directories to office keys, driven
300
+ * by the office registry's inventory (the only raw-id ↔ office authority).
301
+ * Shared, user-keyed, and unrecognized directories are never touched. A
302
+ * conflict — both the legacy and the office-key directory exist — is reported
303
+ * for manual merge, never clobbered; callers treat it as fatal for boot so a
304
+ * conversation cannot silently run with half its credentials.
305
+ */
306
+ export function migrateConversationVaultKeys(options) {
307
+ const vaultsDir = join(options.stateDir, "vaults");
308
+ const migrated = [];
309
+ const conflicts = [];
310
+ if (!existsSync(vaultsDir))
311
+ return { migrated, conflicts };
312
+ for (const office of options.offices) {
313
+ const legacyDir = join(vaultsDir, legacyConversationCredentialKey(office.conversationId));
314
+ if (!existsSync(legacyDir))
315
+ continue;
316
+ const targetDir = join(vaultsDir, officeKey(office));
317
+ if (existsSync(targetDir)) {
318
+ conflicts.push(office.conversationId);
319
+ continue;
320
+ }
321
+ renameSync(legacyDir, targetDir);
322
+ migrated.push(office.conversationId);
323
+ }
324
+ return { migrated, conflicts };
325
+ }
326
+ /**
327
+ * Decide whether a new conversation vault may inherit `sandbox.defaultSharedVault`.
328
+ *
329
+ * Ambient copy is a membership-trust convenience: only appropriate when the
330
+ * people who can drive the agent are already gated by platform membership
331
+ * (Slack/Discord/Telegram). Open-trigger surfaces (GitHub issue/PR comments)
332
+ * must not inherit ambient credentials — host-side platform identity or an
333
+ * explicitly provisioned vault only.
334
+ *
335
+ * Topology: only isolated sandboxes (`image` / `cloudflare`) auto-provision
336
+ * per-conversation vaults that receive the copy. `host` / `container` /
337
+ * `firecracker` do not use this ambient path.
338
+ */
339
+ export function allowsAmbientDefaultSharedVault(options) {
340
+ const trustModel = options.trustModel ?? "membership";
341
+ if (trustModel === "open-trigger")
342
+ return false;
343
+ return options.sandboxType === "image" || options.sandboxType === "cloudflare";
344
+ }
345
+ export function resolveVaultInjection(options) {
346
+ const { vault, capabilities, sandboxType, address } = options;
347
+ if (vault && vault.mounts.length > 0 && !capabilities.fileMounts) {
348
+ throw new Error(`Sandbox type "${sandboxType}" does not support vault file mounts`);
349
+ }
350
+ const mounts = [];
351
+ for (const mount of vault?.mounts ?? []) {
352
+ if (!existsSync(mount.source)) {
353
+ reportUserFacingError(new Error("Vault mount source is missing"), {
354
+ domain: "sandbox",
355
+ surface: "vault_injection",
356
+ operation: "resolve_mounts",
357
+ severity: "warning",
358
+ context: {
359
+ sandboxType,
360
+ conversationId: address.conversationId,
361
+ target: mount.target,
362
+ hasVault: Boolean(vault),
363
+ },
364
+ });
365
+ continue;
366
+ }
367
+ mounts.push({ source: mount.source, target: mount.target });
368
+ }
369
+ const env = capabilities.env && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;
370
+ return { ...(env ? { env } : {}), mounts };
371
+ }
281
372
  //# sourceMappingURL=index.js.map