@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
@@ -36,6 +36,28 @@ export interface ParsedCommand {
36
36
  }
37
37
 
38
38
  const SHELL_PROGRAMS = new Set(['sh', 'bash', 'zsh', 'dash', 'ksh', 'fish']);
39
+ // Script interpreters that can execute arbitrary code from stdin — piping
40
+ // untrusted data into these is as dangerous as piping into a shell.
41
+ const SCRIPT_INTERPRETERS = new Set([
42
+ 'python', 'python3', 'ruby', 'perl', 'node', 'deno', 'bun',
43
+ ]);
44
+ // Flags that make an interpreter execute code from an inline argument or stdin
45
+ // rather than from a file (e.g. `python -c 'code'`, `node -e 'code'`).
46
+ const STDIN_EXEC_FLAGS = new Set(['-c', '-e', '-']);
47
+ // Per-interpreter flags that consume the next argument as a value (not a filename).
48
+ // Mapped by interpreter name since flags differ across interpreters
49
+ // (e.g. -I is standalone in Python but takes a value in Ruby).
50
+ // Note: `-m` is intentionally excluded — it means "run module", so the next arg
51
+ // is a module name and the interpreter is NOT in stdin-exec mode.
52
+ const INTERPRETER_VALUE_FLAGS: ReadonlyMap<string, ReadonlySet<string>> = new Map([
53
+ ['python', new Set(['-W', '-X', '-Q'])],
54
+ ['python3', new Set(['-W', '-X', '-Q'])],
55
+ ['ruby', new Set(['-r', '--require', '-I'])],
56
+ ['node', new Set(['-r', '--require', '--import', '--conditions'])],
57
+ ['deno', new Set()],
58
+ ['bun', new Set()],
59
+ ['perl', new Set(['-I'])],
60
+ ]);
39
61
  const OPAQUE_PROGRAMS = new Set(['eval', 'source', 'alias']);
40
62
  const DANGEROUS_ENV_VARS = new Set([
41
63
  'LD_PRELOAD', 'LD_LIBRARY_PATH',
@@ -239,6 +261,28 @@ function extractSegments(node: TSNode): CommandSegment[] {
239
261
  return segments;
240
262
  }
241
263
 
264
+ /**
265
+ * Returns true when the interpreter args indicate stdin-exec mode — i.e. the
266
+ * interpreter will read code from stdin (or from an inline -c/-e argument)
267
+ * rather than from a file. Concretely:
268
+ * - Any STDIN_EXEC_FLAGS present → stdin-exec
269
+ * - No positional (non-flag) arguments at all → stdin-exec (bare `python`)
270
+ * - Otherwise the first positional arg is a filename → NOT stdin-exec
271
+ */
272
+ function isStdinExecMode(interpreter: string, args: string[]): boolean {
273
+ const valueFlags = INTERPRETER_VALUE_FLAGS.get(interpreter) ?? new Set<string>();
274
+ for (let i = 0; i < args.length; i++) {
275
+ const arg = args[i];
276
+ if (STDIN_EXEC_FLAGS.has(arg)) return true;
277
+ // First non-flag argument is a filename/module → file mode
278
+ if (!arg.startsWith('-')) return false;
279
+ // Flags like -W, -X consume the next token as their value — skip it
280
+ if (valueFlags.has(arg)) i++;
281
+ }
282
+ // No positional arguments at all → interpreter reads from stdin
283
+ return true;
284
+ }
285
+
242
286
  function detectDangerousPatterns(node: TSNode, segments: CommandSegment[]): DangerousPattern[] {
243
287
  const patterns: DangerousPattern[] = [];
244
288
 
@@ -251,6 +295,12 @@ function detectDangerousPatterns(node: TSNode, segments: CommandSegment[]): Dang
251
295
  description: `Pipeline into ${prog}`,
252
296
  text: segments[i].command,
253
297
  });
298
+ } else if (SCRIPT_INTERPRETERS.has(prog) && isStdinExecMode(prog, segments[i].args)) {
299
+ patterns.push({
300
+ type: 'pipe_to_shell',
301
+ description: `Pipeline into ${prog}`,
302
+ text: segments[i].command,
303
+ });
254
304
  }
