@vellumai/assistant 0.5.15 → 0.5.16

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 (175) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docs/architecture/integrations.md +15 -14
  3. package/knip.json +3 -1
  4. package/openapi.yaml +11 -43
  5. package/package.json +1 -1
  6. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -375
  7. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  8. package/src/__tests__/checker.test.ts +59 -0
  9. package/src/__tests__/cli-command-risk-guard.test.ts +98 -10
  10. package/src/__tests__/cli-memory.test.ts +372 -0
  11. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  12. package/src/__tests__/config-schema.test.ts +0 -2
  13. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  14. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  15. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  16. package/src/__tests__/conversation-usage.test.ts +1 -0
  17. package/src/__tests__/credential-security-e2e.test.ts +4 -1
  18. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  19. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  20. package/src/__tests__/guardian-routing-invariants.test.ts +151 -0
  21. package/src/__tests__/heartbeat-service.test.ts +1 -3
  22. package/src/__tests__/intent-routing.test.ts +6 -18
  23. package/src/__tests__/log-export-workspace.test.ts +2 -28
  24. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  25. package/src/__tests__/managed-store.test.ts +2 -10
  26. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  27. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  28. package/src/__tests__/migration-export-http.test.ts +3 -34
  29. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  30. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  31. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  32. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  33. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  34. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  35. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  36. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  37. package/src/__tests__/oauth-store.test.ts +0 -5
  38. package/src/__tests__/outlook-messaging-provider.test.ts +576 -0
  39. package/src/__tests__/path-policy.test.ts +2 -17
  40. package/src/__tests__/permission-types.test.ts +0 -1
  41. package/src/__tests__/platform-callback-registration.test.ts +3 -7
  42. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  43. package/src/__tests__/provider-error-scenarios.test.ts +0 -2
  44. package/src/__tests__/qdrant-manager.test.ts +68 -21
  45. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  46. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  47. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  48. package/src/__tests__/secret-allowlist.test.ts +20 -35
  49. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  50. package/src/__tests__/skill-load-feature-flag.test.ts +2 -43
  51. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  52. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  53. package/src/__tests__/skill-load-tool.test.ts +3 -67
  54. package/src/__tests__/skill-memory.test.ts +362 -119
  55. package/src/__tests__/skills.test.ts +22 -49
  56. package/src/__tests__/slack-channel-config.test.ts +2 -21
  57. package/src/__tests__/starter-bundle.test.ts +2 -8
  58. package/src/__tests__/stt-hints.test.ts +7 -2
  59. package/src/__tests__/system-prompt.test.ts +25 -45
  60. package/src/__tests__/task-compiler.test.ts +0 -21
  61. package/src/__tests__/task-management-tools.test.ts +0 -21
  62. package/src/__tests__/task-memory-cleanup.test.ts +0 -21
  63. package/src/__tests__/task-runner.test.ts +0 -21
  64. package/src/__tests__/task-scheduler.test.ts +0 -21
  65. package/src/__tests__/terminal-tools.test.ts +1 -17
  66. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  67. package/src/__tests__/tool-approval-handler.test.ts +1 -20
  68. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  69. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  70. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  71. package/src/__tests__/tool-executor.test.ts +0 -1
  72. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -20
  73. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  74. package/src/__tests__/trust-store.test.ts +9 -41
  75. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  76. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -21
  77. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -22
  78. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -22
  79. package/src/__tests__/trusted-contact-verification.test.ts +0 -22
  80. package/src/__tests__/turn-boundary-resolution.test.ts +0 -28
  81. package/src/__tests__/twilio-provider.test.ts +0 -16
  82. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  83. package/src/__tests__/twilio-routes.test.ts +0 -24
  84. package/src/__tests__/update-bulletin.test.ts +17 -89
  85. package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -20
  86. package/src/__tests__/usage-routes.test.ts +0 -21
  87. package/src/__tests__/user-reference.test.ts +1 -5
  88. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  89. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  90. package/src/__tests__/voice-invite-redemption.test.ts +0 -21
  91. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -24
  92. package/src/__tests__/voice-session-bridge.test.ts +0 -21
  93. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -23
  94. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -23
  96. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  97. package/src/acp/client-handler.ts +1 -2
  98. package/src/cli/__tests__/notifications.test.ts +0 -22
  99. package/src/cli/cli-memory.ts +176 -0
  100. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  101. package/src/cli/commands/oauth/connect.ts +15 -0
  102. package/src/cli/commands/oauth/providers.ts +49 -42
  103. package/src/cli/commands/platform/__tests__/connect.test.ts +2 -48
  104. package/src/cli/commands/platform/__tests__/disconnect.test.ts +2 -48
  105. package/src/cli/commands/platform/__tests__/status.test.ts +0 -50
  106. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  107. package/src/config/bundled-skills/messaging/SKILL.md +17 -2
  108. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  109. package/src/config/feature-flag-registry.json +16 -0
  110. package/src/config/loader.ts +4 -0
  111. package/src/config/schemas/security.ts +0 -6
  112. package/src/config/schemas/services.ts +8 -0
  113. package/src/context/window-manager.ts +28 -9
  114. package/src/credential-execution/approval-bridge.ts +0 -1
  115. package/src/daemon/config-watcher.ts +51 -0
  116. package/src/daemon/conversation-agent-loop.ts +3 -2
  117. package/src/daemon/conversation-process.ts +1 -0
  118. package/src/daemon/conversation-usage.ts +1 -0
  119. package/src/daemon/handlers/skills.ts +9 -1
  120. package/src/daemon/lifecycle.ts +13 -4
  121. package/src/daemon/message-types/conversations.ts +1 -0
  122. package/src/daemon/providers-setup.ts +2 -0
  123. package/src/daemon/server.ts +26 -22
  124. package/src/events/domain-events.ts +1 -2
  125. package/src/memory/db-init.ts +9 -0
  126. package/src/memory/job-handlers/batch-extraction.ts +16 -4
  127. package/src/memory/job-handlers/embedding.test.ts +3 -27
  128. package/src/memory/job-handlers/journal-carry-forward.test.ts +1 -29
  129. package/src/memory/llm-usage-store.ts +35 -2
  130. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  131. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  132. package/src/memory/migrations/index.ts +2 -0
  133. package/src/memory/qdrant-manager.ts +26 -5
  134. package/src/memory/query-expansion.ts +1 -1
  135. package/src/memory/retriever.test.ts +22 -20
  136. package/src/memory/retriever.ts +10 -2
  137. package/src/memory/schema/oauth.ts +1 -1
  138. package/src/memory/search/mmr.ts +8 -5
  139. package/src/memory/slack-thread-store.ts +17 -0
  140. package/src/messaging/providers/outlook/adapter.ts +193 -0
  141. package/src/messaging/providers/outlook/client.ts +311 -0
  142. package/src/messaging/providers/outlook/types.ts +83 -0
  143. package/src/notifications/adapters/slack.ts +1 -1
  144. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  145. package/src/oauth/connect-orchestrator.ts +10 -3
  146. package/src/oauth/oauth-store.ts +10 -11
  147. package/src/oauth/provider-serializer.ts +3 -0
  148. package/src/oauth/provider-visibility.ts +16 -0
  149. package/src/oauth/seed-providers.ts +49 -17
  150. package/src/permissions/checker.ts +39 -7
  151. package/src/permissions/types.ts +2 -4
  152. package/src/prompts/journal-context.ts +9 -11
  153. package/src/prompts/system-prompt.ts +3 -64
  154. package/src/prompts/templates/UPDATES.md +6 -0
  155. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  156. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  157. package/src/runtime/auth/route-policy.ts +0 -4
  158. package/src/runtime/guardian-reply-router.ts +6 -2
  159. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  160. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  161. package/src/runtime/routes/memory-item-routes.test.ts +0 -17
  162. package/src/runtime/routes/memory-item-routes.ts +103 -12
  163. package/src/runtime/routes/oauth-apps.ts +18 -1
  164. package/src/runtime/routes/oauth-providers.ts +13 -1
  165. package/src/runtime/routes/settings-routes.ts +1 -0
  166. package/src/runtime/routes/usage-routes.ts +19 -2
  167. package/src/runtime/routes/work-items-routes.test.ts +0 -21
  168. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  169. package/src/security/secret-allowlist.ts +4 -4
  170. package/src/skills/skill-memory.ts +62 -23
  171. package/src/tools/memory/handlers.test.ts +1 -29
  172. package/src/tools/permission-checker.ts +0 -18
  173. package/src/tools/skills/skill-script-runner.ts +1 -1
  174. package/src/util/device-id.ts +3 -65
  175. package/src/workspace/git-service.ts +27 -6
