@vellumai/cli 0.10.10 → 0.10.11-dev.202607212222.fe33210

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/cli",
3
- "version": "0.10.10",
3
+ "version": "0.10.11-dev.202607212222.fe33210",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "exports": {
@@ -19,6 +19,13 @@ const stopProcessMock = mock(
19
19
  async (_pid: number, _label: string): Promise<boolean> => true,
20
20
  );
21
21
 
22
+ // Snapshot the real modules so the afterAll below can restore them. Bun runs
23
+ // every test file in one process with a shared loader, and `mock.restore()`
24
+ // does not undo `mock.module()`; without restoring, these mocks (notably the
25
+ // partial `process.js` mock) leak into sibling test files.
26
+ const realOrphanDetection = { ...(await import("../lib/orphan-detection.js")) };
27
+ const realProcess = { ...(await import("../lib/process.js")) };
28
+
22
29
  beforeAll(() => {
23
30
  mock.module("../lib/orphan-detection.js", () => ({
24
31
  detectOrphanedProcesses: detectOrphansMock,
@@ -65,6 +72,9 @@ afterEach(() => {
65
72
 
66
73
  afterAll(() => {
67
74
  process.argv = [...originalArgv];
75
+ // Restore the real modules so the mocks do not leak into sibling test files.
76
+ mock.module("../lib/orphan-detection.js", () => realOrphanDetection);
77
+ mock.module("../lib/process.js", () => realProcess);
68
78
  });
69
79
 
70
80
  // ── Tests ─────────────────────────────────────────────────────────────────────
@@ -10,8 +10,9 @@ import {
10
10
  import { tmpdir } from "node:os";
11
11
  import { join } from "node:path";
12
12
 
13
- import { afterEach, describe, expect, mock, test } from "bun:test";
13
+ import { afterAll, afterEach, describe, expect, mock, test } from "bun:test";
14
14
 
15
+ const realChildProcess = { ...childProcess };
15
16
  const execFileSyncMock = mock(childProcess.execFileSync);
16
17
 
17
18
  mock.module("node:child_process", () => ({
@@ -19,6 +20,12 @@ mock.module("node:child_process", () => ({
19
20
  execFileSync: execFileSyncMock,
20
21
  }));
21
22
 
23
+ // Restore the real module once this file finishes so the mock does not leak
24
+ // into sibling test files in the same `bun test` run.
25
+ afterAll(() => {
26
+ mock.module("node:child_process", () => realChildProcess);
27
+ });
28
+
22
29
  import {
23
30
  buildIngressNginxConfig,
24
31
  buildRemoteWebIndexHtml,
@@ -25,7 +25,14 @@ afterAll(() => {
25
25
  /* best-effort cleanup */
26
26
  }
27
27
 
28
- // Reset all module mocks so mock.module() calls in one test file
29
- // don't leak into the next file in the same bun test run.
28
+ // Restore spies created via spyOn()/mock() at the end of the run.
29
+ //
30
+ // NOTE: this does NOT prevent inter-file leaks of `mock.module()`. This
31
+ // `afterAll` runs once, after ALL files complete (a preload's afterAll wraps
32
+ // the whole run, not each file), and `mock.restore()` does not undo
33
+ // `mock.module()` registrations anyway. A file that calls `mock.module()`
34
+ // must restore the real module itself in its own `afterAll` by re-registering
35
+ // the captured real exports (see e.g. teleport.test.ts / recover.test.ts),
36
+ // otherwise the mock leaks into whichever file Bun runs next.
30
37
  mock.restore();
31
38
  });
@@ -17,10 +17,22 @@ import type { AssistantEntry } from "../lib/assistant-config.js";
17
17
  const testDir = mkdtempSync(join(tmpdir(), "retire-local-test-"));
18
18
  const originalLockfileDir = process.env.VELLUM_LOCKFILE_DIR;
19
19
 
20
+ // Snapshot the real modules before mocking so the module-scoped `afterAll`
21
+ // below can restore them. Bun runs every test file in one process with a
22
+ // shared loader, and `mock.restore()` does not undo `mock.module()`. Without
23
+ // restoring, the `retire-archive.js` mock in particular leaks its hardcoded
24
+ // `test-assistant.*` paths into sibling files (e.g. `recover.test.ts`), which
25
+ // then fail to find their own archives.
26
+ const realProcess = { ...(await import("../lib/process.js")) };
27
+ const realNginxIngress = { ...(await import("../lib/nginx-ingress.js")) };
28
+ const realRetireArchive = { ...(await import("../lib/retire-archive.js")) };
29
+
20
30
  const stopProcessByPidFileMock = mock(
21
31
  async (_pidFile: string, _label: string): Promise<boolean> => true,
22
32
  );
23
- const stopOrphanedDaemonProcessesMock = mock(async (): Promise<boolean> => false);
33
+ const stopOrphanedDaemonProcessesMock = mock(
34
+ async (): Promise<boolean> => false,
35
+ );
24
36
  const stopIngressNginxMock = mock(async (): Promise<boolean> => false);
25
37
 
26
38
  mock.module("../lib/process.js", () => ({
@@ -40,6 +52,14 @@ mock.module("../lib/retire-archive.js", () => ({
40
52
  getMetadataPath: () => join(retiredStagingDir, "test-assistant.meta.json"),
41
53
  }));
42
54
 
55
+ // Restore the real modules once this file finishes so the mocks above do not
56
+ // leak into other test files in the same `bun test` run.
57
+ afterAll(() => {
58
+ mock.module("../lib/process.js", () => realProcess);
59
+ mock.module("../lib/nginx-ingress.js", () => realNginxIngress);
60
+ mock.module("../lib/retire-archive.js", () => realRetireArchive);
61
+ });
62
+
43
63
  import { retireLocal } from "../lib/retire-local.js";
44
64
 
45
65
  const instanceDir = join(testDir, "test-instance");
@@ -23,11 +23,19 @@ const isProcessAliveMock = mock((): { alive: boolean; pid: number | null } => ({
23
23
  pid: null,
24
24
  }));
25
25
 
26
+ const realProcess = { ...(await import("../lib/process.js")) };
27
+
26
28
  mock.module("../lib/process.js", () => ({
27
29
  isProcessAlive: isProcessAliveMock,
28
30
  stopProcessByPidFile: stopProcessByPidFileMock,
29
31
  }));
30
32
 
33
+ // Restore the real module once this file finishes so the mock does not leak
34
+ // into other test files in the same `bun test` run.
35
+ afterAll(() => {
36
+ mock.module("../lib/process.js", () => realProcess);
37
+ });
38
+
31
39
  import { sleep } from "../commands/sleep.js";
32
40
  import {
33
41
  DEFAULT_DAEMON_PORT,
@@ -282,6 +282,17 @@ mock.module("../lib/local-runtime-client.js", () => ({
282
282
  localRuntimePreflightFromGcs: localRuntimePreflightFromGcsMock,
283
283
  }));
284
284
 
285
+ // Snapshot the remaining real modules before mocking so `afterAll` can
286
+ // restore them too — otherwise these mocks leak into sibling test files that
287
+ // import the same modules in the same `bun test` run.
288
+ const realHatchLocal = { ...(await import("../lib/hatch-local.js")) };
289
+ const realDocker = { ...(await import("../lib/docker.js")) };
290
+ const realProcess = { ...(await import("../lib/process.js")) };
291
+ const realRetireLocal = { ...(await import("../lib/retire-local.js")) };
292
+ const realUpgradeLifecycle = {
293
+ ...(await import("../lib/upgrade-lifecycle.js")),
294
+ };
295
+
285
296
  const hatchLocalMock = mock(async () => {});
286
297
 
287
298
  mock.module("../lib/hatch-local.js", () => ({
@@ -350,6 +361,11 @@ afterAll(() => {
350
361
  mock.module("../lib/guardian-token.js", () => realGuardianToken);
351
362
  mock.module("../lib/platform-client.js", () => realPlatformClient);
352
363
  mock.module("../lib/local-runtime-client.js", () => realLocalRuntimeClient);
364
+ mock.module("../lib/hatch-local.js", () => realHatchLocal);
365
+ mock.module("../lib/docker.js", () => realDocker);
366
+ mock.module("../lib/process.js", () => realProcess);
367
+ mock.module("../lib/retire-local.js", () => realRetireLocal);
368
+ mock.module("../lib/upgrade-lifecycle.js", () => realUpgradeLifecycle);
353
369
  rmSync(testDir, { recursive: true, force: true });
354
370
  delete process.env.VELLUM_LOCKFILE_DIR;
355
371
  });
@@ -15,6 +15,15 @@ import { startCes } from "../local.js";
15
15
  // Mocks
16
16
  // ---------------------------------------------------------------------------
17
17
 
18
+ // Snapshot the real modules before any `mock.module()` call so we can
19
+ // re-register them in a module-scoped `afterAll` below. Bun runs every test
20
+ // file in one process with a shared loader; without restoring, these mocks
21
+ // leak into sibling files (e.g. `step-runner.test.ts`, whose real `spawn`
22
+ // then returns this file's fake child with no `stdin` and a no-op `on`).
23
+ const realChildProcess = { ...(await import("node:child_process")) };
24
+ const realXdgLog = { ...(await import("../xdg-log.js")) };
25
+ const realProcess = { ...(await import("../process.js")) };
26
+
18
27
  // Capture spawn calls so we can assert on cmd/env.
19
28
  let lastSpawnCall: {
20
29
  cmd: string[];
@@ -55,6 +64,15 @@ mock.module("../process.js", () => ({
55
64
  stopProcessGracefully: mock(async () => {}),
56
65
  }));
57
66
 
67
+ // Restore the real modules once this file finishes so the mocks above do not
68
+ // leak into other test files in the same `bun test` run. `mock.restore()` does
69
+ // not undo `mock.module()`, so we re-register the captured real exports.
70
+ afterAll(() => {
71
+ mock.module("node:child_process", () => realChildProcess);
72
+ mock.module("../xdg-log.js", () => realXdgLog);
73
+ mock.module("../process.js", () => realProcess);
74
+ });
75
+
58
76
  // ---------------------------------------------------------------------------
59
77
  // Tests
60
78
  // ---------------------------------------------------------------------------
@@ -1,4 +1,12 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import {
2
+ afterAll,
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ mock,
8
+ test,
9
+ } from "bun:test";
2
10
  import { join } from "path";
3
11
 
4
12
  const TEST_HOME = "/test/home";
@@ -18,6 +26,13 @@ mock.module("os", () => ({
18
26
  homedir: () => TEST_HOME,
19
27
  }));
20
28
 
29
+ // Restore the real `os` module once this file finishes so the `homedir()`
30
+ // override does not leak into other test files in the same `bun test` run.
31
+ afterAll(() => {
32
+ mock.module("node:os", () => realOs);
33
+ mock.module("os", () => realOs);
34
+ });
35
+
21
36
  // Imports that depend on the mocked `os` module must come after the
22
37
  // mock.module() calls above.
23
38
  const {
package/src/lib/local.ts CHANGED
@@ -42,8 +42,8 @@ const _require = createRequire(import.meta.url);
42
42
  const DARWIN_UNIX_SOCKET_MAX_PATH_BYTES = 103;
43
43
 
44
44
  // The longest socket filename we place in the workspace directory.
45
- // assistant-skill.sock = 20 chars, plus 1 for the "/" separator = 21 overhead.
46
- const LONGEST_SOCKET_FILENAME = "assistant-skill.sock";
45
+ // assistant.sock = 14 chars, plus 1 for the "/" separator = 15 overhead.
46
+ const LONGEST_SOCKET_FILENAME = "assistant.sock";
47
47
  const LOCAL_RUNTIME_PACKAGE = "vellum";
48
48
 
49
49
  export interface LocalRuntimeInstall {
@@ -300,7 +300,7 @@ function warnIfLegacyWorkspaceFallbackDetected(
300
300
  }
301
301
 
302
302
  /**
303
- * On macOS, if `{workspaceDir}/assistant-skill.sock` would exceed the
303
+ * On macOS, if `{workspaceDir}/assistant.sock` would exceed the
304
304
  * 103-byte AF_UNIX path limit, compute a short tmpdir-based IPC socket
305
305
  * directory and return it. Returns `undefined` when no override is needed
306
306
  * (the workspace path is short enough, or we're not on macOS).
@@ -340,7 +340,6 @@ function applyIpcSocketDirOverride(
340
340
  mkdirSync(override, { recursive: true });
341
341
  env.GATEWAY_IPC_SOCKET_DIR = override;
342
342
  env.ASSISTANT_IPC_SOCKET_DIR = override;
343
- env.ASSISTANT_SKILL_IPC_SOCKET_DIR = override;
344
343
  }
345
344
 
346
345
  function isAssistantSourceDir(dir: string): boolean {
@@ -30,6 +30,7 @@ export const LLM_PROVIDER_ENV_VAR_NAMES: Record<string, string> = {
30
30
  minimax: "MINIMAX_API_KEY",
31
31
  atlascloud: "ATLASCLOUD_API_KEY",
32
32
  together: "TOGETHER_API_KEY",
33
+ litellm: "LITELLM_API_KEY",
33
34
  baseten: "BASETEN_API_KEY",
34
35
  };
35
36