255
305
  }
256
306
  }
@@ -1,5 +1,6 @@
1
1
  import type { ToolContext, ToolExecutionResult } from '../types.js';
2
2
  import { getWatcher, deleteWatcher } from '../../watcher/watcher-store.js';
3
+ import { getWatcherProvider } from '../../watcher/provider-registry.js';
3
4
 
4
5
  export async function executeWatcherDelete(
5
6
  input: Record<string, unknown>,
@@ -20,6 +21,11 @@ export async function executeWatcherDelete(
20
21
  return { content: `Error: Failed to delete watcher: ${watcherId}`, isError: true };
21
22
  }
22
23
 
24
+ // Evict any in-process provider state (e.g. Linear issue-state cache) now
25
+ // that the watcher's DB row is gone, so its UUID doesn't leak memory.
26
+ const provider = getWatcherProvider(watcher.providerId);
27
+ provider?.cleanup?.(watcherId);
28
+
23
29
  return {
24
30
  content: `Watcher deleted: "${watcher.name}"`,
25
31
  isError: false,
@@ -219,7 +219,7 @@ function buildWeatherPageHtml(d: WeatherPageInput): string {
219
219
  const widthPctC = Math.max(((hc - lc) / cRange) * 100, 3);
220
220
  const leftPct = isF ? leftPctF : leftPctC;
221
221
  const widthPct = isF ? widthPctF : widthPctC;
222
- const precipCell = f.precip !== null && f.precip > 0
222
+ const precipCell = f.precip != null && f.precip > 0
223
223
  ? `<span style="font-size:12px;color:var(--v-accent);width:36px;text-align:right">${f.precip}%</span>`
224
224
  : `<span style="width:36px"></span>`;
225
225
  return `<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--v-surface-border)">` +
@@ -8,6 +8,7 @@ import {
8
8
  loadSession,
9
9
  type TwitterSession,
10
10
  } from './session.js';
11
+ import { ProviderError } from '../util/errors.js';
11
12
 
12
13
  const CDP_BASE = 'http://localhost:9222';
13
14
 
@@ -325,17 +326,182 @@ async function graphqlGet(queryId: string, queryName: string, variables: Record<
325
326
  const url = graphqlUrl(queryId, queryName, variables);
326
327
  const json = await cdpGet(wsUrl, url) as { errors?: Array<{ message: string }> };
327
328
  if (json.errors?.length) {
328
- throw new Error(`X API errors: ${json.errors.map(e => e.message).join('; ')}`);
329
+ throw new ProviderError(`X API errors: ${json.errors.map(e => e.message).join('; ')}`, 'x');
329
330
  }
330
331
  return json;
331
332
  }
332
333
 
333
- // ─── Tweet extraction helpers ────────────────────────────────────────────────
334
+ // ─── Twitter API response types ──────────────────────────────────────────────
335
+
336
+ interface TwitterUserLegacy {
337
+ screen_name?: string;
338
+ name?: string;
339
+ }
340
+
341
+ interface TwitterUserCore {
342
+ screen_name?: string;
343
+ name?: string;
344
+ }
345
+
346
+ interface TwitterUserResult {
347
+ rest_id?: string;
348
+ legacy?: TwitterUserLegacy;
349
+ core?: TwitterUserCore;
350
+ }
351
+
352
+ interface TwitterUserResults {
353
+ result?: TwitterUserResult;
354
+ }
355
+
356
+ interface TweetLegacy {
357
+ full_text?: string;
358
+ created_at?: string;
359
+ }
360
+
361
+ interface TweetResult {
362
+ __typename?: string;
363
+ rest_id?: string;
364
+ legacy?: TweetLegacy;
365
+ core?: { user_results?: TwitterUserResults };
366
+ tweet?: TweetResult;
367
+ }
368
+
369
+ interface TweetResults {
370
+ result?: TweetResult;
371
+ }
372
+
373
+ interface TimelineItemContent {
374
+ __typename?: string;
375
+ tweet_results?: TweetResults;
376
+ user_results?: TwitterUserResults;
377
+ // Notification-specific fields
378
+ id?: string;
379
+ rich_message?: { text?: string };
380
+ notification_text?: { text?: string };
381
+ timestamp_ms?: string;
382
+ notification_url?: { url?: string };
383
+ }
334
384
 
335
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
336
- type AnyJson = any;
385
+ interface TimelineModuleItem {
386
+ item?: { itemContent?: TimelineItemContent };
387
+ }
388
+
389
+ interface TimelineEntryContent {
390
+ itemContent?: TimelineItemContent;
391
+ items?: TimelineModuleItem[];
392
+ }
393
+
394
+ interface TimelineEntry {
395
+ entryId?: string;
396
+ content?: TimelineEntryContent;
397
+ }
398
+
399
+ interface TimelineInstruction {
400
+ entries?: TimelineEntry[];
401
+ }
402
+
403
+ interface TimelineContainer {
404
+ instructions?: TimelineInstruction[];
405
+ }
406
+
407
+ interface TimelineWrapper {
408
+ timeline?: TimelineContainer;
409
+ }
410
+
411
+ interface TwitterApiError {
412
+ message: string;
413
+ }
414
+
415
+ /** Response from CreateTweet mutation. */
416
+ interface CreateTweetResponse {
417
+ errors?: TwitterApiError[];
418
+ data?: {
419
+ create_tweet?: {
420
+ tweet_results?: TweetResults;
421
+ };
422
+ };
423
+ }
424
+
425
+ /** Response from UserByScreenName query. */
426
+ interface UserByScreenNameResponse {
427
+ data?: {
428
+ user?: {
429
+ result?: TwitterUserResult;
430
+ };
431
+ };
432
+ }
433
+
434
+ /** Response from UserTweets query. */
435
+ interface UserTweetsResponse {
436
+ data?: {
437
+ user?: {
438
+ result?: {
439
+ timeline_v2?: TimelineWrapper;
440
+ timeline?: TimelineWrapper;
441
+ };
442
+ };
443
+ };
444
+ }
445
+
446
+ /** Response from TweetDetail query. */
447
+ interface TweetDetailResponse {
448
+ data?: {
449
+ threaded_conversation_with_injections_v2?: TimelineContainer;
450
+ };
451
+ }
452
+
453
+ /** Response from SearchTimeline query. */
454
+ interface SearchTimelineResponse {
455
+ data?: {
456
+ search_by_raw_query?: {
457
+ search_timeline?: TimelineWrapper;
458
+ };
459
+ };
460
+ }
461
+
462
+ /** Response from Bookmarks query. */
463
+ interface BookmarksResponse {
464
+ data?: {
465
+ bookmark_timeline_v2?: TimelineWrapper;
466
+ };
467
+ }
468
+
469
+ /** Response from HomeTimeline query. */
470
+ interface HomeTimelineResponse {
471
+ data?: {
472
+ home?: {
473
+ home_timeline_urt?: TimelineContainer;
474
+ };
475
+ };
476
+ }
477
+
478
+ /** Response from NotificationsTimeline query. */
479
+ interface NotificationsTimelineResponse {
480
+ data?: {
481
+ viewer_v2?: {
482
+ user_results?: {
483
+ result?: {
484
+ notification_timeline?: TimelineWrapper;
485
+ };
486
+ };
487
+ };
488
+ };
489
+ }
490
+
491
+ /** Response from Likes / Following / Followers / UserMedia queries. */
492
+ interface UserTimelineResponse {
493
+ data?: {
494
+ user?: {
495
+ result?: {
496
+ timeline?: TimelineWrapper;
497
+ };
498
+ };
499
+ };
500
+ }
501
+
502
+ // ─── Tweet extraction helpers ────────────────────────────────────────────────
337
503
 
338
- function extractScreenName(tweetResult: AnyJson): string {
504
+ function extractScreenName(tweetResult: TweetResult): string {
339
505
  return (
340
506
  tweetResult?.core?.user_results?.result?.legacy?.screen_name ??
341
507
  tweetResult?.core?.user_results?.result?.core?.screen_name ??
@@ -344,7 +510,7 @@ function extractScreenName(tweetResult: AnyJson): string {
344
510
  }
345
511
 
346
512
  /** Extract tweets from a timeline instructions array (shared by most endpoints). */
347
- function extractTweetsFromInstructions(instructions: AnyJson[]): TweetEntry[] {
513
+ function extractTweetsFromInstructions(instructions: TimelineInstruction[]): TweetEntry[] {
348
514
  const tweets: TweetEntry[] = [];
349
515
  for (const instruction of instructions) {
350
516
  // Handle both array-style entries and direct entries
@@ -386,7 +552,7 @@ function extractTweetsFromInstructions(instructions: AnyJson[]): TweetEntry[] {
386
552
  }
387
553
 
388
554
  /** Extract users from a timeline instructions array (Followers/Following). */
389
- function extractUsersFromInstructions(instructions: AnyJson[]): UserInfo[] {
555
+ function extractUsersFromInstructions(instructions: TimelineInstruction[]): UserInfo[] {
390
556
  const users: UserInfo[] = [];
391
557
  for (const instruction of instructions) {
392
558
  for (const entry of instruction.entries ?? []) {
@@ -460,19 +626,19 @@ export async function postTweet(text: string, opts?: { inReplyToTweetId?: string
460
626
  queryId: QUERY_IDS.CreateTweet,
461
627
  });
462
628
 
463
- const json = (await cdpFetch(wsUrl, url, body)) as AnyJson;
629
+ const json = (await cdpFetch(wsUrl, url, body)) as CreateTweetResponse;
464
630
 
465
631
  if (json.errors?.length) {
466
- throw new Error(`X API errors: ${json.errors.map((e: AnyJson) => e.message).join('; ')}`);
632
+ throw new ProviderError(`X API errors: ${json.errors.map(e => e.message).join('; ')}`, 'x');
467
633
  }
468
634
 
469
635
  const tweetResults = json.data?.create_tweet?.tweet_results;
470
636
  const result = tweetResults?.result;
471
637
  if (!result?.rest_id) {
472
638
  if (tweetResults && !result) {
473
- throw new Error('X rejected this post — it may be a duplicate of a recent post. Try different text.');
639
+ throw new ProviderError('X rejected this post — it may be a duplicate of a recent post. Try different text.', 'x');
474
640
  }
475
- throw new Error(`Unexpected response from X API. Response: ${JSON.stringify(json).slice(0, 500)}`);
641
+ throw new ProviderError(`Unexpected response from X API. Response: ${JSON.stringify(json).slice(0, 500)}`, 'x');
476
642
  }
477
643
 
478
644
  return {
@@ -488,11 +654,11 @@ export async function getUserByScreenName(screenName: string): Promise<UserInfo>
488
654
  const json = await graphqlGet(QUERY_IDS.UserByScreenName, 'UserByScreenName', {
489
655
  screen_name: screenName,
490
656
  withGrokTranslatedBio: true,
491
- }) as AnyJson;
657
+ }) as UserByScreenNameResponse;
492
658
 
493
659
  const user = json.data?.user?.result;
494
660
  if (!user?.rest_id) {
495
- throw new Error(`User @${screenName} not found`);
661
+ throw new ProviderError(`User @${screenName} not found`, 'x');
496
662
  }
497
663
 
498
664
  return {
@@ -511,7 +677,7 @@ export async function getUserTweets(userId: string, count = 20): Promise<TweetEn
511
677
  includePromotedContent: true,
512
678
  withQuickPromoteEligibilityTweetFields: true,
513
679
  withVoice: true,
514
- }) as AnyJson;
680
+ }) as UserTweetsResponse;
515
681
 
516
682
  // Response path: data.user.result.timeline_v2.timeline.instructions[]
517
683
  // Fallback to data.user.result.timeline.timeline.instructions[]
@@ -533,7 +699,7 @@ export async function getTweetDetail(tweetId: string): Promise<TweetEntry[]> {
533
699
  withQuickPromoteEligibilityTweetFields: true,
534
700
  withBirdwatchNotes: true,
535
701
  withVoice: true,
536
- }) as AnyJson;
702
+ }) as TweetDetailResponse;
537
703
 
538
704
  // Response path: data.threaded_conversation_with_injections_v2.instructions[]
539
705
  const instructions = json.data?.threaded_conversation_with_injections_v2?.instructions ?? [];
@@ -553,7 +719,7 @@ export async function searchTweets(
553
719
  // to the search page and capture the response from network events.
554
720
  const productParam = product === 'Top' ? '' : `&f=${product.toLowerCase()}`;
555
721
  const pageUrl = `https://x.com/search?q=${encodeURIComponent(query)}&src=typed_query${productParam}`;
556
- const json = await cdpNavigateAndCapture(wsUrl, pageUrl, 'SearchTimeline') as AnyJson;
722
+ const json = await cdpNavigateAndCapture(wsUrl, pageUrl, 'SearchTimeline') as SearchTimelineResponse;
557
723
 
558
724
  const instructions = json.data?.search_by_raw_query?.search_timeline?.timeline?.instructions ?? [];
559
725
  return extractTweetsFromInstructions(instructions);
@@ -565,7 +731,7 @@ export async function getBookmarks(count = 20): Promise<TweetEntry[]> {
565
731
  const json = await graphqlGet(QUERY_IDS.Bookmarks, 'Bookmarks', {
566
732
  count,
567
733
  includePromotedContent: true,
568
- }) as AnyJson;
734
+ }) as BookmarksResponse;
569
735
 
570
736
  // Response path: data.bookmark_timeline_v2.timeline.instructions[]
571
737
  const instructions = json.data?.bookmark_timeline_v2?.timeline?.instructions ?? [];
@@ -580,7 +746,7 @@ export async function getHomeTimeline(count = 20): Promise<TweetEntry[]> {
580
746
  includePromotedContent: true,
581
747
  requestContext: 'launch',
582
748
  withCommunity: true,
583
- }) as AnyJson;
749
+ }) as HomeTimelineResponse;
584
750
 
585
751
  // Response path: data.home.home_timeline_urt.instructions[]
586
752
  const instructions = json.data?.home?.home_timeline_urt?.instructions ?? [];
@@ -593,7 +759,7 @@ export async function getNotifications(count = 20): Promise<NotificationEntry[]>
593
759
  const json = await graphqlGet(QUERY_IDS.NotificationsTimeline, 'NotificationsTimeline', {
594
760
  timeline_type: 'All',
595
761
  count,
596
- }) as AnyJson;
762
+ }) as NotificationsTimelineResponse;
597
763
 
598
764
  // Response path: data.viewer_v2.user_results.result.notification_timeline.timeline.instructions[]
599
765
  const instructions =
@@ -625,7 +791,7 @@ export async function getLikes(userId: string, count = 20): Promise<TweetEntry[]
625
791
  withClientEventToken: false,
626
792
  withBirdwatchNotes: false,
627
793
  withVoice: true,
628
- }) as AnyJson;
794
+ }) as UserTimelineResponse;
629
795
 
