@vellumai/assistant 0.6.4 → 0.6.5

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 (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -20,7 +20,13 @@ export interface QdrantClientConfig {
20
20
  }
21
21
 
22
22
  export interface QdrantPointPayload {
23
- target_type: "segment" | "item" | "summary" | "media" | "graph_node";
23
+ target_type:
24
+ | "segment"
25
+ | "item"
26
+ | "summary"
27
+ | "media"
28
+ | "graph_node"
29
+ | "pkb_file";
24
30
  target_id: string;
25
31
  text: string;
26
32
  kind?: string;
@@ -496,6 +502,44 @@ export class VellumQdrantClient {
496
502
  }
497
503
  }
498
504
 
505
+ /**
506
+ * Delete all vectors matching target_type, payload path, and memory scope.
507
+ * Used to remove every chunk belonging to a single PKB file within a scope.
508
+ * The memory_scope_id filter is required — omitting it would wipe that
509
+ * path's chunks across every scope that happens to index the same relpath.
510
+ */
511
+ async deleteByTargetTypeAndPath(
512
+ targetType: string,
513
+ path: string,
514
+ memoryScopeId: string,
515
+ ): Promise<void> {
516
+ await this.ensureCollection();
517
+
518
+ const doDelete = () =>
519
+ this.client.delete(this.collection, {
520
+ wait: true,
521
+ filter: {
522
+ must: [
523
+ { key: "target_type", match: { value: targetType } },
524
+ { key: "path", match: { value: path } },
525
+ { key: "memory_scope_id", match: { value: memoryScopeId } },
526
+ ],
527
+ },
528
+ });
529
+
530
+ try {
531
+ await doDelete();
532
+ } catch (err) {
533
+ if (this.isCollectionMissing(err)) {
534
+ this.collectionReady = false;
535
+ await this.ensureCollection();
536
+ await doDelete();
537
+ } else {
538
+ throw err;
539
+ }
540
+ }
541
+ }
542
+
499
543
  async count(): Promise<number> {
500
544
  await this.ensureCollection();
501
545
 
@@ -605,6 +649,10 @@ export class VellumQdrantClient {
605
649
  field_name: "memory_scope_id",
606
650
  field_schema: "keyword",
607
651
  }),
652
+ this.client.createPayloadIndex(this.collection, {
653
+ field_name: "path",
654
+ field_schema: "keyword",
655
+ }),
608
656
  ]);
609
657
  }
610
658
 
@@ -640,6 +688,79 @@ export class VellumQdrantClient {
640
688
  });
641
689
  }
642
690
 
