@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
@@ -10,37 +10,7 @@ import { tmpdir } from "node:os";
10
10
  import { join } from "node:path";
11
11
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
12
12
 
13
- const TEST_DIR = join(tmpdir(), `vellum-skills-test-${crypto.randomUUID()}`);
14
-
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
- const realPlatform = require("../util/platform.js");
17
- mock.module("../util/platform.js", () => ({
18
- ...realPlatform,
19
- getProtectedDir: () => join(TEST_DIR, "protected"),
20
- getDataDir: () => TEST_DIR,
21
-
22
- getSandboxRootDir: () => join(TEST_DIR, "sandbox"),
23
- getSandboxWorkingDir: () => TEST_DIR,
24
- getInterfacesDir: () => join(TEST_DIR, "interfaces"),
25
- ensureDataDir: () => {},
26
- getPidPath: () => join(TEST_DIR, "vellum.pid"),
27
- getDbPath: () => join(TEST_DIR, "data", "assistant.db"),
28
- getLogPath: () => join(TEST_DIR, "logs", "vellum.log"),
29
- getHistoryPath: () => join(TEST_DIR, "history"),
30
- isMacOS: () => process.platform === "darwin",
31
- isLinux: () => process.platform === "linux",
32
- isWindows: () => process.platform === "win32",
33
- getPlatformName: () => process.platform,
34
- getClipboardCommand: () => null,
35
- getWorkspaceConfigPath: () => join(TEST_DIR, "config.json"),
36
- getWorkspaceSkillsDir: () => join(TEST_DIR, "skills"),
37
- getWorkspaceHooksDir: () => join(TEST_DIR, "hooks"),
38
- getHooksDir: () => join(TEST_DIR, "hooks"),
39
- getWorkspaceDir: () => TEST_DIR,
40
- getWorkspacePromptPath: (file: string) => join(TEST_DIR, file),
41
- readSessionToken: () => null,
42
- normalizeAssistantId: (id: string) => id,
43
- }));
13
+ const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
44
14
 
