@geminixiang/mikan 1.0.0-beta.32 → 1.0.0-beta.34

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 (257) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/adapter.d.ts +11 -1
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +18 -1
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts +1 -1
  7. package/dist/adapters/discord/bot.d.ts.map +1 -1
  8. package/dist/adapters/discord/bot.js +26 -20
  9. package/dist/adapters/discord/bot.js.map +1 -1
  10. package/dist/adapters/discord/context.d.ts +2 -1
  11. package/dist/adapters/discord/context.d.ts.map +1 -1
  12. package/dist/adapters/discord/context.js +7 -3
  13. package/dist/adapters/discord/context.js.map +1 -1
  14. package/dist/adapters/github/bot.d.ts +1 -1
  15. package/dist/adapters/github/bot.d.ts.map +1 -1
  16. package/dist/adapters/github/bot.js +10 -5
  17. package/dist/adapters/github/bot.js.map +1 -1
  18. package/dist/adapters/github/context.d.ts +2 -1
  19. package/dist/adapters/github/context.d.ts.map +1 -1
  20. package/dist/adapters/github/context.js +7 -4
  21. package/dist/adapters/github/context.js.map +1 -1
  22. package/dist/adapters/github/repo.d.ts.map +1 -1
  23. package/dist/adapters/github/repo.js +2 -1
  24. package/dist/adapters/github/repo.js.map +1 -1
  25. package/dist/adapters/intake.js +5 -4
  26. package/dist/adapters/intake.js.map +1 -1
  27. package/dist/adapters/shared.d.ts +8 -7
  28. package/dist/adapters/shared.d.ts.map +1 -1
  29. package/dist/adapters/shared.js +18 -16
  30. package/dist/adapters/shared.js.map +1 -1
  31. package/dist/adapters/slack/bot.d.ts +4 -1
  32. package/dist/adapters/slack/bot.d.ts.map +1 -1
  33. package/dist/adapters/slack/bot.js +76 -54
  34. package/dist/adapters/slack/bot.js.map +1 -1
  35. package/dist/adapters/slack/context.d.ts +2 -1
  36. package/dist/adapters/slack/context.d.ts.map +1 -1
  37. package/dist/adapters/slack/context.js +7 -3
  38. package/dist/adapters/slack/context.js.map +1 -1
  39. package/dist/adapters/slack/types.d.ts +2 -1
  40. package/dist/adapters/slack/types.d.ts.map +1 -1
  41. package/dist/adapters/slack/types.js.map +1 -1
  42. package/dist/adapters/telegram/bot.d.ts +1 -1
  43. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  44. package/dist/adapters/telegram/bot.js +17 -10
  45. package/dist/adapters/telegram/bot.js.map +1 -1
  46. package/dist/adapters/telegram/context.d.ts +1 -0
  47. package/dist/adapters/telegram/context.d.ts.map +1 -1
  48. package/dist/adapters/telegram/context.js +7 -3
  49. package/dist/adapters/telegram/context.js.map +1 -1
  50. package/dist/adapters/types.d.ts +3 -2
  51. package/dist/adapters/types.d.ts.map +1 -1
  52. package/dist/adapters/types.js.map +1 -1
  53. package/dist/agent.d.ts +1 -0
  54. package/dist/agent.d.ts.map +1 -1
  55. package/dist/agent.js +122 -50
  56. package/dist/agent.js.map +1 -1
  57. package/dist/cli/boot.d.ts.map +1 -1
  58. package/dist/cli/boot.js +4 -1
  59. package/dist/cli/boot.js.map +1 -1
  60. package/dist/cli/ext-dev.d.ts.map +1 -1
  61. package/dist/cli/ext-dev.js +22 -14
  62. package/dist/cli/ext-dev.js.map +1 -1
  63. package/dist/cli/ext.d.ts.map +1 -1
  64. package/dist/cli/ext.js +5 -3
  65. package/dist/cli/ext.js.map +1 -1
  66. package/dist/cli/office.d.ts +2 -0
  67. package/dist/cli/office.d.ts.map +1 -0
  68. package/dist/cli/office.js +89 -0
  69. package/dist/cli/office.js.map +1 -0
  70. package/dist/cli/types.d.ts +3 -1
  71. package/dist/cli/types.d.ts.map +1 -1
  72. package/dist/cli/types.js.map +1 -1
  73. package/dist/commands/auto-reply.d.ts.map +1 -1
  74. package/dist/commands/auto-reply.js +2 -1
  75. package/dist/commands/auto-reply.js.map +1 -1
  76. package/dist/commands/extensions.js +1 -1
  77. package/dist/commands/extensions.js.map +1 -1
  78. package/dist/commands/login.d.ts.map +1 -1
  79. package/dist/commands/login.js +6 -3
  80. package/dist/commands/login.js.map +1 -1
  81. package/dist/commands/model.d.ts.map +1 -1
  82. package/dist/commands/model.js +7 -4
  83. package/dist/commands/model.js.map +1 -1
  84. package/dist/commands/new.d.ts.map +1 -1
  85. package/dist/commands/new.js +6 -2
  86. package/dist/commands/new.js.map +1 -1
  87. package/dist/commands/sandbox.d.ts.map +1 -1
  88. package/dist/commands/sandbox.js +5 -20
  89. package/dist/commands/sandbox.js.map +1 -1
  90. package/dist/commands/session-view.d.ts.map +1 -1
  91. package/dist/commands/session-view.js +2 -1
  92. package/dist/commands/session-view.js.map +1 -1
  93. package/dist/commands/types.d.ts +5 -4
  94. package/dist/commands/types.d.ts.map +1 -1
  95. package/dist/commands/types.js.map +1 -1
  96. package/dist/config.d.ts +15 -4
  97. package/dist/config.d.ts.map +1 -1
  98. package/dist/config.js +55 -24
  99. package/dist/config.js.map +1 -1
  100. package/dist/events.d.ts.map +1 -1
  101. package/dist/events.js +4 -2
  102. package/dist/events.js.map +1 -1
  103. package/dist/execution-resolver.d.ts.map +1 -1
  104. package/dist/execution-resolver.js +22 -13
  105. package/dist/execution-resolver.js.map +1 -1
  106. package/dist/harness/extensions/loader.d.ts +2 -1
  107. package/dist/harness/extensions/loader.d.ts.map +1 -1
  108. package/dist/harness/extensions/loader.js +5 -3
  109. package/dist/harness/extensions/loader.js.map +1 -1
  110. package/dist/harness/extensions/types.d.ts +3 -0
  111. package/dist/harness/extensions/types.d.ts.map +1 -1
  112. package/dist/harness/extensions/types.js.map +1 -1
  113. package/dist/harness/session-store.d.ts +2 -0
  114. package/dist/harness/session-store.d.ts.map +1 -1
  115. package/dist/harness/session-store.js +2 -0
  116. package/dist/harness/session-store.js.map +1 -1
  117. package/dist/harness/subagent-profiles.d.ts.map +1 -1
  118. package/dist/harness/subagent-profiles.js +9 -0
  119. package/dist/harness/subagent-profiles.js.map +1 -1
  120. package/dist/harness/subagent-runner.js +6 -4
  121. package/dist/harness/subagent-runner.js.map +1 -1
  122. package/dist/harness/types.d.ts +4 -2
  123. package/dist/harness/types.d.ts.map +1 -1
  124. package/dist/harness/types.js.map +1 -1
  125. package/dist/index.d.ts +2 -1
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +1 -0
  128. package/dist/index.js.map +1 -1
  129. package/dist/main.js +47 -0
  130. package/dist/main.js.map +1 -1
  131. package/dist/observability/sentry.d.ts +2 -0
  132. package/dist/observability/sentry.d.ts.map +1 -1
  133. package/dist/observability/sentry.js +7 -0
  134. package/dist/observability/sentry.js.map +1 -1
  135. package/dist/office-address.d.ts +32 -0
  136. package/dist/office-address.d.ts.map +1 -0
  137. package/dist/office-address.js +118 -0
  138. package/dist/office-address.js.map +1 -0
  139. package/dist/office-migration.d.ts +38 -0
  140. package/dist/office-migration.d.ts.map +1 -0
  141. package/dist/office-migration.js +213 -0
  142. package/dist/office-migration.js.map +1 -0
  143. package/dist/office-registry.d.ts +81 -0
  144. package/dist/office-registry.d.ts.map +1 -0
  145. package/dist/office-registry.js +705 -0
  146. package/dist/office-registry.js.map +1 -0
  147. package/dist/packages/admin.js +5 -3
  148. package/dist/packages/admin.js.map +1 -1
  149. package/dist/packages/inspect.d.ts.map +1 -1
  150. package/dist/packages/inspect.js +5 -2
  151. package/dist/packages/inspect.js.map +1 -1
  152. package/dist/packages/materialize.d.ts +2 -1
  153. package/dist/packages/materialize.d.ts.map +1 -1
  154. package/dist/packages/materialize.js +6 -16
  155. package/dist/packages/materialize.js.map +1 -1
  156. package/dist/packages/resolve.d.ts.map +1 -1
  157. package/dist/packages/resolve.js +8 -9
  158. package/dist/packages/resolve.js.map +1 -1
  159. package/dist/packages/types.d.ts +3 -2
  160. package/dist/packages/types.d.ts.map +1 -1
  161. package/dist/packages/types.js.map +1 -1
  162. package/dist/provisioner.d.ts +7 -0
  163. package/dist/provisioner.d.ts.map +1 -1
  164. package/dist/provisioner.js +17 -0
  165. package/dist/provisioner.js.map +1 -1
  166. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  167. package/dist/runtime/conversation-runtime.js +88 -67
  168. package/dist/runtime/conversation-runtime.js.map +1 -1
  169. package/dist/runtime/session-lifecycle.d.ts +22 -12
  170. package/dist/runtime/session-lifecycle.d.ts.map +1 -1
  171. package/dist/runtime/session-lifecycle.js +85 -53
  172. package/dist/runtime/session-lifecycle.js.map +1 -1
  173. package/dist/runtime/types.d.ts +14 -4
  174. package/dist/runtime/types.d.ts.map +1 -1
  175. package/dist/runtime/types.js.map +1 -1
  176. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  177. package/dist/sandbox/cloudflare.js +1 -0
  178. package/dist/sandbox/cloudflare.js.map +1 -1
  179. package/dist/sandbox/container.d.ts.map +1 -1
  180. package/dist/sandbox/container.js +1 -0
  181. package/dist/sandbox/container.js.map +1 -1
  182. package/dist/sandbox/firecracker.d.ts.map +1 -1
  183. package/dist/sandbox/firecracker.js +1 -0
  184. package/dist/sandbox/firecracker.js.map +1 -1
  185. package/dist/sandbox/gondolin.d.ts.map +1 -1
  186. package/dist/sandbox/gondolin.js +1 -0
  187. package/dist/sandbox/gondolin.js.map +1 -1
  188. package/dist/sandbox/host.d.ts.map +1 -1
  189. package/dist/sandbox/host.js +1 -0
  190. package/dist/sandbox/host.js.map +1 -1
  191. package/dist/sandbox/identity.d.ts +35 -7
  192. package/dist/sandbox/identity.d.ts.map +1 -1
  193. package/dist/sandbox/identity.js +31 -5
  194. package/dist/sandbox/identity.js.map +1 -1
  195. package/dist/sandbox/image.d.ts.map +1 -1
  196. package/dist/sandbox/image.js +1 -0
  197. package/dist/sandbox/image.js.map +1 -1
  198. package/dist/sandbox/index.d.ts +2 -0
  199. package/dist/sandbox/index.d.ts.map +1 -1
  200. package/dist/sandbox/index.js +12 -0
  201. package/dist/sandbox/index.js.map +1 -1
  202. package/dist/sandbox/types.d.ts +6 -0
  203. package/dist/sandbox/types.d.ts.map +1 -1
  204. package/dist/sandbox/types.js.map +1 -1
  205. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  206. package/dist/sessions/chat-history-sync.js +33 -4
  207. package/dist/sessions/chat-history-sync.js.map +1 -1
  208. package/dist/sessions/store.d.ts +13 -1
  209. package/dist/sessions/store.d.ts.map +1 -1
  210. package/dist/sessions/store.js +78 -9
  211. package/dist/sessions/store.js.map +1 -1
  212. package/dist/settings-mutation.d.ts +3 -3
  213. package/dist/settings-mutation.d.ts.map +1 -1
  214. package/dist/settings-mutation.js +4 -4
  215. package/dist/settings-mutation.js.map +1 -1
  216. package/dist/store.d.ts +5 -0
  217. package/dist/store.d.ts.map +1 -1
  218. package/dist/store.js +13 -5
  219. package/dist/store.js.map +1 -1
  220. package/dist/tools/event.d.ts.map +1 -1
  221. package/dist/tools/event.js +5 -2
  222. package/dist/tools/event.js.map +1 -1
  223. package/dist/tools/subagent.d.ts.map +1 -1
  224. package/dist/tools/subagent.js +6 -3
  225. package/dist/tools/subagent.js.map +1 -1
  226. package/dist/trigger.d.ts.map +1 -1
  227. package/dist/trigger.js +6 -3
  228. package/dist/trigger.js.map +1 -1
  229. package/dist/types.d.ts +78 -9
  230. package/dist/types.d.ts.map +1 -1
  231. package/dist/types.js.map +1 -1
  232. package/dist/vault/index.d.ts +16 -0
  233. package/dist/vault/index.d.ts.map +1 -1
  234. package/dist/vault/index.js +31 -1
  235. package/dist/vault/index.js.map +1 -1
  236. package/dist/web/admin/portal.d.ts +13 -0
  237. package/dist/web/admin/portal.d.ts.map +1 -1
  238. package/dist/web/admin/portal.js +156 -173
  239. package/dist/web/admin/portal.js.map +1 -1
  240. package/dist/web/admin/types.d.ts +3 -3
  241. package/dist/web/admin/types.d.ts.map +1 -1
  242. package/dist/web/admin/types.js.map +1 -1
  243. package/dist/web/session-view/portal.d.ts.map +1 -1
  244. package/dist/web/session-view/portal.js +24 -14
  245. package/dist/web/session-view/portal.js.map +1 -1
  246. package/dist/web/session-view/service.d.ts +1 -1
  247. package/dist/web/session-view/service.d.ts.map +1 -1
  248. package/dist/web/session-view/service.js +48 -11
  249. package/dist/web/session-view/service.js.map +1 -1
  250. package/dist/workspace-projection/index.d.ts +10 -3
  251. package/dist/workspace-projection/index.d.ts.map +1 -1
  252. package/dist/workspace-projection/index.js +129 -45
  253. package/dist/workspace-projection/index.js.map +1 -1
  254. package/dist/workspace-projection/types.d.ts +14 -3
  255. package/dist/workspace-projection/types.d.ts.map +1 -1
  256. package/dist/workspace-projection/types.js.map +1 -1
  257. package/package.json +2 -1
