@vellumai/assistant 0.4.48 → 0.4.50

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 (423) hide show
  1. package/ARCHITECTURE.md +26 -35
  2. package/README.md +5 -26
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/memory.md +180 -119
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +2 -2
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/agent-loop.test.ts +3 -1
  12. package/src/__tests__/anthropic-provider.test.ts +249 -2
  13. package/src/__tests__/approval-cascade.test.ts +796 -0
  14. package/src/__tests__/approval-primitive.test.ts +0 -1
  15. package/src/__tests__/approval-routes-http.test.ts +4 -0
  16. package/src/__tests__/assistant-attachments.test.ts +12 -34
  17. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  18. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  22. package/src/__tests__/channel-guardian.test.ts +0 -2
  23. package/src/__tests__/channel-readiness-routes.test.ts +15 -6
  24. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  25. package/src/__tests__/checker.test.ts +13 -20
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-schema.test.ts +1 -68
  29. package/src/__tests__/config-watcher.test.ts +0 -1
  30. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  31. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  32. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  33. package/src/__tests__/context-token-estimator.test.ts +196 -13
  34. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  35. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  36. package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
  37. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  38. package/src/__tests__/credential-metadata-store.test.ts +64 -73
  39. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  40. package/src/__tests__/credential-security-invariants.test.ts +13 -7
  41. package/src/__tests__/credential-vault-unit.test.ts +284 -49
  42. package/src/__tests__/credential-vault.test.ts +150 -16
  43. package/src/__tests__/credentials-cli.test.ts +71 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  45. package/src/__tests__/date-context.test.ts +93 -77
  46. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  47. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  48. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  51. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  52. package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
  53. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  54. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  55. package/src/__tests__/heartbeat-service.test.ts +0 -1
  56. package/src/__tests__/history-repair.test.ts +245 -0
  57. package/src/__tests__/host-cu-proxy.test.ts +791 -0
  58. package/src/__tests__/host-shell-tool.test.ts +27 -15
  59. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  60. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  61. package/src/__tests__/integration-status.test.ts +32 -51
  62. package/src/__tests__/intent-routing.test.ts +0 -1
  63. package/src/__tests__/invite-redemption-service.test.ts +65 -1
  64. package/src/__tests__/invite-routes-http.test.ts +10 -9
  65. package/src/__tests__/keychain-broker-client.test.ts +14 -46
  66. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  67. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  68. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  69. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  70. package/src/__tests__/memory-regressions.test.ts +477 -2841
  71. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  72. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  73. package/src/__tests__/mime-builder.test.ts +28 -0
  74. package/src/__tests__/native-web-search.test.ts +1 -0
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +941 -15
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +870 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  83. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  84. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  85. package/src/__tests__/recording-handler.test.ts +3 -4
  86. package/src/__tests__/registry.test.ts +2 -3
  87. package/src/__tests__/relay-server.test.ts +46 -1
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/schedule-tools.test.ts +32 -0
  91. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  95. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  96. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  97. package/src/__tests__/secure-keys.test.ts +7 -2
  98. package/src/__tests__/send-endpoint-busy.test.ts +24 -6
  99. package/src/__tests__/sequence-store.test.ts +0 -1
  100. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  101. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  102. package/src/__tests__/session-agent-loop.test.ts +19 -15
  103. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  104. package/src/__tests__/session-error.test.ts +124 -2
  105. package/src/__tests__/session-history-web-search.test.ts +918 -0
  106. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  107. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  108. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  109. package/src/__tests__/session-queue.test.ts +37 -27
  110. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  111. package/src/__tests__/session-slash-known.test.ts +1 -15
  112. package/src/__tests__/session-slash-queue.test.ts +1 -15
  113. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  114. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  115. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  116. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  117. package/src/__tests__/skill-include-graph.test.ts +66 -0
  118. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  119. package/src/__tests__/skill-load-tool.test.ts +149 -1
  120. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  121. package/src/__tests__/skills-install-extract.test.ts +93 -0
  122. package/src/__tests__/skills-uninstall.test.ts +1 -1
  123. package/src/__tests__/skills.test.ts +3 -3
  124. package/src/__tests__/skillssh-registry.test.ts +451 -0
  125. package/src/__tests__/slack-channel-config.test.ts +67 -3
  126. package/src/__tests__/slack-share-routes.test.ts +17 -19
  127. package/src/__tests__/system-prompt.test.ts +0 -1
  128. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  129. package/src/__tests__/terminal-tools.test.ts +4 -3
  130. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  131. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  132. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  133. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  134. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  135. package/src/__tests__/tool-executor.test.ts +0 -1
  136. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  137. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  138. package/src/__tests__/trust-store.test.ts +7 -13
  139. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  140. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  141. package/src/__tests__/twilio-routes.test.ts +0 -16
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  143. package/src/__tests__/voice-invite-redemption.test.ts +32 -1
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  145. package/src/agent/ax-tree-compaction.test.ts +286 -0
  146. package/src/agent/loop.ts +104 -131
  147. package/src/approvals/AGENTS.md +1 -1
  148. package/src/approvals/guardian-request-resolvers.ts +14 -2
  149. package/src/bundler/compiler-tools.ts +66 -2
  150. package/src/calls/call-domain.ts +133 -6
  151. package/src/calls/call-store.ts +6 -0
  152. package/src/calls/relay-server.ts +52 -18
  153. package/src/calls/relay-setup-router.ts +17 -1
  154. package/src/calls/twilio-config.ts +3 -8
  155. package/src/calls/twilio-routes.ts +1 -2
  156. package/src/calls/types.ts +3 -1
  157. package/src/calls/voice-ingress-preflight.ts +1 -1
  158. package/src/cli/commands/browser-relay.ts +18 -12
  159. package/src/cli/commands/completions.ts +0 -3
  160. package/src/cli/commands/credentials.ts +101 -15
  161. package/src/cli/commands/doctor.ts +4 -3
  162. package/src/cli/commands/mcp.ts +46 -59
  163. package/src/cli/commands/memory.ts +16 -165
  164. package/src/cli/commands/oauth/apps.ts +284 -0
  165. package/src/cli/commands/oauth/connections.ts +633 -0
  166. package/src/cli/commands/oauth/index.ts +52 -0
  167. package/src/cli/commands/oauth/providers.ts +256 -0
  168. package/src/cli/commands/sessions.ts +5 -2
  169. package/src/cli/commands/skills.ts +177 -339
  170. package/src/cli/http-client.ts +0 -20
  171. package/src/cli/main-screen.tsx +2 -2
  172. package/src/cli/program.ts +6 -11
  173. package/src/cli/reference.ts +1 -3
  174. package/src/cli.ts +4 -10
  175. package/src/config/assistant-feature-flags.ts +0 -3
  176. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  177. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  178. package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
  179. package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
  180. package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
  181. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
  182. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  183. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  184. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  185. package/src/config/bundled-tool-registry.ts +2 -5
  186. package/src/config/env-registry.ts +14 -83
  187. package/src/config/env.ts +11 -50
  188. package/src/config/feature-flag-registry.json +16 -16
  189. package/src/config/loader.ts +0 -6
  190. package/src/config/schema.ts +4 -13
  191. package/src/config/schemas/memory-lifecycle.ts +0 -9
  192. package/src/config/schemas/memory-processing.ts +0 -180
  193. package/src/config/schemas/memory-retrieval.ts +32 -104
  194. package/src/config/schemas/memory.ts +0 -10
  195. package/src/config/skills.ts +21 -2
  196. package/src/config/types.ts +0 -4
  197. package/src/context/image-dimensions.ts +229 -0
  198. package/src/context/token-estimator.ts +75 -12
  199. package/src/context/window-manager.ts +53 -11
  200. package/src/daemon/assistant-attachments.ts +1 -13
  201. package/src/daemon/config-watcher.ts +61 -3
  202. package/src/daemon/daemon-control.ts +1 -1
  203. package/src/daemon/date-context.ts +114 -31
  204. package/src/daemon/handlers/config-ingress.ts +8 -33
  205. package/src/daemon/handlers/config-slack-channel.ts +49 -46
  206. package/src/daemon/handlers/config-telegram.ts +32 -16
  207. package/src/daemon/handlers/sessions.ts +27 -36
  208. package/src/daemon/handlers/shared.ts +0 -130
  209. package/src/daemon/handlers/skills.ts +20 -1
  210. package/src/daemon/history-repair.ts +72 -8
  211. package/src/daemon/host-cu-proxy.ts +430 -0
  212. package/src/daemon/lifecycle.ts +67 -71
  213. package/src/daemon/mcp-reload-service.ts +2 -2
  214. package/src/daemon/message-protocol.ts +3 -0
  215. package/src/daemon/message-types/computer-use.ts +1 -129
  216. package/src/daemon/message-types/host-cu.ts +19 -0
  217. package/src/daemon/message-types/memory.ts +4 -16
  218. package/src/daemon/message-types/messages.ts +4 -0
  219. package/src/daemon/message-types/sessions.ts +4 -0
  220. package/src/daemon/server.ts +25 -21
  221. package/src/daemon/session-agent-loop-handlers.ts +40 -0
  222. package/src/daemon/session-agent-loop.ts +334 -48
  223. package/src/daemon/session-attachments.ts +1 -2
  224. package/src/daemon/session-error.ts +89 -6
  225. package/src/daemon/session-history.ts +17 -7
  226. package/src/daemon/session-media-retry.ts +6 -2
  227. package/src/daemon/session-memory.ts +69 -149
  228. package/src/daemon/session-process.ts +10 -1
  229. package/src/daemon/session-runtime-assembly.ts +49 -19
  230. package/src/daemon/session-slash.ts +1 -1
  231. package/src/daemon/session-surfaces.ts +43 -28
  232. package/src/daemon/session-tool-setup.ts +9 -10
  233. package/src/daemon/session.ts +150 -17
  234. package/src/daemon/tool-side-effects.ts +2 -8
  235. package/src/daemon/watch-handler.ts +2 -2
  236. package/src/events/tool-metrics-listener.ts +2 -2
  237. package/src/hooks/manager.ts +1 -4
  238. package/src/inbound/public-ingress-urls.ts +7 -7
  239. package/src/instrument.ts +61 -1
  240. package/src/logfire.ts +16 -5
  241. package/src/memory/admin.ts +2 -191
  242. package/src/memory/canonical-guardian-store.ts +38 -2
  243. package/src/memory/conversation-crud.ts +0 -33
  244. package/src/memory/conversation-key-store.ts +21 -0
  245. package/src/memory/conversation-queries.ts +22 -3
  246. package/src/memory/db-init.ts +32 -0
  247. package/src/memory/embedding-backend.ts +84 -8
  248. package/src/memory/embedding-types.ts +9 -1
  249. package/src/memory/indexer.ts +7 -46
  250. package/src/memory/items-extractor.ts +274 -76
  251. package/src/memory/job-handlers/backfill.ts +2 -127
  252. package/src/memory/job-handlers/cleanup.ts +2 -16
  253. package/src/memory/job-handlers/extraction.ts +2 -138
  254. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  255. package/src/memory/job-handlers/summarization.ts +3 -148
  256. package/src/memory/job-utils.ts +21 -59
  257. package/src/memory/jobs-store.ts +1 -159
  258. package/src/memory/jobs-worker.ts +9 -52
  259. package/src/memory/migrations/104-core-indexes.ts +3 -3
  260. package/src/memory/migrations/149-oauth-tables.ts +62 -0
  261. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  262. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  263. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  264. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  265. package/src/memory/migrations/154-drop-fts.ts +20 -0
  266. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  267. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  268. package/src/memory/migrations/index.ts +8 -0
  269. package/src/memory/qdrant-client.ts +148 -51
  270. package/src/memory/raw-query.ts +1 -1
  271. package/src/memory/retriever.test.ts +294 -273
  272. package/src/memory/retriever.ts +421 -645
  273. package/src/memory/schema/calls.ts +2 -0
  274. package/src/memory/schema/index.ts +1 -0
  275. package/src/memory/schema/memory-core.ts +3 -48
  276. package/src/memory/schema/oauth.ts +67 -0
  277. package/src/memory/search/formatting.ts +263 -176
  278. package/src/memory/search/lexical.ts +1 -254
  279. package/src/memory/search/ranking.ts +0 -455
  280. package/src/memory/search/semantic.ts +100 -14
  281. package/src/memory/search/staleness.ts +47 -0
  282. package/src/memory/search/tier-classifier.ts +21 -0
  283. package/src/memory/search/types.ts +15 -77
  284. package/src/memory/task-memory-cleanup.ts +4 -6
  285. package/src/messaging/provider.ts +4 -4
  286. package/src/messaging/providers/gmail/client.ts +82 -2
  287. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  288. package/src/messaging/providers/gmail/people-client.ts +10 -10
  289. package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
  290. package/src/messaging/providers/whatsapp/adapter.ts +11 -8
  291. package/src/messaging/registry.ts +2 -32
  292. package/src/notifications/copy-composer.ts +0 -5
  293. package/src/notifications/signal.ts +4 -5
  294. package/src/oauth/byo-connection.test.ts +133 -25
  295. package/src/oauth/byo-connection.ts +22 -6
  296. package/src/oauth/connect-orchestrator.ts +113 -57
  297. package/src/oauth/connect-types.ts +17 -23
  298. package/src/oauth/connection-resolver.ts +35 -11
  299. package/src/oauth/connection.ts +1 -1
  300. package/src/oauth/manual-token-connection.ts +104 -0
  301. package/src/oauth/oauth-store.ts +582 -0
  302. package/src/oauth/platform-connection.test.ts +29 -0
  303. package/src/oauth/platform-connection.ts +6 -5
  304. package/src/oauth/provider-behaviors.ts +124 -0
  305. package/src/oauth/scope-policy.ts +9 -2
  306. package/src/oauth/seed-providers.ts +167 -0
  307. package/src/oauth/token-persistence.ts +81 -77
  308. package/src/permissions/checker.ts +3 -3
  309. package/src/permissions/defaults.ts +1 -1
  310. package/src/permissions/prompter.ts +10 -1
  311. package/src/permissions/trust-store.ts +36 -1
  312. package/src/playbooks/playbook-compiler.ts +1 -1
  313. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  314. package/src/prompts/system-prompt.ts +46 -42
  315. package/src/providers/anthropic/client.ts +59 -20
  316. package/src/providers/retry.ts +1 -27
  317. package/src/providers/types.ts +7 -1
  318. package/src/runtime/AGENTS.md +9 -0
  319. package/src/runtime/auth/route-policy.ts +6 -6
  320. package/src/runtime/channel-reply-delivery.ts +0 -40
  321. package/src/runtime/gateway-client.ts +0 -7
  322. package/src/runtime/guardian-reply-router.ts +24 -22
  323. package/src/runtime/http-server.ts +10 -8
  324. package/src/runtime/http-types.ts +2 -2
  325. package/src/runtime/invite-redemption-service.ts +19 -1
  326. package/src/runtime/invite-service.ts +25 -0
  327. package/src/runtime/middleware/twilio-validation.ts +1 -11
  328. package/src/runtime/pending-interactions.ts +14 -12
  329. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  330. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  331. package/src/runtime/routes/conversation-routes.ts +81 -19
  332. package/src/runtime/routes/events-routes.ts +21 -11
  333. package/src/runtime/routes/host-cu-routes.ts +97 -0
  334. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  335. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  336. package/src/runtime/routes/integrations/slack/share.ts +6 -7
  337. package/src/runtime/routes/log-export-routes.ts +126 -8
  338. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  339. package/src/runtime/routes/memory-item-routes.ts +503 -0
  340. package/src/runtime/routes/session-management-routes.ts +3 -3
  341. package/src/runtime/routes/settings-routes.ts +55 -48
  342. package/src/runtime/routes/surface-action-routes.ts +1 -1
  343. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  344. package/src/runtime/routes/watch-routes.ts +128 -0
  345. package/src/runtime/routes/workspace-routes.ts +2 -1
  346. package/src/schedule/integration-status.ts +10 -9
  347. package/src/security/credential-key.ts +0 -156
  348. package/src/security/keychain-broker-client.ts +22 -10
  349. package/src/security/oauth2.ts +1 -1
  350. package/src/security/secure-keys.ts +25 -3
  351. package/src/security/token-manager.ts +137 -64
  352. package/src/skills/catalog-install.ts +414 -0
  353. package/src/skills/include-graph.ts +32 -0
  354. package/src/skills/skillssh-registry.ts +503 -0
  355. package/src/telegram/bot-username.ts +2 -3
  356. package/src/tools/assets/search.ts +5 -1
  357. package/src/tools/browser/network-recorder.ts +1 -1
  358. package/src/tools/browser/network-recording-types.ts +1 -1
  359. package/src/tools/computer-use/definitions.ts +36 -11
  360. package/src/tools/computer-use/registry.ts +5 -6
  361. package/src/tools/credentials/broker.ts +1 -2
  362. package/src/tools/credentials/metadata-store.ts +17 -121
  363. package/src/tools/credentials/vault.ts +92 -167
  364. package/src/tools/memory/definitions.ts +4 -13
  365. package/src/tools/memory/handlers.test.ts +83 -103
  366. package/src/tools/memory/handlers.ts +50 -85
  367. package/src/tools/registry.ts +2 -7
  368. package/src/tools/schedule/create.ts +8 -1
  369. package/src/tools/schedule/update.ts +8 -1
  370. package/src/tools/skills/load.ts +85 -3
  371. package/src/tools/watch/watch-state.ts +0 -12
  372. package/src/util/logger.ts +7 -41
  373. package/src/util/platform.ts +9 -28
  374. package/src/watcher/providers/google-calendar.ts +2 -1
  375. package/src/__tests__/clarification-resolver.test.ts +0 -193
  376. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  377. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  378. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  379. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  380. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  381. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  382. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  383. package/src/__tests__/conflict-policy.test.ts +0 -269
  384. package/src/__tests__/conflict-store.test.ts +0 -372
  385. package/src/__tests__/contradiction-checker.test.ts +0 -361
  386. package/src/__tests__/entity-extractor.test.ts +0 -211
  387. package/src/__tests__/entity-search.test.ts +0 -1117
  388. package/src/__tests__/profile-compiler.test.ts +0 -392
  389. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  390. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  391. package/src/__tests__/session-profile-injection.test.ts +0 -557
  392. package/src/cli/commands/dev.ts +0 -129
  393. package/src/cli/commands/map.ts +0 -391
  394. package/src/cli/commands/oauth.ts +0 -77
  395. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  396. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  397. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  398. package/src/daemon/computer-use-session.ts +0 -1026
  399. package/src/daemon/ride-shotgun-handler.ts +0 -569
  400. package/src/daemon/session-conflict-gate.ts +0 -167
  401. package/src/daemon/session-dynamic-profile.ts +0 -77
  402. package/src/memory/clarification-resolver.ts +0 -417
  403. package/src/memory/conflict-intent.ts +0 -205
  404. package/src/memory/conflict-policy.ts +0 -127
  405. package/src/memory/conflict-store.ts +0 -410
  406. package/src/memory/contradiction-checker.ts +0 -508
  407. package/src/memory/entity-extractor.ts +0 -535
  408. package/src/memory/format-recall.ts +0 -47
  409. package/src/memory/fts-reconciler.ts +0 -165
  410. package/src/memory/job-handlers/conflict.ts +0 -200
  411. package/src/memory/profile-compiler.ts +0 -195
  412. package/src/memory/recall-cache.ts +0 -117
  413. package/src/memory/search/entity.ts +0 -535
  414. package/src/memory/search/query-expansion.test.ts +0 -70
  415. package/src/memory/search/query-expansion.ts +0 -118
  416. package/src/oauth/provider-base-urls.ts +0 -21
  417. package/src/oauth/provider-profiles.ts +0 -192
  418. package/src/prompts/computer-use-prompt.ts +0 -98
  419. package/src/runtime/routes/computer-use-routes.ts +0 -641
  420. package/src/runtime/routes/mcp-routes.ts +0 -20
  421. package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
  422. package/src/runtime/telegram-streaming-delivery.ts +0 -393
  423. package/src/tools/computer-use/request-computer-control.ts +0 -56