45
15
  const noopLogger = {
46
16
  info: () => {},
@@ -91,9 +61,9 @@ describe("skills catalog loading", () => {
91
61
  });
92
62
 
93
63
  afterEach(() => {
94
- if (existsSync(TEST_DIR)) {
95
- rmSync(TEST_DIR, { recursive: true, force: true });
96
- }
64
+ const skillsDir = join(TEST_DIR, "skills");
65
+ if (existsSync(skillsDir))
66
+ rmSync(skillsDir, { recursive: true, force: true });
97
67
  });
98
68
 
99
69
  test("parses markdown list path entries from SKILLS.md", () => {
@@ -221,9 +191,12 @@ describe("workspace skills", () => {
221
191
  });
222
192
 
223
193
  afterEach(() => {
224
- if (existsSync(TEST_DIR)) {
225
- rmSync(TEST_DIR, { recursive: true, force: true });
226
- }
194
+ const skillsDir = join(TEST_DIR, "skills");
195
+ if (existsSync(skillsDir))
196
+ rmSync(skillsDir, { recursive: true, force: true });
197
+ const outsideDir = join(TEST_DIR, "outside");
198
+ if (existsSync(outsideDir))
199
+ rmSync(outsideDir, { recursive: true, force: true });
227
200
  if (existsSync(WORKSPACE_DIR)) {
228
201
  rmSync(WORKSPACE_DIR, { recursive: true, force: true });
229
202
  }
@@ -282,9 +255,9 @@ describe("tool manifest detection", () => {
282
255
  });
283
256
 
284
257
  afterEach(() => {
285
- if (existsSync(TEST_DIR)) {
286
- rmSync(TEST_DIR, { recursive: true, force: true });
287
- }
258
+ const skillsDir = join(TEST_DIR, "skills");
259
+ if (existsSync(skillsDir))
260
+ rmSync(skillsDir, { recursive: true, force: true });
288
261
  });
289
262
 
290
263
  test("attaches toolManifest metadata when valid TOOLS.json is present", () => {
@@ -455,9 +428,9 @@ describe("includes frontmatter parsing", () => {
455
428
  });
456
429
 
457
430
  afterEach(() => {
458
- if (existsSync(TEST_DIR)) {
459
- rmSync(TEST_DIR, { recursive: true, force: true });
460
- }
431
+ const skillsDir = join(TEST_DIR, "skills");
432
+ if (existsSync(skillsDir))
433
+ rmSync(skillsDir, { recursive: true, force: true });
461
434
  });
462
435
 
463
436
  function writeSkillWithIncludes(skillId: string, includes: string): void {
@@ -553,9 +526,9 @@ describe("bundled browser skill", () => {
553
526
  });
554
527
 
555
528
  afterEach(() => {
556
- if (existsSync(TEST_DIR)) {
557
- rmSync(TEST_DIR, { recursive: true, force: true });
558
- }
529
+ const skillsDir = join(TEST_DIR, "skills");
530
+ if (existsSync(skillsDir))
531
+ rmSync(skillsDir, { recursive: true, force: true });
559
532
  });
560
533
 
561
534
  test("browser skill appears in full catalog (including bundled)", () => {
@@ -679,9 +652,9 @@ describe("bundled computer-use skill", () => {
679
652
  });
680
653
 
681
654
  afterEach(() => {
682
- if (existsSync(TEST_DIR)) {
683
- rmSync(TEST_DIR, { recursive: true, force: true });
684
- }
655
+ const skillsDir = join(TEST_DIR, "skills");
656
+ if (existsSync(skillsDir))
657
+ rmSync(skillsDir, { recursive: true, force: true });
685
658
  });
686
659
 
687
660
  test("computer-use skill appears in full catalog (including bundled)", () => {
@@ -1,9 +1,8 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
1
+ import { rmSync } from "node:fs";
3
2
  import { join } from "node:path";
4
3
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
5
4
 
6
- const testDir = mkdtempSync(join(tmpdir(), "slack-channel-cfg-test-"));
5
+ const testDir = process.env.VELLUM_WORKSPACE_DIR!;
7
6
  const secureStorePath = join(testDir, "keys.enc");
8
7
  const metadataPath = join(testDir, "metadata.json");
9
8
  const originalVellumDev = process.env.VELLUM_DEV;
@@ -59,19 +58,6 @@ mock.module("../config/loader.js", () => ({
59
58
  setNestedValue,
60
59
  }));
61
60
 
62
- mock.module("../util/platform.js", () => ({
63
- getProtectedDir: () => join(testDir, "protected"),
64
- getDataDir: () => testDir,
65
-
66
- isMacOS: () => process.platform === "darwin",
67
- isLinux: () => process.platform === "linux",
68
- isWindows: () => process.platform === "win32",
69
- getPidPath: () => join(testDir, "test.pid"),
70
- getDbPath: () => join(testDir, "test.db"),
71
- getLogPath: () => join(testDir, "test.log"),
72
- ensureDataDir: () => {},
73
- }));
74
-
75
61
  mock.module("../util/logger.js", () => ({
76
62
  getLogger: () => ({
77
63
  info: () => {},
@@ -182,11 +168,6 @@ afterAll(() => {
182
168
  } else {
183
169
  process.env.VELLUM_DEV = originalVellumDev;
184
170
  }
185
- try {
186
- rmSync(testDir, { recursive: true });
187
- } catch {
188
- /* best effort */
189
- }
190
171
  });
191
172
 
192
173
  describe("Slack channel config handler", () => {
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
4
4
 
5
- // Stub the root dir before importing trust-store so it uses our temp directory
5
+ // Set up a temp directory before importing trust-store
6
6
  const TEST_ROOT = join(
7
7
  import.meta.dirname ?? __dirname,
8
8
  "..",
@@ -11,23 +11,17 @@ const TEST_ROOT = join(
11
11
  );
12
12
  const TRUST_PATH = join(TEST_ROOT, "protected", "trust.json");
13
13
 
14
- // We need to mock getRootDir before importing trust-store
15
14
  import { mock } from "bun:test";
16
15
 
17
16
  // Point the file-based trust backend at the test temp dir.
18
17
  process.env.GATEWAY_SECURITY_DIR = join(TEST_ROOT, "protected");
19
18
 
20
- // Mock the platform module to use our test root
21
- mock.module("../util/platform.js", () => ({
22
- getProtectedDir: () => join(TEST_ROOT, "protected"),
23
- }));
24
-
25
19
  // Mock the skills config module used by defaults.ts
26
20
  mock.module("../config/skills.js", () => ({
27
21
  getBundledSkillsDir: () => join(TEST_ROOT, "bundled-skills"),
28
22
  }));
29
23
 
30
- // Now import trust-store (which uses the mocked platform)
24
+ // Now import trust-store (which uses GATEWAY_SECURITY_DIR)
31
25
  import {
32
26
  acceptStarterBundle,
33
27
  clearCache,
@@ -64,7 +64,11 @@ mock.module("pino", () => ({ default: mockPinoLogger }));
64
64
  mock.module("pino-pretty", () => ({ default: () => ({}) }));
65
65
 
66
66
  // Import after mocking
67
- import { buildSttHints, resolveCallHints, type SttHintsInput } from "../calls/stt-hints.js";
67
+ import {
68
+ buildSttHints,
69
+ resolveCallHints,
70
+ type SttHintsInput,
71
+ } from "../calls/stt-hints.js";
68
72
 
69
73
  function emptyInput(): SttHintsInput {
70
74
  return {
@@ -159,7 +163,8 @@ describe("buildSttHints", () => {
159
163
 
160
164
  test("proper nouns extracted across sentence boundaries", () => {
161
165
  const input = emptyInput();
162
- input.taskDescription = "Meet with Alice. Then call Bob! Ask Charlie? Done.";
166
+ input.taskDescription =
167
+ "Meet with Alice. Then call Bob! Ask Charlie? Done.";
163
168
  const result = buildSttHints(input);
164
169
  expect(result).toContain("Alice");
165
170
  expect(result).toContain("Bob");
@@ -5,45 +5,14 @@ import {
5
5
  rmSync,
6
6
  writeFileSync,
7
7
  } from "node:fs";
8
- import { tmpdir } from "node:os";
9
8
  import { join } from "node:path";
10
9
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
10
 
12
11
  // Mock platform to use a temp directory
13
- const TEST_DIR = join(tmpdir(), `vellum-sysprompt-test-${crypto.randomUUID()}`);
12
+ const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
14
13
 
15
14
  import { mock } from "bun:test";
16
15
 
17
- // eslint-disable-next-line @typescript-eslint/no-require-imports
18
- const realPlatform = require("../util/platform.js");
19
- mock.module("../util/platform.js", () => ({
20
- ...realPlatform,
21
- getProtectedDir: () => join(TEST_DIR, "protected"),
22
- getDataDir: () => TEST_DIR,
23
- getWorkspaceDir: () => TEST_DIR,
24
- getWorkspaceConfigPath: () => join(TEST_DIR, "config.json"),
25
- getWorkspaceSkillsDir: () => join(TEST_DIR, "skills"),
26
- getWorkspaceHooksDir: () => join(TEST_DIR, "hooks"),
27
- getConversationsDir: () => join(TEST_DIR, "conversations"),
28
- getWorkspacePromptPath: (file: string) => join(TEST_DIR, file),
29
- ensureDataDir: () => {},
30
- getPidPath: () => join(TEST_DIR, "vellum.pid"),
31
- getDbPath: () => join(TEST_DIR, "data", "assistant.db"),
32
- getLogPath: () => join(TEST_DIR, "logs", "vellum.log"),
33
- getHistoryPath: () => join(TEST_DIR, "history"),
34
- getHooksDir: () => join(TEST_DIR, "hooks"),
35
-
36
- getSandboxRootDir: () => join(TEST_DIR, "sandbox"),
37
- getSandboxWorkingDir: () => TEST_DIR,
38
- getInterfacesDir: () => join(TEST_DIR, "interfaces"),
39
- isMacOS: () => process.platform === "darwin",
40
- isLinux: () => process.platform === "linux",
41
- isWindows: () => process.platform === "win32",
42
- getPlatformName: () => process.platform,
43
- getClipboardCommand: () => null,
44
- readSessionToken: () => null,
45
- }));
46
-
47
16
  const noopLogger: Record<string, unknown> = new Proxy(
48
17
  {} as Record<string, unknown>,
49
18
  {
@@ -123,7 +92,6 @@ function basePrompt(result: string): string {
123
92
  for (const heading of [
124
93
  "## Configuration",
125
94
  "## Skills Catalog",
126
- "## Available Skills",
127
95
  "## External Communications Identity",
128
96
  "## Connected Services",
129
97
  "## Dynamic Skill Authoring Workflow",
@@ -144,8 +112,16 @@ describe("buildSystemPrompt", () => {
144
112
  });
145
113
 
146
114
  afterEach(() => {
147
- if (existsSync(TEST_DIR)) {
148
- rmSync(TEST_DIR, { recursive: true, force: true });
115
+ for (const name of [
116
+ "IDENTITY.md",
117
+ "SOUL.md",
118
+ "USER.md",
119
+ "BOOTSTRAP.md",
120
+ "UPDATES.md",
121
+ "skills",
122
+ ]) {
123
+ const p = join(TEST_DIR, name);
124
+ if (existsSync(p)) rmSync(p, { recursive: true, force: true });
149
125
  }
150
126
  });
151
127
 
@@ -196,7 +172,7 @@ describe("buildSystemPrompt", () => {
196
172
  expect(basePrompt(result)).toBe("Be kind");
197
173
  });
198
174
 
199
- test("appends skills catalog when skills are configured", () => {
175
+ test("does not include skills catalog in system prompt", () => {
200
176
  const skillsDir = join(TEST_DIR, "skills");
201
177
  mkdirSync(join(skillsDir, "release-checklist"), { recursive: true });
202
178
  writeFileSync(
@@ -208,11 +184,11 @@ describe("buildSystemPrompt", () => {
208
184
  writeFileSync(join(TEST_DIR, "IDENTITY.md"), "Custom identity");
209
185
  const result = buildSystemPrompt();
210
186
  expect(result).toContain("Custom identity");
211
- expect(result).toContain("## Available Skills");
212
- expect(result).toContain("**release-checklist**: Deployment checks");
187
+ expect(result).not.toContain("## Available Skills");
188
+ expect(result).not.toContain("**release-checklist**");
213
189
  });
214
190
 
215
- test("keeps SOUL.md and IDENTITY.md additive with skills", () => {
191
+ test("keeps SOUL.md and IDENTITY.md additive without skills catalog", () => {
216
192
  const skillsDir = join(TEST_DIR, "skills");
217
193
  mkdirSync(join(skillsDir, "incident-response"), { recursive: true });
218
194
  writeFileSync(
@@ -225,10 +201,7 @@ describe("buildSystemPrompt", () => {
225
201
 
226
202
  const result = buildSystemPrompt();
227
203
  expect(result).toContain("Identity content\n\nSoul content");
228
- expect(result).toContain("## Available Skills");
229
- expect(result.indexOf("Soul content")).toBeLessThan(
230
- result.indexOf("## Available Skills"),
231
- );
204
+ expect(result).not.toContain("## Available Skills");
232
205
  });
233
206
 
234
207
  test("includes external service access section", () => {
@@ -492,8 +465,15 @@ describe("ensurePromptFiles", () => {
492
465
  });
493
466
 
494
467
  afterEach(() => {
495
- if (existsSync(TEST_DIR)) {
496
- rmSync(TEST_DIR, { recursive: true, force: true });
468
+ for (const name of [
469
+ "IDENTITY.md",
470
+ "SOUL.md",
471
+ "USER.md",
472
+ "BOOTSTRAP.md",
473
+ "conversations",
474
+ ]) {
475
+ const p = join(TEST_DIR, name);
476
+ if (existsSync(p)) rmSync(p, { recursive: true, force: true });
497
477
  }
498
478
  });
499
479
 
@@ -1,22 +1,6 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
1
  import { afterAll, beforeEach, describe, expect, test } from "bun:test";
5
2
  import { mock } from "bun:test";
6
3
 
7
- const testDir = mkdtempSync(join(tmpdir(), "task-compiler-test-"));
8
-
9
- mock.module("../util/platform.js", () => ({
10
- getDataDir: () => testDir,
11
- isMacOS: () => process.platform === "darwin",
12
- isLinux: () => process.platform === "linux",
13
- isWindows: () => process.platform === "win32",
14
- getPidPath: () => join(testDir, "test.pid"),
15
- getDbPath: () => join(testDir, "test.db"),
16
- getLogPath: () => join(testDir, "test.log"),
17
- ensureDataDir: () => {},
18
- }));
19
-
20
4
  mock.module("../util/logger.js", () => ({
21
5
  getLogger: () =>
22
6
  new Proxy({} as Record<string, unknown>, {
@@ -49,11 +33,6 @@ initializeDb();
49
33
 
50
34
  afterAll(() => {
51
35
  resetDb();
52
- try {
53
- rmSync(testDir, { recursive: true });
54
- } catch {
55
- /* best effort */
56
- }
57
36
  });
58
37
 
59
38
  // ── Helpers ──────────────────────────────────────────────────────────
@@ -1,21 +1,5 @@
1
- import { mkdtempSync, 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 = mkdtempSync(join(tmpdir(), "task-mgmt-test-"));
7
-
8
- mock.module("../util/platform.js", () => ({
9
- getDataDir: () => testDir,
10
- isMacOS: () => process.platform === "darwin",
11
- isLinux: () => process.platform === "linux",
12
- isWindows: () => process.platform === "win32",
13
- getPidPath: () => join(testDir, "test.pid"),
14
- getDbPath: () => join(testDir, "test.db"),
15
- getLogPath: () => join(testDir, "test.log"),
16
- ensureDataDir: () => {},
17
- }));
18
-
19
3
  mock.module("../util/logger.js", () => ({
20
4
  getLogger: () =>
21
5
  new Proxy({} as Record<string, unknown>, {
@@ -76,11 +60,6 @@ initializeDb();
76
60
 
77
61
  afterAll(() => {
78
62
  resetDb();
79
- try {
80
- rmSync(testDir, { recursive: true });
81
- } catch {
82
- /* best effort */
83
- }
84
63
  });
85
64
 
86
65
  const ctx: ToolContext = {
@@ -1,6 +1,3 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
1
  import {
5
2
  afterAll,
6
3
  beforeAll,
@@ -15,19 +12,6 @@ import { eq } from "drizzle-orm";
15
12
 
16
13
  import { DEFAULT_CONFIG } from "../config/defaults.js";
17
14
 
18
- const testDir = mkdtempSync(join(tmpdir(), "task-memory-cleanup-"));
19
-
20
- mock.module("../util/platform.js", () => ({
21
- getDataDir: () => testDir,
22
- isMacOS: () => process.platform === "darwin",
23
- isLinux: () => process.platform === "linux",
24
- isWindows: () => process.platform === "win32",
25
- getPidPath: () => join(testDir, "test.pid"),
26
- getDbPath: () => join(testDir, "test.db"),
27
- getLogPath: () => join(testDir, "test.log"),
28
- ensureDataDir: () => {},
29
- }));
30
-
31
15
  mock.module("../util/logger.js", () => ({
32
16
  getLogger: () =>
33
17
  new Proxy({} as Record<string, unknown>, {
@@ -105,11 +89,6 @@ describe("invalidateAssistantInferredItemsForConversation", () => {
105
89
 
106
90
  afterAll(() => {
107
91
  resetDb();
108
- try {
109
- rmSync(testDir, { recursive: true });
110
- } catch {
111
- // best effort
112
- }
113
92
  });
114
93
 
115
94
  function seedConversations() {
@@ -1,21 +1,5 @@
1
- import { mkdtempSync, 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 = mkdtempSync(join(tmpdir(), "task-runner-test-"));
7
-
8
- mock.module("../util/platform.js", () => ({
9
- getDataDir: () => testDir,
10
- isMacOS: () => process.platform === "darwin",
11
- isLinux: () => process.platform === "linux",
12
- isWindows: () => process.platform === "win32",
13
- getPidPath: () => join(testDir, "test.pid"),
14
- getDbPath: () => join(testDir, "test.db"),
15
- getLogPath: () => join(testDir, "test.log"),
16
- ensureDataDir: () => {},
17
- }));
18
-
19
3
  mock.module("../util/logger.js", () => ({
20
4
  getLogger: () =>
21
5
  new Proxy({} as Record<string, unknown>, {
@@ -32,11 +16,6 @@ initializeDb();
32
16
 
33
17
  afterAll(() => {
34
18
  resetDb();
35
- try {
36
- rmSync(testDir, { recursive: true });
37
- } catch {
38
- /* best effort */
39
- }
40
19
  });
41
20
 
42
21
  // ── renderTemplate ──────────────────────────────────────────────────
@@ -1,21 +1,5 @@
1
- import { mkdtempSync, 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 = mkdtempSync(join(tmpdir(), "task-scheduler-test-"));
7
-
8
- mock.module("../util/platform.js", () => ({
9
- getDataDir: () => testDir,
10
- isMacOS: () => process.platform === "darwin",
11
- isLinux: () => process.platform === "linux",
12
- isWindows: () => process.platform === "win32",
13
- getPidPath: () => join(testDir, "test.pid"),
14
- getDbPath: () => join(testDir, "test.db"),
15
- getLogPath: () => join(testDir, "test.log"),
16
- ensureDataDir: () => {},
17
- }));
18
-
19
3
  mock.module("../util/logger.js", () => ({
20
4
  getLogger: () =>
21
5
  new Proxy({} as Record<string, unknown>, {
@@ -51,11 +35,6 @@ function forceScheduleDue(scheduleId: string): void {
51
35
 
52
36
  afterAll(() => {
53
37
  resetDb();
54
- try {
55
- rmSync(testDir, { recursive: true });
56
- } catch {
57
- /* best effort */
58
- }
59
38
  });
60
39
 
61
40
  // ── scheduleTask helper ─────────────────────────────────────────────
@@ -1,6 +1,3 @@
1
- import { mkdtempSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
1
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
5
2
 
6
3
  import type { ShellOutputResult } from "../tools/shared/shell-output.js";
@@ -16,20 +13,7 @@ mock.module("../util/logger.js", () => ({
16
13
  }),
17
14
  }));
18
15
 
19
- const testTmpDir = mkdtempSync(join(tmpdir(), "terminal-test-"));
20
-
21
- mock.module("../util/platform.js", () => ({
22
- getProtectedDir: () => join(testTmpDir, "protected"),
23
- getDataDir: () => join(testTmpDir, "data"),
24
- getSandboxWorkingDir: () => join(testTmpDir, "sandbox"),
25
- isMacOS: () => process.platform === "darwin",
26
- isLinux: () => process.platform === "linux",
27
- isWindows: () => process.platform === "win32",
28
- getPidPath: () => join(testTmpDir, "test.pid"),
29
- getDbPath: () => join(testTmpDir, "test.db"),
30
- getLogPath: () => join(testTmpDir, "test.log"),
31
- ensureDataDir: () => {},
32
- }));
16
+ const testTmpDir = process.env.VELLUM_WORKSPACE_DIR!;
33
17
 
34
18
  mock.module("../config/loader.js", () => ({
35
19
  getConfig: () => ({
@@ -216,85 +216,6 @@ function makeSystemPrompt(size: "small" | "production" = "small"): string {
216
216
  "Each MCP server entry requires: name, command, args, and optional env.",
217
217
  );
218
218
 
219
- // Dynamic skills catalog (~5K chars)
220
- sections.push("", "## Available Skills", "<available_skills>");
221
- const skillCategories = [
222
- {
223
- id: "gmail",
224
- name: "Gmail",
225
- desc: "Send, search, draft, and manage Gmail messages",
226
- },
227
- {
228
- id: "calendar",
229
- name: "Google Calendar",
230
- desc: "Create, list, update, and delete calendar events",
231
- },
232
- {
233
- id: "slack",
234
- name: "Slack",
235
- desc: "Send messages, search channels, manage threads",
236
- },
237
- { id: "contacts", name: "Contacts", desc: "Search and manage contacts" },
238
- {
239
- id: "tasks",
240
- name: "Tasks",
241
- desc: "Create, list, update, and complete tasks",
242
- },
243
- {
244
- id: "browser",
245
- name: "Browser",
246
- desc: "Navigate web pages, take screenshots, interact with web content",
247
- },
248
- {
249
- id: "schedule",
250
- name: "Schedule",
251
- desc: "Set reminders and schedule recurring tasks",
252
- },
253
- {
254
- id: "messaging",
255
- name: "Messaging",
256
- desc: "Send iMessage and SMS messages",
257
- },
258
- {
259
- id: "sequences",
260
- name: "Sequences",
261
- desc: "Create and manage multi-step automation workflows",
262
- },
263
- {
264
- id: "playbooks",
265
- name: "Playbooks",
266
- desc: "Execute pre-defined operational playbooks",
267
- },
268
- {
269
- id: "notes",
270
- name: "Notes",
271
- desc: "Create and manage notes in Apple Notes",
272
- },
273
- { id: "music", name: "Music", desc: "Control Apple Music playback" },
274
- {
275
- id: "photos",
276
- name: "Photos",
277
- desc: "Search and manage photos in Apple Photos",
278
- },
279
- {
280
- id: "maps",
281
- name: "Maps",
282
- desc: "Search locations, get directions, find nearby places",
283
- },
284
- {
285
- id: "weather",
286
- name: "Weather",
287
- desc: "Get current weather and forecasts",
288
- },
289
- ];
290
- for (const skill of skillCategories) {
291
- sections.push(
292
- ` <skill id="${skill.id}" name="${skill.name}" description="${skill.desc}" ` +
293
- `credential_setup="oauth" enabled="true" />`,
294
- );
295
- }
296
- sections.push("</available_skills>");
297
-
298
219
  // Attachment handling (~1K chars)
299
220
  sections.push(
300
221
  "",
@@ -1,20 +1,6 @@
1
- import { mkdtempSync, 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 = mkdtempSync(join(tmpdir(), "tool-approval-handler-test-"));
7
-
8
- mock.module("../util/platform.js", () => ({
9
- getDataDir: () => testDir,
10
- isMacOS: () => process.platform === "darwin",
11
- isLinux: () => process.platform === "linux",
12
- isWindows: () => process.platform === "win32",
13
- getPidPath: () => join(testDir, "test.pid"),
14
- getDbPath: () => join(testDir, "test.db"),
15
- getLogPath: () => join(testDir, "test.log"),
16
- ensureDataDir: () => {},
17
- }));
3
+ const testDir = process.env.VELLUM_WORKSPACE_DIR!;
18
4
 
19
5
  mock.module("../util/logger.js", () => ({
20
6
  getLogger: () =>
@@ -72,11 +58,6 @@ function clearTables(): void {
72
58
 
73
59
  afterAll(() => {
74
60
  resetDb();
75
- try {
76
- rmSync(testDir, { recursive: true });
77
- } catch {
78
- /* best effort */
79
- }
80
61
  });
81
62
 
82
63
  // ---------------------------------------------------------------------------