@vellumai/assistant 0.4.46 → 0.4.49

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 (382) hide show
  1. package/ARCHITECTURE.md +7 -7
  2. package/README.md +2 -23
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/security.md +5 -5
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +1 -1
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/anthropic-provider.test.ts +156 -0
  12. package/src/__tests__/approval-cascade.test.ts +810 -0
  13. package/src/__tests__/approval-primitive.test.ts +0 -1
  14. package/src/__tests__/approval-routes-http.test.ts +2 -0
  15. package/src/__tests__/assistant-attachments.test.ts +12 -34
  16. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  17. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  18. package/src/__tests__/browser-fill-credential.test.ts +5 -2
  19. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  20. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
  21. package/src/__tests__/channel-guardian.test.ts +0 -2
  22. package/src/__tests__/channel-readiness-routes.test.ts +35 -25
  23. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  24. package/src/__tests__/checker.test.ts +9 -29
  25. package/src/__tests__/cli.test.ts +23 -0
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-watcher.test.ts +0 -1
  29. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  30. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  31. package/src/__tests__/context-token-estimator.test.ts +196 -13
  32. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  33. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  34. package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  36. package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
  37. package/src/__tests__/credential-broker-server-use.test.ts +22 -21
  38. package/src/__tests__/credential-broker.test.ts +2 -1
  39. package/src/__tests__/credential-metadata-store.test.ts +239 -26
  40. package/src/__tests__/credential-resolve.test.ts +5 -4
  41. package/src/__tests__/credential-security-e2e.test.ts +8 -8
  42. package/src/__tests__/credential-security-invariants.test.ts +111 -7
  43. package/src/__tests__/credential-vault-unit.test.ts +287 -54
  44. package/src/__tests__/credential-vault.test.ts +406 -12
  45. package/src/__tests__/credentials-cli.test.ts +82 -6
  46. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  47. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  48. package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/gemini-image-service.test.ts +75 -45
  51. package/src/__tests__/gemini-provider.test.ts +9 -6
  52. package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
  53. package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
  54. package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
  55. package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
  56. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  57. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  58. package/src/__tests__/guardian-grant-minting.test.ts +35 -0
  59. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  60. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  61. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  62. package/src/__tests__/heartbeat-service.test.ts +0 -1
  63. package/src/__tests__/host-cu-proxy.test.ts +629 -0
  64. package/src/__tests__/host-shell-tool.test.ts +27 -15
  65. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  66. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  67. package/src/__tests__/integration-status.test.ts +38 -25
  68. package/src/__tests__/intent-routing.test.ts +0 -1
  69. package/src/__tests__/invite-routes-http.test.ts +10 -9
  70. package/src/__tests__/keychain-broker-client.test.ts +11 -43
  71. package/src/__tests__/managed-proxy-context.test.ts +5 -3
  72. package/src/__tests__/media-generate-image.test.ts +63 -2
  73. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
  74. package/src/__tests__/messaging-send-tool.test.ts +4 -6
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +373 -14
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +756 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
  83. package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
  84. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  85. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  86. package/src/__tests__/recording-handler.test.ts +3 -4
  87. package/src/__tests__/registry.test.ts +2 -2
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  91. package/src/__tests__/schema-transforms.test.ts +226 -0
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
  95. package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
  96. package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
  97. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  98. package/src/__tests__/secret-onetime-send.test.ts +5 -3
  99. package/src/__tests__/send-endpoint-busy.test.ts +21 -6
  100. package/src/__tests__/sequence-store.test.ts +0 -1
  101. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  102. package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
  103. package/src/__tests__/skill-include-graph.test.ts +66 -0
  104. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  105. package/src/__tests__/skill-load-tool.test.ts +149 -1
  106. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  107. package/src/__tests__/skills-uninstall.test.ts +3 -3
  108. package/src/__tests__/skills.test.ts +3 -12
  109. package/src/__tests__/slack-channel-config.test.ts +76 -11
  110. package/src/__tests__/slack-share-routes.test.ts +17 -14
  111. package/src/__tests__/system-prompt.test.ts +0 -1
  112. package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
  113. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  114. package/src/__tests__/terminal-tools.test.ts +4 -3
  115. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  116. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  117. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  118. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  119. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  120. package/src/__tests__/tool-executor.test.ts +0 -1
  121. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  122. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  123. package/src/__tests__/trust-store.test.ts +1 -22
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  126. package/src/__tests__/twilio-config.test.ts +2 -1
  127. package/src/__tests__/twilio-provider.test.ts +4 -2
  128. package/src/__tests__/twilio-routes.test.ts +5 -20
  129. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  130. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  131. package/src/agent/ax-tree-compaction.test.ts +235 -0
  132. package/src/agent/loop.ts +76 -130
  133. package/src/calls/call-domain.ts +8 -10
  134. package/src/calls/relay-server.ts +9 -13
  135. package/src/calls/twilio-config.ts +4 -8
  136. package/src/calls/twilio-provider.ts +2 -1
  137. package/src/calls/twilio-rest.ts +2 -1
  138. package/src/calls/twilio-routes.ts +1 -2
  139. package/src/calls/voice-ingress-preflight.ts +1 -1
  140. package/src/cli/commands/browser-relay.ts +46 -15
  141. package/src/cli/commands/completions.ts +0 -3
  142. package/src/cli/commands/credentials.ts +110 -23
  143. package/src/cli/commands/oauth/apps.ts +255 -0
  144. package/src/cli/commands/oauth/connections.ts +299 -0
  145. package/src/cli/commands/oauth/index.ts +52 -0
  146. package/src/cli/commands/oauth/providers.ts +242 -0
  147. package/src/cli/commands/skills.ts +4 -338
  148. package/src/cli/program.ts +1 -5
  149. package/src/cli/reference.ts +1 -3
  150. package/src/cli.ts +3 -2
  151. package/src/config/assistant-feature-flags.ts +0 -3
  152. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  153. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
  154. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  155. package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
  156. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
  157. package/src/config/bundled-skills/gmail/SKILL.md +4 -4
  158. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
  159. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
  160. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
  161. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
  162. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
  163. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
  164. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
  165. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
  166. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
  167. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
  168. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
  169. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
  170. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
  171. package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
  172. package/src/config/bundled-skills/google-calendar/calendar-client.ts +90 -44
  173. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
  174. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
  175. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
  176. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
  177. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
  178. package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
  179. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
  180. package/src/config/bundled-skills/messaging/SKILL.md +6 -6
  181. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
  182. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
  183. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
  184. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
  185. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
  186. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
  187. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
  188. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
  189. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
  190. package/src/config/bundled-skills/messaging/tools/shared.ts +12 -15
  191. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  192. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  193. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  194. package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
  195. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
  196. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
  197. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
  198. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
  199. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
  200. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
  201. package/src/config/env-registry.ts +14 -83
  202. package/src/config/env.ts +11 -50
  203. package/src/config/feature-flag-registry.json +16 -16
  204. package/src/config/schema.ts +3 -1
  205. package/src/config/skills.ts +21 -2
  206. package/src/context/image-dimensions.ts +229 -0
  207. package/src/context/token-estimator.ts +75 -12
  208. package/src/context/window-manager.ts +49 -10
  209. package/src/daemon/assistant-attachments.ts +1 -13
  210. package/src/daemon/guardian-action-generators.ts +4 -5
  211. package/src/daemon/handlers/config-ingress.ts +8 -33
  212. package/src/daemon/handlers/config-slack-channel.ts +76 -56
  213. package/src/daemon/handlers/config-telegram.ts +53 -24
  214. package/src/daemon/handlers/sessions.ts +10 -24
  215. package/src/daemon/handlers/shared.ts +0 -130
  216. package/src/daemon/host-cu-proxy.ts +401 -0
  217. package/src/daemon/lifecycle.ts +39 -63
  218. package/src/daemon/message-protocol.ts +3 -0
  219. package/src/daemon/message-types/computer-use.ts +2 -119
  220. package/src/daemon/message-types/host-cu.ts +19 -0
  221. package/src/daemon/message-types/integrations.ts +1 -0
  222. package/src/daemon/message-types/messages.ts +3 -0
  223. package/src/daemon/server.ts +14 -21
  224. package/src/daemon/session-agent-loop-handlers.ts +2 -0
  225. package/src/daemon/session-attachments.ts +1 -2
  226. package/src/daemon/session-messaging.ts +3 -1
  227. package/src/daemon/session-slash.ts +1 -1
  228. package/src/daemon/session-surfaces.ts +40 -28
  229. package/src/daemon/session-tool-setup.ts +20 -11
  230. package/src/daemon/session.ts +139 -16
  231. package/src/daemon/tool-side-effects.ts +2 -8
  232. package/src/daemon/watch-handler.ts +2 -2
  233. package/src/email/providers/index.ts +2 -1
  234. package/src/events/tool-metrics-listener.ts +2 -2
  235. package/src/hooks/manager.ts +1 -4
  236. package/src/inbound/public-ingress-urls.ts +7 -7
  237. package/src/instrument.ts +15 -1
  238. package/src/logfire.ts +16 -5
  239. package/src/media/app-icon-generator.ts +30 -4
  240. package/src/media/avatar-router.ts +26 -3
  241. package/src/media/gemini-image-service.ts +28 -2
  242. package/src/memory/conversation-key-store.ts +21 -0
  243. package/src/memory/db-init.ts +4 -0
  244. package/src/memory/guardian-action-store.ts +1 -1
  245. package/src/memory/migrations/149-oauth-tables.ts +60 -0
  246. package/src/memory/migrations/index.ts +1 -0
  247. package/src/memory/schema/guardian.ts +1 -1
  248. package/src/memory/schema/index.ts +1 -0
  249. package/src/memory/schema/oauth.ts +65 -0
  250. package/src/messaging/provider.ts +19 -13
  251. package/src/messaging/providers/gmail/adapter.ts +40 -23
  252. package/src/messaging/providers/gmail/client.ts +283 -122
  253. package/src/messaging/providers/gmail/people-client.ts +32 -24
  254. package/src/messaging/providers/slack/adapter.ts +29 -19
  255. package/src/messaging/providers/slack/client.ts +265 -78
  256. package/src/messaging/providers/telegram-bot/adapter.ts +19 -18
  257. package/src/messaging/providers/whatsapp/adapter.ts +17 -11
  258. package/src/messaging/registry.ts +2 -31
  259. package/src/notifications/copy-composer.ts +0 -5
  260. package/src/notifications/signal.ts +4 -5
  261. package/src/oauth/byo-connection.test.ts +537 -0
  262. package/src/oauth/byo-connection.ts +128 -0
  263. package/src/oauth/connect-orchestrator.ts +139 -56
  264. package/src/oauth/connect-types.ts +17 -23
  265. package/src/oauth/connection-resolver.ts +58 -0
  266. package/src/oauth/connection.ts +38 -0
  267. package/src/oauth/manual-token-connection.ts +104 -0
  268. package/src/oauth/oauth-store.ts +496 -0
  269. package/src/oauth/platform-connection.test.ts +192 -0
  270. package/src/oauth/platform-connection.ts +111 -0
  271. package/src/oauth/provider-behaviors.ts +124 -0
  272. package/src/oauth/scope-policy.ts +9 -2
  273. package/src/oauth/seed-providers.ts +161 -0
  274. package/src/oauth/token-persistence.ts +74 -78
  275. package/src/permissions/checker.ts +8 -4
  276. package/src/permissions/defaults.ts +0 -1
  277. package/src/permissions/prompter.ts +10 -1
  278. package/src/permissions/trust-store.ts +13 -0
  279. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  280. package/src/prompts/system-prompt.ts +70 -45
  281. package/src/providers/anthropic/client.ts +133 -24
  282. package/src/providers/gemini/client.ts +15 -6
  283. package/src/providers/managed-proxy/constants.ts +2 -2
  284. package/src/providers/managed-proxy/context.ts +5 -1
  285. package/src/providers/ratelimit.ts +17 -0
  286. package/src/providers/registry.ts +2 -2
  287. package/src/providers/retry.ts +1 -27
  288. package/src/runtime/AGENTS.md +17 -0
  289. package/src/runtime/auth/route-policy.ts +0 -3
  290. package/src/runtime/channel-invite-transports/telegram.ts +2 -1
  291. package/src/runtime/channel-readiness-service.ts +168 -195
  292. package/src/runtime/channel-readiness-types.ts +4 -0
  293. package/src/runtime/channel-reply-delivery.ts +0 -40
  294. package/src/runtime/gateway-client.ts +0 -7
  295. package/src/runtime/guardian-action-conversation-turn.ts +1 -3
  296. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  297. package/src/runtime/guardian-action-message-composer.ts +3 -23
  298. package/src/runtime/http-server.ts +17 -10
  299. package/src/runtime/http-types.ts +2 -3
  300. package/src/runtime/middleware/rate-limiter.ts +74 -20
  301. package/src/runtime/middleware/twilio-validation.ts +1 -11
  302. package/src/runtime/pending-interactions.ts +14 -12
  303. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  304. package/src/runtime/routes/channel-readiness-routes.ts +2 -0
  305. package/src/runtime/routes/conversation-routes.ts +73 -19
  306. package/src/runtime/routes/diagnostics-routes.ts +11 -9
  307. package/src/runtime/routes/events-routes.ts +21 -11
  308. package/src/runtime/routes/guardian-approval-interception.ts +20 -5
  309. package/src/runtime/routes/host-cu-routes.ts +97 -0
  310. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  311. package/src/runtime/routes/integrations/slack/share.ts +6 -6
  312. package/src/runtime/routes/integrations/twilio.ts +6 -5
  313. package/src/runtime/routes/log-export-routes.ts +126 -8
  314. package/src/runtime/routes/secret-routes.ts +3 -2
  315. package/src/runtime/routes/settings-routes.ts +113 -48
  316. package/src/runtime/routes/surface-action-routes.ts +1 -1
  317. package/src/runtime/routes/watch-routes.ts +128 -0
  318. package/src/schedule/integration-status.ts +10 -8
  319. package/src/security/credential-key.ts +14 -0
  320. package/src/security/keychain-broker-client.ts +5 -6
  321. package/src/security/oauth2.ts +1 -1
  322. package/src/security/token-manager.ts +145 -43
  323. package/src/skills/catalog-install.ts +358 -0
  324. package/src/skills/include-graph.ts +32 -0
  325. package/src/telegram/bot-username.ts +2 -3
  326. package/src/tools/apps/definitions.ts +0 -5
  327. package/src/tools/assets/materialize.ts +0 -5
  328. package/src/tools/assets/search.ts +0 -5
  329. package/src/tools/browser/headless-browser.ts +1 -67
  330. package/src/tools/browser/network-recorder.ts +1 -1
  331. package/src/tools/browser/network-recording-types.ts +1 -1
  332. package/src/tools/claude-code/claude-code.ts +0 -5
  333. package/src/tools/computer-use/definitions.ts +46 -11
  334. package/src/tools/computer-use/registry.ts +4 -5
  335. package/src/tools/credentials/broker.ts +5 -4
  336. package/src/tools/credentials/metadata-store.ts +22 -74
  337. package/src/tools/credentials/resolve.ts +2 -1
  338. package/src/tools/credentials/vault.ts +139 -151
  339. package/src/tools/filesystem/edit.ts +1 -6
  340. package/src/tools/filesystem/read.ts +0 -5
  341. package/src/tools/filesystem/write.ts +1 -6
  342. package/src/tools/host-filesystem/edit.ts +1 -6
  343. package/src/tools/host-filesystem/read.ts +1 -6
  344. package/src/tools/host-filesystem/write.ts +1 -6
  345. package/src/tools/mcp/mcp-tool-factory.ts +18 -1
  346. package/src/tools/memory/definitions.ts +0 -5
  347. package/src/tools/network/web-fetch.ts +0 -5
  348. package/src/tools/network/web-search.ts +0 -5
  349. package/src/tools/registry.ts +2 -7
  350. package/src/tools/schema-transforms.ts +99 -0
  351. package/src/tools/skills/load.ts +62 -8
  352. package/src/tools/swarm/delegate.ts +0 -5
  353. package/src/tools/system/avatar-generator.ts +0 -5
  354. package/src/tools/ui-surface/definitions.ts +0 -15
  355. package/src/tools/watch/screen-watch.ts +0 -5
  356. package/src/tools/watch/watch-state.ts +0 -12
  357. package/src/util/logger.ts +7 -41
  358. package/src/util/platform.ts +9 -28
  359. package/src/version.ts +10 -0
  360. package/src/watcher/providers/github.ts +51 -52
  361. package/src/watcher/providers/gmail.ts +88 -80
  362. package/src/watcher/providers/google-calendar.ts +94 -86
  363. package/src/watcher/providers/linear.ts +87 -93
  364. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  365. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  366. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  367. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  368. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  369. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  370. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  371. package/src/cli/commands/dev.ts +0 -129
  372. package/src/cli/commands/map.ts +0 -391
  373. package/src/cli/commands/oauth.ts +0 -77
  374. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
  375. package/src/daemon/computer-use-session.ts +0 -1020
  376. package/src/daemon/ride-shotgun-handler.ts +0 -567
  377. package/src/oauth/provider-profiles.ts +0 -192
  378. package/src/prompts/computer-use-prompt.ts +0 -98
  379. package/src/runtime/routes/computer-use-routes.ts +0 -641
  380. package/src/runtime/telegram-streaming-delivery.test.ts +0 -597
  381. package/src/runtime/telegram-streaming-delivery.ts +0 -383
  382. package/src/tools/computer-use/request-computer-control.ts +0 -61
