@vellumai/assistant 0.3.4 → 0.3.6

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 (506) hide show
  1. package/Dockerfile +2 -0
  2. package/README.md +88 -2
  3. package/eslint.config.mjs +31 -0
  4. package/package.json +1 -1
  5. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  6. package/scripts/ipc/generate-swift.ts +31 -2
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
  8. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  9. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
  10. package/src/__tests__/approval-message-composer.test.ts +253 -0
  11. package/src/__tests__/browser-manager.test.ts +1 -0
  12. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  13. package/src/__tests__/call-domain.test.ts +12 -2
  14. package/src/__tests__/call-orchestrator.test.ts +799 -249
  15. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  16. package/src/__tests__/call-recovery.test.ts +3 -0
  17. package/src/__tests__/call-routes-http.test.ts +32 -2
  18. package/src/__tests__/call-store.test.ts +3 -0
  19. package/src/__tests__/channel-approval-routes.test.ts +1277 -98
  20. package/src/__tests__/channel-approval.test.ts +37 -0
  21. package/src/__tests__/channel-approvals.test.ts +36 -50
  22. package/src/__tests__/channel-guardian.test.ts +630 -22
  23. package/src/__tests__/channel-readiness-service.test.ts +324 -0
  24. package/src/__tests__/checker.test.ts +14 -7
  25. package/src/__tests__/clarification-resolver.test.ts +44 -24
  26. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  27. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  28. package/src/__tests__/config-schema.test.ts +14 -8
  29. package/src/__tests__/context-window-manager.test.ts +30 -2
  30. package/src/__tests__/contradiction-checker.test.ts +20 -5
  31. package/src/__tests__/credential-security-invariants.test.ts +7 -2
  32. package/src/__tests__/daemon-lifecycle.test.ts +13 -12
  33. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  34. package/src/__tests__/dictation-mode-detection.test.ts +63 -0
  35. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  36. package/src/__tests__/entity-search.test.ts +615 -0
  37. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  38. package/src/__tests__/guardian-action-store.test.ts +123 -0
  39. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  40. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  41. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  42. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  43. package/src/__tests__/handlers-twilio-config.test.ts +533 -0
  44. package/src/__tests__/intent-routing.test.ts +2 -0
  45. package/src/__tests__/ipc-snapshot.test.ts +291 -1
  46. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  47. package/src/__tests__/messaging-send-tool.test.ts +65 -0
  48. package/src/__tests__/model-intents.test.ts +96 -0
  49. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  50. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  51. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  52. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  53. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  54. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  55. package/src/__tests__/qdrant-manager.test.ts +27 -20
  56. package/src/__tests__/relay-server.test.ts +779 -40
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +6 -0
  58. package/src/__tests__/run-orchestrator.test.ts +42 -4
  59. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  60. package/src/__tests__/runtime-runs.test.ts +16 -0
  61. package/src/__tests__/schedule-store.test.ts +18 -4
  62. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  63. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  64. package/src/__tests__/session-agent-loop.test.ts +857 -0
  65. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  66. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  67. package/src/__tests__/session-profile-injection.test.ts +6 -0
  68. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  69. package/src/__tests__/session-queue.test.ts +6 -0
  70. package/src/__tests__/session-runtime-assembly.test.ts +321 -13
  71. package/src/__tests__/session-slash-known.test.ts +6 -0
  72. package/src/__tests__/session-slash-queue.test.ts +6 -0
  73. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  74. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  75. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  76. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  77. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  78. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  79. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  80. package/src/__tests__/skills.test.ts +2 -0
  81. package/src/__tests__/sms-messaging-provider.test.ts +126 -0
  82. package/src/__tests__/starter-task-flow.test.ts +2 -0
  83. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  84. package/src/__tests__/system-prompt.test.ts +2 -0
  85. package/src/__tests__/task-management-tools.test.ts +2 -2
  86. package/src/__tests__/task-runner.test.ts +14 -4
  87. package/src/__tests__/terminal-tools.test.ts +25 -19
  88. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  89. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  90. package/src/__tests__/tool-executor.test.ts +23 -24
  91. package/src/__tests__/trust-store.test.ts +3 -3
  92. package/src/__tests__/twilio-rest.test.ts +29 -0
  93. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  94. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  95. package/src/__tests__/twilio-routes.test.ts +167 -11
  96. package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
  97. package/src/__tests__/user-reference.test.ts +2 -0
  98. package/src/__tests__/voice-quality.test.ts +222 -0
  99. package/src/__tests__/web-search.test.ts +46 -30
  100. package/src/__tests__/work-item-output.test.ts +110 -0
  101. package/src/agent/loop.ts +1 -1
  102. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  103. package/src/amazon/client.ts +1418 -0
  104. package/src/amazon/request-extractor.ts +135 -0
  105. package/src/amazon/session.ts +109 -0
  106. package/src/autonomy/autonomy-store.ts +5 -5
  107. package/src/browser-extension-relay/client.ts +124 -0
  108. package/src/browser-extension-relay/protocol.ts +63 -0
  109. package/src/browser-extension-relay/server.ts +177 -0
  110. package/src/bundler/app-bundler.ts +3 -3
  111. package/src/bundler/bundle-signer.ts +1 -1
  112. package/src/bundler/signature-verifier.ts +1 -1
  113. package/src/calls/call-conversation-messages.ts +33 -0
  114. package/src/calls/call-domain.ts +114 -10
  115. package/src/calls/call-orchestrator.ts +268 -59
  116. package/src/calls/call-pointer-messages.ts +53 -0
  117. package/src/calls/call-recovery.ts +3 -8
  118. package/src/calls/call-store.ts +69 -87
  119. package/src/calls/elevenlabs-config.ts +3 -2
  120. package/src/calls/guardian-action-sweep.ts +105 -0
  121. package/src/calls/guardian-dispatch.ts +203 -0
  122. package/src/calls/guardian-question-copy.ts +133 -0
  123. package/src/calls/relay-server.ts +466 -8
  124. package/src/calls/speaker-identification.ts +1 -1
  125. package/src/calls/twilio-config.ts +22 -14
  126. package/src/calls/twilio-provider.ts +6 -4
  127. package/src/calls/twilio-rest.ts +308 -7
  128. package/src/calls/twilio-routes.ts +65 -12
  129. package/src/calls/types.ts +3 -1
  130. package/src/channels/types.ts +25 -0
  131. package/src/cli/amazon.ts +815 -0
  132. package/src/cli/config-commands.ts +2 -2
  133. package/src/cli/core-commands.ts +4 -3
  134. package/src/cli/influencer.ts +244 -0
  135. package/src/cli/map.ts +89 -6
  136. package/src/cli.ts +1 -1
  137. package/src/config/agent-schema.ts +171 -0
  138. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  139. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  140. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  141. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  142. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  143. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  144. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  145. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  146. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  147. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  148. package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
  149. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
  150. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
  151. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  152. package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
  153. package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
  154. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  155. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  156. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  157. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  158. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  159. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  160. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  161. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +259 -0
  162. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  163. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
  164. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
  165. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
  166. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
  167. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
  168. package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
  169. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
  170. package/src/config/bundled-skills/messaging/SKILL.md +33 -8
  171. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  172. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
  174. package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
  175. package/src/config/bundled-skills/twitter/SKILL.md +19 -3
  176. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  177. package/src/config/bundled-tool-registry.ts +310 -0
  178. package/src/config/calls-schema.ts +181 -0
  179. package/src/config/core-schema.ts +309 -0
  180. package/src/config/defaults.ts +28 -3
  181. package/src/config/env-registry.ts +162 -0
  182. package/src/config/env.ts +175 -0
  183. package/src/config/loader.ts +6 -6
  184. package/src/config/memory-schema.ts +528 -0
  185. package/src/config/sandbox-schema.ts +55 -0
  186. package/src/config/schema.ts +158 -1133
  187. package/src/config/skill-state.ts +1 -1
  188. package/src/config/skills-schema.ts +32 -0
  189. package/src/config/skills.ts +35 -24
  190. package/src/config/system-prompt.ts +131 -56
  191. package/src/config/templates/IDENTITY.md +2 -2
  192. package/src/config/templates/SOUL.md +1 -1
  193. package/src/config/types.ts +1 -0
  194. package/src/config/user-reference.ts +4 -9
  195. package/src/config/vellum-skills/catalog.json +6 -7
  196. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  197. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
  198. package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
  199. package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
  200. package/src/context/window-manager.ts +27 -7
  201. package/src/daemon/approval-generators.ts +186 -0
  202. package/src/daemon/approved-devices-store.ts +140 -0
  203. package/src/daemon/assistant-attachments.ts +1 -1
  204. package/src/daemon/classifier.ts +35 -32
  205. package/src/daemon/config-watcher.ts +1 -1
  206. package/src/daemon/daemon-control.ts +217 -0
  207. package/src/daemon/handlers/apps.ts +2 -3
  208. package/src/daemon/handlers/config-channels.ts +158 -0
  209. package/src/daemon/handlers/config-inbox.ts +540 -0
  210. package/src/daemon/handlers/config-ingress.ts +231 -0
  211. package/src/daemon/handlers/config-integrations.ts +258 -0
  212. package/src/daemon/handlers/config-model.ts +143 -0
  213. package/src/daemon/handlers/config-parental.ts +163 -0
  214. package/src/daemon/handlers/config-scheduling.ts +172 -0
  215. package/src/daemon/handlers/config-slack.ts +92 -0
  216. package/src/daemon/handlers/config-telegram.ts +301 -0
  217. package/src/daemon/handlers/config-tools.ts +177 -0
  218. package/src/daemon/handlers/config-trust.ts +104 -0
  219. package/src/daemon/handlers/config-twilio.ts +1080 -0
  220. package/src/daemon/handlers/config.ts +53 -1689
  221. package/src/daemon/handlers/diagnostics.ts +1 -1
  222. package/src/daemon/handlers/dictation.ts +180 -0
  223. package/src/daemon/handlers/documents.ts +18 -32
  224. package/src/daemon/handlers/identity.ts +14 -23
  225. package/src/daemon/handlers/index.ts +11 -0
  226. package/src/daemon/handlers/misc.ts +3 -5
  227. package/src/daemon/handlers/pairing.ts +98 -0
  228. package/src/daemon/handlers/sessions.ts +56 -5
  229. package/src/daemon/handlers/shared.ts +6 -1
  230. package/src/daemon/handlers/skills.ts +1 -1
  231. package/src/daemon/handlers/twitter-auth.ts +2 -0
  232. package/src/daemon/handlers/work-items.ts +17 -9
  233. package/src/daemon/handlers/workspace-files.ts +4 -3
  234. package/src/daemon/install-cli-launchers.ts +113 -0
  235. package/src/daemon/ipc-contract/apps.ts +356 -0
  236. package/src/daemon/ipc-contract/browser.ts +74 -0
  237. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  238. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  239. package/src/daemon/ipc-contract/documents.ts +74 -0
  240. package/src/daemon/ipc-contract/inbox.ts +209 -0
  241. package/src/daemon/ipc-contract/integrations.ts +284 -0
  242. package/src/daemon/ipc-contract/memory.ts +48 -0
  243. package/src/daemon/ipc-contract/messages.ts +211 -0
  244. package/src/daemon/ipc-contract/pairing.ts +45 -0
  245. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  246. package/src/daemon/ipc-contract/schedules.ts +97 -0
  247. package/src/daemon/ipc-contract/sessions.ts +315 -0
  248. package/src/daemon/ipc-contract/shared.ts +42 -0
  249. package/src/daemon/ipc-contract/skills.ts +120 -0
  250. package/src/daemon/ipc-contract/subagents.ts +58 -0
  251. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  252. package/src/daemon/ipc-contract/trust.ts +60 -0
  253. package/src/daemon/ipc-contract/work-items.ts +225 -0
  254. package/src/daemon/ipc-contract/workspace.ts +113 -0
  255. package/src/daemon/ipc-contract-inventory.json +70 -0
  256. package/src/daemon/ipc-contract-inventory.ts +55 -29
  257. package/src/daemon/ipc-contract.ts +229 -2426
  258. package/src/daemon/ipc-protocol.ts +1 -1
  259. package/src/daemon/ipc-validate.ts +7 -0
  260. package/src/daemon/lifecycle.ts +97 -377
  261. package/src/daemon/pairing-store.ts +177 -0
  262. package/src/daemon/providers-setup.ts +43 -0
  263. package/src/daemon/ride-shotgun-handler.ts +68 -3
  264. package/src/daemon/server.ts +66 -46
  265. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  266. package/src/daemon/session-agent-loop.ts +117 -275
  267. package/src/daemon/session-dynamic-profile.ts +1 -1
  268. package/src/daemon/session-history.ts +1 -1
  269. package/src/daemon/session-media-retry.ts +1 -1
  270. package/src/daemon/session-messaging.ts +37 -2
  271. package/src/daemon/session-notifiers.ts +5 -25
  272. package/src/daemon/session-process.ts +99 -59
  273. package/src/daemon/session-queue-manager.ts +96 -4
  274. package/src/daemon/session-runtime-assembly.ts +199 -10
  275. package/src/daemon/session-surfaces.ts +19 -4
  276. package/src/daemon/session-tool-setup.ts +30 -30
  277. package/src/daemon/session-workspace.ts +1 -1
  278. package/src/daemon/session.ts +35 -2
  279. package/src/daemon/shutdown-handlers.ts +122 -0
  280. package/src/daemon/trace-emitter.ts +1 -1
  281. package/src/daemon/watch-handler.ts +36 -33
  282. package/src/doordash/cart-queries.ts +787 -0
  283. package/src/doordash/client.ts +144 -127
  284. package/src/doordash/order-queries.ts +85 -0
  285. package/src/doordash/queries.ts +10 -1308
  286. package/src/doordash/search-queries.ts +203 -0
  287. package/src/doordash/session.ts +3 -2
  288. package/src/doordash/store-queries.ts +246 -0
  289. package/src/doordash/types.ts +367 -0
  290. package/src/email/providers/agentmail.ts +2 -1
  291. package/src/email/providers/index.ts +3 -2
  292. package/src/email/service.ts +3 -2
  293. package/src/errors.ts +43 -0
  294. package/src/home-base/prebuilt/seed.ts +1 -1
  295. package/src/hooks/cli.ts +6 -5
  296. package/src/hooks/config.ts +6 -8
  297. package/src/hooks/discovery.ts +6 -5
  298. package/src/hooks/manager.ts +4 -3
  299. package/src/hooks/runner.ts +2 -2
  300. package/src/hooks/templates.ts +5 -5
  301. package/src/inbound/public-ingress-urls.ts +6 -4
  302. package/src/index.ts +4 -2
  303. package/src/influencer/client.ts +1104 -0
  304. package/src/instrument.ts +4 -3
  305. package/src/logfire.ts +4 -3
  306. package/src/memory/admin.ts +25 -35
  307. package/src/memory/attachments-store.ts +4 -7
  308. package/src/memory/channel-delivery-store.ts +30 -1
  309. package/src/memory/channel-guardian-store.ts +202 -2
  310. package/src/memory/clarification-resolver.ts +37 -33
  311. package/src/memory/conflict-store.ts +67 -61
  312. package/src/memory/contradiction-checker.ts +141 -117
  313. package/src/memory/conversation-store.ts +335 -51
  314. package/src/memory/db-connection.ts +27 -4
  315. package/src/memory/db-init.ts +265 -4
  316. package/src/memory/db.ts +14 -1
  317. package/src/memory/embedding-backend.ts +27 -5
  318. package/src/memory/embedding-ollama.ts +2 -1
  319. package/src/memory/entity-extractor.ts +38 -35
  320. package/src/memory/guardian-action-store.ts +430 -0
  321. package/src/memory/inbox-escalation-projection.ts +59 -0
  322. package/src/memory/inbox-thread-store.ts +218 -0
  323. package/src/memory/ingress-invite-store.ts +338 -0
  324. package/src/memory/ingress-member-store.ts +350 -0
  325. package/src/memory/items-extractor.ts +91 -97
  326. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  327. package/src/memory/job-handlers/media-processing.ts +69 -0
  328. package/src/memory/job-handlers/summarization.ts +32 -26
  329. package/src/memory/job-utils.ts +3 -10
  330. package/src/memory/jobs-store.ts +8 -10
  331. package/src/memory/jobs-worker.ts +55 -36
  332. package/src/memory/media-store.ts +759 -0
  333. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  334. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  335. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  336. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  337. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  338. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  339. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  340. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  341. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  342. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  343. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  344. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  345. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  346. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  347. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  348. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  349. package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
  350. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  351. package/src/memory/migrations/index.ts +24 -0
  352. package/src/memory/migrations/registry.ts +79 -0
  353. package/src/memory/migrations/validate-migration-state.ts +69 -0
  354. package/src/memory/qdrant-manager.ts +49 -8
  355. package/src/memory/query-builder.ts +1 -1
  356. package/src/memory/raw-query.ts +119 -0
  357. package/src/memory/recall-cache.ts +4 -1
  358. package/src/memory/retriever.ts +165 -47
  359. package/src/memory/schema-migration.ts +25 -984
  360. package/src/memory/schema.ts +228 -7
  361. package/src/memory/search/entity.ts +205 -31
  362. package/src/memory/search/lexical.ts +81 -52
  363. package/src/memory/search/ranking.ts +27 -23
  364. package/src/memory/search/semantic.ts +157 -19
  365. package/src/memory/search/types.ts +24 -0
  366. package/src/memory/shared-app-links-store.ts +4 -5
  367. package/src/memory/validation.ts +19 -0
  368. package/src/messaging/draft-store.ts +5 -6
  369. package/src/messaging/provider-types.ts +2 -0
  370. package/src/messaging/providers/sms/adapter.ts +201 -0
  371. package/src/messaging/providers/sms/client.ts +93 -0
  372. package/src/messaging/providers/sms/types.ts +7 -0
  373. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  374. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  375. package/src/messaging/providers/whatsapp/client.ts +67 -0
  376. package/src/messaging/style-analyzer.ts +5 -4
  377. package/src/messaging/thread-summarizer.ts +61 -69
  378. package/src/messaging/triage-engine.ts +62 -71
  379. package/src/migrations/config-merge.ts +53 -0
  380. package/src/migrations/data-layout.ts +68 -0
  381. package/src/migrations/data-merge.ts +33 -0
  382. package/src/migrations/hooks-merge.ts +90 -0
  383. package/src/migrations/index.ts +6 -0
  384. package/src/migrations/log.ts +23 -0
  385. package/src/migrations/skills-merge.ts +33 -0
  386. package/src/migrations/workspace-layout.ts +79 -0
  387. package/src/permissions/checker.ts +133 -11
  388. package/src/permissions/prompter.ts +14 -0
  389. package/src/permissions/shell-identity.ts +31 -1
  390. package/src/permissions/trust-store.ts +21 -1
  391. package/src/providers/anthropic/client.ts +4 -4
  392. package/src/providers/failover.ts +2 -2
  393. package/src/providers/model-intents.ts +70 -0
  394. package/src/providers/ollama/client.ts +2 -1
  395. package/src/providers/provider-send-message.ts +176 -0
  396. package/src/providers/registry.ts +71 -30
  397. package/src/providers/retry.ts +35 -1
  398. package/src/providers/types.ts +12 -1
  399. package/src/runtime/approval-conversation-turn.ts +97 -0
  400. package/src/runtime/approval-message-composer.ts +253 -0
  401. package/src/runtime/channel-approval-parser.ts +36 -2
  402. package/src/runtime/channel-approvals.ts +11 -24
  403. package/src/runtime/channel-guardian-service.ts +88 -21
  404. package/src/runtime/channel-readiness-service.ts +418 -0
  405. package/src/runtime/channel-readiness-types.ts +35 -0
  406. package/src/runtime/channel-retry-sweep.ts +184 -0
  407. package/src/runtime/guardian-context-resolver.ts +108 -0
  408. package/src/runtime/http-server.ts +275 -717
  409. package/src/runtime/http-types.ts +59 -3
  410. package/src/runtime/middleware/auth.ts +116 -0
  411. package/src/runtime/middleware/error-handler.ts +33 -0
  412. package/src/runtime/middleware/twilio-validation.ts +127 -0
  413. package/src/runtime/routes/app-routes.ts +1 -1
  414. package/src/runtime/routes/call-routes.ts +51 -7
  415. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  416. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  417. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  418. package/src/runtime/routes/channel-route-shared.ts +144 -0
  419. package/src/runtime/routes/channel-routes.ts +32 -1588
  420. package/src/runtime/routes/conversation-routes.ts +50 -7
  421. package/src/runtime/routes/events-routes.ts +2 -2
  422. package/src/runtime/routes/identity-routes.ts +126 -0
  423. package/src/runtime/routes/pairing-routes.ts +143 -0
  424. package/src/runtime/routes/run-routes.ts +15 -1
  425. package/src/runtime/run-orchestrator.ts +86 -35
  426. package/src/schedule/schedule-store.ts +36 -32
  427. package/src/schedule/scheduler.ts +3 -3
  428. package/src/security/encrypted-store.ts +5 -7
  429. package/src/security/oauth2.ts +45 -15
  430. package/src/security/parental-control-store.ts +183 -0
  431. package/src/security/secret-allowlist.ts +4 -3
  432. package/src/security/secret-scanner.ts +5 -5
  433. package/src/security/secure-keys.ts +1 -1
  434. package/src/security/token-manager.ts +3 -2
  435. package/src/services/vercel-deploy.ts +6 -2
  436. package/src/skills/tool-manifest.ts +3 -3
  437. package/src/skills/vellum-catalog-remote.ts +75 -16
  438. package/src/slack/slack-webhook.ts +2 -1
  439. package/src/swarm/orchestrator.ts +92 -1
  440. package/src/swarm/router-planner.ts +6 -9
  441. package/src/swarm/worker-prompts.ts +9 -12
  442. package/src/tasks/task-compiler.ts +19 -28
  443. package/src/tasks/task-runner.ts +1 -1
  444. package/src/tools/assets/materialize.ts +2 -2
  445. package/src/tools/assets/search.ts +15 -14
  446. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  447. package/src/tools/browser/auto-navigate.ts +1 -0
  448. package/src/tools/browser/browser-execution.ts +10 -1
  449. package/src/tools/browser/browser-manager.ts +119 -4
  450. package/src/tools/browser/network-recorder.ts +5 -0
  451. package/src/tools/calls/call-start.ts +1 -0
  452. package/src/tools/credentials/broker.ts +11 -2
  453. package/src/tools/credentials/metadata-store.ts +18 -14
  454. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  455. package/src/tools/credentials/vault.ts +49 -23
  456. package/src/tools/execution-target.ts +11 -1
  457. package/src/tools/executor.ts +68 -9
  458. package/src/tools/host-terminal/cli-discover.ts +1 -1
  459. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  460. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  461. package/src/tools/network/script-proxy/server.ts +1 -1
  462. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  463. package/src/tools/network/web-fetch.ts +18 -2
  464. package/src/tools/network/web-search.ts +8 -4
  465. package/src/tools/reminder/reminder-store.ts +14 -15
  466. package/src/tools/schedule/create.ts +1 -0
  467. package/src/tools/schedule/list.ts +2 -1
  468. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  469. package/src/tools/skills/skill-script-runner.ts +24 -9
  470. package/src/tools/skills/skill-tool-factory.ts +1 -0
  471. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  472. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  473. package/src/tools/terminal/parser.ts +50 -0
  474. package/src/tools/types.ts +2 -0
  475. package/src/tools/watcher/delete.ts +6 -0
  476. package/src/tools/weather/service.ts +1 -1
  477. package/src/twitter/client.ts +190 -24
  478. package/src/twitter/router.ts +1 -1
  479. package/src/twitter/session.ts +4 -3
  480. package/src/util/clipboard.ts +1 -1
  481. package/src/util/errors.ts +65 -8
  482. package/src/util/fs.ts +40 -0
  483. package/src/util/json.ts +10 -0
  484. package/src/util/log-redact.ts +189 -0
  485. package/src/util/logger.ts +19 -17
  486. package/src/util/object.ts +3 -0
  487. package/src/util/platform.ts +105 -363
  488. package/src/util/pricing.ts +1 -1
  489. package/src/util/promise-guard.ts +1 -1
  490. package/src/util/retry.ts +19 -0
  491. package/src/util/row-mapper.ts +79 -0
  492. package/src/util/silently.ts +21 -0
  493. package/src/watcher/engine.ts +5 -1
  494. package/src/watcher/provider-types.ts +20 -0
  495. package/src/watcher/providers/github.ts +156 -0
  496. package/src/watcher/providers/gmail.ts +1 -0
  497. package/src/watcher/providers/google-calendar.ts +1 -0
  498. package/src/watcher/providers/linear.ts +460 -0
  499. package/src/watcher/providers/slack.ts +1 -0
  500. package/src/work-items/work-item-runner.ts +1 -1
  501. package/src/workspace/git-service.ts +1 -1
  502. package/src/workspace/provider-commit-message-generator.ts +51 -22
  503. package/src/__tests__/call-bridge.test.ts +0 -517
  504. package/src/__tests__/session-process-bridge.test.ts +0 -244
  505. package/src/calls/call-bridge.ts +0 -168
  506. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -0,0 +1,301 @@
