vellum 0.2.1 → 0.2.2

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 (349) hide show
  1. package/README.md +15 -2
  2. package/bun.lock +5 -2
  3. package/package.json +4 -2
  4. package/scripts/capture-x-graphql.ts +562 -0
  5. package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
  6. package/scripts/test.sh +5 -0
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
  8. package/src/__tests__/account-registry.test.ts +2 -1
  9. package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
  10. package/src/__tests__/asset-materialize-tool.test.ts +16 -15
  11. package/src/__tests__/asset-search-tool.test.ts +23 -22
  12. package/src/__tests__/attachments-store.test.ts +56 -127
  13. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
  14. package/src/__tests__/browser-skill-endstate.test.ts +4 -3
  15. package/src/__tests__/call-bridge.test.ts +385 -0
  16. package/src/__tests__/call-constants.test.ts +40 -0
  17. package/src/__tests__/call-orchestrator.test.ts +130 -4
  18. package/src/__tests__/call-recovery.test.ts +518 -0
  19. package/src/__tests__/call-routes-http.test.ts +459 -0
  20. package/src/__tests__/call-state-machine.test.ts +143 -0
  21. package/src/__tests__/call-store.test.ts +216 -1
  22. package/src/__tests__/cli-discover.test.ts +1 -1
  23. package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
  24. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  25. package/src/__tests__/computer-use-tools.test.ts +250 -0
  26. package/src/__tests__/config-schema.test.ts +299 -3
  27. package/src/__tests__/conflict-store.test.ts +2 -1
  28. package/src/__tests__/contacts-tools.test.ts +331 -0
  29. package/src/__tests__/conversation-store.test.ts +30 -32
  30. package/src/__tests__/credential-security-invariants.test.ts +4 -0
  31. package/src/__tests__/date-context.test.ts +373 -0
  32. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  33. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
  34. package/src/__tests__/followup-tools.test.ts +303 -0
  35. package/src/__tests__/handlers-twitter-config.test.ts +718 -0
  36. package/src/__tests__/intent-routing.test.ts +64 -57
  37. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +62 -28
  39. package/src/__tests__/llm-usage-store.test.ts +3 -8
  40. package/src/__tests__/media-generate-image.test.ts +1 -1
  41. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
  42. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  43. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  44. package/src/__tests__/playbook-tools.test.ts +342 -0
  45. package/src/__tests__/profile-compiler.test.ts +2 -1
  46. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  47. package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
  48. package/src/__tests__/recurrence-engine.test.ts +69 -0
  49. package/src/__tests__/recurrence-types.test.ts +71 -0
  50. package/src/__tests__/registry.test.ts +5 -3
  51. package/src/__tests__/relay-server.test.ts +633 -0
  52. package/src/__tests__/reminder-store.test.ts +6 -3
  53. package/src/__tests__/reminder.test.ts +43 -77
  54. package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
  55. package/src/__tests__/run-orchestrator.test.ts +4 -4
  56. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
  57. package/src/__tests__/runtime-runs-http.test.ts +4 -4
  58. package/src/__tests__/runtime-runs.test.ts +4 -4
  59. package/src/__tests__/schedule-store.test.ts +482 -0
  60. package/src/__tests__/schedule-tools.test.ts +700 -0
  61. package/src/__tests__/scheduler-recurrence.test.ts +329 -0
  62. package/src/__tests__/server-history-render.test.ts +14 -13
  63. package/src/__tests__/session-error.test.ts +28 -0
  64. package/src/__tests__/session-init.benchmark.test.ts +462 -0
  65. package/src/__tests__/session-queue.test.ts +71 -48
  66. package/src/__tests__/session-runtime-assembly.test.ts +161 -0
  67. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  68. package/src/__tests__/signup-e2e.test.ts +2 -1
  69. package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
  70. package/src/__tests__/skill-script-runner.test.ts +159 -0
  71. package/src/__tests__/speaker-identification.test.ts +52 -0
  72. package/src/__tests__/subagent-manager-notify.test.ts +42 -10
  73. package/src/__tests__/subagent-tools.test.ts +141 -41
  74. package/src/__tests__/task-compiler.test.ts +2 -1
  75. package/src/__tests__/task-runner.test.ts +2 -1
  76. package/src/__tests__/task-scheduler.test.ts +2 -1
  77. package/src/__tests__/task-tools.test.ts +49 -56
  78. package/src/__tests__/tool-audit-listener.test.ts +1 -0
  79. package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
  80. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  81. package/src/__tests__/tool-executor.test.ts +13 -17
  82. package/src/__tests__/turn-commit.test.ts +218 -3
  83. package/src/__tests__/twilio-provider.test.ts +143 -0
  84. package/src/__tests__/twilio-routes.test.ts +789 -0
  85. package/src/__tests__/twitter-auth-handler.test.ts +581 -0
  86. package/src/__tests__/view-image-tool.test.ts +217 -0
  87. package/src/__tests__/workspace-git-service.test.ts +186 -0
  88. package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
  89. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  90. package/src/bundler/app-bundler.ts +12 -8
  91. package/src/calls/call-bridge.ts +95 -0
  92. package/src/calls/call-constants.ts +43 -5
  93. package/src/calls/call-domain.ts +276 -0
  94. package/src/calls/call-orchestrator.ts +43 -17
  95. package/src/calls/call-recovery.ts +207 -0
  96. package/src/calls/call-state-machine.ts +68 -0
  97. package/src/calls/call-store.ts +192 -5
  98. package/src/calls/relay-server.ts +41 -4
  99. package/src/calls/speaker-identification.ts +213 -0
  100. package/src/calls/twilio-provider.ts +10 -6
  101. package/src/calls/twilio-routes.ts +90 -76
  102. package/src/calls/types.ts +1 -1
  103. package/src/cli/config-commands.ts +334 -0
  104. package/src/cli/core-commands.ts +776 -0
  105. package/src/cli/doordash.ts +251 -1
  106. package/src/cli/ipc-client.ts +82 -0
  107. package/src/cli/map.ts +246 -0
  108. package/src/cli/twitter.ts +575 -0
  109. package/src/cli.ts +7 -5
  110. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  111. package/src/commands/cc-command-registry.ts +209 -0
  112. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  113. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  114. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
  115. package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
  116. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
  117. package/src/config/bundled-skills/document/SKILL.md +18 -0
  118. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  119. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  120. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  121. package/src/config/bundled-skills/doordash/SKILL.md +82 -23
  122. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  123. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  124. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  125. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  126. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  127. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
  128. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
  129. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  130. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  131. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
  132. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
  133. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
  134. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
  135. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  136. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  137. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  138. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  139. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  140. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  141. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  142. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  143. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  144. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  145. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  146. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  147. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  148. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  149. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  150. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  151. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  152. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  153. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  154. package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
  155. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  156. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  157. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  158. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  159. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  160. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  161. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  162. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  163. package/src/config/bundled-skills/twitter/SKILL.md +134 -0
  164. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  165. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  166. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  167. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  168. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  169. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  170. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  171. package/src/config/defaults.ts +33 -0
  172. package/src/config/loader.ts +4 -1
  173. package/src/config/schema.ts +161 -1
  174. package/src/config/system-prompt.ts +61 -16
  175. package/src/config/templates/IDENTITY.md +7 -0
  176. package/src/config/types.ts +4 -0
  177. package/src/contacts/contact-store.ts +4 -4
  178. package/src/daemon/assistant-attachments.ts +10 -0
  179. package/src/daemon/classifier.ts +3 -1
  180. package/src/daemon/computer-use-session.ts +3 -1
  181. package/src/daemon/date-context.ts +136 -0
  182. package/src/daemon/handlers/apps.ts +16 -1
  183. package/src/daemon/handlers/browser.ts +54 -0
  184. package/src/daemon/handlers/computer-use.ts +7 -1
  185. package/src/daemon/handlers/config.ts +163 -5
  186. package/src/daemon/handlers/diagnostics.ts +5 -1
  187. package/src/daemon/handlers/documents.ts +18 -29
  188. package/src/daemon/handlers/home-base.ts +5 -1
  189. package/src/daemon/handlers/index.ts +40 -277
  190. package/src/daemon/handlers/misc.ts +9 -1
  191. package/src/daemon/handlers/publish.ts +6 -1
  192. package/src/daemon/handlers/sessions.ts +65 -12
  193. package/src/daemon/handlers/shared.ts +36 -1
  194. package/src/daemon/handlers/signing.ts +37 -0
  195. package/src/daemon/handlers/skills.ts +20 -6
  196. package/src/daemon/handlers/subagents.ts +8 -3
  197. package/src/daemon/handlers/twitter-auth.ts +169 -0
  198. package/src/daemon/handlers/work-items.ts +384 -68
  199. package/src/daemon/ipc-contract-inventory.json +28 -4
  200. package/src/daemon/ipc-contract.ts +133 -37
  201. package/src/daemon/ipc-protocol.ts +7 -2
  202. package/src/daemon/lifecycle.ts +21 -0
  203. package/src/daemon/main.ts +10 -4
  204. package/src/daemon/ride-shotgun-handler.ts +74 -10
  205. package/src/daemon/server.ts +143 -26
  206. package/src/daemon/session-agent-loop.ts +887 -0
  207. package/src/daemon/session-attachments.ts +28 -5
  208. package/src/daemon/session-error.ts +24 -3
  209. package/src/daemon/session-lifecycle.ts +147 -0
  210. package/src/daemon/session-media-retry.ts +147 -0
  211. package/src/daemon/session-messaging.ts +145 -0
  212. package/src/daemon/session-notifiers.ts +164 -0
  213. package/src/daemon/session-process.ts +2 -2
  214. package/src/daemon/session-queue-manager.ts +1 -0
  215. package/src/daemon/session-runtime-assembly.ts +52 -0
  216. package/src/daemon/session-skill-tools.ts +124 -5
  217. package/src/daemon/session-slash.ts +3 -0
  218. package/src/daemon/session-surfaces.ts +77 -2
  219. package/src/daemon/session-tool-setup.ts +216 -2
  220. package/src/daemon/session-usage.ts +0 -2
  221. package/src/daemon/session.ts +114 -1404
  222. package/src/daemon/video-thumbnail.ts +60 -0
  223. package/src/doordash/client.ts +121 -27
  224. package/src/doordash/queries.ts +1 -2
  225. package/src/export/formatter.ts +3 -1
  226. package/src/followups/followup-store.ts +4 -2
  227. package/src/followups/types.ts +6 -0
  228. package/src/hooks/templates.ts +1 -1
  229. package/src/index.ts +32 -1153
  230. package/src/memory/attachments-store.ts +28 -83
  231. package/src/memory/channel-delivery-store.ts +7 -21
  232. package/src/memory/clarification-resolver.ts +6 -5
  233. package/src/memory/contradiction-checker.ts +3 -2
  234. package/src/memory/conversation-key-store.ts +10 -29
  235. package/src/memory/conversation-store.ts +2 -1
  236. package/src/memory/db.ts +96 -2
  237. package/src/memory/entity-extractor.ts +6 -3
  238. package/src/memory/items-extractor.ts +5 -4
  239. package/src/memory/jobs-store.ts +3 -2
  240. package/src/memory/llm-usage-store.ts +1 -2
  241. package/src/memory/runs-store.ts +1 -2
  242. package/src/memory/schema.ts +23 -2
  243. package/src/messaging/style-analyzer.ts +3 -2
  244. package/src/messaging/thread-summarizer.ts +8 -12
  245. package/src/messaging/triage-engine.ts +4 -2
  246. package/src/providers/openrouter/client.ts +20 -0
  247. package/src/providers/registry.ts +8 -0
  248. package/src/runtime/http-server.ts +108 -20
  249. package/src/runtime/routes/attachment-routes.ts +2 -3
  250. package/src/runtime/routes/call-routes.ts +140 -0
  251. package/src/runtime/routes/channel-routes.ts +5 -10
  252. package/src/runtime/routes/conversation-routes.ts +5 -5
  253. package/src/runtime/routes/run-routes.ts +2 -2
  254. package/src/runtime/run-orchestrator.ts +9 -3
  255. package/src/schedule/recurrence-engine.ts +138 -0
  256. package/src/schedule/recurrence-types.ts +67 -0
  257. package/src/schedule/schedule-store.ts +102 -57
  258. package/src/schedule/scheduler.ts +9 -6
  259. package/src/security/oauth2.ts +29 -4
  260. package/src/security/secret-allowlist.ts +46 -0
  261. package/src/skills/clawhub.ts +1 -1
  262. package/src/subagent/manager.ts +40 -8
  263. package/src/swarm/backend-claude-code.ts +64 -9
  264. package/src/swarm/worker-prompts.ts +2 -1
  265. package/src/tasks/SPEC.md +34 -28
  266. package/src/tasks/ephemeral-permissions.ts +16 -7
  267. package/src/tasks/task-compiler.ts +5 -4
  268. package/src/tasks/task-runner.ts +10 -5
  269. package/src/tasks/task-scheduler.ts +1 -1
  270. package/src/tasks/tool-sanitizer.ts +36 -0
  271. package/src/tools/assets/search.ts +4 -4
  272. package/src/tools/browser/api-map.ts +220 -0
  273. package/src/tools/browser/auto-navigate.ts +270 -0
  274. package/src/tools/browser/browser-execution.ts +2 -1
  275. package/src/tools/browser/browser-manager.ts +2 -2
  276. package/src/tools/browser/network-recorder.ts +5 -4
  277. package/src/tools/browser/x-auto-navigate.ts +207 -0
  278. package/src/tools/calls/call-end.ts +17 -67
  279. package/src/tools/calls/call-start.ts +24 -85
  280. package/src/tools/calls/call-status.ts +35 -51
  281. package/src/tools/claude-code/claude-code.ts +77 -11
  282. package/src/tools/contacts/contact-merge.ts +46 -78
  283. package/src/tools/contacts/contact-search.ts +35 -79
  284. package/src/tools/contacts/contact-upsert.ts +35 -108
  285. package/src/tools/credentials/vault.ts +20 -4
  286. package/src/tools/document/document-tool.ts +71 -144
  287. package/src/tools/executor.ts +129 -10
  288. package/src/tools/followups/followup_create.ts +46 -88
  289. package/src/tools/followups/followup_list.ts +34 -74
  290. package/src/tools/followups/followup_resolve.ts +31 -66
  291. package/src/tools/host-terminal/cli-discover.ts +2 -1
  292. package/src/tools/host-terminal/host-shell.ts +10 -0
  293. package/src/tools/memory/handlers.ts +5 -4
  294. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  295. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  296. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  297. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  298. package/src/tools/network/web-fetch.ts +18 -6
  299. package/src/tools/playbooks/index.ts +4 -5
  300. package/src/tools/playbooks/playbook-create.ts +3 -47
  301. package/src/tools/playbooks/playbook-delete.ts +1 -25
  302. package/src/tools/playbooks/playbook-list.ts +1 -28
  303. package/src/tools/playbooks/playbook-update.ts +3 -51
  304. package/src/tools/reminder/reminder.ts +5 -78
  305. package/src/tools/schedule/create.ts +69 -74
  306. package/src/tools/schedule/delete.ts +21 -47
  307. package/src/tools/schedule/list.ts +55 -74
  308. package/src/tools/schedule/update.ts +77 -84
  309. package/src/tools/subagent/abort.ts +29 -58
  310. package/src/tools/subagent/message.ts +30 -63
  311. package/src/tools/subagent/read.ts +53 -84
  312. package/src/tools/subagent/spawn.ts +43 -82
  313. package/src/tools/subagent/status.ts +42 -71
  314. package/src/tools/swarm/delegate.ts +2 -1
  315. package/src/tools/tasks/index.ts +8 -8
  316. package/src/tools/tasks/task-delete.ts +60 -88
  317. package/src/tools/tasks/task-list.ts +31 -52
  318. package/src/tools/tasks/task-run.ts +72 -108
  319. package/src/tools/tasks/task-save.ts +33 -65
  320. package/src/tools/tasks/work-item-enqueue.ts +183 -215
  321. package/src/tools/tasks/work-item-list.ts +33 -63
  322. package/src/tools/tasks/work-item-remove.ts +45 -97
  323. package/src/tools/tasks/work-item-update.ts +91 -163
  324. package/src/tools/terminal/backends/native.ts +3 -1
  325. package/src/tools/tool-manifest.ts +0 -62
  326. package/src/tools/types.ts +6 -0
  327. package/src/tools/ui-surface/definitions.ts +3 -1
  328. package/src/tools/watch/screen-watch.ts +3 -1
  329. package/src/tools/watcher/create.ts +52 -98
  330. package/src/tools/watcher/delete.ts +20 -46
  331. package/src/tools/watcher/digest.ts +36 -70
  332. package/src/tools/watcher/list.ts +49 -79
  333. package/src/tools/watcher/update.ts +45 -91
  334. package/src/twitter/client.ts +690 -0
  335. package/src/twitter/session.ts +91 -0
  336. package/src/usage/types.ts +0 -1
  337. package/src/util/truncate.ts +6 -0
  338. package/src/watcher/providers/slack.ts +2 -1
  339. package/src/watcher/watcher-store.ts +3 -2
  340. package/src/work-items/work-item-store.ts +27 -2
  341. package/src/workspace/commit-message-enrichment-service.ts +31 -7
  342. package/src/workspace/git-service.ts +87 -22
  343. package/src/workspace/provider-commit-message-generator.ts +242 -0
  344. package/src/workspace/turn-commit.ts +62 -3
  345. package/src/tools/contacts/index.ts +0 -4
  346. package/src/tools/document/index.ts +0 -5
  347. package/src/tools/followups/index.ts +0 -3
  348. package/src/tools/subagent/index.ts +0 -5
  349. /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import * as net from 'node:net';