@@ -6,7 +6,7 @@
6
6
  * The split/normalize logic itself doesn't differ across platforms — only the
7
7
  * markup wrappers — so it lives here once.
8
8
  */
9
- import type { MessagingEventHandler } from "../adapter.js";
9
+ import type { MessagingEventHandler, OfficeAddress } from "../adapter.js";
10
10
  export type { ChatResponseErrorContext, ChatResponseErrorOperation, ChatResponseErrorReporter, ResolveStopTargetInput, RetryOptions, } from "./types.js";
11
11
  import type { ChatResponseErrorContext, ChatResponseErrorReporter, RetryOptions, ResolveStopTargetInput } from "./types.js";
12
12
  export declare function createChatResponseErrorReporter(resolve: () => Omit<ChatResponseErrorContext, "operation" | "extra">): ChatResponseErrorReporter;
@@ -34,13 +34,13 @@ export declare function withRetry<T>(fn: () => Promise<T>, opts: RetryOptions):
34
34
  */
35
35
  export declare function splitText(text: string, limit: number, formatContinuation: (partNum: number) => string): string[];
36
36
  /**
37
- * Append a JSON-serializable entry to `${workingDir}/${channel}/log.jsonl`,
37
+ * Append a JSON-serializable entry to the office's `log.jsonl`,
38
38
  * creating the directory on first use. This is the single write path every
39
39
  * adapter uses for human-readable message history.
40
40
  */