630
796
  // Response path: data.user.result.timeline.timeline.instructions[]
631
797
  const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
@@ -640,7 +806,7 @@ export async function getFollowers(userId: string, screenName?: string): Promise
640
806
  if (screenName) {
641
807
  requireSession();
642
808
  const wsUrl = await findTwitterTab();
643
- const json = await cdpNavigateAndCapture(wsUrl, `https://x.com/${screenName}/followers`, 'Followers') as AnyJson;
809
+ const json = await cdpNavigateAndCapture(wsUrl, `https://x.com/${screenName}/followers`, 'Followers') as UserTimelineResponse;
644
810
  const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
645
811
  return extractUsersFromInstructions(instructions);
646
812
  }
@@ -650,7 +816,7 @@ export async function getFollowers(userId: string, screenName?: string): Promise
650
816
  count: 20,
651
817
  includePromotedContent: false,
652
818
  withGrokTranslatedBio: false,
653
- }) as AnyJson;
819
+ }) as UserTimelineResponse;
654
820
 
655
821
  const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
656
822
  return extractUsersFromInstructions(instructions);
@@ -664,7 +830,7 @@ export async function getFollowing(userId: string, count = 20): Promise<UserInfo
664
830
  count,
665
831
  includePromotedContent: false,
666
832
  withGrokTranslatedBio: false,
