@vellumai/cli 0.1.1 → 0.1.2
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/README.md +97 -0
- package/package.json +1 -1
- package/src/adapters/openclaw.ts +7 -0
- package/src/commands/hatch.ts +119 -120
- package/src/commands/retire.ts +139 -0
- package/src/index.ts +4 -1
- package/src/lib/assistant-config.ts +95 -0
- package/src/lib/aws.ts +590 -0
- package/src/lib/gcp.ts +71 -15
package/src/lib/gcp.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
|
|
1
3
|
import { exec, execOutput } from "./step-runner";
|
|
2
4
|
|
|
3
5
|
export async function getActiveProject(): Promise<string> {
|
|
@@ -39,16 +41,19 @@ interface FirewallRuleState {
|
|
|
39
41
|
async function describeFirewallRule(
|
|
40
42
|
ruleName: string,
|
|
41
43
|
project: string,
|
|
44
|
+
account?: string,
|
|
42
45
|
): Promise<FirewallRuleState | null> {
|
|
43
46
|
try {
|
|
44
|
-
const
|
|
47
|
+
const args = [
|
|
45
48
|
"compute",
|
|
46
49
|
"firewall-rules",
|
|
47
50
|
"describe",
|
|
48
51
|
ruleName,
|
|
49
52
|
`--project=${project}`,
|
|
50
53
|
"--format=json(name,direction,allowed,sourceRanges,destinationRanges,targetTags,description)",
|
|
51
|
-
]
|
|
54
|
+
];
|
|
55
|
+
if (account) args.push(`--account=${account}`);
|
|
56
|
+
const output = await execOutput("gcloud", args);
|
|
52
57
|
const parsed = JSON.parse(output);
|
|
53
58
|
const allowed = (parsed.allowed ?? [])
|
|
54
59
|
.map((a: { IPProtocol: string; ports?: string[] }) => {
|
|
@@ -85,7 +90,7 @@ function ruleNeedsUpdate(spec: FirewallRuleSpec, state: FirewallRuleState): bool
|
|
|
85
90
|
);
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
async function createFirewallRule(spec: FirewallRuleSpec, project: string): Promise<void> {
|
|
93
|
+
async function createFirewallRule(spec: FirewallRuleSpec, project: string, account?: string): Promise<void> {
|
|
89
94
|
const args = [
|
|
90
95
|
"compute",
|
|
91
96
|
"firewall-rules",
|
|
@@ -104,35 +109,41 @@ async function createFirewallRule(spec: FirewallRuleSpec, project: string): Prom
|
|
|
104
109
|
if (spec.destinationRanges) {
|
|
105
110
|
args.push(`--destination-ranges=${spec.destinationRanges}`);
|
|
106
111
|
}
|
|
112
|
+
if (account) args.push(`--account=${account}`);
|
|
107
113
|
await exec("gcloud", args);
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
async function deleteFirewallRule(ruleName: string, project: string): Promise<void> {
|
|
111
|
-
|
|
116
|
+
async function deleteFirewallRule(ruleName: string, project: string, account?: string): Promise<void> {
|
|
117
|
+
const args = [
|
|
112
118
|
"compute",
|
|
113
119
|
"firewall-rules",
|
|
114
120
|
"delete",
|
|
115
121
|
ruleName,
|
|
116
122
|
`--project=${project}`,
|
|
117
123
|
"--quiet",
|
|
118
|
-
]
|
|
124
|
+
];
|
|
125
|
+
if (account) args.push(`--account=${account}`);
|
|
126
|
+
await exec("gcloud", args);
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
export async function syncFirewallRules(
|
|
122
130
|
desiredRules: FirewallRuleSpec[],
|
|
123
131
|
project: string,
|
|
124
132
|
tag: string,
|
|
133
|
+
account?: string,
|
|
125
134
|
): Promise<void> {
|
|
126
135
|
let existingNames: string[];
|
|
127
136
|
try {
|
|
128
|
-
const
|
|
137
|
+
const listArgs = [
|
|
129
138
|
"compute",
|
|
130
139
|
"firewall-rules",
|
|
131
140
|
"list",
|
|
132
141
|
`--project=${project}`,
|
|
133
142
|
`--filter=targetTags:${tag}`,
|
|
134
143
|
"--format=value(name)",
|
|
135
|
-
]
|
|
144
|
+
];
|
|
145
|
+
if (account) listArgs.push(`--account=${account}`);
|
|
146
|
+
const output = await execOutput("gcloud", listArgs);
|
|
136
147
|
existingNames = output
|
|
137
148
|
.split("\n")
|
|
138
149
|
.map((s) => s.trim())
|
|
@@ -146,23 +157,23 @@ export async function syncFirewallRules(
|
|
|
146
157
|
for (const existingName of existingNames) {
|
|
147
158
|
if (!desiredNames.has(existingName)) {
|
|
148
159
|
console.log(` 🗑️ Deleting stale firewall rule: ${existingName}`);
|
|
149
|
-
await deleteFirewallRule(existingName, project);
|
|
160
|
+
await deleteFirewallRule(existingName, project, account);
|
|
150
161
|
}
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
for (const spec of desiredRules) {
|
|
154
|
-
const state = await describeFirewallRule(spec.name, project);
|
|
165
|
+
const state = await describeFirewallRule(spec.name, project, account);
|
|
155
166
|
|
|
156
167
|
if (!state) {
|
|
157
168
|
console.log(` ➕ Creating firewall rule: ${spec.name}`);
|
|
158
|
-
await createFirewallRule(spec, project);
|
|
169
|
+
await createFirewallRule(spec, project, account);
|
|
159
170
|
continue;
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
if (ruleNeedsUpdate(spec, state)) {
|
|
163
174
|
console.log(` 🔄 Updating firewall rule: ${spec.name}`);
|
|
164
|
-
await deleteFirewallRule(spec.name, project);
|
|
165
|
-
await createFirewallRule(spec, project);
|
|
175
|
+
await deleteFirewallRule(spec.name, project, account);
|
|
176
|
+
await createFirewallRule(spec, project, account);
|
|
166
177
|
continue;
|
|
167
178
|
}
|
|
168
179
|
|
|
@@ -222,9 +233,10 @@ export async function instanceExists(
|
|
|
222
233
|
instanceName: string,
|
|
223
234
|
project: string,
|
|
224
235
|
zone: string,
|
|
236
|
+
account?: string,
|
|
225
237
|
): Promise<boolean> {
|
|
226
238
|
try {
|
|
227
|
-
|
|
239
|
+
const args = [
|
|
228
240
|
"compute",
|
|
229
241
|
"instances",
|
|
230
242
|
"describe",
|
|
@@ -232,7 +244,9 @@ export async function instanceExists(
|
|
|
232
244
|
`--project=${project}`,
|
|
233
245
|
`--zone=${zone}`,
|
|
234
246
|
"--format=get(name)",
|
|
235
|
-
]
|
|
247
|
+
];
|
|
248
|
+
if (account) args.push(`--account=${account}`);
|
|
249
|
+
await execOutput("gcloud", args);
|
|
236
250
|
return true;
|
|
237
251
|
} catch {
|
|
238
252
|
return false;
|
|
@@ -259,3 +273,45 @@ export async function sshCommand(
|
|
|
259
273
|
`--command=${command}`,
|
|
260
274
|
]);
|
|
261
275
|
}
|
|
276
|
+
|
|
277
|
+
export async function retireInstance(
|
|
278
|
+
name: string,
|
|
279
|
+
project: string,
|
|
280
|
+
zone: string,
|
|
281
|
+
): Promise<void> {
|
|
282
|
+
const exists = await instanceExists(name, project, zone);
|
|
283
|
+
if (!exists) {
|
|
284
|
+
console.warn(
|
|
285
|
+
`\u26a0\ufe0f Instance ${name} not found in GCP (project=${project}, zone=${zone}).`,
|
|
286
|
+
);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log(`\u{1F5D1}\ufe0f Deleting GCP instance ${name}\n`);
|
|
291
|
+
|
|
292
|
+
const child = spawn(
|
|
293
|
+
"gcloud",
|
|
294
|
+
[
|
|
295
|
+
"compute",
|
|
296
|
+
"instances",
|
|
297
|
+
"delete",
|
|
298
|
+
name,
|
|
299
|
+
`--project=${project}`,
|
|
300
|
+
`--zone=${zone}`,
|
|
301
|
+
],
|
|
302
|
+
{ stdio: "inherit" },
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
await new Promise<void>((resolve, reject) => {
|
|
306
|
+
child.on("close", (code) => {
|
|
307
|
+
if (code === 0) {
|
|
308
|
+
resolve();
|
|
309
|
+
} else {
|
|
310
|
+
reject(new Error(`gcloud instance delete exited with code ${code}`));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
child.on("error", reject);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
console.log(`\u2705 Instance ${name} deleted.`);
|
|
317
|
+
}
|