2
2
  import { randomBytes } from 'node:crypto';
3
- import { existsSync, chmodSync, writeFileSync, unlinkSync, readdirSync, watch, type FSWatcher } from 'node:fs';
3
+ import { existsSync, chmodSync, readFileSync, writeFileSync, unlinkSync, readdirSync, watch, type FSWatcher } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { getSocketPath, getSessionTokenPath, getRootDir, getWorkspaceDir, getWorkspaceSkillsDir, getSandboxWorkingDir, removeSocketFile, getTCPPort, getTCPHost, isTCPEnabled } from '../util/platform.js';
6
6
  import { hasNoAuthOverride } from './connection-policy.js';
@@ -10,7 +10,7 @@ import { RateLimitProvider } from '../providers/ratelimit.js';
10
10
  import { getConfig, invalidateConfigCache } from '../config/loader.js';
11
11
  import { buildSystemPrompt } from '../config/system-prompt.js';
12
12
  import { clearCache as clearTrustCache } from '../permissions/trust-store.js';
13
- import { resetAllowlist } from '../security/secret-allowlist.js';
13
+ import { resetAllowlist, validateAllowlistFile } from '../security/secret-allowlist.js';
14
14
  import { checkIngressForSecrets } from '../security/secret-ingress.js';
15
15
  import { IngressBlockedError } from '../util/errors.js';
