@vellumai/assistant 0.6.3 → 0.6.4

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 (667) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +5 -13
  4. package/docs/backup-troubleshooting.md +52 -0
  5. package/docs/browser-use-architecture-phase2.md +174 -0
  6. package/docs/stt-provider-onboarding.md +120 -0
  7. package/knip.json +12 -2
  8. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  9. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  10. package/openapi.yaml +982 -72
  11. package/package.json +4 -6
  12. package/scripts/generate-openapi.ts +0 -1
  13. package/scripts/test.sh +73 -18
  14. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  15. package/src/__tests__/agent-loop.test.ts +123 -0
  16. package/src/__tests__/anthropic-provider.test.ts +263 -10
  17. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  18. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  19. package/src/__tests__/browser-fill-credential.test.ts +11 -0
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  22. package/src/__tests__/btw-routes.test.ts +7 -0
  23. package/src/__tests__/call-controller.test.ts +581 -20
  24. package/src/__tests__/catalog-files.test.ts +138 -0
  25. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  26. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  27. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  28. package/src/__tests__/checker.test.ts +157 -10
  29. package/src/__tests__/clawhub-files.test.ts +347 -0
  30. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  31. package/src/__tests__/config-analysis.test.ts +100 -0
  32. package/src/__tests__/config-schema.test.ts +1013 -66
  33. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  34. package/src/__tests__/config-watcher.test.ts +43 -8
  35. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  36. package/src/__tests__/contacts-write.test.ts +197 -0
  37. package/src/__tests__/context-window-manager.test.ts +88 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  40. package/src/__tests__/conversation-agent-loop.test.ts +98 -2
  41. package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
  42. package/src/__tests__/conversation-error.test.ts +70 -0
  43. package/src/__tests__/conversation-history-web-search.test.ts +11 -4
  44. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  45. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  46. package/src/__tests__/conversation-list-source.test.ts +145 -0
  47. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  48. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  49. package/src/__tests__/conversation-queue.test.ts +901 -60
  50. package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
  51. package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
  52. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  53. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  54. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  55. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  56. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  59. package/src/__tests__/credential-health-service.test.ts +352 -0
  60. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  61. package/src/__tests__/credential-vault-unit.test.ts +379 -3
  62. package/src/__tests__/credentials-cli.test.ts +40 -16
  63. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  64. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  65. package/src/__tests__/device-id.test.ts +112 -0
  66. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  67. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  68. package/src/__tests__/email-html-renderer.test.ts +71 -0
  69. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  70. package/src/__tests__/emit-event-signal.test.ts +71 -0
  71. package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
  72. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  73. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  74. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  75. package/src/__tests__/gemini-provider.test.ts +64 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  77. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  78. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  79. package/src/__tests__/gmail-preferences.test.ts +117 -0
  80. package/src/__tests__/headless-browser-interactions.test.ts +43 -0
  81. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  82. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  83. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  84. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  85. package/src/__tests__/heartbeat-service.test.ts +70 -17
  86. package/src/__tests__/home-state-routes.test.ts +162 -0
  87. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  88. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  89. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  90. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  91. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  92. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  93. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  94. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  95. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  96. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  97. package/src/__tests__/llm-usage-store.test.ts +363 -0
  98. package/src/__tests__/media-stream-output.test.ts +555 -0
  99. package/src/__tests__/media-stream-parser.test.ts +374 -0
  100. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  101. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  102. package/src/__tests__/media-turn-detector.test.ts +440 -0
  103. package/src/__tests__/message-queue.test.ts +125 -0
  104. package/src/__tests__/migration-export-http.test.ts +6 -6
  105. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  106. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  107. package/src/__tests__/migration-validate-http.test.ts +3 -3
  108. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  109. package/src/__tests__/model-intents.test.ts +2 -2
  110. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  111. package/src/__tests__/oauth-cli.test.ts +2 -0
  112. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  115. package/src/__tests__/oauth-store.test.ts +85 -0
  116. package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
  117. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  118. package/src/__tests__/openai-provider.test.ts +176 -0
  119. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  120. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  121. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  122. package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
  123. package/src/__tests__/persona-resolver.test.ts +251 -0
  124. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  125. package/src/__tests__/platform.test.ts +92 -1
  126. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  127. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  128. package/src/__tests__/pricing.test.ts +174 -0
  129. package/src/__tests__/qdrant-manager.test.ts +29 -8
  130. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  131. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  132. package/src/__tests__/relay-server.test.ts +423 -5
  133. package/src/__tests__/search-skills-unified.test.ts +118 -0
  134. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  135. package/src/__tests__/secure-keys.test.ts +107 -0
  136. package/src/__tests__/send-endpoint-busy.test.ts +5 -1
  137. package/src/__tests__/sequence-store.test.ts +1 -1
  138. package/src/__tests__/server-history-render.test.ts +49 -0
  139. package/src/__tests__/settings-routes.test.ts +201 -0
  140. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  141. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  142. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  143. package/src/__tests__/skills.test.ts +5 -2
  144. package/src/__tests__/skillssh-files.test.ts +446 -0
  145. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  146. package/src/__tests__/slack-channel-config.test.ts +564 -1
  147. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  148. package/src/__tests__/stt-stream-session.test.ts +535 -0
  149. package/src/__tests__/system-prompt.test.ts +112 -26
  150. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  151. package/src/__tests__/terminal-tools.test.ts +18 -7
  152. package/src/__tests__/test-preload.ts +18 -0
  153. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  155. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  156. package/src/__tests__/tool-executor.test.ts +33 -24
  157. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  158. package/src/__tests__/trust-store.test.ts +7 -1
  159. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  160. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  161. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  162. package/src/__tests__/twilio-routes.test.ts +376 -0
  163. package/src/__tests__/unicode.test.ts +293 -0
  164. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  165. package/src/__tests__/update-bulletin.test.ts +206 -5
  166. package/src/__tests__/usage-routes.test.ts +25 -4
  167. package/src/__tests__/user-reference.test.ts +46 -61
  168. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  169. package/src/__tests__/voice-config-update.test.ts +403 -0
  170. package/src/__tests__/voice-quality.test.ts +434 -19
  171. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  172. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  173. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  174. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  175. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  176. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  177. package/src/__tests__/workspace-policy.test.ts +2 -0
  178. package/src/agent/image-optimize.ts +24 -12
  179. package/src/agent/loop.ts +43 -3
  180. package/src/backup/__tests__/backup-key.test.ts +152 -0
  181. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  182. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  183. package/src/backup/__tests__/local-writer.test.ts +218 -0
  184. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  185. package/src/backup/__tests__/paths.test.ts +300 -0
  186. package/src/backup/__tests__/restore.test.ts +498 -0
  187. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  188. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  189. package/src/backup/backup-key.ts +137 -0
  190. package/src/backup/backup-worker.ts +459 -0
  191. package/src/backup/list-snapshots.ts +147 -0
  192. package/src/backup/local-writer.ts +133 -0
  193. package/src/backup/offsite-writer.ts +222 -0
  194. package/src/backup/paths.ts +226 -0
  195. package/src/backup/restore.ts +322 -0
  196. package/src/backup/snapshot-lock.ts +431 -0
  197. package/src/backup/stream-crypt.ts +263 -0
  198. package/src/bundler/package-resolver.ts +4 -0
  199. package/src/calls/audio-store.ts +11 -5
  200. package/src/calls/call-controller.ts +226 -71
  201. package/src/calls/call-domain.ts +9 -0
  202. package/src/calls/call-speech-output.ts +190 -0
  203. package/src/calls/call-transport.ts +77 -0
  204. package/src/calls/media-stream-audio-transcode.ts +173 -0
  205. package/src/calls/media-stream-output.ts +660 -0
  206. package/src/calls/media-stream-parser.ts +300 -0
  207. package/src/calls/media-stream-protocol.ts +166 -0
  208. package/src/calls/media-stream-server.ts +592 -0
  209. package/src/calls/media-stream-stt-session.ts +460 -0
  210. package/src/calls/media-turn-detector.ts +230 -0
  211. package/src/calls/relay-server.ts +90 -75
  212. package/src/calls/resolve-call-tts-provider.ts +136 -0
  213. package/src/calls/telephony-stt-routing.ts +145 -0
  214. package/src/calls/tts-call-strategy.ts +161 -0
  215. package/src/calls/tts-text-sanitizer.ts +32 -16
  216. package/src/calls/twilio-routes.ts +281 -17
  217. package/src/calls/voice-quality.ts +78 -35
  218. package/src/calls/voice-session-bridge.ts +8 -1
  219. package/src/channels/types.ts +16 -0
  220. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  221. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  222. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  223. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  224. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  225. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  226. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  227. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  228. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  229. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  230. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  231. package/src/cli/commands/backup.ts +993 -0
  232. package/src/cli/commands/conversations.ts +77 -0
  233. package/src/cli/commands/credentials.ts +0 -1
  234. package/src/cli/commands/domain.ts +210 -0
  235. package/src/cli/commands/email.ts +255 -3
  236. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  237. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  238. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  239. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  240. package/src/cli/commands/oauth/mode.ts +12 -3
  241. package/src/cli/commands/oauth/providers.ts +15 -0
  242. package/src/cli/commands/oauth/shared.ts +2 -1
  243. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
  244. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  245. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  246. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  247. package/src/cli/program.ts +30 -4
  248. package/src/config/__tests__/backup-schema.test.ts +134 -0
  249. package/src/config/assistant-feature-flags.ts +61 -62
  250. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  251. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  252. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  253. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  254. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  255. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  256. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  258. package/src/config/bundled-skills/gmail/SKILL.md +53 -7
  259. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  260. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  261. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  262. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  263. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  264. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  265. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  266. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  267. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  268. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  269. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  270. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  271. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  272. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  273. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  274. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  275. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  276. package/src/config/bundled-skills/outlook/SKILL.md +2 -2
  277. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  278. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  279. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  280. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  281. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  282. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  283. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  284. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  285. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  286. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  287. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  288. package/src/config/bundled-tool-registry.ts +8 -0
  289. package/src/config/env-registry.ts +24 -0
  290. package/src/config/env.ts +34 -10
  291. package/src/config/feature-flag-registry.json +46 -14
  292. package/src/config/loader.ts +26 -12
  293. package/src/config/schema.ts +35 -10
  294. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  295. package/src/config/schemas/analysis.ts +51 -0
  296. package/src/config/schemas/backup.ts +72 -0
  297. package/src/config/schemas/calls.ts +1 -26
  298. package/src/config/schemas/elevenlabs.ts +0 -59
  299. package/src/config/schemas/filing.ts +47 -7
  300. package/src/config/schemas/heartbeat.ts +27 -5
  301. package/src/config/schemas/host-browser.ts +47 -1
  302. package/src/config/schemas/inference.ts +1 -1
  303. package/src/config/schemas/memory-lifecycle.ts +14 -2
  304. package/src/config/schemas/services.ts +44 -0
  305. package/src/config/schemas/stt.ts +59 -0
  306. package/src/config/schemas/tts.ts +230 -0
  307. package/src/config/schemas/updates.ts +14 -0
  308. package/src/config/skills.ts +4 -0
  309. package/src/config/types.ts +4 -0
  310. package/src/contacts/contact-store.ts +56 -11
  311. package/src/contacts/contacts-write.ts +38 -1
  312. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  313. package/src/context/tool-result-truncation.ts +2 -1
  314. package/src/context/window-manager.ts +45 -12
  315. package/src/credential-execution/executable-discovery.ts +12 -2
  316. package/src/credential-execution/process-manager.ts +33 -2
  317. package/src/credential-health/credential-health-service.ts +366 -0
  318. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  319. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  320. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  321. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  322. package/src/daemon/config-watcher.ts +99 -5
  323. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  324. package/src/daemon/conversation-agent-loop.ts +101 -24
  325. package/src/daemon/conversation-error.ts +11 -0
  326. package/src/daemon/conversation-history.ts +40 -6
  327. package/src/daemon/conversation-launch.ts +220 -0
  328. package/src/daemon/conversation-lifecycle.ts +59 -9
  329. package/src/daemon/conversation-messaging.ts +37 -3
  330. package/src/daemon/conversation-notifiers.ts +5 -0
  331. package/src/daemon/conversation-process.ts +581 -19
  332. package/src/daemon/conversation-queue-manager.ts +24 -0
  333. package/src/daemon/conversation-runtime-assembly.ts +11 -1
  334. package/src/daemon/conversation-slash.ts +36 -0
  335. package/src/daemon/conversation-surfaces.ts +94 -4
  336. package/src/daemon/conversation-tool-setup.ts +25 -0
  337. package/src/daemon/conversation-usage.ts +7 -4
  338. package/src/daemon/conversation.ts +86 -28
  339. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  340. package/src/daemon/handlers/conversations.ts +4 -1
  341. package/src/daemon/handlers/shared.ts +22 -0
  342. package/src/daemon/handlers/skills.ts +321 -77
  343. package/src/daemon/host-browser-proxy.ts +2 -1
  344. package/src/daemon/lifecycle.ts +122 -25
  345. package/src/daemon/message-protocol.ts +6 -0
  346. package/src/daemon/message-types/conversations.ts +34 -1
  347. package/src/daemon/message-types/home.ts +40 -0
  348. package/src/daemon/message-types/meet.ts +143 -0
  349. package/src/daemon/message-types/messages.ts +14 -0
  350. package/src/daemon/message-types/schedules.ts +34 -2
  351. package/src/daemon/message-types/skills.ts +16 -0
  352. package/src/daemon/message-types/surfaces.ts +2 -0
  353. package/src/daemon/server.ts +347 -2
  354. package/src/daemon/shutdown-handlers.ts +32 -4
  355. package/src/daemon/shutdown-registry.ts +40 -0
  356. package/src/daemon/tool-side-effects.ts +9 -0
  357. package/src/email/html-renderer.ts +76 -0
  358. package/src/heartbeat/heartbeat-service.ts +93 -7
  359. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  360. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  361. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  362. package/src/home/__tests__/feed-types.test.ts +275 -0
  363. package/src/home/__tests__/feed-writer.test.ts +688 -0
  364. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  365. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  366. package/src/home/__tests__/progress-formula.test.ts +213 -0
  367. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  368. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  369. package/src/home/assistant-feed-authoring.ts +124 -0
  370. package/src/home/emit-feed-event.ts +158 -0
  371. package/src/home/feed-scheduler.ts +247 -0
  372. package/src/home/feed-types.ts +181 -0
  373. package/src/home/feed-writer.ts +469 -0
  374. package/src/home/platform-gmail-digest.ts +163 -0
  375. package/src/home/progress-formula.ts +86 -0
  376. package/src/home/relationship-state-writer.ts +824 -0
  377. package/src/home/relationship-state.ts +143 -0
  378. package/src/home/rollup-producer.ts +384 -0
  379. package/src/hooks/runner.ts +7 -0
  380. package/src/inbound/platform-callback-registration.ts +12 -3
  381. package/src/inbound/public-ingress-urls.ts +12 -0
  382. package/src/instrument.ts +1 -1
  383. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  384. package/src/ipc/cli-client.ts +151 -0
  385. package/src/ipc/cli-server.ts +234 -0
  386. package/src/ipc/gateway-client.ts +180 -0
  387. package/src/ipc/routes/index.ts +5 -0
  388. package/src/ipc/routes/wake-conversation.ts +19 -0
  389. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  390. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  391. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  392. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  393. package/src/memory/app-store.ts +1 -1
  394. package/src/memory/attachments-store.ts +70 -0
  395. package/src/memory/auto-analysis-enqueue.ts +127 -0
  396. package/src/memory/auto-analysis-guard.ts +27 -0
  397. package/src/memory/cleanup-schedule-state.ts +37 -0
  398. package/src/memory/conversation-analyze-job.ts +73 -0
  399. package/src/memory/conversation-crud.ts +99 -0
  400. package/src/memory/conversation-disk-view.ts +7 -0
  401. package/src/memory/conversation-group-migration.ts +34 -2
  402. package/src/memory/conversation-queries.ts +6 -5
  403. package/src/memory/db-init.ts +6 -0
  404. package/src/memory/db-maintenance.ts +108 -0
  405. package/src/memory/db.ts +1 -0
  406. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  407. package/src/memory/graph/extraction.test.ts +23 -0
  408. package/src/memory/graph/extraction.ts +8 -0
  409. package/src/memory/graph/retriever.ts +27 -18
  410. package/src/memory/graph/scoring.test.ts +186 -0
  411. package/src/memory/graph/scoring.ts +31 -1
  412. package/src/memory/graph/tools.ts +1 -1
  413. package/src/memory/group-crud.ts +6 -1
  414. package/src/memory/indexer.ts +95 -16
  415. package/src/memory/job-handlers/cleanup.ts +11 -8
  416. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  417. package/src/memory/jobs-store.ts +64 -4
  418. package/src/memory/jobs-worker.ts +22 -9
  419. package/src/memory/llm-usage-store.ts +92 -56
  420. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  421. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  422. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  423. package/src/memory/migrations/index.ts +6 -0
  424. package/src/memory/migrations/registry.ts +8 -0
  425. package/src/memory/qdrant-manager.ts +43 -16
  426. package/src/memory/schema/conversations.ts +2 -0
  427. package/src/memory/schema/oauth.ts +3 -0
  428. package/src/memory/usage-buckets.ts +396 -0
  429. package/src/messaging/providers/gmail/client.ts +57 -6
  430. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  431. package/src/messaging/providers/slack/adapter.ts +143 -38
  432. package/src/messaging/providers/slack/client.ts +16 -0
  433. package/src/messaging/providers/slack/types.ts +4 -0
  434. package/src/notifications/decision-engine.ts +3 -3
  435. package/src/notifications/signal.ts +5 -0
  436. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  437. package/src/oauth/byo-connection.test.ts +18 -1
  438. package/src/oauth/byo-connection.ts +3 -1
  439. package/src/oauth/connect-orchestrator.ts +2 -0
  440. package/src/oauth/connection-resolver.ts +6 -2
  441. package/src/oauth/connection.ts +2 -0
  442. package/src/oauth/oauth-store.ts +9 -0
  443. package/src/oauth/platform-connection.test.ts +98 -0
  444. package/src/oauth/platform-connection.ts +52 -31
  445. package/src/oauth/seed-providers.ts +7 -0
  446. package/src/permissions/checker.ts +16 -6
  447. package/src/permissions/defaults.ts +49 -1
  448. package/src/permissions/trust-store.ts +3 -3
  449. package/src/permissions/workspace-policy.ts +3 -0
  450. package/src/platform/client.test.ts +10 -0
  451. package/src/platform/sync-identity.ts +129 -0
  452. package/src/prompts/persona-resolver.ts +126 -2
  453. package/src/prompts/system-prompt.ts +59 -18
  454. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  455. package/src/prompts/templates/SOUL.md +3 -1
  456. package/src/prompts/templates/UPDATES.md +12 -0
  457. package/src/prompts/templates/channels/slack.md +20 -0
  458. package/src/prompts/update-bulletin-format.ts +26 -9
  459. package/src/prompts/update-bulletin.ts +34 -23
  460. package/src/prompts/user-reference.ts +20 -17
  461. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  462. package/src/providers/anthropic/client.ts +157 -61
  463. package/src/providers/fireworks/client.ts +2 -2
  464. package/src/providers/gemini/client.ts +9 -1
  465. package/src/providers/model-catalog.ts +6 -0
  466. package/src/providers/model-intents.ts +4 -4
  467. package/src/providers/ollama/client.ts +2 -2
  468. package/src/providers/openai/chat-completions-provider.ts +474 -0
  469. package/src/providers/openai/client.ts +25 -440
  470. package/src/providers/openai/responses-provider.ts +502 -0
  471. package/src/providers/openrouter/client.ts +101 -4
  472. package/src/providers/provider-secret-catalog.ts +139 -0
  473. package/src/providers/registry.ts +2 -2
  474. package/src/providers/retry.ts +14 -3
  475. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  476. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  477. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  478. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  479. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  480. package/src/providers/speech-to-text/deepgram.ts +115 -0
  481. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  482. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  483. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  484. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  485. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  486. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  487. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  488. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  489. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  490. package/src/providers/speech-to-text/resolve.ts +386 -6
  491. package/src/providers/types.ts +9 -0
  492. package/src/runtime/AGENTS.md +43 -1
  493. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  494. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  495. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  496. package/src/runtime/agent-wake.ts +512 -0
  497. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  498. package/src/runtime/auth/route-policy.ts +30 -5
  499. package/src/runtime/auth/token-service.ts +56 -1
  500. package/src/runtime/btw-sidechain.ts +2 -0
  501. package/src/runtime/capability-tokens.ts +10 -10
  502. package/src/runtime/channel-invite-transport.ts +1 -1
  503. package/src/runtime/channel-invite-transports/email.ts +14 -6
  504. package/src/runtime/channel-readiness-service.ts +12 -22
  505. package/src/runtime/chrome-extension-registry.ts +38 -2
  506. package/src/runtime/http-server.ts +395 -10
  507. package/src/runtime/http-types.ts +6 -2
  508. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  509. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  510. package/src/runtime/migrations/migration-transport.ts +1 -0
  511. package/src/runtime/migrations/migration-wizard.ts +1 -0
  512. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  513. package/src/runtime/migrations/vbundle-importer.ts +34 -0
  514. package/src/runtime/pending-interactions.ts +0 -11
  515. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  516. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  517. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  518. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  519. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  520. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  521. package/src/runtime/routes/app-management-routes.ts +12 -18
  522. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  523. package/src/runtime/routes/attachment-routes.ts +216 -17
  524. package/src/runtime/routes/backup-routes.ts +519 -0
  525. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  526. package/src/runtime/routes/btw-routes.ts +8 -6
  527. package/src/runtime/routes/contact-routes.test.ts +298 -0
  528. package/src/runtime/routes/contact-routes.ts +132 -5
  529. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  530. package/src/runtime/routes/conversation-management-routes.ts +115 -0
  531. package/src/runtime/routes/conversation-routes.ts +367 -146
  532. package/src/runtime/routes/filing-routes.ts +93 -0
  533. package/src/runtime/routes/home-feed-routes.ts +334 -0
  534. package/src/runtime/routes/home-state-routes.ts +138 -0
  535. package/src/runtime/routes/host-browser-routes.ts +3 -14
  536. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  537. package/src/runtime/routes/identity-routes.ts +3 -17
  538. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  539. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  540. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  541. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  542. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  543. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  544. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  545. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  546. package/src/runtime/routes/migration-routes.ts +40 -5
  547. package/src/runtime/routes/settings-routes.ts +22 -5
  548. package/src/runtime/routes/skills-routes.ts +76 -7
  549. package/src/runtime/routes/stt-routes.ts +233 -0
  550. package/src/runtime/routes/surface-action-routes.ts +41 -2
  551. package/src/runtime/routes/tts-routes.ts +108 -24
  552. package/src/runtime/routes/usage-routes.ts +30 -2
  553. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  554. package/src/runtime/routes/user-routes.ts +13 -1
  555. package/src/runtime/routes/work-items-routes.ts +8 -1
  556. package/src/runtime/runtime-mode.ts +33 -0
  557. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  558. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  559. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  560. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  561. package/src/runtime/services/analyze-conversation.ts +344 -0
  562. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  563. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  564. package/src/runtime/skill-route-registry.ts +49 -0
  565. package/src/runtime/slack-block-formatting.ts +437 -10
  566. package/src/schedule/scheduler.ts +50 -0
  567. package/src/security/oauth2.ts +26 -4
  568. package/src/security/secure-keys.ts +25 -2
  569. package/src/security/token-manager.ts +8 -0
  570. package/src/sequence/engine.ts +23 -0
  571. package/src/sequence/types.ts +1 -1
  572. package/src/skills/catalog-files.ts +64 -2
  573. package/src/skills/category-inference.ts +122 -0
  574. package/src/skills/clawhub-files.ts +213 -0
  575. package/src/skills/clawhub.ts +84 -23
  576. package/src/skills/skill-file-provider.ts +40 -0
  577. package/src/skills/skillssh-files.ts +395 -0
  578. package/src/skills/skillssh-registry.ts +4 -4
  579. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  580. package/src/stt/__tests__/types.test.ts +89 -0
  581. package/src/stt/daemon-batch-transcriber.ts +195 -0
  582. package/src/stt/stt-stream-session.ts +499 -0
  583. package/src/stt/types.ts +330 -0
  584. package/src/stt/wav-encoder.test.ts +373 -0
  585. package/src/stt/wav-encoder.ts +175 -0
  586. package/src/subagent/manager.ts +38 -14
  587. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  588. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  589. package/src/tools/browser/browser-execution.ts +1163 -23
  590. package/src/tools/browser/browser-manager.ts +45 -0
  591. package/src/tools/browser/browser-mode-constants.ts +12 -0
  592. package/src/tools/browser/browser-mode.ts +92 -0
  593. package/src/tools/browser/browser-status-constants.ts +33 -0
  594. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  595. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  596. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  597. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  598. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
  599. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  600. package/src/tools/browser/cdp-client/errors.ts +15 -0
  601. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  602. package/src/tools/browser/cdp-client/factory.ts +797 -87
  603. package/src/tools/browser/cdp-client/index.ts +16 -2
  604. package/src/tools/browser/cdp-client/types.ts +68 -0
  605. package/src/tools/credentials/vault.ts +35 -6
  606. package/src/tools/network/web-fetch.ts +5 -2
  607. package/src/tools/network/web-search.ts +5 -2
  608. package/src/tools/shared/shell-output.ts +3 -1
  609. package/src/tools/side-effects.ts +2 -0
  610. package/src/tools/skills/sandbox-runner.ts +3 -2
  611. package/src/tools/terminal/safe-env.ts +10 -2
  612. package/src/tools/terminal/shell.ts +15 -4
  613. package/src/tools/tool-manifest.ts +21 -0
  614. package/src/tools/types.ts +17 -0
  615. package/src/tools/ui-surface/definitions.ts +6 -1
  616. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  617. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  618. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  619. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  620. package/src/tts/provider-catalog.ts +201 -0
  621. package/src/tts/provider-registry.ts +73 -0
  622. package/src/tts/providers/deepgram-provider.ts +219 -0
  623. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  624. package/src/tts/providers/fish-audio-provider.ts +183 -0
  625. package/src/tts/providers/index.ts +42 -0
  626. package/src/tts/providers/register-builtins.ts +130 -0
  627. package/src/tts/synthesize-text.ts +110 -0
  628. package/src/tts/tts-config-resolver.ts +78 -0
  629. package/src/tts/types.ts +153 -0
  630. package/src/types/onboarding-context.ts +7 -0
  631. package/src/util/abort-reasons.ts +58 -0
  632. package/src/util/device-id.ts +32 -16
  633. package/src/util/errors.ts +9 -1
  634. package/src/util/platform.ts +54 -10
  635. package/src/util/pricing.ts +66 -3
  636. package/src/util/spawn.ts +1 -1
  637. package/src/util/truncate.ts +4 -2
  638. package/src/util/unicode.ts +201 -0
  639. package/src/version.ts +19 -24
  640. package/src/watcher/engine.ts +23 -0
  641. package/src/watcher/watcher-store.ts +31 -0
  642. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  643. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  644. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  645. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  646. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  647. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  648. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  649. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  650. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  651. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  652. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  653. package/src/workspace/migrations/registry.ts +16 -0
  654. package/src/workspace/top-level-renderer.ts +13 -1
  655. package/src/workspace/turn-commit.ts +31 -0
  656. package/src/__tests__/email-cli.test.ts +0 -297
  657. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  658. package/src/cli/commands/browser-relay.ts +0 -466
  659. package/src/email/guardrails.ts +0 -221
  660. package/src/email/provider.ts +0 -117
  661. package/src/email/providers/agentmail.ts +0 -361
  662. package/src/email/providers/index.ts +0 -65
  663. package/src/email/service.ts +0 -384
  664. package/src/email/types.ts +0 -126
  665. package/src/prompts/templates/USER.md +0 -13
  666. package/src/providers/speech-to-text/types.ts +0 -17
  667. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
