@vellumai/assistant 0.3.5 → 0.3.7

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 (487) hide show
  1. package/README.md +51 -0
  2. package/eslint.config.mjs +31 -0
  3. package/package.json +1 -1
  4. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  5. package/scripts/ipc/generate-swift.ts +18 -2
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
  7. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  8. package/src/__tests__/browser-manager.test.ts +1 -0
  9. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  10. package/src/__tests__/call-orchestrator.test.ts +752 -271
  11. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  12. package/src/__tests__/call-recovery.test.ts +3 -0
  13. package/src/__tests__/call-routes-http.test.ts +5 -0
  14. package/src/__tests__/call-store.test.ts +3 -0
  15. package/src/__tests__/channel-approval-routes.test.ts +1260 -85
  16. package/src/__tests__/channel-approval.test.ts +37 -0
  17. package/src/__tests__/channel-approvals.test.ts +4 -65
  18. package/src/__tests__/channel-guardian.test.ts +556 -0
  19. package/src/__tests__/channel-readiness-service.test.ts +74 -7
  20. package/src/__tests__/checker.test.ts +14 -7
  21. package/src/__tests__/clarification-resolver.test.ts +44 -24
  22. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  23. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  24. package/src/__tests__/config-schema.test.ts +12 -7
  25. package/src/__tests__/context-window-manager.test.ts +30 -2
  26. package/src/__tests__/contradiction-checker.test.ts +20 -5
  27. package/src/__tests__/credential-security-invariants.test.ts +6 -2
  28. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  29. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  30. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  31. package/src/__tests__/guardian-action-store.test.ts +123 -0
  32. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  33. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  34. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  35. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  36. package/src/__tests__/handlers-twilio-config.test.ts +126 -0
  37. package/src/__tests__/intent-routing.test.ts +2 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +228 -1
  39. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  40. package/src/__tests__/model-intents.test.ts +96 -0
  41. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  42. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  43. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  44. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  45. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  46. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  47. package/src/__tests__/qdrant-manager.test.ts +27 -20
  48. package/src/__tests__/relay-server.test.ts +779 -40
  49. package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
  50. package/src/__tests__/run-orchestrator.test.ts +20 -4
  51. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  52. package/src/__tests__/runtime-runs.test.ts +16 -0
  53. package/src/__tests__/schedule-store.test.ts +18 -4
  54. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  55. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  56. package/src/__tests__/session-agent-loop.test.ts +857 -0
  57. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  58. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  59. package/src/__tests__/session-profile-injection.test.ts +6 -0
  60. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  61. package/src/__tests__/session-queue.test.ts +6 -0
  62. package/src/__tests__/session-runtime-assembly.test.ts +237 -13
  63. package/src/__tests__/session-slash-known.test.ts +6 -0
  64. package/src/__tests__/session-slash-queue.test.ts +6 -0
  65. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  66. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  67. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  68. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  69. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  70. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  71. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  72. package/src/__tests__/skills.test.ts +2 -0
  73. package/src/__tests__/sms-messaging-provider.test.ts +2 -1
  74. package/src/__tests__/starter-task-flow.test.ts +2 -0
  75. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  76. package/src/__tests__/system-prompt.test.ts +2 -0
  77. package/src/__tests__/task-management-tools.test.ts +2 -2
  78. package/src/__tests__/task-runner.test.ts +14 -4
  79. package/src/__tests__/terminal-tools.test.ts +25 -19
  80. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  81. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  82. package/src/__tests__/tool-executor.test.ts +23 -24
  83. package/src/__tests__/trust-store.test.ts +3 -3
  84. package/src/__tests__/twilio-rest.test.ts +29 -0
  85. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  86. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  87. package/src/__tests__/twilio-routes.test.ts +141 -21
  88. package/src/__tests__/user-reference.test.ts +2 -0
  89. package/src/__tests__/voice-quality.test.ts +222 -0
  90. package/src/__tests__/web-search.test.ts +45 -29
  91. package/src/agent/loop.ts +1 -1
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  93. package/src/amazon/client.ts +1418 -0
  94. package/src/amazon/request-extractor.ts +135 -0
  95. package/src/amazon/session.ts +109 -0
  96. package/src/autonomy/autonomy-store.ts +5 -5
  97. package/src/browser-extension-relay/client.ts +124 -0
  98. package/src/browser-extension-relay/protocol.ts +63 -0
  99. package/src/browser-extension-relay/server.ts +177 -0
  100. package/src/bundler/app-bundler.ts +3 -3
  101. package/src/bundler/bundle-signer.ts +1 -1
  102. package/src/bundler/signature-verifier.ts +1 -1
  103. package/src/calls/call-conversation-messages.ts +33 -0
  104. package/src/calls/call-domain.ts +106 -5
  105. package/src/calls/call-orchestrator.ts +252 -54
  106. package/src/calls/call-pointer-messages.ts +53 -0
  107. package/src/calls/call-recovery.ts +3 -8
  108. package/src/calls/call-store.ts +69 -87
  109. package/src/calls/elevenlabs-config.ts +3 -2
  110. package/src/calls/guardian-action-sweep.ts +105 -0
  111. package/src/calls/guardian-dispatch.ts +203 -0
  112. package/src/calls/guardian-question-copy.ts +133 -0
  113. package/src/calls/relay-server.ts +466 -8
  114. package/src/calls/speaker-identification.ts +1 -1
  115. package/src/calls/twilio-config.ts +7 -5
  116. package/src/calls/twilio-provider.ts +6 -4
  117. package/src/calls/twilio-rest.ts +40 -15
  118. package/src/calls/twilio-routes.ts +60 -45
  119. package/src/calls/types.ts +3 -1
  120. package/src/channels/types.ts +25 -0
  121. package/src/cli/amazon.ts +815 -0
  122. package/src/cli/config-commands.ts +2 -2
  123. package/src/cli/core-commands.ts +4 -3
  124. package/src/cli/influencer.ts +244 -0
  125. package/src/cli/map.ts +89 -6
  126. package/src/cli.ts +1 -1
  127. package/src/config/agent-schema.ts +171 -0
  128. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  129. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  130. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  131. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  132. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  133. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  134. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  135. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  136. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  137. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  138. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  139. package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
  140. package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
  141. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  142. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  143. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  144. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  145. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  146. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  147. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  148. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
  149. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  150. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
  151. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
  152. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  153. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
  154. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
  155. package/src/config/bundled-skills/messaging/SKILL.md +12 -2
  156. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  157. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  158. package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
  159. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  160. package/src/config/bundled-tool-registry.ts +310 -0
  161. package/src/config/calls-schema.ts +181 -0
  162. package/src/config/core-schema.ts +309 -0
  163. package/src/config/defaults.ts +27 -3
  164. package/src/config/env-registry.ts +169 -0
  165. package/src/config/env.ts +175 -0
  166. package/src/config/loader.ts +6 -6
  167. package/src/config/memory-schema.ts +528 -0
  168. package/src/config/sandbox-schema.ts +55 -0
  169. package/src/config/schema.ts +157 -1138
  170. package/src/config/skill-state.ts +1 -1
  171. package/src/config/skills-schema.ts +32 -0
  172. package/src/config/skills.ts +35 -24
  173. package/src/config/system-prompt.ts +107 -56
  174. package/src/config/templates/SOUL.md +1 -1
  175. package/src/config/types.ts +1 -0
  176. package/src/config/user-reference.ts +4 -9
  177. package/src/config/vellum-skills/catalog.json +0 -7
  178. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  179. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
  180. package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
  181. package/src/context/window-manager.ts +27 -7
  182. package/src/daemon/approval-generators.ts +186 -0
  183. package/src/daemon/approved-devices-store.ts +140 -0
  184. package/src/daemon/assistant-attachments.ts +1 -1
  185. package/src/daemon/classifier.ts +35 -32
  186. package/src/daemon/config-watcher.ts +1 -1
  187. package/src/daemon/daemon-control.ts +254 -0
  188. package/src/daemon/handlers/apps.ts +2 -3
  189. package/src/daemon/handlers/config-channels.ts +158 -0
  190. package/src/daemon/handlers/config-inbox.ts +540 -0
  191. package/src/daemon/handlers/config-ingress.ts +231 -0
  192. package/src/daemon/handlers/config-integrations.ts +258 -0
  193. package/src/daemon/handlers/config-model.ts +143 -0
  194. package/src/daemon/handlers/config-parental.ts +163 -0
  195. package/src/daemon/handlers/config-scheduling.ts +172 -0
  196. package/src/daemon/handlers/config-slack.ts +92 -0
  197. package/src/daemon/handlers/config-telegram.ts +301 -0
  198. package/src/daemon/handlers/config-tools.ts +177 -0
  199. package/src/daemon/handlers/config-trust.ts +104 -0
  200. package/src/daemon/handlers/config-twilio.ts +1080 -0
  201. package/src/daemon/handlers/config.ts +53 -2463
  202. package/src/daemon/handlers/diagnostics.ts +1 -1
  203. package/src/daemon/handlers/dictation.ts +4 -6
  204. package/src/daemon/handlers/documents.ts +18 -32
  205. package/src/daemon/handlers/index.ts +9 -0
  206. package/src/daemon/handlers/misc.ts +3 -5
  207. package/src/daemon/handlers/pairing.ts +98 -0
  208. package/src/daemon/handlers/sessions.ts +74 -5
  209. package/src/daemon/handlers/shared.ts +3 -1
  210. package/src/daemon/handlers/skills.ts +1 -1
  211. package/src/daemon/handlers/twitter-auth.ts +2 -0
  212. package/src/daemon/handlers/work-items.ts +2 -2
  213. package/src/daemon/handlers/workspace-files.ts +4 -3
  214. package/src/daemon/install-cli-launchers.ts +113 -0
  215. package/src/daemon/ipc-contract/apps.ts +356 -0
  216. package/src/daemon/ipc-contract/browser.ts +74 -0
  217. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  218. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  219. package/src/daemon/ipc-contract/documents.ts +74 -0
  220. package/src/daemon/ipc-contract/inbox.ts +209 -0
  221. package/src/daemon/ipc-contract/integrations.ts +284 -0
  222. package/src/daemon/ipc-contract/memory.ts +48 -0
  223. package/src/daemon/ipc-contract/messages.ts +211 -0
  224. package/src/daemon/ipc-contract/pairing.ts +45 -0
  225. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  226. package/src/daemon/ipc-contract/schedules.ts +97 -0
  227. package/src/daemon/ipc-contract/sessions.ts +321 -0
  228. package/src/daemon/ipc-contract/shared.ts +42 -0
  229. package/src/daemon/ipc-contract/skills.ts +120 -0
  230. package/src/daemon/ipc-contract/subagents.ts +58 -0
  231. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  232. package/src/daemon/ipc-contract/trust.ts +60 -0
  233. package/src/daemon/ipc-contract/work-items.ts +225 -0
  234. package/src/daemon/ipc-contract/workspace.ts +113 -0
  235. package/src/daemon/ipc-contract-inventory.json +62 -0
  236. package/src/daemon/ipc-contract-inventory.ts +55 -29
  237. package/src/daemon/ipc-contract.ts +227 -2527
  238. package/src/daemon/ipc-protocol.ts +1 -1
  239. package/src/daemon/ipc-validate.ts +7 -0
  240. package/src/daemon/lifecycle.ts +97 -379
  241. package/src/daemon/pairing-store.ts +177 -0
  242. package/src/daemon/providers-setup.ts +43 -0
  243. package/src/daemon/ride-shotgun-handler.ts +67 -2
  244. package/src/daemon/server.ts +60 -44
  245. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  246. package/src/daemon/session-agent-loop.ts +113 -275
  247. package/src/daemon/session-dynamic-profile.ts +1 -1
  248. package/src/daemon/session-history.ts +1 -1
  249. package/src/daemon/session-media-retry.ts +1 -1
  250. package/src/daemon/session-messaging.ts +37 -2
  251. package/src/daemon/session-notifiers.ts +5 -25
  252. package/src/daemon/session-process.ts +99 -59
  253. package/src/daemon/session-queue-manager.ts +98 -4
  254. package/src/daemon/session-runtime-assembly.ts +149 -15
  255. package/src/daemon/session-surfaces.ts +26 -4
  256. package/src/daemon/session-tool-setup.ts +28 -30
  257. package/src/daemon/session-workspace.ts +1 -1
  258. package/src/daemon/session.ts +24 -1
  259. package/src/daemon/shutdown-handlers.ts +122 -0
  260. package/src/daemon/trace-emitter.ts +1 -1
  261. package/src/daemon/watch-handler.ts +36 -33
  262. package/src/doordash/cart-queries.ts +787 -0
  263. package/src/doordash/client.ts +144 -127
  264. package/src/doordash/order-queries.ts +85 -0
  265. package/src/doordash/queries.ts +10 -1308
  266. package/src/doordash/search-queries.ts +203 -0
  267. package/src/doordash/session.ts +3 -2
  268. package/src/doordash/store-queries.ts +246 -0
  269. package/src/doordash/types.ts +367 -0
  270. package/src/email/providers/agentmail.ts +2 -1
  271. package/src/email/providers/index.ts +3 -2
  272. package/src/email/service.ts +3 -2
  273. package/src/errors.ts +43 -0
  274. package/src/home-base/prebuilt/seed.ts +1 -1
  275. package/src/hooks/cli.ts +6 -5
  276. package/src/hooks/config.ts +6 -8
  277. package/src/hooks/discovery.ts +6 -5
  278. package/src/hooks/manager.ts +4 -3
  279. package/src/hooks/runner.ts +2 -2
  280. package/src/hooks/templates.ts +5 -5
  281. package/src/inbound/public-ingress-urls.ts +3 -1
  282. package/src/index.ts +4 -2
  283. package/src/influencer/client.ts +1104 -0
  284. package/src/instrument.ts +4 -3
  285. package/src/logfire.ts +4 -3
  286. package/src/memory/admin.ts +25 -35
  287. package/src/memory/attachments-store.ts +4 -7
  288. package/src/memory/channel-delivery-store.ts +30 -1
  289. package/src/memory/channel-guardian-store.ts +200 -1
  290. package/src/memory/clarification-resolver.ts +37 -33
  291. package/src/memory/conflict-store.ts +67 -61
  292. package/src/memory/contradiction-checker.ts +141 -117
  293. package/src/memory/conversation-store.ts +335 -51
  294. package/src/memory/db-connection.ts +27 -4
  295. package/src/memory/db-init.ts +121 -4
  296. package/src/memory/db.ts +14 -1
  297. package/src/memory/embedding-backend.ts +27 -5
  298. package/src/memory/embedding-ollama.ts +2 -1
  299. package/src/memory/entity-extractor.ts +38 -35
  300. package/src/memory/guardian-action-store.ts +430 -0
  301. package/src/memory/inbox-escalation-projection.ts +59 -0
  302. package/src/memory/inbox-thread-store.ts +218 -0
  303. package/src/memory/ingress-invite-store.ts +338 -0
  304. package/src/memory/ingress-member-store.ts +350 -0
  305. package/src/memory/items-extractor.ts +91 -97
  306. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  307. package/src/memory/job-handlers/media-processing.ts +11 -42
  308. package/src/memory/job-handlers/summarization.ts +32 -26
  309. package/src/memory/job-utils.ts +3 -10
  310. package/src/memory/jobs-store.ts +6 -9
  311. package/src/memory/jobs-worker.ts +51 -36
  312. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  313. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  314. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  315. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  316. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  317. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  318. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  319. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  320. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  321. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  322. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  323. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  324. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  325. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  326. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  327. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  328. package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
  329. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  330. package/src/memory/migrations/index.ts +24 -0
  331. package/src/memory/migrations/registry.ts +79 -0
  332. package/src/memory/migrations/validate-migration-state.ts +69 -0
  333. package/src/memory/qdrant-manager.ts +49 -8
  334. package/src/memory/query-builder.ts +1 -1
  335. package/src/memory/raw-query.ts +119 -0
  336. package/src/memory/recall-cache.ts +4 -1
  337. package/src/memory/retriever.ts +163 -47
  338. package/src/memory/schema-migration.ts +25 -984
  339. package/src/memory/schema.ts +130 -7
  340. package/src/memory/search/entity.ts +10 -19
  341. package/src/memory/search/lexical.ts +81 -52
  342. package/src/memory/search/ranking.ts +21 -22
  343. package/src/memory/search/semantic.ts +157 -19
  344. package/src/memory/shared-app-links-store.ts +4 -5
  345. package/src/memory/validation.ts +19 -0
  346. package/src/messaging/draft-store.ts +5 -6
  347. package/src/messaging/providers/sms/adapter.ts +3 -6
  348. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  349. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  350. package/src/messaging/providers/whatsapp/client.ts +67 -0
  351. package/src/messaging/style-analyzer.ts +5 -4
  352. package/src/messaging/thread-summarizer.ts +61 -69
  353. package/src/messaging/triage-engine.ts +62 -71
  354. package/src/migrations/config-merge.ts +53 -0
  355. package/src/migrations/data-layout.ts +68 -0
  356. package/src/migrations/data-merge.ts +33 -0
  357. package/src/migrations/hooks-merge.ts +90 -0
  358. package/src/migrations/index.ts +6 -0
  359. package/src/migrations/log.ts +23 -0
  360. package/src/migrations/skills-merge.ts +33 -0
  361. package/src/migrations/workspace-layout.ts +79 -0
  362. package/src/permissions/checker.ts +126 -11
  363. package/src/permissions/prompter.ts +14 -0
  364. package/src/permissions/shell-identity.ts +31 -1
  365. package/src/permissions/trust-store.ts +21 -1
  366. package/src/providers/anthropic/client.ts +4 -4
  367. package/src/providers/failover.ts +2 -2
  368. package/src/providers/model-intents.ts +70 -0
  369. package/src/providers/ollama/client.ts +2 -1
  370. package/src/providers/provider-send-message.ts +176 -0
  371. package/src/providers/registry.ts +71 -30
  372. package/src/providers/retry.ts +35 -1
  373. package/src/providers/types.ts +12 -1
  374. package/src/runtime/approval-conversation-turn.ts +97 -0
  375. package/src/runtime/approval-message-composer.ts +115 -5
  376. package/src/runtime/assistant-event-hub.ts +3 -1
  377. package/src/runtime/channel-approval-parser.ts +36 -2
  378. package/src/runtime/channel-approvals.ts +0 -21
  379. package/src/runtime/channel-guardian-service.ts +48 -7
  380. package/src/runtime/channel-readiness-service.ts +160 -34
  381. package/src/runtime/channel-readiness-types.ts +10 -4
  382. package/src/runtime/channel-retry-sweep.ts +184 -0
  383. package/src/runtime/guardian-context-resolver.ts +108 -0
  384. package/src/runtime/http-server.ts +289 -745
  385. package/src/runtime/http-types.ts +56 -3
  386. package/src/runtime/middleware/auth.ts +116 -0
  387. package/src/runtime/middleware/error-handler.ts +33 -0
  388. package/src/runtime/middleware/twilio-validation.ts +127 -0
  389. package/src/runtime/routes/app-routes.ts +1 -1
  390. package/src/runtime/routes/call-routes.ts +49 -6
  391. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  392. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  393. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  394. package/src/runtime/routes/channel-route-shared.ts +144 -0
  395. package/src/runtime/routes/channel-routes.ts +32 -1634
  396. package/src/runtime/routes/conversation-routes.ts +50 -7
  397. package/src/runtime/routes/events-routes.ts +2 -2
  398. package/src/runtime/routes/identity-routes.ts +126 -0
  399. package/src/runtime/routes/pairing-routes.ts +144 -0
  400. package/src/runtime/routes/run-routes.ts +15 -1
  401. package/src/runtime/run-orchestrator.ts +52 -34
  402. package/src/schedule/schedule-store.ts +36 -32
  403. package/src/schedule/scheduler.ts +3 -3
  404. package/src/security/encrypted-store.ts +5 -7
  405. package/src/security/oauth2.ts +45 -15
  406. package/src/security/parental-control-store.ts +183 -0
  407. package/src/security/secret-allowlist.ts +4 -3
  408. package/src/security/secret-scanner.ts +5 -5
  409. package/src/security/secure-keys.ts +1 -1
  410. package/src/security/token-manager.ts +3 -2
  411. package/src/services/vercel-deploy.ts +6 -2
  412. package/src/skills/tool-manifest.ts +3 -3
  413. package/src/skills/vellum-catalog-remote.ts +75 -16
  414. package/src/slack/slack-webhook.ts +2 -1
  415. package/src/swarm/orchestrator.ts +92 -1
  416. package/src/swarm/router-planner.ts +6 -9
  417. package/src/swarm/worker-prompts.ts +9 -12
  418. package/src/tasks/task-compiler.ts +19 -28
  419. package/src/tasks/task-runner.ts +1 -1
  420. package/src/tools/assets/search.ts +15 -14
  421. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  422. package/src/tools/browser/auto-navigate.ts +1 -0
  423. package/src/tools/browser/browser-execution.ts +13 -1
  424. package/src/tools/browser/browser-manager.ts +119 -4
  425. package/src/tools/browser/network-recorder.ts +5 -0
  426. package/src/tools/credentials/broker.ts +11 -2
  427. package/src/tools/credentials/metadata-store.ts +18 -14
  428. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  429. package/src/tools/credentials/vault.ts +49 -23
  430. package/src/tools/executor.ts +80 -18
  431. package/src/tools/host-terminal/cli-discover.ts +1 -1
  432. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  433. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  434. package/src/tools/network/script-proxy/server.ts +1 -1
  435. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  436. package/src/tools/network/web-fetch.ts +18 -2
  437. package/src/tools/network/web-search.ts +7 -3
  438. package/src/tools/reminder/reminder-store.ts +14 -15
  439. package/src/tools/schedule/create.ts +1 -0
  440. package/src/tools/schedule/list.ts +2 -1
  441. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  442. package/src/tools/skills/skill-script-runner.ts +24 -9
  443. package/src/tools/skills/skill-tool-factory.ts +1 -0
  444. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  445. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  446. package/src/tools/terminal/parser.ts +50 -0
  447. package/src/tools/watcher/delete.ts +6 -0
  448. package/src/tools/weather/service.ts +1 -1
  449. package/src/twitter/client.ts +190 -24
  450. package/src/twitter/session.ts +4 -3
  451. package/src/util/clipboard.ts +1 -1
  452. package/src/util/errors.ts +65 -8
  453. package/src/util/fs.ts +40 -0
  454. package/src/util/json.ts +10 -0
  455. package/src/util/log-redact.ts +189 -0
  456. package/src/util/logger.ts +25 -18
  457. package/src/util/object.ts +3 -0
  458. package/src/util/platform.ts +72 -365
  459. package/src/util/pricing.ts +1 -1
  460. package/src/util/promise-guard.ts +1 -1
  461. package/src/util/retry.ts +19 -0
  462. package/src/util/row-mapper.ts +79 -0
  463. package/src/util/silently.ts +21 -0
  464. package/src/watcher/engine.ts +5 -1
  465. package/src/watcher/provider-types.ts +20 -0
  466. package/src/watcher/providers/github.ts +156 -0
  467. package/src/watcher/providers/gmail.ts +1 -0
  468. package/src/watcher/providers/google-calendar.ts +1 -0
  469. package/src/watcher/providers/linear.ts +460 -0
  470. package/src/watcher/providers/slack.ts +1 -0
  471. package/src/work-items/work-item-runner.ts +1 -1
  472. package/src/workspace/git-service.ts +1 -1
  473. package/src/workspace/provider-commit-message-generator.ts +51 -22
  474. package/src/__tests__/call-bridge.test.ts +0 -517
  475. package/src/__tests__/session-process-bridge.test.ts +0 -244
  476. package/src/calls/call-bridge.ts +0 -168
  477. package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
  478. package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
  479. package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
  480. package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
  481. package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
  482. package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
  483. package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
  484. package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
  485. package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
  486. package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
  487. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -61,7 +61,7 @@ const SENSITIVE_KEYS = new Set([
61
61
  function redactDeep(value: unknown): unknown {
62
62
  if (typeof value === 'string') return redact(value);
63
63
  if (Array.isArray(value)) return value.map(redactDeep);
64
- if (value !== null && typeof value === 'object') {
64
+ if (value != null && typeof value === 'object') {
65
65
  const out: Record<string, unknown> = {};
66
66
  for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
67
67
  if (SENSITIVE_KEYS.has(k.toLowerCase())) {
@@ -1,6 +1,5 @@
1
1
  import * as net from 'node:net';
2
- import { getConfig } from '../../config/loader.js';
3
- import { getFailoverProvider, listProviders } from '../../providers/registry.js';
2
+ import { getConfiguredProvider } from '../../providers/provider-send-message.js';
4
3
  import type { DictationRequest } from '../ipc-protocol.js';
5
4
  import { log, defineHandlers, type HandlerContext } from './shared.js';
6
5
 
@@ -147,15 +146,14 @@ export async function handleDictationRequest(
147
146
  : msg.transcription; // command prompt already embeds the selected text and instruction
148
147
 
149
148
  try {
150
- const config = getConfig();
151
- if (!listProviders().includes(config.provider)) {
152
- log.warn({ provider: config.provider }, 'Dictation: no provider available, returning raw transcription');
149
+ const provider = getConfiguredProvider();
150
+ if (!provider) {
151
+ log.warn('Dictation: no provider available, returning raw transcription');
153
152
  const fallbackText = mode === 'command' ? (msg.context.selectedText ?? msg.transcription) : msg.transcription;
154
153
  ctx.send(socket, { type: 'dictation_response', text: fallbackText, mode });
155
154
  return;
156
155
  }
157
156
 
158
- const provider = getFailoverProvider(config.provider, config.providerOrder);
159
157
  const response = await provider.sendMessage(
160
158
  [{ role: 'user', content: [{ type: 'text', text: userText }] }],
161
159
  [], // no tools
@@ -2,12 +2,23 @@ import { defineHandlers } from './shared.js';
2
2
  import type { HandlerContext } from './shared.js';
3
3
  import type { DocumentSaveRequest, DocumentLoadRequest, DocumentListRequest } from '../ipc-protocol.js';
4
4
  import type * as net from 'node:net';
5
- import type { Database } from 'bun:sqlite';
6
- import { getDb } from '../../memory/db.js';
5
+ import { rawRun, rawGet, rawAll } from '../../memory/db.js';
7
6
  import { getLogger } from '../../util/logger.js';
8
7
 
9
8
  const log = getLogger('documents');
10
9
 
10
+ interface DocumentRow {
11
+ surface_id: string;
12
+ conversation_id: string;
13
+ title: string;
14
+ content: string;
15
+ word_count: number;
16
+ created_at: number;
17
+ updated_at: number;
18
+ }
19
+
20
+ type DocumentListRow = Omit<DocumentRow, 'content'>;
21
+
11
22
  export function handleDocumentSave(msg: DocumentSaveRequest, socket: net.Socket, ctx: HandlerContext): void {
12
23
  log.info({
13
24
  surfaceId: msg.surfaceId,
@@ -18,13 +29,9 @@ export function handleDocumentSave(msg: DocumentSaveRequest, socket: net.Socket,
18
29
  }, 'Received save request');
19
30
 
20
31
  try {
21
- const db = getDb();
22
- // Get the raw SQLite client from Drizzle
23
- const sqlite = (db as unknown as { $client: Database }).$client;
24
32
  const now = Date.now();
25
33
 
26
- // Upsert document (insert or update if exists)
27
- sqlite.run(
34
+ rawRun(
28
35
  `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at)
29
36
  VALUES (?, ?, ?, ?, ?, ?, ?)
30
37
  ON CONFLICT(surface_id) DO UPDATE SET
@@ -32,7 +39,7 @@ export function handleDocumentSave(msg: DocumentSaveRequest, socket: net.Socket,
32
39
  content = excluded.content,
33
40
  word_count = excluded.word_count,
34
41
  updated_at = excluded.updated_at`,
35
- [msg.surfaceId, msg.conversationId, msg.title, msg.content, msg.wordCount, now, now]
42
+ msg.surfaceId, msg.conversationId, msg.title, msg.content, msg.wordCount, now, now,
36
43
  );
37
44
 
38
45
  ctx.send(socket, {
@@ -55,22 +62,11 @@ export function handleDocumentSave(msg: DocumentSaveRequest, socket: net.Socket,
55
62
 
56
63
  export function handleDocumentLoad(msg: DocumentLoadRequest, socket: net.Socket, ctx: HandlerContext): void {
57
64
  try {
58
- const db = getDb();
59
- const sqlite = (db as unknown as { $client: Database }).$client;
60
-
61
- const result = sqlite.prepare(/*sql*/ `
65
+ const result = rawGet<DocumentRow>(/*sql*/ `
62
66
  SELECT surface_id, conversation_id, title, content, word_count, created_at, updated_at
63
67
  FROM documents
64
68
  WHERE surface_id = ?
65
- `).get(msg.surfaceId) as {
66
- surface_id: string;
67
- conversation_id: string;
68
- title: string;
69
- content: string;
70
- word_count: number;
71
- created_at: number;
72
- updated_at: number;
73
- } | undefined;
69
+ `, msg.surfaceId);
74
70
 
75
71
  if (result) {
76
72
  ctx.send(socket, {
@@ -119,9 +115,6 @@ export function handleDocumentLoad(msg: DocumentLoadRequest, socket: net.Socket,
119
115
 
120
116
  export function handleDocumentList(msg: DocumentListRequest, socket: net.Socket, ctx: HandlerContext): void {
121
117
  try {
122
- const db = getDb();
123
- const sqlite = (db as unknown as { $client: Database }).$client;
124
-
125
118
  let query = /*sql*/ `
126
119
  SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
127
120
  FROM documents
@@ -135,14 +128,7 @@ export function handleDocumentList(msg: DocumentListRequest, socket: net.Socket,
135
128
 
136
129
  query += ' ORDER BY updated_at DESC';
137
130
 
138
- const results = sqlite.prepare(query).all(...params) as Array<{
139
- surface_id: string;
140
- conversation_id: string;
141
- title: string;
142
- word_count: number;
143
- created_at: number;
144
- updated_at: number;
145
- }>;
131
+ const results = rawAll<DocumentListRow>(query, ...params);
146
132
 
147
133
  ctx.send(socket, {
148
134
  type: 'document_list_response',
@@ -23,6 +23,8 @@ import { twitterAuthHandlers } from './twitter-auth.js';
23
23
  import { workspaceFileHandlers } from './workspace-files.js';
24
24
  import { identityHandlers } from './identity.js';
25
25
  import { dictationHandlers } from './dictation.js';
26
+ import { inboxInviteHandlers } from './config-inbox.js';
27
+ import { pairingHandlers } from './pairing.js';
26
28
 
27
29
  // Re-export types and utilities for backwards compatibility
28
30
  export type {
@@ -88,6 +90,11 @@ const inlineHandlers = defineHandlers({
88
90
  },
89
91
  integration_disconnect: () => { /* no-op — integration registry removed */ },
90
92
 
93
+ // Stub handler: assistant_inbox — real implementation will be added in a follow-up PR.
94
+ assistant_inbox: (_msg, socket, ctx) => {
95
+ ctx.send(socket, { type: 'assistant_inbox_response', success: false, error: 'Not yet implemented' });
96
+ },
97
+
91
98
  });
92
99
 
93
100
  const handlers = {
@@ -109,6 +116,8 @@ const handlers = {
109
116
  ...workspaceFileHandlers,
110
117
  ...identityHandlers,
111
118
  ...dictationHandlers,
119
+ ...inboxInviteHandlers,
120
+ ...pairingHandlers,
112
121
  ...inlineHandlers,
113
122
  } satisfies DispatchMap;
114
123
 
@@ -3,8 +3,7 @@ import { v4 as uuid } from 'uuid';
3
3
  import { readFileSync } from 'node:fs';
4
4
  import { createHash } from 'node:crypto';
5
5
  import * as conversationStore from '../../memory/conversation-store.js';
6
- import { getConfig } from '../../config/loader.js';
7
- import { getFailoverProvider, listProviders } from '../../providers/registry.js';
6
+ import { getConfiguredProvider } from '../../providers/provider-send-message.js';
8
7
  import type { Provider } from '../../providers/types.js';
9
8
  import { classifyInteraction } from '../classifier.js';
10
9
  import { checkIngressForSecrets } from '../../security/secret-ingress.js';
@@ -172,10 +171,9 @@ export async function handleSuggestionRequest(
172
171
  }
173
172
 
174
173
  // Try LLM suggestion using the configured provider
175
- const config = getConfig();
176
- if (listProviders().includes(config.provider)) {
174
+ const provider = getConfiguredProvider();
175
+ if (provider) {
177
176
  try {
178
- const provider = getFailoverProvider(config.provider, config.providerOrder);
179
177
  let promise = suggestionInFlight.get(m.id);
180
178
  if (!promise) {
181
179
  promise = generateSuggestion(provider, text);
@@ -0,0 +1,98 @@
1
+ import * as net from 'node:net';
2
+ import type {
3
+ PairingApprovalResponse,
4
+ ApprovedDeviceRemove,
5
+ } from '../ipc-protocol.js';
6
+ import { log, defineHandlers, type HandlerContext } from './shared.js';
7
+ import {
8
+ approveDevice,
9
+ removeDevice,
10
+ clearAllDevices,
11
+ listDevices,
12
+ } from '../approved-devices-store.js';
13
+ import type { PairingStore } from '../pairing-store.js';
14
+
15
+ /** Module-level reference set by the daemon server at startup. */
16
+ let pairingStoreRef: PairingStore | null = null;
17
+ let bearerTokenRef: string | undefined;
18
+
19
+ export function initPairingHandlers(store: PairingStore, bearerToken: string | undefined): void {
20
+ pairingStoreRef = store;
21
+ bearerTokenRef = bearerToken;
22
+ }
23
+
24
+ function handlePairingApprovalResponse(
25
+ msg: PairingApprovalResponse,
26
+ _socket: net.Socket,
27
+ _ctx: HandlerContext,
28
+ ): void {
29
+ if (!pairingStoreRef) {
30
+ log.warn('Pairing store not initialized');
31
+ return;
32
+ }
33
+
34
+ const entry = pairingStoreRef.get(msg.pairingRequestId);
35
+ if (!entry) {
36
+ log.warn({ pairingRequestId: msg.pairingRequestId }, 'Pairing request not found for approval response');
37
+ return;
38
+ }
39
+
40
+ // Idempotent: if already approved/denied, just re-broadcast the current status
41
+ if (entry.status === 'approved' || entry.status === 'denied') {
42
+ log.info({ pairingRequestId: msg.pairingRequestId, status: entry.status }, 'Duplicate approval response, no-op');
43
+ return;
44
+ }
45
+
46
+ if (msg.decision === 'deny') {
47
+ pairingStoreRef.deny(msg.pairingRequestId);
48
+ log.info({ pairingRequestId: msg.pairingRequestId }, 'Pairing request denied');
49
+ return;
50
+ }
51
+
52
+ // approve_once or always_allow
53
+ if (!bearerTokenRef) {
54
+ log.error('Cannot approve pairing: no bearer token configured');
55
+ return;
56
+ }
57
+
58
+ pairingStoreRef.approve(msg.pairingRequestId, bearerTokenRef);
59
+ log.info({ pairingRequestId: msg.pairingRequestId, decision: msg.decision }, 'Pairing request approved');
60
+
61
+ // If always_allow, persist the device to the allowlist
62
+ if (msg.decision === 'always_allow' && entry.hashedDeviceId) {
63
+ approveDevice(entry.hashedDeviceId, entry.deviceName ?? 'Unknown Device');
64
+ }
65
+ }
66
+
67
+ function handleApprovedDevicesList(socket: net.Socket, ctx: HandlerContext): void {
68
+ const devices = listDevices();
69
+ ctx.send(socket, {
70
+ type: 'approved_devices_list_response',
71
+ devices,
72
+ });
73
+ }
74
+
75
+ function handleApprovedDeviceRemove(
76
+ msg: ApprovedDeviceRemove,
77
+ socket: net.Socket,
78
+ ctx: HandlerContext,
79
+ ): void {
80
+ const success = removeDevice(msg.hashedDeviceId);
81
+ ctx.send(socket, {
82
+ type: 'approved_device_remove_response',
83
+ success,
84
+ });
85
+ log.info({ hashedDeviceId: msg.hashedDeviceId, success }, 'Device removal requested via IPC');
86
+ }
87
+
88
+ function handleApprovedDevicesClear(_socket: net.Socket, _ctx: HandlerContext): void {
89
+ clearAllDevices();
90
+ log.info('All approved devices cleared via IPC');
91
+ }
92
+
93
+ export const pairingHandlers = defineHandlers({
94
+ pairing_approval_response: handlePairingApprovalResponse,
95
+ approved_devices_list: (_msg, socket, ctx) => handleApprovedDevicesList(socket, ctx),
96
+ approved_device_remove: handleApprovedDeviceRemove,
97
+ approved_devices_clear: (_msg, socket, ctx) => handleApprovedDevicesClear(socket, ctx),
98
+ });
@@ -1,4 +1,6 @@
1
1
  import * as net from 'node:net';
2
+ import { isChannelId, parseChannelId } from '../../channels/types.js';
3
+ import { silentlyWithLog } from '../../util/silently.js';
2
4
  import { v4 as uuid } from 'uuid';
3
5
  import * as conversationStore from '../../memory/conversation-store.js';
4
6
  import * as externalConversationStore from '../../memory/external-conversation-store.js';
@@ -14,6 +16,7 @@ import type {
14
16
  SecretResponse,
15
17
  SessionCreateRequest,
16
18
  SessionSwitchRequest,
19
+ SessionRenameRequest,
17
20
  CancelRequest,
18
21
  DeleteQueuedMessage,
19
22
  HistoryRequest,
@@ -22,6 +25,7 @@ import type {
22
25
  UsageRequest,
23
26
  SandboxSetRequest,
24
27
  ServerMessage,
28
+ ConversationSearchRequest,
25
29
  } from '../ipc-protocol.js';
26
30
  import { getConfig } from '../../config/loader.js';
27
31
  import { getSubagentManager } from '../../subagent/index.js';
@@ -80,7 +84,20 @@ export async function handleUserMessage(
80
84
  attributes: { source: 'user_message' },
81
85
  });
82
86
 
83
- const result = session.enqueueMessage(msg.content ?? '', msg.attachments ?? [], sendEvent, requestId, msg.activeSurfaceId, msg.currentPage);
87
+ const ipcChannel = parseChannelId(msg.channel) ?? 'macos';
88
+ const queuedChannelMetadata = {
89
+ userMessageChannel: ipcChannel,
90
+ assistantMessageChannel: ipcChannel,
91
+ };
92
+ const result = session.enqueueMessage(
93
+ msg.content ?? '',
94
+ msg.attachments ?? [],
95
+ sendEvent,
96
+ requestId,
97
+ msg.activeSurfaceId,
98
+ msg.currentPage,
99
+ queuedChannelMetadata,
100
+ );
84
101
  if (result.rejected) {
85
102
  rlog.warn('Message rejected — queue is full');
86
103
  session.traceEmitter.emit('request_error', 'Message rejected — queue is full', {
@@ -114,8 +131,13 @@ export async function handleUserMessage(
114
131
  }
115
132
 
116
133
  rlog.info('Processing user message');
134
+ session.setTurnChannelContext({
135
+ userMessageChannel: ipcChannel,
136
+ assistantMessageChannel: ipcChannel,
137
+ });
117
138
  session.setAssistantId('self');
118
139
  session.setGuardianContext(null);
140
+ session.setCommandIntent(null);
119
141
  // Fire-and-forget: don't block the IPC handler so the connection can
120
142
  // continue receiving messages (e.g. cancel, confirmations, or
121
143
  // additional user_message that will be queued by the session).
@@ -210,12 +232,14 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
210
232
  type: 'session_list_response',
211
233
  sessions: conversations.map((c) => {
212
234
  const binding = bindings.get(c.id);
235
+ const originChannel = parseChannelId(c.originChannel);
213
236
  return {
214
237
  id: c.id,
215
238
  title: c.title ?? 'Untitled',
216
239
  updatedAt: c.updatedAt,
217
240
  threadType: normalizeThreadType(c.threadType),
218
- ...(binding ? {
241
+ source: c.source ?? 'user',
242
+ ...(binding && isChannelId(binding.sourceChannel) ? {
219
243
  channelBinding: {
220
244
  sourceChannel: binding.sourceChannel,
221
245
  externalChatId: binding.externalChatId,
@@ -224,6 +248,7 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
224
248
  username: binding.username,
225
249
  },
226
250
  } : {}),
251
+ ...(originChannel ? { conversationOriginChannel: originChannel } : {}),
227
252
  };
228
253
  }),
229
254
  hasMore: offset + conversations.length < totalCount,
@@ -276,6 +301,11 @@ export async function handleSessionCreate(
276
301
  ctx.socketToSession.set(socket, conversation.id);
277
302
  const sendEvent = (event: ServerMessage) => ctx.send(socket, event);
278
303
  const requestId = uuid();
304
+ const transportChannel = parseChannelId(msg.transport?.channelId) ?? 'macos';
305
+ session.setTurnChannelContext({
306
+ userMessageChannel: transportChannel,
307
+ assistantMessageChannel: transportChannel,
308
+ });
279
309
  session.processMessage(msg.initialMessage, [], sendEvent, requestId).catch((err) => {
280
310
  const message = err instanceof Error ? err.message : String(err);
281
311
  log.error({ err, sessionId: conversation.id }, 'Error processing initial message');
@@ -323,6 +353,24 @@ export async function handleSessionSwitch(
323
353
  });
324
354
  }
325
355
 
356
+ export function handleSessionRename(
357
+ msg: SessionRenameRequest,
358
+ socket: net.Socket,
359
+ ctx: HandlerContext,
360
+ ): void {
361
+ const conversation = conversationStore.getConversation(msg.sessionId);
362
+ if (!conversation) {
363
+ ctx.send(socket, { type: 'error', message: `Session ${msg.sessionId} not found` });
364
+ return;
365
+ }
366
+ conversationStore.updateConversationTitle(msg.sessionId, msg.title);
367
+ ctx.send(socket, {
368
+ type: 'session_title_updated',
369
+ sessionId: msg.sessionId,
370
+ title: msg.title,
371
+ });
372
+ }
373
+
326
374
  export function handleCancel(msg: CancelRequest, socket: net.Socket, ctx: HandlerContext): void {
327
375
  const sessionId = msg.sessionId || ctx.socketToSession.get(socket);
328
376
  if (sessionId) {
@@ -403,9 +451,12 @@ export function handleHistoryRequest(
403
451
  if (a.mimeType.startsWith('video/') && !a.thumbnailBase64) {
404
452
  const attachmentId = a.id;
405
453
  const base64 = a.dataBase64;
406
- generateVideoThumbnail(base64).then((thumb) => {
407
- if (thumb) setAttachmentThumbnail(attachmentId, thumb);
408
- }).catch(() => {});
454
+ silentlyWithLog(
455
+ generateVideoThumbnail(base64).then((thumb) => {
456
+ if (thumb) setAttachmentThumbnail(attachmentId, thumb);
457
+ }),
458
+ 'video thumbnail generation',
459
+ );
409
460
  }
410
461
 
411
462
  return {
@@ -541,6 +592,22 @@ export function handleDeleteQueuedMessage(
541
592
  }
542
593
  }
543
594
 
595
+ export function handleConversationSearch(
596
+ msg: ConversationSearchRequest,
597
+ socket: net.Socket,
598
+ ctx: HandlerContext,
599
+ ): void {
600
+ const results = conversationStore.searchConversations(msg.query, {
601
+ limit: msg.limit,
602
+ maxMessagesPerConversation: msg.maxMessagesPerConversation,
603
+ });
604
+ ctx.send(socket, {
605
+ type: 'conversation_search_response',
606
+ query: msg.query,
607
+ results,
608
+ });
609
+ }
610
+
544
611
  export const sessionHandlers = defineHandlers({
545
612
  user_message: handleUserMessage,
546
613
  confirmation_response: handleConfirmationResponse,
@@ -549,6 +616,7 @@ export const sessionHandlers = defineHandlers({
549
616
  session_create: handleSessionCreate,
550
617
  sessions_clear: (_msg, socket, ctx) => handleSessionsClear(socket, ctx),
551
618
  session_switch: handleSessionSwitch,
619
+ session_rename: handleSessionRename,
552
620
  cancel: handleCancel,
553
621
  delete_queued_message: handleDeleteQueuedMessage,
554
622
  history_request: handleHistoryRequest,
@@ -556,4 +624,5 @@ export const sessionHandlers = defineHandlers({
556
624
  regenerate: handleRegenerate,
557
625
  usage_request: handleUsageRequest,
558
626
  sandbox_set: handleSandboxSet,
627
+ conversation_search: handleConversationSearch,
559
628
  });
@@ -105,6 +105,8 @@ export interface SessionCreateOptions {
105
105
  memoryScopeId?: string;
106
106
  isPrivateThread?: boolean;
107
107
  strictPrivateSideEffects?: boolean;
108
+ /** Channel command intent metadata (e.g. Telegram /start). */
109
+ commandIntent?: { type: string; payload?: string; languageCode?: string };
108
110
  }
109
111
 
110
112
  /**
@@ -252,7 +254,7 @@ export function wireEscalationHandler(
252
254
  }
253
255
 
254
256
  export function isRecord(value: unknown): value is Record<string, unknown> {
255
- return typeof value === 'object' && value !== null;
257
+ return typeof value === 'object' && value != null;
256
258
  }
257
259
 
258
260
  export function formatBytes(sizeBytes: number): string {
@@ -423,7 +423,7 @@ export async function handleSkillsSearch(
423
423
  ctx: HandlerContext,
424
424
  ): Promise<void> {
425
425
  try {
426
- // Search vellum-skills catalog (remote with bundled fallback)
426
+ // Search vellum-skills catalog (platform API with bundled fallback)
427
427
  const catalogEntries = await listCatalogEntries();
428
428
  const query = (msg.query ?? '').toLowerCase();
429
429
  const matchingCatalog = catalogEntries.filter((e) => {
@@ -72,6 +72,7 @@ export async function handleTwitterAuthStart(
72
72
  clientId,
73
73
  clientSecret,
74
74
  extraParams: {},
75
+ tokenEndpointAuthMethod: clientSecret ? 'client_secret_basic' : undefined,
75
76
  };
76
77
 
77
78
  const result = await startOAuth2Flow(oauthConfig, {
@@ -131,6 +132,7 @@ export async function handleTwitterAuthStart(
131
132
  oauth2TokenUrl: 'https://api.x.com/2/oauth2/token',
132
133
  oauth2ClientId: clientId,
133
134
  oauth2ClientSecret: clientSecret ?? null,
135
+ oauth2TokenEndpointAuthMethod: clientSecret ? 'client_secret_basic' : undefined,
134
136
  grantedScopes: result.grantedScopes,
135
137
  expiresAt: result.tokens.expiresIn ? Date.now() + result.tokens.expiresIn * 1000 : null,
136
138
  });
@@ -393,7 +393,7 @@ export async function handleWorkItemRunTask(
393
393
  // Compute required tools using the same resolution logic as preflight:
394
394
  // work-item snapshot first, then task template, then all registered tools.
395
395
  let requiredTools: string[];
396
- if (workItem.requiredTools !== null && workItem.requiredTools !== undefined) {
396
+ if (workItem.requiredTools != null) {
397
397
  requiredTools = sanitizeToolList(JSON.parse(workItem.requiredTools));
398
398
  } else {
399
399
  requiredTools = task.requiredTools
@@ -513,7 +513,7 @@ export async function handleWorkItemPreflight(
513
513
  // back to the task template (or all registered tools) when the
514
514
  // snapshot is null.
515
515
  let requiredTools: string[];
516
- if (workItem.requiredTools !== null && workItem.requiredTools !== undefined) {
516
+ if (workItem.requiredTools != null) {
517
517
  requiredTools = sanitizeToolList(JSON.parse(workItem.requiredTools));
518
518
  } else {
519
519
  const task = getTask(workItem.taskId);
@@ -1,6 +1,7 @@
1
1
  import * as net from 'node:net';
2
- import { existsSync, readFileSync } from 'node:fs';
2
+ import { readFileSync } from 'node:fs';
3
3
  import { join, resolve, sep } from 'node:path';
4
+ import { pathExists } from '../../util/fs.js';
4
5
  import { getWorkspaceDir } from '../../util/platform.js';
5
6
  import { log, defineHandlers, type HandlerContext } from './shared.js';
6
7
  import type { WorkspaceFileReadRequest } from '../ipc-protocol.js';
@@ -13,7 +14,7 @@ function handleWorkspaceFilesList(socket: net.Socket, ctx: HandlerContext): void
13
14
  const files = WORKSPACE_FILES.map((name) => ({
14
15
  path: name,
15
16
  name,
16
- exists: existsSync(join(base, name)),
17
+ exists: pathExists(join(base, name)),
17
18
  }));
18
19
  ctx.send(socket, { type: 'workspace_files_list_response', files });
19
20
  }
@@ -42,7 +43,7 @@ function handleWorkspaceFileRead(
42
43
  }
43
44
 
44
45
  try {
45
- if (!existsSync(resolved)) {
46
+ if (!pathExists(resolved)) {
46
47
  ctx.send(socket, {
47
48
  type: 'workspace_file_read_response',
48
49
  path: requested,
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Installs standalone CLI launcher scripts in ~/.vellum/bin/ so that
3
+ * integration commands (e.g. `doordash`, `map`) can be invoked directly
4
+ * without requiring `vellum` on PATH.
5
+ *
6
+ * Each launcher is a shell script that hardcodes absolute paths to `bun`
7
+ * and the CLI entrypoint, forwarding all arguments to the appropriate
8
+ * subcommand.
9
+ */
10
+
11
+ import { execSync } from 'node:child_process';
12
+ import { existsSync, mkdirSync, writeFileSync, chmodSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+ import { homedir } from 'node:os';
15
+ import { getLogger } from '../util/logger.js';
16
+
17
+ const log = getLogger('install-cli-launchers');
18
+
19
+ /** Integration subcommands that should get standalone launchers. */
20
+ const INTEGRATION_COMMANDS = ['doordash', 'map'];
21
+
22
+ /**
23
+ * Resolve the absolute path to the bun binary.
24
+ * Prefers process.execPath (works when running under bun), then falls
25
+ * back to `which bun`.
26
+ */
27
+ function resolveBunPath(): string {
28
+ // process.execPath points to the bun binary when running under bun
29
+ if (process.execPath && process.execPath.includes('bun')) {
30
+ return process.execPath;
31
+ }
32
+ try {
33
+ return execSync('which bun', { encoding: 'utf-8' }).trim();
34
+ } catch {
35
+ throw new Error('Could not find bun binary');
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Resolve the absolute path to the CLI entrypoint (index.ts).
41
+ * Uses import.meta.dirname to find the source tree root.
42
+ */
43
+ function resolveCliEntrypoint(): string {
44
+ // This file is at assistant/src/daemon/install-cli-launchers.ts
45
+ // The CLI entrypoint is at assistant/src/index.ts
46
+ const thisDir = import.meta.dirname ?? __dirname;
47
+ return join(thisDir, '..', 'index.ts');
48
+ }
49
+
50
+ /**
51
+ * Check whether a given command name conflicts with an existing system
52
+ * binary (i.e. something other than our own launcher).
53
+ */
54
+ function hasSystemConflict(name: string, binDir: string): boolean {
55
+ try {
56
+ const result = execSync(`which ${name}`, { encoding: 'utf-8' }).trim();
57
+ // If `which` resolves to our own bin dir, that's not a conflict
58
+ if (result.startsWith(binDir)) return false;
59
+ return true;
60
+ } catch {
61
+ // `which` failed — no conflict
62
+ return false;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Install standalone CLI launcher scripts in ~/.vellum/bin/.
68
+ *
69
+ * For each integration command, generates a shell script that execs
70
+ * bun with the CLI entrypoint and the subcommand name prepended.
71
+ * Uses the short name by default (e.g. `doordash`), falling back to
72
+ * `vellum-<name>` if the short name conflicts with an existing system binary.
73
+ */
74
+ export function installCliLaunchers(): void {
75
+ const binDir = join(homedir(), '.vellum', 'bin');
76
+
77
+ let bunPath: string;
78
+ try {
79
+ bunPath = resolveBunPath();
80
+ } catch (err) {
81
+ log.warn({ err }, 'Cannot install CLI launchers: bun not found');
82
+ return;
83
+ }
84
+
85
+ const entrypoint = resolveCliEntrypoint();
86
+ if (!existsSync(entrypoint)) {
87
+ // In compiled builds (e.g. macOS app via `bun build --compile`), the
88
+ // source tree isn't available. Launcher scripts are a dev-mode
89
+ // convenience; compiled builds use their own command dispatch, so we
90
+ // silently skip installation.
91
+ log.debug({ entrypoint }, 'CLI entrypoint not found (compiled build?) — skipping launcher installation');
92
+ return;
93
+ }
94
+
95
+ if (!existsSync(binDir)) {
96
+ mkdirSync(binDir, { recursive: true });
97
+ }
98
+
99
+ for (const name of INTEGRATION_COMMANDS) {
100
+ const launcherName = hasSystemConflict(name, binDir) ? `vellum-${name}` : name;
101
+ const launcherPath = join(binDir, launcherName);
102
+
103
+ const script = `#!/bin/bash
104
+ exec "${bunPath}" "${entrypoint}" ${name} "$@"
105
+ `;
106
+
107
+ writeFileSync(launcherPath, script);
108
+ chmodSync(launcherPath, 0o755);
109
+ log.debug({ launcherName, launcherPath }, 'Installed CLI launcher');
110
+ }
111
+
112
+ log.info({ binDir, commands: INTEGRATION_COMMANDS }, 'CLI launchers installed');
113
+ }