@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,177 @@
1
+ /**
2
+ * In-memory pairing request store with TTL.
3
+ *
4
+ * Each pairing request lives for at most TTL_MS (5 minutes) before
5
+ * being swept as expired. Status transitions:
6
+ * registered → pending → approved | denied | expired
7
+ */
8
+
9
+ import { createHash, timingSafeEqual } from 'node:crypto';
10
+ import { getLogger } from '../util/logger.js';
11
+
12
+ const log = getLogger('pairing-store');
13
+
14
+ const TTL_MS = 5 * 60 * 1000; // 5 minutes
15
+ const SWEEP_INTERVAL_MS = 30_000; // 30 seconds
16
+
17
+ export type PairingStatus = 'registered' | 'pending' | 'approved' | 'denied' | 'expired';
18
+
19
+ export interface PairingRequest {
20
+ pairingRequestId: string;
21
+ hashedPairingSecret: string;
22
+ hashedDeviceId?: string;
23
+ deviceName?: string;
24
+ status: PairingStatus;
25
+ gatewayUrl: string;
26
+ localLanUrl: string | null;
27
+ bearerToken?: string;
28
+ createdAt: number;
29
+ }
30
+
31
+ function hashValue(value: string): string {
32
+ return createHash('sha256').update(value).digest('hex');
33
+ }
34
+
35
+ function timingSafeCompare(a: string, b: string): boolean {
36
+ const bufA = Buffer.from(a);
37
+ const bufB = Buffer.from(b);
38
+ if (bufA.length !== bufB.length) return false;
39
+ return timingSafeEqual(bufA, bufB);
40
+ }
41
+
42
+ export class PairingStore {
43
+ private requests = new Map<string, PairingRequest>();
44
+ private sweepTimer: ReturnType<typeof setInterval> | null = null;
45
+
46
+ start(): void {
47
+ this.sweepTimer = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);
48
+ }
49
+
50
+ stop(): void {
51
+ if (this.sweepTimer) {
52
+ clearInterval(this.sweepTimer);
53
+ this.sweepTimer = null;
54
+ }
55
+ this.requests.clear();
56
+ }
57
+
58
+ /**
59
+ * Pre-register a pairing request (called when QR is displayed).
60
+ * Idempotent: if the same ID exists and secret matches, overwrite.
61
+ * Returns false with 'conflict' if ID exists but secret doesn't match.
62
+ */
63
+ register(params: {
64
+ pairingRequestId: string;
65
+ pairingSecret: string;
66
+ gatewayUrl: string;
67
+ localLanUrl?: string | null;
68
+ }): { ok: true } | { ok: false; reason: 'conflict' } {
69
+ const hashedSecret = hashValue(params.pairingSecret);
70
+ const existing = this.requests.get(params.pairingRequestId);
71
+
72
+ if (existing) {
73
+ if (!timingSafeCompare(existing.hashedPairingSecret, hashedSecret)) {
74
+ return { ok: false, reason: 'conflict' };
75
+ }
76
+ }
77
+
78
+ this.requests.set(params.pairingRequestId, {
79
+ pairingRequestId: params.pairingRequestId,
80
+ hashedPairingSecret: hashedSecret,
81
+ status: 'registered',
82
+ gatewayUrl: params.gatewayUrl,
83
+ localLanUrl: params.localLanUrl ?? null,
84
+ createdAt: Date.now(),
85
+ });
86
+
87
+ log.info({ pairingRequestId: params.pairingRequestId }, 'Pairing request registered');
88
+ return { ok: true };
89
+ }
90
+
91
+ /**
92
+ * iOS initiates a pairing request. Validates the secret and transitions
93
+ * the entry to "pending" (or "approved" if auto-approved).
94
+ */
95
+ beginRequest(params: {
96
+ pairingRequestId: string;
97
+ pairingSecret: string;
98
+ deviceId: string;
99
+ deviceName: string;
100
+ }): { ok: true; entry: PairingRequest } | { ok: false; reason: 'not_found' | 'invalid_secret' | 'expired' } {
101
+ const entry = this.requests.get(params.pairingRequestId);
102
+ if (!entry) {
103
+ return { ok: false, reason: 'not_found' };
104
+ }
105
+
106
+ if (entry.status === 'expired' || entry.status === 'denied') {
107
+ return { ok: false, reason: 'expired' };
108
+ }
109
+
110
+ const hashedSecret = hashValue(params.pairingSecret);
111
+ if (!timingSafeCompare(entry.hashedPairingSecret, hashedSecret)) {
112
+ return { ok: false, reason: 'invalid_secret' };
113
+ }
114
+
115
+ entry.hashedDeviceId = hashValue(params.deviceId);
116
+ entry.deviceName = params.deviceName;
117
+ if (entry.status === 'registered') {
118
+ entry.status = 'pending';
119
+ }
120
+
121
+ return { ok: true, entry };
122
+ }
123
+
124
+ /**
125
+ * Approve a pairing request. Sets the bearer token for iOS to retrieve.
126
+ */
127
+ approve(pairingRequestId: string, bearerToken: string): PairingRequest | null {
128
+ const entry = this.requests.get(pairingRequestId);
129
+ if (!entry) return null;
130
+ entry.status = 'approved';
131
+ entry.bearerToken = bearerToken;
132
+ return entry;
133
+ }
134
+
135
+ /**
136
+ * Deny a pairing request.
137
+ */
138
+ deny(pairingRequestId: string): PairingRequest | null {
139
+ const entry = this.requests.get(pairingRequestId);
140
+ if (!entry) return null;
141
+ entry.status = 'denied';
142
+ return entry;
143
+ }
144
+
145
+ /**
146
+ * Get a pairing request by ID.
147
+ */
148
+ get(pairingRequestId: string): PairingRequest | null {
149
+ return this.requests.get(pairingRequestId) ?? null;
150
+ }
151
+
152
+ /**
153
+ * Validate the secret for a status poll request (timing-safe).
154
+ */
155
+ validateSecret(pairingRequestId: string, secret: string): boolean {
156
+ const entry = this.requests.get(pairingRequestId);
157
+ if (!entry) return false;
158
+ const hashedSecret = hashValue(secret);
159
+ return timingSafeCompare(entry.hashedPairingSecret, hashedSecret);
160
+ }
161
+
162
+ private sweep(): void {
163
+ const now = Date.now();
164
+ for (const [id, entry] of this.requests) {
165
+ if (now - entry.createdAt > TTL_MS) {
166
+ if (entry.status !== 'approved') {
167
+ entry.status = 'expired';
168
+ }
169
+ // Remove entries older than 2x TTL regardless of status
170
+ if (now - entry.createdAt > TTL_MS * 2) {
171
+ this.requests.delete(id);
172
+ log.debug({ pairingRequestId: id }, 'Pairing request swept');
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,43 @@
1
+ import { initializeProviders } from '../providers/registry.js';
2
+ import { initializeTools } from '../tools/registry.js';
3
+ import { registerWatcherProvider } from '../watcher/provider-registry.js';
4
+ import { gmailProvider } from '../watcher/providers/gmail.js';
5
+ import { googleCalendarProvider } from '../watcher/providers/google-calendar.js';
6
+ import { slackProvider as slackWatcherProvider } from '../watcher/providers/slack.js';
7
+ import { githubProvider } from '../watcher/providers/github.js';
8
+ import { linearProvider } from '../watcher/providers/linear.js';
9
+ import { registerMessagingProvider } from '../messaging/registry.js';
10
+ import { slackProvider as slackMessagingProvider } from '../messaging/providers/slack/adapter.js';
11
+ import { gmailMessagingProvider } from '../messaging/providers/gmail/adapter.js';
12
+ import { telegramBotMessagingProvider } from '../messaging/providers/telegram-bot/adapter.js';
13
+ import { smsMessagingProvider } from '../messaging/providers/sms/adapter.js';
14
+ import { whatsappMessagingProvider } from '../messaging/providers/whatsapp/adapter.js';
15
+ import { initWatcherEngine } from '../watcher/engine.js';
16
+ import type { AssistantConfig } from '../config/types.js';
17
+ import { getLogger } from '../util/logger.js';
18
+
19
+ const log = getLogger('lifecycle');
20
+
21
+ export async function initializeProvidersAndTools(config: AssistantConfig): Promise<void> {
22
+ log.info('Daemon startup: initializing providers and tools');
23
+ initializeProviders(config);
24
+ await initializeTools();
25
+ log.info('Daemon startup: providers and tools initialized');
26
+ }
27
+
28
+ export function registerWatcherProviders(): void {
29
+ registerWatcherProvider(gmailProvider);
30
+ registerWatcherProvider(googleCalendarProvider);
31
+ registerWatcherProvider(slackWatcherProvider);
32
+ registerWatcherProvider(githubProvider);
33
+ registerWatcherProvider(linearProvider);
34
+ initWatcherEngine();
35
+ }
36
+
37
+ export function registerMessagingProviders(): void {
38
+ registerMessagingProvider(slackMessagingProvider);
39
+ registerMessagingProvider(gmailMessagingProvider);
40
+ registerMessagingProvider(telegramBotMessagingProvider);
41
+ registerMessagingProvider(smsMessagingProvider);
42
+ registerMessagingProvider(whatsappMessagingProvider);
43
+ }
@@ -23,6 +23,9 @@ const log = getLogger('ride-shotgun-handler');
23
23
  /** Active network recorders keyed by watchId. */
24
24
  const activeRecorders = new Map<string, NetworkRecorder>();
25
25
 
26
+ /** Active progress interval timers keyed by watchId, cleared on session completion. */
27
+ const activeProgressIntervals = new Map<string, NodeJS.Timeout>();
28
+
26
29
  /** Return domain-specific URL patterns that indicate a successful login. */
27
30
  function getLoginSignals(targetDomain?: string): string[] {
28
31
  if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
@@ -52,6 +55,13 @@ async function completeSession(session: WatchSession): Promise<void> {
52
55
  session.timeoutHandle = undefined;
53
56
  }
54
57
 
58
+ // Clear progress interval timer if one was registered for this session
59
+ const progressTimer = activeProgressIntervals.get(session.watchId);
60
+ if (progressTimer) {
61
+ clearInterval(progressTimer);
62
+ activeProgressIntervals.delete(session.watchId);
63
+ }
64
+
55
65
  const { watchId, sessionId } = session;
56
66
  log.info(
57
67
  { watchId, sessionId, observationCount: session.observations.length },
@@ -135,9 +145,62 @@ export async function handleRideShotgunStart(
135
145
  activeRecorders.set(watchId, recorder);
136
146
  log.info({ watchId, targetDomain, attempt }, 'Network recording started for learn session');
137
147
 
148
+ // Send periodic progress updates with network entry counts and idle detection
149
+ let lastNetworkEntryCount = 0;
150
+ let lastActivityTimestamp = Date.now();
151
+ let idleHintSent = false;
152
+
153
+ const progressInterval: NodeJS.Timeout = setInterval(() => {
154
+ if (session.status !== 'active') {
155
+ clearInterval(progressInterval);
156
+ return;
157
+ }
158
+
159
+ const currentCount = recorder.entryCount;
160
+
161
+ // Track activity: reset idle timer when count changes
162
+ if (currentCount !== lastNetworkEntryCount) {
163
+ lastNetworkEntryCount = currentCount;
164
+ lastActivityTimestamp = Date.now();
165
+ // If we previously sent an idle hint, clear it now that activity resumed
166
+ if (idleHintSent) {
167
+ idleHintSent = false;
168
+ log.info({ watchId, currentCount }, 'Activity resumed — clearing idleHint');
169
+ ctx.send(socket, {
170
+ type: 'ride_shotgun_progress',
171
+ watchId,
172
+ message: `Recording network traffic...`,
173
+ networkEntryCount: currentCount,
174
+ statusMessage: 'Recording network traffic...',
175
+ idleHint: false,
176
+ });
177
+ return;
178
+ }
179
+ }
180
+
181
+ // Idle detection: if some initial activity happened and no new entries for 15s, hint once
182
+ const idleMs = Date.now() - lastActivityTimestamp;
183
+ let idleHint: boolean | undefined;
184
+ if (!idleHintSent && currentCount > 0 && idleMs >= 15_000) {
185
+ idleHint = true;
186
+ idleHintSent = true;
187
+ log.info({ watchId, currentCount, idleMs }, 'Idle detected — sending idleHint');
188
+ }
189
+
190
+ ctx.send(socket, {
191
+ type: 'ride_shotgun_progress',
192
+ watchId,
193
+ message: `Recording network traffic...`,
194
+ networkEntryCount: currentCount,
195
+ statusMessage: 'Recording network traffic...',
196
+ ...(idleHint !== undefined ? { idleHint } : {}),
197
+ });
198
+ }, 5000);
199
+ activeProgressIntervals.set(watchId, progressInterval);
200
+
138
201
  // For x.com, auto-navigate Chrome through key pages to capture the full API surface.
139
202
  // Skip login detection — auto-navigation will complete the session when done.
140
- if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
203
+ if ((targetDomain === 'x.com' || targetDomain === 'twitter.com') && msg.autoNavigate !== false) {
141
204
  // Don't set onLoginDetected — it would kill the session after the first
142
205
  // GraphQL call (5s grace), before auto-navigation finishes.
143
206
  const abortSignal = { aborted: false };
@@ -192,8 +255,10 @@ export async function handleRideShotgunStart(
192
255
  completeSession(session);
193
256
  }
194
257
  });
258
+ } else if (msg.autoNavigate === false && targetDomain) {
259
+ // Manual mode: just record network traffic until timeout or early stop — no login detection shortcut.
195
260
  } else {
196
- // No targetDomain: use login detection as before
261
+ // No targetDomain or targetDomain without explicit autoNavigate=false: use login detection
197
262
  recorder.onLoginDetected = () => {
198
263
  log.info({ watchId }, 'Login detected — auto-stopping learn session');
199
264
  completeSession(session);
@@ -15,6 +15,7 @@ import { IngressBlockedError } from '../util/errors.js';
15
15
  import * as conversationStore from '../memory/conversation-store.js';
16
16
  import * as attachmentsStore from '../memory/attachments-store.js';
17
17
  import { Session, DEFAULT_MEMORY_POLICY, type SessionMemoryPolicy } from './session.js';
18
+ import { parseChannelId, type ChannelId } from '../channels/types.js';
18
19
  import { resolveChannelCapabilities } from './session-runtime-assembly.js';
19
20
  import { ComputerUseSession } from './computer-use-session.js';
20
21
  import {
@@ -31,7 +32,6 @@ import { ensureBlobDir, sweepStaleBlobs } from './ipc-blob-store.js';
31
32
  import { bootstrapHomeBaseAppLink } from '../home-base/bootstrap.js';
32
33
  import { SessionEvictor } from './session-evictor.js';
33
34
  import { getSubagentManager } from '../subagent/index.js';
34
- import { tryRouteCallMessage } from '../calls/call-bridge.js';
35
35
  import { resolveSlash } from './session-slash.js';
36
36
  import { createUserMessage, createAssistantMessage } from '../agent/message-types.js';
37
37
  import { registerDaemonCallbacks } from '../work-items/work-item-runner.js';
@@ -53,6 +53,24 @@ function readPackageVersion(): string | undefined {
53
53
 
54
54
  const daemonVersion = readPackageVersion();
55
55
 
56
+ function resolveTurnChannel(sourceChannel?: string, transportChannelId?: string): ChannelId {
57
+ if (sourceChannel != null) {
58
+ const parsed = parseChannelId(sourceChannel);
59
+ if (!parsed) {
60
+ throw new Error(`Invalid sourceChannel: ${sourceChannel}`);
61
+ }
62
+ return parsed;
63
+ }
64
+ if (transportChannelId != null) {
65
+ const parsed = parseChannelId(transportChannelId);
66
+ if (!parsed) {
67
+ throw new Error(`Invalid transport.channelId: ${transportChannelId}`);
68
+ }
69
+ return parsed;
70
+ }
71
+ return 'macos';
72
+ }
73
+
56
74
  export class DaemonServer {
57
75
  private server: net.Server | null = null;
58
76
  private tcpServer: tls.Server | null = null;
@@ -358,7 +376,7 @@ export class DaemonServer {
358
376
  const parseDurationMs = Number(process.hrtime.bigint() - parseStartNs) / 1_000_000;
359
377
  for (const entry of parsed) {
360
378
  const msg = entry.msg;
361
- if (typeof msg === 'object' && msg !== null && (msg as { type?: unknown }).type === 'cu_observation') {
379
+ if (typeof msg === 'object' && msg != null && (msg as { type?: unknown }).type === 'cu_observation') {
362
380
  const maybeSessionId = (msg as { sessionId?: unknown }).sessionId;
363
381
  const sessionId = typeof maybeSessionId === 'string' ? maybeSessionId : 'unknown';
364
382
  const previousSequence = this.cuObservationParseSequence.get(sessionId) ?? 0;
@@ -488,6 +506,20 @@ export class DaemonServer {
488
506
  }
489
507
  }
490
508
 
509
+ get lastConfigFingerprint(): string {
510
+ return this.configWatcher.lastFingerprint;
511
+ }
512
+
513
+ set lastConfigFingerprint(value: string) {
514
+ this.configWatcher.lastFingerprint = value;
515
+ }
516
+
517
+ refreshConfigFromSources(): boolean {
518
+ const changed = this.configWatcher.refreshConfigFromSources();
519
+ if (changed) this.evictSessionsForReload();
520
+ return changed;
521
+ }
522
+
491
523
  private async sendInitialSession(socket: net.Socket): Promise<void> {
492
524
  const conversation = conversationStore.getLatestConversation();
493
525
  if (!conversation) {
@@ -669,6 +701,12 @@ export class DaemonServer {
669
701
  session.setAssistantId(options?.assistantId ?? 'self');
670
702
  session.setGuardianContext(options?.guardianContext ?? null);
671
703
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
704
+ session.setCommandIntent(options?.commandIntent ?? null);
705
+ const resolvedChannel = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
706
+ session.setTurnChannelContext({
707
+ userMessageChannel: resolvedChannel,
708
+ assistantMessageChannel: resolvedChannel,
709
+ });
672
710
 
673
711
  const attachments = attachmentIds
674
712
  ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
@@ -682,21 +720,6 @@ export class DaemonServer {
682
720
  const requestId = crypto.randomUUID();
683
721
  const messageId = session.persistUserMessage(content, attachments, requestId);
684
722
 
685
- let bridgeHandled = false;
686
- try {
687
- const bridgeResult = await tryRouteCallMessage(conversationId, content, messageId);
688
- bridgeHandled = bridgeResult.handled;
689
- } catch (err) {
690
- log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
691
- }
692
-
693
- if (bridgeHandled) {
694
- resetSessionProcessingState(session);
695
- session.drainQueue('loop_complete');
696
- log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
697
- return { messageId };
698
- }
699
-
700
723
  session.runAgentLoop(content, messageId, () => {}).catch((err) => {
701
724
  log.error({ err, conversationId }, 'Background agent loop failed');
702
725
  });
@@ -725,6 +748,12 @@ export class DaemonServer {
725
748
  session.setAssistantId(options?.assistantId ?? 'self');
726
749
  session.setGuardianContext(options?.guardianContext ?? null);
727
750
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
751
+ session.setCommandIntent(options?.commandIntent ?? null);
752
+ const resolvedChannel2 = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
753
+ session.setTurnChannelContext({
754
+ userMessageChannel: resolvedChannel2,
755
+ assistantMessageChannel: resolvedChannel2,
756
+ });
728
757
 
729
758
  const attachments = attachmentIds
730
759
  ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
@@ -738,19 +767,33 @@ export class DaemonServer {
738
767
  const slashResult = resolveSlash(content);
739
768
 
740
769
  if (slashResult.kind === 'unknown') {
770
+ const serverTurnCtx = session.getTurnChannelContext();
771
+ const serverChannelMeta = serverTurnCtx
772
+ ? { userMessageChannel: serverTurnCtx.userMessageChannel, assistantMessageChannel: serverTurnCtx.assistantMessageChannel }
773
+ : undefined;
741
774
  const userMsg = createUserMessage(content, attachments);
742
775
  const persisted = conversationStore.addMessage(
743
776
  conversationId,
744
777
  'user',
745
778
  JSON.stringify(userMsg.content),
779
+ serverChannelMeta,
746
780
  );
747
781
  session.getMessages().push(userMsg);
748
782
 
783
+ if (serverTurnCtx) {
784
+ try {
785
+ conversationStore.setConversationOriginChannelIfUnset(conversationId, serverTurnCtx.userMessageChannel);
786
+ } catch (err) {
787
+ log.warn({ err, conversationId }, 'Failed to set origin channel (best-effort)');
788
+ }
789
+ }
790
+
749
791
  const assistantMsg = createAssistantMessage(slashResult.message);
750
792
  conversationStore.addMessage(
751
793
  conversationId,
752
794
  'assistant',
753
795
  JSON.stringify(assistantMsg.content),
796
+ serverChannelMeta,
754
797
  );
755
798
  session.getMessages().push(assistantMsg);
756
799
  return { messageId: persisted.id };
@@ -771,22 +814,6 @@ export class DaemonServer {
771
814
  throw err;
772
815
  }
773
816
 
774
- let bridgeHandled = false;
775
- try {
776
- const bridgeResult = await tryRouteCallMessage(conversationId, resolvedContent, messageId);
777
- bridgeHandled = bridgeResult.handled;
778
- } catch (err) {
779
- log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
780
- }
781
-
782
- if (bridgeHandled) {
783
- (session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
784
- resetSessionProcessingState(session);
785
- session.drainQueue('loop_complete');
786
- log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
787
- return { messageId };
788
- }
789
-
790
817
  await session.runAgentLoop(resolvedContent, messageId, () => {});
791
818
 
792
819
  return { messageId };
@@ -809,14 +836,3 @@ export class DaemonServer {
809
836
  }
810
837
 
811
838
  }
812
-
813
- function resetSessionProcessingState(session: Session): void {
814
- const s = session as unknown as {
815
- processing: boolean;
816
- abortController: AbortController | null;
817
- currentRequestId: string | undefined;
818
- };
819
- s.processing = false;
820
- s.abortController = null;
821
- s.currentRequestId = undefined;
822
- }