@@ -2,7 +2,7 @@ import type {
2
2
  ToolContext,
3
3
  ToolExecutionResult,
4
4
  } from "../../../../tools/types.js";
5
- import { err, ok, resolveProvider, withProviderToken } from "./shared.js";
5
+ import { err, getProviderConnection, ok, resolveProvider } from "./shared.js";
6
6
 
7
7
  export async function run(
8
8
  input: Record<string, unknown>,
@@ -23,47 +23,46 @@ export async function run(
23
23
  );
24
24
  }
25
25
 
26
- return withProviderToken(provider, async (token) => {
27
- const result = await provider.senderDigest!(token, query, {
28
- maxMessages,
29
- maxSenders,
30
- pageToken,
31
- });
32
-
33
- if (result.senders.length === 0) {
34
- return ok(
35
- JSON.stringify({
36
- senders: [],
37
- total_scanned: result.totalScanned,
38
- query_used: result.queryUsed,
39
- ...(result.truncated ? { truncated: true } : {}),
40
- message:
41
- "No emails found matching the query. Try broadening the search (e.g. remove category filter or extend date range).",
42
- }),
43
- );
44
- }
45
-
46
- // Map to snake_case output format for LLM consumption
47
- const senders = result.senders.map((s) => ({
48
- id: s.id,
49
- display_name: s.displayName,
50
- email: s.email,
51
- message_count: s.messageCount,
52
- has_unsubscribe: s.hasUnsubscribe,
53
- newest_message_id: s.newestMessageId,
54
- search_query: s.searchQuery,
55
- }));
26
+ const conn = getProviderConnection(provider);
27
+ const result = await provider.senderDigest!(conn, query, {
28
+ maxMessages,
29
+ maxSenders,
30
+ pageToken,
31
+ });
56
32
 
33
+ if (result.senders.length === 0) {
57
34
  return ok(
58
35
  JSON.stringify({
59
- senders,
36
+ senders: [],
60
37
  total_scanned: result.totalScanned,
61
38
  query_used: result.queryUsed,
62
39
  ...(result.truncated ? { truncated: true } : {}),
63
- note: `message_count reflects emails found per sender within the ${result.totalScanned} messages scanned. Use messaging_archive_by_sender with the sender's search_query to archive their messages.`,
40
+ message:
41
+ "No emails found matching the query. Try broadening the search (e.g. remove category filter or extend date range).",
64
42
  }),
65
43
  );
66
- });
44
+ }
45
+
46
+ // Map to snake_case output format for LLM consumption
47
+ const senders = result.senders.map((s) => ({
48
+ id: s.id,
49
+ display_name: s.displayName,
50
+ email: s.email,
51
+ message_count: s.messageCount,
52
+ has_unsubscribe: s.hasUnsubscribe,
53
+ newest_message_id: s.newestMessageId,
54
+ search_query: s.searchQuery,
55
+ }));
56
+
57
+ return ok(
58
+ JSON.stringify({
59
+ senders,
60
+ total_scanned: result.totalScanned,
61
+ query_used: result.queryUsed,
62
+ ...(result.truncated ? { truncated: true } : {}),
63
+ note: `message_count reflects emails found per sender within the ${result.totalScanned} messages scanned. Use messaging_archive_by_sender with the sender's search_query to archive their messages.`,
64
+ }),
65
+ );
67
66
  } catch (e) {
68
67
  return err(e instanceof Error ? e.message : String(e));
69
68
  }