@@ -13,11 +13,11 @@ import {
13
13
  } from "node:fs";
14
14
  import { tmpdir } from "node:os";
15
15
  import { join } from "node:path";
16
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
16
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
17
+
17
18
  // ── Shared mock setup ────────────────────────────────────────────────────────
18
19
  // Config mock must be declared before importing tool modules so that the
19
20
  // mock.module calls are hoisted above the dynamic imports.
20
- import { mock } from "bun:test";
21
21
 
22
22
  mock.module("../config/loader.js", () => ({
23
23
  getConfig: () => ({
@@ -75,15 +75,6 @@ mock.module("../tools/network/script-proxy/index.js", () => ({
75
75
  getSessionEnv: () => ({}),
76
76
  }));
77
77
 
78
- mock.module("../util/platform.js", () => ({
79
- getProtectedDir: () => "/tmp/protected",
80
- getDataDir: () => "/tmp",
81
- getWorkspaceDir: () => "/tmp/workspace",
82
- getConversationsDir: () => "/tmp/workspace/conversations",
83
- getDbPath: () => "/tmp/assistant.db",
84
- ensureDataDir: () => {},
85
- }));
86
-
87
78
  mock.module("../tools/credentials/resolve.js", () => ({
88
79
  resolveCredentialRef: () => null,
89
80
  }));
@@ -15,30 +15,14 @@
15
15
  * - Secret scanning < 50ms for large outputs (100KB)
16
16
  * - ToolExecutor overhead < 20ms regardless of tool execution time
17
17
  */
18
- import { mkdtempSync, rmSync } from "node:fs";
19
- import { tmpdir } from "node:os";
20
- import { join } from "node:path";
21
- import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
22
18
 
23
- const testDir = mkdtempSync(join(tmpdir(), "tool-pipeline-bench-"));
19
+ import { beforeAll, describe, expect, mock, test } from "bun:test";
24
20
 
25
21
  // Local registry for ToolExecutor tests — the mock delegates to this map
26
22
  // so that registerTool/getTool/getAllTools work for our benchmark tools.
27
23
  const localRegistry = new Map<string, import("../tools/types.js").Tool>();
28
24
 
29
25
  // Mocks must precede imports of modules under test.
30
- mock.module("../util/platform.js", () => ({
31
- getDataDir: () => testDir,
32
- isMacOS: () => process.platform === "darwin",
33
- isLinux: () => process.platform === "linux",
34
- isWindows: () => process.platform === "win32",
35
- getPidPath: () => join(testDir, "test.pid"),
36
- getDbPath: () => join(testDir, "test.db"),
37
- getLogPath: () => join(testDir, "test.log"),
38
- ensureDataDir: () => {},
39
- getHooksDir: () => join(testDir, "hooks"),
40
- }));
41
-
42
26
  mock.module("../util/logger.js", () => ({
43
27
  getLogger: () =>
44
28
  new Proxy({} as Record<string, unknown>, {
@@ -192,14 +176,6 @@ describe("Tool execution pipeline benchmark", () => {
192
176
  }
193
177
  });
194
178
 
195
- afterAll(() => {
196
- try {
197
- rmSync(testDir, { recursive: true });
198
- } catch {
199
- // best effort cleanup
200
- }
201
- });
202
-
203
179
  test("classifyRisk: low-risk tool (file_read) is fast", async () => {
204
180
  const { timings } = await benchmarkAsync(
205
181
  () => classifyRisk("file_read", { path: "/tmp/test.ts" }, "/tmp"),
@@ -34,7 +34,6 @@ const mockConfig = {
34
34
  },
35
35
  permissions: {
36
36
  mode: "workspace" as const,
37
- dangerouslySkipPermissions: false,
38
37
  },
39
38
  };
40
39
 
@@ -52,7 +52,6 @@ const mockConfig = {
52
52
  },
53
53
  permissions: {
54
54
  mode: "workspace" as const,
55
- dangerouslySkipPermissions: false,
56
55
  },
57
56
  };
58
57
 
@@ -8,23 +8,9 @@
8
8
  * 5. Inline wait-and-resume for trusted-contact grant-gated tools
9
9
  */
10
10
 
11
- import { mkdtempSync, rmSync } from "node:fs";
12
- import { tmpdir } from "node:os";
13
- import { join } from "node:path";
14
11
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
15
12
 
16
- const testDir = mkdtempSync(join(tmpdir(), "tool-grant-escalation-test-"));
17
-
18
- mock.module("../util/platform.js", () => ({
19
- getDataDir: () => testDir,
20
- isMacOS: () => process.platform === "darwin",
21
- isLinux: () => process.platform === "linux",
22
- isWindows: () => process.platform === "win32",
23
- getPidPath: () => join(testDir, "test.pid"),
24
- getDbPath: () => join(testDir, "test.db"),
25
- getLogPath: () => join(testDir, "test.log"),
26
- ensureDataDir: () => {},
27
- }));
13
+ const testDir = process.env.VELLUM_WORKSPACE_DIR!;
28
14
 
29
15
  mock.module("../util/logger.js", () => ({
30
16
  getLogger: () =>
@@ -146,11 +132,6 @@ function resetTables(): void {
146
132
 
147
133
  afterAll(() => {
148
134
  resetDb();
149
- try {
150
- rmSync(testDir, { recursive: true });
151
- } catch {
152
- /* best effort */
153
- }
154
135
  });
155
136
 
156
137
  // ---------------------------------------------------------------------------
@@ -8,29 +8,9 @@
8
8
  * - handleToolResult includes toolUseId in emitted tool_result
9
9
  * - Event ordering: tool_use_preview_start → input_json_delta → tool_use
10
10
  */
11
- import { join } from "node:path";
12
11
  import { beforeEach, describe, expect, mock, test } from "bun:test";
13
12
 
14
13
  // ── Mock platform (must precede imports that read it) ─────────────────────────
15
- mock.module("../util/platform.js", () => ({
16
- getSessionTokenPath: () => "/tmp/test-token",
17
- getProtectedDir: () => join("/tmp/test", "protected"),
18
- getDataDir: () => "/tmp/test",
19
- getWorkspaceDir: () => "/tmp/test/workspace",
20
- getWorkspaceSkillsDir: () => "/tmp/test/skills",
21
- getSandboxWorkingDir: () => "/tmp/test/sandbox",
22
- getTCPPort: () => undefined,
23
- getTCPHost: () => "127.0.0.1",
24
- isTCPEnabled: () => false,
25
- isMacOS: () => false,
26
- isLinux: () => true,
27
- isWindows: () => false,
28
- getPidPath: () => "/tmp/test.pid",
29
- getLogPath: () => "/tmp/test.log",
30
- getDbPath: () => "/tmp/test.db",
31
- ensureDataDir: () => {},
32
- }));
33
-
34
14
  mock.module("../util/logger.js", () => ({
35
15
  getLogger: () =>
36
16
  new Proxy({} as Record<string, unknown>, {
@@ -1,16 +1,9 @@
1
- import {
2
- mkdirSync,
3
- mkdtempSync,
4
- readFileSync,
5
- rmSync,
6
- writeFileSync,
7
- } from "node:fs";
8
- import { tmpdir } from "node:os";
1
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
9
2
  import { dirname, join } from "node:path";
10
3
  import { beforeEach, describe, expect, mock, test } from "bun:test";
11
4
 
12
5
  // Create a temp directory for the trust file
13
- const testDir = mkdtempSync(join(tmpdir(), "trust-store-test-"));
6
+ const testDir = process.env.VELLUM_WORKSPACE_DIR!;
14
7
 
15
8
  // Point the file-based trust backend at the test temp dir so
16
9
  // getGatewaySecurityDir() (which checks this env var first) writes
@@ -18,19 +11,6 @@ const testDir = mkdtempSync(join(tmpdir(), "trust-store-test-"));
18
11
  process.env.GATEWAY_SECURITY_DIR = join(testDir, "protected");
19
12
 
20
13
  // Mock platform module so trust-store writes to temp dir instead of ~/.vellum
21
- mock.module("../util/platform.js", () => ({
22
- getProtectedDir: () => join(testDir, "protected"),
23
- getWorkspaceDir: () => join(testDir, "workspace"),
24
- getDataDir: () => testDir,
25
- isMacOS: () => process.platform === "darwin",
26
- isLinux: () => process.platform === "linux",
27
- isWindows: () => process.platform === "win32",
28
- getPidPath: () => join(testDir, "test.pid"),
29
- getDbPath: () => join(testDir, "test.db"),
30
- getLogPath: () => join(testDir, "test.log"),
31
- ensureDataDir: () => {},
32
- }));
33
-
34
14
  // Mock logger to suppress output during tests
35
15
  mock.module("../util/logger.js", () => ({
36
16
  getLogger: () => ({
@@ -744,7 +724,7 @@ describe("Trust Store", () => {
744
724
  rule.id === "default:allow-bash-rm-bootstrap" ||
745
725
  rule.id === "default:allow-bash-rm-updates"
746
726
  ) {
747
- expect(rule.scope).toBe(join(testDir, "workspace"));
727
+ expect(rule.scope).toBe(testDir);
748
728
  } else {
749
729
  expect(rule.scope).toBe("everywhere");
750
730
  }
@@ -917,7 +897,7 @@ describe("Trust Store", () => {
917
897
  });
918
898
 
919
899
  test("bootstrap delete rule matches only when workingDir is the workspace dir", () => {
920
- const workspaceDir = join(testDir, "workspace");
900
+ const workspaceDir = testDir;
921
901
  // Should match when workingDir is the workspace directory — the bootstrap
922
902
  // rule (priority 100) outranks the global default allow (priority 50).
923
903
  const match = findHighestPriorityRule(
@@ -940,7 +920,7 @@ describe("Trust Store", () => {
940
920
  });
941
921
 
942
922
  test("updates delete rule matches only when workingDir is the workspace dir", () => {
943
- const workspaceDir = join(testDir, "workspace");
923
+ const workspaceDir = testDir;
944
924
  const match = findHighestPriorityRule(
945
925
  "bash",
946
926
  ["rm UPDATES.md"],
@@ -1028,7 +1008,7 @@ describe("Trust Store", () => {
1028
1008
  expect(managed!.tool).toBe("file_write");
1029
1009
  expect(managed!.decision).toBe("ask");
1030
1010
  expect(managed!.priority).toBe(50);
1031
- expect(managed!.pattern).toContain("workspace/skills/**");
1011
+ expect(managed!.pattern).toContain("skills/**");
1032
1012
 
1033
1013
  const bundled = rules.find(
1034
1014
  (r) => r.id === "default:ask-file_write-bundled-skills",
@@ -1048,7 +1028,7 @@ describe("Trust Store", () => {
1048
1028
  expect(managed!.tool).toBe("file_edit");
1049
1029
  expect(managed!.decision).toBe("ask");
1050
1030
  expect(managed!.priority).toBe(50);
1051
- expect(managed!.pattern).toContain("workspace/skills/**");
1031
+ expect(managed!.pattern).toContain("skills/**");
1052
1032
 
1053
1033
  const bundled = rules.find(
1054
1034
  (r) => r.id === "default:ask-file_edit-bundled-skills",
@@ -1159,13 +1139,7 @@ describe("Trust Store", () => {
1159
1139
  });
1160
1140
 
1161
1141
  test("findHighestPriorityRule matches default ask for file_write on managed skill path", () => {
1162
- const skillFile = join(
1163
- testDir,
1164
- "workspace",
1165
- "skills",
1166
- "my-skill",
1167
- "SKILL.md",
1168
- );
1142
+ const skillFile = join(testDir, "skills", "my-skill", "SKILL.md");
1169
1143
  const match = findHighestPriorityRule(
1170
1144
  "file_write",
1171
1145
  [`file_write:${skillFile}`],
@@ -1177,13 +1151,7 @@ describe("Trust Store", () => {
1177
1151
  });
1178
1152
 
1179
1153
  test("findHighestPriorityRule matches default ask for file_edit on managed skill path", () => {
1180
- const skillFile = join(
1181
- testDir,
1182
- "workspace",
1183
- "skills",
1184
- "my-skill",
1185
- "tools.ts",
1186
- );
1154
+ const skillFile = join(testDir, "skills", "my-skill", "tools.ts");
1187
1155
  const match = findHighestPriorityRule(
1188
1156
  "file_edit",
1189
1157
  [`file_edit:${skillFile}`],
@@ -9,30 +9,9 @@
9
9
  * 5. Delivery failures allow retry on next poll
10
10
  */
11
11
 
12
- import { mkdtempSync, rmSync } from "node:fs";
13
- import { tmpdir } from "node:os";
14
- import { join } from "node:path";
15
- import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
16
-
17
- const testDir = mkdtempSync(join(tmpdir(), "tc-approval-notifier-test-"));
12
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
18
13
 
19
14
  // ── Platform mock ──
20
- // eslint-disable-next-line @typescript-eslint/no-require-imports
21
- const realPlatform = require("../util/platform.js");
22
- mock.module("../util/platform.js", () => ({
23
- ...realPlatform,
24
- getDataDir: () => testDir,
25
- isMacOS: () => process.platform === "darwin",
26
- isLinux: () => process.platform === "linux",
27
- isWindows: () => process.platform === "win32",
28
- getPidPath: () => join(testDir, "test.pid"),
29
- getDbPath: () => join(testDir, "test.db"),
30
- getLogPath: () => join(testDir, "test.log"),
31
- ensureDataDir: () => {},
32
- normalizeAssistantId: (id: string) =>
33
- id === "self" || id === "" ? "self" : id,
34
- }));
35
-
36
15
  // ── Logger mock ──
37
16
  // eslint-disable-next-line @typescript-eslint/no-require-imports
38
17
  const realLogger = require("../util/logger.js");
@@ -255,14 +234,6 @@ describe("trusted-contact pending-approval notifier", () => {
255
234
  mockGuardianContact = null;
256
235
  });
257
236
 
258
- afterAll(() => {
259
- try {
260
- rmSync(testDir, { recursive: true });
261
- } catch {
262
- /* best effort */
263
- }
264
- });
265
-
266
237
  test("sends waiting message to trusted contact when pending approval exists", async () => {
267
238
  mockPendingApprovals = [
268
239
  {
@@ -17,29 +17,14 @@
17
17
  * f. Timeout/stale flow: guardian decision after prompt timeout produces deterministic outcome
18
18
  */
19
19
 
20
- import { mkdtempSync, rmSync } from "node:fs";
21
- import { tmpdir } from "node:os";
22
- import { join } from "node:path";
23
20
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
24
21
 
25
- const testDir = mkdtempSync(join(tmpdir(), "tc-inline-approval-integration-"));
22
+ const testDir = process.env.VELLUM_WORKSPACE_DIR!;
26
23
 
27
24
  // ---------------------------------------------------------------------------
28
25
  // Mocks — must be set before any production imports
29
26
  // ---------------------------------------------------------------------------
30
27
 
31
- mock.module("../util/platform.js", () => ({
32
- getDataDir: () => testDir,
33
- getProtectedDir: () => join(testDir, "protected"),
34
- isMacOS: () => process.platform === "darwin",
35
- isLinux: () => process.platform === "linux",
36
- isWindows: () => process.platform === "win32",
37
- getPidPath: () => join(testDir, "test.pid"),
38
- getDbPath: () => join(testDir, "test.db"),
39
- getLogPath: () => join(testDir, "test.log"),
40
- ensureDataDir: () => {},
41
- }));
42
-
43
28
  mock.module("../util/logger.js", () => ({
44
29
  getLogger: () =>
45
30
  new Proxy({} as Record<string, unknown>, {
@@ -205,11 +190,6 @@ function resetTables(): void {
205
190
 
206
191
  afterAll(() => {
207
192
  resetDb();
208
- try {
209
- rmSync(testDir, { recursive: true });
210
- } catch {
211
- /* best effort */
212
- }
213
193
  });
214
194
 
215
195
  // ---------------------------------------------------------------------------
@@ -11,29 +11,12 @@
11
11
  * 4. activated — when the trusted contact successfully verifies
12
12
  * 5. denied — when the guardian denies the request
13
13
  */
14
- import { mkdtempSync, rmSync } from "node:fs";
15
- import { tmpdir } from "node:os";
16
- import { join } from "node:path";
17
14
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
18
15
 
19
16
  // ---------------------------------------------------------------------------
20
17
  // Test isolation: in-memory SQLite via temp directory
21
18
  // ---------------------------------------------------------------------------
22
19
 
23
- const testDir = mkdtempSync(join(tmpdir(), "trusted-contact-lifecycle-notif-"));
24
-
25
- mock.module("../util/platform.js", () => ({
26
- getProtectedDir: () => join(testDir, "protected"),
27
- getDataDir: () => testDir,
28
- isMacOS: () => process.platform === "darwin",
29
- isLinux: () => process.platform === "linux",
30
- isWindows: () => process.platform === "win32",
31
- getPidPath: () => join(testDir, "test.pid"),
32
- getDbPath: () => join(testDir, "test.db"),
33
- getLogPath: () => join(testDir, "test.log"),
34
- ensureDataDir: () => {},
35
- }));
36
-
37
20
  mock.module("../util/logger.js", () => ({
38
21
  getLogger: () =>
39
22
  new Proxy({} as Record<string, unknown>, {
@@ -96,11 +79,6 @@ initializeDb();
96
79
 
97
80
  afterAll(() => {
98
81
  resetDb();
99
- try {
100
- rmSync(testDir, { recursive: true });
101
- } catch {
102
- /* best effort */
103
- }
104
82
  });
105
83
 
106
84
  // ---------------------------------------------------------------------------
@@ -6,29 +6,12 @@
6
6
  * These tests confirm no channel-specific assumptions leaked into the
7
7
  * trusted contact code paths.
8
8
  */
9
- import { mkdtempSync, rmSync } from "node:fs";
10
- import { tmpdir } from "node:os";
11
- import { join } from "node:path";
12
9
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
13
10
 
14
11
  // ---------------------------------------------------------------------------
15
12
  // Test isolation: in-memory SQLite via temp directory
16
13
  // ---------------------------------------------------------------------------
17
14
 
18
- const testDir = mkdtempSync(join(tmpdir(), "trusted-contact-multichannel-"));
19
-
20
- mock.module("../util/platform.js", () => ({
21
- getProtectedDir: () => join(testDir, "protected"),
22
- getDataDir: () => testDir,
23
- isMacOS: () => process.platform === "darwin",
24
- isLinux: () => process.platform === "linux",
25
- isWindows: () => process.platform === "win32",
26
- getPidPath: () => join(testDir, "test.pid"),
27
- getDbPath: () => join(testDir, "test.db"),
28
- getLogPath: () => join(testDir, "test.log"),
29
- ensureDataDir: () => {},
30
- }));
31
-
32
15
  mock.module("../util/logger.js", () => ({
33
16
  getLogger: () =>
34
17
  new Proxy({} as Record<string, unknown>, {
@@ -106,11 +89,6 @@ initializeDb();
106
89
 
107
90
  afterAll(() => {
108
91
  resetDb();
109
- try {
110
- rmSync(testDir, { recursive: true });
111
- } catch {
112
- /* best effort */
113
- }
114
92
  });
115
93
 
116
94
  // ---------------------------------------------------------------------------
@@ -9,29 +9,12 @@
9
9
  * 4. Reactivate previously revoked members on re-verification
10
10
  * 5. NOT create a guardian binding (trusted contacts are not guardians)
11
11
  */
12
- import { mkdtempSync, rmSync } from "node:fs";
13
- import { tmpdir } from "node:os";
14
- import { join } from "node:path";
15
12
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
16
13
 
17
14
  // ---------------------------------------------------------------------------
18
15
  // Test isolation: in-memory SQLite via temp directory
19
16
  // ---------------------------------------------------------------------------
20
17
 
21
- const testDir = mkdtempSync(join(tmpdir(), "trusted-contact-verify-test-"));
22
-
23
- mock.module("../util/platform.js", () => ({
24
- getProtectedDir: () => join(testDir, "protected"),
25
- getDataDir: () => testDir,
26
- isMacOS: () => process.platform === "darwin",
27
- isLinux: () => process.platform === "linux",
28
- isWindows: () => process.platform === "win32",
29
- getPidPath: () => join(testDir, "test.pid"),
30
- getDbPath: () => join(testDir, "test.db"),
31
- getLogPath: () => join(testDir, "test.log"),
32
- ensureDataDir: () => {},
33
- }));
34
-
35
18
  mock.module("../util/logger.js", () => ({
36
19
  getLogger: () =>
37
20
  new Proxy({} as Record<string, unknown>, {
@@ -59,11 +42,6 @@ initializeDb();
59
42
 
60
43
  afterAll(() => {
61
44
  resetDb();
62
- try {
63
- rmSync(testDir, { recursive: true });
64
- } catch {
65
- /* best effort */
66
- }
67
45
  });
68
46
 
69
47
  // ---------------------------------------------------------------------------
@@ -1,28 +1,5 @@
1
- import { mkdtempSync, realpathSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
1
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
5
2
 
6
- const testDir = realpathSync(
7
- mkdtempSync(join(tmpdir(), "turn-boundary-resolution-test-")),
8
- );
9
- const workspaceDir = join(testDir, ".vellum", "workspace");
10
- const conversationsDir = join(workspaceDir, "conversations");
11
-
12
- mock.module("../util/platform.js", () => ({
13
- getProtectedDir: () => join(join(testDir, ".vellum"), "protected"),
14
- getDataDir: () => join(workspaceDir, "data"),
15
- getWorkspaceDir: () => workspaceDir,
16
- getConversationsDir: () => conversationsDir,
17
- isMacOS: () => process.platform === "darwin",
18
- isLinux: () => process.platform === "linux",
19
- isWindows: () => process.platform === "win32",
20
- getPidPath: () => join(testDir, "test.pid"),
21
- getDbPath: () => join(testDir, "test.db"),
22
- getLogPath: () => join(testDir, "test.log"),
23
- ensureDataDir: () => {},
24
- }));
25
-
26
3
  mock.module("../util/logger.js", () => ({
27
4
  getLogger: () =>
28
5
  new Proxy({} as Record<string, unknown>, {
@@ -74,11 +51,6 @@ function toolResultContent(toolUseIds: string[]): string {
74
51
 
75
52
  afterAll(() => {
76
53
  resetDb();
77
- try {
78
- rmSync(testDir, { recursive: true, force: true });
79
- } catch {
80
- /* best effort */
81
- }
82
54
  });
83
55
 
84
56
  describe("getAssistantMessageIdsInTurn", () => {
@@ -3,26 +3,10 @@
3
3
  * fail-closed auth token behavior, and caller ID eligibility checks.
4
4
  */
5
5
  import { createHmac } from "node:crypto";
6
- import { mkdtempSync } from "node:fs";
7
- import { tmpdir } from "node:os";
8
- import { join } from "node:path";
9
6
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
10
7
 
11
8
  import { credentialKey } from "../security/credential-key.js";
12
9
 
13
- const testDir = mkdtempSync(join(tmpdir(), "twilio-provider-test-"));
14
-
15
- mock.module("../util/platform.js", () => ({
16
- getDataDir: () => testDir,
17
- isMacOS: () => process.platform === "darwin",
18
- isLinux: () => process.platform === "linux",
19
- isWindows: () => process.platform === "win32",
20
- getPidPath: () => join(testDir, "test.pid"),
21
- getDbPath: () => join(testDir, "test.db"),
22
- getLogPath: () => join(testDir, "test.log"),
23
- ensureDataDir: () => {},
24
- }));
25
-
26
10
  mock.module("../util/logger.js", () => ({
27
11
  getLogger: () =>
28
12
  new Proxy({} as Record<string, unknown>, {
@@ -175,18 +175,13 @@ describe("generateTwiML with voice quality profile", () => {
175
175
 
176
176
  expect(twimlMedium).toContain('interruptSensitivity="medium"');
177
177
 
178
- const twimlHigh = generateTwiML(
179
- callSessionId,
180
- relayUrl,
181
- welcomeGreeting,
182
- {
183
- language: "en-US",
184
- transcriptionProvider: "Deepgram",
185
- ttsProvider: "Google",
186
- voice: "Google.en-US-Journey-O",
187
- interruptSensitivity: "high",
188
- },
189
- );
178
+ const twimlHigh = generateTwiML(callSessionId, relayUrl, welcomeGreeting, {
179
+ language: "en-US",
180
+ transcriptionProvider: "Deepgram",
181
+ ttsProvider: "Google",
182
+ voice: "Google.en-US-Journey-O",
183
+ interruptSensitivity: "high",
184
+ });
190
185
 
191
186
  expect(twimlHigh).toContain('interruptSensitivity="high"');
192
187
  });
@@ -12,9 +12,6 @@
12
12
  * - Voice webhook TwiML relay URL generation
13
13
  * - Handler-level idempotency concurrency (concurrent duplicates, failure-retry)
14
14
  */
15
- import { mkdtempSync, realpathSync, rmSync } from "node:fs";
16
- import { tmpdir } from "node:os";
17
- import { join } from "node:path";
18
15
  import {
19
16
  afterAll,
20
17
  beforeEach,
@@ -84,22 +81,6 @@ mock.module("../config/env.js", () => ({
84
81
  },
85
82
  }));
86
83
 
87
- const testDir = realpathSync(
88
- mkdtempSync(join(tmpdir(), "twilio-routes-test-")),
89
- );
90
-
91
- mock.module("../util/platform.js", () => ({
92
- getProtectedDir: () => join(testDir, "protected"),
93
- getDataDir: () => testDir,
94
- isMacOS: () => process.platform === "darwin",
95
- isLinux: () => process.platform === "linux",
96
- isWindows: () => process.platform === "win32",
97
- getPidPath: () => join(testDir, "test.pid"),
98
- getDbPath: () => join(testDir, "test.db"),
99
- getLogPath: () => join(testDir, "test.log"),
100
- ensureDataDir: () => {},
101
- }));
102
-
103
84
  mock.module("../util/logger.js", () => ({
104
85
  getLogger: () => ({
105
86
  info: () => {},
@@ -442,11 +423,6 @@ describe("twilio webhook routes", () => {
442
423
  afterAll(() => {
443
424
  globalThis.fetch = originalFetch;
444
425
  resetDb();
445
- try {
446
- rmSync(testDir, { recursive: true, force: true });
447
- } catch {
448
- /* best effort */
449
- }
450
426
  });
451
427
 
452
428
  // ── Callback idempotency / replay tests ───────────────────────────