16
16
  import { clearEmbeddingBackendCache } from '../memory/embedding-backend.js';
@@ -36,9 +36,24 @@ import { assistantEventHub } from '../runtime/assistant-event-hub.js';
36
36
  import { buildAssistantEvent } from '../runtime/assistant-event.js';
37
37
  import { SessionEvictor } from './session-evictor.js';
38
38
  import { getSubagentManager } from '../subagent/index.js';
39
+ import { tryHandlePendingCallAnswer } from '../calls/call-bridge.js';
40
+ import { resolveSlash } from './session-slash.js';
41
+ import { createUserMessage, createAssistantMessage } from '../agent/message-types.js';
39
42
 
40
43
  const log = getLogger('server');
41
44
 
45
+ function readPackageVersion(): string | undefined {
46
+ try {
47
+ const pkgPath = join(import.meta.dir, '../../package.json');
48
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version?: string };
49
+ return pkg.version;
50
+ } catch {
51
+ return undefined;
52
+ }
53
+ }
54
+
55
+ const daemonVersion = readPackageVersion();
56
+
42
57
  export class DaemonServer {
43
58
  private server: net.Server | null = null;
44
59
  private tcpServer: net.Server | null = null;
@@ -125,21 +140,23 @@ export class DaemonServer {
125
140
  };
126
141
  // When a subagent finishes, inject the result into the parent session
127
142
  // so the LLM automatically informs the user.
128
- getSubagentManager().onSubagentFinished = (parentSessionId, message, sendToClient) => {
143
+ getSubagentManager().onSubagentFinished = (parentSessionId, message, sendToClient, notification) => {
129
144
  const parentSession = this.sessions.get(parentSessionId);
130
145
  if (!parentSession) {
131
146
  log.warn({ parentSessionId }, 'Subagent finished but parent session not found');
132
147
  return;
133
148
  }
134
149
  const requestId = `subagent-notify-${Date.now()}`;
135
- const enqueueResult = parentSession.enqueueMessage(message, [], sendToClient, requestId);
150
+ // Store structured notification data in the DB for history reconstruction
151
+ const metadata = { subagentNotification: notification };
152
+ const enqueueResult = parentSession.enqueueMessage(message, [], sendToClient, requestId, undefined, undefined, metadata);
136
153
  if (enqueueResult.rejected) {
137
154
  log.warn({ parentSessionId }, 'Parent session queue full, dropping subagent notification');
138
155
  return;
139
156
  }
140
157
  if (!enqueueResult.queued) {
141
158
  // Parent is idle — send directly.
142
- const messageId = parentSession.persistUserMessage(message, []);
159
+ const messageId = parentSession.persistUserMessage(message, [], undefined, metadata);
143
160
  parentSession.runAgentLoop(message, messageId, sendToClient).catch((err) => {
144
161
  log.error({ parentSessionId, err }, 'Failed to process subagent notification in parent');
145
162
  });
@@ -330,6 +347,16 @@ export class DaemonServer {
330
347
  },
331
348
  'secret-allowlist.json': () => {
332
349
  resetAllowlist();
350
+ try {
351
+ const errors = validateAllowlistFile();
352
+ if (errors && errors.length > 0) {
353
+ for (const e of errors) {
354
+ log.warn({ index: e.index, pattern: e.pattern }, `Invalid regex in secret-allowlist.json: ${e.message}`);
355
+ }
356
+ }
357
+ } catch (err) {
358
+ log.warn({ err }, 'Failed to validate secret-allowlist.json');
359
+ }
333
360
  },
334
361
  };
335
362
 
@@ -381,6 +408,7 @@ export class DaemonServer {
381
408
  this.broadcast({
382
409
  type: 'daemon_status',
383
410
  httpPort: port,
411
+ version: daemonVersion,
384
412
  });
385
413
  }
386
414
 
@@ -744,10 +772,7 @@ export class DaemonServer {
744
772
  ('sessionId' in msg && typeof msgRecord.sessionId === 'string'
745
773
  ? msgRecord.sessionId as string
746
774
  : undefined) ?? this.socketToSession.get(socket);
747
- // Resolve assistantId from the session if available; fall back to daemon default.
748
- const socketSession = sessionId ? this.sessions.get(sessionId) : undefined;
749
- const assistantId = socketSession?.assistantId ?? this.assistantId;
750
- this.publishAssistantEvent(msg, sessionId, assistantId);
775
+ this.publishAssistantEvent(msg, sessionId, this.assistantId);
751
776
  }
752
777
 
753
778
  broadcast(msg: ServerMessage, excludeSocket?: net.Socket): void {
@@ -763,10 +788,7 @@ export class DaemonServer {
763
788
  ('sessionId' in msg && typeof msgRecord.sessionId === 'string'
764
789
  ? msgRecord.sessionId as string
765
790
  : undefined) ?? (excludeSocket ? this.socketToSession.get(excludeSocket) : undefined);
766
- // Resolve assistantId from the origin session if available; fall back to daemon default.
767
- const originSession = sessionId ? this.sessions.get(sessionId) : undefined;
768
- const assistantId = originSession?.assistantId ?? this.assistantId;
769
- this.publishAssistantEvent(msg, sessionId, assistantId);
791
+ this.publishAssistantEvent(msg, sessionId, this.assistantId);
770
792
  }
771
793
 
772
794
  /**
@@ -797,6 +819,7 @@ export class DaemonServer {
797
819
  this.send(socket, {
798
820
  type: 'daemon_status',
799
821
  httpPort: this.httpPort,
822
+ version: daemonVersion,
800
823
  });
801
824
  return;
802
825
  }
@@ -815,6 +838,7 @@ export class DaemonServer {
815
838
  this.send(socket, {
816
839
  type: 'daemon_status',
817
840
  httpPort: this.httpPort,
841
+ version: daemonVersion,
818
842
  });
819
843
  }
820
844
 
@@ -987,14 +1011,11 @@ export class DaemonServer {
987
1011
  throw new Error('Session is already processing a message');
988
1012
  }
989
1013
 
990
- // Set the session identity AFTER the isProcessing check so a rejected
991
- // request doesn't mutate the session state visible to an in-flight request.
992
- session.setAssistantId('self');
993
1014
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
994
1015
 
995
1016
  // Resolve attachment IDs to full attachment data for the session
996
1017
  const attachments = attachmentIds
997
- ? attachmentsStore.getAttachmentsByIds('self', attachmentIds).map((a) => ({
1018
+ ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
998
1019
  id: a.id,
999
1020
  filename: a.originalFilename,
1000
1021
  mimeType: a.mimeType,
@@ -1002,10 +1023,32 @@ export class DaemonServer {
1002
1023
  }))
1003
1024
  : [];
1004
1025
 
1005
- // persistUserMessage throws if the session is busy or persistence fails
1026
+ // Persist the user message immediately after the isProcessing() guard.
1027
+ // This synchronously sets session.processing = true, closing the race
1028
+ // window that previously existed between the guard and the async bridge
1029
+ // check (two concurrent requests could both pass isProcessing() and
1030
+ // race into message handling).
1006
1031
  const requestId = crypto.randomUUID();
1007
1032
  const messageId = session.persistUserMessage(content, attachments, requestId);
1008
1033
 
1034
+ // Now that the processing lock is held, check the call-answer bridge.
1035
+ let bridgeHandled = false;
1036
+ try {
1037
+ const bridgeResult = await tryHandlePendingCallAnswer(conversationId, content, messageId);
1038
+ bridgeHandled = bridgeResult.handled;
1039
+ } catch (err) {
1040
+ log.warn({ err, conversationId }, 'Call-answer bridge check failed (non-fatal), proceeding with agent loop');
1041
+ }
1042
+
1043
+ if (bridgeHandled) {
1044
+ // The message was consumed by the call system. Release the session.
1045
+ resetSessionProcessingState(session);
1046
+ // Drain any queued messages that arrived while processing was true.
1047
+ session.drainQueue('loop_complete');
1048
+ log.info({ conversationId, messageId }, 'User message consumed by call-answer bridge, skipping agent loop');
1049
+ return { messageId };
1050
+ }
1051
+
1009
1052
  // Fire-and-forget the agent loop. Errors are logged but do not
1010
1053
  // affect the HTTP response (the client polls GET /messages).
1011
1054
  session.runAgentLoop(content, messageId, () => {}).catch((err) => {
@@ -1039,14 +1082,11 @@ export class DaemonServer {
1039
1082
  throw new Error('Session is already processing a message');
1040
1083
  }
1041
1084
 
1042
- // Set the session identity AFTER the isProcessing check so a rejected
1043
- // request doesn't mutate the session state visible to an in-flight request.
1044
- session.setAssistantId('self');
1045
1085
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
1046
1086
 
1047
1087
  // Resolve attachment IDs to full attachment data for the session
1048
1088
  const attachments = attachmentIds
1049
- ? attachmentsStore.getAttachmentsByIds('self', attachmentIds).map((a) => ({
1089
+ ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
1050
1090
  id: a.id,
1051
1091
  filename: a.originalFilename,
1052
1092
  mimeType: a.mimeType,
@@ -1054,12 +1094,74 @@ export class DaemonServer {
1054
1094
  }))
1055
1095
  : [];
1056
1096
 
1057
- const messageId = await session.processMessage(content, attachments, () => {}, crypto.randomUUID());
1097
+ // Resolve slash commands before persistence (synchronous no race window).
1098
+ const slashResult = resolveSlash(content);
1099
+
1100
+ // Unknown slash command — persist the exchange (user + assistant) and
1101
+ // return immediately. This path doesn't set processing=true since no
1102
+ // agent loop runs, so there is no race concern.
1103
+ if (slashResult.kind === 'unknown') {
1104
+ const userMsg = createUserMessage(content, attachments);
1105
+ const persisted = conversationStore.addMessage(
1106
+ conversationId,
1107
+ 'user',
1108
+ JSON.stringify(userMsg.content),
1109
+ );
1110
+ session.getMessages().push(userMsg);
1111
+
1112
+ const assistantMsg = createAssistantMessage(slashResult.message);
1113
+ conversationStore.addMessage(
1114
+ conversationId,
1115
+ 'assistant',
1116
+ JSON.stringify(assistantMsg.content),
1117
+ );
1118
+ session.getMessages().push(assistantMsg);
1119
+ return { messageId: persisted.id };
1120
+ }
1058
1121
 
1059
- if (!messageId) {
1060
- throw new Error('Failed to persist user message');
1122
+ const resolvedContent = slashResult.content;
1123
+
1124
+ // Preactivate skill tools when slash resolution identifies a known skill
1125
+ if (slashResult.kind === 'rewritten') {
1126
+ (session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = [slashResult.skillId];
1127
+ }
1128
+
1129
+ // Persist the user message immediately after the isProcessing() guard.
1130
+ // This synchronously sets session.processing = true, closing the race
1131
+ // window that previously existed between the guard and the async bridge
1132
+ // check.
1133
+ const requestId = crypto.randomUUID();
1134
+ let messageId: string;
1135
+ try {
1136
+ messageId = session.persistUserMessage(resolvedContent, attachments, requestId);
1137
+ } catch (err) {
1138
+ // runAgentLoop never ran, so its finally block won't clear this
1139
+ (session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
1140
+ throw err;
1061
1141
  }
1062
1142
 
1143
+ // Now that the processing lock is held, check the call-answer bridge.
1144
+ let bridgeHandled = false;
1145
+ try {
1146
+ const bridgeResult = await tryHandlePendingCallAnswer(conversationId, content, messageId);
1147
+ bridgeHandled = bridgeResult.handled;
1148
+ } catch (err) {
1149
+ log.warn({ err, conversationId }, 'Call-answer bridge check failed (non-fatal), proceeding with agent loop');
1150
+ }
1151
+
1152
+ if (bridgeHandled) {
1153
+ // The message was consumed by the call system. Release the session.
1154
+ (session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
1155
+ resetSessionProcessingState(session);
1156
+ // Drain any queued messages that arrived while processing was true.
1157
+ session.drainQueue('loop_complete');
1158
+ log.info({ conversationId, messageId }, 'User message consumed by call-answer bridge, skipping agent loop');
1159
+ return { messageId };
1160
+ }
1161
+
1162
+ // Run the agent loop (blocking — the channel inbound endpoint needs the reply).
1163
+ await session.runAgentLoop(resolvedContent, messageId, () => {});
1164
+
1063
1165
  return { messageId };
1064
1166
  }
1065
1167
 
@@ -1071,7 +1173,7 @@ export class DaemonServer {
1071
1173
  getOrCreateSession: (conversationId) =>
1072
1174
  this.getOrCreateSession(conversationId),
1073
1175
  resolveAttachments: (attachmentIds) =>
1074
- attachmentsStore.getAttachmentsByIds('self', attachmentIds).map((a) => ({
1176
+ attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
1075
1177
  id: a.id,
1076
1178
  filename: a.originalFilename,
1077
1179
  mimeType: a.mimeType,
@@ -1081,3 +1183,18 @@ export class DaemonServer {
1081
1183
  }
1082
1184
 
1083
1185
  }
1186
+
1187
+ /**
1188
+ * Reset the processing state set by `persistUserMessage` when the agent loop
1189
+ * is intentionally skipped (e.g. call-answer bridge consumed the message).
1190
+ */
1191
+ function resetSessionProcessingState(session: Session): void {
1192
+ const s = session as unknown as {
1193
+ processing: boolean;
1194
+ abortController: AbortController | null;
1195
+ currentRequestId: string | undefined;
1196
+ };
1197
+ s.processing = false;
1198
+ s.abortController = null;
1199
+ s.currentRequestId = undefined;
1200
+ }