41
- export declare function appendChannelLog(workingDir: string, channel: string, entry: object): void;
41
+ export declare function appendChannelLog(workingDir: string, address: OfficeAddress, entry: object): void;
42
42
  /** Convenience for appending the bot's own outbound message. */
43
- export declare function appendBotResponseLog(workingDir: string, channel: string, text: string, ts: string, threadTs?: string, extraFields?: Record<string, unknown>): void;
43
+ export declare function appendBotResponseLog(workingDir: string, address: OfficeAddress, text: string, ts: string, threadTs?: string, extraFields?: Record<string, unknown>): void;
44
44
  /**
45
45
  * Pick which session key a `/stop` should target without applying any
46
46
  * platform-specific fallback policy. Order:
@@ -49,10 +49,11 @@ export declare function appendBotResponseLog(workingDir: string, channel: string
49
49
  */
50
50
  export declare function resolveStopTarget(input: ResolveStopTargetInput): string | null;
51
51
  /**
52
- * Return the single running scoped session for this conversation, or null when
53
- * there are zero or multiple matches.
52
+ * Return the single running scoped session for this office, or null when there
53
+ * are zero or multiple matches. Another platform's identically named
54
+ * conversation is a different office and is never a stop target.
54
55
  */
55
- export declare function resolveOnlyScopedStopTarget(handler: MessagingEventHandler, conversationId: string): string | null;
56
+ export declare function resolveOnlyScopedStopTarget(handler: MessagingEventHandler, address: OfficeAddress): string | null;
56
57
  /**
57
58
  * Render tool-call args for human display. Drops `label` (already in the
58
59
  * heading) and folds `path` + `offset`/`limit` into a single `path:start-end`
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAI3D,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,sBAAsB,EACtB,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACZ,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,IAAI,CAAC,wBAAwB,EAAE,WAAW,GAAG,OAAO,CAAC,GACnE,yBAAyB,CAI3B;AA0BD,qBAAa,mBAAmB;IAIlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAE3B,YAA6B,IAAI,GAAE,MAAW,EAAI;IAElD,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAGvC;IAED,IAAI,IAAI,MAAM,CAEb;YAEa,WAAW;CAe1B;AAID;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAwBvF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAC9C,MAAM,EAAE,CAeV;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIzF;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACxC,IAAI,CAWN;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI,CAM9E;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,qBAAqB,EAC9B,cAAc,EAAE,MAAM,GACrB,MAAM,GAAG,IAAI,CAOf;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAsBhF;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQpF"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK1E,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,sBAAsB,EACtB,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACZ,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,IAAI,CAAC,wBAAwB,EAAE,WAAW,GAAG,OAAO,CAAC,GACnE,yBAAyB,CAI3B;AA0BD,qBAAa,mBAAmB;IAIlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAE3B,YAA6B,IAAI,GAAE,MAAW,EAAI;IAElD,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAGvC;IAED,IAAI,IAAI,MAAM,CAEb;YAEa,WAAW;CAe1B;AAID;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAwBvF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAC9C,MAAM,EAAE,CAeV;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAGhG;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACxC,IAAI,CAWN;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI,CAM9E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,aAAa,GACrB,MAAM,GAAG,IAAI,CAQf;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAsBhF;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQpF"}
@@ -9,7 +9,8 @@
9
9
  import { appendFileSync } from "fs";
10
10
  import { mkdir, writeFile } from "fs/promises";
11
11
  import { dirname, join } from "path";
12
- import { ensureDirExists } from "../utils/file-guards.js";
12
+ import { sameOffice } from "../office-address.js";
13
+ import { ensureOfficeDir } from "../office-registry.js";
13
14
  import * as log from "../log.js";
14
15
  import { reportUserFacingError } from "../observability/sentry.js";
15
16
  export function createChatResponseErrorReporter(resolve) {
@@ -120,18 +121,17 @@ export function splitText(text, limit, formatContinuation) {
120
121
  return parts;
121
122
  }
122
123
  /**
123
- * Append a JSON-serializable entry to `${workingDir}/${channel}/log.jsonl`,
124
+ * Append a JSON-serializable entry to the office's `log.jsonl`,
124
125
  * creating the directory on first use. This is the single write path every
125
126
  * adapter uses for human-readable message history.
126
127
  */
