@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
@@ -1,26 +0,0 @@
1
- import { sendDraft } from "../../../../messaging/providers/gmail/client.js";
2
- import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
3
- import type {
4
- ToolContext,
5
- ToolExecutionResult,
6
- } from "../../../../tools/types.js";
7
- import { err, ok } from "./shared.js";
8
-
9
- export async function run(
10
- input: Record<string, unknown>,
11
- _context: ToolContext,
12
- ): Promise<ToolExecutionResult> {
13
- const account = input.account as string | undefined;
14
- const draftId = input.draft_id as string;
15
- if (!draftId) return err("draft_id is required.");
16
-
17
- try {
18
- const connection = await resolveOAuthConnection("google", {
19
- account,
20
- });
21
- const msg = await sendDraft(connection, draftId);
22
- return ok(`Draft sent (Message ID: ${msg.id}).`);
23
- } catch (e) {
24
- return err(e instanceof Error ? e.message : String(e));
25
- }
26
- }
@@ -1,347 +0,0 @@
1
- import {
2
- batchGetMessages,
3
- listMessages,
4
- } from "../../../../messaging/providers/gmail/client.js";
5
- import type { GmailMessage } from "../../../../messaging/providers/gmail/types.js";
6
- import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
7
- import type {
8
- ToolContext,
9
- ToolExecutionResult,
10
- } from "../../../../tools/types.js";
11
- import { storeScanResult } from "./scan-result-store.js";
12
- import { err, ok } from "./shared.js";
13
-
14
- function isRateLimitError(e: unknown): boolean {
15
- if (!(e instanceof Error)) return false;
16
- return /\b429\b/.test(e.message);
17
- }
18
-
19
- function isAbortError(e: unknown): boolean {
20
- if (e instanceof DOMException && e.name === "AbortError") return true;
21
- if (e instanceof Error && e.message === "fetch deadline exceeded") return true;
22
- // AbortSignal.reason propagated through promise chains
23
- if (
24
- e instanceof Error &&
25
- "cause" in e &&
26
- e.cause instanceof Error &&
27
- e.cause.message === "fetch deadline exceeded"
28
- )
29
- return true;
30
- return false;
31
- }
32
-
33
- const MAX_MESSAGES_CAP = 5000;
34
- const MAX_IDS_PER_SENDER = 5000;
35
- const MAX_SAMPLE_SUBJECTS = 3;
36
- const MAX_SENDERS_CAP = 75;
37
- const MAX_SUBJECT_LENGTH = 80;
38
- const MAX_RESULT_BYTES = 24_000;
39
-
40
- interface SenderAggregation {
41
- displayName: string;
42
- email: string;
43
- messageCount: number;
44
- hasUnsubscribe: boolean;
45
- newestMessageId: string;
46
- newestUnsubscribableMessageId: string | null;
47
- newestUnsubscribableEpoch: number;
48
- oldestDate: string;
49
- newestDate: string;
50
- messageIds: string[];
51
- hasMore: boolean;
52
- sampleSubjects: string[];
53
- }
54
-
55
- /** Parse "Display Name <email@example.com>" into parts. */
56
- function parseFrom(from: string): { displayName: string; email: string } {
57
- const match = from.match(/^(.+?)\s*<([^>]+)>$/);
58
- if (match) {
59
- return {
60
- displayName: match[1].replace(/^["']|["']$/g, "").trim(),
61
- email: match[2].toLowerCase(),
62
- };
63
- }
64
- // Bare email address
65
- const bare = from.trim().toLowerCase();
66
- return { displayName: "", email: bare };
67
- }
68
-
69
- export async function run(
70
- input: Record<string, unknown>,
71
- _context: ToolContext,
72
- ): Promise<ToolExecutionResult> {
73
- const account = input.account as string | undefined;
74
- const query =
75
- (input.query as string) ?? "in:inbox category:promotions newer_than:90d";
76
- const maxMessages = Math.min(
77
- (input.max_messages as number) ?? 2000,
78
- MAX_MESSAGES_CAP,
79
- );
80
- const maxSenders = Math.min(
81
- (input.max_senders as number) ?? 50,
82
- MAX_SENDERS_CAP,
83
- );
84
- const inputPageToken = input.page_token as string | undefined;
85
-
86
- try {
87
- const connection = await resolveOAuthConnection("google", {
88
- account,
89
- });
90
- // Pipeline: fire metadata fetches for each page of IDs as they arrive,
91
- // overlapping fetch latency with pagination latency
92
- const allMessageIds: string[] = [];
93
- const fetchPromises: Promise<GmailMessage[]>[] = [];
94
- const fetchAbort = new AbortController();
95
- let pageToken: string | undefined = inputPageToken;
96
- let truncated = false;
97
- let timeBudgetExceeded = false;
98
- const metadataHeaders = ["From", "List-Unsubscribe", "Subject", "Date"];
99
- const startTime = Date.now();
100
- const TIME_BUDGET_MS = 90_000;
101
-
102
- let rateLimited = false;
103
-
104
- while (allMessageIds.length < maxMessages) {
105
- if (Date.now() - startTime > TIME_BUDGET_MS) {
106
- timeBudgetExceeded = true;
107
- truncated = true;
108
- break;
109
- }
110
- const pageSize = Math.min(100, maxMessages - allMessageIds.length);
111
- let listResp;
112
- try {
113
- listResp = await listMessages(
114
- connection,
115
- query,
116
- pageSize,
117
- pageToken,
118
- );
119
- } catch (e) {
120
- if (isRateLimitError(e)) {
121
- rateLimited = true;
122
- truncated = true;
123
- break;
124
- }
125
- throw e;
126
- }
127
- const ids = (listResp.messages ?? []).map((m) => m.id);
128
- if (ids.length === 0) break;
129
- allMessageIds.push(...ids);
130
- fetchPromises.push(
131
- batchGetMessages(
132
- connection,
133
- ids,
134
- "metadata",
135
- metadataHeaders,
136
- "id,internalDate,payload/headers",
137
- fetchAbort.signal,
138
- ),
139
- );
140
- pageToken = listResp.nextPageToken ?? undefined;
141
- if (!pageToken) break;
142
- }
143
-
144
- // If we stopped because we hit the cap but there were still more pages, flag truncation
145
- if (allMessageIds.length >= maxMessages && pageToken) {
146
- truncated = true;
147
- }
148
-
149
- if (allMessageIds.length === 0) {
150
- if (rateLimited) {
151
- return ok(
152
- JSON.stringify({
153
- senders: [],
154
- total_scanned: 0,
155
- rate_limited: true,
156
- truncated: true,
157
- message:
158
- "Rate limited before any messages could be fetched. Try again later or reduce max_messages.",
159
- }),
160
- );
161
- }
162
- return ok(
163
- JSON.stringify({
164
- senders: [],
165
- total_scanned: 0,
166
- message:
167
- "No emails found matching the query. Try broadening the search (e.g. remove category filter or extend date range).",
168
- }),
169
- );
170
- }
171
-
172
- // Settle all fetch promises — collect successes and tolerate 429 failures.
173
- // Abort in-flight requests when the deadline fires so they don't continue
174
- // consuming API quota in the background.
175
- const elapsedMs = Date.now() - startTime;
176
- const settleDeadlineMs = Math.max(TIME_BUDGET_MS - elapsedMs, 5_000);
177
- const deadlineTimer = setTimeout(() => {
178
- fetchAbort.abort(new Error("fetch deadline exceeded"));
179
- }, settleDeadlineMs);
180
- const settled = await Promise.allSettled(fetchPromises);
181
- clearTimeout(deadlineTimer);
182
- const messages: GmailMessage[] = [];
183
- for (const result of settled) {
184
- if (result.status === "fulfilled") {
185
- messages.push(...result.value);
186
- } else if (isRateLimitError(result.reason)) {
187
- rateLimited = true;
188
- truncated = true;
189
- } else if (isAbortError(result.reason)) {
190
- timeBudgetExceeded = true;
191
- truncated = true;
192
- } else {
193
- throw result.reason;
194
- }
195
- }
196
-
197
- // Group by sender email
198
- const senderMap = new Map<string, SenderAggregation>();
199
-
200
- for (const msg of messages) {
201
- const headers = msg.payload?.headers ?? [];
202
- const fromHeader =
203
- headers.find((h) => h.name.toLowerCase() === "from")?.value ?? "";
204
- const subject =
205
- headers.find((h) => h.name.toLowerCase() === "subject")?.value ?? "";
206
- const dateStr =
207
- headers.find((h) => h.name.toLowerCase() === "date")?.value ?? "";
208
- const listUnsub = headers.find(
209
- (h) => h.name.toLowerCase() === "list-unsubscribe",
210
- )?.value;
211
-
212
- const { displayName, email } = parseFrom(fromHeader);
213
- if (!email) continue;
214
-
215
- let agg = senderMap.get(email);
216
- if (!agg) {
217
- agg = {
218
- displayName,
219
- email,
220
- messageCount: 0,
221
- hasUnsubscribe: false,
222
- newestMessageId: msg.id,
223
- newestUnsubscribableMessageId: null,
224
- newestUnsubscribableEpoch: 0,
225
- oldestDate: dateStr,
226
- newestDate: dateStr,
227
- messageIds: [],
228
- hasMore: false,
229
- sampleSubjects: [],
230
- };
231
- senderMap.set(email, agg);
232
- }
233
-
234
- agg.messageCount++;
235
-
236
- if (listUnsub) agg.hasUnsubscribe = true;
237
-
238
- // Use displayName from earliest message that has one
239
- if (!agg.displayName && displayName) agg.displayName = displayName;
240
-
241
- // Track message IDs (cap at MAX_IDS_PER_SENDER)
242
- if (agg.messageIds.length < MAX_IDS_PER_SENDER) {
243
- agg.messageIds.push(msg.id);
244
- } else {
245
- agg.hasMore = true;
246
- }
247
-
248
- // Track date range - compare using internalDate (epoch ms) for reliability
249
- const msgEpoch = msg.internalDate ? Number(msg.internalDate) : 0;
250
- const oldestEpoch = agg.oldestDate
251
- ? new Date(agg.oldestDate).getTime()
252
- : Infinity;
253
- const newestEpoch = agg.newestDate
254
- ? new Date(agg.newestDate).getTime()
255
- : 0;
256
-
257
- if (msgEpoch > 0 && msgEpoch < oldestEpoch) {
258
- agg.oldestDate = dateStr || agg.oldestDate;
259
- }
260
- if (msgEpoch > newestEpoch) {
261
- agg.newestDate = dateStr || agg.newestDate;
262
- agg.newestMessageId = msg.id;
263
- }
264
-
265
- // Track the newest message that actually has List-Unsubscribe so
266
- // gmail_unsubscribe() is called with a message that carries the header
267
- if (listUnsub && msgEpoch >= agg.newestUnsubscribableEpoch) {
268
- agg.newestUnsubscribableMessageId = msg.id;
269
- agg.newestUnsubscribableEpoch = msgEpoch;
270
- }
271
-
272
- // Collect sample subjects
273
- if (subject && agg.sampleSubjects.length < MAX_SAMPLE_SUBJECTS) {
274
- agg.sampleSubjects.push(subject);
275
- }
276
- }
277
-
278
- // Sort by message count descending, take top N
279
- const sorted = [...senderMap.values()]
280
- .sort((a, b) => b.messageCount - a.messageCount)
281
- .slice(0, maxSenders);
282
-
283
- const resultSenders = sorted.map((s) => ({
284
- id: Buffer.from(s.email).toString("base64url"),
285
- display_name: s.displayName || s.email.split("@")[0],
286
- email: s.email,
287
- message_count: s.messageCount,
288
- has_unsubscribe: s.hasUnsubscribe,
289
- // When unsubscribe is available, point to a message that carries the header
290
- newest_message_id:
291
- s.hasUnsubscribe && s.newestUnsubscribableMessageId
292
- ? s.newestUnsubscribableMessageId
293
- : s.newestMessageId,
294
- oldest_date: s.oldestDate,
295
- newest_date: s.newestDate,
296
- // Preserve original query filters so follow-up searches stay scoped
297
- search_query: `from:${s.email} ${query}`,
298
- sample_subjects: s.sampleSubjects.map((subj) =>
299
- subj.length > MAX_SUBJECT_LENGTH
300
- ? subj.slice(0, MAX_SUBJECT_LENGTH) + "…"
301
- : subj,
302
- ),
303
- }));
304
-
305
- // Trim senders if the serialized result would exceed the byte budget.
306
- // Senders are already sorted by message_count desc, so we drop the
307
- // least-active ones first.
308
- while (resultSenders.length > 1) {
309
- const probe = JSON.stringify({ senders: resultSenders });
310
- if (probe.length <= MAX_RESULT_BYTES) break;
311
- resultSenders.pop();
312
- }
313
-
314
- // Build a set of sender IDs that survived the trim so the scan store
315
- // only holds entries the LLM can reference.
316
- const keptSenderIds = new Set(resultSenders.map((s) => s.id));
317
-
318
- // Store message IDs server-side to keep them out of LLM context
319
- const scanId = storeScanResult(
320
- sorted
321
- .filter((s) =>
322
- keptSenderIds.has(Buffer.from(s.email).toString("base64url")),
323
- )
324
- .map((s) => ({
325
- id: Buffer.from(s.email).toString("base64url"),
326
- messageIds: s.messageIds,
327
- newestMessageId: s.newestMessageId,
328
- newestUnsubscribableMessageId: s.newestUnsubscribableMessageId,
329
- })),
330
- );
331
-
332
- return ok(
333
- JSON.stringify({
334
- scan_id: scanId,
335
- senders: resultSenders,
336
- total_scanned: allMessageIds.length,
337
- query_used: query,
338
- ...(truncated ? { truncated: true } : {}),
339
- ...(timeBudgetExceeded ? { time_budget_exceeded: true } : {}),
340
- ...(rateLimited ? { rate_limited: true } : {}),
341
- note: `message_count reflects emails found per sender within the ${allMessageIds.length} messages scanned. Use scan_id with gmail_archive to archive messages (pass scan_id + sender_ids instead of message_ids).`,
342
- }),
343
- );
344
- } catch (e) {
345
- return err(e instanceof Error ? e.message : String(e));
346
- }
347
- }
@@ -1,29 +0,0 @@
1
- import { trashMessage } from "../../../../messaging/providers/gmail/client.js";
2
- import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
3
- import type {
4
- ToolContext,
5
- ToolExecutionResult,
6
- } from "../../../../tools/types.js";
7
- import { err, ok } from "./shared.js";
8
-
9
- export async function run(
10
- input: Record<string, unknown>,
11
- _context: ToolContext,
12
- ): Promise<ToolExecutionResult> {
13
- const account = input.account as string | undefined;
14
- const messageId = input.message_id as string;
15
-
16
- if (!messageId) {
17
- return err("message_id is required.");
18
- }
19
-
20
- try {
21
- const connection = await resolveOAuthConnection("google", {
22
- account,
23
- });
24
- await trashMessage(connection, messageId);
25
- return ok("Message moved to trash.");
26
- } catch (e) {
27
- return err(e instanceof Error ? e.message : String(e));
28
- }
29
- }
@@ -1,122 +0,0 @@
1
- import {
2
- getMessage,
3
- sendMessage,
4
- } from "../../../../messaging/providers/gmail/client.js";
5
- import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
6
- import {
7
- isPrivateOrLocalHost,
8
- resolveHostAddresses,
9
- resolveRequestAddress,
10
- } from "../../../../tools/network/url-safety.js";
11
- import type {
12
- ToolContext,
13
- ToolExecutionResult,
14
- } from "../../../../tools/types.js";
15
- import { err, ok, pinnedHttpsRequest } from "./shared.js";
16
-
17
- export async function run(
18
- input: Record<string, unknown>,
19
- context: ToolContext,
20
- ): Promise<ToolExecutionResult> {
21
- const account = input.account as string | undefined;
22
- if (!context.triggeredBySurfaceAction && !context.batchAuthorizedByTask) {
23
- return err(
24
- "This tool requires either a surface action or a scheduled task run with this tool in required_tools. Present results in a selection table with action buttons and wait for the user to click before proceeding.",
25
- );
26
- }
27
-
28
- const messageId = input.message_id as string;
29
-
30
- if (!messageId) {
31
- return err("message_id is required.");
32
- }
33
-
34
- try {
35
- const connection = await resolveOAuthConnection("google", {
36
- account,
37
- });
38
- const message = await getMessage(connection, messageId, "metadata", [
39
- "List-Unsubscribe",
40
- "List-Unsubscribe-Post",
41
- ]);
42
- const headers = message.payload?.headers ?? [];
43
- const unsubHeader = headers.find(
44
- (h) => h.name.toLowerCase() === "list-unsubscribe",
45
- )?.value;
46
-
47
- if (!unsubHeader) {
48
- return err(
49
- "No List-Unsubscribe header found. Manual unsubscribe may be required.",
50
- );
51
- }
52
-
53
- const httpsMatch = unsubHeader.match(/<(https:\/\/[^>]+)>/);
54
- const mailtoMatch = unsubHeader.match(/<mailto:([^>]+)>/);
55
- const postHeader = headers.find(
56
- (h) => h.name.toLowerCase() === "list-unsubscribe-post",
57
- )?.value;
58
-
59
- if (httpsMatch) {
60
- const url = httpsMatch[1];
61
- let parsed: URL;
62
- let validatedAddresses: string[];
63
- try {
64
- parsed = new URL(url);
65
- if (parsed.protocol !== "https:") {
66
- return err("Unsubscribe URL must use HTTPS.");
67
- }
68
- if (isPrivateOrLocalHost(parsed.hostname)) {
69
- return err("Unsubscribe URL points to a private or local address.");
70
- }
71
- const { addresses, blockedAddress } = await resolveRequestAddress(
72
- parsed.hostname,
73
- resolveHostAddresses,
74
- false,
75
- );
76
- if (blockedAddress) {
77
- return err("Unsubscribe URL resolves to a private or local address.");
78
- }
79
- if (addresses.length === 0) {
80
- return err("Unable to resolve unsubscribe URL hostname.");
81
- }
82
- validatedAddresses = addresses;
83
- } catch {
84
- return err("Invalid unsubscribe URL.");
85
- }
86
-
87
- const method = postHeader ? "POST" : "GET";
88
- const reqOpts = postHeader
89
- ? {
90
- method: "POST" as const,
91
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
92
- body: postHeader,
93
- }
94
- : undefined;
95
-
96
- let lastStatus = 0;
97
- for (const address of validatedAddresses) {
98
- try {
99
- lastStatus = await pinnedHttpsRequest(parsed, address, reqOpts);
100
- if (lastStatus >= 200 && lastStatus < 400) {
101
- return ok(`Successfully unsubscribed via HTTPS ${method}.`);
102
- }
103
- } catch {
104
- continue;
105
- }
106
- }
107
- return err(`Unsubscribe request failed: ${lastStatus}`);
108
- }
109
-
110
- if (mailtoMatch) {
111
- const mailtoAddr = mailtoMatch[1].split("?")[0];
112
- await sendMessage(connection, mailtoAddr, "Unsubscribe", "Unsubscribe");
113
- return ok(`Unsubscribe email sent to ${mailtoAddr}.`);
114
- }
115
-
116
- return err(
117
- "No supported unsubscribe method found (requires https: or mailto: URL).",
118
- );
119
- } catch (e) {
120
- return err(e instanceof Error ? e.message : String(e));
121
- }
122
- }
@@ -1,67 +0,0 @@
1
- import {
2
- getVacation,
3
- updateVacation,
4
- } from "../../../../messaging/providers/gmail/client.js";
5
- import type { GmailVacationSettings } from "../../../../messaging/providers/gmail/types.js";
6
- import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
7
- import type {
8
- ToolContext,
9
- ToolExecutionResult,
10
- } from "../../../../tools/types.js";
11
- import { err, ok } from "./shared.js";
12
-
13
- export async function run(
14
- input: Record<string, unknown>,
15
- _context: ToolContext,
16
- ): Promise<ToolExecutionResult> {
17
- const account = input.account as string | undefined;
18
- const action = input.action as string;
19
-
20
- if (!action) {
21
- return err("action is required (get, enable, or disable).");
22
- }
23
-
24
- try {
25
- const connection = await resolveOAuthConnection("google", {
26
- account,
27
- });
28
- switch (action) {
29
- case "get": {
30
- const settings = await getVacation(connection);
31
- return ok(JSON.stringify(settings, null, 2));
32
- }
33
-
34
- case "enable": {
35
- const message = input.message as string;
36
- if (!message)
37
- return err("message is required when enabling vacation responder.");
38
-
39
- const settings: GmailVacationSettings = {
40
- enableAutoReply: true,
41
- responseSubject: (input.subject as string) ?? "Out of Office",
42
- responseBodyPlainText: message,
43
- restrictToContacts: (input.restrict_to_contacts as boolean) ?? false,
44
- restrictToDomain: (input.restrict_to_domain as boolean) ?? false,
45
- };
46
-
47
- if (input.start_time) settings.startTime = String(input.start_time);
48
- if (input.end_time) settings.endTime = String(input.end_time);
49
-
50
- const updated = await updateVacation(connection, settings);
51
- return ok(
52
- `Vacation responder enabled.\n${JSON.stringify(updated, null, 2)}`,
53
- );
54
- }
55
-
56
- case "disable": {
57
- await updateVacation(connection, { enableAutoReply: false });
58
- return ok("Vacation responder disabled.");
59
- }
60
-
61
- default:
62
- return err(`Unknown action "${action}". Use get, enable, or disable.`);
63
- }
64
- } catch (e) {
65
- return err(e instanceof Error ? e.message : String(e));
66
- }
67
- }
@@ -1,100 +0,0 @@
1
- import { randomBytes } from "crypto";
2
-
3
- interface SenderData {
4
- messageIds: string[];
5
- newestMessageId: string;
6
- newestUnsubscribableMessageId: string | null;
7
- }
8
-
9
- interface ScanEntry {
10
- senders: Map<string, SenderData>;
11
- createdAt: number;
12
- }
13
-
14
- const MAX_ENTRIES = 16;
15
- const TTL_MS = 30 * 60_000; // 30 minutes
16
-
17
- const _store = new Map<string, ScanEntry>();
18
-
19
- /** Store scan results and return a unique scan ID. */
20
- export function storeScanResult(
21
- senders: Array<{
22
- id: string;
23
- messageIds: string[];
24
- newestMessageId: string;
25
- newestUnsubscribableMessageId: string | null;
26
- }>,
27
- ): string {
28
- const scanId = randomBytes(8).toString("hex");
29
-
30
- // LRU eviction: remove oldest if at capacity
31
- if (_store.size >= MAX_ENTRIES) {
32
- const oldest = _store.keys().next().value;
33
- if (oldest !== undefined) _store.delete(oldest);
34
- }
35
-
36
- const senderMap = new Map<string, SenderData>();
37
- for (const s of senders) {
38
- senderMap.set(s.id, {
39
- messageIds: s.messageIds,
40
- newestMessageId: s.newestMessageId,
41
- newestUnsubscribableMessageId: s.newestUnsubscribableMessageId,
42
- });
43
- }
44
-
45
- _store.set(scanId, { senders: senderMap, createdAt: Date.now() });
46
- return scanId;
47
- }
48
-
49
- /** Retrieve message IDs for the given senders from a scan result. */
50
- export function getSenderMessageIds(
51
- scanId: string,
52
- senderIds: string[],
53
- ): string[] | null {
54
- const entry = _store.get(scanId);
55
- if (!entry) return null;
56
- if (Date.now() - entry.createdAt > TTL_MS) {
57
- _store.delete(scanId);
58
- return null;
59
- }
60
- // LRU: move to end
61
- _store.delete(scanId);
62
- _store.set(scanId, entry);
63
-
64
- const ids: string[] = [];
65
- for (const sid of senderIds) {
66
- const data = entry.senders.get(sid);
67
- if (data) ids.push(...data.messageIds);
68
- }
69
- return ids;
70
- }
71
-
72
- /** Retrieve metadata for a single sender from a scan result. */
73
- export function getSenderMetadata(
74
- scanId: string,
75
- senderId: string,
76
- ): {
77
- newestMessageId: string;
78
- newestUnsubscribableMessageId: string | null;
79
- } | null {
80
- const entry = _store.get(scanId);
81
- if (!entry) return null;
82
- if (Date.now() - entry.createdAt > TTL_MS) {
83
- _store.delete(scanId);
84
- return null;
85
- }
86
- const data = entry.senders.get(senderId);
87
- if (!data) return null;
88
- return {
89
- newestMessageId: data.newestMessageId,
90
- newestUnsubscribableMessageId: data.newestUnsubscribableMessageId,
91
- };
92
- }
93
-
94
- /** Clear the store (for tests). */
95
- export function clearScanStore(): void {
96
- _store.clear();
97
- }
98
-
99
- /** Visible for testing: override TTL check by returning internal store reference. */
100
- export const _internals = { store: _store, TTL_MS };