667
- }) as AnyJson;
833
+ }) as UserTimelineResponse;
668
834
 
669
835
  // Response path: data.user.result.timeline.timeline.instructions[]
670
836
  const instructions = json.data?.user?.result?.timeline?.timeline?.instructions ?? [];
@@ -681,7 +847,7 @@ export async function getUserMedia(userId: string, count = 20): Promise<TweetEnt
681
847
  withClientEventToken: false,
682
848
  withBirdwatchNotes: false,
683
849
  withVoice: true,
684
- }) as AnyJson;
850
+ }) as UserTimelineResponse;
685
851
 
686
852
  // Response path: data.user.result.timeline.timeline.instructions[]
687
853
  // (same as Likes — contains tweets that have media)
@@ -6,6 +6,7 @@
6
6
  import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
8
  import { getDataDir } from '../util/platform.js';
9
+ import { ConfigError } from '../util/errors.js';
9
10
  import type { SessionRecording, ExtractedCredential } from '../tools/browser/network-recording-types.js';
10
11
 
11
12
  export interface TwitterSession {
@@ -50,17 +51,17 @@ export function clearSession(): void {
50
51
  */
51
52
  export function importFromRecording(recordingPath: string): TwitterSession {
52
53
  if (!existsSync(recordingPath)) {
53
- throw new Error(`Recording not found: ${recordingPath}`);
54
+ throw new ConfigError(`Recording not found: ${recordingPath}`);
54
55
  }
55
56
  const recording = JSON.parse(readFileSync(recordingPath, 'utf-8')) as SessionRecording;
56
57
  if (!recording.cookies?.length) {
57
- throw new Error('Recording contains no cookies');
58
+ throw new ConfigError('Recording contains no cookies');
58
59
  }
59
60
  // Require the two cookies that prove a logged-in Twitter session:
60
61
  // the auth session cookie and the ct0 CSRF cookie.
61
62
  const cookieNames = new Set(recording.cookies.map(c => c.name));
62
63
  if (!cookieNames.has('ct0') || !cookieNames.has(`auth_${'token'}`)) {
63
- throw new Error(
64
+ throw new ConfigError(
64
65
  'Recording is missing required Twitter session cookies. ' +
65
66
  'Make sure you are logged in to x.com before recording.',
66
67
  );
@@ -25,7 +25,7 @@ export function extractLastCodeBlock(text: string): string | null {
25
25
  const re = /```[^\n]*\n((?:[\s\S]*?\n)?)```/g;
26
26
  let last: RegExpExecArray | null = null;
27
27
  let m: RegExpExecArray | null;
28
- while ((m = re.exec(text)) !== null) {
28
+ while ((m = re.exec(text)) != null) {
29
29
  last = m;
30
30
  }
31
31
  if (!last) return null;
@@ -33,7 +33,71 @@ export enum ErrorCode {
33
33
  INTERNAL_ERROR = 'INTERNAL_ERROR',
34
34
  }
35
35
 
36
- export class AssistantError extends Error {
36
+ // ── Root ──────────────────────────────────────────────────────────────────────
37
+
38
+ /** Root base class for all named Vellum errors. */
39
+ export class VellumError extends Error {
40
+ constructor(message: string, options?: ErrorOptions) {
41
+ super(message, options);
42
+ this.name = 'VellumError';
43
+ }
44
+ }
45
+
46
+ // ── Backend errors ────────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Errors originating from infrastructure or external service calls.
50
+ * Catch this when you want to handle any backend failure uniformly.
51
+ */
52
+ export class BackendError extends VellumError {
53
+ constructor(message: string, options?: ErrorOptions) {
54
+ super(message, options);
55
+ this.name = 'BackendError';
56
+ }
57
+ }
58
+
59
+ /**
60
+ * The embedding or vector-search backend is not configured or not reachable.
61
+ * Thrown before attempting an embedding operation so callers can skip or defer.
62
+ */
63
+ export class BackendUnavailableError extends BackendError {
64
+ constructor(reason: string) {
65
+ super(reason);
66
+ this.name = 'BackendUnavailableError';
67
+ }
68
+ }
69
+
70
+ /**
71
+ * A request or token-budget quota was exceeded.
72
+ * Thrown by the provider rate-limiter and by domain-specific clients (e.g. DoorDash).
73
+ */
74
+ export class RateLimitError extends BackendError {
75
+ constructor(message: string) {
76
+ super(message);
77
+ this.name = 'RateLimitError';
78
+ }
79
+ }
80
+
81
+ // ── User errors ───────────────────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Errors caused by user input, policy violations, or user-facing constraints.
85
+ * Catch this when you want to present an actionable message to the user.
86
+ */
87
+ export class UserError extends VellumError {
88
+ constructor(message: string, options?: ErrorOptions) {
89
+ super(message, options);
90
+ this.name = 'UserError';
91
+ }
92
+ }
93
+
94
+ // ── AssistantError subtree ────────────────────────────────────────────────────
95
+
96
+ /**
97
+ * Base class for errors originating from assistant logic (providers, tools,
98
+ * permissions, config). Extends VellumError and carries a structured ErrorCode.
99
+ */
100
+ export class AssistantError extends VellumError {
37
101
  constructor(
38
102
  message: string,
39
103
  public readonly code: ErrorCode,
@@ -111,13 +175,6 @@ export class IntegrityError extends AssistantError {
111
175
  }
112
176
  }
113
177
 
114
- export class RateLimitError extends AssistantError {
115
- constructor(message: string) {
116
- super(message, ErrorCode.RATE_LIMIT_ERROR);
117
- this.name = 'RateLimitError';
118
- }
119
- }
120
-
121
178
  export class IngressBlockedError extends AssistantError {
122
179
  constructor(
123
180
  message: string,
package/src/util/fs.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Centralized filesystem helpers — single source of truth for common
3
+ * existence-check and stat patterns scattered across the codebase.
4
+ *
5
+ * Modules should import from here instead of using raw existsSync/statSync
6
+ * from 'node:fs' for these patterns.
7
+ */
8
+
9
+ import { existsSync, mkdirSync, readFileSync, statSync, type Stats } from 'node:fs';
10
+
11
+ /** Check whether a path (file or directory) exists on disk. */
12
+ export function pathExists(path: string): boolean {
13
+ return existsSync(path);
14
+ }
15
+
16
+ /** Create a directory (and parents) if it doesn't already exist. */
17
+ export function ensureDir(dir: string): void {
18
+ if (!existsSync(dir)) {
19
+ mkdirSync(dir, { recursive: true });
20
+ }
21
+ }
22
+
23
+ /** Read a UTF-8 text file, returning null if it doesn't exist or is unreadable. */
24
+ export function readTextFileSync(path: string): string | null {
25
+ try {
26
+ if (!existsSync(path)) return null;
27
+ return readFileSync(path, 'utf-8');
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ /** Get file stats, returning null if the path doesn't exist or is inaccessible. */
34
+ export function safeStatSync(path: string): Stats | null {
35
+ try {
36
+ return statSync(path);
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Parse JSON without throwing — returns null on failure.
3
+ */
4
+ export function parseJsonSafe<T = unknown>(text: string): T | null {
5
+ try {
6
+ return JSON.parse(text) as T;
7
+ } catch {
8
+ return null;
9
+ }
10
+ }