@vellumai/cli 0.1.3 → 0.1.5

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.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,15 +1,15 @@
1
1
  import { GATEWAY_PORT } from "../lib/constants";
2
2
  import { buildOpenclawRuntimeServer } from "../lib/openclaw-runtime-server";
3
3
 
4
- export function buildOpenclawStartupScript(
4
+ export async function buildOpenclawStartupScript(
5
5
  bearerToken: string,
6
6
  sshUser: string,
7
7
  anthropicApiKey: string,
8
8
  timestampRedirect: string,
9
9
  userSetup: string,
10
10
  ownershipFixup: string,
11
- ): string {
12
- const runtimeServer = buildOpenclawRuntimeServer();
11
+ ): Promise<string> {
12
+ const runtimeServer = await buildOpenclawRuntimeServer();
13
13
 
14
14
  return `#!/bin/bash
15
15
  set -e
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "child_process";
2
2
  import { randomBytes } from "crypto";
3
3
  import { existsSync, unlinkSync, writeFileSync } from "fs";
4
+ import { createRequire } from "module";
4
5
  import { tmpdir, userInfo } from "os";
5
6
  import { dirname, join } from "path";
6
7
 
@@ -22,6 +23,8 @@ import { buildInterfacesSeed } from "../lib/interfaces-seed";
22
23
  import { generateRandomSuffix } from "../lib/random-name";
23
24
  import { exec, execOutput } from "../lib/step-runner";
24
25
 
26
+ const _require = createRequire(import.meta.url);
27
+
25
28
  const INSTALL_SCRIPT_REMOTE_PATH = "/tmp/vellum-install.sh";
26
29
  const INSTALL_SCRIPT_PATH = join(import.meta.dir, "..", "adapters", "install.sh");
27
30
  const MACHINE_TYPE = "e2-standard-4"; // 4 vCPUs, 16 GB memory
@@ -76,19 +79,19 @@ chown -R "$SSH_USER:$SSH_USER" "$SSH_USER_HOME" 2>/dev/null || true
76
79
  `;
77
80
  }
78
81
 
79
- export function buildStartupScript(
82
+ export async function buildStartupScript(
80
83
  species: Species,
81
84
  bearerToken: string,
82
85
  sshUser: string,
83
86
  anthropicApiKey: string,
84
- ): string {
87
+ ): Promise<string> {
85
88
  const platformUrl = process.env.VELLUM_ASSISTANT_PLATFORM_URL ?? "https://assistant.vellum.ai";
86
89
  const timestampRedirect = buildTimestampRedirect();
87
90
  const userSetup = buildUserSetup(sshUser);
88
91
  const ownershipFixup = buildOwnershipFixup();
89
92
 
90
93
  if (species === "openclaw") {
91
- return buildOpenclawStartupScript(
94
+ return await buildOpenclawStartupScript(
92
95
  bearerToken,
93
96
  sshUser,
94
97
  anthropicApiKey,
@@ -117,6 +120,7 @@ ANTHROPIC_API_KEY=\$ANTHROPIC_API_KEY
117
120
  GATEWAY_RUNTIME_PROXY_ENABLED=\$GATEWAY_RUNTIME_PROXY_ENABLED
118
121
  RUNTIME_PROXY_BEARER_TOKEN=\$RUNTIME_PROXY_BEARER_TOKEN
119
122
  INTERFACES_SEED_DIR=\$INTERFACES_SEED_DIR
123
+ RUNTIME_HTTP_PORT=7821
120
124
  DOTENV_EOF
121
125
 
122
126
  mkdir -p "\$HOME/.vellum/workspace"
@@ -485,7 +489,7 @@ async function hatchGcp(
485
489
  console.error("Error: ANTHROPIC_API_KEY environment variable is not set.");
486
490
  process.exit(1);
487
491
  }
488
- const startupScript = buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
492
+ const startupScript = await buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
489
493
  const startupScriptPath = join(tmpdir(), `${instanceName}-startup.sh`);
490
494
  writeFileSync(startupScriptPath, startupScript);
491
495
 
@@ -583,7 +587,8 @@ async function hatchGcp(
583
587
  (await checkCurlFailure(instanceName, project, zone, account))
584
588
  ) {
585
589
  console.log("");
586
- console.log("🔄 Detected install script curl failure, attempting recovery...");
590
+ const installScriptUrl = `${process.env.VELLUM_ASSISTANT_PLATFORM_URL ?? "https://assistant.vellum.ai"}/install.sh`;
591
+ console.log(`🔄 Detected install script curl failure for ${installScriptUrl}, attempting recovery...`);
587
592
  await recoverFromCurlFailure(instanceName, project, zone, sshUser, account);
588
593
  console.log("✅ Recovery successful!");
589
594
  } else {
@@ -649,7 +654,7 @@ async function hatchCustom(
649
654
  process.exit(1);
650
655
  }
651
656
 
652
- const startupScript = buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
657
+ const startupScript = await buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
653
658
  const startupScriptPath = join(tmpdir(), `${instanceName}-startup.sh`);
654
659
  writeFileSync(startupScriptPath, startupScript);
655
660
 
@@ -714,6 +719,22 @@ async function hatchCustom(
714
719
  }
715
720
  }
716
721
 
722
+ function resolveGatewayDir(): string {
723
+ const sourceDir = join(import.meta.dir, "..", "..", "..", "gateway");
724
+ if (existsSync(sourceDir)) {
725
+ return sourceDir;
726
+ }
727
+
728
+ try {
729
+ const pkgPath = _require.resolve("@vellumai/vellum-gateway/package.json");
730
+ return dirname(pkgPath);
731
+ } catch {
732
+ throw new Error(
733
+ "Gateway not found. Ensure @vellumai/vellum-gateway is installed or run from the source tree.",
734
+ );
735
+ }
736
+ }
737
+
717
738
  async function hatchLocal(species: Species, name: string | null): Promise<void> {
718
739
  const instanceName = name ?? `${species}-${generateRandomSuffix()}`;
719
740
 
@@ -722,9 +743,9 @@ async function hatchLocal(species: Species, name: string | null): Promise<void>
722
743
  console.log("");
723
744
 
724
745
  console.log("🔨 Starting local daemon...");
725
- const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
726
746
 
727
- if (existsSync(daemonBinary)) {
747
+ if (process.env.VELLUM_DESKTOP_APP) {
748
+ const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
728
749
  const child = spawn(daemonBinary, [], {
729
750
  detached: true,
730
751
  stdio: "ignore",
@@ -748,7 +769,17 @@ async function hatchLocal(species: Species, name: string | null): Promise<void>
748
769
  console.warn("⚠️ Daemon socket did not appear within 10s — continuing anyway");
749
770
  }
750
771
  } else {
751
- const child = spawn("bunx", ["vellum", "daemon", "start"], {
772
+ const assistantDir = join(import.meta.dir, "..", "..", "..", "assistant");
773
+ const assistantIndex = join(assistantDir, "src", "index.ts");
774
+
775
+ if (!existsSync(assistantIndex)) {
776
+ throw new Error(
777
+ "vellum-daemon binary not found and assistant source not available.\n" +
778
+ " Ensure the daemon binary is bundled alongside the CLI, or run from the source tree.",
779
+ );
780
+ }
781
+
782
+ const child = spawn("bun", ["run", assistantIndex, "daemon", "start"], {
752
783
  stdio: "inherit",
753
784
  env: { ...process.env },
754
785
  });
@@ -766,24 +797,19 @@ async function hatchLocal(species: Species, name: string | null): Promise<void>
766
797
  }
767
798
 
768
799
  console.log("🌐 Starting gateway...");
769
- const gatewayDir = join(import.meta.dir, "..", "..", "..", "gateway");
770
- if (!existsSync(gatewayDir)) {
771
- console.warn("⚠️ Gateway directory not found at", gatewayDir);
772
- console.warn(' Gateway will not be started\n');
773
- } else {
774
- const gateway = spawn("bun", ["run", "src/index.ts"], {
775
- cwd: gatewayDir,
776
- detached: true,
777
- stdio: "ignore",
778
- env: {
779
- ...process.env,
780
- GATEWAY_RUNTIME_PROXY_ENABLED: "true",
781
- GATEWAY_RUNTIME_PROXY_REQUIRE_AUTH: "false",
782
- },
783
- });
784
- gateway.unref();
785
- console.log("✅ Gateway started\n");
786
- }
800
+ const gatewayDir = resolveGatewayDir();
801
+ const gateway = spawn("bun", ["run", "src/index.ts"], {
802
+ cwd: gatewayDir,
803
+ detached: true,
804
+ stdio: "ignore",
805
+ env: {
806
+ ...process.env,
807
+ GATEWAY_RUNTIME_PROXY_ENABLED: "true",
808
+ GATEWAY_RUNTIME_PROXY_REQUIRE_AUTH: "false",
809
+ },
810
+ });
811
+ gateway.unref();
812
+ console.log("✅ Gateway started\n");
787
813
 
788
814
  const runtimeUrl = `http://localhost:${GATEWAY_PORT}`;
789
815
  const localEntry: AssistantEntry = {
package/src/lib/aws.ts CHANGED
@@ -420,7 +420,7 @@ export async function hatchAws(
420
420
  console.log("\u{1F50D} Finding latest Debian AMI...");
421
421
  const amiId = await getLatestDebianAmi(region);
422
422
 
423
- const startupScript = buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
423
+ const startupScript = await buildStartupScript(species, bearerToken, sshUser, anthropicApiKey);
424
424
  const startupScriptPath = join(tmpdir(), `${instanceName}-startup.sh`);
425
425
  writeFileSync(startupScriptPath, startupScript);
426
426
 
package/src/lib/gcp.ts CHANGED
@@ -139,15 +139,14 @@ export async function syncFirewallRules(
139
139
  "firewall-rules",
140
140
  "list",
141
141
  `--project=${project}`,
142
- `--filter=targetTags:${tag}`,
143
- "--format=value(name)",
142
+ "--format=json(name,targetTags)",
144
143
  ];
145
144
  if (account) listArgs.push(`--account=${account}`);
146
145
  const output = await execOutput("gcloud", listArgs);
147
- existingNames = output
148
- .split("\n")
149
- .map((s) => s.trim())
150
- .filter(Boolean);
146
+ const allRules = JSON.parse(output) as Array<{ name: string; targetTags?: string[] }>;
147
+ existingNames = allRules
148
+ .filter((r) => r.targetTags?.includes(tag))
149
+ .map((r) => r.name);
151
150
  } catch {
152
151
  existingNames = [];
153
152
  }
@@ -190,10 +189,11 @@ export async function fetchFirewallRules(
190
189
  "firewall-rules",
191
190
  "list",
192
191
  `--project=${project}`,
193
- `--filter=targetTags:${tag}`,
194
192
  "--format=json",
195
193
  ]);
196
- return output;
194
+ const rules = JSON.parse(output) as Array<{ targetTags?: string[] }>;
195
+ const filtered = rules.filter((r) => r.targetTags?.includes(tag));
196
+ return JSON.stringify(filtered, null, 2);
197
197
  }
198
198
 
199
199
  export interface GcpInstance {
@@ -1,20 +1,16 @@
1
- import { readFileSync } from "fs";
2
1
  import { join } from "path";
3
2
 
4
- const COMPONENTS_DIR = join(import.meta.dir, "..", "components");
5
- const CONSTANTS_PATH = join(import.meta.dir, "constants.ts");
3
+ const constantsSource = await Bun.file(join(import.meta.dir, "constants.ts")).text();
4
+ const defaultMainScreenSource = await Bun.file(join(import.meta.dir, "..", "components", "DefaultMainScreen.tsx")).text();
6
5
 
7
6
  function inlineLocalImports(source: string): string {
8
- const constantsSource = readFileSync(CONSTANTS_PATH, "utf-8");
9
-
10
7
  return source
11
8
  .replace(/import\s*\{[^}]*\}\s*from\s*["'][^"']*\/constants["'];?\s*\n/, constantsSource + "\n")
12
9
  .replace(/import\s*\{[^}]*\}\s*from\s*["']path["'];?\s*\n/, "");
13
10
  }
14
11
 
15
12
  export function buildInterfacesSeed(): string {
16
- const rawSource = readFileSync(join(COMPONENTS_DIR, "DefaultMainScreen.tsx"), "utf-8");
17
- const mainWindowSource = inlineLocalImports(rawSource);
13
+ const mainWindowSource = inlineLocalImports(defaultMainScreenSource);
18
14
 
19
15
  return `
20
16
  INTERFACES_SEED_DIR="/tmp/interfaces-seed"
@@ -1,10 +1,7 @@
1
- import { readFileSync } from "fs";
2
1
  import { join } from "path";
3
2
 
4
- const ADAPTER_PATH = join(import.meta.dir, "..", "adapters", "openclaw-http-server.ts");
5
-
6
- export function buildOpenclawRuntimeServer(): string {
7
- const serverSource = readFileSync(ADAPTER_PATH, "utf-8");
3
+ export async function buildOpenclawRuntimeServer(): Promise<string> {
4
+ const serverSource = await Bun.file(join(import.meta.dir, "..", "adapters", "openclaw-http-server.ts")).text();
8
5
 
9
6
  return `
10
7
  cat > /opt/openclaw-runtime-server.ts << 'RUNTIME_SERVER_EOF'