@vellumai/assistant 0.4.53 → 0.4.55

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 (255) hide show
  1. package/bun.lock +62 -349
  2. package/docs/architecture/integrations.md +1 -1
  3. package/docs/architecture/keychain-broker.md +94 -29
  4. package/docs/architecture/security.md +2 -2
  5. package/knip.json +7 -29
  6. package/package.json +2 -9
  7. package/src/__tests__/agent-loop.test.ts +1 -1
  8. package/src/__tests__/app-git-history.test.ts +0 -2
  9. package/src/__tests__/app-git-service.test.ts +1 -6
  10. package/src/__tests__/approval-cascade.test.ts +0 -1
  11. package/src/__tests__/avatar-e2e.test.ts +0 -1
  12. package/src/__tests__/browser-fill-credential.test.ts +1 -6
  13. package/src/__tests__/call-domain.test.ts +0 -1
  14. package/src/__tests__/call-routes-http.test.ts +0 -1
  15. package/src/__tests__/channel-guardian.test.ts +4 -4
  16. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  17. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  18. package/src/__tests__/checker.test.ts +13 -11
  19. package/src/__tests__/claude-code-skill-regression.test.ts +0 -1
  20. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -2
  21. package/src/__tests__/config-loader-backfill.test.ts +0 -3
  22. package/src/__tests__/config-schema.test.ts +3 -9
  23. package/src/__tests__/config-watcher.test.ts +11 -3
  24. package/src/__tests__/credential-broker-browser-fill.test.ts +27 -24
  25. package/src/__tests__/credential-broker-server-use.test.ts +60 -24
  26. package/src/__tests__/credential-security-e2e.test.ts +1 -6
  27. package/src/__tests__/credential-security-invariants.test.ts +13 -8
  28. package/src/__tests__/credential-vault-unit.test.ts +28 -12
  29. package/src/__tests__/credential-vault.test.ts +40 -28
  30. package/src/__tests__/credentials-cli.test.ts +1 -21
  31. package/src/__tests__/email-invite-adapter.test.ts +0 -1
  32. package/src/__tests__/fixtures/credential-security-fixtures.ts +3 -3
  33. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -79
  34. package/src/__tests__/gateway-only-enforcement.test.ts +1 -21
  35. package/src/__tests__/guardian-action-conversation-turn.test.ts +8 -8
  36. package/src/__tests__/guardian-action-late-reply.test.ts +13 -14
  37. package/src/__tests__/guardian-action-store.test.ts +0 -57
  38. package/src/__tests__/guardian-outbound-http.test.ts +1 -1
  39. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -3
  40. package/src/__tests__/hooks-blocking.test.ts +1 -1
  41. package/src/__tests__/hooks-config.test.ts +5 -29
  42. package/src/__tests__/hooks-discovery.test.ts +1 -1
  43. package/src/__tests__/hooks-integration.test.ts +1 -1
  44. package/src/__tests__/hooks-manager.test.ts +1 -1
  45. package/src/__tests__/hooks-runner.test.ts +1 -23
  46. package/src/__tests__/hooks-settings.test.ts +1 -1
  47. package/src/__tests__/hooks-templates.test.ts +1 -1
  48. package/src/__tests__/integration-status.test.ts +0 -1
  49. package/src/__tests__/invite-routes-http.test.ts +0 -3
  50. package/src/__tests__/list-messages-attachments.test.ts +4 -4
  51. package/src/__tests__/llm-usage-store.test.ts +50 -0
  52. package/src/__tests__/managed-proxy-context.test.ts +41 -41
  53. package/src/__tests__/media-generate-image.test.ts +2 -2
  54. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -6
  55. package/src/__tests__/memory-regressions.experimental.test.ts +4 -4
  56. package/src/__tests__/memory-regressions.test.ts +27 -27
  57. package/src/__tests__/memory-retrieval.benchmark.test.ts +1 -1
  58. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -4
  59. package/src/__tests__/notification-decision-fallback.test.ts +1 -1
  60. package/src/__tests__/oauth-cli.test.ts +1 -4
  61. package/src/__tests__/oauth-store.test.ts +1 -3
  62. package/src/__tests__/openai-provider.test.ts +7 -7
  63. package/src/__tests__/platform.test.ts +14 -4
  64. package/src/__tests__/pricing.test.ts +0 -223
  65. package/src/__tests__/provider-commit-message-generator.test.ts +1 -4
  66. package/src/__tests__/provider-fail-open-selection.test.ts +58 -54
  67. package/src/__tests__/provider-managed-proxy-integration.test.ts +63 -63
  68. package/src/__tests__/provider-registry-ollama.test.ts +3 -3
  69. package/src/__tests__/public-ingress-urls.test.ts +1 -1
  70. package/src/__tests__/registry.test.ts +3 -103
  71. package/src/__tests__/script-proxy-injection-runtime.test.ts +2 -7
  72. package/src/__tests__/secret-onetime-send.test.ts +1 -6
  73. package/src/__tests__/secret-routes-managed-proxy.test.ts +6 -13
  74. package/src/__tests__/secure-keys.test.ts +241 -229
  75. package/src/__tests__/session-abort-tool-results.test.ts +0 -1
  76. package/src/__tests__/session-confirmation-signals.test.ts +0 -1
  77. package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -7
  78. package/src/__tests__/session-pre-run-repair.test.ts +0 -1
  79. package/src/__tests__/session-provider-retry-repair.test.ts +0 -1
  80. package/src/__tests__/session-queue.test.ts +2 -4
  81. package/src/__tests__/session-slash-known.test.ts +0 -1
  82. package/src/__tests__/session-slash-queue.test.ts +0 -1
  83. package/src/__tests__/session-slash-unknown.test.ts +0 -1
  84. package/src/__tests__/session-workspace-injection.test.ts +0 -1
  85. package/src/__tests__/session-workspace-tool-tracking.test.ts +0 -1
  86. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  87. package/src/__tests__/slack-channel-config.test.ts +1 -7
  88. package/src/__tests__/swarm-recursion.test.ts +0 -1
  89. package/src/__tests__/swarm-session-integration.test.ts +0 -1
  90. package/src/__tests__/swarm-tool.test.ts +0 -1
  91. package/src/__tests__/task-compiler.test.ts +1 -1
  92. package/src/__tests__/test-support/browser-skill-harness.ts +0 -18
  93. package/src/__tests__/test-support/computer-use-skill-harness.ts +0 -23
  94. package/src/__tests__/tool-executor.test.ts +1 -1
  95. package/src/__tests__/trust-store.test.ts +3 -82
  96. package/src/__tests__/twilio-config.test.ts +0 -1
  97. package/src/__tests__/twilio-provider.test.ts +0 -5
  98. package/src/__tests__/twilio-routes.test.ts +0 -1
  99. package/src/__tests__/usage-cache-backfill-migration.test.ts +10 -10
  100. package/src/calls/guardian-question-copy.ts +1 -1
  101. package/src/cli/commands/bash.ts +3 -0
  102. package/src/cli/commands/doctor.ts +10 -34
  103. package/src/cli/commands/memory.ts +3 -5
  104. package/src/cli/commands/sessions.ts +1 -1
  105. package/src/cli/commands/usage.ts +359 -0
  106. package/src/cli/http-client.ts +22 -12
  107. package/src/cli/program.ts +2 -0
  108. package/src/cli/reference.ts +1 -0
  109. package/src/cli.ts +251 -181
  110. package/src/config/assistant-feature-flags.ts +0 -7
  111. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  112. package/src/config/bundled-skills/claude-code/SKILL.md +1 -1
  113. package/src/config/bundled-skills/claude-code/TOOLS.json +1 -1
  114. package/src/config/bundled-skills/gmail/SKILL.md +0 -1
  115. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  116. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  117. package/src/config/bundled-skills/messaging/SKILL.md +0 -1
  118. package/src/config/bundled-skills/sequences/SKILL.md +0 -1
  119. package/src/config/env.ts +13 -0
  120. package/src/config/feature-flag-registry.json +9 -41
  121. package/src/config/schemas/security.ts +1 -2
  122. package/src/config/skills.ts +1 -1
  123. package/src/contacts/contact-store.ts +0 -50
  124. package/src/daemon/approved-devices-store.ts +0 -44
  125. package/src/daemon/classifier.ts +1 -1
  126. package/src/daemon/config-watcher.ts +14 -8
  127. package/src/daemon/handlers/config-model.ts +1 -1
  128. package/src/daemon/handlers/sessions.ts +4 -116
  129. package/src/daemon/handlers/skills.ts +1 -1
  130. package/src/daemon/lifecycle.ts +13 -15
  131. package/src/daemon/providers-setup.ts +1 -1
  132. package/src/daemon/server.ts +20 -3
  133. package/src/daemon/session-slash.ts +2 -2
  134. package/src/daemon/shutdown-handlers.ts +15 -0
  135. package/src/daemon/watch-handler.ts +2 -2
  136. package/src/email/guardrails.ts +1 -1
  137. package/src/email/service.ts +0 -5
  138. package/src/hooks/templates.ts +1 -1
  139. package/src/media/app-icon-generator.ts +2 -2
  140. package/src/media/avatar-router.ts +2 -2
  141. package/src/media/gemini-image-service.ts +5 -5
  142. package/src/memory/admin.ts +2 -2
  143. package/src/memory/app-git-service.ts +0 -7
  144. package/src/memory/conversation-crud.ts +1 -1
  145. package/src/memory/conversation-title-service.ts +2 -2
  146. package/src/memory/embedding-backend.ts +30 -26
  147. package/src/memory/external-conversation-store.ts +0 -30
  148. package/src/memory/guardian-action-store.ts +0 -31
  149. package/src/memory/guardian-approvals.ts +1 -56
  150. package/src/memory/indexer.ts +4 -3
  151. package/src/memory/items-extractor.ts +1 -1
  152. package/src/memory/job-handlers/backfill.ts +5 -2
  153. package/src/memory/job-handlers/index-maintenance.ts +2 -2
  154. package/src/memory/job-handlers/media-processing.ts +2 -2
  155. package/src/memory/job-handlers/summarization.ts +1 -1
  156. package/src/memory/job-utils.ts +1 -2
  157. package/src/memory/jobs-worker.ts +2 -2
  158. package/src/memory/llm-usage-store.ts +57 -11
  159. package/src/memory/media-store.ts +4 -535
  160. package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +2 -2
  161. package/src/memory/migrations/110-channel-guardian.ts +0 -1
  162. package/src/memory/published-pages-store.ts +0 -83
  163. package/src/memory/qdrant-circuit-breaker.ts +0 -8
  164. package/src/memory/retriever.ts +1 -1
  165. package/src/memory/schema/calls.ts +0 -67
  166. package/src/memory/search/semantic.ts +1 -8
  167. package/src/memory/shared-app-links-store.ts +0 -15
  168. package/src/messaging/registry.ts +0 -5
  169. package/src/messaging/style-analyzer.ts +1 -1
  170. package/src/notifications/copy-composer.ts +5 -13
  171. package/src/notifications/decision-engine.ts +2 -2
  172. package/src/notifications/deliveries-store.ts +0 -39
  173. package/src/notifications/guardian-question-mode.ts +6 -10
  174. package/src/notifications/preference-extractor.ts +1 -1
  175. package/src/oauth/byo-connection.test.ts +29 -20
  176. package/src/oauth/provider-behaviors.ts +1 -1
  177. package/src/permissions/checker.ts +1 -1
  178. package/src/permissions/shell-identity.ts +0 -5
  179. package/src/permissions/trust-store.ts +0 -37
  180. package/src/prompts/system-prompt.ts +4 -4
  181. package/src/prompts/templates/SOUL.md +1 -1
  182. package/src/providers/managed-proxy/constants.ts +8 -10
  183. package/src/providers/managed-proxy/context.ts +14 -9
  184. package/src/providers/provider-send-message.ts +4 -52
  185. package/src/providers/registry.ts +16 -50
  186. package/src/runtime/actor-token-store.ts +0 -23
  187. package/src/runtime/auth/__tests__/guard-tests.test.ts +64 -0
  188. package/src/runtime/http-router.ts +5 -1
  189. package/src/runtime/http-server.ts +101 -4
  190. package/src/runtime/invite-instruction-generator.ts +25 -51
  191. package/src/runtime/invite-service.ts +0 -20
  192. package/src/runtime/routes/attachment-routes.ts +1 -1
  193. package/src/runtime/routes/brain-graph-routes.ts +1 -1
  194. package/src/runtime/routes/call-routes.ts +1 -1
  195. package/src/runtime/routes/conversation-routes.ts +32 -11
  196. package/src/runtime/routes/debug-routes.ts +1 -1
  197. package/src/runtime/routes/diagnostics-routes.ts +2 -2
  198. package/src/runtime/routes/documents-routes.ts +3 -3
  199. package/src/runtime/routes/global-search-routes.ts +1 -1
  200. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -20
  201. package/src/runtime/routes/guardian-refresh-routes.ts +0 -20
  202. package/src/runtime/routes/secret-routes.ts +4 -4
  203. package/src/runtime/routes/session-management-routes.ts +27 -0
  204. package/src/runtime/routes/trust-rules-routes.ts +1 -1
  205. package/src/security/credential-backend.ts +148 -0
  206. package/src/security/oauth2.ts +1 -1
  207. package/src/security/secret-allowlist.ts +1 -1
  208. package/src/security/secure-keys.ts +98 -160
  209. package/src/security/token-manager.ts +0 -7
  210. package/src/sequence/guardrails.ts +0 -4
  211. package/src/sequence/store.ts +1 -20
  212. package/src/sequence/types.ts +1 -36
  213. package/src/signals/bash.ts +33 -0
  214. package/src/signals/cancel.ts +69 -0
  215. package/src/signals/conversation-undo.ts +127 -0
  216. package/src/signals/trust-rule.ts +174 -0
  217. package/src/skills/clawhub.ts +5 -5
  218. package/src/skills/managed-store.ts +4 -4
  219. package/src/subagent/manager.ts +8 -1
  220. package/src/telemetry/usage-telemetry-reporter.test.ts +366 -0
  221. package/src/telemetry/usage-telemetry-reporter.ts +181 -0
  222. package/src/tools/claude-code/claude-code.ts +2 -2
  223. package/src/tools/credentials/vault.ts +8 -4
  224. package/src/tools/memory/handlers.test.ts +24 -26
  225. package/src/tools/memory/handlers.ts +1 -13
  226. package/src/tools/registry.ts +5 -100
  227. package/src/tools/terminal/parser.ts +34 -4
  228. package/src/tools/tool-manifest.ts +0 -10
  229. package/src/usage/actors.ts +0 -12
  230. package/src/util/canonicalize-identity.ts +0 -9
  231. package/src/util/errors.ts +0 -3
  232. package/src/util/platform.ts +24 -7
  233. package/src/util/pricing.ts +0 -38
  234. package/src/watcher/constants.ts +0 -7
  235. package/src/watcher/providers/linear.ts +1 -1
  236. package/src/work-items/work-item-store.ts +4 -4
  237. package/src/workspace/commit-message-provider.ts +1 -1
  238. package/src/workspace/git-service.ts +44 -1
  239. package/src/workspace/provider-commit-message-generator.ts +1 -1
  240. package/src/__tests__/fixtures/proxy-fixtures.ts +0 -147
  241. package/src/browser-extension-relay/client.ts +0 -155
  242. package/src/contacts/index.ts +0 -18
  243. package/src/daemon/tls-certs.ts +0 -270
  244. package/src/errors.ts +0 -41
  245. package/src/events/index.ts +0 -18
  246. package/src/followups/index.ts +0 -10
  247. package/src/playbooks/index.ts +0 -10
  248. package/src/runtime/auth/index.ts +0 -44
  249. package/src/tasks/candidate-store.ts +0 -95
  250. package/src/tools/browser/api-map.ts +0 -313
  251. package/src/tools/browser/auto-navigate.ts +0 -469
  252. package/src/tools/browser/headless-browser.ts +0 -590
  253. package/src/tools/browser/recording-store.ts +0 -75
  254. package/src/tools/computer-use/registry.ts +0 -21
  255. package/src/tools/tasks/index.ts +0 -27
