@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,414 @@
1
+ import { execSync } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import {
4
+ cpSync,
5
+ existsSync,
6
+ mkdirSync,
7
+ readFileSync,
8
+ renameSync,
9
+ rmSync,
10
+ writeFileSync,
11
+ } from "node:fs";
12
+ import { homedir } from "node:os";
13
+ import { dirname, join, posix, resolve, sep } from "node:path";
14
+ import { gunzipSync } from "node:zlib";
15
+
16
+ import { getLogger } from "../util/logger.js";
17
+ import {
18
+ getWorkspaceConfigPath,
19
+ getWorkspaceSkillsDir,
20
+ readPlatformToken,
21
+ } from "../util/platform.js";
22
+
23
+ const log = getLogger("catalog-install");
24
+
25
+ // ─── Types ───────────────────────────────────────────────────────────────────
26
+
27
+ export interface CatalogSkill {
28
+ id: string;
29
+ name: string;
30
+ description: string;
31
+ emoji?: string;
32
+ includes?: string[];
33
+ version?: string;
34
+ }
35
+
36
+ export interface CatalogManifest {
37
+ version: number;
38
+ skills: CatalogSkill[];
39
+ }
40
+
41
+ // ─── Path helpers ────────────────────────────────────────────────────────────
42
+
43
+ export function getSkillsIndexPath(): string {
44
+ return join(getWorkspaceSkillsDir(), "SKILLS.md");
45
+ }
46
+
47
+ /**
48
+ * Resolve the repo-level skills/ directory when running in dev mode.
49
+ * Returns the path if VELLUM_DEV is set and the directory exists, or undefined.
50
+ */
51
+ export function getRepoSkillsDir(): string | undefined {
52
+ if (!process.env.VELLUM_DEV) return undefined;
53
+
54
+ // assistant/src/skills/catalog-install.ts -> ../../../skills/
55
+ const candidate = join(import.meta.dir, "..", "..", "..", "skills");
56
+ if (existsSync(join(candidate, "catalog.json"))) {
57
+ return candidate;
58
+ }
59
+ return undefined;
60
+ }
61
+
62
+ // ─── Platform API ────────────────────────────────────────────────────────────
63
+
64
+ function getConfigPlatformUrl(): string | undefined {
65
+ try {
66
+ const configPath = getWorkspaceConfigPath();
67
+ if (!existsSync(configPath)) return undefined;
68
+ const raw = JSON.parse(readFileSync(configPath, "utf-8")) as Record<
69
+ string,
70
+ unknown
71
+ >;
72
+ const platform = raw.platform as Record<string, unknown> | undefined;
73
+ const baseUrl = platform?.baseUrl;
74
+ if (typeof baseUrl === "string" && baseUrl.trim()) return baseUrl.trim();
75
+ } catch {
76
+ // ignore
77
+ }
78
+ return undefined;
79
+ }
80
+
81
+ function getPlatformUrl(): string {
82
+ return (
83
+ process.env.VELLUM_PLATFORM_URL ??
84
+ getConfigPlatformUrl() ??
85
+ "https://platform.vellum.ai"
86
+ );
87
+ }
88
+
89
+ function buildHeaders(): Record<string, string> {
90
+ const headers: Record<string, string> = {};
91
+ const token = readPlatformToken();
92
+ if (token) {
93
+ headers["X-Session-Token"] = token;
94
+ }
95
+ return headers;
96
+ }
97
+
98
+ // ─── Catalog operations ──────────────────────────────────────────────────────
99
+
100
+ export async function fetchCatalog(): Promise<CatalogSkill[]> {
101
+ const url = `${getPlatformUrl()}/v1/skills/`;
102
+ const response = await fetch(url, {
103
+ headers: buildHeaders(),
104
+ signal: AbortSignal.timeout(10000),
105
+ });
106
+
107
+ if (!response.ok) {
108
+ throw new Error(
109
+ `Platform API error ${response.status}: ${response.statusText}`,
110
+ );
111
+ }
112
+
113
+ const manifest = (await response.json()) as CatalogManifest;
114
+ if (!Array.isArray(manifest.skills)) {
115
+ throw new Error("Platform catalog has invalid skills array");
116
+ }
117
+ return manifest.skills;
118
+ }
119
+
120
+ export function readLocalCatalog(repoSkillsDir: string): CatalogSkill[] {
121
+ try {
122
+ const raw = readFileSync(join(repoSkillsDir, "catalog.json"), "utf-8");
123
+ const manifest = JSON.parse(raw) as CatalogManifest;
124
+ if (!Array.isArray(manifest.skills)) return [];
125
+ return manifest.skills;
126
+ } catch {
127
+ return [];
128
+ }
129
+ }
130
+
131
+ // ─── Tar extraction ──────────────────────────────────────────────────────────
132
+
133
+ /**
134
+ * Extract all files from a tar archive (uncompressed) into a directory.
135
+ * Returns true if a SKILL.md was found in the archive.
136
+ */
137
+ export function extractTarToDir(tarBuffer: Buffer, destDir: string): boolean {
138
+ let foundSkillMd = false;
139
+ let offset = 0;
140
+ while (offset + 512 <= tarBuffer.length) {
141
+ const header = tarBuffer.subarray(offset, offset + 512);
142
+
143
+ // End-of-archive (two consecutive zero blocks)
144
+ if (header.every((b) => b === 0)) break;
145
+
146
+ // Filename (bytes 0-99, null-terminated)
147
+ const nameEnd = header.indexOf(0, 0);
148
+ const name = header
149
+ .subarray(0, Math.min(nameEnd >= 0 ? nameEnd : 100, 100))
150
+ .toString("utf-8");
151
+
152
+ // File type (byte 156): '5' = directory, '0' or '\0' = regular file
153
+ const typeFlag = header[156];
154
+
155
+ // File size (bytes 124-135, octal)
156
+ const sizeStr = header.subarray(124, 136).toString("utf-8").trim();
157
+ const size = parseInt(sizeStr, 8) || 0;
158
+
159
+ offset += 512; // past header
160
+
161
+ // Skip directories and empty names
162
+ if (name && typeFlag !== 53 /* '5' */) {
163
+ // Prevent path traversal and absolute path writes
164
+ const normalizedName = name.replace(/\\/g, "/").replace(/^\.\/+/, "");
165
+ const normalizedPath = posix.normalize(normalizedName);
166
+ const hasWindowsDrivePrefix = /^[a-zA-Z]:\//.test(normalizedPath);
167
+ const isTraversal =
168
+ normalizedPath === ".." || normalizedPath.startsWith("../");
169
+
170
+ if (
171
+ normalizedPath &&
172
+ normalizedPath !== "." &&
173
+ !normalizedPath.startsWith("/") &&
174
+ !hasWindowsDrivePrefix &&
175
+ !isTraversal
176
+ ) {
177
+ const destRoot = resolve(destDir);
178
+ const destPath = resolve(destRoot, normalizedPath);
179
+ const insideDestination =
180
+ destPath === destRoot || destPath.startsWith(destRoot + sep);
181
+ if (!insideDestination) {
182
+ offset += Math.ceil(size / 512) * 512;
183
+ continue;
184
+ }
185
+
186
+ mkdirSync(dirname(destPath), { recursive: true });
187
+ writeFileSync(destPath, tarBuffer.subarray(offset, offset + size));
188
+
189
+ if (
190
+ normalizedPath === "SKILL.md" ||
191
+ normalizedPath.endsWith("/SKILL.md")
192
+ ) {
193
+ foundSkillMd = true;
194
+ }
195
+ }
196
+ }
197
+
198
+ // Skip to next header (data padded to 512 bytes)
199
+ offset += Math.ceil(size / 512) * 512;
200
+ }
201
+ return foundSkillMd;
202
+ }
203
+
204
+ export async function fetchAndExtractSkill(
205
+ skillId: string,
206
+ destDir: string,
207
+ ): Promise<void> {
208
+ const url = `${getPlatformUrl()}/v1/skills/${encodeURIComponent(skillId)}/`;
209
+ const response = await fetch(url, {
210
+ headers: buildHeaders(),
211
+ signal: AbortSignal.timeout(15000),
212
+ });
213
+
214
+ if (!response.ok) {
215
+ throw new Error(
216
+ `Failed to fetch skill "${skillId}": HTTP ${response.status}`,
217
+ );
218
+ }
219
+
220
+ const gzipBuffer = Buffer.from(await response.arrayBuffer());
221
+ const tarBuffer = gunzipSync(gzipBuffer);
222
+ const foundSkillMd = extractTarToDir(tarBuffer, destDir);
223
+
224
+ if (!foundSkillMd) {
225
+ throw new Error(`SKILL.md not found in archive for "${skillId}"`);
226
+ }
227
+ }
228
+
229
+ // ─── SKILLS.md index management ──────────────────────────────────────────────
230
+
231
+ function atomicWriteFile(filePath: string, content: string): void {
232
+ const dir = dirname(filePath);
233
+ mkdirSync(dir, { recursive: true });
234
+ const tmpPath = join(dir, `.tmp-${randomUUID()}`);
235
+ writeFileSync(tmpPath, content, "utf-8");
236
+ renameSync(tmpPath, filePath);
237
+ }
238
+
239
+ export function upsertSkillsIndex(id: string): void {
240
+ const indexPath = getSkillsIndexPath();
241
+ let lines: string[] = [];
242
+ if (existsSync(indexPath)) {
243
+ lines = readFileSync(indexPath, "utf-8").split("\n");
244
+ }
245
+
246
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
247
+ const pattern = new RegExp(`^[-*]\\s+(?:\`)?${escaped}(?:\`)?\\s*$`);
248
+ if (lines.some((line) => pattern.test(line))) return;
249
+
250
+ const nonEmpty = lines.filter((l) => l.trim());
251
+ nonEmpty.push(`- ${id}`);
252
+ const content = nonEmpty.join("\n");
253
+ atomicWriteFile(indexPath, content.endsWith("\n") ? content : content + "\n");
254
+ }
255
+
256
+ export function removeSkillsIndexEntry(id: string): void {
257
+ const indexPath = getSkillsIndexPath();
258
+ if (!existsSync(indexPath)) return;
259
+
260
+ const lines = readFileSync(indexPath, "utf-8").split("\n");
261
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
262
+ const pattern = new RegExp(`^[-*]\\s+(?:\`)?${escaped}(?:\`)?\\s*$`);
263
+ const filtered = lines.filter((line) => !pattern.test(line));
264
+
265
+ // If nothing changed, skip the write
266
+ if (filtered.length === lines.length) return;
267
+
268
+ const content = filtered.join("\n");
269
+ atomicWriteFile(indexPath, content.endsWith("\n") ? content : content + "\n");
270
+ }
271
+
272
+ // ─── Install / uninstall ─────────────────────────────────────────────────────
273
+
274
+ export function uninstallSkillLocally(skillId: string): void {
275
+ const skillDir = join(getWorkspaceSkillsDir(), skillId);
276
+
277
+ if (!existsSync(skillDir)) {
278
+ throw new Error(`Skill "${skillId}" is not installed.`);
279
+ }
280
+
281
+ rmSync(skillDir, { recursive: true, force: true });
282
+ removeSkillsIndexEntry(skillId);
283
+ }
284
+
285
+ export async function installSkillLocally(
286
+ skillId: string,
287
+ catalogEntry: CatalogSkill,
288
+ overwrite: boolean,
289
+ ): Promise<void> {
290
+ const skillDir = join(getWorkspaceSkillsDir(), skillId);
291
+ const skillFilePath = join(skillDir, "SKILL.md");
292
+
293
+ if (existsSync(skillFilePath) && !overwrite) {
294
+ throw new Error(
295
+ `Skill "${skillId}" is already installed. Use --overwrite to replace it.`,
296
+ );
297
+ }
298
+
299
+ mkdirSync(skillDir, { recursive: true });
300
+
301
+ // In dev mode, install from the local repo skills directory if available
302
+ const repoSkillsDir = getRepoSkillsDir();
303
+ const repoSkillSource = repoSkillsDir
304
+ ? join(repoSkillsDir, skillId)
305
+ : undefined;
306
+
307
+ if (repoSkillSource && existsSync(join(repoSkillSource, "SKILL.md"))) {
308
+ cpSync(repoSkillSource, skillDir, { recursive: true });
309
+ } else {
310
+ await fetchAndExtractSkill(skillId, skillDir);
311
+ }
312
+
313
+ // Write version metadata
314
+ if (catalogEntry.version) {
315
+ const meta = {
316
+ version: catalogEntry.version,
317
+ installedAt: new Date().toISOString(),
318
+ };
319
+ atomicWriteFile(
320
+ join(skillDir, "version.json"),
321
+ JSON.stringify(meta, null, 2) + "\n",
322
+ );
323
+ }
324
+
325
+ // Install npm dependencies if the skill has a package.json
326
+ if (existsSync(join(skillDir, "package.json"))) {
327
+ const bunPath = `${homedir()}/.bun/bin`;
328
+ execSync("bun install", {
329
+ cwd: skillDir,
330
+ stdio: "inherit",
331
+ env: { ...process.env, PATH: `${bunPath}:${process.env.PATH}` },
332
+ });
333
+ }
334
+
335
+ // Register in SKILLS.md only after all steps succeed
336
+ upsertSkillsIndex(skillId);
337
+ }
338
+
339
+ // ─── Auto-install (for skill_load) ──────────────────────────────────────────
340
+
341
+ /**
342
+ * Resolve the catalog skill list, checking local (dev mode) first, then remote.
343
+ *
344
+ * In dev mode with a local catalog, returns local entries immediately to avoid
345
+ * unnecessary network latency. Pass `skillId` to trigger a deferred remote
346
+ * fetch only when the requested skill is not found locally — this preserves the
347
+ * ability to discover remote-only skills without penalising every call with a
348
+ * 10s timeout on flaky networks.
349
+ *
350
+ * Callers that install multiple skills in a loop should call this once and pass
351
+ * the result to `autoInstallFromCatalog` to avoid redundant network requests.
352
+ */
353
+ export async function resolveCatalog(
354
+ skillId?: string,
355
+ ): Promise<CatalogSkill[]> {
356
+ const repoSkillsDir = getRepoSkillsDir();
357
+ if (repoSkillsDir) {
358
+ const local = readLocalCatalog(repoSkillsDir);
359
+ if (local.length > 0) {
360
+ // If no specific skill requested, or it exists locally, skip remote fetch
361
+ if (!skillId || local.some((s) => s.id === skillId)) {
362
+ return local;
363
+ }
364
+ // Skill not found locally — merge with remote so remote-only skills
365
+ // can still be discovered. Local entries take precedence by id.
366
+ try {
367
+ const remote = await fetchCatalog();
368
+ const localIds = new Set(local.map((s) => s.id));
369
+ return [...local, ...remote.filter((s) => !localIds.has(s.id))];
370
+ } catch {
371
+ return local;
372
+ }
373
+ }
374
+ }
375
+
376
+ return fetchCatalog();
377
+ }
378
+
379
+ /**
380
+ * Attempt to find and install a skill from the first-party catalog.
381
+ * Returns true if the skill was installed, false if not found in catalog.
382
+ * Throws on install failures (network, filesystem, etc).
383
+ *
384
+ * When `catalog` is provided it is used directly, avoiding a redundant
385
+ * network fetch — pass a pre-resolved catalog when calling in a loop.
386
+ */
387
+ export async function autoInstallFromCatalog(
388
+ skillId: string,
389
+ catalog?: CatalogSkill[],
390
+ ): Promise<boolean> {
391
+ let skills: CatalogSkill[];
392
+
393
+ if (catalog) {
394
+ skills = catalog;
395
+ } else {
396
+ try {
397
+ skills = await resolveCatalog(skillId);
398
+ } catch (err) {
399
+ log.warn(
400
+ { err, skillId },
401
+ "Failed to fetch remote catalog for auto-install",
402
+ );
403
+ return false;
404
+ }
405
+ }
406
+
407
+ const entry = skills.find((s) => s.id === skillId);
408
+ if (!entry) {
409
+ return false;
410
+ }
411
+
412
+ await installSkillLocally(skillId, entry, false);
413
+ return true;
414
+ }
@@ -151,3 +151,35 @@ export function traverseIncludes(
151
151
  dfs(rootId);
152
152
  return { visited };
153
153
  }
154
+
155
+ /**
156
+ * Collect all missing skill IDs reachable from the root's include graph.
157
+ * DFS traversal that tracks visited nodes to prevent infinite loops on cycles.
158
+ * The root itself is never reported as missing (it's already loaded by the caller).
159
+ */
160
+ export function collectAllMissing(
161
+ rootId: string,
162
+ catalogIndex: Map<string, SkillSummary>,
163
+ ): Set<string> {
164
+ const missing = new Set<string>();
165
+ const visited = new Set<string>();
166
+
167
+ function dfs(id: string): void {
168
+ if (visited.has(id)) return;
169
+ visited.add(id);
170
+
171
+ const skill = catalogIndex.get(id);
172
+ if (!skill?.includes) return;
173
+
174
+ for (const childId of skill.includes) {
175
+ if (!catalogIndex.has(childId)) {
176
+ missing.add(childId);
177
+ } else if (!visited.has(childId)) {
178
+ dfs(childId);
179
+ }
180
+ }
181
+ }
182
+
183
+ dfs(rootId);
184
+ return missing;
185
+ }