127
- export function appendChannelLog(workingDir, channel, entry) {
128
- const dir = join(workingDir, channel);
129
- ensureDirExists(dir);
128
+ export function appendChannelLog(workingDir, address, entry) {
129
+ const dir = ensureOfficeDir(workingDir, address);
130
130
  appendFileSync(join(dir, "log.jsonl"), `${JSON.stringify(entry)}\n`);
131
131
  }
132
132
  /** Convenience for appending the bot's own outbound message. */
133
- export function appendBotResponseLog(workingDir, channel, text, ts, threadTs, extraFields = {}) {
134
- appendChannelLog(workingDir, channel, {
133
+ export function appendBotResponseLog(workingDir, address, text, ts, threadTs, extraFields = {}) {
134
+ appendChannelLog(workingDir, address, {
135
135
  date: new Date().toISOString(),
136
136
  ts,
137
137
  ...(threadTs ? { threadTs } : {}),
@@ -150,22 +150,24 @@ export function appendBotResponseLog(workingDir, channel, text, ts, threadTs, ex
150
150
  * 2. The bare conversationId, if running.
151
151
  */
152
152
  export function resolveStopTarget(input) {
153
- const { handler, conversationId, sessionKey } = input;
154
- if (sessionKey && handler.isRunning(sessionKey))
153
+ const { handler, address, sessionKey } = input;
154
+ if (sessionKey && handler.isRunning(address, sessionKey))
155
155
  return sessionKey;
156
- if (handler.isRunning(conversationId))
157
- return conversationId;
156
+ if (handler.isRunning(address, address.conversationId))
157
+ return address.conversationId;
158
158
  return null;
159
159
  }
160
160
  /**
161
- * Return the single running scoped session for this conversation, or null when
162
- * there are zero or multiple matches.
161
+ * Return the single running scoped session for this office, or null when there
162
+ * are zero or multiple matches. Another platform's identically named
163
+ * conversation is a different office and is never a stop target.
163
164
  */
164
- export function resolveOnlyScopedStopTarget(handler, conversationId) {
165
+ export function resolveOnlyScopedStopTarget(handler, address) {
165
166
  const runningScopes = handler
166
167
  .getRunningSessions()
167
- .map((s) => s.sessionKey)
168
- .filter((k) => k.startsWith(`${conversationId}:`));
168
+ .filter((session) => sameOffice(session.address, address))
169
+ .map((session) => session.sessionKey)
170
+ .filter((key) => key.startsWith(`${address.conversationId}:`));
169
171
  return runningScopes.length === 1 ? runningScopes[0] : null;
170
172
  }
171
173
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helpers shared across platform adapters.\n *\n * The agent runner is platform-agnostic: it hands strings and structured tool\n * results to each adapter, which decides how to split, format, and route them.\n * The split/normalize logic itself doesn't differ across platforms — only the\n * markup wrappers — so it lives here once.\n */\n\nimport { appendFileSync } from \"fs\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname, join } from \"path\";\nimport type { MessagingEventHandler } from \"../adapter.js\";\nimport { ensureDirExists } from \"../utils/file-guards.js\";\nimport * as log from \"../log.js\";\nimport { reportUserFacingError } from \"../observability/sentry.js\";\nexport type {\n ChatResponseErrorContext,\n ChatResponseErrorOperation,\n ChatResponseErrorReporter,\n ResolveStopTargetInput,\n RetryOptions,\n} from \"./types.js\";\nimport type {\n ChatResponseErrorContext,\n ChatResponseErrorReporter,\n RetryOptions,\n ResolveStopTargetInput,\n} from \"./types.js\";\n\nexport function createChatResponseErrorReporter(\n resolve: () => Omit<ChatResponseErrorContext, \"operation\" | \"extra\">,\n): ChatResponseErrorReporter {\n return (err, operation, extra) => {\n reportChatResponseError(err, { ...resolve(), operation, extra });\n };\n}\n\nfunction reportChatResponseError(err: unknown, context: ChatResponseErrorContext): void {\n reportUserFacingError(err, {\n domain: \"chat_platform\",\n surface: \"chat_response\",\n operation: context.operation,\n severity: context.operation === \"set_working\" ? \"warning\" : \"error\",\n platform: context.platform,\n context: {\n conversationId: context.conversationId,\n channelId: context.channelId,\n chatId: context.chatId,\n messageId: context.messageId,\n sessionKey: context.sessionKey,\n responseMessageId: context.responseMessageId,\n threadTs: context.threadTs,\n replyTargetId: context.replyTargetId,\n replyToId: context.replyToId,\n conversationKind: context.conversationKind,\n isThreaded: context.isThreaded,\n ...context.extra,\n },\n });\n}\n\nexport class MessagingEventQueue {\n private queue: Array<() => Promise<void>> = [];\n private processing = false;\n\n constructor(private readonly name: string = \"\") {}\n\n enqueue(work: () => Promise<void>): void {\n this.queue.push(work);\n this.processNext();\n }\n\n size(): number {\n return this.queue.length;\n }\n\n private async processNext(): Promise<void> {\n if (this.processing || this.queue.length === 0) return;\n this.processing = true;\n const work = this.queue.shift()!;\n try {\n await work();\n } catch (err) {\n log.logWarning(\n `${this.name ? this.name + \" \" : \"\"}queue error`,\n err instanceof Error ? err.message : String(err),\n );\n }\n this.processing = false;\n this.processNext();\n }\n}\n\n// RetryOptions is defined in ./types.ts and re-exported from the top of this file.\n\n/**\n * Run `fn` and retry with exponential backoff when its error matches\n * `isRateLimited`. Other errors propagate immediately. Each platform supplies\n * its own predicate so we don't have to know every SDK's error shape here.\n */\nexport async function withRetry<T>(fn: () => Promise<T>, opts: RetryOptions): Promise<T> {\n const maxAttempts = opts.maxAttempts ?? 3;\n const baseDelayMs = opts.baseDelayMs ?? 1000;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n const isLastAttempt = attempt === maxAttempts - 1;\n if (isLastAttempt || !opts.isRateLimited(lastError)) {\n throw lastError;\n }\n\n const delay = baseDelayMs * Math.pow(2, attempt);\n log.logWarning(\n `Retrying after error in ${delay}ms (attempt ${attempt + 1}/${maxAttempts}): ${lastError.message}`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n throw lastError;\n}\n\n/**\n * Split `text` into chunks no larger than `limit`, appending a continuation\n * marker (e.g. `_(continued 1)_`) at the end of every part except the last.\n *\n * Each adapter passes its own `formatContinuation` so the marker uses the\n * platform's italic / emphasis convention.\n */\nexport function splitText(\n text: string,\n limit: number,\n formatContinuation: (partNum: number) => string,\n): string[] {\n if (text.length <= limit) return [text];\n const parts: string[] = [];\n let remaining = text;\n let partNum = 1;\n while (remaining.length > 0) {\n const suffixReserve = formatContinuation(partNum).length + 8;\n const chunkLimit = Math.max(1, limit - suffixReserve);\n const chunk = remaining.slice(0, chunkLimit);\n remaining = remaining.slice(chunkLimit);\n const suffix = remaining.length > 0 ? `\\n${formatContinuation(partNum)}` : \"\";\n parts.push(chunk + suffix);\n partNum++;\n }\n return parts;\n}\n\n/**\n * Append a JSON-serializable entry to `${workingDir}/${channel}/log.jsonl`,\n * creating the directory on first use. This is the single write path every\n * adapter uses for human-readable message history.\n */\nexport function appendChannelLog(workingDir: string, channel: string, entry: object): void {\n const dir = join(workingDir, channel);\n ensureDirExists(dir);\n appendFileSync(join(dir, \"log.jsonl\"), `${JSON.stringify(entry)}\\n`);\n}\n\n/** Convenience for appending the bot's own outbound message. */\nexport function appendBotResponseLog(\n workingDir: string,\n channel: string,\n text: string,\n ts: string,\n threadTs?: string,\n extraFields: Record<string, unknown> = {},\n): void {\n appendChannelLog(workingDir, channel, {\n date: new Date().toISOString(),\n ts,\n ...(threadTs ? { threadTs } : {}),\n user: \"bot\",\n text,\n attachments: [],\n isMessagingBot: true,\n ...extraFields,\n });\n}\n\n// ResolveStopTargetInput is defined in ./types.ts and re-exported from the top of this file.\n\n/**\n * Pick which session key a `/stop` should target without applying any\n * platform-specific fallback policy. Order:\n * 1. The provided sessionKey, if running.\n * 2. The bare conversationId, if running.\n */\nexport function resolveStopTarget(input: ResolveStopTargetInput): string | null {\n const { handler, conversationId, sessionKey } = input;\n\n if (sessionKey && handler.isRunning(sessionKey)) return sessionKey;\n if (handler.isRunning(conversationId)) return conversationId;\n return null;\n}\n\n/**\n * Return the single running scoped session for this conversation, or null when\n * there are zero or multiple matches.\n */\nexport function resolveOnlyScopedStopTarget(\n handler: MessagingEventHandler,\n conversationId: string,\n): string | null {\n const runningScopes = handler\n .getRunningSessions()\n .map((s) => s.sessionKey)\n .filter((k) => k.startsWith(`${conversationId}:`));\n\n return runningScopes.length === 1 ? runningScopes[0] : null;\n}\n\n/**\n * Render tool-call args for human display. Drops `label` (already in the\n * heading) and folds `path` + `offset`/`limit` into a single `path:start-end`\n * line. Pure data normalization with no platform-specific markup.\n */\nexport function formatToolArgs(args: Record<string, unknown> | undefined): string {\n if (!args) return \"\";\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n if (key === \"label\" || key === \"offset\" || key === \"limit\") continue;\n\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n lines.push(\n offset !== undefined && limit !== undefined\n ? `${value}:${offset}-${offset + limit}`\n : value,\n );\n continue;\n }\n\n lines.push(typeof value === \"string\" ? value : JSON.stringify(value));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Fetch `url` and write the response body to `destPath`, creating parent\n * directories as needed. Throws on non-2xx responses or write failures.\n */\nexport async function downloadUrlToFile(url: string, destPath: string): Promise<void> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n const buffer = await response.arrayBuffer();\n await mkdir(dirname(destPath), { recursive: true });\n await writeFile(destPath, Buffer.from(buffer));\n}\n"]}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helpers shared across platform adapters.\n *\n * The agent runner is platform-agnostic: it hands strings and structured tool\n * results to each adapter, which decides how to split, format, and route them.\n * The split/normalize logic itself doesn't differ across platforms — only the\n * markup wrappers — so it lives here once.\n */\n\nimport { appendFileSync } from \"fs\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname, join } from \"path\";\nimport type { MessagingEventHandler, OfficeAddress } from \"../adapter.js\";\nimport { sameOffice } from \"../office-address.js\";\nimport { ensureOfficeDir } from \"../office-registry.js\";\nimport * as log from \"../log.js\";\nimport { reportUserFacingError } from \"../observability/sentry.js\";\nexport type {\n ChatResponseErrorContext,\n ChatResponseErrorOperation,\n ChatResponseErrorReporter,\n ResolveStopTargetInput,\n RetryOptions,\n} from \"./types.js\";\nimport type {\n ChatResponseErrorContext,\n ChatResponseErrorReporter,\n RetryOptions,\n ResolveStopTargetInput,\n} from \"./types.js\";\n\nexport function createChatResponseErrorReporter(\n resolve: () => Omit<ChatResponseErrorContext, \"operation\" | \"extra\">,\n): ChatResponseErrorReporter {\n return (err, operation, extra) => {\n reportChatResponseError(err, { ...resolve(), operation, extra });\n };\n}\n\nfunction reportChatResponseError(err: unknown, context: ChatResponseErrorContext): void {\n reportUserFacingError(err, {\n domain: \"chat_platform\",\n surface: \"chat_response\",\n operation: context.operation,\n severity: context.operation === \"set_working\" ? \"warning\" : \"error\",\n platform: context.platform,\n context: {\n conversationId: context.conversationId,\n channelId: context.channelId,\n chatId: context.chatId,\n messageId: context.messageId,\n sessionKey: context.sessionKey,\n responseMessageId: context.responseMessageId,\n threadTs: context.threadTs,\n replyTargetId: context.replyTargetId,\n replyToId: context.replyToId,\n conversationKind: context.conversationKind,\n isThreaded: context.isThreaded,\n ...context.extra,\n },\n });\n}\n\nexport class MessagingEventQueue {\n private queue: Array<() => Promise<void>> = [];\n private processing = false;\n\n constructor(private readonly name: string = \"\") {}\n\n enqueue(work: () => Promise<void>): void {\n this.queue.push(work);\n this.processNext();\n }\n\n size(): number {\n return this.queue.length;\n }\n\n private async processNext(): Promise<void> {\n if (this.processing || this.queue.length === 0) return;\n this.processing = true;\n const work = this.queue.shift()!;\n try {\n await work();\n } catch (err) {\n log.logWarning(\n `${this.name ? this.name + \" \" : \"\"}queue error`,\n err instanceof Error ? err.message : String(err),\n );\n }\n this.processing = false;\n this.processNext();\n }\n}\n\n// RetryOptions is defined in ./types.ts and re-exported from the top of this file.\n\n/**\n * Run `fn` and retry with exponential backoff when its error matches\n * `isRateLimited`. Other errors propagate immediately. Each platform supplies\n * its own predicate so we don't have to know every SDK's error shape here.\n */\nexport async function withRetry<T>(fn: () => Promise<T>, opts: RetryOptions): Promise<T> {\n const maxAttempts = opts.maxAttempts ?? 3;\n const baseDelayMs = opts.baseDelayMs ?? 1000;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n const isLastAttempt = attempt === maxAttempts - 1;\n if (isLastAttempt || !opts.isRateLimited(lastError)) {\n throw lastError;\n }\n\n const delay = baseDelayMs * Math.pow(2, attempt);\n log.logWarning(\n `Retrying after error in ${delay}ms (attempt ${attempt + 1}/${maxAttempts}): ${lastError.message}`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n throw lastError;\n}\n\n/**\n * Split `text` into chunks no larger than `limit`, appending a continuation\n * marker (e.g. `_(continued 1)_`) at the end of every part except the last.\n *\n * Each adapter passes its own `formatContinuation` so the marker uses the\n * platform's italic / emphasis convention.\n */\nexport function splitText(\n text: string,\n limit: number,\n formatContinuation: (partNum: number) => string,\n): string[] {\n if (text.length <= limit) return [text];\n const parts: string[] = [];\n let remaining = text;\n let partNum = 1;\n while (remaining.length > 0) {\n const suffixReserve = formatContinuation(partNum).length + 8;\n const chunkLimit = Math.max(1, limit - suffixReserve);\n const chunk = remaining.slice(0, chunkLimit);\n remaining = remaining.slice(chunkLimit);\n const suffix = remaining.length > 0 ? `\\n${formatContinuation(partNum)}` : \"\";\n parts.push(chunk + suffix);\n partNum++;\n }\n return parts;\n}\n\n/**\n * Append a JSON-serializable entry to the office's `log.jsonl`,\n * creating the directory on first use. This is the single write path every\n * adapter uses for human-readable message history.\n */\nexport function appendChannelLog(workingDir: string, address: OfficeAddress, entry: object): void {\n const dir = ensureOfficeDir(workingDir, address);\n appendFileSync(join(dir, \"log.jsonl\"), `${JSON.stringify(entry)}\\n`);\n}\n\n/** Convenience for appending the bot's own outbound message. */\nexport function appendBotResponseLog(\n workingDir: string,\n address: OfficeAddress,\n text: string,\n ts: string,\n threadTs?: string,\n extraFields: Record<string, unknown> = {},\n): void {\n appendChannelLog(workingDir, address, {\n date: new Date().toISOString(),\n ts,\n ...(threadTs ? { threadTs } : {}),\n user: \"bot\",\n text,\n attachments: [],\n isMessagingBot: true,\n ...extraFields,\n });\n}\n\n// ResolveStopTargetInput is defined in ./types.ts and re-exported from the top of this file.\n\n/**\n * Pick which session key a `/stop` should target without applying any\n * platform-specific fallback policy. Order:\n * 1. The provided sessionKey, if running.\n * 2. The bare conversationId, if running.\n */\nexport function resolveStopTarget(input: ResolveStopTargetInput): string | null {\n const { handler, address, sessionKey } = input;\n\n if (sessionKey && handler.isRunning(address, sessionKey)) return sessionKey;\n if (handler.isRunning(address, address.conversationId)) return address.conversationId;\n return null;\n}\n\n/**\n * Return the single running scoped session for this office, or null when there\n * are zero or multiple matches. Another platform's identically named\n * conversation is a different office and is never a stop target.\n */\nexport function resolveOnlyScopedStopTarget(\n handler: MessagingEventHandler,\n address: OfficeAddress,\n): string | null {\n const runningScopes = handler\n .getRunningSessions()\n .filter((session) => sameOffice(session.address, address))\n .map((session) => session.sessionKey)\n .filter((key) => key.startsWith(`${address.conversationId}:`));\n\n return runningScopes.length === 1 ? runningScopes[0] : null;\n}\n\n/**\n * Render tool-call args for human display. Drops `label` (already in the\n * heading) and folds `path` + `offset`/`limit` into a single `path:start-end`\n * line. Pure data normalization with no platform-specific markup.\n */\nexport function formatToolArgs(args: Record<string, unknown> | undefined): string {\n if (!args) return \"\";\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n if (key === \"label\" || key === \"offset\" || key === \"limit\") continue;\n\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n lines.push(\n offset !== undefined && limit !== undefined\n ? `${value}:${offset}-${offset + limit}`\n : value,\n );\n continue;\n }\n\n lines.push(typeof value === \"string\" ? value : JSON.stringify(value));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Fetch `url` and write the response body to `destPath`, creating parent\n * directories as needed. Throws on non-2xx responses or write failures.\n */\nexport async function downloadUrlToFile(url: string, destPath: string): Promise<void> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n const buffer = await response.arrayBuffer();\n await mkdir(dirname(destPath), { recursive: true });\n await writeFile(destPath, Buffer.from(buffer));\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { MessagingBot, ConversationEvent, MessagingEventHandler, MessagingInfo } from "../../adapter.js";
1
+ import { type MessagingBot, type ConversationEvent, type MessagingEventHandler, type MessagingInfo } from "../../adapter.js";
2
2
  import type { EventsWatcher } from "../../events.js";
3
3
  import type { ChannelStore } from "../../store.js";
4
4
  import type { SlackChannel, SlackUser } from "./types.js";
@@ -23,6 +23,9 @@ export declare class SlackMessagingBot implements MessagingBot {
23
23
  private channels;
24
24
  private queues;
25
25
  private eventsWatcher;
26
+ /** Host office dir for a Slack conversation (see officeDirName). */
27
+ private conversationDir;
28
+ private resolveReplyMode;
26
29
  private createContext;
27
30
  constructor(handler: MessagingEventHandler, config: {
28
31
  appToken: string;
@@ -1 +1 @@
1
- {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ import { WebAPIRateLimitedError, WebClient } from "@slack/web-api";
3
3
  import { existsSync, readFileSync } from "fs";
4
4
  import { readFile } from "fs/promises";
5
5
  import { basename, join } from "path";
6
+ import { createConversationEvent, createConversationMessage, } from "../../adapter.js";
7
+ import { conversationOfficeDir, createOfficeAddress } from "../../office-address.js";
6
8
  import { COMMAND_MANIFEST } from "../../commands/manifest.js";
7
9
  import { resolveConversationSettings } from "../../config.js";
8
10
  import { parseExtActionId } from "../../harness/extensions/blockkit.js";
@@ -79,10 +81,17 @@ export function buildMrkdwnContextBlock(text) {
79
81
  // SlackMessagingBot
80
82
  // ============================================================================
81
83
  export class SlackMessagingBot {
84
+ /** Host office dir for a Slack conversation (see officeDirName). */
85
+ conversationDir(channelId) {
86
+ return conversationOfficeDir(this.workingDir, createOfficeAddress("slack", channelId));
87
+ }
88
+ resolveReplyMode(address) {
89
+ const scope = { address, conversationDir: this.conversationDir(address.conversationId) };
90
+ return resolveConversationSettings(scope).slack?.replyMode ?? "top-level";
91
+ }
82
92
  createContext(event) {
83
93
  return createSlackAdapters(event, this, {
84
- replyMode: resolveConversationSettings(join(this.workingDir, event.conversationId)).slack?.replyMode ??
85
- "top-level",
94
+ replyMode: this.resolveReplyMode(event.address),
86
95
  });
87
96
  }
88
97
  constructor(handler, config) {
@@ -312,16 +321,16 @@ export class SlackMessagingBot {
312
321
  });
313
322
  }
314
323
  logToFile(channel, entry) {
315
- appendChannelLog(this.workingDir, channel, entry);
324
+ appendChannelLog(this.workingDir, createOfficeAddress("slack", channel), entry);
316
325
  }
317
326
  logBotResponse(channel, text, ts, threadTs, slackBlocks) {
318
- appendBotResponseLog(this.workingDir, channel, text, ts, threadTs, {
327
+ appendBotResponseLog(this.workingDir, createOfficeAddress("slack", channel), text, ts, threadTs, {
319
328
  platform: "slack",
320
329
  ...(slackBlocks ? { slackBlocks } : {}),
321
330
  });
322
331
  }
323
332
  ownsBlockKitMessage(channel, ts, threadTs) {
324
- const content = readTextFileIfExists(join(this.workingDir, channel, "log.jsonl"));
333
+ const content = readTextFileIfExists(join(this.conversationDir(channel), "log.jsonl"));
325
334
  if (content === undefined)
326
335
  return false;
327
336
  for (const line of content.trim().split("\n").toReversed()) {
@@ -399,7 +408,7 @@ export class SlackMessagingBot {
399
408
  const eventForRun = eventPlan.event;
400
409
  if (eventPlan.initialMessageTs && eventForRun.sessionKey) {
401
410
  registerThreadSession({
402
- conversationDir: join(this.workingDir, conversationId),
411
+ conversationDir: this.conversationDir(conversationId),
403
412
  sessionKey: eventForRun.sessionKey,
404
413
  });
405
414
  }
@@ -407,7 +416,9 @@ export class SlackMessagingBot {
407
416
  initialMessageTs: eventPlan.initialMessageTs,
408
417
  }).sessionKey;
409
418
  this.getQueue(runQueueKey).enqueue(async () => {
410
- const slackEvent = {
419
+ const slackEvent = createConversationEvent({
420
+ platform: "slack",
421
+ address: eventForRun.address,
411
422
  type: eventForRun.type,
412
423
  conversationId,
413
424
  conversationKind: eventForRun.conversationKind,
@@ -416,16 +427,12 @@ export class SlackMessagingBot {
416
427
  thread_ts: eventForRun.thread_ts,
417
428
  user: eventForRun.user,
418
429
  text: eventForRun.text,
419
- attachments: eventForRun.attachments?.map((attachment) => ({
420
- original: attachment.name,
421
- localPath: attachment.localPath,
422
- })),
430
+ attachments: eventForRun.attachments,
423
431
  sessionKey: eventForRun.sessionKey,
424
- };
432
+ });
425
433
  const context = createSlackAdapters(slackEvent, this, {
426
434
  initialMessageTs: eventPlan.initialMessageTs,
427
- replyMode: resolveConversationSettings(join(this.workingDir, eventForRun.conversationId)).slack
428
- ?.replyMode ?? "top-level",
435
+ replyMode: this.resolveReplyMode(eventForRun.address),
429
436
  });
430
437
  return this.handler.handleEvent(eventForRun, this, context);
431
438
  });
@@ -446,13 +453,14 @@ export class SlackMessagingBot {
446
453
  resolveQueueKey(conversationId, sessionKey) {
447
454
  if (!isSlackThreadSessionKey(sessionKey))
448
455
  return sessionKey;
449
- if (this.handler.isRunning(sessionKey))
456
+ if (this.handler.isRunning(createOfficeAddress("slack", conversationId), sessionKey)) {
450
457
  return sessionKey;
458
+ }
451
459
  return this.hasKnownThreadSession(conversationId, sessionKey) ? sessionKey : conversationId;
452
460
  }
453
461
  hasKnownThreadSession(conversationId, sessionKey) {
454
462
  return hasMaterializedChatSession({
455
- conversationDir: join(this.workingDir, conversationId),
463
+ conversationDir: this.conversationDir(conversationId),
456
464
  sessionKey,
457
465
  });
458
466
  }
@@ -628,7 +636,9 @@ export class SlackMessagingBot {
628
636
  return { type: "home", blocks: blocks };
629
637
  }
630
638
  createCommandAdapters(conversationId, userId, userName, text, ts, options = {}) {
631
- const message = {
639
+ const message = createConversationMessage({
640
+ platform: "slack",
641
+ conversationId,
632
642
  id: ts,
633
643
  sessionKey: conversationId,
634
644
  conversationKind: options.ephemeralChannelId ? "shared" : "direct",
@@ -636,7 +646,7 @@ export class SlackMessagingBot {
636
646
  userName,
637
647
  text,
638
648
  attachments: [],
639
- };
649
+ });
640
650
  const respond = async (responseText) => {
641
651
  if (options.ephemeralChannelId) {
642
652
  await this.postEphemeral(options.ephemeralChannelId, userId, responseText, options.threadTs);
@@ -676,6 +686,7 @@ export class SlackMessagingBot {
676
686
  deleteResponse: async () => { },
677
687
  };
678
688
  return {
689
+ address: message.address,
679
690
  message,
680
691
  responder,
681
692
  platform: this.getMessagingInfo(),
@@ -703,9 +714,10 @@ export class SlackMessagingBot {
703
714
  isMessagingBot: false,
704
715
  ...(threadTs ? { threadTs } : {}),
705
716
  });
706
- const event = {
707
- type: options.type ?? (isDirectMessage ? "dm" : "mention"),
717
+ const event = createConversationEvent({
718
+ platform: "slack",
708
719
  conversationId,
720
+ type: options.type ?? (isDirectMessage ? "dm" : "mention"),
709
721
  conversationKind: isDirectMessage ? "direct" : "shared",
710
722
  ts: eventTs,
711
723
  user: payload.user_id,
@@ -713,7 +725,7 @@ export class SlackMessagingBot {
713
725
  attachments: [],
714
726
  ...(threadTs ? { thread_ts: threadTs } : {}),
715
727
  sessionKey,
716
- };
728
+ });
717
729
  const context = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage ? { threadTs } : { ephemeralChannelId: conversationId, threadTs });
718
730
  return { event, context };
719
731
  }
@@ -763,15 +775,18 @@ export class SlackMessagingBot {
763
775
  getMessagingInfo: () => this.getMessagingInfo(),
764
776
  };
765
777
  const event = {
766
- type: "dm",
767
- conversationId,
768
- conversationKind: "direct",
778
+ ...createConversationEvent({
779
+ platform: "slack",
780
+ conversationId,
781
+ type: "dm",
782
+ conversationKind: "direct",
783
+ ts: eventTs,
784
+ user: payload.user_id,
785
+ text: payload.command,
786
+ attachments: [],
787
+ sessionKey: conversationId,
788
+ }),
769
789
  channel: conversationId,
770
- ts: eventTs,
771
- user: payload.user_id,
772
- text: payload.command,
773
- attachments: [],
774
- sessionKey: conversationId,
775
790
  };
776
791
  const context = createSlackAdapters(event, this);
777
792
  await this.handler.handleNewCommand(conversationId, conversationId, commandMessagingBot, context.message, context.responder, context.platform);
@@ -804,18 +819,19 @@ export class SlackMessagingBot {
804
819
  // Thread replies get their own isolated session (channelId:thread_ts).
805
820
  const sessionKey = resolveSlackSessionKey(e.channel, e.thread_ts);
806
821
  const mentionText = this.stripOwnMention(e.text);
807
- const slackEvent = {
808
- type: "mention",
822
+ const slackEvent = createConversationEvent({
823
+ platform: "slack",
809
824
  conversationId: e.channel,
825
+ type: "mention",
810
826
  conversationKind: "shared",
811
- channel: e.channel,
812
827
  ts: e.ts,
813
828
  thread_ts: e.thread_ts,
814
829
  user: e.user,
815
830
  text: mentionText || "Please respond to the recent conversation context.",
816
- files: e.files,
817
831
  sessionKey,
818
- };
832
+ channel: e.channel,
833
+ files: e.files,
834
+ });
819
835
  const attachmentsPromise = this.logUserMessage(slackEvent);
820
836
  // Only trigger processing for messages AFTER startup (not replayed old messages)
821
837
  if (this.startupTs && e.ts < this.startupTs) {
@@ -892,18 +908,19 @@ export class SlackMessagingBot {
892
908
  }
893
909
  const isThreadReply = !!e.thread_ts;
894
910
  const sessionKey = isDM ? resolveSlackSessionKey(e.channel, e.thread_ts) : undefined;
895
- const slackEvent = {
896
- type: isDM ? "dm" : "mention",
911
+ const slackEvent = createConversationEvent({
912
+ platform: "slack",
897
913
  conversationId: e.channel,
914
+ type: (isDM ? "dm" : "mention"),
898
915
  conversationKind,
899
- channel: e.channel,
900
916
  ts: e.ts,
901
917
  thread_ts: e.thread_ts,
902
918
  user: e.user,
903
919
  text: this.stripOwnMention(e.text),
904
- files: e.files,
905
920
  sessionKey,
906
- };
921
+ channel: e.channel,
922
+ files: e.files,
923
+ });
907
924
  const attachmentsPromise = this.logUserMessage(slackEvent);
908
925
  // Only trigger processing for messages AFTER startup (not replayed old messages)
909
926
  if (this.startupTs && e.ts < this.startupTs) {
@@ -1002,7 +1019,7 @@ export class SlackMessagingBot {
1002
1019
  const channelId = body.container?.channel_id || conversationIdOf(sessionKey);
1003
1020
  log.logInfo(`[Force Stop] User ${userId} requested force stop for ${sessionKey}`);
1004
1021
  // Use handler's forceStop method
1005
- this.handler.forceStop(sessionKey);
1022
+ this.handler.forceStop(createOfficeAddress("slack", channelId), sessionKey);
1006
1023
  // Notify in channel
1007
1024
  await this.postMessage(channelId, formatForceStopped("slack", userId ?? "unknown"));
1008
1025
  // Refresh home tab
@@ -1038,7 +1055,7 @@ export class SlackMessagingBot {
1038
1055
  if (extAction) {
1039
1056
  this.getQueue(this.resolveQueueKey(channelId, sessionKey)).enqueue(async () => {
1040
1057
  const consumed = await this.handler.handleExtensionAction({
1041
- conversationId: channelId,
1058
+ address: createOfficeAddress("slack", channelId),
1042
1059
  sessionKey,
1043
1060
  conversationKind: channelId.startsWith("D") ? "direct" : "shared",
1044
1061
  slug: extAction.slug,
@@ -1092,9 +1109,10 @@ export class SlackMessagingBot {
1092
1109
  messageTs: container.message_ts,
1093
1110
  },
1094
1111
  });
1095
- const event = {
1096
- type: "slack_action",
1112
+ const event = createConversationEvent({
1113
+ platform: "slack",
1097
1114
  conversationId: channelId,
1115
+ type: "slack_action",
1098
1116
  conversationKind: channelId.startsWith("D") ? "direct" : "shared",
1099
1117
  ts,
1100
1118
  user: userId,
@@ -1102,19 +1120,23 @@ export class SlackMessagingBot {
1102
1120
  attachments: [],
1103
1121
  ...(threadTs ? { thread_ts: threadTs } : {}),
1104
1122
  sessionKey,
1105
- };
1123
+ });
1106
1124
  this.getQueue(this.resolveQueueKey(channelId, sessionKey)).enqueue(async () => {
1107
1125
  const slackEvent = {
1108
- type: event.conversationKind === "direct" ? "dm" : "mention",
1109
- conversationId: channelId,
1110
- conversationKind: event.conversationKind,
1126
+ ...createConversationEvent({
1127
+ platform: "slack",
1128
+ conversationId: channelId,
1129
+ type: (event.conversationKind === "direct" ? "dm" : "mention"),
1130
+ conversationKind: event.conversationKind,
1131
+ ts,
1132
+ thread_ts: threadTs,
1133
+ user: userId,
1134
+ text,
1135
+ attachments: [],
1136
+ sessionKey,
1137
+ }),
1111
1138
  channel: channelId,
1112
- ts,
1113
- thread_ts: threadTs,
1114
- user: userId,
1115
- text,
1116
1139
  attachments: [],
1117
- sessionKey,
1118
1140
  };
1119
1141
  return this.handler.handleEvent(event, this, this.createContext(slackEvent));
1120
1142
  });
@@ -1176,7 +1198,7 @@ export class SlackMessagingBot {
1176
1198
  // Private - Backfill
1177
1199
  // ==========================================================================
1178
1200
  async getExistingTimestamps(channelId) {
1179
- const logPath = join(this.workingDir, channelId, "log.jsonl");
1201
+ const logPath = join(this.conversationDir(channelId), "log.jsonl");
1180
1202
  const timestamps = new Set();
1181
1203
  if (!existsSync(logPath))
1182
1204
  return timestamps;
@@ -1283,7 +1305,7 @@ export class SlackMessagingBot {
1283
1305
  // Only backfill channels that already have a log.jsonl (mikan has interacted with them before)
1284
1306
  const channelsToBackfill = [];
1285
1307
  for (const [channelId, channel] of this.channels) {
1286
- const logPath = join(this.workingDir, channelId, "log.jsonl");
1308
+ const logPath = join(this.conversationDir(channelId), "log.jsonl");
1287
1309
  if (existsSync(logPath)) {
1288
1310
  channelsToBackfill.push([channelId, channel]);
1289
1311
  }