691
+ /**
692
+ * Scroll over every point with a given target_type and return the requested
693
+ * payload fields. Handles Qdrant's cursor-based pagination internally.
694
+ *
695
+ * Used by startup reconciliation (e.g. PKB filesystem diffing) to enumerate
696
+ * all indexed points for a target type without loading vectors.
697
+ */
698
+ async scrollByTargetType(
699
+ targetType: string,
700
+ options?: {
701
+ memoryScopeId?: string;
702
+ path?: string;
703
+ batchSize?: number;
704
+ },
705
+ ): Promise<Array<{ id: string; payload: Record<string, unknown> }>> {
706
+ await this.ensureCollection();
707
+
708
+ const batchSize = options?.batchSize ?? 256;
709
+ const must: Array<Record<string, unknown>> = [
710
+ { key: "target_type", match: { value: targetType } },
711
+ ];
712
+ if (options?.memoryScopeId) {
713
+ must.push({
714
+ key: "memory_scope_id",
715
+ match: { value: options.memoryScopeId },
716
+ });
717
+ }
718
+ if (options?.path) {
719
+ must.push({ key: "path", match: { value: options.path } });
720
+ }
721
+ const filter = {
722
+ must,
723
+ must_not: [{ key: "_meta", match: { value: true } }],
724
+ };
725
+
726
+ // Guard against a pathological pagination loop.
727
+ const maxIterations = 10_000;
728
+ const doScroll = async () => {
729
+ const out: Array<{ id: string; payload: Record<string, unknown> }> = [];
730
+ let offset: string | number | undefined = undefined;
731
+ for (let i = 0; i < maxIterations; i++) {
732
+ const result = await this.client.scroll(this.collection, {
733
+ filter,
734
+ limit: batchSize,
735
+ with_payload: true,
736
+ with_vector: false,
737
+ ...(offset !== undefined ? { offset } : {}),
738
+ });
739
+ for (const point of result.points) {
740
+ const id =
741
+ typeof point.id === "string" ? point.id : String(point.id);
742
+ const payload = (point.payload ?? {}) as Record<string, unknown>;
743
+ out.push({ id, payload });
744
+ }
745
+ const next = result.next_page_offset;
746
+ if (next == null) break;
747
+ offset = typeof next === "string" ? next : (next as number);
748
+ }
749
+ return out;
750
+ };
751
+
752
+ try {
753
+ return await doScroll();
754
+ } catch (err) {
755
+ if (this.isCollectionMissing(err)) {
756
+ this.collectionReady = false;
757
+ await this.ensureCollection();
758
+ return await doScroll();
759
+ }
760
+ throw err;
761
+ }
762
+ }
763
+
643
764
  private async findByTarget(
644
765
  targetType: string,
645
766
  targetId: string
@@ -62,6 +62,43 @@ export function setThreadTs(
62
62
  log.debug({ conversationId, channelId, threadTs }, "Thread mapping created");
63
63
  }
64
64
 
65
+ /**
66
+ * Read-side accessor for the in-memory thread mapping. Returns the
67
+ * `threadTs` previously associated with this conversation via
68
+ * {@link setThreadTs}, or `null` if no mapping exists. Does not bump
69
+ * `lastUsedAt` or otherwise mutate the entry — pure lookup.
70
+ */
71
+ export function getThreadTs(conversationId: string): string | null {
72
+ const mapping = threadMappings.get(conversationId);
73
+ return mapping ? mapping.threadTs : null;
74
+ }
75
+
76
+ /**
77
+ * Read both `threadTs` and `channelId` without mutating the entry. Used by
78
+ * dispatch to snapshot pre-update state so a turn that ends up rejected
79
+ * as already-processing can restore the in-flight turn's mapping.
80
+ */
81
+ export function peekThreadMapping(
82
+ conversationId: string,
83
+ ): { threadTs: string; channelId: string } | null {
84
+ const mapping = threadMappings.get(conversationId);
85
+ return mapping
86
+ ? { threadTs: mapping.threadTs, channelId: mapping.channelId }
87
+ : null;
88
+ }
89
+
90
+ /**
91
+ * Drop any thread mapping associated with this conversation. Called on
92
+ * inbound Slack turns that arrive at the channel root (no `threadTs` on
93
+ * the callback URL) so that a stale mapping from a prior in-thread turn
94
+ * cannot be copied onto the outbound reply's `slackMeta`. Without this,
95
+ * a channel-root reply following an earlier thread turn would be
96
+ * persisted as if it belonged to the old thread.
97
+ */
98
+ export function clearThreadTs(conversationId: string): void {
99
+ threadMappings.delete(conversationId);
100
+ }
101
+
65
102
  /**
66
103
  * Extract the threadTs from a Slack reply callback URL, if present.
67
104
  * The gateway encodes threadTs as a query parameter on the callback URL.
@@ -65,6 +65,7 @@ function extractPlainTextBody(msg: GmailMessage): string {
65
65
  function mapGmailMessage(msg: GmailMessage): Message {
66
66
  const from = extractHeader(msg, "From");
67
67
  const subject = extractHeader(msg, "Subject");
68
+ const rfc822MessageId = extractHeader(msg, "Message-ID");
68
69
 
69
70
  // Parse sender name/email from "Name <email>" format
70
71
  const emailMatch = from.match(/<([^>]+)>/);
@@ -90,6 +91,7 @@ function mapGmailMessage(msg: GmailMessage): Message {
90
91
  subject,
91
92
  labelIds: msg.labelIds,
92
93
  snippet: msg.snippet,
94
+ ...(rfc822MessageId ? { rfc822MessageId } : {}),
93
95
  },
94
96
  };
95
97
  }
@@ -251,23 +253,11 @@ export const gmailMessagingProvider: MessagingProvider = {
251
253
  options?: HistoryOptions,
252
254
  ): Promise<Message[]> {
253
255
  const conn = requireConnection(connection);
254
- // Get all messages in a Gmail thread
256
+ const thread = await gmail.getThread(conn, threadId, "full");
257
+ const messages = thread.messages ?? [];
258
+ if (!messages.length) return [];
255
259
  const limit = options?.limit ?? 50;
256
- const listResult = await gmail.listMessages(
257
- conn,
258
- `thread:${threadId}`,
259
- limit,
260
- );
261
-
262
- if (!listResult.messages?.length) return [];
263
-
264
- const messages = await gmail.batchGetMessages(
265
- conn,
266
- listResult.messages.map((m) => m.id),
267
- "full",
268
- );
269
-
270
- return messages.map(mapGmailMessage);
260
+ return messages.slice(0, limit).map(mapGmailMessage);
271
261
  },
272
262
 
273
263
  async markRead(
@@ -16,6 +16,7 @@ import type {
16
16
  GmailMessageListResponse,
17
17
  GmailModifyRequest,
18
18
  GmailProfile,
19
+ GmailThread,
19
20
  GmailVacationSettings,
20
21
  } from "./types.js";
21
22
 
@@ -217,6 +218,7 @@ export async function listMessages(
217
218
  maxResults = 20,
218
219
  pageToken?: string,
219
220
  labelIds?: string[],
221
+ signal?: AbortSignal,
220
222
  ): Promise<GmailMessageListResponse> {
221
223
  const params = new URLSearchParams();
222
224
  if (query) params.set("q", query);
@@ -230,6 +232,7 @@ export async function listMessages(
230
232
  "/messages",
231
233
  undefined,
232
234
  paramsToQuery(params),
235
+ signal,
233
236
  );
234
237
  }
235
238
 
@@ -256,6 +259,25 @@ export async function getMessage(
256
259
  );
257
260
  }
258
261
 
262
+ /** Get a thread and all its messages by thread ID. */
263
+ export async function getThread(
264
+ connection: OAuthConnection,
265
+ threadId: string,
266
+ format: GmailMessageFormat = "full",
267
+ metadataHeaders?: string[],
268
+ ): Promise<GmailThread> {
269
+ const params = new URLSearchParams({ format });
270
+ if (format === "metadata" && metadataHeaders) {
271
+ for (const h of metadataHeaders) params.append("metadataHeaders", h);
272
+ }
273
+ return request<GmailThread>(
274
+ connection,
275
+ `/threads/${threadId}`,
276
+ undefined,
277
+ paramsToQuery(params),
278
+ );
279
+ }
280
+
259
281
  /**
260
282
  * Parse a single part from a multipart batch response into its HTTP status and JSON body.
261
283
  * Each part contains MIME headers, then an embedded HTTP response (status line, headers, body).
@@ -44,6 +44,13 @@ export interface GmailMessage {
44
44
  raw?: string;
45
45
  }
46
46
 
47
+ /** Gmail thread response */
48
+ export interface GmailThread {
49
+ id: string;
50
+ historyId?: string;
51
+ messages?: GmailMessage[];
52
+ }
53
+
47
54
  /** Gmail label */
48
55
  export interface GmailLabel {
49
56
  id: string;
@@ -108,7 +108,8 @@ async function runReadWithFallback<T>(
108
108
  if (connection) return call(connection);
109
109
  const auth = getReadAuth(undefined);
110
110
  const usingUserToken =
111
- _cachedSlackWriteAuth !== null && _cachedSlackReadAuth !== _cachedSlackWriteAuth;
111
+ _cachedSlackWriteAuth !== null &&
112
+ _cachedSlackReadAuth !== _cachedSlackWriteAuth;
112
113
  try {
113
114
  return await call(auth);
114
115
  } catch (err) {
@@ -203,6 +204,11 @@ function mapMessage(
203
204
  channelId: string,
204
205
  senderName: string,
205
206
  ): Message {
207
+ // Bot-authored when Slack sets `subtype: "bot_message"` or attributes the
208
+ // row to a `bot_id` with no user. Backfill callers rely on this flag to
209
+ // avoid rehydrating assistant/bot replies as user turns.
210
+ const isBot =
211
+ msg.subtype === "bot_message" || (msg.bot_id != null && !msg.user);
206
212
  return {
207
213
  id: msg.ts,
208
214
  conversationId: channelId,
@@ -214,6 +220,7 @@ function mapMessage(
214
220
  platform: "slack",
215
221
  reactions: msg.reactions?.map((r) => ({ name: r.name, count: r.count })),
216
222
  hasAttachments: (msg.files?.length ?? 0) > 0,
223
+ ...(isBot ? { metadata: { isBot: true } } : {}),
217
224
  };
218
225
  }
219
226
 
@@ -234,7 +241,12 @@ export const slackProvider: MessagingProvider = {
234
241
  id: "slack",
235
242
  displayName: "Slack",
236
243
  credentialService: "slack",
237
- capabilities: new Set(["reactions", "threads", "join_channel", "leave_channel"]),
244
+ capabilities: new Set([
245
+ "reactions",
246
+ "threads",
247
+ "join_channel",
248
+ "leave_channel",
249
+ ]),
238
250
 
239
251
  async isConnected(): Promise<boolean> {
240
252
  // Socket Mode: check for bot token directly in credential store.
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Tests for the daemon-side Slack backfill helpers.
3
+ *
4
+ * Verifies:
5
+ * - Pass-through of channelId, threadTs, and the `before` cursor.
6
+ * - Default limit of 50 when none is supplied; explicit limits override.
7
+ * - resolveConnection() is invoked once per call so any cached read/write
8
+ * auth mutation lands before the adapter method runs.
9
+ * - Transient failure modes (timeout, 401, generic Slack API error, missing
10
+ * connection) return [] instead of propagating the error.
11
+ * - `channel_not_found` errors are rethrown so wrong-workspace configuration
12
+ * bugs in multi-account setups surface loudly rather than silently
13
+ * dropping context.
14
+ * - `account` is threaded through to resolveConnection() when provided.
15
+ */
16
+
17
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
18
+
19
+ import type { OAuthConnection } from "../../../oauth/connection.js";
20
+ import type { Message } from "../../provider-types.js";
21
+
22
+ // ── Module mocks ────────────────────────────────────────────────────────────
23
+
24
+ type ResolveConnectionFn = (
25
+ account?: string,
26
+ ) => Promise<OAuthConnection | undefined>;
27
+ type GetHistoryFn = (
28
+ connection: OAuthConnection | undefined,
29
+ conversationId: string,
30
+ options?: { limit?: number; before?: string; after?: string },
31
+ ) => Promise<Message[]>;
32
+ type GetThreadRepliesFn = (
33
+ connection: OAuthConnection | undefined,
34
+ conversationId: string,
35
+ threadId: string,
36
+ options?: { limit?: number },
37
+ ) => Promise<Message[]>;
38
+
39
+ const resolveConnectionMock = mock<ResolveConnectionFn>(async () => undefined);
40
+ const getHistoryMock = mock<GetHistoryFn>(async () => []);
41
+ const getThreadRepliesMock = mock<GetThreadRepliesFn>(async () => []);
42
+
43
+ mock.module("./adapter.js", () => ({
44
+ slackProvider: {
45
+ id: "slack",
46
+ displayName: "Slack",
47
+ credentialService: "slack",
48
+ capabilities: new Set(["threads"]),
49
+ resolveConnection: (account?: string) => resolveConnectionMock(account),
50
+ getHistory: (
51
+ connection: OAuthConnection | undefined,
52
+ conversationId: string,
53
+ options?: { limit?: number; before?: string; after?: string },
54
+ ) => getHistoryMock(connection, conversationId, options),
55
+ getThreadReplies: (
56
+ connection: OAuthConnection | undefined,
57
+ conversationId: string,
58
+ threadId: string,
59
+ options?: { limit?: number },
60
+ ) => getThreadRepliesMock(connection, conversationId, threadId, options),
61
+ // Stub the rest of the MessagingProvider surface as no-ops; the backfill
62
+ // helpers should never reach for these.
63
+ testConnection: async () => {
64
+ throw new Error("not used");
65
+ },
66
+ listConversations: async () => [],
67
+ search: async () => ({ total: 0, messages: [], hasMore: false }),
68
+ sendMessage: async () => {
69
+ throw new Error("not used");
70
+ },
71
+ },
72
+ }));
73
+
74
+ import { backfillDm, backfillThread } from "./backfill.js";
75
+
76
+ function makeMessage(overrides: Partial<Message> = {}): Message {
77
+ return {
78
+ id: "1700000000.000100",
79
+ conversationId: "C123",
80
+ sender: { id: "U1", name: "Alice" },
81
+ text: "hello",
82
+ timestamp: 1700000000000,
83
+ platform: "slack",
84
+ ...overrides,
85
+ };
86
+ }
87
+
88
+ // ── Tests ────────────────────────────────────────────────────────────────────
89
+
90
+ describe("backfillThread", () => {
91
+ beforeEach(() => {
92
+ resolveConnectionMock.mockReset();
93
+ resolveConnectionMock.mockImplementation(async () => undefined);
94
+ getThreadRepliesMock.mockReset();
95
+ getThreadRepliesMock.mockImplementation(async () => []);
96
+ getHistoryMock.mockReset();
97
+ getHistoryMock.mockImplementation(async () => []);
98
+ });
99
+
100
+ test("passes channelId/threadTs through and defaults limit to 50", async () => {
101
+ const reply = makeMessage({
102
+ id: "1700000000.000200",
103
+ threadId: "1700000000.000100",
104
+ });
105
+ getThreadRepliesMock.mockImplementation(async () => [reply]);
106
+
107
+ const out = await backfillThread("C123", "1700000000.000100");
108
+
109
+ expect(resolveConnectionMock).toHaveBeenCalledTimes(1);
110
+ expect(getThreadRepliesMock).toHaveBeenCalledTimes(1);
111
+ const [conn, channel, thread, opts] = getThreadRepliesMock.mock.calls[0];
112
+ expect(conn).toBeUndefined();
113
+ expect(channel).toBe("C123");
114
+ expect(thread).toBe("1700000000.000100");
115
+ expect(opts).toEqual({ limit: 50 });
116
+ expect(out).toEqual([reply]);
117
+ });
118
+
119
+ test("respects explicit limit override", async () => {
120
+ await backfillThread("C123", "1700000000.000100", { limit: 10 });
121
+ const [, , , opts] = getThreadRepliesMock.mock.calls[0];
122
+ expect(opts).toEqual({ limit: 10 });
123
+ });
124
+
125
+ test("returns [] when getThreadReplies throws (generic Slack API error)", async () => {
126
+ getThreadRepliesMock.mockImplementation(async () => {
127
+ throw new Error("Slack API error: ratelimited");
128
+ });
129
+ const out = await backfillThread("C123", "1700000000.000100");
130
+ expect(out).toEqual([]);
131
+ });
132
+
133
+ test("rethrows channel_not_found so wrong-workspace config surfaces", async () => {
134
+ getThreadRepliesMock.mockImplementation(async () => {
135
+ throw new Error("Slack API error: channel_not_found");
136
+ });
137
+ await expect(backfillThread("C123", "1700000000.000100")).rejects.toThrow(
138
+ /channel_not_found/,
139
+ );
140
+ });
141
+
142
+ test("threads `account` through to resolveConnection", async () => {
143
+ await backfillThread("C123", "1700000000.000100", {
144
+ account: "team-acme",
145
+ });
146
+ expect(resolveConnectionMock).toHaveBeenCalledTimes(1);
147
+ expect(resolveConnectionMock.mock.calls[0][0]).toBe("team-acme");
148
+ });
149
+
150
+ test("returns [] when getThreadReplies throws (auth error)", async () => {
151
+ getThreadRepliesMock.mockImplementation(async () => {
152
+ const err = new Error("Slack API HTTP 401");
153
+ Object.assign(err, { status: 401 });
154
+ throw err;
155
+ });
156
+ const out = await backfillThread("C123", "1700000000.000100");
157
+ expect(out).toEqual([]);
158
+ });
159
+
160
+ test("returns [] when getThreadReplies throws (timeout)", async () => {
161
+ getThreadRepliesMock.mockImplementation(async () => {
162
+ throw new Error("ETIMEDOUT");
163
+ });
164
+ const out = await backfillThread("C123", "1700000000.000100");
165
+ expect(out).toEqual([]);
166
+ });
167
+
168
+ test("returns [] when resolveConnection throws (missing connection)", async () => {
169
+ resolveConnectionMock.mockImplementation(async () => {
170
+ throw new Error("no connection available");
171
+ });
172
+ const out = await backfillThread("C123", "1700000000.000100");
173
+ expect(out).toEqual([]);
174
+ // resolveConnection failed before getThreadReplies could be reached.
175
+ expect(getThreadRepliesMock).not.toHaveBeenCalled();
176
+ });
177
+ });
178
+
179
+ describe("backfillDm", () => {
180
+ beforeEach(() => {
181
+ resolveConnectionMock.mockReset();
182
+ resolveConnectionMock.mockImplementation(async () => undefined);
183
+ getHistoryMock.mockReset();
184
+ getHistoryMock.mockImplementation(async () => []);
185
+ getThreadRepliesMock.mockReset();
186
+ getThreadRepliesMock.mockImplementation(async () => []);
187
+ });
188
+
189
+ test("passes channelId through and defaults limit to 50, before undefined", async () => {
190
+ const msg = makeMessage();
191
+ getHistoryMock.mockImplementation(async () => [msg]);
192
+
193
+ const out = await backfillDm("D123");
194
+
195
+ expect(resolveConnectionMock).toHaveBeenCalledTimes(1);
196
+ expect(getHistoryMock).toHaveBeenCalledTimes(1);
197
+ const [conn, channel, opts] = getHistoryMock.mock.calls[0];
198
+ expect(conn).toBeUndefined();
199
+ expect(channel).toBe("D123");
200
+ expect(opts).toEqual({ limit: 50, before: undefined });
201
+ expect(out).toEqual([msg]);
202
+ });
203
+
204
+ test("respects explicit limit override and forwards `before` cursor", async () => {
205
+ await backfillDm("D123", { limit: 25, before: "1700000000.000099" });
206
+ const [, , opts] = getHistoryMock.mock.calls[0];
207
+ expect(opts).toEqual({ limit: 25, before: "1700000000.000099" });
208
+ });
209
+
210
+ test("returns [] when getHistory throws (generic Slack API error)", async () => {
211
+ getHistoryMock.mockImplementation(async () => {
212
+ throw new Error("Slack API error: not_in_channel");
213
+ });
214
+ const out = await backfillDm("D123");
215
+ expect(out).toEqual([]);
216
+ });
217
+
218
+ test("rethrows channel_not_found so wrong-workspace config surfaces", async () => {
219
+ getHistoryMock.mockImplementation(async () => {
220
+ throw new Error("Slack API error: channel_not_found");
221
+ });
222
+ await expect(backfillDm("D123")).rejects.toThrow(/channel_not_found/);
223
+ });
224
+
225
+ test("threads `account` through to resolveConnection", async () => {
226
+ await backfillDm("D123", { account: "team-acme" });
227
+ expect(resolveConnectionMock).toHaveBeenCalledTimes(1);
228
+ expect(resolveConnectionMock.mock.calls[0][0]).toBe("team-acme");
229
+ });
230
+
231
+ test("returns [] when getHistory throws (auth error)", async () => {
232
+ getHistoryMock.mockImplementation(async () => {
233
+ const err = new Error("Slack API HTTP 401");
234
+ Object.assign(err, { status: 401 });
235
+ throw err;
236
+ });
237
+ const out = await backfillDm("D123");
238
+ expect(out).toEqual([]);
239
+ });
240
+
241
+ test("returns [] when getHistory throws (timeout)", async () => {
242
+ getHistoryMock.mockImplementation(async () => {
243
+ throw new Error("ETIMEDOUT");
244
+ });
245
+ const out = await backfillDm("D123");
246
+ expect(out).toEqual([]);
247
+ });
248
+
249
+ test("returns [] when resolveConnection throws (missing connection)", async () => {
250
+ resolveConnectionMock.mockImplementation(async () => {
251
+ throw new Error("no connection available");
252
+ });
253
+ const out = await backfillDm("D123");
254
+ expect(out).toEqual([]);
255
+ expect(getHistoryMock).not.toHaveBeenCalled();
256
+ });
257
+ });