@geminixiang/mikan 0.3.2 → 0.4.0-beta.0

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 (371) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/adapter.d.ts +1 -138
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +1 -4
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +25 -33
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +28 -0
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/discord/types.d.ts +6 -0
  13. package/dist/adapters/discord/types.d.ts.map +1 -0
  14. package/dist/adapters/discord/types.js +2 -0
  15. package/dist/adapters/discord/types.js.map +1 -0
  16. package/dist/adapters/intake.d.ts +11 -0
  17. package/dist/adapters/intake.d.ts.map +1 -0
  18. package/dist/adapters/intake.js +42 -0
  19. package/dist/adapters/intake.js.map +1 -0
  20. package/dist/adapters/shared.d.ts +7 -31
  21. package/dist/adapters/shared.d.ts.map +1 -1
  22. package/dist/adapters/shared.js +18 -2
  23. package/dist/adapters/shared.js.map +1 -1
  24. package/dist/adapters/slack/bot.d.ts +14 -33
  25. package/dist/adapters/slack/bot.d.ts.map +1 -1
  26. package/dist/adapters/slack/bot.js +148 -116
  27. package/dist/adapters/slack/bot.js.map +1 -1
  28. package/dist/adapters/slack/context.d.ts +3 -4
  29. package/dist/adapters/slack/context.d.ts.map +1 -1
  30. package/dist/adapters/slack/context.js +97 -14
  31. package/dist/adapters/slack/context.js.map +1 -1
  32. package/dist/adapters/slack/session.d.ts +5 -20
  33. package/dist/adapters/slack/session.d.ts.map +1 -1
  34. package/dist/adapters/slack/session.js.map +1 -1
  35. package/dist/adapters/slack/types.d.ts +84 -0
  36. package/dist/adapters/slack/types.d.ts.map +1 -0
  37. package/dist/adapters/slack/types.js +2 -0
  38. package/dist/adapters/slack/types.js.map +1 -0
  39. package/dist/adapters/streaming.d.ts +18 -0
  40. package/dist/adapters/streaming.d.ts.map +1 -0
  41. package/dist/adapters/streaming.js +44 -0
  42. package/dist/adapters/streaming.js.map +1 -0
  43. package/dist/adapters/telegram/bot.d.ts +1 -4
  44. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  45. package/dist/adapters/telegram/bot.js +32 -39
  46. package/dist/adapters/telegram/bot.js.map +1 -1
  47. package/dist/adapters/telegram/context.d.ts.map +1 -1
  48. package/dist/adapters/telegram/context.js +33 -0
  49. package/dist/adapters/telegram/context.js.map +1 -1
  50. package/dist/adapters/telegram/types.d.ts +6 -0
  51. package/dist/adapters/telegram/types.d.ts.map +1 -0
  52. package/dist/adapters/telegram/types.js +2 -0
  53. package/dist/adapters/telegram/types.js.map +1 -0
  54. package/dist/adapters/types.d.ts +58 -0
  55. package/dist/adapters/types.d.ts.map +1 -0
  56. package/dist/adapters/types.js +2 -0
  57. package/dist/adapters/types.js.map +1 -0
  58. package/dist/agent.d.ts +4 -16
  59. package/dist/agent.d.ts.map +1 -1
  60. package/dist/agent.js +27 -20
  61. package/dist/agent.js.map +1 -1
  62. package/dist/commands/admin.d.ts.map +1 -1
  63. package/dist/commands/admin.js +1 -1
  64. package/dist/commands/admin.js.map +1 -1
  65. package/dist/commands/auto-reply.d.ts.map +1 -1
  66. package/dist/commands/auto-reply.js +1 -8
  67. package/dist/commands/auto-reply.js.map +1 -1
  68. package/dist/commands/login.d.ts.map +1 -1
  69. package/dist/commands/login.js +3 -3
  70. package/dist/commands/login.js.map +1 -1
  71. package/dist/commands/model.d.ts +5 -8
  72. package/dist/commands/model.d.ts.map +1 -1
  73. package/dist/commands/model.js +15 -20
  74. package/dist/commands/model.js.map +1 -1
  75. package/dist/commands/new.d.ts.map +1 -1
  76. package/dist/commands/new.js +5 -10
  77. package/dist/commands/new.js.map +1 -1
  78. package/dist/commands/parse.d.ts.map +1 -1
  79. package/dist/commands/parse.js +1 -4
  80. package/dist/commands/parse.js.map +1 -1
  81. package/dist/commands/registry.d.ts +1 -0
  82. package/dist/commands/registry.d.ts.map +1 -1
  83. package/dist/commands/registry.js +23 -0
  84. package/dist/commands/registry.js.map +1 -1
  85. package/dist/commands/sandbox.d.ts +2 -5
  86. package/dist/commands/sandbox.d.ts.map +1 -1
  87. package/dist/commands/sandbox.js +11 -16
  88. package/dist/commands/sandbox.js.map +1 -1
  89. package/dist/commands/session-view.d.ts.map +1 -1
  90. package/dist/commands/session-view.js +10 -15
  91. package/dist/commands/session-view.js.map +1 -1
  92. package/dist/commands/types.d.ts +11 -2
  93. package/dist/commands/types.d.ts.map +1 -1
  94. package/dist/commands/types.js.map +1 -1
  95. package/dist/config.d.ts +6 -28
  96. package/dist/config.d.ts.map +1 -1
  97. package/dist/config.js +43 -41
  98. package/dist/config.js.map +1 -1
  99. package/dist/context.d.ts +1 -15
  100. package/dist/context.d.ts.map +1 -1
  101. package/dist/context.js.map +1 -1
  102. package/dist/events.d.ts +3 -44
  103. package/dist/events.d.ts.map +1 -1
  104. package/dist/events.js +2 -9
  105. package/dist/events.js.map +1 -1
  106. package/dist/execution-resolver.d.ts +3 -7
  107. package/dist/execution-resolver.d.ts.map +1 -1
  108. package/dist/execution-resolver.js +8 -8
  109. package/dist/execution-resolver.js.map +1 -1
  110. package/dist/index.d.ts +3 -3
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +2 -2
  113. package/dist/index.js.map +1 -1
  114. package/dist/log.d.ts +2 -6
  115. package/dist/log.d.ts.map +1 -1
  116. package/dist/log.js +1 -37
  117. package/dist/log.js.map +1 -1
  118. package/dist/main.d.ts +1 -1
  119. package/dist/main.d.ts.map +1 -1
  120. package/dist/main.js +16 -16
  121. package/dist/main.js.map +1 -1
  122. package/dist/observability/instrument.d.ts.map +1 -0
  123. package/dist/{instrument.js → observability/instrument.js} +2 -2
  124. package/dist/observability/instrument.js.map +1 -0
  125. package/dist/{sentry.d.ts → observability/sentry.d.ts} +2 -30
  126. package/dist/observability/sentry.d.ts.map +1 -0
  127. package/dist/observability/sentry.js.map +1 -0
  128. package/dist/observability/types.d.ts +31 -0
  129. package/dist/observability/types.d.ts.map +1 -0
  130. package/dist/observability/types.js +2 -0
  131. package/dist/observability/types.js.map +1 -0
  132. package/dist/{ui-copy.d.ts → platform-messages.d.ts} +1 -1
  133. package/dist/platform-messages.d.ts.map +1 -0
  134. package/dist/{ui-copy.js → platform-messages.js} +1 -1
  135. package/dist/platform-messages.js.map +1 -0
  136. package/dist/portal-shell.d.ts +2 -28
  137. package/dist/portal-shell.d.ts.map +1 -1
  138. package/dist/portal-shell.js +2 -2
  139. package/dist/portal-shell.js.map +1 -1
  140. package/dist/provisioner.d.ts +2 -23
  141. package/dist/provisioner.d.ts.map +1 -1
  142. package/dist/provisioner.js +1 -1
  143. package/dist/provisioner.js.map +1 -1
  144. package/dist/runtime/conversation-orchestrator.d.ts +4 -19
  145. package/dist/runtime/conversation-orchestrator.d.ts.map +1 -1
  146. package/dist/runtime/conversation-orchestrator.js +3 -3
  147. package/dist/runtime/conversation-orchestrator.js.map +1 -1
  148. package/dist/runtime/session-runtime.d.ts +2 -23
  149. package/dist/runtime/session-runtime.d.ts.map +1 -1
  150. package/dist/runtime/session-runtime.js +7 -9
  151. package/dist/runtime/session-runtime.js.map +1 -1
  152. package/dist/runtime/types.d.ts +35 -0
  153. package/dist/runtime/types.d.ts.map +1 -0
  154. package/dist/runtime/types.js +2 -0
  155. package/dist/runtime/types.js.map +1 -0
  156. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  157. package/dist/sandbox/cloudflare.js +1 -1
  158. package/dist/sandbox/cloudflare.js.map +1 -1
  159. package/dist/sandbox/container.d.ts.map +1 -1
  160. package/dist/sandbox/container.js +1 -4
  161. package/dist/sandbox/container.js.map +1 -1
  162. package/dist/sessions/chat-session-manager.d.ts +2 -46
  163. package/dist/sessions/chat-session-manager.d.ts.map +1 -1
  164. package/dist/sessions/chat-session-manager.js +12 -40
  165. package/dist/sessions/chat-session-manager.js.map +1 -1
  166. package/dist/sessions/metadata.d.ts +1 -13
  167. package/dist/sessions/metadata.d.ts.map +1 -1
  168. package/dist/sessions/metadata.js.map +1 -1
  169. package/dist/sessions/policy.d.ts +3 -10
  170. package/dist/sessions/policy.d.ts.map +1 -1
  171. package/dist/sessions/policy.js.map +1 -1
  172. package/dist/sessions/store.d.ts +1 -12
  173. package/dist/sessions/store.d.ts.map +1 -1
  174. package/dist/sessions/store.js +4 -7
  175. package/dist/sessions/store.js.map +1 -1
  176. package/dist/sessions/types.d.ts +76 -0
  177. package/dist/sessions/types.d.ts.map +1 -0
  178. package/dist/sessions/types.js +2 -0
  179. package/dist/sessions/types.js.map +1 -0
  180. package/dist/store.d.ts +2 -19
  181. package/dist/store.d.ts.map +1 -1
  182. package/dist/store.js +1 -1
  183. package/dist/store.js.map +1 -1
  184. package/dist/tools/event.d.ts +30 -36
  185. package/dist/tools/event.d.ts.map +1 -1
  186. package/dist/tools/event.js +207 -26
  187. package/dist/tools/event.js.map +1 -1
  188. package/dist/tools/index.d.ts +2 -2
  189. package/dist/tools/index.d.ts.map +1 -1
  190. package/dist/tools/index.js.map +1 -1
  191. package/dist/tools/sandbox.d.ts.map +1 -1
  192. package/dist/tools/sandbox.js +1 -1
  193. package/dist/tools/sandbox.js.map +1 -1
  194. package/dist/tools/truncate.d.ts +2 -26
  195. package/dist/tools/truncate.d.ts.map +1 -1
  196. package/dist/tools/truncate.js.map +1 -1
  197. package/dist/tools/types.d.ts +54 -0
  198. package/dist/tools/types.d.ts.map +1 -0
  199. package/dist/tools/types.js +2 -0
  200. package/dist/tools/types.js.map +1 -0
  201. package/dist/trigger.d.ts +2 -13
  202. package/dist/trigger.d.ts.map +1 -1
  203. package/dist/trigger.js.map +1 -1
  204. package/dist/types.d.ts +307 -0
  205. package/dist/types.d.ts.map +1 -0
  206. package/dist/types.js +4 -0
  207. package/dist/types.js.map +1 -0
  208. package/dist/utils/date.d.ts +10 -0
  209. package/dist/utils/date.d.ts.map +1 -0
  210. package/dist/utils/date.js +23 -0
  211. package/dist/utils/date.js.map +1 -0
  212. package/dist/utils/env.d.ts.map +1 -0
  213. package/dist/utils/env.js.map +1 -0
  214. package/dist/utils/file-guards.d.ts.map +1 -0
  215. package/dist/utils/file-guards.js.map +1 -0
  216. package/dist/utils/fs-atomic.d.ts.map +1 -0
  217. package/dist/utils/fs-atomic.js.map +1 -0
  218. package/dist/utils/html.d.ts.map +1 -0
  219. package/dist/utils/html.js.map +1 -0
  220. package/dist/utils/http-body.d.ts +10 -0
  221. package/dist/utils/http-body.d.ts.map +1 -0
  222. package/dist/utils/http-body.js +34 -0
  223. package/dist/utils/http-body.js.map +1 -0
  224. package/dist/vault/index.d.ts +34 -0
  225. package/dist/vault/index.d.ts.map +1 -0
  226. package/dist/{vault.js → vault/index.js} +4 -4
  227. package/dist/vault/index.js.map +1 -0
  228. package/dist/{vault-routing.d.ts → vault/routing.d.ts} +2 -2
  229. package/dist/vault/routing.d.ts.map +1 -0
  230. package/dist/{vault-routing.js → vault/routing.js} +2 -2
  231. package/dist/vault/routing.js.map +1 -0
  232. package/dist/{vault.d.ts → vault/types.d.ts} +3 -34
  233. package/dist/vault/types.d.ts.map +1 -0
  234. package/dist/vault/types.js +2 -0
  235. package/dist/vault/types.js.map +1 -0
  236. package/dist/web/admin/portal.d.ts +5 -0
  237. package/dist/web/admin/portal.d.ts.map +1 -0
  238. package/dist/{admin → web/admin}/portal.js +140 -52
  239. package/dist/web/admin/portal.js.map +1 -0
  240. package/dist/web/admin/store.d.ts +13 -0
  241. package/dist/web/admin/store.d.ts.map +1 -0
  242. package/dist/web/admin/store.js +23 -0
  243. package/dist/web/admin/store.js.map +1 -0
  244. package/dist/web/admin/types.d.ts +28 -0
  245. package/dist/web/admin/types.d.ts.map +1 -0
  246. package/dist/web/admin/types.js +2 -0
  247. package/dist/web/admin/types.js.map +1 -0
  248. package/dist/web/login/oauth.d.ts +6 -0
  249. package/dist/web/login/oauth.d.ts.map +1 -0
  250. package/dist/{login/index.js → web/login/oauth.js} +33 -30
  251. package/dist/web/login/oauth.js.map +1 -0
  252. package/dist/{login → web/login}/portal.d.ts +5 -5
  253. package/dist/web/login/portal.d.ts.map +1 -0
  254. package/dist/{login → web/login}/portal.js +16 -35
  255. package/dist/web/login/portal.js.map +1 -0
  256. package/dist/web/login/store.d.ts +12 -0
  257. package/dist/web/login/store.d.ts.map +1 -0
  258. package/dist/web/login/store.js +28 -0
  259. package/dist/web/login/store.js.map +1 -0
  260. package/dist/web/login/types.d.ts +50 -0
  261. package/dist/web/login/types.d.ts.map +1 -0
  262. package/dist/web/login/types.js +2 -0
  263. package/dist/web/login/types.js.map +1 -0
  264. package/dist/web/session-view/command.d.ts +4 -0
  265. package/dist/web/session-view/command.d.ts.map +1 -0
  266. package/dist/{session-view → web/session-view}/command.js +1 -1
  267. package/dist/web/session-view/command.js.map +1 -0
  268. package/dist/{session-view → web/session-view}/portal.d.ts +2 -5
  269. package/dist/web/session-view/portal.d.ts.map +1 -0
  270. package/dist/{session-view → web/session-view}/portal.js +5 -5
  271. package/dist/web/session-view/portal.js.map +1 -0
  272. package/dist/web/session-view/service.d.ts +6 -0
  273. package/dist/web/session-view/service.d.ts.map +1 -0
  274. package/dist/{session-view → web/session-view}/service.js +6 -36
  275. package/dist/web/session-view/service.js.map +1 -0
  276. package/dist/web/session-view/store.d.ts +8 -0
  277. package/dist/web/session-view/store.d.ts.map +1 -0
  278. package/dist/web/session-view/store.js +20 -0
  279. package/dist/web/session-view/store.js.map +1 -0
  280. package/dist/{session-view/service.d.ts → web/session-view/types.d.ts} +20 -4
  281. package/dist/web/session-view/types.d.ts.map +1 -0
  282. package/dist/web/session-view/types.js +2 -0
  283. package/dist/web/session-view/types.js.map +1 -0
  284. package/dist/web/token-store.d.ts +19 -0
  285. package/dist/web/token-store.d.ts.map +1 -0
  286. package/dist/web/token-store.js +45 -0
  287. package/dist/web/token-store.js.map +1 -0
  288. package/dist/web/types.d.ts +5 -0
  289. package/dist/web/types.d.ts.map +1 -0
  290. package/dist/web/types.js +2 -0
  291. package/dist/web/types.js.map +1 -0
  292. package/package.json +1 -1
  293. package/dist/adapters/discord/index.d.ts +0 -3
  294. package/dist/adapters/discord/index.d.ts.map +0 -1
  295. package/dist/adapters/discord/index.js +0 -3
  296. package/dist/adapters/discord/index.js.map +0 -1
  297. package/dist/adapters/slack/index.d.ts +0 -3
  298. package/dist/adapters/slack/index.d.ts.map +0 -1
  299. package/dist/adapters/slack/index.js +0 -3
  300. package/dist/adapters/slack/index.js.map +0 -1
  301. package/dist/adapters/slack/thread-manager.d.ts +0 -19
  302. package/dist/adapters/slack/thread-manager.d.ts.map +0 -1
  303. package/dist/adapters/slack/thread-manager.js +0 -11
  304. package/dist/adapters/slack/thread-manager.js.map +0 -1
  305. package/dist/adapters/telegram/index.d.ts +0 -3
  306. package/dist/adapters/telegram/index.d.ts.map +0 -1
  307. package/dist/adapters/telegram/index.js +0 -3
  308. package/dist/adapters/telegram/index.js.map +0 -1
  309. package/dist/admin/portal.d.ts +0 -27
  310. package/dist/admin/portal.d.ts.map +0 -1
  311. package/dist/admin/portal.js.map +0 -1
  312. package/dist/admin/store.d.ts +0 -22
  313. package/dist/admin/store.d.ts.map +0 -1
  314. package/dist/admin/store.js +0 -39
  315. package/dist/admin/store.js.map +0 -1
  316. package/dist/commands/index.d.ts +0 -5
  317. package/dist/commands/index.d.ts.map +0 -1
  318. package/dist/commands/index.js +0 -20
  319. package/dist/commands/index.js.map +0 -1
  320. package/dist/env.d.ts.map +0 -1
  321. package/dist/env.js.map +0 -1
  322. package/dist/file-guards.d.ts.map +0 -1
  323. package/dist/file-guards.js.map +0 -1
  324. package/dist/fs-atomic.d.ts.map +0 -1
  325. package/dist/fs-atomic.js.map +0 -1
  326. package/dist/html.d.ts.map +0 -1
  327. package/dist/html.js.map +0 -1
  328. package/dist/instrument.d.ts.map +0 -1
  329. package/dist/instrument.js.map +0 -1
  330. package/dist/login/index.d.ts +0 -43
  331. package/dist/login/index.d.ts.map +0 -1
  332. package/dist/login/index.js.map +0 -1
  333. package/dist/login/portal.d.ts.map +0 -1
  334. package/dist/login/portal.js.map +0 -1
  335. package/dist/login/store.d.ts +0 -26
  336. package/dist/login/store.d.ts.map +0 -1
  337. package/dist/login/store.js +0 -56
  338. package/dist/login/store.js.map +0 -1
  339. package/dist/runtime/index.d.ts +0 -2
  340. package/dist/runtime/index.d.ts.map +0 -1
  341. package/dist/runtime/index.js +0 -2
  342. package/dist/runtime/index.js.map +0 -1
  343. package/dist/sentry.d.ts.map +0 -1
  344. package/dist/sentry.js.map +0 -1
  345. package/dist/session-view/command.d.ts +0 -5
  346. package/dist/session-view/command.d.ts.map +0 -1
  347. package/dist/session-view/command.js.map +0 -1
  348. package/dist/session-view/portal.d.ts.map +0 -1
  349. package/dist/session-view/portal.js.map +0 -1
  350. package/dist/session-view/service.d.ts.map +0 -1
  351. package/dist/session-view/service.js.map +0 -1
  352. package/dist/session-view/store.d.ts +0 -18
  353. package/dist/session-view/store.d.ts.map +0 -1
  354. package/dist/session-view/store.js +0 -36
  355. package/dist/session-view/store.js.map +0 -1
  356. package/dist/ui-copy.d.ts.map +0 -1
  357. package/dist/ui-copy.js.map +0 -1
  358. package/dist/vault-routing.d.ts.map +0 -1
  359. package/dist/vault-routing.js.map +0 -1
  360. package/dist/vault.d.ts.map +0 -1
  361. package/dist/vault.js.map +0 -1
  362. /package/dist/{instrument.d.ts → observability/instrument.d.ts} +0 -0
  363. /package/dist/{sentry.js → observability/sentry.js} +0 -0
  364. /package/dist/{env.d.ts → utils/env.d.ts} +0 -0
  365. /package/dist/{env.js → utils/env.js} +0 -0
  366. /package/dist/{file-guards.d.ts → utils/file-guards.d.ts} +0 -0
  367. /package/dist/{file-guards.js → utils/file-guards.js} +0 -0
  368. /package/dist/{fs-atomic.d.ts → utils/fs-atomic.d.ts} +0 -0
  369. /package/dist/{fs-atomic.js → utils/fs-atomic.js} +0 -0
  370. /package/dist/{html.d.ts → utils/html.d.ts} +0 -0
  371. /package/dist/{html.js → utils/html.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared truncation utilities for tool outputs.\n *\n * Truncation is based on two independent limits - whichever is hit first wins:\n * - Line limit (default: 2000 lines)\n * - Byte limit (default: 50KB)\n *\n * Never returns partial lines (except bash tail truncation edge case).\n */\n\nexport const DEFAULT_MAX_LINES = 2000;\nexport const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB\n\nexport interface TruncationResult {\n /** The truncated content */\n content: string;\n /** Whether truncation occurred */\n truncated: boolean;\n /** Which limit was hit: \"lines\", \"bytes\", or null if not truncated */\n truncatedBy: \"lines\" | \"bytes\" | null;\n /** Total number of lines in the original content */\n totalLines: number;\n /** Total number of bytes in the original content */\n totalBytes: number;\n /** Number of complete lines in the truncated output */\n outputLines: number;\n /** Number of bytes in the truncated output */\n outputBytes: number;\n /** Whether the last line was partially truncated (only for tail truncation edge case) */\n lastLinePartial: boolean;\n /** Whether the first line exceeded the byte limit (for head truncation) */\n firstLineExceedsLimit: boolean;\n}\n\nexport interface TruncationOptions {\n /** Maximum number of lines (default: 2000) */\n maxLines?: number;\n /** Maximum number of bytes (default: 50KB) */\n maxBytes?: number;\n}\n\n/**\n * Format bytes as human-readable size.\n */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes}B`;\n } else if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)}KB`;\n } else {\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n }\n}\n\n/**\n * Truncate content from the head (keep first N lines/bytes).\n * Suitable for file reads where you want to see the beginning.\n *\n * Never returns partial lines. If first line exceeds byte limit,\n * returns empty content with firstLineExceedsLimit=true.\n */\nexport function truncateHead(content: string, options: TruncationOptions = {}): TruncationResult {\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n const totalBytes = Buffer.byteLength(content, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n\n // Check if no truncation needed\n if (totalLines <= maxLines && totalBytes <= maxBytes) {\n return {\n content,\n truncated: false,\n truncatedBy: null,\n totalLines,\n totalBytes,\n outputLines: totalLines,\n outputBytes: totalBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n }\n\n // Check if first line alone exceeds byte limit\n const firstLineBytes = Buffer.byteLength(lines[0], \"utf-8\");\n if (firstLineBytes > maxBytes) {\n return {\n content: \"\",\n truncated: true,\n truncatedBy: \"bytes\",\n totalLines,\n totalBytes,\n outputLines: 0,\n outputBytes: 0,\n lastLinePartial: false,\n firstLineExceedsLimit: true,\n };\n }\n\n // Collect complete lines that fit\n const outputLinesArr: string[] = [];\n let outputBytesCount = 0;\n let truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n\n for (let i = 0; i < lines.length && i < maxLines; i++) {\n const line = lines[i];\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + (i > 0 ? 1 : 0); // +1 for newline\n\n if (outputBytesCount + lineBytes > maxBytes) {\n truncatedBy = \"bytes\";\n break;\n }\n\n outputLinesArr.push(line);\n outputBytesCount += lineBytes;\n }\n\n // If we exited due to line limit\n if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n truncatedBy = \"lines\";\n }\n\n const outputContent = outputLinesArr.join(\"\\n\");\n const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n\n return {\n content: outputContent,\n truncated: true,\n truncatedBy,\n totalLines,\n totalBytes,\n outputLines: outputLinesArr.length,\n outputBytes: finalOutputBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n}\n\n/**\n * Truncate content from the tail (keep last N lines/bytes).\n * Suitable for bash output where you want to see the end (errors, final results).\n *\n * May return partial first line if the last line of original content exceeds byte limit.\n */\nexport function truncateTail(content: string, options: TruncationOptions = {}): TruncationResult {\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n const totalBytes = Buffer.byteLength(content, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n\n // Check if no truncation needed\n if (totalLines <= maxLines && totalBytes <= maxBytes) {\n return {\n content,\n truncated: false,\n truncatedBy: null,\n totalLines,\n totalBytes,\n outputLines: totalLines,\n outputBytes: totalBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n }\n\n // Work backwards from the end\n const outputLinesArr: string[] = [];\n let outputBytesCount = 0;\n let truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n let lastLinePartial = false;\n\n for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {\n const line = lines[i];\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + (outputLinesArr.length > 0 ? 1 : 0); // +1 for newline\n\n if (outputBytesCount + lineBytes > maxBytes) {\n truncatedBy = \"bytes\";\n // Edge case: if we haven't added ANY lines yet and this line exceeds maxBytes,\n // take the end of the line (partial)\n if (outputLinesArr.length === 0) {\n const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);\n outputLinesArr.unshift(truncatedLine);\n outputBytesCount = Buffer.byteLength(truncatedLine, \"utf-8\");\n lastLinePartial = true;\n }\n break;\n }\n\n outputLinesArr.unshift(line);\n outputBytesCount += lineBytes;\n }\n\n // If we exited due to line limit\n if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n truncatedBy = \"lines\";\n }\n\n const outputContent = outputLinesArr.join(\"\\n\");\n const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n\n return {\n content: outputContent,\n truncated: true,\n truncatedBy,\n totalLines,\n totalBytes,\n outputLines: outputLinesArr.length,\n outputBytes: finalOutputBytes,\n lastLinePartial,\n firstLineExceedsLimit: false,\n };\n}\n\n/**\n * Truncate a string to fit within a byte limit (from the end).\n * Handles multi-byte UTF-8 characters correctly.\n */\nfunction truncateStringToBytesFromEnd(str: string, maxBytes: number): string {\n const buf = Buffer.from(str, \"utf-8\");\n if (buf.length <= maxBytes) {\n return str;\n }\n\n // Start from the end, skip maxBytes back\n let start = buf.length - maxBytes;\n\n // Find a valid UTF-8 boundary (start of a character)\n while (start < buf.length && (buf[start] & 0xc0) === 0x80) {\n start++;\n }\n\n return buf.slice(start).toString(\"utf-8\");\n}\n"]}
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared truncation utilities for tool outputs.\n *\n * Truncation is based on two independent limits - whichever is hit first wins:\n * - Line limit (default: 2000 lines)\n * - Byte limit (default: 50KB)\n *\n * Never returns partial lines (except bash tail truncation edge case).\n */\n\nexport const DEFAULT_MAX_LINES = 2000;\nexport const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB\n\nexport type { TruncationOptions, TruncationResult } from \"./types.js\";\nimport type { TruncationOptions, TruncationResult } from \"./types.js\";\n\n/**\n * Format bytes as human-readable size.\n */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes}B`;\n } else if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)}KB`;\n } else {\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n }\n}\n\n/**\n * Truncate content from the head (keep first N lines/bytes).\n * Suitable for file reads where you want to see the beginning.\n *\n * Never returns partial lines. If first line exceeds byte limit,\n * returns empty content with firstLineExceedsLimit=true.\n */\nexport function truncateHead(content: string, options: TruncationOptions = {}): TruncationResult {\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n const totalBytes = Buffer.byteLength(content, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n\n // Check if no truncation needed\n if (totalLines <= maxLines && totalBytes <= maxBytes) {\n return {\n content,\n truncated: false,\n truncatedBy: null,\n totalLines,\n totalBytes,\n outputLines: totalLines,\n outputBytes: totalBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n }\n\n // Check if first line alone exceeds byte limit\n const firstLineBytes = Buffer.byteLength(lines[0], \"utf-8\");\n if (firstLineBytes > maxBytes) {\n return {\n content: \"\",\n truncated: true,\n truncatedBy: \"bytes\",\n totalLines,\n totalBytes,\n outputLines: 0,\n outputBytes: 0,\n lastLinePartial: false,\n firstLineExceedsLimit: true,\n };\n }\n\n // Collect complete lines that fit\n const outputLinesArr: string[] = [];\n let outputBytesCount = 0;\n let truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n\n for (let i = 0; i < lines.length && i < maxLines; i++) {\n const line = lines[i];\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + (i > 0 ? 1 : 0); // +1 for newline\n\n if (outputBytesCount + lineBytes > maxBytes) {\n truncatedBy = \"bytes\";\n break;\n }\n\n outputLinesArr.push(line);\n outputBytesCount += lineBytes;\n }\n\n // If we exited due to line limit\n if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n truncatedBy = \"lines\";\n }\n\n const outputContent = outputLinesArr.join(\"\\n\");\n const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n\n return {\n content: outputContent,\n truncated: true,\n truncatedBy,\n totalLines,\n totalBytes,\n outputLines: outputLinesArr.length,\n outputBytes: finalOutputBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n}\n\n/**\n * Truncate content from the tail (keep last N lines/bytes).\n * Suitable for bash output where you want to see the end (errors, final results).\n *\n * May return partial first line if the last line of original content exceeds byte limit.\n */\nexport function truncateTail(content: string, options: TruncationOptions = {}): TruncationResult {\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n const totalBytes = Buffer.byteLength(content, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n\n // Check if no truncation needed\n if (totalLines <= maxLines && totalBytes <= maxBytes) {\n return {\n content,\n truncated: false,\n truncatedBy: null,\n totalLines,\n totalBytes,\n outputLines: totalLines,\n outputBytes: totalBytes,\n lastLinePartial: false,\n firstLineExceedsLimit: false,\n };\n }\n\n // Work backwards from the end\n const outputLinesArr: string[] = [];\n let outputBytesCount = 0;\n let truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n let lastLinePartial = false;\n\n for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {\n const line = lines[i];\n const lineBytes = Buffer.byteLength(line, \"utf-8\") + (outputLinesArr.length > 0 ? 1 : 0); // +1 for newline\n\n if (outputBytesCount + lineBytes > maxBytes) {\n truncatedBy = \"bytes\";\n // Edge case: if we haven't added ANY lines yet and this line exceeds maxBytes,\n // take the end of the line (partial)\n if (outputLinesArr.length === 0) {\n const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);\n outputLinesArr.unshift(truncatedLine);\n outputBytesCount = Buffer.byteLength(truncatedLine, \"utf-8\");\n lastLinePartial = true;\n }\n break;\n }\n\n outputLinesArr.unshift(line);\n outputBytesCount += lineBytes;\n }\n\n // If we exited due to line limit\n if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\n truncatedBy = \"lines\";\n }\n\n const outputContent = outputLinesArr.join(\"\\n\");\n const finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\n\n return {\n content: outputContent,\n truncated: true,\n truncatedBy,\n totalLines,\n totalBytes,\n outputLines: outputLinesArr.length,\n outputBytes: finalOutputBytes,\n lastLinePartial,\n firstLineExceedsLimit: false,\n };\n}\n\n/**\n * Truncate a string to fit within a byte limit (from the end).\n * Handles multi-byte UTF-8 characters correctly.\n */\nfunction truncateStringToBytesFromEnd(str: string, maxBytes: number): string {\n const buf = Buffer.from(str, \"utf-8\");\n if (buf.length <= maxBytes) {\n return str;\n }\n\n // Start from the end, skip maxBytes back\n let start = buf.length - maxBytes;\n\n // Find a valid UTF-8 boundary (start of a character)\n while (start < buf.length && (buf[start] & 0xc0) === 0x80) {\n start++;\n }\n\n return buf.slice(start).toString(\"utf-8\");\n}\n"]}
@@ -0,0 +1,54 @@
1
+ import type { MikanEvent } from "../types.js";
2
+ export type EventPayload = MikanEvent;
3
+ export interface EventStore {
4
+ write(filename: string, payload: MikanEvent): Promise<{
5
+ path: string;
6
+ size: number;
7
+ }>;
8
+ list(): Promise<Array<{
9
+ filename: string;
10
+ payload: MikanEvent;
11
+ size: number;
12
+ mtimeMs: number;
13
+ }>>;
14
+ read(filename: string): Promise<{
15
+ filename: string;
16
+ payload: MikanEvent;
17
+ size: number;
18
+ mtimeMs: number;
19
+ }>;
20
+ update(filename: string, payload: MikanEvent): Promise<{
21
+ path: string;
22
+ size: number;
23
+ }>;
24
+ delete(filename: string): Promise<{
25
+ deleted: boolean;
26
+ }>;
27
+ }
28
+ export interface TruncationResult {
29
+ /** The truncated content */
30
+ content: string;
31
+ /** Whether truncation occurred */
32
+ truncated: boolean;
33
+ /** Which limit was hit: "lines", "bytes", or null if not truncated */
34
+ truncatedBy: "lines" | "bytes" | null;
35
+ /** Total number of lines in the original content */
36
+ totalLines: number;
37
+ /** Total number of bytes in the original content */
38
+ totalBytes: number;
39
+ /** Number of complete lines in the truncated output */
40
+ outputLines: number;
41
+ /** Number of bytes in the truncated output */
42
+ outputBytes: number;
43
+ /** Whether the last line was partially truncated (only for tail truncation edge case) */
44
+ lastLinePartial: boolean;
45
+ /** Whether the first line exceeded the byte limit (for head truncation) */
46
+ firstLineExceedsLimit: boolean;
47
+ }
48
+ export interface TruncationOptions {
49
+ /** Maximum number of lines (default: 2000) */
50
+ maxLines?: number;
51
+ /** Maximum number of bytes (default: 50KB) */
52
+ maxBytes?: number;
53
+ }
54
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC;AAEtC,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtF,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjG,IAAI,CACF,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrF,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvF,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACzD;AAID,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,eAAe,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB","sourcesContent":["import type { MikanEvent } from \"../types.js\";\n\n// ── event tool ───────────────────────────────────────────────────────────────\n\nexport type EventPayload = MikanEvent;\n\nexport interface EventStore {\n write(filename: string, payload: MikanEvent): Promise<{ path: string; size: number }>;\n list(): Promise<Array<{ filename: string; payload: MikanEvent; size: number; mtimeMs: number }>>;\n read(\n filename: string,\n ): Promise<{ filename: string; payload: MikanEvent; size: number; mtimeMs: number }>;\n update(filename: string, payload: MikanEvent): Promise<{ path: string; size: number }>;\n delete(filename: string): Promise<{ deleted: boolean }>;\n}\n\n// ── truncation ───────────────────────────────────────────────────────────────\n\nexport interface TruncationResult {\n /** The truncated content */\n content: string;\n /** Whether truncation occurred */\n truncated: boolean;\n /** Which limit was hit: \"lines\", \"bytes\", or null if not truncated */\n truncatedBy: \"lines\" | \"bytes\" | null;\n /** Total number of lines in the original content */\n totalLines: number;\n /** Total number of bytes in the original content */\n totalBytes: number;\n /** Number of complete lines in the truncated output */\n outputLines: number;\n /** Number of bytes in the truncated output */\n outputBytes: number;\n /** Whether the last line was partially truncated (only for tail truncation edge case) */\n lastLinePartial: boolean;\n /** Whether the first line exceeded the byte limit (for head truncation) */\n firstLineExceedsLimit: boolean;\n}\n\nexport interface TruncationOptions {\n /** Maximum number of lines (default: 2000) */\n maxLines?: number;\n /** Maximum number of bytes (default: 50KB) */\n maxBytes?: number;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MikanEvent } from \"../types.js\";\n\n// ── event tool ───────────────────────────────────────────────────────────────\n\nexport type EventPayload = MikanEvent;\n\nexport interface EventStore {\n write(filename: string, payload: MikanEvent): Promise<{ path: string; size: number }>;\n list(): Promise<Array<{ filename: string; payload: MikanEvent; size: number; mtimeMs: number }>>;\n read(\n filename: string,\n ): Promise<{ filename: string; payload: MikanEvent; size: number; mtimeMs: number }>;\n update(filename: string, payload: MikanEvent): Promise<{ path: string; size: number }>;\n delete(filename: string): Promise<{ deleted: boolean }>;\n}\n\n// ── truncation ───────────────────────────────────────────────────────────────\n\nexport interface TruncationResult {\n /** The truncated content */\n content: string;\n /** Whether truncation occurred */\n truncated: boolean;\n /** Which limit was hit: \"lines\", \"bytes\", or null if not truncated */\n truncatedBy: \"lines\" | \"bytes\" | null;\n /** Total number of lines in the original content */\n totalLines: number;\n /** Total number of bytes in the original content */\n totalBytes: number;\n /** Number of complete lines in the truncated output */\n outputLines: number;\n /** Number of bytes in the truncated output */\n outputBytes: number;\n /** Whether the last line was partially truncated (only for tail truncation edge case) */\n lastLinePartial: boolean;\n /** Whether the first line exceeded the byte limit (for head truncation) */\n firstLineExceedsLimit: boolean;\n}\n\nexport interface TruncationOptions {\n /** Maximum number of lines (default: 2000) */\n maxLines?: number;\n /** Maximum number of bytes (default: 50KB) */\n maxBytes?: number;\n}\n"]}
package/dist/trigger.d.ts CHANGED
@@ -1,17 +1,6 @@
1
1
  import type { BotEvent } from "./adapter.js";
