@vellumai/cli 0.1.2 → 0.1.3

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.2",
3
+ "version": "0.1.3",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@ import { spawn } from "child_process";
2
2
  import { randomBytes } from "crypto";
3
3
  import { existsSync, unlinkSync, writeFileSync } from "fs";
4
4
  import { tmpdir, userInfo } from "os";
5
- import { join } from "path";
5
+ import { dirname, join } from "path";
6
6
 
7
7
  import { buildOpenclawStartupScript } from "../adapters/openclaw";
8
8
  import { saveAssistantEntry } from "../lib/assistant-config";
@@ -722,21 +722,48 @@ async function hatchLocal(species: Species, name: string | null): Promise<void>
722
722
  console.log("");
723
723
 
724
724
  console.log("🔨 Starting local daemon...");
725
- const child = spawn("bunx", ["vellum", "daemon", "start"], {
726
- stdio: "inherit",
727
- env: { ...process.env },
728
- });
725
+ const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
729
726
 
730
- await new Promise<void>((resolve, reject) => {
731
- child.on("close", (code) => {
732
- if (code === 0) {
733
- resolve();
734
- } else {
735
- reject(new Error(`Daemon start exited with code ${code}`));
727
+ if (existsSync(daemonBinary)) {
728
+ const child = spawn(daemonBinary, [], {
729
+ detached: true,
730
+ stdio: "ignore",
731
+ env: { ...process.env },
732
+ });
733
+ child.unref();
734
+
735
+ const homeDir = process.env.HOME ?? userInfo().homedir;
736
+ const socketPath = join(homeDir, ".vellum", "vellum.sock");
737
+ const maxWait = 10000;
738
+ const pollInterval = 100;
739
+ let waited = 0;
740
+ while (waited < maxWait) {
741
+ if (existsSync(socketPath)) {
742
+ break;
736
743
  }
744
+ await new Promise((r) => setTimeout(r, pollInterval));
745
+ waited += pollInterval;
746
+ }
747
+ if (!existsSync(socketPath)) {
748
+ console.warn("⚠️ Daemon socket did not appear within 10s — continuing anyway");
749
+ }
750
+ } else {
751
+ const child = spawn("bunx", ["vellum", "daemon", "start"], {
752
+ stdio: "inherit",
753
+ env: { ...process.env },
737
754
  });
738
- child.on("error", reject);
739
- });
755
+
756
+ await new Promise<void>((resolve, reject) => {
757
+ child.on("close", (code) => {
758
+ if (code === 0) {
759
+ resolve();
760
+ } else {
761
+ reject(new Error(`Daemon start exited with code ${code}`));
762
+ }
763
+ });
764
+ child.on("error", reject);
765
+ });
766
+ }
740
767
 
741
768
  console.log("🌐 Starting gateway...");
742
769
  const gatewayDir = join(import.meta.dir, "..", "..", "..", "gateway");
@@ -92,12 +92,22 @@ async function retireCustom(entry: AssistantEntry): Promise<void> {
92
92
  console.log(`\u2705 Custom instance retired.`);
93
93
  }
94
94
 
95
+ function parseSource(): string | undefined {
96
+ const args = process.argv.slice(4);
97
+ for (let i = 0; i < args.length; i++) {
98
+ if (args[i] === "--source" && args[i + 1]) {
99
+ return args[i + 1];
100
+ }
101
+ }
102
+ return undefined;
103
+ }
104
+
95
105
  export async function retire(): Promise<void> {
96
106
  const name = process.argv[3];
97
107
 
98
108
  if (!name) {
99
109
  console.error("Error: Instance name is required.");
100
- console.error("Usage: vellum-cli retire <name>");
110
+ console.error("Usage: vellum-cli retire <name> [--source <source>]");
101
111
  process.exit(1);
102
112
  }
103
113
 
@@ -108,6 +118,7 @@ export async function retire(): Promise<void> {
108
118
  process.exit(1);
109
119
  }
110
120
 
121
+ const source = parseSource();
111
122
  const cloud = resolveCloud(entry);
112
123
 
113
124
  if (cloud === "gcp") {
@@ -117,14 +128,14 @@ export async function retire(): Promise<void> {
117
128
  console.error("Error: GCP project and zone not found in assistant config.");
118
129
  process.exit(1);
119
130
  }
120
- await retireGcpInstance(name, project, zone);
131
+ await retireGcpInstance(name, project, zone, source);
121
132
  } else if (cloud === "aws") {
122
133
  const region = entry.region;
123
134
  if (!region) {
124
135
  console.error("Error: AWS region not found in assistant config.");
125
136
  process.exit(1);
126
137
  }
127
- await retireAwsInstance(name, region);
138
+ await retireAwsInstance(name, region, source);
128
139
  } else if (cloud === "local") {
129
140
  await retireLocal();
130
141
  } else if (cloud === "custom") {
package/src/lib/aws.ts CHANGED
@@ -547,6 +547,7 @@ async function getInstanceIdByName(
547
547
  export async function retireInstance(
548
548
  name: string,
549
549
  region: string,
550
+ source?: string,
550
551
  ): Promise<void> {
551
552
  const instanceId = await getInstanceIdByName(name, region);
552
553
  if (!instanceId) {
@@ -556,6 +557,23 @@ export async function retireInstance(
556
557
  return;
557
558
  }
558
559
 
560
+ if (source) {
561
+ try {
562
+ await exec("aws", [
563
+ "ec2",
564
+ "create-tags",
565
+ "--resources",
566
+ instanceId,
567
+ "--tags",
568
+ `Key=retired-by,Value=${source}`,
569
+ "--region",
570
+ region,
571
+ ]);
572
+ } catch {
573
+ console.warn(`\u26a0\ufe0f Could not tag instance before termination`);
574
+ }
575
+ }
576
+
559
577
  console.log(`\u{1F5D1}\ufe0f Terminating AWS instance ${name} (${instanceId})\n`);
560
578
 
561
579
  const child = spawnChild(
package/src/lib/gcp.ts CHANGED
@@ -278,6 +278,7 @@ export async function retireInstance(
278
278
  name: string,
279
279
  project: string,
280
280
  zone: string,
281
+ source?: string,
281
282
  ): Promise<void> {
282
283
  const exists = await instanceExists(name, project, zone);
283
284
  if (!exists) {
@@ -287,6 +288,22 @@ export async function retireInstance(
287
288
  return;
288
289
  }
289
290
 
291
+ if (source) {
292
+ try {
293
+ await exec("gcloud", [
294
+ "compute",
295
+ "instances",
296
+ "add-labels",
297
+ name,
298
+ `--project=${project}`,
299
+ `--zone=${zone}`,
300
+ `--labels=retired-by=${source}`,
301
+ ]);
302
+ } catch {
303
+ console.warn(`\u26a0\ufe0f Could not label instance before deletion`);
304
+ }
305
+ }
306
+
290
307
  console.log(`\u{1F5D1}\ufe0f Deleting GCP instance ${name}\n`);
291
308
 
292
309
  const child = spawn(