@@ -6,9 +6,9 @@ import type { MessagingProvider } from "../../../../messaging/provider.js";
6
6
  import {
7
7
  getConnectedProviders,
8
8
  getMessagingProvider,
9
- isPlatformEnabled,
10
9
  } from "../../../../messaging/registry.js";
11
- import { withValidToken } from "../../../../security/token-manager.js";
10
+ import type { OAuthConnection } from "../../../../oauth/connection.js";
11
+ import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
12
12
  import type { ToolExecutionResult } from "../../../../tools/types.js";
13
13
 
14
14
  export function ok(content: string): ToolExecutionResult {
@@ -109,9 +109,7 @@ export function extractEmail(address: string): string {
109
109
  export function resolveProvider(platformInput?: string): MessagingProvider {
110
110
  if (platformInput) return getMessagingProvider(platformInput);
111
111
 
112
- const connected = getConnectedProviders().filter((p) =>
113
- isPlatformEnabled(p.id),
114
- );
112
+ const connected = getConnectedProviders();
115
113
  if (connected.length === 1) return connected[0];
116
114
  if (connected.length === 0) {
117
115
  throw new Error(
@@ -126,16 +124,15 @@ export function resolveProvider(platformInput?: string): MessagingProvider {
126
124
  }
127
125
 
128
126
  /**
129
- * Execute a callback with a valid OAuth token for the given provider.
130
- * Providers that manage their own auth (e.g. Telegram with a bot token)
131
- * expose isConnected() and don't need an OAuth access_token lookup.
127
+ * Resolve an OAuthConnection (or empty string for non-OAuth providers)
128
+ * for the given messaging provider.
129
+ *
130
+ * Non-OAuth providers (e.g. Telegram) use isConnected() and don't need
131
+ * tokens — they receive an empty string which the string overload handles.
132
132
  */
133
- export async function withProviderToken<T>(
133
+ export function getProviderConnection(
134
134
  provider: MessagingProvider,
135
- fn: (token: string) => Promise<T>,
136
- ): Promise<T> {
137
- if (provider.isConnected?.()) {
138
- return fn("");
139
- }
140
- return withValidToken(provider.credentialService, fn);
135
+ ): OAuthConnection | string {
136
+ if (provider.isConnected?.()) return "";
137
+ return resolveOAuthConnection(provider.credentialService);
141
138
  }
@@ -9,4 +9,4 @@ metadata:
9
9
  user-invocable: true
10
10
  ---
11
11
 
12
- Tools for managing assistant settings: voice configuration (TTS voice, PTT activation key, wake word), avatar generation, system settings navigation, and in-app settings tab navigation.
12
+ Tools for managing assistant settings: voice configuration (TTS voice, PTT activation key, conversation timeout), avatar generation, system settings navigation, and in-app settings tab navigation.
@@ -3,7 +3,7 @@
3
3
  "tools": [
4
4
  {
5
5
  "name": "voice_config_update",
6
- "description": "Update a voice configuration setting (TTS voice ID, PTT activation key, wake word enabled/keyword/timeout). Changes take effect immediately.",
6
+ "description": "Update a voice configuration setting (TTS voice ID, PTT activation key, conversation timeout). Changes take effect immediately.",
7
7
  "category": "system",
8
8
  "risk": "low",
9
9
  "input_schema": {
@@ -11,13 +11,7 @@
11
11
  "properties": {
12
12
  "setting": {
13
13
  "type": "string",
14
- "enum": [
15
- "activation_key",
16
- "wake_word_enabled",
17
- "wake_word_keyword",
18
- "wake_word_timeout",
19
- "tts_voice_id"
20
- ],
14
+ "enum": ["activation_key", "conversation_timeout", "tts_voice_id"],
21
15
  "description": "The voice setting to change"
22
16
  },
23
17
  "value": {
@@ -18,16 +18,8 @@ const VOICE_SETTINGS = {
18
18
  userDefaultsKey: "pttActivationKey",
19
19
  type: "string" as const,
20
20
  },
21
- wake_word_enabled: {
22
- userDefaultsKey: "wakeWordEnabled",
23
- type: "boolean" as const,
24
- },
25
- wake_word_keyword: {
26
- userDefaultsKey: "wakeWordKeyword",
27
- type: "string" as const,
28
- },
29
- wake_word_timeout: {
30
- userDefaultsKey: "wakeWordTimeoutSeconds",
21
+ conversation_timeout: {
22
+ userDefaultsKey: "voiceConversationTimeoutSeconds",
31
23
  type: "number" as const,
32
24
  },
33
25
  tts_voice_id: { userDefaultsKey: "ttsVoiceId", type: "string" as const },
@@ -41,9 +33,7 @@ const VALID_TIMEOUTS = [5, 10, 15, 30, 60];
41
33
 
42
34
  const FRIENDLY_NAMES: Record<VoiceSettingName, string> = {
43
35
  activation_key: "PTT activation key",
44
- wake_word_enabled: "Wake word",
45
- wake_word_keyword: "Wake word keyword",
46
- wake_word_timeout: "Wake word timeout",
36
+ conversation_timeout: "Conversation timeout",
47
37
  tts_voice_id: "ElevenLabs voice",
48
38
  };
49
39
 
@@ -76,30 +66,12 @@ function validateSetting(
76
66
  }
77
67
  return { ok: true, coerced: result.value };
78
68
  }
79
- case "wake_word_enabled": {
80
- if (typeof value === "boolean") return { ok: true, coerced: value };
81
- if (value === "true") return { ok: true, coerced: true };
82
- if (value === "false") return { ok: true, coerced: false };
83
- return {
84
- ok: false,
85
- error: 'wake_word_enabled must be a boolean (or "true"/"false" string)',
86
- };
87
- }
88
- case "wake_word_keyword": {
89
- if (typeof value !== "string" || value.trim().length === 0) {
90
- return {
91
- ok: false,
92
- error: "wake_word_keyword must be a non-empty string",
93
- };
94
- }
95
- return { ok: true, coerced: value.trim() };
96
- }
97
- case "wake_word_timeout": {
69
+ case "conversation_timeout": {
98
70
  const num = typeof value === "number" ? value : Number(value);
99
71
  if (Number.isNaN(num) || !VALID_TIMEOUTS.includes(num)) {
100
72
  return {
101
73
  ok: false,
102
- error: `wake_word_timeout must be one of: ${VALID_TIMEOUTS.join(
74
+ error: `conversation_timeout must be one of: ${VALID_TIMEOUTS.join(
103
75
  ", ",
104
76
  )}`,
105
77
  };
@@ -2,8 +2,8 @@
2
2
  * Shared utilities for slack skill tools.
3
3
  */
4
4
 
5
- import { getMessagingProvider } from "../../../../messaging/registry.js";
6
- import { withValidToken } from "../../../../security/token-manager.js";
5
+ import type { OAuthConnection } from "../../../../oauth/connection.js";
6
+ import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
7
7
  import type { ToolExecutionResult } from "../../../../tools/types.js";
8
8
 
9
9
  export function ok(content: string): ToolExecutionResult {
@@ -14,12 +14,6 @@ export function err(message: string): ToolExecutionResult {
14
14
  return { content: message, isError: true };
15
15
  }
16
16
 
17
- /**
18
- * Execute a callback with a valid Slack OAuth token.
19
- */
20
- export async function withSlackToken<T>(
21
- fn: (token: string) => Promise<T>,
22
- ): Promise<T> {
23
- const provider = getMessagingProvider("slack");
24
- return withValidToken(provider.credentialService, fn);
17
+ export function getSlackConnection(): OAuthConnection {
18
+ return resolveOAuthConnection("integration:slack");
25
19
  }
@@ -3,7 +3,7 @@ import type {
3
3
  ToolContext,
4
4
  ToolExecutionResult,
5
5
  } from "../../../../tools/types.js";
6
- import { err, ok, withSlackToken } from "./shared.js";
6
+ import { err, getSlackConnection, ok } from "./shared.js";
7
7
 
8
8
  export async function run(
9
9
  input: Record<string, unknown>,
@@ -18,10 +18,9 @@ export async function run(
18
18
  }
19
19
 
20
20
  try {
21
- return await withSlackToken(async (token) => {
22
- await addReaction(token, channel, timestamp, emoji);
23
- return ok(`Added :${emoji}: reaction.`);
24
- });
21
+ const connection = getSlackConnection();
22
+ await addReaction(connection, channel, timestamp, emoji);
23
+ return ok(`Added :${emoji}: reaction.`);
25
24
  } catch (e) {
26
25
  return err(e instanceof Error ? e.message : String(e));
27
26
  }
@@ -3,7 +3,7 @@ import type {
3
3
  ToolContext,
4
4
  ToolExecutionResult,
5
5
  } from "../../../../tools/types.js";
6
- import { err, ok, withSlackToken } from "./shared.js";
6
+ import { err, getSlackConnection, ok } from "./shared.js";
7
7
 
8
8
  export async function run(
9
9
  input: Record<string, unknown>,
@@ -16,23 +16,22 @@ export async function run(
16
16
  }
17
17
 
18
18
  try {
19
- return await withSlackToken(async (token) => {
20
- const resp = await slack.conversationInfo(token, channelId);
21
- const conv = resp.channel;
19
+ const connection = getSlackConnection();
20
+ const resp = await slack.conversationInfo(connection, channelId);
21
+ const conv = resp.channel;
22
22
 
23
- const result = {
24
- channelId: conv.id,
25
- name: conv.name ?? conv.id,
26
- topic: conv.topic?.value || null,
27
- purpose: conv.purpose?.value || null,
28
- isPrivate: conv.is_private ?? conv.is_group ?? false,
29
- isArchived: conv.is_archived ?? false,
30
- memberCount: conv.num_members ?? null,
31
- latestActivityTs: conv.latest?.ts ?? null,
32
- };
23
+ const result = {
24
+ channelId: conv.id,
25
+ name: conv.name ?? conv.id,
26
+ topic: conv.topic?.value || null,
27
+ purpose: conv.purpose?.value || null,
28
+ isPrivate: conv.is_private ?? conv.is_group ?? false,
29
+ isArchived: conv.is_archived ?? false,
30
+ memberCount: conv.num_members ?? null,
31
+ latestActivityTs: conv.latest?.ts ?? null,
32
+ };
33
33
 
34
- return ok(JSON.stringify(result, null, 2));
35
- });
34
+ return ok(JSON.stringify(result, null, 2));
36
35
  } catch (e) {
37
36
  return err(e instanceof Error ? e.message : String(e));
38
37
  }
@@ -3,7 +3,7 @@ import type {
3
3
  ToolContext,
4
4
  ToolExecutionResult,
5
5
  } from "../../../../tools/types.js";
6
- import { err, ok, withSlackToken } from "./shared.js";
6
+ import { err, getSlackConnection, ok } from "./shared.js";
7
7
 
8
8
  export async function run(
9
9
  input: Record<string, unknown>,
@@ -17,10 +17,9 @@ export async function run(
17
17
  }
18
18
 
19
19
  try {
20
- return await withSlackToken(async (token) => {
21
- await deleteMessage(token, channel, timestamp);
22
- return ok(`Message deleted.`);
23
- });
20
+ const connection = getSlackConnection();
21
+ await deleteMessage(connection, channel, timestamp);
22
+ return ok(`Message deleted.`);
24
23
  } catch (e) {
25
24
  return err(e instanceof Error ? e.message : String(e));
26
25
  }
@@ -3,7 +3,7 @@ import type {
3
3
  ToolContext,
4
4
  ToolExecutionResult,
5
5
  } from "../../../../tools/types.js";
6
- import { err, ok, withSlackToken } from "./shared.js";
6
+ import { err, getSlackConnection, ok } from "./shared.js";
7
7
 
8
8
  export async function run(
9
9
  input: Record<string, unknown>,
@@ -18,10 +18,9 @@ export async function run(
18
18
  }
19
19
 
20
20
  try {
21
- return await withSlackToken(async (token) => {
22
- await updateMessage(token, channel, timestamp, text);
23
- return ok(`Message updated.`);
24
- });
21
+ const connection = getSlackConnection();
22
+ await updateMessage(connection, channel, timestamp, text);
23
+ return ok(`Message updated.`);
25
24
  } catch (e) {
26
25
  return err(e instanceof Error ? e.message : String(e));
27
26
  }
@@ -3,7 +3,7 @@ import type {
3
3
  ToolContext,
4
4
  ToolExecutionResult,
5
5
  } from "../../../../tools/types.js";
6
- import { err, ok, withSlackToken } from "./shared.js";
6
+ import { err, getSlackConnection, ok } from "./shared.js";
7
7
 
8
8
  export async function run(
9
9
  input: Record<string, unknown>,
@@ -16,10 +16,9 @@ export async function run(
16
16
  }
17
17
 
18
18
  try {
19
- return await withSlackToken(async (token) => {
20
- await leaveConversation(token, channel);
21
- return ok("Left channel.");
22
- });
19
+ const connection = getSlackConnection();
20
+ await leaveConversation(connection, channel);
21
+ return ok("Left channel.");
23
22
  } catch (e) {
24
23
  return err(e instanceof Error ? e.message : String(e));
25
24
  }
@@ -1,11 +1,12 @@
1
1
  import { getConfig } from "../../../../config/loader.js";
2
2
  import * as slack from "../../../../messaging/providers/slack/client.js";
3
3
  import type { SlackConversation } from "../../../../messaging/providers/slack/types.js";
4
+ import type { OAuthConnection } from "../../../../oauth/connection.js";
4
5
  import type {
5
6
  ToolContext,
6
7
  ToolExecutionResult,
7
8
  } from "../../../../tools/types.js";
8
- import { err, ok, withSlackToken } from "./shared.js";
9
+ import { err, getSlackConnection, ok } from "./shared.js";
9
10
 
10
11
  interface ThreadSummary {
11
12
  threadTs: string;
@@ -26,13 +27,16 @@ interface ChannelDigest {
26
27
 
27
28
  const userNameCache = new Map<string, string>();
28
29
 
29
- async function resolveUserName(token: string, userId: string): Promise<string> {
30
+ async function resolveUserName(
31
+ connection: OAuthConnection,
32
+ userId: string,
33
+ ): Promise<string> {
30
34
  if (!userId) return "unknown";
31
35
  const cached = userNameCache.get(userId);
32
36
  if (cached) return cached;
33
37
 
34
38
  try {
35
- const resp = await slack.userInfo(token, userId);
39
+ const resp = await slack.userInfo(connection, userId);
36
40
  const name =
37
41
  resp.user.profile?.display_name ||
38
42
  resp.user.profile?.real_name ||
@@ -46,7 +50,7 @@ async function resolveUserName(token: string, userId: string): Promise<string> {
46
50
  }
47
51
 
48
52
  async function scanChannel(
49
- token: string,
53
+ connection: OAuthConnection,
50
54
  conv: SlackConversation,
51
55
  oldestTs: string,
52
56
  includeThreads: boolean,
@@ -57,7 +61,7 @@ async function scanChannel(
57
61
 
58
62
  try {
59
63
  const history = await slack.conversationHistory(
60
- token,
64
+ connection,
61
65
  channelId,
62
66
  100,
63
67
  undefined,
@@ -71,7 +75,7 @@ async function scanChannel(
71
75
  }
72
76
 
73
77
  const keyParticipants = await Promise.all(
74
- [...participantIds].map((uid) => resolveUserName(token, uid)),
78
+ [...participantIds].map((uid) => resolveUserName(connection, uid)),
75
79
  );
76
80
 
77
81
  const threadMessages = messages
@@ -86,7 +90,7 @@ async function scanChannel(
86
90
  if (includeThreads) {
87
91
  try {
88
92
  const replies = await slack.conversationReplies(
89
- token,
93
+ connection,
90
94
  channelId,
91
95
  msg.ts,
92
96
  10,
@@ -97,11 +101,11 @@ async function scanChannel(
97
101
  }
98
102
  participants = await Promise.all(
99
103
  [...threadParticipantIds].map((uid) =>
100
- resolveUserName(token, uid),
104
+ resolveUserName(connection, uid),
101
105
  ),
102
106
  );
103
107
  } catch {
104
- participants = [await resolveUserName(token, msg.user ?? "")];
108
+ participants = [await resolveUserName(connection, msg.user ?? "")];
105
109
  }
106
110
  }
107
111
 
@@ -260,15 +264,34 @@ export async function run(
260
264
  const format = (input.format as string) ?? "text";
261
265
 
262
266
  try {
263
- return await withSlackToken(async (token) => {
264
- const oldestTs = String((Date.now() - hoursBack * 60 * 60 * 1000) / 1000);
267
+ const connection = getSlackConnection();
268
+ const oldestTs = String((Date.now() - hoursBack * 60 * 60 * 1000) / 1000);
265
269
 
266
- let channelsToScan: SlackConversation[];
267
- let failedLookups = 0;
270
+ let channelsToScan: SlackConversation[];
271
+ let failedLookups = 0;
268
272
 
269
- if (channelIds?.length) {
273
+ if (channelIds?.length) {
274
+ const results = await Promise.allSettled(
275
+ channelIds.map((id) => slack.conversationInfo(connection, id)),
276
+ );
277
+ channelsToScan = results
278
+ .filter(
279
+ (
280
+ r,
281
+ ): r is PromiseFulfilledResult<
282
+ Awaited<ReturnType<typeof slack.conversationInfo>>
283
+ > => r.status === "fulfilled",
284
+ )
285
+ .map((r) => r.value.channel);
286
+ failedLookups = results.filter((r) => r.status === "rejected").length;
287
+ } else {
288
+ const config = getConfig();
289
+ const preferredIds = config.skills?.entries?.slack?.config
290
+ ?.preferredChannels as string[] | undefined;
291
+
292
+ if (preferredIds?.length) {
270
293
  const results = await Promise.allSettled(
271
- channelIds.map((id) => slack.conversationInfo(token, id)),
294
+ preferredIds.map((id) => slack.conversationInfo(connection, id)),
272
295
  );
273
296
  channelsToScan = results
274
297
  .filter(
@@ -281,89 +304,69 @@ export async function run(
281
304
  .map((r) => r.value.channel);
282
305
  failedLookups = results.filter((r) => r.status === "rejected").length;
283
306
  } else {
284
- const config = getConfig();
285
- const preferredIds = config.skills?.entries?.slack?.config
286
- ?.preferredChannels as string[] | undefined;
287
-
288
- if (preferredIds?.length) {
289
- const results = await Promise.allSettled(
290
- preferredIds.map((id) => slack.conversationInfo(token, id)),
307
+ const allChannels: SlackConversation[] = [];
308
+ let cursor: string | undefined;
309
+ do {
310
+ const resp = await slack.listConversations(
311
+ connection,
312
+ "public_channel,private_channel",
313
+ true,
314
+ 200,
315
+ cursor,
291
316
  );
292
- channelsToScan = results
293
- .filter(
294
- (
295
- r,
296
- ): r is PromiseFulfilledResult<
297
- Awaited<ReturnType<typeof slack.conversationInfo>>
298
- > => r.status === "fulfilled",
299
- )
300
- .map((r) => r.value.channel);
301
- failedLookups = results.filter((r) => r.status === "rejected").length;
302
- } else {
303
- const allChannels: SlackConversation[] = [];
304
- let cursor: string | undefined;
305
- do {
306
- const resp = await slack.listConversations(
307
- token,
308
- "public_channel,private_channel",
309
- true,
310
- 200,
311
- cursor,
312
- );
313
- allChannels.push(...resp.channels);
314
- cursor = resp.response_metadata?.next_cursor || undefined;
315
- } while (cursor);
316
-
317
- channelsToScan = allChannels
318
- .filter((c) => c.is_member)
319
- .sort((a, b) => {
320
- const aTs = a.latest?.ts ? parseFloat(a.latest.ts) : 0;
321
- const bTs = b.latest?.ts ? parseFloat(b.latest.ts) : 0;
322
- return bTs - aTs;
323
- })
324
- .slice(0, maxChannels);
325
- }
317
+ allChannels.push(...resp.channels);
318
+ cursor = resp.response_metadata?.next_cursor || undefined;
319
+ } while (cursor);
320
+
321
+ channelsToScan = allChannels
322
+ .filter((c) => c.is_member)
323
+ .sort((a, b) => {
324
+ const aTs = a.latest?.ts ? parseFloat(a.latest.ts) : 0;
325
+ const bTs = b.latest?.ts ? parseFloat(b.latest.ts) : 0;
326
+ return bTs - aTs;
327
+ })
328
+ .slice(0, maxChannels);
326
329
  }
330
+ }
327
331
 
328
- const scanResults = await Promise.allSettled(
329
- channelsToScan.map((conv) =>
330
- scanChannel(token, conv, oldestTs, includeThreads),
331
- ),
332
- );
333
-
334
- const digests: ChannelDigest[] = scanResults
335
- .filter(
336
- (r): r is PromiseFulfilledResult<ChannelDigest> =>
337
- r.status === "fulfilled",
338
- )
339
- .map((r) => r.value)
340
- .filter((d) => d.messageCount > 0 || d.error);
341
-
342
- const skippedCount = scanResults.filter(
343
- (r) => r.status === "rejected",
344
- ).length;
345
-
346
- if (format === "blocks") {
347
- const blocks = buildBlockKitOutput(
348
- digests,
349
- hoursBack,
350
- channelsToScan.length,
351
- skippedCount,
352
- );
353
- return ok(JSON.stringify({ blocks }, null, 2));
354
- }
332
+ const scanResults = await Promise.allSettled(
333
+ channelsToScan.map((conv) =>
334
+ scanChannel(connection, conv, oldestTs, includeThreads),
335
+ ),
336
+ );
355
337
 
356
- const result = {
357
- scannedChannels: digests.length,
358
- totalChannelsAttempted: channelsToScan.length,
359
- skippedDueToErrors: skippedCount,
360
- failedLookups,
338
+ const digests: ChannelDigest[] = scanResults
339
+ .filter(
340
+ (r): r is PromiseFulfilledResult<ChannelDigest> =>
341
+ r.status === "fulfilled",
342
+ )
343
+ .map((r) => r.value)
344
+ .filter((d) => d.messageCount > 0 || d.error);
345
+
346
+ const skippedCount = scanResults.filter(
347
+ (r) => r.status === "rejected",
348
+ ).length;
349
+
350
+ if (format === "blocks") {
351
+ const blocks = buildBlockKitOutput(
352
+ digests,
361
353
  hoursBack,
362
- channels: digests,
363
- };
354
+ channelsToScan.length,
355
+ skippedCount,
356
+ );
357
+ return ok(JSON.stringify({ blocks }, null, 2));
358
+ }
364
359
 
365
- return ok(JSON.stringify(result, null, 2));
366
- });
360
+ const result = {
361
+ scannedChannels: digests.length,
362
+ totalChannelsAttempted: channelsToScan.length,
363
+ skippedDueToErrors: skippedCount,
364
+ failedLookups,
365
+ hoursBack,
366
+ channels: digests,
367
+ };
368
+
369
+ return ok(JSON.stringify(result, null, 2));
367
370
  } catch (e) {
368
371
  return err(e instanceof Error ? e.message : String(e));
369
372
  }