@@ -56,7 +56,6 @@ mock.module("../util/platform.js", () => ({
56
56
  }));
57
57
 
58
58
  mock.module("../memory/guardian-action-store.js", () => ({
59
- getPendingDeliveryByConversation: () => null,
60
59
  getGuardianActionRequest: () => null,
61
60
  resolveGuardianActionRequest: () => {},
62
61
  }));
@@ -25,17 +25,11 @@ const metadataByKey = new Map<
25
25
  >();
26
26
 
27
27
  mock.module("../security/secure-keys.js", () => ({
28
- getSecureKey: () => undefined,
29
- setSecureKey: setSecureKeyMock,
30
28
  setSecureKeyAsync: async (key?: string, value?: string) =>
31
29
  setSecureKeyMock(key, value),
32
- deleteSecureKey: () => "deleted",
33
30
  deleteSecureKeyAsync: async () => "deleted" as const,
34
- listSecureKeys: () => [],
35
- getBackendType: () => null,
36
- isDowngradedFromKeychain: () => false,
31
+ listSecureKeysAsync: async () => [],
37
32
  _resetBackend: () => {},
38
- _setBackend: () => {},
39
33
  }));
40
34
 
41
35
  mock.module("../tools/credentials/metadata-store.js", () => ({
@@ -15,7 +15,6 @@ mock.module("../util/platform.js", () => ({
15
15
  }));
16
16
 
17
17
  mock.module("../memory/guardian-action-store.js", () => ({
18
- getPendingDeliveryByConversation: () => null,
19
18
  getGuardianActionRequest: () => null,
20
19
  resolveGuardianActionRequest: () => {},
21
20
  }));
@@ -15,7 +15,6 @@ mock.module("../util/platform.js", () => ({
15
15
  }));
16
16
 
17
17
  mock.module("../memory/guardian-action-store.js", () => ({
18
- getPendingDeliveryByConversation: () => null,
19
18
  getGuardianActionRequest: () => null,
20
19
  resolveGuardianActionRequest: () => {},
21
20
  }));
@@ -39,7 +39,6 @@ mock.module("../util/platform.js", () => ({
39
39
  }));
40
40
 
41
41
  mock.module("../memory/guardian-action-store.js", () => ({
42
- getPendingDeliveryByConversation: () => null,
43
42
  getGuardianActionRequest: () => null,
44
43
  resolveGuardianActionRequest: () => {},
45
44
  }));
@@ -621,8 +620,7 @@ describe("Session message queue", () => {
621
620
  const sessionErr = events.find((e) => e.type === "session_error");
622
621
  expect(sessionErr).toBeDefined();
623
622
 
624
- // Should also emit generic error for backward compatibility
625
- // (callers rely on error events to detect failures)
623
+ // Should also emit generic error (callers rely on error events to detect failures)
626
624
  const genericErr = events.find((e) => e.type === "error");
627
625
  expect(genericErr).toBeDefined();
628
626
  });
@@ -1674,7 +1672,7 @@ describe("Regression: cancel semantics and error channel split", () => {
1674
1672
  const sessionErr = allEvents.find((e) => e.type === "session_error");
1675
1673
  expect(sessionErr).toBeDefined();
1676
1674
 
1677
- // Should also get generic error for backward compatibility
1675
+ // Should also get generic error
1678
1676
  const genericErr = allEvents.find((e) => e.type === "error");
1679
1677
  expect(genericErr).toBeDefined();
1680
1678
  });
@@ -22,7 +22,6 @@ mock.module("../util/platform.js", () => ({
22
22
  }));
23
23
 
24
24
  mock.module("../memory/guardian-action-store.js", () => ({
25
- getPendingDeliveryByConversation: () => null,
26
25
  getGuardianActionRequest: () => null,
27
26
  resolveGuardianActionRequest: () => {},
28
27
  }));
@@ -22,7 +22,6 @@ mock.module("../util/platform.js", () => ({
22
22
  }));
23
23
 
24
24
  mock.module("../memory/guardian-action-store.js", () => ({
25
- getPendingDeliveryByConversation: () => null,
26
25
  getGuardianActionRequest: () => null,
27
26
  resolveGuardianActionRequest: () => {},
28
27
  }));
@@ -22,7 +22,6 @@ mock.module("../util/platform.js", () => ({
22
22
  }));
23
23
 
24
24
  mock.module("../memory/guardian-action-store.js", () => ({
25
- getPendingDeliveryByConversation: () => null,
26
25
  getGuardianActionRequest: () => null,
27
26
  resolveGuardianActionRequest: () => {},
28
27
  }));
@@ -25,7 +25,6 @@ mock.module("../util/platform.js", () => ({
25
25
  }));
26
26
 
27
27
  mock.module("../memory/guardian-action-store.js", () => ({
28
- getPendingDeliveryByConversation: () => null,
29
28
  getGuardianActionRequest: () => null,
30
29
  resolveGuardianActionRequest: () => {},
31
30
  }));
@@ -23,7 +23,6 @@ mock.module("../util/platform.js", () => ({
23
23
  }));
24
24
 
25
25
  mock.module("../memory/guardian-action-store.js", () => ({
26
- getPendingDeliveryByConversation: () => null,
27
26
  getGuardianActionRequest: () => null,
28
27
  resolveGuardianActionRequest: () => {},
29
28
  }));
@@ -54,7 +54,6 @@ mock.module("../config/assistant-feature-flags.js", () => ({
54
54
  },
55
55
  loadDefaultsRegistry: () => ({}),
56
56
  getAssistantFeatureFlagDefaults: () => ({}),
57
- _resetDefaultsCache: () => {},
58
57
  }));
59
58
 
60
59
  mock.module("../config/skill-state.js", () => ({
@@ -100,19 +100,13 @@ mock.module("../security/secure-keys.js", () => {
100
100
  return "not-found" as const;
101
101
  };
102
102
  return {
103
- getSecureKey: (account: string) => secureKeyStore[account] ?? undefined,
104
103
  getSecureKeyAsync: async (account: string) =>
105
104
  secureKeyStore[account] ?? undefined,
106
- setSecureKey: syncSet,
107
- deleteSecureKey: syncDelete,
108
105
  setSecureKeyAsync: async (account: string, value: string) =>
109
106
  syncSet(account, value),
110
107
  deleteSecureKeyAsync: async (account: string) => syncDelete(account),
111
- listSecureKeys: () => Object.keys(secureKeyStore),
112
- getBackendType: () => "encrypted",
113
- isDowngradedFromKeychain: () => false,
108
+ listSecureKeysAsync: async () => Object.keys(secureKeyStore),
114
109
  _resetBackend: () => {},
115
- _setBackend: () => {},
116
110
  };
117
111
  });
118
112
 
@@ -68,7 +68,6 @@ const mockProvider = {
68
68
  };
69
69
  mock.module("../security/secure-keys.js", () => ({
70
70
  getSecureKeyAsync: async () => "test-api-key",
71
- getSecureKey: () => "test-api-key",
72
71
  }));
73
72
 
74
73
  mock.module("../providers/registry.js", () => ({
@@ -57,7 +57,6 @@ const mockTestProvider = {
57
57
  let mockAnthropicKey: string | undefined = "test-api-key";
58
58
  mock.module("../security/secure-keys.js", () => ({
59
59
  getSecureKeyAsync: async () => mockAnthropicKey,
60
- getSecureKey: () => mockAnthropicKey,
61
60
  }));
62
61
 
63
62
  mock.module("../providers/registry.js", () => ({
@@ -63,7 +63,6 @@ const mockProvider = {
63
63
  };
64
64
  mock.module("../security/secure-keys.js", () => ({
65
65
  getSecureKeyAsync: async () => "test-api-key",
66
- getSecureKey: () => "test-api-key",
67
66
  }));
68
67
 
69
68
  mock.module("../providers/registry.js", () => ({
@@ -32,7 +32,7 @@ mock.module("../config/loader.js", () => ({
32
32
  }));
33
33
 
34
34
  mock.module("./indexer.js", () => ({
35
- indexMessageNow: () => {},
35
+ indexMessageNow: async () => ({ indexedSegments: 0, enqueuedJobs: 0 }),
36
36
  }));
37
37
 
38
38
  import type { Database } from "bun:sqlite";
@@ -61,24 +61,6 @@ export function buildSkillLoadHistory(
61
61
  ];
62
62
  }
63
63
 
64
- /**
65
- * Assert that a set of tool names is exactly the expected set (order-independent).
66
- */
67
- export function expectToolNamesEqual(
68
- actual: string[],
69
- expected: readonly string[],
70
- ): void {
71
- const sorted = [...actual].sort();
72
- const expectedSorted = [...expected].sort();
73
- if (JSON.stringify(sorted) !== JSON.stringify(expectedSorted)) {
74
- throw new Error(
75
- `Tool names mismatch.\nExpected: ${JSON.stringify(
76
- expectedSorted,
77
- )}\nActual: ${JSON.stringify(sorted)}`,
78
- );
79
- }
80
- }
81
-
82
64
  /**
83
65
  * Assert that all browser tool names are present in a given set.
84
66
  */
@@ -17,28 +17,5 @@ export const COMPUTER_USE_TOOL_NAMES = [
17
17
  "computer_use_respond",
18
18
  ] as const;
19
19
 
20
- /** The skill ID for the bundled computer-use skill (used in later PRs). */
21
- export const COMPUTER_USE_SKILL_ID = "computer-use";
22
-
23
20
  /** Number of computer_use_* tools. */
24
21
  export const COMPUTER_USE_TOOL_COUNT = COMPUTER_USE_TOOL_NAMES.length; // 11
25
-
26
- import { expect } from "bun:test";
27
-
28
- /**
29
- * Assert that every COMPUTER_USE_TOOL_NAMES entry is present in `names`.
30
- */
31
- export function assertComputerUseToolsPresent(names: string[]): void {
32
- for (const name of COMPUTER_USE_TOOL_NAMES) {
33
- expect(names).toContain(name);
34
- }
35
- }
36
-
37
- /**
38
- * Assert that no COMPUTER_USE_TOOL_NAMES entry is present in `names`.
39
- */
40
- export function assertComputerUseToolsAbsent(names: string[]): void {
41
- for (const name of COMPUTER_USE_TOOL_NAMES) {
42
- expect(names).not.toContain(name);
43
- }
44
- }
@@ -196,7 +196,7 @@ describe("ToolExecutor allowedToolNames gating", () => {
196
196
  }
197
197
  });
198
198
 
199
- test("executes normally when allowedToolNames is not set (backward compat)", async () => {
199
+ test("executes normally when allowedToolNames is not set", async () => {
200
200
  const executor = new ToolExecutor(makePrompter());
201
201
  const result = await executor.execute(
202
202
  "file_read",
@@ -57,7 +57,6 @@ import {
57
57
  } from "../permissions/trust-store.js";
58
58
 
59
59
  const trustPath = join(testDir, "protected", "trust.json");
60
- const legacyTrustPath = join(testDir, "trust.json");
61
60
  const DEFAULT_TEMPLATES = getDefaultRuleTemplates();
62
61
  const NUM_DEFAULTS = DEFAULT_TEMPLATES.length;
63
62
  const DEFAULT_PRIORITY_BY_ID = new Map(
@@ -73,11 +72,6 @@ describe("Trust Store", () => {
73
72
  } catch {
74
73
  /* may not exist */
75
74
  }
76
- try {
77
- rmSync(legacyTrustPath);
78
- } catch {
79
- /* may not exist */
80
- }
81
75
  });
82
76
 
83
77
  // Intentionally do not remove `testDir` in afterAll.
@@ -1227,79 +1221,6 @@ describe("Trust Store", () => {
1227
1221
  // ── loadFromDisk resilience (misc) ──────────────────────────────
1228
1222
 
1229
1223
  describe("loadFromDisk resilience (misc)", () => {
1230
- test("migrates legacy root trust file to protected path", () => {
1231
- mkdirSync(dirname(legacyTrustPath), { recursive: true });
1232
- writeFileSync(
1233
- legacyTrustPath,
1234
- JSON.stringify({
1235
- version: 3,
1236
- rules: [
1237
- {
1238
- id: "legacy-deny",
1239
- tool: "host_bash",
1240
- pattern: "rm -rf *",
1241
- scope: "everywhere",
1242
- decision: "deny",
1243
- priority: 200,
1244
- createdAt: 123,
1245
- },
1246
- ],
1247
- }),
1248
- );
1249
-
1250
- clearCache();
1251
- const rules = getAllRules();
1252
-
1253
- expect(rules.find((r) => r.id === "legacy-deny")).toBeDefined();
1254
- expect(readFileSync(trustPath, "utf-8")).toContain("legacy-deny");
1255
- expect(() => readFileSync(legacyTrustPath, "utf-8")).toThrow();
1256
- });
1257
-
1258
- test("prefers protected trust file when both protected and legacy files exist", () => {
1259
- mkdirSync(dirname(trustPath), { recursive: true });
1260
- writeFileSync(
1261
- trustPath,
1262
- JSON.stringify({
1263
- version: 3,
1264
- rules: [
1265
- {
1266
- id: "protected-rule",
1267
- tool: "bash",
1268
- pattern: "protected *",
1269
- scope: "/tmp",
1270
- decision: "allow",
1271
- priority: 100,
1272
- createdAt: 1,
1273
- },
1274
- ],
1275
- }),
1276
- );
1277
- writeFileSync(
1278
- legacyTrustPath,
1279
- JSON.stringify({
1280
- version: 3,
1281
- rules: [
1282
- {
1283
- id: "legacy-rule",
1284
- tool: "bash",
1285
- pattern: "legacy *",
1286
- scope: "/tmp",
1287
- decision: "deny",
1288
- priority: 200,
1289
- createdAt: 2,
1290
- },
1291
- ],
1292
- }),
1293
- );
1294
-
1295
- clearCache();
1296
- const rules = getAllRules();
1297
-
1298
- expect(rules.find((r) => r.id === "protected-rule")).toBeDefined();
1299
- expect(rules.find((r) => r.id === "legacy-rule")).toBeUndefined();
1300
- expect(readFileSync(legacyTrustPath, "utf-8")).toContain("legacy-rule");
1301
- });
1302
-
1303
1224
  test("malformed file (valid JSON but null) is handled gracefully", () => {
1304
1225
  mkdirSync(dirname(trustPath), { recursive: true });
1305
1226
  writeFileSync(trustPath, "null");
@@ -1540,10 +1461,10 @@ describe("Trust Store", () => {
1540
1461
  });
1541
1462
  });
1542
1463
 
1543
- // ── backward compatibility ────────────────────────────────────
1464
+ // ── optional ctx parameter ────────────────────────────────────
1544
1465
 
1545
- describe("backward compatibility", () => {
1546
- test("existing callers without ctx parameter still work", () => {
1466
+ describe("optional ctx parameter", () => {
1467
+ test("callers without ctx parameter still work", () => {
1547
1468
  addRule("bash", "git *", "/tmp", "allow", 200);
1548
1469
  // Calling without the 4th argument — must still match
1549
1470
  const match = findHighestPriorityRule("bash", ["git status"], "/tmp");
@@ -13,7 +13,6 @@ mock.module("../util/logger.js", () => ({
13
13
  }));
14
14
 
15
15
  mock.module("../security/secure-keys.js", () => ({
16
- getSecureKey: (key: string) => mockSecureKeys[key] ?? null,
17
16
  getSecureKeyAsync: async (key: string) => mockSecureKeys[key] ?? null,
18
17
  }));
19
18
 
@@ -41,11 +41,6 @@ mock.module("../config/loader.js", () => ({
41
41
  }));
42
42
 
43
43
  mock.module("../security/secure-keys.js", () => ({
44
- getSecureKey: (key: string) => {
45
- if (key === credentialKey("twilio", "auth_token")) return mockAuthToken;
46
- if (key === credentialKey("twilio", "account_sid")) return mockAccountSid;
47
- return undefined;
48
- },
49
44
  getSecureKeyAsync: async (key: string) => {
50
45
  if (key === credentialKey("twilio", "auth_token")) return mockAuthToken;
51
46
  if (key === credentialKey("twilio", "account_sid")) return mockAccountSid;
@@ -143,7 +143,6 @@ mock.module("../config/loader.js", () => ({
143
143
  }));
144
144
 
145
145
  mock.module("../security/secure-keys.js", () => ({
146
- getSecureKey: (key: string) => mockSecureKeyStore[key],
147
146
  setSecureKeyAsync: async (key: string, value: string) => {
148
147
  mockSecureKeyStore[key] = value;
149
148
  return true;
@@ -46,7 +46,7 @@ import {
46
46
  import { migrateBackfillUsageCacheAccounting } from "../memory/migrations/140-backfill-usage-cache-accounting.js";
47
47
  import type { PricingUsage } from "../usage/types.js";
48
48
  import {
49
- estimateCost,
49
+ resolvePricing,
50
50
  resolvePricingForUsageWithOverrides,
51
51
  } from "../util/pricing.js";
52
52
 
@@ -187,7 +187,8 @@ describe("migrateBackfillUsageCacheAccounting", () => {
187
187
  model,
188
188
  inputTokens: 700,
189
189
  outputTokens: 70,
190
- estimatedCostUsd: estimateCost(700, 70, model, "anthropic"),
190
+ estimatedCostUsd:
191
+ resolvePricing("anthropic", model, 700, 70).estimatedCostUsd ?? 0,
191
192
  });
192
193
  insertRequestLog({
193
194
  id: "log-prev",
@@ -201,12 +202,9 @@ describe("migrateBackfillUsageCacheAccounting", () => {
201
202
  }),
202
203
  });
203
204
 
204
- const flattenedHistoricalCost = estimateCost(
205
- 3_420_218,
206
- 11_768,
207
- model,
208
- "anthropic",
209
- );
205
+ const flattenedHistoricalCost =
206
+ resolvePricing("anthropic", model, 3_420_218, 11_768).estimatedCostUsd ??
207
+ 0;
210
208
  insertUsageEvent({
211
209
  id: "usage-target",
212
210
  conversationId: "conv-usage-1",
@@ -245,7 +243,8 @@ describe("migrateBackfillUsageCacheAccounting", () => {
245
243
  }),
246
244
  });
247
245
 
248
- const noLogCost = estimateCost(1_234, 56, model, "anthropic");
246
+ const noLogCost =
247
+ resolvePricing("anthropic", model, 1_234, 56).estimatedCostUsd ?? 0;
249
248
  insertUsageEvent({
250
249
  id: "usage-no-logs",
251
250
  conversationId: "conv-usage-2",
@@ -346,7 +345,8 @@ describe("migrateBackfillUsageCacheAccounting", () => {
346
345
  model,
347
346
  inputTokens: 1_200,
348
347
  outputTokens: 80,
349
- estimatedCostUsd: estimateCost(1_200, 80, model, "anthropic"),
348
+ estimatedCostUsd:
349
+ resolvePricing("anthropic", model, 1_200, 80).estimatedCostUsd ?? 0,
350
350
  });
351
351
  insertRequestLog({
352
352
  id: "log-target",
@@ -52,7 +52,7 @@ export async function generateGuardianCopy(
52
52
  const fallback = buildFallbackCopy(questionText);
53
53
 
54
54
  // If no provider is configured, return fallback immediately
55
- const resolved = resolveConfiguredProvider();
55
+ const resolved = await resolveConfiguredProvider();
56
56
  if (!resolved) {
57
57
  log.debug(
58
58
  "No provider available for guardian copy generation, using fallback",
@@ -47,6 +47,9 @@ This is a developer debugging tool for inspecting how the assistant invokes and
47
47
  observes shell commands. The command runs with the assistant's environment, working
48
48
  directory, and process context — not the caller's shell.
49
49
 
50
+ Requires the assistant to be running with VELLUM_DEBUG=1. When debug mode is off
51
+ (the default), the assistant ignores bash signal files and returns an error.
52
+
50
53
  The CLI writes the command to signals/bash.<requestId> and polls
51
54
  signals/bash.<requestId>.result for the output. The assistant must be running
52
55
  for this to work.
@@ -10,10 +10,10 @@ import { isHttpHealthy } from "../../daemon/daemon-control.js";
10
10
  import { getSecureKeyAsync } from "../../security/secure-keys.js";
11
11
  import {
12
12
  getDbPath,
13
+ getHooksDir,
13
14
  getLogPath,
14
15
  getRootDir,
15
16
  getWorkspaceDir,
16
- getWorkspaceHooksDir,
17
17
  getWorkspaceSkillsDir,
18
18
  } from "../../util/platform.js";
19
19
  import { log } from "../logger.js";
@@ -42,11 +42,10 @@ Diagnostic checks performed:
42
42
  6. Disk space Ensures at least 100MB free on the data partition
43
43
  7. Log file size Warns if the log file exceeds 50MB
44
44
  8. Database integrity Runs SQLite PRAGMA integrity_check
45
- 9. HTTP token permissions Verifies the http-token file has 0600 or 0700 mode
46
- 10. Trust rule syntax Validates trust.json structure and rule fields
47
- 11. WASM files Checks that tree-sitter WASM binaries are present
48
- 12. Browser runtime Verifies Playwright and Chromium availability
49
- 13. Sandbox diagnostics Reports sandbox backend status and configuration
45
+ 9. Trust rule syntax Validates trust.json structure and rule fields
46
+ 10. WASM files Checks that tree-sitter WASM binaries are present
47
+ 11. Browser runtime Verifies Playwright and Chromium availability
48
+ 12. Sandbox diagnostics Reports sandbox backend status and configuration
50
49
 
51
50
  Examples:
52
51
  $ assistant doctor`,
@@ -134,7 +133,7 @@ Examples:
134
133
  `${dataDir}/db`,
135
134
  `${dataDir}/logs`,
136
135
  getWorkspaceSkillsDir(),
137
- getWorkspaceHooksDir(),
136
+ getHooksDir(),
138
137
  `${rootDir}/protected`,
139
138
  ];
140
139
  const missing = requiredDirs.filter((d) => !existsSync(d));
@@ -216,30 +215,7 @@ Examples:
216
215
  fail("Database integrity check", "database file not found");
217
216
  }
218
217
 
219
- // 9. HTTP token
220
- const tokenPath = `${rootDir}/http-token`;
221
- if (existsSync(tokenPath)) {
222
- try {
223
- const tokenStat = statSync(tokenPath);
224
- const mode = tokenStat.mode & 0o777;
225
- if (mode === 0o600 || mode === 0o700) {
226
- pass(
227
- `HTTP token permissions (${mode.toString(8).padStart(4, "0")})`,
228
- );
229
- } else {
230
- fail(
231
- "HTTP token permissions",
232
- `expected 0600 or 0700, got 0${mode.toString(8)}`,
233
- );
234
- }
235
- } catch {
236
- fail("HTTP token permissions", "could not stat http-token file");
237
- }
238
- } else {
239
- pass("HTTP token (not present — assistant not running)");
240
- }
241
-
242
- // 10. Trust rule syntax
218
+ // 9. Trust rule syntax
243
219
  const trustPath = `${rootDir}/protected/trust.json`;
244
220
  if (existsSync(trustPath)) {
245
221
  try {
@@ -279,7 +255,7 @@ Examples:
279
255
  pass("Trust rule syntax (no trust.json yet)");
280
256
  }
281
257
 
282
- // 11. WASM files
258
+ // 10. WASM files
283
259
  const wasmFiles = [
284
260
  { pkg: "web-tree-sitter", file: "web-tree-sitter.wasm" },
285
261
  { pkg: "tree-sitter-bash", file: "tree-sitter-bash.wasm" },
@@ -321,7 +297,7 @@ Examples:
321
297
  fail("WASM files", missingWasm.join(", "));
322
298
  }
323
299
 
324
- // 12. Browser runtime (Playwright + Chromium)
300
+ // 11. Browser runtime (Playwright + Chromium)
325
301
  const { checkBrowserRuntime } =
326
302
  await import("../../tools/browser/runtime-check.js");
327
303
  const browserStatus = await checkBrowserRuntime();
@@ -339,7 +315,7 @@ Examples:
339
315
  );
340
316
  }
341
317
 
342
- // 13. Sandbox backend diagnostics
318
+ // 12. Sandbox backend diagnostics
343
319
  const { runSandboxDiagnostics } =
344
320
  await import("../../tools/terminal/sandbox-diagnostics.js");
345
321
  const sandbox = runSandboxDiagnostics();
@@ -58,9 +58,9 @@ Fields shown:
58
58
  Examples:
59
59
  $ assistant memory status`,
60
60
  )
61
- .action(() => {
61
+ .action(async () => {
62
62
  initializeDb();
63
- const status = getMemorySystemStatus();
63
+ const status = await getMemorySystemStatus();
64
64
  log.info(`Memory enabled: ${status.enabled ? "yes" : "no"}`);
65
65
  log.info(`Memory degraded: ${status.degraded ? "yes" : "no"}`);
66
66
  if (status.reason) log.info(`Reason: ${status.reason}`);
@@ -112,9 +112,7 @@ Examples:
112
112
 
113
113
  memory
114
114
  .command("cleanup")
115
- .description(
116
- "Queue cleanup jobs for stale superseded items",
117
- )
115
+ .description("Queue cleanup jobs for stale superseded items")
118
116
  .option(
119
117
  "--retention-ms <ms>",
120
118
  "Optional retention threshold in milliseconds",
@@ -227,7 +227,7 @@ Examples:
227
227
 
228
228
  const config = getConfig();
229
229
  const qdrantUrl = getQdrantUrlEnv() || config.memory.qdrant.url;
230
- const embeddingSelection = selectEmbeddingBackend(config);
230
+ const embeddingSelection = await selectEmbeddingBackend(config);
231
231
  const embeddingModel = embeddingSelection.backend
232
232
  ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
233
233
  : undefined;