@easybits.cloud/cli 0.6.1 → 0.7.0
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 +8 -3
- package/dist/index.js +168 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,9 +75,10 @@ easybits db rm leads --yes
|
|
|
75
75
|
# Agents
|
|
76
76
|
easybits agents ls
|
|
77
77
|
easybits agents create --template goose --name helper --dotenv .env
|
|
78
|
-
easybits agents
|
|
79
|
-
easybits agents message
|
|
80
|
-
easybits agents
|
|
78
|
+
easybits agents get helper # by name or id
|
|
79
|
+
easybits agents message helper "hello"
|
|
80
|
+
easybits agents message helper "and now?" --session ses_456 # continue a conversation
|
|
81
|
+
easybits agents destroy helper --yes
|
|
81
82
|
|
|
82
83
|
# Files, websites, account
|
|
83
84
|
easybits files ls
|
|
@@ -95,6 +96,10 @@ easybits docs cli # a docs section as markdown (--en for English)
|
|
|
95
96
|
easybits docs --open # open the docs in your browser
|
|
96
97
|
```
|
|
97
98
|
|
|
99
|
+
**Names or ids.** Wherever a command takes an agent, a sandbox/machine or a database, you can
|
|
100
|
+
pass its name instead of the id (`easybits sb exec scratch -- ls`, `easybits domains ls shop`).
|
|
101
|
+
The match is exact and case-insensitive; if two share the name the CLI exits 2 and lists the ids.
|
|
102
|
+
|
|
98
103
|
Every command has help with examples: `easybits <command> <subcommand> --help`
|
|
99
104
|
(or `easybits help <command> <subcommand>`). A typo gets a "Did you mean" suggestion.
|
|
100
105
|
|
package/dist/index.js
CHANGED
|
@@ -992,11 +992,11 @@ function printSandbox(s) {
|
|
|
992
992
|
if (s.tier) console.log(`Tier: ${s.tier}${s.monthlyMxn != null ? ` ($${s.monthlyMxn} MXN/month)` : ""}`);
|
|
993
993
|
}
|
|
994
994
|
async function sandbox(ctx, usage2) {
|
|
995
|
-
const id = need(ctx, 0, "sandbox
|
|
995
|
+
const id = need(ctx, 0, "sandbox", usage2);
|
|
996
996
|
const eb = await getClient(ctx);
|
|
997
997
|
return eb.sandboxes.get(id);
|
|
998
998
|
}
|
|
999
|
-
var FILES_USAGE = "easybits sandboxes files <ls|read|write> <sandbox
|
|
999
|
+
var FILES_USAGE = "easybits sandboxes files <ls|read|write> <sandbox> <path> [local-file]";
|
|
1000
1000
|
var sandboxes = {
|
|
1001
1001
|
name: "sandboxes",
|
|
1002
1002
|
aliases: ["sandbox", "sb"],
|
|
@@ -1061,7 +1061,7 @@ var sandboxes = {
|
|
|
1061
1061
|
get: {
|
|
1062
1062
|
aliases: ["show", "status"],
|
|
1063
1063
|
summary: "Show one sandbox",
|
|
1064
|
-
usage: "easybits sandboxes get <sandbox
|
|
1064
|
+
usage: "easybits sandboxes get <sandbox>",
|
|
1065
1065
|
examples: ["easybits sandboxes get sb_abc123"],
|
|
1066
1066
|
async run(ctx) {
|
|
1067
1067
|
const rec = sandboxRecord(await sandbox(ctx, this.usage));
|
|
@@ -1070,7 +1070,7 @@ var sandboxes = {
|
|
|
1070
1070
|
},
|
|
1071
1071
|
exec: {
|
|
1072
1072
|
summary: "Run a shell command inside a sandbox",
|
|
1073
|
-
usage: "easybits sandboxes exec <sandbox
|
|
1073
|
+
usage: "easybits sandboxes exec <sandbox> [--cwd <dir>] [--timeout <s>] [--dotenv <path>] -- <command...>",
|
|
1074
1074
|
options: {
|
|
1075
1075
|
cwd: { type: "string", value: "dir", description: "Working directory" },
|
|
1076
1076
|
timeout: { type: "string", value: "seconds", description: "Kill the command after this long" },
|
|
@@ -1084,7 +1084,7 @@ var sandboxes = {
|
|
|
1084
1084
|
"easybits sb exec sb_abc123 --json -- 'ls -la /' | jq .exitCode"
|
|
1085
1085
|
],
|
|
1086
1086
|
async run(ctx) {
|
|
1087
|
-
need(ctx, 0, "sandbox
|
|
1087
|
+
need(ctx, 0, "sandbox", this.usage);
|
|
1088
1088
|
const command = ctx.args.slice(1).join(" ");
|
|
1089
1089
|
if (!command) throw usageError("Missing <command>.", this.usage);
|
|
1090
1090
|
const env = await envFrom(ctx, this.usage);
|
|
@@ -1107,7 +1107,7 @@ var sandboxes = {
|
|
|
1107
1107
|
},
|
|
1108
1108
|
logs: {
|
|
1109
1109
|
summary: "Read the sandbox journal (optionally one systemd unit)",
|
|
1110
|
-
usage: "easybits sandboxes logs <sandbox
|
|
1110
|
+
usage: "easybits sandboxes logs <sandbox> [--unit <unit>] [--lines <n>] [--since <spec>] [--grep <text>]",
|
|
1111
1111
|
options: {
|
|
1112
1112
|
unit: { type: "string", value: "unit", description: "systemd unit to filter" },
|
|
1113
1113
|
lines: { type: "string", value: "n", description: "Last N lines (default 200)" },
|
|
@@ -1142,7 +1142,7 @@ var sandboxes = {
|
|
|
1142
1142
|
],
|
|
1143
1143
|
async run(ctx) {
|
|
1144
1144
|
const action = need(ctx, 0, "ls|read|write", FILES_USAGE);
|
|
1145
|
-
const id = need(ctx, 1, "sandbox
|
|
1145
|
+
const id = need(ctx, 1, "sandbox", FILES_USAGE);
|
|
1146
1146
|
const path = need(ctx, 2, "path", FILES_USAGE);
|
|
1147
1147
|
const eb = await getClient(ctx);
|
|
1148
1148
|
const sb = await eb.sandboxes.get(id);
|
|
@@ -1186,7 +1186,7 @@ var sandboxes = {
|
|
|
1186
1186
|
},
|
|
1187
1187
|
suspend: {
|
|
1188
1188
|
summary: "Suspend to disk (frees CPU; TTL paused)",
|
|
1189
|
-
usage: "easybits sandboxes suspend <sandbox
|
|
1189
|
+
usage: "easybits sandboxes suspend <sandbox>",
|
|
1190
1190
|
examples: ["easybits sandboxes suspend sb_abc123"],
|
|
1191
1191
|
async run(ctx) {
|
|
1192
1192
|
const r = await (await sandbox(ctx, this.usage)).suspend();
|
|
@@ -1195,7 +1195,7 @@ var sandboxes = {
|
|
|
1195
1195
|
},
|
|
1196
1196
|
resume: {
|
|
1197
1197
|
summary: "Wake a suspended sandbox",
|
|
1198
|
-
usage: "easybits sandboxes resume <sandbox
|
|
1198
|
+
usage: "easybits sandboxes resume <sandbox> [--dotenv <path>] [--env K=V]...",
|
|
1199
1199
|
options: {
|
|
1200
1200
|
env: { type: "string", multiple: true, value: "K=V", description: "Rewrite env on wake, non-secret (repeatable)" },
|
|
1201
1201
|
...ENV_FILE_OPTION
|
|
@@ -1210,11 +1210,11 @@ var sandboxes = {
|
|
|
1210
1210
|
destroy: {
|
|
1211
1211
|
aliases: ["rm", "delete"],
|
|
1212
1212
|
summary: "Destroy a sandbox (irreversible)",
|
|
1213
|
-
usage: "easybits sandboxes destroy <sandbox
|
|
1213
|
+
usage: "easybits sandboxes destroy <sandbox> [--yes]",
|
|
1214
1214
|
options: { ...YES_OPTION },
|
|
1215
1215
|
examples: ["easybits sandboxes destroy sb_abc123", "easybits sb rm sb_abc123 --yes"],
|
|
1216
1216
|
async run(ctx) {
|
|
1217
|
-
need(ctx, 0, "sandbox
|
|
1217
|
+
need(ctx, 0, "sandbox", this.usage);
|
|
1218
1218
|
requireYesIfHeadless(ctx);
|
|
1219
1219
|
const sb = await sandbox(ctx, this.usage);
|
|
1220
1220
|
await confirm(
|
|
@@ -1228,7 +1228,7 @@ var sandboxes = {
|
|
|
1228
1228
|
},
|
|
1229
1229
|
snapshot: {
|
|
1230
1230
|
summary: "Capture a copy-on-write snapshot without stopping the box",
|
|
1231
|
-
usage: "easybits sandboxes snapshot <sandbox
|
|
1231
|
+
usage: "easybits sandboxes snapshot <sandbox> [--name <name>]",
|
|
1232
1232
|
options: { name: { type: "string", value: "name", description: "Snapshot label" } },
|
|
1233
1233
|
examples: ["easybits sandboxes snapshot sb_abc123 --name before-upgrade"],
|
|
1234
1234
|
async run(ctx) {
|
|
@@ -1240,7 +1240,7 @@ var sandboxes = {
|
|
|
1240
1240
|
};
|
|
1241
1241
|
|
|
1242
1242
|
// src/commands/machines.ts
|
|
1243
|
-
var SECRETS_USAGE = "easybits machines secrets <ls|set|unset> <machine
|
|
1243
|
+
var SECRETS_USAGE = "easybits machines secrets <ls|set|unset> <machine> [--dotenv <path> | NAME]";
|
|
1244
1244
|
var machines = {
|
|
1245
1245
|
name: "machines",
|
|
1246
1246
|
aliases: ["deploy", "machine"],
|
|
@@ -1270,11 +1270,11 @@ var machines = {
|
|
|
1270
1270
|
deploy: {
|
|
1271
1271
|
aliases: ["release"],
|
|
1272
1272
|
summary: "Publish the machine's current app code as a new release",
|
|
1273
|
-
usage: "easybits machines deploy <machine
|
|
1273
|
+
usage: "easybits machines deploy <machine> [--message <text>]",
|
|
1274
1274
|
options: { message: { type: "string", short: "m", value: "text", description: "Release note" } },
|
|
1275
1275
|
examples: ['easybits machines deploy sb_abc123 -m "v1.2: fix checkout"'],
|
|
1276
1276
|
async run(ctx) {
|
|
1277
|
-
const id = need(ctx, 0, "machine
|
|
1277
|
+
const id = need(ctx, 0, "machine", this.usage);
|
|
1278
1278
|
const eb = await getClient(ctx);
|
|
1279
1279
|
const r = await eb.machines.deploy(id, { message: str(ctx, "message") });
|
|
1280
1280
|
emit(ctx, r, () => console.log(`Release v${r.version} ${r.releaseId} (${r.status}, ${fmtBytes(r.sizeBytes)})`));
|
|
@@ -1282,11 +1282,11 @@ var machines = {
|
|
|
1282
1282
|
},
|
|
1283
1283
|
releases: {
|
|
1284
1284
|
summary: "List releases, newest first",
|
|
1285
|
-
usage: "easybits machines releases <machine
|
|
1285
|
+
usage: "easybits machines releases <machine> [--limit <n>]",
|
|
1286
1286
|
options: { limit: { type: "string", value: "n", description: "How many" } },
|
|
1287
1287
|
examples: ["easybits machines releases sb_abc123 --limit 5"],
|
|
1288
1288
|
async run(ctx) {
|
|
1289
|
-
const id = need(ctx, 0, "machine
|
|
1289
|
+
const id = need(ctx, 0, "machine", this.usage);
|
|
1290
1290
|
const eb = await getClient(ctx);
|
|
1291
1291
|
const r = await eb.machines.releases(id, { limit: int(ctx, "limit", this.usage) });
|
|
1292
1292
|
emit(
|
|
@@ -1295,21 +1295,21 @@ var machines = {
|
|
|
1295
1295
|
() => table(
|
|
1296
1296
|
r.items.map((x) => ({ ...x, size: fmtBytes(x.sizeBytes), createdAt: fmtDate(x.createdAt) })),
|
|
1297
1297
|
[["version", "VERSION"], ["releaseId", "ID"], ["status", "STATUS"], ["size", "SIZE"], ["createdAt", "CREATED"], ["message", "MESSAGE"]],
|
|
1298
|
-
"No releases yet. Publish one: easybits machines deploy <machine
|
|
1298
|
+
"No releases yet. Publish one: easybits machines deploy <machine>"
|
|
1299
1299
|
)
|
|
1300
1300
|
);
|
|
1301
1301
|
}
|
|
1302
1302
|
},
|
|
1303
1303
|
logs: {
|
|
1304
1304
|
summary: "Tail the app's own log",
|
|
1305
|
-
usage: "easybits machines logs <machine
|
|
1305
|
+
usage: "easybits machines logs <machine> [--lines <n>] [--grep <text>]",
|
|
1306
1306
|
options: {
|
|
1307
1307
|
lines: { type: "string", value: "n", description: "Last N lines" },
|
|
1308
1308
|
grep: { type: "string", value: "text", description: "Only lines matching" }
|
|
1309
1309
|
},
|
|
1310
1310
|
examples: ["easybits machines logs sb_abc123 --lines 100", "easybits machines logs sb_abc123 --grep ERROR"],
|
|
1311
1311
|
async run(ctx) {
|
|
1312
|
-
const id = need(ctx, 0, "machine
|
|
1312
|
+
const id = need(ctx, 0, "machine", this.usage);
|
|
1313
1313
|
const eb = await getClient(ctx);
|
|
1314
1314
|
const r = await eb.machines.logs(id, { lines: int(ctx, "lines", this.usage), grep: str(ctx, "grep") });
|
|
1315
1315
|
emit(ctx, r, () => process.stdout.write(r.output.endsWith("\n") || !r.output ? r.output : r.output + "\n"));
|
|
@@ -1317,10 +1317,10 @@ var machines = {
|
|
|
1317
1317
|
},
|
|
1318
1318
|
rollback: {
|
|
1319
1319
|
summary: "Put a previous release back on the same machine (data untouched)",
|
|
1320
|
-
usage: "easybits machines rollback <machine
|
|
1320
|
+
usage: "easybits machines rollback <machine> <release-id>",
|
|
1321
1321
|
examples: ["easybits machines rollback sb_abc123 rel_789"],
|
|
1322
1322
|
async run(ctx) {
|
|
1323
|
-
const id = need(ctx, 0, "machine
|
|
1323
|
+
const id = need(ctx, 0, "machine", this.usage);
|
|
1324
1324
|
const rel = need(ctx, 1, "release-id", this.usage);
|
|
1325
1325
|
const eb = await getClient(ctx);
|
|
1326
1326
|
const r = await eb.machines.rollback(id, rel);
|
|
@@ -1340,7 +1340,7 @@ var machines = {
|
|
|
1340
1340
|
],
|
|
1341
1341
|
async run(ctx) {
|
|
1342
1342
|
const action = need(ctx, 0, "ls|set|unset", SECRETS_USAGE);
|
|
1343
|
-
const id = need(ctx, 1, "machine
|
|
1343
|
+
const id = need(ctx, 1, "machine", SECRETS_USAGE);
|
|
1344
1344
|
const eb = await getClient(ctx);
|
|
1345
1345
|
if (action === "ls" || action === "list") {
|
|
1346
1346
|
const r = await eb.machines.secrets(id);
|
|
@@ -1368,7 +1368,7 @@ var machines = {
|
|
|
1368
1368
|
|
|
1369
1369
|
// src/commands/domains.ts
|
|
1370
1370
|
async function sandbox2(ctx, usage2) {
|
|
1371
|
-
const id = need(ctx, 0, "sandbox
|
|
1371
|
+
const id = need(ctx, 0, "sandbox", usage2);
|
|
1372
1372
|
return (await getClient(ctx)).sandboxes.get(id);
|
|
1373
1373
|
}
|
|
1374
1374
|
var domains = {
|
|
@@ -1381,7 +1381,7 @@ var domains = {
|
|
|
1381
1381
|
ls: {
|
|
1382
1382
|
aliases: ["list"],
|
|
1383
1383
|
summary: "List domains attached to a sandbox",
|
|
1384
|
-
usage: "easybits domains ls <sandbox
|
|
1384
|
+
usage: "easybits domains ls <sandbox>",
|
|
1385
1385
|
examples: ["easybits domains ls sb_abc123"],
|
|
1386
1386
|
async run(ctx) {
|
|
1387
1387
|
const items = await (await sandbox2(ctx, this.usage)).listDomains();
|
|
@@ -1390,7 +1390,7 @@ var domains = {
|
|
|
1390
1390
|
},
|
|
1391
1391
|
add: {
|
|
1392
1392
|
summary: "Attach a domain to a port; prints the DNS record to create",
|
|
1393
|
-
usage: "easybits domains add <sandbox
|
|
1393
|
+
usage: "easybits domains add <sandbox> <domain> --port <port>",
|
|
1394
1394
|
options: { port: { type: "string", value: "port", description: "Port inside the sandbox (required)" } },
|
|
1395
1395
|
examples: ["easybits domains add sb_abc123 shop.example.com --port 3000"],
|
|
1396
1396
|
async run(ctx) {
|
|
@@ -1407,7 +1407,7 @@ var domains = {
|
|
|
1407
1407
|
},
|
|
1408
1408
|
verify: {
|
|
1409
1409
|
summary: "Check DNS + HTTPS for a domain",
|
|
1410
|
-
usage: "easybits domains verify <sandbox
|
|
1410
|
+
usage: "easybits domains verify <sandbox> <domain>",
|
|
1411
1411
|
examples: ["easybits domains verify sb_abc123 shop.example.com"],
|
|
1412
1412
|
async run(ctx) {
|
|
1413
1413
|
const domain = need(ctx, 1, "domain", this.usage);
|
|
@@ -1423,11 +1423,11 @@ var domains = {
|
|
|
1423
1423
|
rm: {
|
|
1424
1424
|
aliases: ["remove", "delete"],
|
|
1425
1425
|
summary: "Detach a domain",
|
|
1426
|
-
usage: "easybits domains rm <sandbox
|
|
1426
|
+
usage: "easybits domains rm <sandbox> <domain> [--yes]",
|
|
1427
1427
|
options: { ...YES_OPTION },
|
|
1428
1428
|
examples: ["easybits domains rm sb_abc123 shop.example.com", "easybits domains rm sb_abc123 shop.example.com --yes"],
|
|
1429
1429
|
async run(ctx) {
|
|
1430
|
-
need(ctx, 0, "sandbox
|
|
1430
|
+
need(ctx, 0, "sandbox", this.usage);
|
|
1431
1431
|
const domain = need(ctx, 1, "domain", this.usage);
|
|
1432
1432
|
requireYesIfHeadless(ctx);
|
|
1433
1433
|
await confirm(ctx, `Detach ${domain} from ${ctx.args[0]}? It stops serving right away.`);
|
|
@@ -1438,12 +1438,100 @@ var domains = {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
};
|
|
1440
1440
|
|
|
1441
|
+
// src/refs.ts
|
|
1442
|
+
var ID_FORMAT = {
|
|
1443
|
+
agent: /^[0-9a-f]{24}$/i,
|
|
1444
|
+
db: /^[0-9a-f]{24}$/i,
|
|
1445
|
+
sandbox: /^sb_[0-9a-z-]+$/i
|
|
1446
|
+
};
|
|
1447
|
+
var looksLikeId = (kind, ref) => ID_FORMAT[kind].test(ref);
|
|
1448
|
+
var REF_ARGS = {
|
|
1449
|
+
"agents get": { index: 0, kind: "agent" },
|
|
1450
|
+
"agents message": { index: 0, kind: "agent" },
|
|
1451
|
+
"agents destroy": { index: 0, kind: "agent" },
|
|
1452
|
+
"sandboxes get": { index: 0, kind: "sandbox" },
|
|
1453
|
+
"sandboxes exec": { index: 0, kind: "sandbox" },
|
|
1454
|
+
"sandboxes logs": { index: 0, kind: "sandbox" },
|
|
1455
|
+
"sandboxes files": { index: 1, kind: "sandbox" },
|
|
1456
|
+
"sandboxes suspend": { index: 0, kind: "sandbox" },
|
|
1457
|
+
"sandboxes resume": { index: 0, kind: "sandbox" },
|
|
1458
|
+
"sandboxes destroy": { index: 0, kind: "sandbox" },
|
|
1459
|
+
"sandboxes snapshot": { index: 0, kind: "sandbox" },
|
|
1460
|
+
"machines deploy": { index: 0, kind: "sandbox" },
|
|
1461
|
+
"machines releases": { index: 0, kind: "sandbox" },
|
|
1462
|
+
"machines logs": { index: 0, kind: "sandbox" },
|
|
1463
|
+
"machines rollback": { index: 0, kind: "sandbox" },
|
|
1464
|
+
"machines secrets": { index: 1, kind: "sandbox" },
|
|
1465
|
+
"domains ls": { index: 0, kind: "sandbox" },
|
|
1466
|
+
"domains add": { index: 0, kind: "sandbox" },
|
|
1467
|
+
"domains verify": { index: 0, kind: "sandbox" },
|
|
1468
|
+
"domains rm": { index: 0, kind: "sandbox" },
|
|
1469
|
+
"db rm": { index: 0, kind: "db" },
|
|
1470
|
+
"db tables": { index: 0, kind: "db" },
|
|
1471
|
+
"db query": { index: 0, kind: "db" }
|
|
1472
|
+
};
|
|
1473
|
+
function matchRef(kind, ref, items) {
|
|
1474
|
+
if (looksLikeId(kind, ref)) return { ok: true, id: ref };
|
|
1475
|
+
const list2 = items ?? [];
|
|
1476
|
+
if (list2.some((x) => x.id === ref)) return { ok: true, id: ref };
|
|
1477
|
+
const want = ref.trim().toLowerCase();
|
|
1478
|
+
const matches = list2.filter((x) => (x.name ?? "").trim().toLowerCase() === want);
|
|
1479
|
+
if (matches.length === 1) return { ok: true, id: matches[0].id };
|
|
1480
|
+
if (matches.length === 0) return { ok: false, reason: "not_found" };
|
|
1481
|
+
return { ok: false, reason: "ambiguous", matches };
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
// src/resolve.ts
|
|
1485
|
+
var LS_HINT = {
|
|
1486
|
+
agent: "easybits agents ls",
|
|
1487
|
+
sandbox: "easybits sandboxes ls",
|
|
1488
|
+
db: "easybits db ls"
|
|
1489
|
+
};
|
|
1490
|
+
var NOUN = { agent: "agent", sandbox: "sandbox or machine", db: "database" };
|
|
1491
|
+
var cache = /* @__PURE__ */ new Map();
|
|
1492
|
+
function listRefs(ctx, kind) {
|
|
1493
|
+
let p = cache.get(kind);
|
|
1494
|
+
if (!p) {
|
|
1495
|
+
p = (async () => {
|
|
1496
|
+
const eb = await getClient(ctx);
|
|
1497
|
+
if (kind === "agent") return (await eb.listAgents()).map((a) => ({ id: a.agentId, name: a.name, status: a.status }));
|
|
1498
|
+
if (kind === "db") return (await eb.listDatabases()).items.map((d) => ({ id: d.id, name: d.name }));
|
|
1499
|
+
return (await eb.sandboxes.list()).map((s) => ({ id: s.sandboxId, name: s.name, status: s.status }));
|
|
1500
|
+
})();
|
|
1501
|
+
p.catch(() => cache.delete(kind));
|
|
1502
|
+
cache.set(kind, p);
|
|
1503
|
+
}
|
|
1504
|
+
return p;
|
|
1505
|
+
}
|
|
1506
|
+
async function resolveRef(ctx, kind, ref) {
|
|
1507
|
+
if (looksLikeId(kind, ref)) return ref;
|
|
1508
|
+
const r = matchRef(kind, ref, await listRefs(ctx, kind));
|
|
1509
|
+
if (r.ok) return r.id;
|
|
1510
|
+
if (r.reason === "not_found") {
|
|
1511
|
+
throw new CliError(`No ${NOUN[kind]} with id or name "${ref}".`, EXIT.API, `List them with: ${LS_HINT[kind]}`, "not_found", 404);
|
|
1512
|
+
}
|
|
1513
|
+
const shown = r.matches.slice(0, 10).map((m) => ` ${m.id}${m.status ? ` (${m.status})` : ""}`);
|
|
1514
|
+
if (r.matches.length > 10) shown.push(` \u2026and ${r.matches.length - 10} more`);
|
|
1515
|
+
throw new CliError(
|
|
1516
|
+
`"${ref}" matches ${r.matches.length} ${kind === "db" ? "databases" : `${kind}s`}. Use the id:`,
|
|
1517
|
+
EXIT.USAGE,
|
|
1518
|
+
`${shown.join("\n")}
|
|
1519
|
+
List them with: ${LS_HINT[kind]}`,
|
|
1520
|
+
"ambiguous"
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
async function resolveRefs(ctx, key) {
|
|
1524
|
+
const spec = REF_ARGS[key];
|
|
1525
|
+
const ref = spec ? ctx.args[spec.index] : void 0;
|
|
1526
|
+
if (!spec || !ref) return;
|
|
1527
|
+
ctx.args[spec.index] = await resolveRef(ctx, spec.kind, ref);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1441
1530
|
// src/commands/db.ts
|
|
1442
|
-
async function findDb(
|
|
1443
|
-
const
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
return hit;
|
|
1531
|
+
async function findDb(ctx, id) {
|
|
1532
|
+
const hit = (await listRefs(ctx, "db")).find((d) => d.id === id);
|
|
1533
|
+
if (!hit) throw new CliError(`No database "${id}".`, 1, "List them with: easybits db ls", "not_found", 404);
|
|
1534
|
+
return { id, name: hit.name ?? id };
|
|
1447
1535
|
}
|
|
1448
1536
|
var db = {
|
|
1449
1537
|
name: "db",
|
|
@@ -1493,7 +1581,7 @@ var db = {
|
|
|
1493
1581
|
const ref = need(ctx, 0, "db-id|name", this.usage);
|
|
1494
1582
|
requireYesIfHeadless(ctx);
|
|
1495
1583
|
const eb = await getClient(ctx);
|
|
1496
|
-
const hit = await findDb(
|
|
1584
|
+
const hit = await findDb(ctx, ref);
|
|
1497
1585
|
await confirm(ctx, `Delete database ${hit.name} (${hit.id}) and all its data?`, { typeName: hit.name });
|
|
1498
1586
|
const r = await eb.deleteDatabase(hit.id);
|
|
1499
1587
|
emit(ctx, { ...r, id: hit.id, name: hit.name }, () => console.log(`Deleted ${hit.name} (${hit.id})`));
|
|
@@ -1508,7 +1596,7 @@ var db = {
|
|
|
1508
1596
|
async run(ctx) {
|
|
1509
1597
|
const ref = need(ctx, 0, "db-id|name", this.usage);
|
|
1510
1598
|
const eb = await getClient(ctx);
|
|
1511
|
-
const hit = await findDb(
|
|
1599
|
+
const hit = await findDb(ctx, ref);
|
|
1512
1600
|
const q = (sql, args) => eb.queryDatabase(hit.id, sql, args);
|
|
1513
1601
|
const names = (await q("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_litestream_%' ORDER BY name")).rows.map((r) => String(r[0]));
|
|
1514
1602
|
const ident = (n) => `"${n.replace(/"/g, '""')}"`;
|
|
@@ -1549,7 +1637,7 @@ var db = {
|
|
|
1549
1637
|
const ref = need(ctx, 0, "db-id|name", this.usage);
|
|
1550
1638
|
const sql = need(ctx, 1, "sql", this.usage);
|
|
1551
1639
|
const eb = await getClient(ctx);
|
|
1552
|
-
const hit = await findDb(
|
|
1640
|
+
const hit = await findDb(ctx, ref);
|
|
1553
1641
|
const args = list(ctx, "arg");
|
|
1554
1642
|
const r = await eb.queryDatabase(hit.id, sql, args.length ? args : void 0);
|
|
1555
1643
|
emit(ctx, r, () => {
|
|
@@ -1595,6 +1683,27 @@ var agents = {
|
|
|
1595
1683
|
);
|
|
1596
1684
|
}
|
|
1597
1685
|
},
|
|
1686
|
+
get: {
|
|
1687
|
+
aliases: ["show"],
|
|
1688
|
+
summary: "Show one agent (by id or name)",
|
|
1689
|
+
usage: "easybits agents get <agent>",
|
|
1690
|
+
examples: ["easybits agents get helper", "easybits agents get 6650f0c2a1b2c3d4e5f60718 --json"],
|
|
1691
|
+
async run(ctx) {
|
|
1692
|
+
const id = need(ctx, 0, "agent", this.usage);
|
|
1693
|
+
const eb = await getClient(ctx);
|
|
1694
|
+
const a = await eb.getAgent(id);
|
|
1695
|
+
emit(ctx, a, () => {
|
|
1696
|
+
console.log(`ID: ${a.agentId}`);
|
|
1697
|
+
if (a.name) console.log(`Name: ${a.name}`);
|
|
1698
|
+
console.log(`Template: ${a.template}`);
|
|
1699
|
+
console.log(`Status: ${a.status}`);
|
|
1700
|
+
console.log(`Sandbox: ${a.sandboxId}`);
|
|
1701
|
+
console.log(`URL: ${a.agentUrl}`);
|
|
1702
|
+
console.log(`Created: ${fmtDate(a.createdAt)}`);
|
|
1703
|
+
console.log(`Expires: ${a.expiresAt ? fmtDate(a.expiresAt) : "never"}`);
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1598
1707
|
create: {
|
|
1599
1708
|
summary: "Create an agent from a template",
|
|
1600
1709
|
usage: "easybits agents create --template <template> [--name <name>] [--dotenv <path>] [--env K=V]... [--timeout <s>]",
|
|
@@ -1631,12 +1740,12 @@ var agents = {
|
|
|
1631
1740
|
},
|
|
1632
1741
|
message: {
|
|
1633
1742
|
aliases: ["msg", "send"],
|
|
1634
|
-
summary: "Send a message; streams the reply",
|
|
1635
|
-
usage: "easybits agents message <agent
|
|
1743
|
+
summary: "Send a message (agent by id or name); streams the reply",
|
|
1744
|
+
usage: "easybits agents message <agent> <text...> [--session <id>]",
|
|
1636
1745
|
options: { session: { type: "string", value: "id", description: "Continue a conversation" } },
|
|
1637
|
-
examples: ['easybits agents message
|
|
1746
|
+
examples: ['easybits agents message helper "summarize /data/work/README.md"', "easybits agents message 6650f0c2a1b2c3d4e5f60718 hi --json"],
|
|
1638
1747
|
async run(ctx) {
|
|
1639
|
-
const id = need(ctx, 0, "agent
|
|
1748
|
+
const id = need(ctx, 0, "agent", this.usage);
|
|
1640
1749
|
const content = ctx.args.slice(1).join(" ");
|
|
1641
1750
|
if (!content) throw usageError("Missing <text>.", this.usage);
|
|
1642
1751
|
const eb = await getClient(ctx);
|
|
@@ -1653,11 +1762,11 @@ var agents = {
|
|
|
1653
1762
|
destroy: {
|
|
1654
1763
|
aliases: ["rm", "delete"],
|
|
1655
1764
|
summary: "Destroy an agent and its sandbox",
|
|
1656
|
-
usage: "easybits agents destroy <agent
|
|
1765
|
+
usage: "easybits agents destroy <agent> [--yes]",
|
|
1657
1766
|
options: { ...YES_OPTION },
|
|
1658
|
-
examples: ["easybits agents destroy
|
|
1767
|
+
examples: ["easybits agents destroy helper # asks you to type the id", "easybits agents destroy helper --yes"],
|
|
1659
1768
|
async run(ctx) {
|
|
1660
|
-
const id = need(ctx, 0, "agent
|
|
1769
|
+
const id = need(ctx, 0, "agent", this.usage);
|
|
1661
1770
|
requireYesIfHeadless(ctx);
|
|
1662
1771
|
await confirm(ctx, `Destroy agent ${id} and its sandbox (including /data)?`, { typeName: id });
|
|
1663
1772
|
const eb = await getClient(ctx);
|
|
@@ -1770,6 +1879,9 @@ var GLOBAL_FLAGS = `Global flags:
|
|
|
1770
1879
|
-h, --help Help (also: easybits <command> --help)
|
|
1771
1880
|
-v, --version Print the CLI version
|
|
1772
1881
|
|
|
1882
|
+
Names or ids: agents, sandboxes/machines and databases take either
|
|
1883
|
+
(exact, case-insensitive; two with the same name \u2192 exit 2 with the ids).
|
|
1884
|
+
|
|
1773
1885
|
Deletes (sandboxes destroy, agents destroy, db rm, domains rm, files delete) ask first;
|
|
1774
1886
|
without a terminal or with --json pass -y/--yes, or they exit 2.
|
|
1775
1887
|
|
|
@@ -1830,7 +1942,7 @@ var BANNER = " \x1B[38;2;244;245;251m\u2860\u2812\u2812\u28E4\x1B[38;
|
|
|
1830
1942
|
|
|
1831
1943
|
// src/index.ts
|
|
1832
1944
|
import { EasybitsError as EasybitsError2 } from "@easybits.cloud/sdk";
|
|
1833
|
-
var VERSION = true ? "0.
|
|
1945
|
+
var VERSION = true ? "0.7.0" : "dev";
|
|
1834
1946
|
var GLOBAL_OPTIONS = {
|
|
1835
1947
|
json: { type: "boolean" },
|
|
1836
1948
|
token: { type: "string" },
|
|
@@ -1922,17 +2034,20 @@ async function main(argv2) {
|
|
|
1922
2034
|
const cmd = findCommand(cmdName);
|
|
1923
2035
|
if (!cmd) throw unknownCommand(cmdName);
|
|
1924
2036
|
let leaf = cmd.leaf;
|
|
2037
|
+
let subKey;
|
|
1925
2038
|
const skip = [pos[0]];
|
|
1926
2039
|
if (cmd.subs) {
|
|
1927
2040
|
const subName = pos[1] != null ? argv2[pos[1]] : void 0;
|
|
1928
2041
|
const entry = subName ? findSub(cmd, subName) : void 0;
|
|
1929
2042
|
if (entry) {
|
|
1930
2043
|
leaf = entry[1];
|
|
2044
|
+
subKey = entry[0];
|
|
1931
2045
|
skip.push(pos[1]);
|
|
1932
2046
|
} else if (subName) {
|
|
1933
2047
|
throw unknownSub(cmd, subName);
|
|
1934
2048
|
} else if (cmd.defaultSub && !argv2.includes("--help") && !argv2.includes("-h")) {
|
|
1935
2049
|
leaf = cmd.subs[cmd.defaultSub];
|
|
2050
|
+
subKey = cmd.defaultSub;
|
|
1936
2051
|
} else if (!argv2.includes("--help") && !argv2.includes("-h")) {
|
|
1937
2052
|
throw usageError(`Missing subcommand for "${cmd.name}".`, `easybits ${cmd.name} <${Object.keys(cmd.subs).join("|")}>`);
|
|
1938
2053
|
}
|
|
@@ -1952,11 +2067,17 @@ async function main(argv2) {
|
|
|
1952
2067
|
args: positionals,
|
|
1953
2068
|
opts: values
|
|
1954
2069
|
};
|
|
2070
|
+
const refKey = `${cmd.name} ${subKey ?? ""}`.trim();
|
|
2071
|
+
const target = leaf;
|
|
2072
|
+
const run = async () => {
|
|
2073
|
+
await resolveRefs(ctx, refKey);
|
|
2074
|
+
await target.run.call(target, ctx);
|
|
2075
|
+
};
|
|
1955
2076
|
try {
|
|
1956
|
-
await
|
|
2077
|
+
await run();
|
|
1957
2078
|
} catch (e) {
|
|
1958
2079
|
if (e instanceof EasybitsError2 && e.status === 401 && usedSession() && await forceRefresh()) {
|
|
1959
|
-
await
|
|
2080
|
+
await run();
|
|
1960
2081
|
return;
|
|
1961
2082
|
}
|
|
1962
2083
|
throw e;
|
package/package.json
CHANGED