@@ -0,0 +1,503 @@
1
+ import { execSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join, resolve, sep } from "node:path";
5
+
6
+ import { getWorkspaceSkillsDir } from "../util/platform.js";
7
+ import { upsertSkillsIndex } from "./catalog-install.js";
8
+
9
+ // ─── Types ───────────────────────────────────────────────────────────────────
10
+
11
+ export interface SkillsShSearchResult {
12
+ id: string; // e.g. "vercel-labs/agent-skills/vercel-react-best-practices"
13
+ skillId: string; // e.g. "vercel-react-best-practices"
14
+ name: string;
15
+ installs: number;
16
+ source: string; // e.g. "vercel-labs/agent-skills"
17
+ }
18
+
19
+ export type RiskLevel =
20
+ | "safe"
21
+ | "low"
22
+ | "medium"
23
+ | "high"
24
+ | "critical"
25
+ | "unknown";
26
+
27
+ export interface PartnerAudit {
28
+ risk: RiskLevel;
29
+ alerts?: number;
30
+ score?: number;
31
+ analyzedAt: string;
32
+ }
33
+
34
+ /** Map from audit provider name (e.g. "ath", "socket", "snyk") to audit data */
35
+ export type SkillAuditData = Record<string, PartnerAudit>;
36
+
37
+ /** Map from skill slug to per-provider audit data */
38
+ export type AuditResponse = Record<string, SkillAuditData>;
39
+
40
+ export interface ResolvedSkillSource {
41
+ owner: string;
42
+ repo: string;
43
+ skillSlug: string;
44
+ ref?: string;
45
+ }
46
+
47
+ /** Map of relative file paths to their string contents */
48
+ export type SkillFiles = Record<string, string>;
49
+
50
+ // ─── Display helpers ─────────────────────────────────────────────────────────
51
+
52
+ const RISK_DISPLAY: Record<RiskLevel, string> = {
53
+ safe: "PASS",
54
+ low: "PASS",
55
+ medium: "WARN",
56
+ high: "FAIL",
57
+ critical: "FAIL",
58
+ unknown: "?",
59
+ };
60
+
61
+ const PROVIDER_DISPLAY: Record<string, string> = {
62
+ ath: "ATH",
63
+ socket: "Socket",
64
+ snyk: "Snyk",
65
+ };
66
+
67
+ export function riskToDisplay(risk: RiskLevel): string {
68
+ return RISK_DISPLAY[risk] ?? "?";
69
+ }
70
+
71
+ export function providerDisplayName(provider: string): string {
72
+ return PROVIDER_DISPLAY[provider] ?? provider;
73
+ }
74
+
75
+ export function formatAuditBadges(auditData: SkillAuditData): string {
76
+ const providers = Object.keys(auditData);
77
+ if (providers.length === 0) return "Security: no audit data";
78
+
79
+ const badges = providers.map((provider) => {
80
+ const audit = auditData[provider]!;
81
+ const display = riskToDisplay(audit.risk);
82
+ const name = providerDisplayName(provider);
83
+ return `[${name}:${display}]`;
84
+ });
85
+
86
+ return `Security: ${badges.join(" ")}`;
87
+ }
88
+
89
+ // ─── API clients ─────────────────────────────────────────────────────────────
90
+
91
+ export async function searchSkillsRegistry(
92
+ query: string,
93
+ limit?: number,
94
+ ): Promise<SkillsShSearchResult[]> {
95
+ const params = new URLSearchParams({ q: query });
96
+ if (limit != null) {
97
+ params.set("limit", String(limit));
98
+ }
99
+
100
+ const url = `https://skills.sh/api/search?${params.toString()}`;
101
+ const response = await fetch(url, {
102
+ signal: AbortSignal.timeout(10_000),
103
+ });
104
+
105
+ if (!response.ok) {
106
+ throw new Error(
107
+ `skills.sh search failed: HTTP ${response.status} ${response.statusText}`,
108
+ );
109
+ }
110
+
111
+ const data = (await response.json()) as { skills: SkillsShSearchResult[] };
112
+ return data.skills ?? [];
113
+ }
114
+
115
+ export async function fetchSkillAudits(
116
+ source: string,
117
+ skillSlugs: string[],
118
+ ): Promise<AuditResponse> {
119
+ if (skillSlugs.length === 0) return {};
120
+
121
+ const params = new URLSearchParams({
122
+ source,
123
+ skills: skillSlugs.join(","),
124
+ });
125
+
126
+ const url = `https://add-skill.vercel.sh/audit?${params.toString()}`;
127
+ const response = await fetch(url, {
128
+ signal: AbortSignal.timeout(10_000),
129
+ });
130
+
131
+ if (!response.ok) {
132
+ throw new Error(
133
+ `Audit fetch failed: HTTP ${response.status} ${response.statusText}`,
134
+ );
135
+ }
136
+
137
+ return (await response.json()) as AuditResponse;
138
+ }
139
+
140
+ // ─── Source resolution ──────────────────────────────────────────────────────
141
+
142
+ /**
143
+ * Parse a skill source string into owner, repo, and skill slug.
144
+ *
145
+ * Supported formats:
146
+ * - `owner/repo@skill-name`
147
+ * - `owner/repo/skill-name`
148
+ * - `https://github.com/owner/repo/tree/<branch>/skills/skill-name`
149
+ */
150
+ export function resolveSkillSource(source: string): ResolvedSkillSource {
151
+ // Full GitHub URL — capture the branch for ref passthrough
152
+ // Branch capture uses non-greedy `.+?` to handle branch names with slashes (e.g. feature/new-flow)
153
+ const urlMatch = source.match(
154
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/(.+?)\/skills\/([a-z0-9][a-z0-9._-]*)\/?$/,
155
+ );
156
+ if (urlMatch) {
157
+ return {
158
+ owner: urlMatch[1]!,
159
+ repo: urlMatch[2]!,
160
+ skillSlug: urlMatch[4]!,
161
+ ref: urlMatch[3]!,
162
+ };
163
+ }
164
+
165
+ // owner/repo@skill-name — restrict slug to safe characters
166
+ const atMatch = source.match(/^([^/]+)\/([^/@]+)@([a-z0-9][a-z0-9._-]*)$/);
167
+ if (atMatch) {
168
+ return { owner: atMatch[1]!, repo: atMatch[2]!, skillSlug: atMatch[3]! };
169
+ }
170
+
171
+ // owner/repo/skill-name (exactly 3 segments) — restrict slug to safe characters
172
+ const slashMatch = source.match(/^([^/]+)\/([^/]+)\/([a-z0-9][a-z0-9._-]*)$/);
173
+ if (slashMatch) {
174
+ return {
175
+ owner: slashMatch[1]!,
176
+ repo: slashMatch[2]!,
177
+ skillSlug: slashMatch[3]!,
178
+ };
179
+ }
180
+
181
+ throw new Error(
182
+ `Invalid skill source "${source}". Expected one of:\n` +
183
+ ` owner/repo@skill-name\n` +
184
+ ` owner/repo/skill-name\n` +
185
+ ` https://github.com/owner/repo/tree/<branch>/skills/skill-name`,
186
+ );
187
+ }
188
+
189
+ // ─── GitHub fetch ───────────────────────────────────────────────────────────
190
+
191
+ interface GitHubContentsEntry {
192
+ name: string;
193
+ type: "file" | "dir";
194
+ download_url: string | null;
195
+ }
196
+
197
+ /** Build common headers for GitHub API requests (User-Agent + optional auth). */
198
+ function githubHeaders(): Record<string, string> {
199
+ const headers: Record<string, string> = {
200
+ Accept: "application/vnd.github.v3+json",
201
+ "User-Agent": "vellum-assistant",
202
+ };
203
+ const token = process.env.GITHUB_TOKEN;
204
+ if (token) {
205
+ headers["Authorization"] = `token ${token}`;
206
+ }
207
+ return headers;
208
+ }
209
+
210
+ interface GitHubTreeEntry {
211
+ path: string;
212
+ type: "blob" | "tree";
213
+ }
214
+
215
+ /**
216
+ * Search the repo tree for a directory containing `<slug>/SKILL.md`.
217
+ * Returns the directory path (e.g. "examples/skills-tool/skills/csv") or null.
218
+ */
219
+ async function findSkillDirInTree(
220
+ owner: string,
221
+ repo: string,
222
+ skillSlug: string,
223
+ ref: string,
224
+ headers: Record<string, string>,
225
+ ): Promise<string | null> {
226
+ const treeUrl = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/trees/${encodeURIComponent(ref)}?recursive=1`;
227
+ const response = await fetch(treeUrl, {
228
+ headers,
229
+ signal: AbortSignal.timeout(15_000),
230
+ });
231
+ if (!response.ok) return null;
232
+
233
+ const data = (await response.json()) as { tree: GitHubTreeEntry[] };
234
+ const suffix = `${skillSlug}/SKILL.md`;
235
+ const match = data.tree.find(
236
+ (entry) =>
237
+ entry.type === "blob" &&
238
+ (entry.path === suffix || entry.path.endsWith(`/${suffix}`)),
239
+ );
240
+ if (!match) return null;
241
+
242
+ // Return the directory containing SKILL.md (strip the trailing /SKILL.md)
243
+ return match.path.slice(0, -"/SKILL.md".length);
244
+ }
245
+
246
+ /**
247
+ * Fetch SKILL.md and supporting files from a GitHub-hosted skills directory.
248
+ *
249
+ * First tries the conventional `skills/<slug>/` path. If that returns a 404,
250
+ * falls back to searching the full repo tree for `<slug>/SKILL.md` at any
251
+ * depth (handles repos like `vercel-labs/bash-tool` where skills live at
252
+ * non-standard paths like `examples/skills-tool/skills/csv/`).
253
+ *
254
+ * Uses the GitHub Contents API for directory listing and file downloads.
255
+ * Recursively fetches subdirectories (e.g. scripts/, references/).
256
+ */
257
+ export async function fetchSkillFromGitHub(
258
+ owner: string,
259
+ repo: string,
260
+ skillSlug: string,
261
+ ref?: string,
262
+ ): Promise<SkillFiles> {
263
+ const headers = githubHeaders();
264
+
265
+ async function fetchDir(
266
+ subpath: string,
267
+ prefix: string,
268
+ ): Promise<SkillFiles> {
269
+ let apiUrl = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${subpath}`;
270
+ if (ref) {
271
+ apiUrl += `?ref=${encodeURIComponent(ref)}`;
272
+ }
273
+
274
+ const response = await fetch(apiUrl, {
275
+ headers,
276
+ signal: AbortSignal.timeout(15_000),
277
+ });
278
+
279
+ if (!response.ok) {
280
+ throw new Error(
281
+ `GitHub API error: HTTP ${response.status} ${response.statusText}`,
282
+ );
283
+ }
284
+
285
+ const entries = (await response.json()) as GitHubContentsEntry[];
286
+ if (!Array.isArray(entries)) {
287
+ throw new Error(
288
+ `Expected a directory listing for ${subpath}/ but got a single file`,
289
+ );
290
+ }
291
+
292
+ const files: SkillFiles = {};
293
+ for (const entry of entries) {
294
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
295
+
296
+ if (entry.type === "dir") {
297
+ // Recursively fetch subdirectory contents
298
+ const subFiles = await fetchDir(
299
+ `${subpath}/${entry.name}`,
300
+ relativePath,
301
+ );
302
+ Object.assign(files, subFiles);
303
+ continue;
304
+ }
305
+
306
+ if (entry.type !== "file" || !entry.download_url) continue;
307
+ const fileResponse = await fetch(entry.download_url, {
308
+ headers,
309
+ signal: AbortSignal.timeout(10_000),
310
+ });
311
+ if (!fileResponse.ok) {
312
+ throw new Error(
313
+ `Failed to download ${relativePath}: HTTP ${fileResponse.status}`,
314
+ );
315
+ }
316
+ files[relativePath] = await fileResponse.text();
317
+ }
318
+
319
+ return files;
320
+ }
321
+
322
+ // Try the conventional skills/<slug>/ path first
323
+ const conventionalPath = `skills/${encodeURIComponent(skillSlug)}`;
324
+ let skillDirPath = conventionalPath;
325
+
326
+ const probeUrl = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${conventionalPath}${ref ? `?ref=${encodeURIComponent(ref)}` : ""}`;
327
+ const probeResponse = await fetch(probeUrl, {
328
+ headers,
329
+ signal: AbortSignal.timeout(15_000),
330
+ });
331
+
332
+ if (probeResponse.status === 404) {
333
+ // Fall back to searching the repo tree for <slug>/SKILL.md at any path
334
+ const treeRef = ref ?? "HEAD";
335
+ const foundPath = await findSkillDirInTree(
336
+ owner,
337
+ repo,
338
+ skillSlug,
339
+ treeRef,
340
+ headers,
341
+ );
342
+ if (!foundPath) {
343
+ throw new Error(
344
+ `Skill "${skillSlug}" not found in ${owner}/${repo}. ` +
345
+ `Searched skills/${skillSlug}/ and the full repo tree.`,
346
+ );
347
+ }
348
+ skillDirPath = foundPath;
349
+ } else if (!probeResponse.ok) {
350
+ throw new Error(
351
+ `GitHub API error: HTTP ${probeResponse.status} ${probeResponse.statusText}`,
352
+ );
353
+ }
354
+
355
+ // If we already have the probe response for the conventional path and it was
356
+ // successful, we can use it directly instead of re-fetching.
357
+ let files: SkillFiles;
358
+ if (skillDirPath === conventionalPath && probeResponse.ok) {
359
+ const entries = (await probeResponse.json()) as GitHubContentsEntry[];
360
+ if (!Array.isArray(entries)) {
361
+ throw new Error(
362
+ `Expected a directory listing for ${conventionalPath}/ but got a single file`,
363
+ );
364
+ }
365
+ // Fetch the directory contents from the already-parsed probe response
366
+ const result: SkillFiles = {};
367
+ for (const entry of entries) {
368
+ if (entry.type === "dir") {
369
+ const subFiles = await fetchDir(
370
+ `${conventionalPath}/${entry.name}`,
371
+ entry.name,
372
+ );
373
+ Object.assign(result, subFiles);
374
+ continue;
375
+ }
376
+ if (entry.type !== "file" || !entry.download_url) continue;
377
+ const fileResponse = await fetch(entry.download_url, {
378
+ headers,
379
+ signal: AbortSignal.timeout(10_000),
380
+ });
381
+ if (!fileResponse.ok) {
382
+ throw new Error(
383
+ `Failed to download ${entry.name}: HTTP ${fileResponse.status}`,
384
+ );
385
+ }
386
+ result[entry.name] = await fileResponse.text();
387
+ }
388
+ files = result;
389
+ } else {
390
+ files = await fetchDir(skillDirPath, "");
391
+ }
392
+
393
+ if (!files["SKILL.md"]) {
394
+ throw new Error(`SKILL.md not found in ${owner}/${repo}/${skillDirPath}/`);
395
+ }
396
+
397
+ return files;
398
+ }
399
+
400
+ // ─── External skill installation ────────────────────────────────────────────
401
+
402
+ // ─── Slug validation ────────────────────────────────────────────────────────
403
+
404
+ const VALID_SKILL_SLUG = /^[a-z0-9][a-z0-9._-]*$/;
405
+
406
+ /**
407
+ * Validate that a skill slug is safe for use in filesystem paths.
408
+ * Follows the same pattern as `validateManagedSkillId` in managed-store.ts.
409
+ */
410
+ export function validateSkillSlug(slug: string): void {
411
+ if (!slug || typeof slug !== "string") {
412
+ throw new Error("Skill slug is required");
413
+ }
414
+ if (slug.includes("..") || slug.includes("/") || slug.includes("\\")) {
415
+ throw new Error(
416
+ `Invalid skill slug "${slug}": must not contain path traversal characters`,
417
+ );
418
+ }
419
+ if (!VALID_SKILL_SLUG.test(slug)) {
420
+ throw new Error(
421
+ `Invalid skill slug "${slug}": must start with a lowercase letter or digit and contain only lowercase letters, digits, dots, hyphens, and underscores`,
422
+ );
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Install a community skill from a GitHub-hosted skills.sh registry repo.
428
+ *
429
+ * 1. Validates the skill slug for path safety
430
+ * 2. Fetches all files from `skills/<skillSlug>/` in the source repo
431
+ * 3. Writes them to `<workspace>/skills/<skillSlug>/` with path traversal protection
432
+ * 4. Writes `version.json` with origin metadata
433
+ * 5. Runs `bun install` if a `package.json` is present
434
+ * 6. Registers the skill in SKILLS.md only after all steps succeed
435
+ */
436
+ export async function installExternalSkill(
437
+ owner: string,
438
+ repo: string,
439
+ skillSlug: string,
440
+ overwrite: boolean,
441
+ ref?: string,
442
+ ): Promise<void> {
443
+ // Validate slug before using in filesystem paths
444
+ validateSkillSlug(skillSlug);
445
+
446
+ const skillDir = join(getWorkspaceSkillsDir(), skillSlug);
447
+ const skillFilePath = join(skillDir, "SKILL.md");
448
+
449
+ if (existsSync(skillFilePath) && !overwrite) {
450
+ throw new Error(
451
+ `Skill "${skillSlug}" is already installed. Use --overwrite to replace it.`,
452
+ );
453
+ }
454
+
455
+ const files = await fetchSkillFromGitHub(owner, repo, skillSlug, ref);
456
+
457
+ // Clear existing directory on overwrite to remove stale files
458
+ if (overwrite && existsSync(skillDir)) {
459
+ rmSync(skillDir, { recursive: true, force: true });
460
+ }
461
+ mkdirSync(skillDir, { recursive: true });
462
+
463
+ // Write files with path traversal protection (follows extractTarToDir pattern)
464
+ for (const [filename, content] of Object.entries(files)) {
465
+ const normalized = filename.replace(/\\/g, "/").replace(/^\.\/+/g, "");
466
+ if (!normalized || normalized.includes("..") || normalized.startsWith("/"))
467
+ continue;
468
+ const destPath = resolve(skillDir, normalized);
469
+ if (
470
+ !destPath.startsWith(resolve(skillDir) + sep) &&
471
+ destPath !== resolve(skillDir)
472
+ )
473
+ continue;
474
+ mkdirSync(dirname(destPath), { recursive: true });
475
+ writeFileSync(destPath, content, "utf-8");
476
+ }
477
+
478
+ // Write origin metadata
479
+ const meta = {
480
+ origin: "skills.sh",
481
+ source: `${owner}/${repo}`,
482
+ skillSlug,
483
+ installedAt: new Date().toISOString(),
484
+ };
485
+ writeFileSync(
486
+ join(skillDir, "version.json"),
487
+ JSON.stringify(meta, null, 2) + "\n",
488
+ "utf-8",
489
+ );
490
+
491
+ // Install npm dependencies if the skill ships a package.json
492
+ if (existsSync(join(skillDir, "package.json"))) {
493
+ const bunPath = `${homedir()}/.bun/bin`;
494
+ execSync("bun install", {
495
+ cwd: skillDir,
496
+ stdio: "inherit",
497
+ env: { ...process.env, PATH: `${bunPath}:${process.env.PATH}` },
498
+ });
499
+ }
500
+
501
+ // Register in SKILLS.md only after files are written and deps installed
502
+ upsertSkillsIndex(skillSlug);
503
+ }
@@ -1,13 +1,12 @@
1
1
  import { getConfig } from "../config/loader.js";
2
2
 
3
3
  /**
4
- * Read the Telegram bot username from config, falling back to the
5
- * TELEGRAM_BOT_USERNAME env var.
4
+ * Read the Telegram bot username from config.
6
5
  */
7
6
  export function getTelegramBotUsername(): string | undefined {
8
7
  const value = getConfig().telegram.botUsername;
9
8
  if (value.trim().length > 0) {
10
9
  return value.trim();
11
10
  }
12
- return process.env.TELEGRAM_BOT_USERNAME || undefined;
11
+ return undefined;
13
12
  }
@@ -22,8 +22,12 @@ import {
22
22
  messageAttachments,
23
23
  messages,
24
24
  } from "../../memory/schema.js";
25
- import { escapeLikeWildcards } from "../../memory/search/lexical.js";
26
25
  import { RiskLevel } from "../../permissions/types.js";
26
+
27
+ /** Escape SQL LIKE wildcard characters so a literal substring match is used. */
28
+ function escapeLikeWildcards(s: string): string {
29
+ return s.replace(/%/g, "").replace(/_/g, "");
30
+ }
27
31
  import type { ToolDefinition } from "../../providers/types.js";
28
32
  import { registerTool } from "../registry.js";
29
33
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CDP Network recorder for Ride Shotgun "learn" mode.
2
+ * CDP Network recorder.
3
3
  *
4
4
  * Connects directly to Chrome's CDP WebSocket endpoint to record
5
5
  * Network.* events across all tabs the user browses.
@@ -1,4 +1,4 @@
1
- /** Types for CDP network recording used by Ride Shotgun "learn" mode. */
1
+ /** Types for CDP network recording. */
2
2
 
3
3
  export interface NetworkRecordedRequest {
4
4
  method: string;
@@ -34,7 +34,7 @@ const reasonProperty = {
34
34
  export const computerUseClickTool: Tool = {
35
35
  name: "computer_use_click",
36
36
  description:
37
- "Click on a UI element by its [ID] from the accessibility tree, or at raw screen coordinates as fallback. Supports single click, double-click, and right-click via the click_type parameter.",
37
+ "Click an element on screen. Prefer element_id (from the accessibility tree) over x/y coordinates.",
38
38
  category: "computer-use",
39
39
  defaultRiskLevel: RiskLevel.Low,
40
40
  executionMode: "proxy",
@@ -86,7 +86,7 @@ export const computerUseClickTool: Tool = {
86
86
  export const computerUseTypeTextTool: Tool = {
87
87
  name: "computer_use_type_text",
88
88
  description:
89
- "Type text at the current cursor position. The target field must already be focused (click it first).",
89
+ "Type text at the current cursor position. First click a text field (by element_id) to focus it, then call this tool. If a field shows 'FOCUSED', skip the click.",
90
90
  category: "computer-use",
91
91
  defaultRiskLevel: RiskLevel.Low,
92
92
  executionMode: "proxy",
@@ -352,13 +352,7 @@ export const computerUseOpenAppTool: Tool = {
352
352
  export const computerUseRunAppleScriptTool: Tool = {
353
353
  name: "computer_use_run_applescript",
354
354
  description:
355
- "Execute an AppleScript to control applications via Apple's scripting bridge. " +
356
- "Use this for operations that are more reliable through scripting than UI interaction: " +
357
- "setting a browser URL directly, navigating Finder to a path, querying app state " +
358
- "(tab count, window titles, document status), or clicking deeply nested menu items. " +
359
- "The script's return value (if any) will be reported back. " +
360
- 'NEVER use "do shell script" — it is blocked for security. ' +
361
- "Keep scripts short and targeted to a single operation.",
355
+ "Run an AppleScript command. Prefer this over click/type when possible — it doesn't move the cursor or interrupt the user. Never use 'do shell script' inside AppleScript (blocked for security).",
362
356
  category: "computer-use",
363
357
  defaultRiskLevel: RiskLevel.Low,
364
358
  executionMode: "proxy",
@@ -395,7 +389,8 @@ export const computerUseRunAppleScriptTool: Tool = {
395
389
 
396
390
  export const computerUseDoneTool: Tool = {
397
391
  name: "computer_use_done",
398
- description: "Task is complete",
392
+ description:
393
+ "Signal that the computer use task is complete. Provide a summary of what was accomplished. This ends the computer use session.",
399
394
  category: "computer-use",
400
395
  defaultRiskLevel: RiskLevel.Low,
401
396
  executionMode: "proxy",
@@ -428,7 +423,7 @@ export const computerUseDoneTool: Tool = {
428
423
  export const computerUseRespondTool: Tool = {
429
424
  name: "computer_use_respond",
430
425
  description:
431
- "Respond directly to the user with a text answer. Use this when the user is asking a question (about their schedule, meetings, calendar, etc.) rather than asking you to control the computer.",
426
+ "Respond to the user with a text answer instead of performing computer actions. Use this when you can answer directly without interacting with the screen.",
432
427
  category: "computer-use",
433
428
  defaultRiskLevel: RiskLevel.Low,
434
429
  executionMode: "proxy",
@@ -458,11 +453,41 @@ export const computerUseRespondTool: Tool = {
458
453
  execute: proxyExecute,
459
454
  };
460
455
 
456
+ // ---------------------------------------------------------------------------
457
+ // observe
458
+ // ---------------------------------------------------------------------------
459
+
460
+ export const computerUseObserveTool: Tool = {
461
+ name: "computer_use_observe",
462
+ description:
463
+ "Capture the current screen state. Returns the accessibility tree with [ID] element references and optionally a screenshot.\n\nThe accessibility tree shows interactive elements like [3] AXButton 'Save' or [17] AXTextField 'Search'. Use element_id to target these elements in subsequent actions — this is much more reliable than pixel coordinates.\n\nCall this before your first computer use action, or to check screen state without acting.",
464
+ category: "computer-use",
465
+ defaultRiskLevel: RiskLevel.Low,
466
+ executionMode: "proxy",
467
+
468
+ getDefinition(): ToolDefinition {
469
+ return {
470
+ name: this.name,
471
+ description: this.description,
472
+ input_schema: {
473
+ type: "object",
474
+ properties: {
475
+ reason: reasonProperty,
476
+ },
477
+ required: ["reason"],
478
+ },
479
+ };
480
+ },
481
+
482
+ execute: proxyExecute,
483
+ };
484
+
461
485
  // ---------------------------------------------------------------------------
462
486
  // All tools exported as array for convenience
463
487
  // ---------------------------------------------------------------------------
464
488
 
465
489
  export const allComputerUseTools: Tool[] = [
490
+ computerUseObserveTool,
466
491
  computerUseClickTool,
467
492
  computerUseTypeTextTool,
468
493
  computerUseKeyTool,
@@ -1,18 +1,17 @@
1
1
  /**
2
2
  * Registers computer-use tools with the daemon's tool registry.
3
3
  *
4
- * The 12 computer_use_* action tools and the computer_use_request_control
5
- * escalation tool are now provided by the bundled computer-use skill.
6
- * This module retains registerComputerUseActionTools() for backward
7
- * compatibility (used by tests), but it is no longer called during
8
- * normal startup.
4
+ * The computer_use_* action tools are now provided by the bundled
5
+ * computer-use skill. This module retains registerComputerUseActionTools()
6
+ * for backward compatibility (used by tests), but it is no longer called
7
+ * during normal startup.
9
8
  */
10
9
 
11
10
  import { registerTool } from "../registry.js";
12
11
  import { allComputerUseTools } from "./definitions.js";
13
12
 
14
13
  /**
15
- * Register the 12 `computer_use_*` action proxy tools.
14
+ * Register the 11 `computer_use_*` action proxy tools.
16
15
  * After cutover these are provided by the bundled computer-use skill instead.
17
16
  */
18
17
  export function registerComputerUseActionTools(): void {
@@ -1,6 +1,6 @@
1
1
  import { v4 as uuid } from "uuid";
2
2
 
3
- import { credentialKey, migrateKeys } from "../../security/credential-key.js";
3
+ import { credentialKey } from "../../security/credential-key.js";
4
4
  import { getSecureKey } from "../../security/secure-keys.js";
5
5
  import { getLogger } from "../../util/logger.js";
6
6
  import type {
@@ -60,7 +60,6 @@ export class CredentialBroker {
60
60
  * Returns a single-use token on success, or a denial reason on failure.
61
61
  */
62
62
  authorize(request: AuthorizeRequest): AuthorizeResult {
63
- migrateKeys();
64
63
  const metadata = getCredentialMetadata(request.service, request.field);
65
64
  if (!metadata) {
66
65
  return {