@vellumai/cli 0.10.7-dev.202607100313.fffdfea → 0.10.7-dev.202607100720.fba456e

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.7-dev.202607100313.fffdfea",
3
+ "version": "0.10.7-dev.202607100720.fba456e",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,4 +1,10 @@
1
- import { mkdtempSync, rmSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
1
+ import {
2
+ mkdtempSync,
3
+ rmSync,
4
+ writeFileSync,
5
+ existsSync,
6
+ mkdirSync,
7
+ } from "node:fs";
2
8
  import { tmpdir } from "node:os";
3
9
  import { join } from "node:path";
4
10
  import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
@@ -12,7 +18,11 @@ import { startCes } from "../local.js";
12
18
  // Capture spawn calls so we can assert on cmd/env.
13
19
  let lastSpawnCall: {
14
20
  cmd: string[];
15
- options: { detached?: boolean; env?: Record<string, string | undefined>; cwd?: string };
21
+ options: {
22
+ detached?: boolean;
23
+ env?: Record<string, string | undefined>;
24
+ cwd?: string;
25
+ };
16
26
  } | null = null;
17
27
 
18
28
  mock.module("node:child_process", () => ({
@@ -90,6 +100,12 @@ describe("startCes", () => {
90
100
  expect(lastSpawnCall).not.toBeNull();
91
101
  expect(lastSpawnCall!.options.detached).toBe(true);
92
102
 
103
+ // Under plain bun (source tree / tests), CES must run via `bun run
104
+ // src/main.ts` — never an adjacent `credential-executor` binary, which in
105
+ // bun's own bin dir is an unrelated globally-installed package bin.
106
+ expect(lastSpawnCall!.cmd[0]).toBe(process.execPath);
107
+ expect(lastSpawnCall!.cmd).toContain("src/main.ts");
108
+
93
109
  // Verify env vars
94
110
  const env = lastSpawnCall!.options.env!;
95
111
  expect(env["CES_LOCAL_SOCKET"]).toBeDefined();
package/src/lib/local.ts CHANGED
@@ -94,9 +94,26 @@ function hasLocalRuntimeComponents(installDir: string): boolean {
94
94
  );
95
95
  }
96
96
 
97
- function resolveBunExecutable(): string {
97
+ /**
98
+ * True when this process is a compiled standalone binary (desktop app or
99
+ * `bun build --compile` CLI) rather than a script executed by a plain `bun`
100
+ * binary (source tree, bunx, npm/global install).
101
+ *
102
+ * Only a compiled binary may trust product siblings in
103
+ * `dirname(process.execPath)`: under plain bun that directory is bun's own
104
+ * bin dir (e.g. `~/.bun/bin`), where bin links of globally-installed packages
105
+ * (`assistant`, `credential-executor`) collide with app-bundle binary names
106
+ * and point at whatever version happens to be installed globally.
107
+ */
108
+ function isCompiledCli(): boolean {
98
109
  const execBase = basename(process.execPath);
99
- if (execBase === "bun" || execBase.startsWith("bun-")) {
110
+ return (
111
+ execBase !== "bun" && execBase !== "bunx" && !execBase.startsWith("bun-")
112
+ );
113
+ }
114
+
115
+ function resolveBunExecutable(): string {
116
+ if (!isCompiledCli()) {
100
117
  return process.execPath;
101
118
  }
102
119
 
@@ -781,7 +798,7 @@ function resolveGatewayDir(resources?: LocalInstanceResources): string {
781
798
 
782
799
  // Compiled binary: gateway/ bundled adjacent to the CLI executable.
783
800
  const binGateway = join(dirname(process.execPath), "gateway");
784
- if (isGatewaySourceDir(binGateway)) {
801
+ if (isCompiledCli() && isGatewaySourceDir(binGateway)) {
785
802
  return binGateway;
786
803
  }
787
804
 
@@ -897,7 +914,7 @@ export async function startCes(
897
914
  let ces;
898
915
  const runtimeCesDir = !watch ? localRuntimeCesDir(resources) : undefined;
899
916
  const cesBinary = join(dirname(process.execPath), "credential-executor");
900
- if (!runtimeCesDir && existsSync(cesBinary) && !watch) {
917
+ if (!runtimeCesDir && isCompiledCli() && existsSync(cesBinary) && !watch) {
901
918
  // Compiled binary alongside the CLI (desktop app / compiled CLI).
902
919
  const cesLogFd = openLogFile("hatch.log");
903
920
  ces = spawn(cesBinary, [], {
@@ -1253,7 +1270,7 @@ export function isGatewayWatchModeAvailable(): boolean {
1253
1270
  */
1254
1271
  function writeAssistantWrapper(resources: LocalInstanceResources): void {
1255
1272
  const assistantBinary = join(dirname(process.execPath), "assistant");
1256
- if (!existsSync(assistantBinary)) return;
1273
+ if (!isCompiledCli() || !existsSync(assistantBinary)) return;
1257
1274
 
1258
1275
  const workspaceDir = join(resources.instanceDir, ".vellum", "workspace");
1259
1276
  const protectedDir = join(resources.instanceDir, ".vellum", "protected");
@@ -1315,7 +1332,7 @@ export async function startLocalDaemon(
1315
1332
  // the user runs the compiled CLI directly from the terminal (e.g. via a
1316
1333
  // /usr/local/bin/vellum symlink into the app bundle).
1317
1334
  const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
1318
- if (existsSync(daemonBinary) && !watch) {
1335
+ if (isCompiledCli() && existsSync(daemonBinary) && !watch) {
1319
1336
  // In watch mode, skip the bundled binary and use source (bun --watch
1320
1337
  // only works with source files, not compiled binaries).
1321
1338
 
@@ -1609,7 +1626,12 @@ export async function startGateway(
1609
1626
  ? localRuntimeGatewayDir(resources)
1610
1627
  : undefined;
1611
1628
  const gatewayBinary = join(dirname(process.execPath), "vellum-gateway");
1612
- if (!runtimeGatewayDir && existsSync(gatewayBinary) && !watch) {
1629
+ if (
1630
+ !runtimeGatewayDir &&
1631
+ isCompiledCli() &&
1632
+ existsSync(gatewayBinary) &&
1633
+ !watch
1634
+ ) {
1613
1635
  // Use the compiled gateway binary when available (desktop app or compiled
1614
1636
  // CLI invoked from the terminal). In watch mode, skip the bundled binary
1615
1637
  // and use source (bun --watch only works with source files).