@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
@@ -0,0 +1,254 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { mkdirSync, readFileSync, writeFileSync, unlinkSync, existsSync, openSync, closeSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
4
+ import {
5
+ getSocketPath,
6
+ getPidPath,
7
+ getRootDir,
8
+ getWorkspaceConfigPath,
9
+ removeSocketFile,
10
+ } from '../util/platform.js';
11
+ import { getLogger } from '../util/logger.js';
12
+ import { DaemonError } from '../util/errors.js';
13
+
14
+ const log = getLogger('lifecycle');
15
+
16
+ const DAEMON_TIMEOUT_DEFAULTS = {
17
+ startupSocketWaitMs: 5000,
18
+ stopTimeoutMs: 5000,
19
+ sigkillGracePeriodMs: 2000,
20
+ };
21
+
22
+ /**
23
+ * Read daemon timeout values directly from the config JSON file, bypassing
24
+ * loadConfig() and its ensureMigratedDataDir()/ensureDataDir() side effects.
25
+ * Falls back to hardcoded defaults on any error (missing file, malformed JSON,
26
+ * unexpected shape) so daemon stop/start never fails due to config issues.
27
+ */
28
+ function readDaemonTimeouts(): typeof DAEMON_TIMEOUT_DEFAULTS {
29
+ try {
30
+ const raw = JSON.parse(readFileSync(getWorkspaceConfigPath(), 'utf-8'));
31
+ if (raw.daemon && typeof raw.daemon === 'object') {
32
+ return {
33
+ startupSocketWaitMs:
34
+ typeof raw.daemon.startupSocketWaitMs === 'number'
35
+ ? raw.daemon.startupSocketWaitMs
36
+ : DAEMON_TIMEOUT_DEFAULTS.startupSocketWaitMs,
37
+ stopTimeoutMs:
38
+ typeof raw.daemon.stopTimeoutMs === 'number'
39
+ ? raw.daemon.stopTimeoutMs
40
+ : DAEMON_TIMEOUT_DEFAULTS.stopTimeoutMs,
41
+ sigkillGracePeriodMs:
42
+ typeof raw.daemon.sigkillGracePeriodMs === 'number'
43
+ ? raw.daemon.sigkillGracePeriodMs
44
+ : DAEMON_TIMEOUT_DEFAULTS.sigkillGracePeriodMs,
45
+ };
46
+ }
47
+ } catch {
48
+ // Missing file, malformed JSON, etc. — use defaults.
49
+ }
50
+ return { ...DAEMON_TIMEOUT_DEFAULTS };
51
+ }
52
+
53
+ function isProcessRunning(pid: number): boolean {
54
+ try {
55
+ process.kill(pid, 0);
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ function readPid(): number | null {
63
+ const pidPath = getPidPath();
64
+ if (!existsSync(pidPath)) return null;
65
+ try {
66
+ const pid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10);
67
+ return isNaN(pid) ? null : pid;
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+
73
+ export function writePid(pid: number): void {
74
+ writeFileSync(getPidPath(), String(pid));
75
+ }
76
+
77
+ export function cleanupPidFile(): void {
78
+ const pidPath = getPidPath();
79
+ if (existsSync(pidPath)) {
80
+ unlinkSync(pidPath);
81
+ }
82
+ }
83
+
84
+ export function isDaemonRunning(): boolean {
85
+ const pid = readPid();
86
+ if (pid == null) return false;
87
+ if (!isProcessRunning(pid)) {
88
+ cleanupPidFile();
89
+ return false;
90
+ }
91
+ return true;
92
+ }
93
+
94
+ export function getDaemonStatus(): { running: boolean; pid?: number } {
95
+ const pid = readPid();
96
+ if (pid == null) return { running: false };
97
+ if (!isProcessRunning(pid)) {
98
+ cleanupPidFile();
99
+ return { running: false };
100
+ }
101
+ return { running: true, pid };
102
+ }
103
+
104
+ export async function startDaemon(): Promise<{
105
+ pid: number;
106
+ alreadyRunning: boolean;
107
+ }> {
108
+ const status = getDaemonStatus();
109
+ if (status.running && status.pid) {
110
+ return { pid: status.pid, alreadyRunning: true };
111
+ }
112
+
113
+ // Only create the root dir for socket/PID — the daemon process itself
114
+ // handles migration + full ensureDataDir() in runDaemon(). Calling
115
+ // ensureDataDir() here would pre-create workspace destination dirs
116
+ // and cause migration moves to no-op.
117
+ const rootDir = getRootDir();
118
+ if (!existsSync(rootDir)) {
119
+ mkdirSync(rootDir, { recursive: true });
120
+ }
121
+
122
+ // Clean up stale socket (only if it's actually a Unix socket)
123
+ const socketPath = getSocketPath();
124
+ removeSocketFile(socketPath);
125
+
126
+ // Spawn the daemon as a detached child process
127
+ const mainPath = resolve(
128
+ import.meta.dirname ?? __dirname,
129
+ 'main.ts',
130
+ );
131
+
132
+ // Redirect the child's stderr to a file instead of piping it back to the
133
+ // parent. A pipe's read end is destroyed when the parent exits, leaving
134
+ // fd 2 broken in the child. Bun (unlike Node.js) does not ignore SIGPIPE,
135
+ // so any later stderr write would silently kill the daemon.
136
+ const stderrPath = join(rootDir, 'daemon-stderr.log');
137
+ const stderrFd = openSync(stderrPath, 'w');
138
+
139
+ const child = spawn('bun', ['run', mainPath], {
140
+ detached: true,
141
+ stdio: ['ignore', 'ignore', stderrFd],
142
+ env: { ...process.env },
143
+ });
144
+
145
+ // The child inherited the fd; close the parent's copy.
146
+ closeSync(stderrFd);
147
+
148
+ let childExited = false;
149
+ let childExitCode: number | null = null;
150
+ child.on('exit', (code) => {
151
+ childExited = true;
152
+ childExitCode = code;
153
+ });
154
+
155
+ child.unref();
156
+
157
+ const pid = child.pid;
158
+ if (!pid) {
159
+ throw new DaemonError('Failed to start daemon: no PID returned');
160
+ }
161
+
162
+ writePid(pid);
163
+
164
+ // Wait for socket to appear
165
+ const timeouts = readDaemonTimeouts();
166
+ const maxWait = timeouts.startupSocketWaitMs;
167
+ const interval = 100;
168
+ let waited = 0;
169
+ while (waited < maxWait) {
170
+ if (existsSync(socketPath)) {
171
+ return { pid, alreadyRunning: false };
172
+ }
173
+ if (childExited) {
174
+ cleanupPidFile();
175
+ const stderr = readFileSync(stderrPath, 'utf-8').trim();
176
+ const detail = stderr
177
+ ? `\n${stderr}`
178
+ : `\nCheck logs at ~/.vellum/workspace/data/logs/ for details.`;
179
+ throw new DaemonError(
180
+ `Daemon exited immediately (code ${childExitCode ?? 'unknown'}).${detail}`,
181
+ );
182
+ }
183
+ await new Promise((r) => setTimeout(r, interval));
184
+ waited += interval;
185
+ }
186
+
187
+ throw new DaemonError(
188
+ `Daemon started but socket not available after ${maxWait}ms`,
189
+ );
190
+ }
191
+
192
+ export type StopResult =
193
+ | { stopped: true }
194
+ | { stopped: false; reason: 'not_running' | 'stop_failed' };
195
+
196
+ export async function stopDaemon(): Promise<StopResult> {
197
+ const pid = readPid();
198
+ if (pid == null || !isProcessRunning(pid)) {
199
+ cleanupPidFile();
200
+ return { stopped: false, reason: 'not_running' };
201
+ }
202
+
203
+ process.kill(pid, 'SIGTERM');
204
+
205
+ const timeouts = readDaemonTimeouts();
206
+
207
+ // Wait for process to exit
208
+ const maxWait = timeouts.stopTimeoutMs;
209
+ const interval = 100;
210
+ let waited = 0;
211
+ while (waited < maxWait) {
212
+ if (!isProcessRunning(pid)) {
213
+ cleanupPidFile();
214
+ return { stopped: true };
215
+ }
216
+ await new Promise((r) => setTimeout(r, interval));
217
+ waited += interval;
218
+ }
219
+
220
+ // Force kill
221
+ try {
222
+ process.kill(pid, 'SIGKILL');
223
+ } catch (err) {
224
+ log.debug({ err, pid }, 'SIGKILL failed, process already exited');
225
+ }
226
+
227
+ // Wait for the process to actually die after SIGKILL. Without this,
228
+ // startDaemon() can race with the dying process's shutdown handler,
229
+ // which removes the socket file and bricks the new daemon.
230
+ const killMaxWait = timeouts.sigkillGracePeriodMs;
231
+ let killWaited = 0;
232
+ while (killWaited < killMaxWait && isProcessRunning(pid)) {
233
+ await new Promise((r) => setTimeout(r, 100));
234
+ killWaited += 100;
235
+ }
236
+
237
+ // Only clean up if the process has actually exited.
238
+ // If it's still alive after SIGKILL + timeout, preserve both socket
239
+ // and PID file so isDaemonRunning() still reports true and prevents
240
+ // a duplicate daemon from being spawned.
241
+ if (!isProcessRunning(pid)) {
242
+ removeSocketFile(getSocketPath());
243
+ cleanupPidFile();
244
+ return { stopped: true };
245
+ }
246
+
247
+ log.warn({ pid }, 'Daemon process still running after SIGKILL + timeout, leaving socket and PID file intact');
248
+ return { stopped: false, reason: 'stop_failed' };
249
+ }
250
+
251
+ export async function ensureDaemonRunning(): Promise<void> {
252
+ if (isDaemonRunning()) return;
253
+ await startDaemon();
254
+ }
@@ -3,6 +3,7 @@ import { v4 as uuid } from 'uuid';
3
3
  import { existsSync, rmSync, readdirSync, readFileSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
5
  import { join } from 'node:path';
6
+ import { getRuntimeHttpPort } from '../../config/env.js';
6
7
  import { queryAppRecords, createAppRecord, updateAppRecord, deleteAppRecord, listApps, getApp, getAppPreview, createApp, updateApp } from '../../memory/app-store.js';
7
8
  import { computeContentId } from '../../util/content-id.js';
8
9
  import { packageApp } from '../../bundler/app-bundler.js';
@@ -365,9 +366,7 @@ export async function handleShareAppCloud(
365
366
  const bundleData = readFileSync(result.bundlePath);
366
367
  const { shareToken } = createSharedAppLink(bundleData, result.manifest);
367
368
 
368
- const port = process.env.RUNTIME_HTTP_PORT
369
- ? parseInt(process.env.RUNTIME_HTTP_PORT, 10)
370
- : 7821;
369
+ const port = getRuntimeHttpPort() ?? 7821;
371
370
  const shareUrl = `http://localhost:${port}/v1/apps/shared/${shareToken}`;
372
371
 
373
372
  ctx.send(socket, {
@@ -0,0 +1,158 @@
1
+ import * as net from 'node:net';
2
+ import { createVerificationChallenge, getGuardianBinding, getPendingChallenge, revokeBinding as revokeGuardianBinding, revokePendingChallenges } from '../../runtime/channel-guardian-service.js';
3
+ import { createReadinessService, type ChannelReadinessService } from '../../runtime/channel-readiness-service.js';
4
+ import * as externalConversationStore from '../../memory/external-conversation-store.js';
5
+ import type {
6
+ GuardianVerificationRequest,
7
+ ChannelReadinessRequest,
8
+ } from '../ipc-protocol.js';
9
+ import { normalizeAssistantId } from '../../util/platform.js';
10
+ import { log, defineHandlers, type HandlerContext } from './shared.js';
11
+
12
+ // Lazy singleton — created on first use so module-load stays lightweight.
13
+ let _readinessService: ChannelReadinessService | undefined;
14
+ export function getReadinessService(): ChannelReadinessService {
15
+ if (!_readinessService) {
16
+ _readinessService = createReadinessService();
17
+ }
18
+ return _readinessService;
19
+ }
20
+
21
+ export function handleGuardianVerification(
22
+ msg: GuardianVerificationRequest,
23
+ socket: net.Socket,
24
+ ctx: HandlerContext,
25
+ ): void {
26
+ // Normalize the assistant ID so challenges are always stored under the
27
+ // same key the inbound-call path will use for lookups (typically "self").
28
+ const assistantId = normalizeAssistantId(msg.assistantId ?? 'self');
29
+ const channel = msg.channel ?? 'telegram';
30
+
31
+ try {
32
+ if (msg.action === 'create_challenge') {
33
+ const result = createVerificationChallenge(assistantId, channel, msg.sessionId);
34
+
35
+ ctx.send(socket, {
36
+ type: 'guardian_verification_response',
37
+ success: true,
38
+ secret: result.secret,
39
+ instruction: result.instruction,
40
+ channel,
41
+ });
42
+ } else if (msg.action === 'status') {
43
+ const binding = getGuardianBinding(assistantId, channel);
44
+ let guardianUsername: string | undefined;
45
+ let guardianDisplayName: string | undefined;
46
+ if (binding?.metadataJson) {
47
+ try {
48
+ const parsed = JSON.parse(binding.metadataJson) as Record<string, unknown>;
49
+ if (typeof parsed.username === 'string' && parsed.username.trim().length > 0) {
50
+ guardianUsername = parsed.username.trim();
51
+ }
52
+ if (typeof parsed.displayName === 'string' && parsed.displayName.trim().length > 0) {
53
+ guardianDisplayName = parsed.displayName.trim();
54
+ }
55
+ } catch {
56
+ // ignore malformed metadata
57
+ }
58
+ }
59
+ if (binding?.guardianDeliveryChatId && (!guardianUsername || !guardianDisplayName)) {
60
+ const ext = externalConversationStore.getBindingByChannelChat(
61
+ channel,
62
+ binding.guardianDeliveryChatId,
63
+ );
64
+ if (!guardianUsername && ext?.username) {
65
+ guardianUsername = ext.username;
66
+ }
67
+ if (!guardianDisplayName && ext?.displayName) {
68
+ guardianDisplayName = ext.displayName;
69
+ }
70
+ }
71
+ const hasPendingChallenge = getPendingChallenge(assistantId, channel) != null;
72
+ ctx.send(socket, {
73
+ type: 'guardian_verification_response',
74
+ success: true,
75
+ bound: binding != null,
76
+ guardianExternalUserId: binding?.guardianExternalUserId,
77
+ guardianUsername,
78
+ guardianDisplayName,
79
+ channel,
80
+ assistantId,
81
+ guardianDeliveryChatId: binding?.guardianDeliveryChatId,
82
+ hasPendingChallenge,
83
+ });
84
+ } else if (msg.action === 'revoke') {
85
+ revokeGuardianBinding(assistantId, channel);
86
+ revokePendingChallenges(assistantId, channel);
87
+ ctx.send(socket, {
88
+ type: 'guardian_verification_response',
89
+ success: true,
90
+ bound: false,
91
+ channel,
92
+ });
93
+ } else {
94
+ ctx.send(socket, {
95
+ type: 'guardian_verification_response',
96
+ success: false,
97
+ error: `Unknown action: ${String(msg.action)}`,
98
+ channel,
99
+ });
100
+ }
101
+ } catch (err) {
102
+ const message = err instanceof Error ? err.message : String(err);
103
+ log.error({ err }, 'Failed to handle guardian verification');
104
+ ctx.send(socket, {
105
+ type: 'guardian_verification_response',
106
+ success: false,
107
+ error: message,
108
+ channel,
109
+ });
110
+ }
111
+ }
112
+
113
+ export async function handleChannelReadiness(
114
+ msg: ChannelReadinessRequest,
115
+ socket: net.Socket,
116
+ ctx: HandlerContext,
117
+ ): Promise<void> {
118
+ try {
119
+ const service = getReadinessService();
120
+
121
+ if (msg.action === 'refresh') {
122
+ if (msg.channel) {
123
+ service.invalidateChannel(msg.channel, msg.assistantId);
124
+ } else {
125
+ service.invalidateAll();
126
+ }
127
+ }
128
+
129
+ const snapshots = await service.getReadiness(msg.channel, msg.includeRemote, msg.assistantId);
130
+
131
+ ctx.send(socket, {
132
+ type: 'channel_readiness_response',
133
+ success: true,
134
+ snapshots: snapshots.map((s) => ({
135
+ channel: s.channel,
136
+ ready: s.ready,
137
+ checkedAt: s.checkedAt,
138
+ stale: s.stale,
139
+ reasons: s.reasons,
140
+ localChecks: s.localChecks,
141
+ remoteChecks: s.remoteChecks,
142
+ })),
143
+ });
144
+ } catch (err) {
145
+ const message = err instanceof Error ? err.message : String(err);
146
+ log.error({ err }, 'Failed to handle channel readiness');
147
+ ctx.send(socket, {
148
+ type: 'channel_readiness_response',
149
+ success: false,
150
+ error: message,
151
+ });
152
+ }
153
+ }
154
+
155
+ export const channelHandlers = defineHandlers({
156
+ channel_readiness: handleChannelReadiness,
157
+ guardian_verification: handleGuardianVerification,
158
+ });