@@ -17,6 +17,8 @@
17
17
  * sidecar and credential data.
18
18
  */
19
19
 
20
+ import { AsyncLocalStorage } from "node:async_hooks";
21
+
20
22
  import type {
21
23
  SecureKeyBackend,
22
24
  SecureKeyDeleteResult,
@@ -75,6 +77,18 @@ let _lastReconnectAttempt = 0;
75
77
  /** In-flight reconnection promise — concurrent callers share the same attempt. */
76
78
  let _reconnectInFlight: Promise<boolean> | undefined;
77
79
 
80
+ /**
81
+ * Per-async-context flag set while we are running the user-registered
82
+ * `_cesReconnect` callback. Reentrant credential reads from within the
83
+ * callback (on the same async call chain) must not `await`
84
+ * `_reconnectInFlight` — that would await the caller's own reconnect and
85
+ * deadlock until `CREDENTIAL_OP_TIMEOUT_MS` (45s) fires. Using
86
+ * AsyncLocalStorage (rather than a module-level boolean) scopes the guard
87
+ * to the actual reentrant stack, so unrelated concurrent callers keep
88
+ * sharing the in-flight reconnect promise normally.
89
+ */
90
+ const _reconnectContext = new AsyncLocalStorage<true>();
91
+
78
92
  /**
79
93
  * Set to true when a ces-http operation returns an unreachable result.
80
94
  * Triggers CES RPC reconnection on the next resolveBackendAsync() call so
@@ -240,6 +254,15 @@ function tryFailoverToCesHttpBackend(
240
254
  async function attemptCesReconnection(): Promise<boolean> {
241
255
  if (!_cesReconnect) return false;
242
256
 
257
+ // Reentrancy guard. A nested credential read from inside the reconnect
258
+ // callback must not `await` our own in-flight promise — that would
259
+ // deadlock on the 45-second credential-op timeout. Report the reconnect
260
+ // as failed so the caller sees "unreachable" and falls back (env vars,
261
+ // dead-backend response) without blocking. Concurrent callers on other
262
+ // async chains don't see the ALS store, so they still share the
263
+ // in-flight promise normally.
264
+ if (_reconnectContext.getStore()) return false;
265
+
243
266
  // If a reconnection is already in flight, share it.
244
267
  if (_reconnectInFlight) return _reconnectInFlight;
245
268
 
@@ -249,7 +272,7 @@ async function attemptCesReconnection(): Promise<boolean> {
249
272
  _lastReconnectAttempt = Date.now();
250
273
  log.warn("Credential backend unavailable — attempting CES reconnection");
251
274
 
252
- _reconnectInFlight = (async () => {
275
+ _reconnectInFlight = _reconnectContext.run(true, async () => {
253
276
  try {
254
277
  const newClient = await _cesReconnect!();
255
278
  if (newClient) {
@@ -262,7 +285,7 @@ async function attemptCesReconnection(): Promise<boolean> {
262
285
  log.warn({ err }, "CES reconnection failed");
263
286
  }
264
287
  return false;
265
- })();
288
+ });
266
289
 
267
290
  try {
268
291
  return await _reconnectInFlight;
@@ -101,6 +101,7 @@ interface RefreshConfig {
101
101
  secret?: string;
102
102
  refreshToken?: string;
103
103
  authMethod?: TokenEndpointAuthMethod;
104
+ tokenExchangeBodyFormat?: "form" | "json";
104
105
  connId: string;
105
106
  }
106
107
 
@@ -166,6 +167,10 @@ async function resolveRefreshConfig(
166
167
  | TokenEndpointAuthMethod
167
168
  | undefined;
168
169
 
170
+ const tokenExchangeBodyFormat =
171
+ (provider.tokenExchangeBodyFormat as "form" | "json" | undefined) ??
172
+ undefined;
173
+
169
174
  return {
170
175
  connId: conn.id,
171
176
  tokenExchangeUrl,
@@ -173,6 +178,7 @@ async function resolveRefreshConfig(
173
178
  secret,
174
179
  refreshToken,
175
180
  authMethod,
181
+ tokenExchangeBodyFormat,
176
182
  };
177
183
  }
178
184
 
@@ -192,6 +198,7 @@ async function doRefresh(service: string, connId: string): Promise<string> {
192
198
  clientId: resolvedClientId,
193
199
  secret,
194
200
  authMethod,
201
+ tokenExchangeBodyFormat,
195
202
  refreshToken,
196
203
  } = refreshConfig;
197
204
 
@@ -222,6 +229,7 @@ async function doRefresh(service: string, connId: string): Promise<string> {
222
229
  refreshToken,
223
230
  secret,
224
231
  authMethod,
232
+ tokenExchangeBodyFormat,
225
233
  );
226
234
  } catch (err) {
227
235
  circuitBreaker.recordFailure(connId);
@@ -6,6 +6,7 @@
6
6
  * sends through the messaging layer.
7
7
  */
8
8
 
9
+ import { emitFeedEvent } from "../home/emit-feed-event.js";
9
10
  import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
10
11
  import { getMessages } from "../memory/conversation-crud.js";
11
12
  import type { ScheduleMessageProcessor } from "../schedule/scheduler.js";
@@ -200,6 +201,28 @@ async function processEnrollment(
200
201
  recordSend(sequence.id);
201
202
  recordEvent(sequence.id, enrollment.id, "send", step.index);
202
203
 
204
+ // Fire-and-forget home-feed activity log entry. Each (enrollment,
205
+ // step) pair is a distinct real signal (an email actually went
206
+ // out), so the dedupKey embeds both — repeat emits for the same
207
+ // step are impossible because the enrollment advances after this
208
+ // line, but if they did occur they'd land on the same entry.
209
+ void emitFeedEvent({
210
+ source: "assistant",
211
+ title: sequence.name,
212
+ summary: `Sent step ${step.index + 1} of ${sequence.steps.length} to ${enrollment.contactEmail}.`,
213
+ dedupKey: `sequence-step:${enrollment.id}:${step.index}`,
214
+ }).catch((err) => {
215
+ log.warn(
216
+ {
217
+ err,
218
+ sequenceId: sequence.id,
219
+ enrollmentId: enrollment.id,
220
+ step: step.index,
221
+ },
222
+ "Failed to emit sequence step feed event",
223
+ );
224
+ });
225
+
203
226
  // Advance to the next step
204
227
  const nextStepIndex = enrollment.currentStep + 1;
205
228
  if (nextStepIndex >= sequence.steps.length) {
@@ -26,7 +26,7 @@ export interface Sequence {
26
26
  id: string;
27
27
  name: string;
28
28
  description: string | null;
29
- channel: string; // messaging channel (gmail, agentmail, slack)
29
+ channel: string; // messaging channel (gmail, email, slack)
30
30
  steps: SequenceStep[];
31
31
  exitOnReply: boolean;
32
32
  status: SequenceStatus;
@@ -29,14 +29,16 @@ import {
29
29
  import { basename, join, posix, sep } from "node:path";
30
30
 
31
31
  import { getPlatformBaseUrl } from "../config/env.js";
32
+ import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
32
33
  import {
33
34
  isTextMimeType as isTextMime,
34
35
  MAX_INLINE_TEXT_SIZE,
35
36
  } from "../runtime/routes/workspace-utils.js";
36
37
  import { getLogger } from "../util/logger.js";
37
38
  import { readPlatformToken } from "../util/platform.js";
38
- import { getCatalog } from "./catalog-cache.js";
39
- import { getRepoSkillsDir } from "./catalog-install.js";
39
+ import { getCachedCatalogSync, getCatalog } from "./catalog-cache.js";
40
+ import { type CatalogSkill, getRepoSkillsDir } from "./catalog-install.js";
41
+ import type { SkillFileProvider } from "./skill-file-provider.js";
40
42
 
41
43
  const log = getLogger("catalog-files");
42
44
 
@@ -490,3 +492,63 @@ export async function readCatalogSkillFileContent(
490
492
  content: response.content,
491
493
  };
492
494
  }
495
+
496
+ // ─── Catalog-to-slim conversion ──────────────────────────────────────────────
497
+
498
+ /**
499
+ * Map a `CatalogSkill` (from the Vellum platform API) to a `SlimSkillResponse`
500
+ * shaped for the "available catalog skill" case. Shared between
501
+ * `listSkillsWithCatalog` (merging catalog entries into the installed list),
502
+ * `getSkillFiles` (catalog fallback for preview listings), and the
503
+ * `VellumCatalogProvider`. Keeping the mapping in one place avoids divergence
504
+ * between the list and detail paths.
505
+ *
506
+ * Extracted here (rather than in `daemon/handlers/skills.ts`) to avoid a
507
+ * circular import — catalog-files depends on `catalog-cache.ts`, which would
508
+ * otherwise be reachable via the handler module.
509
+ */
510
+ export function catalogSkillToSlim(cs: CatalogSkill): SlimSkillResponse {
511
+ return {
512
+ id: cs.id,
513
+ name: cs.metadata?.vellum?.["display-name"] ?? cs.name,
514
+ description: cs.description,
515
+ emoji: cs.emoji,
516
+ kind: "catalog",
517
+ origin: "vellum",
518
+ status: "available",
519
+ };
520
+ }
521
+
522
+ // ─── Vellum Catalog Provider ─────────────────────────────────────────────────
523
+
524
+ /**
525
+ * Create a `SkillFileProvider` that wraps the existing catalog-files functions
526
+ * for the Vellum first-party catalog. This is the first provider implementation
527
+ * in the unified file-preview chain.
528
+ */
529
+ export function createVellumCatalogProvider(): SkillFileProvider {
530
+ return {
531
+ canHandle(skillId: string): boolean {
532
+ const cached = getCachedCatalogSync();
533
+ return cached.some((s) => s.id === skillId);
534
+ },
535
+
536
+ listFiles(skillId: string): Promise<SkillFileEntry[] | null> {
537
+ return readCatalogSkillFiles(skillId);
538
+ },
539
+
540
+ readFileContent(
541
+ skillId: string,
542
+ sanitizedPath: string,
543
+ ): Promise<SkillFileEntry | null> {
544
+ return readCatalogSkillFileContent(skillId, sanitizedPath);
545
+ },
546
+
547
+ async toSlimSkill(skillId: string): Promise<SlimSkillResponse | null> {
548
+ const catalog = await getCatalog();
549
+ const cs = catalog.find((s) => s.id === skillId);
550
+ if (!cs) return null;
551
+ return catalogSkillToSlim(cs);
552
+ },
553
+ };
554
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Skill category inference — ports the Swift `inferCategory` logic from
3
+ * `ConstellationView.swift` to TypeScript for server-side use.
4
+ *
5
+ * Pure function with no side effects or external dependencies.
6
+ */
7
+
8
+ export type SkillCategory =
9
+ | "communication"
10
+ | "productivity"
11
+ | "development"
12
+ | "media"
13
+ | "automation"
14
+ | "webSocial"
15
+ | "knowledge"
16
+ | "integration";
17
+
18
+ export const SKILL_CATEGORIES: SkillCategory[] = [
19
+ "communication",
20
+ "productivity",
21
+ "development",
22
+ "automation",
23
+ "media",
24
+ "webSocial",
25
+ "knowledge",
26
+ "integration",
27
+ ];
28
+
29
+ const CATEGORY_KEYWORDS: [SkillCategory, string[]][] = [
30
+ [
31
+ "communication",
32
+ [
33
+ "email",
34
+ "message",
35
+ "messaging",
36
+ "chat",
37
+ "phone",
38
+ "phone call",
39
+ "voice call",
40
+ "video call",
41
+ "contact",
42
+ "notification",
43
+ "followup",
44
+ "slack",
45
+ "telegram",
46
+ ],
47
+ ],
48
+ [
49
+ "productivity",
50
+ [
51
+ "task",
52
+ "calendar",
53
+ "reminder",
54
+ "schedule",
55
+ "document",
56
+ "playbook",
57
+ "notion",
58
+ ],
59
+ ],
60
+ [
61
+ "development",
62
+ [
63
+ "code",
64
+ "app builder",
65
+ "github",
66
+ "developer",
67
+ "programming",
68
+ "debug",
69
+ "typescript",
70
+ "frontend",
71
+ "subagent",
72
+ "api mapping",
73
+ "cli discovery",
74
+ ],
75
+ ],
76
+ ["automation", ["browser", "computer use", "macos", "watcher", "automat"]],
77
+ [
78
+ "media",
79
+ ["image", "screen", "media", "transcri", "video", "audio", "recording"],
80
+ ],
81
+ [
82
+ "webSocial",
83
+ [
84
+ "x.com",
85
+ "twitter",
86
+ "public ingress",
87
+ "influencer",
88
+ "doordash",
89
+ "amazon",
90
+ "restaurant",
91
+ ],
92
+ ],
93
+ [
94
+ "knowledge",
95
+ [
96
+ "knowledge",
97
+ "weather",
98
+ "start the day",
99
+ "skills catalog",
100
+ "self upgrade",
101
+ "briefing",
102
+ ],
103
+ ],
104
+ ["integration", ["oauth", "setup", "configure", "connect", "webhook"]],
105
+ ];
106
+
107
+ export function inferCategory(
108
+ name: string,
109
+ description: string,
110
+ ): SkillCategory {
111
+ const combined = `${name} ${description}`.toLowerCase();
112
+
113
+ for (const [category, keywords] of CATEGORY_KEYWORDS) {
114
+ for (const keyword of keywords) {
115
+ if (combined.includes(keyword)) {
116
+ return category;
117
+ }
118
+ }
119
+ }
120
+
121
+ return "knowledge";
122
+ }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * clawhub-files — SkillFileProvider implementation for clawhub-origin skills.
3
+ *
4
+ * Backed by the `clawhub inspect` CLI. The initial `clawhubInspect` call
5
+ * fetches file metadata *and* SKILL.md content in a single round trip.
6
+ * Results are cached in memory (5-minute TTL) so that subsequent calls to
7
+ * `listFiles`, `readFileContent`, and `toSlimSkill` for the same slug
8
+ * reuse the inspect data without re-running the CLI.
9
+ *
10
+ * For non-SKILL.md files, `readFileContent` delegates to `clawhubInspectFile`
11
+ * which runs a second CLI call for the specific file.
12
+ */
13
+
14
+ import { basename } from "node:path";
15
+
16
+ import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
17
+ import { isTextMimeType as isTextMime } from "../runtime/routes/workspace-utils.js";
18
+ import { getLogger } from "../util/logger.js";
19
+ import type { SkillFileEntry } from "./catalog-files.js";
20
+ import {
21
+ clawhubInspect,
22
+ clawhubInspectFile,
23
+ type ClawhubInspectResult,
24
+ validateSlug,
25
+ } from "./clawhub.js";
26
+ import type { SkillFileProvider } from "./skill-file-provider.js";
27
+
28
+ const log = getLogger("clawhub-files");
29
+
30
+ // ─── Inspect cache ────────────────────────────────────────────────────────────
31
+
32
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
33
+
34
+ interface CacheEntry {
35
+ data: ClawhubInspectResult;
36
+ expiresAt: number;
37
+ }
38
+
39
+ const inspectCache = new Map<string, CacheEntry>();
40
+
41
+ function getCached(slug: string): ClawhubInspectResult | null {
42
+ const entry = inspectCache.get(slug);
43
+ if (!entry) return null;
44
+ if (Date.now() > entry.expiresAt) {
45
+ inspectCache.delete(slug);
46
+ return null;
47
+ }
48
+ return entry.data;
49
+ }
50
+
51
+ function setCache(slug: string, data: ClawhubInspectResult): void {
52
+ inspectCache.set(slug, { data, expiresAt: Date.now() + CACHE_TTL_MS });
53
+ }
54
+
55
+ /**
56
+ * Run `clawhubInspect` with caching. Returns the inspect result or `null`.
57
+ */
58
+ async function inspectCached(
59
+ slug: string,
60
+ ): Promise<ClawhubInspectResult | null> {
61
+ const cached = getCached(slug);
62
+ if (cached) return cached;
63
+
64
+ const result = await clawhubInspect(slug);
65
+ if (!result.data) {
66
+ log.warn({ slug, error: result.error }, "clawhub inspect failed");
67
+ return null;
68
+ }
69
+ setCache(slug, result.data);
70
+ return result.data;
71
+ }
72
+
73
+ // ─── Binary classification ───────────────────────────────────────────────────
74
+
75
+ /**
76
+ * Classify a file as binary from its name and optional contentType field.
77
+ * If the contentType from the inspect result is present and recognised,
78
+ * prefer it; otherwise fall back to Bun's extension-based MIME detection
79
+ * (same strategy as `catalog-files.ts`).
80
+ */
81
+ function classifyBinary(fileName: string, contentType?: string): boolean {
82
+ if (contentType) {
83
+ return !isTextMime(contentType, fileName);
84
+ }
85
+ const mime = Bun.file(fileName).type;
86
+ return !isTextMime(mime, fileName);
87
+ }
88
+
89
+ // ─── Provider factory ─────────────────────────────────────────────────────────
90
+
91
+ /**
92
+ * Create a `SkillFileProvider` for clawhub-origin skills.
93
+ *
94
+ * `canHandle` returns `true` for slugs that pass clawhub's `validateSlug`
95
+ * regex AND do not look like a skills.sh slug (skills.sh slugs have three
96
+ * slash-separated segments: `owner/repo/skill`).
97
+ */
98
+ export function createClawhubProvider(): SkillFileProvider {
99
+ return {
100
+ canHandle(skillId: string): boolean {
101
+ if (!validateSlug(skillId)) return false;
102
+ // skills.sh slugs have ≥ 3 segments (owner/repo/skill)
103
+ if (skillId.split("/").length >= 3) return false;
104
+ return true;
105
+ },
106
+
107
+ async listFiles(skillId: string): Promise<SkillFileEntry[] | null> {
108
+ const data = await inspectCached(skillId);
109
+ if (!data || !data.files) return null;
110
+
111
+ const entries: SkillFileEntry[] = data.files.map((f) => {
112
+ const name = basename(f.path);
113
+ const isBinary = classifyBinary(name, f.contentType);
114
+ return {
115
+ path: f.path,
116
+ name,
117
+ size: f.size,
118
+ mimeType: f.contentType ?? Bun.file(name).type,
119
+ isBinary,
120
+ content: null,
121
+ };
122
+ });
123
+ entries.sort((a, b) => a.path.localeCompare(b.path));
124
+ return entries;
125
+ },
126
+
127
+ async readFileContent(
128
+ skillId: string,
129
+ sanitizedPath: string,
130
+ ): Promise<SkillFileEntry | null> {
131
+ // If the requested path is SKILL.md and we have cached inspect data
132
+ // with skillMdContent, return it directly without a second CLI call.
133
+ const cached = getCached(skillId);
134
+ if (
135
+ cached &&
136
+ sanitizedPath === "SKILL.md" &&
137
+ cached.skillMdContent != null
138
+ ) {
139
+ const name = "SKILL.md";
140
+ return {
141
+ path: sanitizedPath,
142
+ name,
143
+ size: cached.skillMdContent.length,
144
+ mimeType: "text/markdown",
145
+ isBinary: false,
146
+ content: cached.skillMdContent,
147
+ };
148
+ }
149
+
150
+ const name = basename(sanitizedPath);
151
+ const isBinary = classifyBinary(name);
152
+
153
+ // For non-SKILL.md files (or when SKILL.md isn't cached), run
154
+ // a dedicated inspect call for the specific file.
155
+ const content = await clawhubInspectFile(skillId, sanitizedPath);
156
+
157
+ // Binary files: return metadata with content: null (matching the
158
+ // contract followed by vellum and skills.sh providers). clawhubInspectFile
159
+ // returns null for binary files, which is expected.
160
+ if (isBinary) {
161
+ // Look up file metadata from cached inspect result if available.
162
+ const inspectData =
163
+ getCached(skillId) ?? (await inspectCached(skillId));
164
+ const fileMeta = inspectData?.files?.find(
165
+ (f) => f.path === sanitizedPath,
166
+ );
167
+ return {
168
+ path: sanitizedPath,
169
+ name,
170
+ size: fileMeta?.size ?? 0,
171
+ mimeType: fileMeta?.contentType ?? Bun.file(name).type,
172
+ isBinary: true,
173
+ content: null,
174
+ };
175
+ }
176
+
177
+ // Text file but content fetch failed — file doesn't exist.
178
+ if (content == null) return null;
179
+
180
+ return {
181
+ path: sanitizedPath,
182
+ name,
183
+ size: content.length,
184
+ mimeType: Bun.file(name).type,
185
+ isBinary: false,
186
+ content,
187
+ };
188
+ },
189
+
190
+ async toSlimSkill(skillId: string): Promise<SlimSkillResponse | null> {
191
+ const data = await inspectCached(skillId);
192
+ if (!data) return null;
193
+
194
+ return {
195
+ id: data.skill.slug,
196
+ name: data.skill.displayName,
197
+ description: data.skill.summary,
198
+ kind: "catalog",
199
+ status: "available",
200
+ origin: "clawhub",
201
+ slug: data.skill.slug,
202
+ author: data.owner?.handle ?? "",
203
+ stars: data.stats?.stars ?? 0,
204
+ installs: data.stats?.installs ?? 0,
205
+ reports: 0,
206
+ publishedAt: data.updatedAt
207
+ ? new Date(data.updatedAt).toISOString()
208
+ : undefined,
209
+ version: data.latestVersion?.version ?? "",
210
+ };
211
+ },
212
+ };
213
+ }