1
+ import * as net from 'node:net';
2
+ import { getSecureKey, setSecureKey, deleteSecureKey } from '../../security/secure-keys.js';
3
+ import { upsertCredentialMetadata, deleteCredentialMetadata, getCredentialMetadata } from '../../tools/credentials/metadata-store.js';
4
+ import { triggerGatewayReconcile } from './config-ingress.js';
5
+ import { getIngressPublicBaseUrl } from '../../config/env.js';
6
+ import type { TelegramConfigRequest } from '../ipc-protocol.js';
7
+ import { log, defineHandlers, type HandlerContext } from './shared.js';
8
+
9
+ const TELEGRAM_BOT_TOKEN_IN_URL_PATTERN = /\/bot\d{8,10}:[A-Za-z0-9_-]{30,120}\//g;
10
+ const TELEGRAM_BOT_TOKEN_PATTERN = /(?<![A-Za-z0-9_])\d{8,10}:[A-Za-z0-9_-]{30,120}(?![A-Za-z0-9_])/g;
11
+
12
+ function redactTelegramBotTokens(value: string): string {
13
+ return value
14
+ .replace(TELEGRAM_BOT_TOKEN_IN_URL_PATTERN, '/bot[REDACTED]/')
15
+ .replace(TELEGRAM_BOT_TOKEN_PATTERN, '[REDACTED]');
16
+ }
17
+
18
+ export function summarizeTelegramError(err: unknown): string {
19
+ const parts: string[] = [];
20
+ if (err instanceof Error) {
21
+ parts.push(err.message);
22
+ } else {
23
+ parts.push(String(err));
24
+ }
25
+ const path = (err as { path?: unknown })?.path;
26
+ if (typeof path === 'string' && path.length > 0) {
27
+ parts.push(`path=${path}`);
28
+ }
29
+ const code = (err as { code?: unknown })?.code;
30
+ if (typeof code === 'string' && code.length > 0) {
31
+ parts.push(`code=${code}`);
32
+ }
33
+ return redactTelegramBotTokens(parts.join(' '));
34
+ }
35
+
36
+ export async function handleTelegramConfig(
37
+ msg: TelegramConfigRequest,
38
+ socket: net.Socket,
39
+ ctx: HandlerContext,
40
+ ): Promise<void> {
41
+ try {
42
+ if (msg.action === 'get') {
43
+ const hasBotToken = !!getSecureKey('credential:telegram:bot_token');
44
+ const hasWebhookSecret = !!getSecureKey('credential:telegram:webhook_secret');
45
+ const meta = getCredentialMetadata('telegram', 'bot_token');
46
+ const botUsername = meta?.accountInfo ?? undefined;
47
+ ctx.send(socket, {
48
+ type: 'telegram_config_response',
49
+ success: true,
50
+ hasBotToken,
51
+ botUsername,
52
+ connected: hasBotToken && hasWebhookSecret,
53
+ hasWebhookSecret,
54
+ });
55
+ } else if (msg.action === 'set') {
56
+ // Resolve token: prefer explicit msg.botToken, fall back to secure storage.
57
+ // Track provenance so we only rollback tokens that were freshly provided.
58
+ const isNewToken = !!msg.botToken;
59
+ const botToken = msg.botToken || getSecureKey('credential:telegram:bot_token');
60
+ if (!botToken) {
61
+ ctx.send(socket, {
62
+ type: 'telegram_config_response',
63
+ success: false,
64
+ hasBotToken: false,
65
+ connected: false,
66
+ hasWebhookSecret: false,
67
+ error: 'botToken is required for set action',
68
+ });
69
+ return;
70
+ }
71
+
72
+ // Validate token via Telegram getMe API
73
+ let botUsername: string;
74
+ try {
75
+ const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);
76
+ if (!res.ok) {
77
+ const body = await res.text();
78
+ ctx.send(socket, {
79
+ type: 'telegram_config_response',
80
+ success: false,
81
+ hasBotToken: false,
82
+ connected: false,
83
+ hasWebhookSecret: false,
84
+ error: `Telegram API validation failed: ${body}`,
85
+ });
86
+ return;
87
+ }
88
+ const data = await res.json() as { ok: boolean; result?: { username?: string } };
89
+ if (!data.ok || !data.result?.username) {
90
+ ctx.send(socket, {
91
+ type: 'telegram_config_response',
92
+ success: false,
93
+ hasBotToken: false,
94
+ connected: false,
95
+ hasWebhookSecret: false,
96
+ error: 'Telegram API returned unexpected response',
97
+ });
98
+ return;
99
+ }
100
+ botUsername = data.result.username;
101
+ } catch (err) {
102
+ const message = summarizeTelegramError(err);
103
+ ctx.send(socket, {
104
+ type: 'telegram_config_response',
105
+ success: false,
106
+ hasBotToken: false,
107
+ connected: false,
108
+ hasWebhookSecret: false,
109
+ error: `Failed to validate bot token: ${message}`,
110
+ });
111
+ return;
112
+ }
113
+
114
+ // Store bot token securely
115
+ const stored = setSecureKey('credential:telegram:bot_token', botToken);
116
+ if (!stored) {
117
+ ctx.send(socket, {
118
+ type: 'telegram_config_response',
119
+ success: false,
120
+ hasBotToken: false,
121
+ connected: false,
122
+ hasWebhookSecret: false,
123
+ error: 'Failed to store bot token in secure storage',
124
+ });
125
+ return;
126
+ }
127
+
128
+ // Store metadata with bot username
129
+ upsertCredentialMetadata('telegram', 'bot_token', {
130
+ accountInfo: botUsername,
131
+ });
132
+
133
+ // Ensure webhook secret exists (generate if missing)
134
+ let hasWebhookSecret = !!getSecureKey('credential:telegram:webhook_secret');
135
+ if (!hasWebhookSecret) {
136
+ const { randomUUID } = await import('node:crypto');
137
+ const webhookSecret = randomUUID();
138
+ const secretStored = setSecureKey('credential:telegram:webhook_secret', webhookSecret);
139
+ if (secretStored) {
140
+ upsertCredentialMetadata('telegram', 'webhook_secret', {});
141
+ hasWebhookSecret = true;
142
+ } else {
143
+ // Only roll back the bot token if it was freshly provided.
144
+ // When the token came from secure storage it was already valid
145
+ // configuration; deleting it would destroy working state.
146
+ if (isNewToken) {
147
+ deleteSecureKey('credential:telegram:bot_token');
148
+ deleteCredentialMetadata('telegram', 'bot_token');
149
+ }
150
+ ctx.send(socket, {
151
+ type: 'telegram_config_response',
152
+ success: false,
153
+ hasBotToken: !isNewToken,
154
+ connected: false,
155
+ hasWebhookSecret: false,
156
+ error: 'Failed to store webhook secret',
157
+ });
158
+ return;
159
+ }
160
+ } else {
161
+ // Self-heal: ensure metadata exists even when the secret was
162
+ // already present (covers previously lost/corrupted metadata).
163
+ upsertCredentialMetadata('telegram', 'webhook_secret', {});
164
+ }
165
+
166
+ ctx.send(socket, {
167
+ type: 'telegram_config_response',
168
+ success: true,
169
+ hasBotToken: true,
170
+ botUsername,
171
+ connected: true,
172
+ hasWebhookSecret,
173
+ });
174
+
175
+ // Trigger gateway reconcile so the webhook registration updates immediately
176
+ const effectiveUrl = getIngressPublicBaseUrl();
177
+ if (effectiveUrl) {
178
+ triggerGatewayReconcile(effectiveUrl);
179
+ }
180
+ } else if (msg.action === 'clear') {
181
+ // Deregister the Telegram webhook before deleting credentials.
182
+ // The gateway reconcile short-circuits when credentials are absent,
183
+ // so we must call the Telegram API directly while the token is still
184
+ // available.
185
+ const botToken = getSecureKey('credential:telegram:bot_token');
186
+ if (botToken) {
187
+ try {
188
+ await fetch(`https://api.telegram.org/bot${botToken}/deleteWebhook`);
189
+ } catch (err) {
190
+ log.warn(
191
+ { error: summarizeTelegramError(err) },
192
+ 'Failed to deregister Telegram webhook (proceeding with credential cleanup)',
193
+ );
194
+ }
195
+ }
196
+
197
+ deleteSecureKey('credential:telegram:bot_token');
198
+ deleteCredentialMetadata('telegram', 'bot_token');
199
+ deleteSecureKey('credential:telegram:webhook_secret');
200
+ deleteCredentialMetadata('telegram', 'webhook_secret');
201
+
202
+ ctx.send(socket, {
203
+ type: 'telegram_config_response',
204
+ success: true,
205
+ hasBotToken: false,
206
+ connected: false,
207
+ hasWebhookSecret: false,
208
+ });
209
+
210
+ // Trigger reconcile to deregister webhook
211
+ const effectiveUrl = getIngressPublicBaseUrl();
212
+ if (effectiveUrl) {
213
+ triggerGatewayReconcile(effectiveUrl);
214
+ }
215
+ } else if (msg.action === 'set_commands') {
216
+ const storedToken = getSecureKey('credential:telegram:bot_token');
217
+ if (!storedToken) {
218
+ ctx.send(socket, {
219
+ type: 'telegram_config_response',
220
+ success: false,
221
+ hasBotToken: false,
222
+ connected: false,
223
+ hasWebhookSecret: false,
224
+ error: 'Bot token not configured. Run set action first.',
225
+ });
226
+ return;
227
+ }
228
+
229
+ const commands = msg.commands ?? [
230
+ { command: 'new', description: 'Start a new conversation' },
231
+ { command: 'help', description: 'Show available commands' },
232
+ { command: 'guardian_verify', description: 'Verify your guardian identity' },
233
+ ];
234
+
235
+ try {
236
+ const res = await fetch(`https://api.telegram.org/bot${storedToken}/setMyCommands`, {
237
+ method: 'POST',
238
+ headers: { 'Content-Type': 'application/json' },
239
+ body: JSON.stringify({ commands }),
240
+ });
241
+ if (!res.ok) {
242
+ const body = await res.text();
243
+ ctx.send(socket, {
244
+ type: 'telegram_config_response',
245
+ success: false,
246
+ hasBotToken: true,
247
+ connected: !!getSecureKey('credential:telegram:webhook_secret'),
248
+ hasWebhookSecret: !!getSecureKey('credential:telegram:webhook_secret'),
249
+ error: `Failed to set bot commands: ${body}`,
250
+ });
251
+ return;
252
+ }
253
+ } catch (err) {
254
+ const message = summarizeTelegramError(err);
255
+ ctx.send(socket, {
256
+ type: 'telegram_config_response',
257
+ success: false,
258
+ hasBotToken: true,
259
+ connected: !!getSecureKey('credential:telegram:webhook_secret'),
260
+ hasWebhookSecret: !!getSecureKey('credential:telegram:webhook_secret'),
261
+ error: `Failed to set bot commands: ${message}`,
262
+ });
263
+ return;
264
+ }
265
+
266
+ const hasBotToken = !!getSecureKey('credential:telegram:bot_token');
267
+ const hasWebhookSecret = !!getSecureKey('credential:telegram:webhook_secret');
268
+ ctx.send(socket, {
269
+ type: 'telegram_config_response',
270
+ success: true,
271
+ hasBotToken,
272
+ connected: hasBotToken && hasWebhookSecret,
273
+ hasWebhookSecret,
274
+ });
275
+ } else {
276
+ ctx.send(socket, {
277
+ type: 'telegram_config_response',
278
+ success: false,
279
+ hasBotToken: false,
280
+ connected: false,
281
+ hasWebhookSecret: false,
282
+ error: `Unknown action: ${String((msg as unknown as Record<string, unknown>).action)}`,
283
+ });
284
+ }
285
+ } catch (err) {
286
+ const message = err instanceof Error ? err.message : String(err);
287
+ log.error({ err }, 'Failed to handle Telegram config');
288
+ ctx.send(socket, {
289
+ type: 'telegram_config_response',
290
+ success: false,
291
+ hasBotToken: false,
292
+ connected: false,
293
+ hasWebhookSecret: false,
294
+ error: message,
295
+ });
296
+ }
297
+ }
298
+
299
+ export const telegramHandlers = defineHandlers({
300
+ telegram_config: handleTelegramConfig,
301
+ });
@@ -0,0 +1,177 @@
1
+ import * as net from 'node:net';
2
+ import { join } from 'node:path';
3
+ import { classifyRisk, check, generateAllowlistOptions, generateScopeOptions } from '../../permissions/checker.js';
4
+ import { isSideEffectTool } from '../../tools/executor.js';
5
+ import { resolveExecutionTarget, type ManifestOverride } from '../../tools/execution-target.js';
6
+ import { getAllTools, getTool } from '../../tools/registry.js';
7
+ import { loadSkillCatalog } from '../../config/skills.js';
8
+ import { parseToolManifestFile } from '../../skills/tool-manifest.js';
9
+ import type { ToolPermissionSimulateRequest } from '../ipc-protocol.js';
10
+ import { log, defineHandlers, type HandlerContext } from './shared.js';
11
+
12
+ export function handleEnvVarsRequest(socket: net.Socket, ctx: HandlerContext): void {
13
+ const vars: Record<string, string> = {};
14
+ for (const [key, value] of Object.entries(process.env)) {
15
+ if (value !== undefined) vars[key] = value;
16
+ }
17
+ ctx.send(socket, { type: 'env_vars_response', vars });
18
+ }
19
+
20
+ /**
21
+ * Look up manifest metadata for a tool that isn't in the live registry.
22
+ * Searches all installed skills' TOOLS.json manifests for a matching tool name.
23
+ */
24
+ function resolveManifestOverride(toolName: string): ManifestOverride | undefined {
25
+ if (getTool(toolName)) return undefined;
26
+ try {
27
+ const catalog = loadSkillCatalog();
28
+ for (const skill of catalog) {
29
+ if (!skill.toolManifest?.present || !skill.toolManifest.valid) continue;
30
+ try {
31
+ const manifest = parseToolManifestFile(join(skill.directoryPath, 'TOOLS.json'));
32
+ const entry = manifest.tools.find((t) => t.name === toolName);
33
+ if (entry) {
34
+ return { risk: entry.risk, execution_target: entry.execution_target };
35
+ }
36
+ } catch {
37
+ // Skip unparseable manifests
38
+ }
39
+ }
40
+ } catch {
41
+ // Non-fatal
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ export async function handleToolPermissionSimulate(
47
+ msg: ToolPermissionSimulateRequest,
48
+ socket: net.Socket,
49
+ ctx: HandlerContext,
50
+ ): Promise<void> {
51
+ try {
52
+ if (!msg.toolName || typeof msg.toolName !== 'string') {
53
+ ctx.send(socket, {
54
+ type: 'tool_permission_simulate_response',
55
+ success: false,
56
+ error: 'toolName is required',
57
+ });
58
+ return;
59
+ }
60
+ if (!msg.input || typeof msg.input !== 'object') {
61
+ ctx.send(socket, {
62
+ type: 'tool_permission_simulate_response',
63
+ success: false,
64
+ error: 'input is required and must be an object',
65
+ });
66
+ return;
67
+ }
68
+
69
+ const workingDir = msg.workingDir ?? process.cwd();
70
+
71
+ // For unregistered skill tools, resolve manifest metadata so the simulation
72
+ // uses accurate risk/execution_target values instead of falling back to defaults.
73
+ const manifestOverride = resolveManifestOverride(msg.toolName);
74
+
75
+ const executionTarget = resolveExecutionTarget(msg.toolName, manifestOverride);
76
+ const policyContext = { executionTarget };
77
+
78
+ const riskLevel = await classifyRisk(msg.toolName, msg.input, workingDir, undefined, manifestOverride);
79
+ const result = await check(msg.toolName, msg.input, workingDir, policyContext, manifestOverride);
80
+
81
+ // Private-thread override: promote allow → prompt for side-effect tools
82
+ if (
83
+ msg.forcePromptSideEffects
84
+ && result.decision === 'allow'
85
+ && isSideEffectTool(msg.toolName, msg.input)
86
+ ) {
87
+ result.decision = 'prompt';
88
+ result.reason = 'Private thread: side-effect tools require explicit approval';
89
+ }
90
+
91
+ // Non-interactive override: convert prompt → deny
92
+ if (msg.isInteractive === false && result.decision === 'prompt') {
93
+ result.decision = 'deny';
94
+ result.reason = 'Non-interactive session: no client to approve prompt';
95
+ }
96
+
97
+ // When decision is prompt, generate the full payload the UI needs
98
+ let promptPayload: {
99
+ allowlistOptions: Array<{ label: string; description: string; pattern: string }>;
100
+ scopeOptions: Array<{ label: string; scope: string }>;
101
+ persistentDecisionsAllowed: boolean;
102
+ } | undefined;
103
+
104
+ if (result.decision === 'prompt') {
105
+ const allowlistOptions = await generateAllowlistOptions(msg.toolName, msg.input);
106
+ const scopeOptions = generateScopeOptions(workingDir, msg.toolName);
107
+ const persistentDecisionsAllowed = !(
108
+ msg.toolName === 'bash'
109
+ && msg.input.network_mode === 'proxied'
110
+ );
111
+ promptPayload = { allowlistOptions, scopeOptions, persistentDecisionsAllowed };
112
+ }
113
+
114
+ ctx.send(socket, {
115
+ type: 'tool_permission_simulate_response',
116
+ success: true,
117
+ decision: result.decision,
118
+ riskLevel,
119
+ reason: result.reason,
120
+ executionTarget,
121
+ matchedRuleId: result.matchedRule?.id,
122
+ promptPayload,
123
+ });
124
+ } catch (err) {
125
+ const message = err instanceof Error ? err.message : String(err);
126
+ log.error({ err }, 'Failed to simulate tool permission');
127
+ ctx.send(socket, {
128
+ type: 'tool_permission_simulate_response',
129
+ success: false,
130
+ error: message,
131
+ });
132
+ }
133
+ }
134
+
135
+ export function handleToolNamesList(socket: net.Socket, ctx: HandlerContext): void {
136
+ const tools = getAllTools();
137
+ const nameSet = new Set(tools.map((t) => t.name));
138
+ const schemas: Record<string, import('../ipc-contract.js').ToolInputSchema> = {};
139
+ for (const tool of tools) {
140
+ try {
141
+ const def = tool.getDefinition();
142
+ schemas[tool.name] = def.input_schema as import('../ipc-contract.js').ToolInputSchema;
143
+ } catch {
144
+ // Skip tools whose definitions can't be resolved
145
+ }
146
+ }
147
+
148
+ // Include tools from all installed skills, even those not currently
149
+ // activated in any session.
150
+ try {
151
+ const catalog = loadSkillCatalog();
152
+ for (const skill of catalog) {
153
+ if (!skill.toolManifest?.present || !skill.toolManifest.valid) continue;
154
+ try {
155
+ const manifest = parseToolManifestFile(join(skill.directoryPath, 'TOOLS.json'));
156
+ for (const entry of manifest.tools) {
157
+ if (nameSet.has(entry.name)) continue;
158
+ nameSet.add(entry.name);
159
+ schemas[entry.name] = entry.input_schema as unknown as import('../ipc-contract.js').ToolInputSchema;
160
+ }
161
+ } catch {
162
+ // Skip skills whose manifests can't be parsed
163
+ }
164
+ }
165
+ } catch {
166
+ // Non-fatal — fall back to registered tools only
167
+ }
168
+
169
+ const names = Array.from(nameSet).sort((a, b) => a.localeCompare(b));
170
+ ctx.send(socket, { type: 'tool_names_list_response', names, schemas });
171
+ }
172
+
173
+ export const toolHandlers = defineHandlers({
174
+ env_vars_request: (_msg, socket, ctx) => handleEnvVarsRequest(socket, ctx),
175
+ tool_permission_simulate: handleToolPermissionSimulate,
176
+ tool_names_list: (_msg, socket, ctx) => handleToolNamesList(socket, ctx),
177
+ });
@@ -0,0 +1,104 @@
1
+ import * as net from 'node:net';
2
+ import { addRule, removeRule, updateRule, getAllRules, acceptStarterBundle } from '../../permissions/trust-store.js';
3
+ import type {
4
+ AddTrustRule,
5
+ RemoveTrustRule,
6
+ UpdateTrustRule,
7
+ } from '../ipc-protocol.js';
8
+ import { log, defineHandlers, type HandlerContext } from './shared.js';
9
+
10
+ export function handleAddTrustRule(
11
+ msg: AddTrustRule,
12
+ _socket: net.Socket,
13
+ _ctx: HandlerContext,
14
+ ): void {
15
+ try {
16
+ const hasMetadata = msg.allowHighRisk != null
17
+ || msg.executionTarget != null;
18
+
19
+ addRule(
20
+ msg.toolName,
21
+ msg.pattern,
22
+ msg.scope,
23
+ msg.decision,
24
+ undefined, // priority — use default
25
+ hasMetadata
26
+ ? {
27
+ allowHighRisk: msg.allowHighRisk,
28
+ executionTarget: msg.executionTarget,
29
+ }
30
+ : undefined,
31
+ );
32
+ log.info({ toolName: msg.toolName, pattern: msg.pattern, scope: msg.scope, decision: msg.decision }, 'Trust rule added via client');
33
+ } catch (err) {
34
+ log.error({ err, toolName: msg.toolName, pattern: msg.pattern, scope: msg.scope }, 'Failed to add trust rule via client');
35
+ }
36
+ }
37
+
38
+ export function handleTrustRulesList(socket: net.Socket, ctx: HandlerContext): void {
39
+ const rules = getAllRules();
40
+ ctx.send(socket, { type: 'trust_rules_list_response', rules });
41
+ }
42
+
43
+ export function handleRemoveTrustRule(
44
+ msg: RemoveTrustRule,
45
+ _socket: net.Socket,
46
+ _ctx: HandlerContext,
47
+ ): void {
48
+ try {
49
+ const removed = removeRule(msg.id);
50
+ if (!removed) {
51
+ log.warn({ id: msg.id }, 'Trust rule not found for removal');
52
+ } else {
53
+ log.info({ id: msg.id }, 'Trust rule removed via client');
54
+ }
55
+ } catch (err) {
56
+ log.error({ err }, 'Failed to remove trust rule');
57
+ }
58
+ }
59
+
60
+ export function handleUpdateTrustRule(
61
+ msg: UpdateTrustRule,
62
+ _socket: net.Socket,
63
+ _ctx: HandlerContext,
64
+ ): void {
65
+ try {
66
+ updateRule(msg.id, {
67
+ tool: msg.tool,
68
+ pattern: msg.pattern,
69
+ scope: msg.scope,
70
+ decision: msg.decision,
71
+ priority: msg.priority,
72
+ });
73
+ log.info({ id: msg.id }, 'Trust rule updated via client');
74
+ } catch (err) {
75
+ log.error({ err }, 'Failed to update trust rule');
76
+ }
77
+ }
78
+
79
+ export function handleAcceptStarterBundle(
80
+ socket: net.Socket,
81
+ ctx: HandlerContext,
82
+ ): void {
83
+ try {
84
+ const result = acceptStarterBundle();
85
+ ctx.send(socket, {
86
+ type: 'accept_starter_bundle_response',
87
+ accepted: result.accepted,
88
+ rulesAdded: result.rulesAdded,
89
+ alreadyAccepted: result.alreadyAccepted,
90
+ });
91
+ log.info({ rulesAdded: result.rulesAdded, alreadyAccepted: result.alreadyAccepted }, 'Starter bundle accepted via client');
92
+ } catch (err) {
93
+ log.error({ err }, 'Failed to accept starter bundle');
94
+ ctx.send(socket, { type: 'error', message: 'Failed to accept starter bundle' });
95
+ }
96
+ }
97
+
98
+ export const trustHandlers = defineHandlers({
99
+ add_trust_rule: handleAddTrustRule,
100
+ trust_rules_list: (_msg, socket, ctx) => handleTrustRulesList(socket, ctx),
101
+ remove_trust_rule: handleRemoveTrustRule,
102
+ update_trust_rule: handleUpdateTrustRule,
103
+ accept_starter_bundle: (_msg, socket, ctx) => handleAcceptStarterBundle(socket, ctx),
104
+ });