2
- export type TriggerIntent = "mention" | "direct" | "thread-continuation" | "auto-reply-candidate";
3
- export type TriggerResult = {
4
- trigger: true;
5
- reason: string;
6
- } | {
7
- trigger: false;
8
- reason: string;
9
- };
10
- export type AutoReplyJudge = (input: {
11
- event: BotEvent;
12
- rules: string[];
13
- conversationDir: string;
14
- }) => Promise<boolean>;
2
+ export type { AutoReplyJudge, TriggerIntent, TriggerResult } from "./types.js";
3
+ import type { AutoReplyJudge, TriggerIntent, TriggerResult } from "./types.js";
15
4
  /**
16
5
  * Trivially decide non-auto-reply intents synchronously. For "auto-reply-candidate"
17
6
  * callers must use {@link evaluateAutoReplyPolicy}.
@@ -1 +1 @@
1
- {"version":3,"file":"trigger.d.ts","sourceRoot":"","sources":["../src/trigger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAO7C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,qBAAqB,GAAG,sBAAsB,CAAC;AAElG,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvB;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,GACrD,aAAa,CAEf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4BzB","sourcesContent":["import { completeSimple, getModel, type Api, type Model } from \"@earendil-works/pi-ai\";\nimport type { BotEvent } from \"./adapter.js\";\nimport { loadAutoReplyJudgeModel, loadConversationAutoReplyConfig } from \"./config.js\";\nimport * as log from \"./log.js\";\nimport { join } from \"path\";\n\nconst JUDGE_TIMEOUT_MS = 10_000;\n\nexport type TriggerIntent = \"mention\" | \"direct\" | \"thread-continuation\" | \"auto-reply-candidate\";\n\nexport type TriggerResult = { trigger: true; reason: string } | { trigger: false; reason: string };\n\nexport type AutoReplyJudge = (input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}) => Promise<boolean>;\n\n/**\n * Trivially decide non-auto-reply intents synchronously. For \"auto-reply-candidate\"\n * callers must use {@link evaluateAutoReplyPolicy}.\n */\nexport function decideTrigger(\n intent: Exclude<TriggerIntent, \"auto-reply-candidate\">,\n): TriggerResult {\n return { trigger: true, reason: intent };\n}\n\n/**\n * Decide whether to auto-reply. Never throws — judge errors and timeouts are\n * folded into a `trigger: false` result with a distinct reason, so adapters\n * can apply a single uniform \"do not trigger, but still log\" policy.\n */\nexport async function evaluateAutoReplyPolicy(input: {\n event: BotEvent;\n workingDir: string | undefined;\n judge?: AutoReplyJudge;\n timeoutMs?: number;\n}): Promise<TriggerResult> {\n const { event, workingDir, judge = judgeAutoReplyWithLlm, timeoutMs = JUDGE_TIMEOUT_MS } = input;\n if (!workingDir) return { trigger: false, reason: \"auto-reply-unconfigured\" };\n\n const conversationDir = join(workingDir, event.conversationId);\n\n try {\n const config = loadConversationAutoReplyConfig(conversationDir);\n if (!config.enabled) return { trigger: false, reason: \"auto-reply-disabled\" };\n if (config.rules.length === 0) {\n return { trigger: true, reason: \"auto-reply-enabled\" };\n }\n\n const shouldReply = await withTimeout(\n judge({ event, rules: config.rules, conversationDir }),\n timeoutMs,\n );\n return shouldReply\n ? { trigger: true, reason: \"auto-reply-rule-match\" }\n : { trigger: false, reason: \"auto-reply-rule-no-match\" };\n } catch (err) {\n if (err instanceof JudgeTimeoutError) {\n log.logWarning(\"Auto-reply judge timed out\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-timeout\" };\n }\n log.logWarning(\"Auto-reply policy evaluation failed\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-failed\" };\n }\n}\n\nclass JudgeTimeoutError extends Error {\n constructor(ms: number) {\n super(`auto-reply judge exceeded ${ms}ms`);\n this.name = \"JudgeTimeoutError\";\n }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new JudgeTimeoutError(ms)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nasync function judgeAutoReplyWithLlm(input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}): Promise<boolean> {\n const judgeConfig = loadAutoReplyJudgeModel(input.conversationDir);\n // Config stores provider/model as user-provided strings, while getModel's public\n // overload is narrowed to generated known providers.\n const model = getModel(judgeConfig.provider as never, judgeConfig.model as never) as Model<Api>;\n const answer = await completeSimple(\n model,\n {\n systemPrompt:\n \"You decide whether a bot should reply to a group/channel message. \" +\n \"Use only the rules provided by the user. Answer exactly YES or NO.\",\n messages: [\n {\n role: \"user\",\n timestamp: Date.now(),\n content: [\n \"Rules:\",\n ...input.rules.map((rule, index) => `${index + 1}. ${rule}`),\n \"\",\n \"Message:\",\n input.event.text,\n \"\",\n \"Should the bot reply? Answer exactly YES or NO.\",\n ].join(\"\\n\"),\n },\n ],\n },\n {\n temperature: 0,\n maxTokens: 4,\n reasoning: \"minimal\",\n },\n );\n const text = answer.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n .toUpperCase();\n return /^YES\\b/.test(text);\n}\n"]}
1
+ {"version":3,"file":"trigger.d.ts","sourceRoot":"","sources":["../src/trigger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAO7C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,GACrD,aAAa,CAEf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4BzB","sourcesContent":["import { completeSimple, getModel, type Api, type Model } from \"@earendil-works/pi-ai\";\nimport type { BotEvent } from \"./adapter.js\";\nimport { loadAutoReplyJudgeModel, loadConversationAutoReplyConfig } from \"./config.js\";\nimport * as log from \"./log.js\";\nimport { join } from \"path\";\n\nconst JUDGE_TIMEOUT_MS = 10_000;\n\nexport type { AutoReplyJudge, TriggerIntent, TriggerResult } from \"./types.js\";\nimport type { AutoReplyJudge, TriggerIntent, TriggerResult } from \"./types.js\";\n\n/**\n * Trivially decide non-auto-reply intents synchronously. For \"auto-reply-candidate\"\n * callers must use {@link evaluateAutoReplyPolicy}.\n */\nexport function decideTrigger(\n intent: Exclude<TriggerIntent, \"auto-reply-candidate\">,\n): TriggerResult {\n return { trigger: true, reason: intent };\n}\n\n/**\n * Decide whether to auto-reply. Never throws — judge errors and timeouts are\n * folded into a `trigger: false` result with a distinct reason, so adapters\n * can apply a single uniform \"do not trigger, but still log\" policy.\n */\nexport async function evaluateAutoReplyPolicy(input: {\n event: BotEvent;\n workingDir: string | undefined;\n judge?: AutoReplyJudge;\n timeoutMs?: number;\n}): Promise<TriggerResult> {\n const { event, workingDir, judge = judgeAutoReplyWithLlm, timeoutMs = JUDGE_TIMEOUT_MS } = input;\n if (!workingDir) return { trigger: false, reason: \"auto-reply-unconfigured\" };\n\n const conversationDir = join(workingDir, event.conversationId);\n\n try {\n const config = loadConversationAutoReplyConfig(conversationDir);\n if (!config.enabled) return { trigger: false, reason: \"auto-reply-disabled\" };\n if (config.rules.length === 0) {\n return { trigger: true, reason: \"auto-reply-enabled\" };\n }\n\n const shouldReply = await withTimeout(\n judge({ event, rules: config.rules, conversationDir }),\n timeoutMs,\n );\n return shouldReply\n ? { trigger: true, reason: \"auto-reply-rule-match\" }\n : { trigger: false, reason: \"auto-reply-rule-no-match\" };\n } catch (err) {\n if (err instanceof JudgeTimeoutError) {\n log.logWarning(\"Auto-reply judge timed out\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-timeout\" };\n }\n log.logWarning(\"Auto-reply policy evaluation failed\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-failed\" };\n }\n}\n\nclass JudgeTimeoutError extends Error {\n constructor(ms: number) {\n super(`auto-reply judge exceeded ${ms}ms`);\n this.name = \"JudgeTimeoutError\";\n }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new JudgeTimeoutError(ms)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nasync function judgeAutoReplyWithLlm(input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}): Promise<boolean> {\n const judgeConfig = loadAutoReplyJudgeModel(input.conversationDir);\n // Config stores provider/model as user-provided strings, while getModel's public\n // overload is narrowed to generated known providers.\n const model = getModel(judgeConfig.provider as never, judgeConfig.model as never) as Model<Api>;\n const answer = await completeSimple(\n model,\n {\n systemPrompt:\n \"You decide whether a bot should reply to a group/channel message. \" +\n \"Use only the rules provided by the user. Answer exactly YES or NO.\",\n messages: [\n {\n role: \"user\",\n timestamp: Date.now(),\n content: [\n \"Rules:\",\n ...input.rules.map((rule, index) => `${index + 1}. ${rule}`),\n \"\",\n \"Message:\",\n input.event.text,\n \"\",\n \"Should the bot reply? Answer exactly YES or NO.\",\n ].join(\"\\n\"),\n },\n ],\n },\n {\n temperature: 0,\n maxTokens: 4,\n reasoning: \"minimal\",\n },\n );\n const text = answer.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n .toUpperCase();\n return /^YES\\b/.test(text);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"trigger.js","sourceRoot":"","sources":["../src/trigger.ts"],"names":[],"mappings":"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","sourcesContent":["import { completeSimple, getModel, type Api, type Model } from \"@earendil-works/pi-ai\";\nimport type { BotEvent } from \"./adapter.js\";\nimport { loadAutoReplyJudgeModel, loadConversationAutoReplyConfig } from \"./config.js\";\nimport * as log from \"./log.js\";\nimport { join } from \"path\";\n\nconst JUDGE_TIMEOUT_MS = 10_000;\n\nexport type TriggerIntent = \"mention\" | \"direct\" | \"thread-continuation\" | \"auto-reply-candidate\";\n\nexport type TriggerResult = { trigger: true; reason: string } | { trigger: false; reason: string };\n\nexport type AutoReplyJudge = (input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}) => Promise<boolean>;\n\n/**\n * Trivially decide non-auto-reply intents synchronously. For \"auto-reply-candidate\"\n * callers must use {@link evaluateAutoReplyPolicy}.\n */\nexport function decideTrigger(\n intent: Exclude<TriggerIntent, \"auto-reply-candidate\">,\n): TriggerResult {\n return { trigger: true, reason: intent };\n}\n\n/**\n * Decide whether to auto-reply. Never throws — judge errors and timeouts are\n * folded into a `trigger: false` result with a distinct reason, so adapters\n * can apply a single uniform \"do not trigger, but still log\" policy.\n */\nexport async function evaluateAutoReplyPolicy(input: {\n event: BotEvent;\n workingDir: string | undefined;\n judge?: AutoReplyJudge;\n timeoutMs?: number;\n}): Promise<TriggerResult> {\n const { event, workingDir, judge = judgeAutoReplyWithLlm, timeoutMs = JUDGE_TIMEOUT_MS } = input;\n if (!workingDir) return { trigger: false, reason: \"auto-reply-unconfigured\" };\n\n const conversationDir = join(workingDir, event.conversationId);\n\n try {\n const config = loadConversationAutoReplyConfig(conversationDir);\n if (!config.enabled) return { trigger: false, reason: \"auto-reply-disabled\" };\n if (config.rules.length === 0) {\n return { trigger: true, reason: \"auto-reply-enabled\" };\n }\n\n const shouldReply = await withTimeout(\n judge({ event, rules: config.rules, conversationDir }),\n timeoutMs,\n );\n return shouldReply\n ? { trigger: true, reason: \"auto-reply-rule-match\" }\n : { trigger: false, reason: \"auto-reply-rule-no-match\" };\n } catch (err) {\n if (err instanceof JudgeTimeoutError) {\n log.logWarning(\"Auto-reply judge timed out\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-timeout\" };\n }\n log.logWarning(\"Auto-reply policy evaluation failed\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-failed\" };\n }\n}\n\nclass JudgeTimeoutError extends Error {\n constructor(ms: number) {\n super(`auto-reply judge exceeded ${ms}ms`);\n this.name = \"JudgeTimeoutError\";\n }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new JudgeTimeoutError(ms)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nasync function judgeAutoReplyWithLlm(input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}): Promise<boolean> {\n const judgeConfig = loadAutoReplyJudgeModel(input.conversationDir);\n // Config stores provider/model as user-provided strings, while getModel's public\n // overload is narrowed to generated known providers.\n const model = getModel(judgeConfig.provider as never, judgeConfig.model as never) as Model<Api>;\n const answer = await completeSimple(\n model,\n {\n systemPrompt:\n \"You decide whether a bot should reply to a group/channel message. \" +\n \"Use only the rules provided by the user. Answer exactly YES or NO.\",\n messages: [\n {\n role: \"user\",\n timestamp: Date.now(),\n content: [\n \"Rules:\",\n ...input.rules.map((rule, index) => `${index + 1}. ${rule}`),\n \"\",\n \"Message:\",\n input.event.text,\n \"\",\n \"Should the bot reply? Answer exactly YES or NO.\",\n ].join(\"\\n\"),\n },\n ],\n },\n {\n temperature: 0,\n maxTokens: 4,\n reasoning: \"minimal\",\n },\n );\n const text = answer.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n .toUpperCase();\n return /^YES\\b/.test(text);\n}\n"]}
1
+ {"version":3,"file":"trigger.js","sourceRoot":"","sources":["../src/trigger.ts"],"names":[],"mappings":"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","sourcesContent":["import { completeSimple, getModel, type Api, type Model } from \"@earendil-works/pi-ai\";\nimport type { BotEvent } from \"./adapter.js\";\nimport { loadAutoReplyJudgeModel, loadConversationAutoReplyConfig } from \"./config.js\";\nimport * as log from \"./log.js\";\nimport { join } from \"path\";\n\nconst JUDGE_TIMEOUT_MS = 10_000;\n\nexport type { AutoReplyJudge, TriggerIntent, TriggerResult } from \"./types.js\";\nimport type { AutoReplyJudge, TriggerIntent, TriggerResult } from \"./types.js\";\n\n/**\n * Trivially decide non-auto-reply intents synchronously. For \"auto-reply-candidate\"\n * callers must use {@link evaluateAutoReplyPolicy}.\n */\nexport function decideTrigger(\n intent: Exclude<TriggerIntent, \"auto-reply-candidate\">,\n): TriggerResult {\n return { trigger: true, reason: intent };\n}\n\n/**\n * Decide whether to auto-reply. Never throws — judge errors and timeouts are\n * folded into a `trigger: false` result with a distinct reason, so adapters\n * can apply a single uniform \"do not trigger, but still log\" policy.\n */\nexport async function evaluateAutoReplyPolicy(input: {\n event: BotEvent;\n workingDir: string | undefined;\n judge?: AutoReplyJudge;\n timeoutMs?: number;\n}): Promise<TriggerResult> {\n const { event, workingDir, judge = judgeAutoReplyWithLlm, timeoutMs = JUDGE_TIMEOUT_MS } = input;\n if (!workingDir) return { trigger: false, reason: \"auto-reply-unconfigured\" };\n\n const conversationDir = join(workingDir, event.conversationId);\n\n try {\n const config = loadConversationAutoReplyConfig(conversationDir);\n if (!config.enabled) return { trigger: false, reason: \"auto-reply-disabled\" };\n if (config.rules.length === 0) {\n return { trigger: true, reason: \"auto-reply-enabled\" };\n }\n\n const shouldReply = await withTimeout(\n judge({ event, rules: config.rules, conversationDir }),\n timeoutMs,\n );\n return shouldReply\n ? { trigger: true, reason: \"auto-reply-rule-match\" }\n : { trigger: false, reason: \"auto-reply-rule-no-match\" };\n } catch (err) {\n if (err instanceof JudgeTimeoutError) {\n log.logWarning(\"Auto-reply judge timed out\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-timeout\" };\n }\n log.logWarning(\"Auto-reply policy evaluation failed\", String(err));\n return { trigger: false, reason: \"auto-reply-judge-failed\" };\n }\n}\n\nclass JudgeTimeoutError extends Error {\n constructor(ms: number) {\n super(`auto-reply judge exceeded ${ms}ms`);\n this.name = \"JudgeTimeoutError\";\n }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new JudgeTimeoutError(ms)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nasync function judgeAutoReplyWithLlm(input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}): Promise<boolean> {\n const judgeConfig = loadAutoReplyJudgeModel(input.conversationDir);\n // Config stores provider/model as user-provided strings, while getModel's public\n // overload is narrowed to generated known providers.\n const model = getModel(judgeConfig.provider as never, judgeConfig.model as never) as Model<Api>;\n const answer = await completeSimple(\n model,\n {\n systemPrompt:\n \"You decide whether a bot should reply to a group/channel message. \" +\n \"Use only the rules provided by the user. Answer exactly YES or NO.\",\n messages: [\n {\n role: \"user\",\n timestamp: Date.now(),\n content: [\n \"Rules:\",\n ...input.rules.map((rule, index) => `${index + 1}. ${rule}`),\n \"\",\n \"Message:\",\n input.event.text,\n \"\",\n \"Should the bot reply? Answer exactly YES or NO.\",\n ].join(\"\\n\"),\n },\n ],\n },\n {\n temperature: 0,\n maxTokens: 4,\n reasoning: \"minimal\",\n },\n );\n const text = answer.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n .toUpperCase();\n return /^YES\\b/.test(text);\n}\n"]}
@@ -0,0 +1,307 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import { execFile } from "child_process";
3
+ declare const _execFileAsync: typeof execFile.__promisify__;
4
+ type ExecFileAsync = typeof _execFileAsync;
5
+ export type ConversationKind = "direct" | "shared";
6
+ export type PlatformName = "slack" | "discord" | "telegram";
7
+ export interface ChatMessage {
8
+ id: string;
9
+ sessionKey: string;
10
+ conversationKind: ConversationKind;
11
+ userId: string;
12
+ userName?: string;
13
+ text: string;
14
+ attachments?: {
15
+ name: string;
16
+ localPath: string;
17
+ }[];
18
+ threadTs?: string;
19
+ }
20
+ export interface ChatToolResult {
21
+ toolName: string;
22
+ label?: string;
23
+ args?: Record<string, unknown>;
24
+ result: string;
25
+ isError: boolean;
26
+ durationMs: number;
27
+ }
28
+ export interface ChatResponseBlockKit {
29
+ text: string;
30
+ blocks: object[];
31
+ }
32
+ export interface ChatResponseContext {
33
+ respond(text: string): Promise<void>;
34
+ appendResponseDelta?(delta: string): Promise<void>;
35
+ finishResponse?(finalText?: string): Promise<void>;
36
+ replaceResponse(text: string, options?: {
37
+ createOverflowLink?: () => string;
38
+ }): Promise<void>;
39
+ respondDiagnostic(text: string, options?: {
40
+ style?: "muted" | "error";
41
+ }): Promise<void>;
42
+ respondToolResult(result: ChatToolResult): Promise<void>;
43
+ respondBlockKit?(response: ChatResponseBlockKit): Promise<void>;
44
+ setTyping(isTyping: boolean): Promise<void>;
45
+ setWorking(working: boolean): Promise<void>;
46
+ uploadFile(filePath: string, title?: string): Promise<void>;
47
+ deleteResponse(): Promise<void>;
48
+ }
49
+ export interface PlatformInfo {
50
+ name: string;
51
+ formattingGuide: string;
52
+ channels: {
53
+ id: string;
54
+ name: string;
55
+ }[];
56
+ users: {
57
+ id: string;
58
+ userName: string;
59
+ displayName: string;
60
+ }[];
61
+ diagnostics?: {
62
+ showUsageSummary?: boolean;
63
+ };
64
+ }
65
+ export interface ChatAdapter {
66
+ start(): Promise<void>;
67
+ stop(): Promise<void>;
68
+ getPlatformInfo(): PlatformInfo;
69
+ }
70
+ /**
71
+ * A platform-agnostic event (message/mention) that triggers the agent.
72
+ */
73
+ export interface BotEvent {
74
+ type: string;
75
+ /** Platform-specific raw conversation/channel/chat identifier */
76
+ conversationId: string;
77
+ /** Optional alternate conversation identity used for vault routing. */
78
+ vaultConversationId?: string;
79
+ /** Cross-platform conversation shape: direct message vs shared space */
80
+ conversationKind: ConversationKind;
81
+ /** Message timestamp or ID as string */
82
+ ts: string;
83
+ /** Parent message ID for threaded replies (optional) */
84
+ thread_ts?: string;
85
+ /** User ID */
86
+ user: string;
87
+ /** Message text (already stripped of bot mentions) */
88
+ text: string;
89
+ /** Downloaded attachments */
90
+ attachments?: {
91
+ name: string;
92
+ localPath: string;
93
+ }[];
94
+ /** Platform-computed session key; overrides default conversationId:thread_ts computation */
95
+ sessionKey?: string;
96
+ }
97
+ /**
98
+ * Minimum interface that every platform bot must implement,
99
+ * used by the central handler in main.ts and by EventsWatcher.
100
+ */
101
+ export interface Bot {
102
+ start(): Promise<void>;
103
+ postMessage(channel: string, text: string): Promise<string>;
104
+ updateMessage(channel: string, ts: string, text: string): Promise<void>;
105
+ enqueueEvent(event: BotEvent): boolean;
106
+ getPlatformInfo(): PlatformInfo;
107
+ postPrivate?(conversationId: string, userId: string, text: string): Promise<void>;
108
+ postPrivateDiagnostic?(conversationId: string, userId: string, text: string, options?: {
109
+ style?: "muted" | "error";
110
+ }): Promise<void>;
111
+ }
112
+ /** Pre-created platform adapters passed to the handler */
113
+ export interface BotAdapters {
114
+ message: ChatMessage;
115
+ responseCtx: ChatResponseContext;
116
+ platform: PlatformInfo;
117
+ }
118
+ export interface RunningSession {
119
+ sessionKey: string;
120
+ startedAt: number;
121
+ lastActivityAt?: number;
122
+ currentTool?: string;
123
+ }
124
+ export interface BotHandler {
125
+ isRunning(sessionKey: string): boolean;
126
+ getRunningSessions(): RunningSession[];
127
+ handleEvent(event: BotEvent, bot: Bot, adapters: BotAdapters): Promise<void>;
128
+ handleStop(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;
129
+ forceStop(sessionKey: string): void;
130
+ handleNewCommand(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;
131
+ }
132
+ export interface AgentRunner {
133
+ syncChatHistory(currentMessageId?: string): void;
134
+ run(message: ChatMessage, responseCtx: ChatResponseContext, platform: PlatformInfo): Promise<{
135
+ stopReason: string;
136
+ errorMessage?: string;
137
+ }>;
138
+ abort(): void;
139
+ getCurrentStep(): {
140
+ toolName?: string;
141
+ label?: string;
142
+ } | undefined;
143
+ }
144
+ export interface AgentConfig {
145
+ provider: string;
146
+ model: string;
147
+ thinkingLevel: ThinkingLevel;
148
+ sentryDsn?: string;
149
+ sandboxCpus?: string;
150
+ sandboxMemory?: string;
151
+ sandboxBoostCpus?: string;
152
+ sandboxBoostMemory?: string;
153
+ sandboxImageWorkspaceMount?: "private" | "full";
154
+ defaultSharedVault?: string;
155
+ slack?: {
156
+ replyMode?: "top-level" | "thread";
157
+ };
158
+ }
159
+ export interface AutoReplyConfig {
160
+ enabled: boolean;
161
+ rules: string[];
162
+ }
163
+ export interface JudgeModelConfig {
164
+ provider: string;
165
+ model: string;
166
+ }
167
+ /**
168
+ * Platform conversation history entry from log.jsonl.
169
+ */
170
+ export interface ConversationLogMessage {
171
+ date?: string;
172
+ ts?: string;
173
+ threadTs?: string;
174
+ user?: string;
175
+ userName?: string;
176
+ text?: string;
177
+ isBot?: boolean;
178
+ }
179
+ export interface ImmediateEvent {
180
+ type: "immediate";
181
+ platform: string;
182
+ conversationId: string;
183
+ conversationKind: ConversationKind;
184
+ userId?: string;
185
+ text: string;
186
+ }
187
+ export interface OneShotEvent {
188
+ type: "one-shot";
189
+ platform: string;
190
+ conversationId: string;
191
+ conversationKind: ConversationKind;
192
+ userId?: string;
193
+ text: string;
194
+ at: string;
195
+ }
196
+ export interface PeriodicEvent {
197
+ type: "periodic";
198
+ platform: string;
199
+ conversationId: string;
200
+ conversationKind: ConversationKind;
201
+ userId?: string;
202
+ text: string;
203
+ schedule: string;
204
+ timezone: string;
205
+ }
206
+ export type MikanEvent = ImmediateEvent | OneShotEvent | PeriodicEvent;
207
+ export interface PeriodicEventInfo {
208
+ filename: string;
209
+ platform: string;
210
+ conversationId: string;
211
+ conversationKind: ConversationKind;
212
+ text: string;
213
+ schedule: string;
214
+ timezone: string;
215
+ nextRun: string | null;
216
+ }
217
+ export interface ActorContext {
218
+ platform: string;
219
+ userId: string;
220
+ conversationId: string;
221
+ }
222
+ export type ImageWorkspaceMountMode = "private" | "full";
223
+ export interface LogContext {
224
+ conversationId: string;
225
+ userName?: string;
226
+ conversationName?: string;
227
+ sessionId?: string;
228
+ }
229
+ type PortalView = "admin" | "session" | "vault";
230
+ export interface PortalShellOptions {
231
+ activeView: PortalView;
232
+ pageTitle: string;
233
+ identity?: {
234
+ primary: string;
235
+ secondary?: string;
236
+ };
237
+ conversationSwitcher?: {
238
+ currentId: string;
239
+ options?: Array<{
240
+ id: string;
241
+ label: string;
242
+ running?: boolean;
243
+ }>;
244
+ };
245
+ navLinks?: Partial<Record<PortalView, string>>;
246
+ body: string;
247
+ extraStyles?: string;
248
+ inlineScript?: string;
249
+ extraHead?: string;
250
+ bodyAttributes?: Record<string, string>;
251
+ }
252
+ export interface ContainerMount {
253
+ source: string;
254
+ target: string;
255
+ }
256
+ export interface ResourceLimits {
257
+ cpus?: string;
258
+ memory?: string;
259
+ }
260
+ export interface SandboxLimitStatus {
261
+ limits?: ResourceLimits;
262
+ boosted: boolean;
263
+ }
264
+ export interface ProvisionOptions {
265
+ containerName?: string;
266
+ mounts?: ContainerMount[];
267
+ conversationId?: string;
268
+ }
269
+ export interface DockerContainerManagerOptions {
270
+ limits?: ResourceLimits;
271
+ boostLimits?: ResourceLimits;
272
+ execFileImpl?: ExecFileAsync;
273
+ }
274
+ export interface Attachment {
275
+ original: string;
276
+ localPath: string;
277
+ }
278
+ export interface LoggedMessage {
279
+ date: string;
280
+ ts: string;
281
+ user: string;
282
+ userName?: string;
283
+ displayName?: string;
284
+ text: string;
285
+ attachments: Attachment[];
286
+ isBot: boolean;
287
+ threadTs?: string;
288
+ }
289
+ export interface ChannelStoreConfig {
290
+ workingDir: string;
291
+ botToken: string;
292
+ }
293
+ export type TriggerIntent = "mention" | "direct" | "thread-continuation" | "auto-reply-candidate";
294
+ export type TriggerResult = {
295
+ trigger: true;
296
+ reason: string;
297
+ } | {
298
+ trigger: false;
299
+ reason: string;
300
+ };
301
+ export type AutoReplyJudge = (input: {
302
+ event: BotEvent;
303
+ rules: string[];
304
+ conversationDir: string;
305
+ }) => Promise<boolean>;
306
+ export {};
307
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,QAAA,MAAM,cAAc,+BAAsB,CAAC;AAC3C,KAAK,aAAa,GAAG,OAAO,cAAc,CAAC;AAI3C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,mBAAmB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,cAAc,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,eAAe,CAAC,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/D,WAAW,CAAC,EAAE;QACZ,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,eAAe,IAAI,YAAY,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpD,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,GAAG;IAClB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IACvC,eAAe,IAAI,YAAY,CAAC;IAChC,WAAW,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,qBAAqB,CAAC,CACpB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,kBAAkB,IAAI,cAAc,EAAE,CAAC;IACvC,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvF;AAID,MAAM,WAAW,WAAW;IAC1B,eAAe,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,GAAG,CACD,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,mBAAmB,EAChC,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,KAAK,IAAI,IAAI,CAAC;IACd,cAAc,IAAI;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACrE;AAID,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAChD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE;QACN,SAAS,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,YAAY,GAAG,aAAa,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAID,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,MAAM,CAAC;AAIzD,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,KAAK,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,oBAAoB,CAAC,EAAE;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACnE,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAID,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAID,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,qBAAqB,GAAG,sBAAsB,CAAC;AAElG,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB,KAAK,OAAO,CAAC,OAAO,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 ChatMessage {\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 ChatResponseBlockKit {\n text: string;\n blocks: object[];\n}\n\nexport interface ChatResponseContext {\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 respondBlockKit?(response: ChatResponseBlockKit): 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 PlatformInfo {\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 getPlatformInfo(): PlatformInfo;\n}\n\n/**\n * A platform-agnostic event (message/mention) that triggers the agent.\n */\nexport interface BotEvent {\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 Bot {\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: BotEvent): boolean;\n getPlatformInfo(): PlatformInfo;\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/** Pre-created platform adapters passed to the handler */\nexport interface BotAdapters {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n}\n\nexport interface RunningSession {\n sessionKey: string;\n startedAt: number;\n lastActivityAt?: number;\n currentTool?: string;\n}\n\nexport interface BotHandler {\n isRunning(sessionKey: string): boolean;\n getRunningSessions(): RunningSession[];\n handleEvent(event: BotEvent, bot: Bot, adapters: BotAdapters): Promise<void>;\n handleStop(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;\n forceStop(sessionKey: string): void;\n handleNewCommand(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;\n}\n\n// ── agent ─────────────────────────────────────────────────────────────────────\n\nexport interface AgentRunner {\n syncChatHistory(currentMessageId?: string): void;\n run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\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\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 isBot?: 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 isBot: 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\nexport type AutoReplyJudge = (input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}) => Promise<boolean>;\n"]}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ import { execFile } from "child_process";
2
+ import { promisify } from "util";
3
+ const _execFileAsync = promisify(execFile);
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +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,cAAc,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 ChatMessage {\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 ChatResponseBlockKit {\n text: string;\n blocks: object[];\n}\n\nexport interface ChatResponseContext {\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 respondBlockKit?(response: ChatResponseBlockKit): 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 PlatformInfo {\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 getPlatformInfo(): PlatformInfo;\n}\n\n/**\n * A platform-agnostic event (message/mention) that triggers the agent.\n */\nexport interface BotEvent {\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 Bot {\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: BotEvent): boolean;\n getPlatformInfo(): PlatformInfo;\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/** Pre-created platform adapters passed to the handler */\nexport interface BotAdapters {\n message: ChatMessage;\n responseCtx: ChatResponseContext;\n platform: PlatformInfo;\n}\n\nexport interface RunningSession {\n sessionKey: string;\n startedAt: number;\n lastActivityAt?: number;\n currentTool?: string;\n}\n\nexport interface BotHandler {\n isRunning(sessionKey: string): boolean;\n getRunningSessions(): RunningSession[];\n handleEvent(event: BotEvent, bot: Bot, adapters: BotAdapters): Promise<void>;\n handleStop(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;\n forceStop(sessionKey: string): void;\n handleNewCommand(sessionKey: string, conversationId: string, bot: Bot): Promise<void>;\n}\n\n// ── agent ─────────────────────────────────────────────────────────────────────\n\nexport interface AgentRunner {\n syncChatHistory(currentMessageId?: string): void;\n run(\n message: ChatMessage,\n responseCtx: ChatResponseContext,\n platform: PlatformInfo,\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\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 isBot?: 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 isBot: 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\nexport type AutoReplyJudge = (input: {\n event: BotEvent;\n rules: string[];\n conversationDir: string;\n}) => Promise<boolean>;\n"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Format a Date as a local-timezone timestamp string: YYYY-MM-DD HH:MM:SS±HH:MM
3
+ * Returns null when the date is invalid (non-finite time value).
4
+ *
5
+ * This format is used both when writing user messages (agent.ts) and when
6
+ * reading history back into sessions (chat-session-manager.ts). Keeping it
7
+ * in one place ensures normalizeComparableText's regex stays valid.
8
+ */
9
+ export declare function formatLocalTimestamp(date: Date): string | null;
10
+ //# sourceMappingURL=date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/utils/date.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAY9D","sourcesContent":["/**\n * Format a Date as a local-timezone timestamp string: YYYY-MM-DD HH:MM:SS±HH:MM\n * Returns null when the date is invalid (non-finite time value).\n *\n * This format is used both when writing user messages (agent.ts) and when\n * reading history back into sessions (chat-session-manager.ts). Keeping it\n * in one place ensures normalizeComparableText's regex stays valid.\n */\nexport function formatLocalTimestamp(date: Date): string | null {\n const time = date.getTime();\n if (!Number.isFinite(time)) return null;\n\n const offset = -date.getTimezoneOffset();\n const sign = offset >= 0 ? \"+\" : \"-\";\n const abs = Math.abs(offset);\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +\n `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}` +\n `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`\n );\n}\n\nfunction pad(n: number): string {\n return n.toString().padStart(2, \"0\");\n}\n"]}