@easybits.cloud/cli 0.13.0 → 0.14.1
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 +14 -0
- package/dist/index.js +264 -145
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,8 @@ easybits sandboxes destroy sb_abc123 --yes
|
|
|
50
50
|
|
|
51
51
|
# Hosting: permanent machines (alias: deploy)
|
|
52
52
|
easybits machines ls
|
|
53
|
+
easybits machines launch --repo https://github.com/you/shop.git --tier micro --domain shop.example.com
|
|
54
|
+
easybits machines launch --machine shop --archive ./build.tgz --prebuilt -m v2 # redeploy
|
|
53
55
|
easybits deploy sb_abc123 -m "v1.2" # = machines deploy
|
|
54
56
|
easybits machines releases sb_abc123 --limit 5
|
|
55
57
|
easybits machines logs sb_abc123 --lines 100 --grep ERROR
|
|
@@ -164,6 +166,18 @@ Host *.ghosty
|
|
|
164
166
|
|
|
165
167
|
Full reference: https://www.easybits.cloud/docs#cli · https://www.easybits.cloud/en/docs/cli.md
|
|
166
168
|
|
|
169
|
+
## Changes in 0.14.1
|
|
170
|
+
|
|
171
|
+
- `machines launch --machine` takes a name too, like every other command.
|
|
172
|
+
|
|
173
|
+
## Changes in 0.14.0
|
|
174
|
+
|
|
175
|
+
- `machines launch` (aliases `create`, `new`): create a permanent machine and put an app on it in
|
|
176
|
+
one step — the CLI side of `launch_app`. Source is `--repo`, `--archive <url|file>` (a local file
|
|
177
|
+
is uploaded first) or `--machine` (redeploy onto an existing one). `--tier`, `--prebuilt`,
|
|
178
|
+
`--start`, `--port`, `--env K=V`, `--secret NAME`, `--data <path>`, `--domain`.
|
|
179
|
+
Without a plan it prints the checkout link instead of failing.
|
|
180
|
+
|
|
167
181
|
## Changes in 0.13.0
|
|
168
182
|
|
|
169
183
|
- Catalog photos: `db photos put <db> --table T --key-column sku --dir photos/ [--column C]
|
package/dist/index.js
CHANGED
|
@@ -1377,6 +1377,110 @@ var sandboxes = {
|
|
|
1377
1377
|
}
|
|
1378
1378
|
};
|
|
1379
1379
|
|
|
1380
|
+
// src/commands/machines.ts
|
|
1381
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
|
|
1382
|
+
import { basename as basename2 } from "path";
|
|
1383
|
+
|
|
1384
|
+
// src/refs.ts
|
|
1385
|
+
var ID_FORMAT = {
|
|
1386
|
+
agent: /^[0-9a-f]{24}$/i,
|
|
1387
|
+
db: /^[0-9a-f]{24}$/i,
|
|
1388
|
+
sandbox: /^sb_[0-9a-z-]+$/i
|
|
1389
|
+
};
|
|
1390
|
+
var looksLikeId = (kind, ref) => ID_FORMAT[kind].test(ref);
|
|
1391
|
+
var REF_ARGS = {
|
|
1392
|
+
"agents get": { index: 0, kind: "agent" },
|
|
1393
|
+
"agents message": { index: 0, kind: "agent" },
|
|
1394
|
+
"agents destroy": { index: 0, kind: "agent" },
|
|
1395
|
+
"agents set": { index: 0, kind: "agent" },
|
|
1396
|
+
"agents files": { index: 1, kind: "agent" },
|
|
1397
|
+
"agents skills": { index: 1, kind: "agent" },
|
|
1398
|
+
"agents mcp": { index: 1, kind: "agent" },
|
|
1399
|
+
"agents restart": { index: 0, kind: "agent" },
|
|
1400
|
+
"agents try": { index: 0, kind: "agent" },
|
|
1401
|
+
"agents logs": { index: 0, kind: "agent" },
|
|
1402
|
+
"agents doctor": { index: 0, kind: "agent" },
|
|
1403
|
+
"agents export": { index: 0, kind: "agent" },
|
|
1404
|
+
"sandboxes get": { index: 0, kind: "sandbox" },
|
|
1405
|
+
"sandboxes exec": { index: 0, kind: "sandbox" },
|
|
1406
|
+
"sandboxes logs": { index: 0, kind: "sandbox" },
|
|
1407
|
+
"sandboxes files": { index: 1, kind: "sandbox" },
|
|
1408
|
+
"sandboxes suspend": { index: 0, kind: "sandbox" },
|
|
1409
|
+
"sandboxes resume": { index: 0, kind: "sandbox" },
|
|
1410
|
+
"sandboxes destroy": { index: 0, kind: "sandbox" },
|
|
1411
|
+
"sandboxes snapshot": { index: 0, kind: "sandbox" },
|
|
1412
|
+
"machines deploy": { index: 0, kind: "sandbox" },
|
|
1413
|
+
"machines releases": { index: 0, kind: "sandbox" },
|
|
1414
|
+
"machines logs": { index: 0, kind: "sandbox" },
|
|
1415
|
+
"machines rollback": { index: 0, kind: "sandbox" },
|
|
1416
|
+
"machines secrets": { index: 1, kind: "sandbox" },
|
|
1417
|
+
"domains ls": { index: 0, kind: "sandbox" },
|
|
1418
|
+
"domains add": { index: 0, kind: "sandbox" },
|
|
1419
|
+
"domains verify": { index: 0, kind: "sandbox" },
|
|
1420
|
+
"domains rm": { index: 0, kind: "sandbox" },
|
|
1421
|
+
"db rm": { index: 0, kind: "db" },
|
|
1422
|
+
"db tables": { index: 0, kind: "db" },
|
|
1423
|
+
"db query": { index: 0, kind: "db" },
|
|
1424
|
+
"db photos": { index: 1, kind: "db" }
|
|
1425
|
+
};
|
|
1426
|
+
function matchRef(kind, ref, items) {
|
|
1427
|
+
if (looksLikeId(kind, ref)) return { ok: true, id: ref };
|
|
1428
|
+
const list2 = items ?? [];
|
|
1429
|
+
if (list2.some((x) => x.id === ref)) return { ok: true, id: ref };
|
|
1430
|
+
const want = ref.trim().toLowerCase();
|
|
1431
|
+
const matches = list2.filter((x) => (x.name ?? "").trim().toLowerCase() === want);
|
|
1432
|
+
if (matches.length === 1) return { ok: true, id: matches[0].id };
|
|
1433
|
+
if (matches.length === 0) return { ok: false, reason: "not_found" };
|
|
1434
|
+
return { ok: false, reason: "ambiguous", matches };
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
// src/resolve.ts
|
|
1438
|
+
var LS_HINT = {
|
|
1439
|
+
agent: "easybits agents ls",
|
|
1440
|
+
sandbox: "easybits sandboxes ls",
|
|
1441
|
+
db: "easybits db ls"
|
|
1442
|
+
};
|
|
1443
|
+
var NOUN = () => ({ agent: t("agent", "agente"), sandbox: t("sandbox or machine", "sandbox o m\xE1quina"), db: t("database", "base de datos") });
|
|
1444
|
+
var NOUNS = () => ({ agent: t("agents", "agentes"), sandbox: t("sandboxes", "sandboxes"), db: t("databases", "bases de datos") });
|
|
1445
|
+
var cache = /* @__PURE__ */ new Map();
|
|
1446
|
+
function listRefs(ctx, kind) {
|
|
1447
|
+
let p = cache.get(kind);
|
|
1448
|
+
if (!p) {
|
|
1449
|
+
p = (async () => {
|
|
1450
|
+
const eb = await getClient(ctx);
|
|
1451
|
+
if (kind === "agent") return (await eb.listAgents()).map((a) => ({ id: a.agentId, name: a.name, status: a.status }));
|
|
1452
|
+
if (kind === "db") return (await eb.listDatabases()).items.map((d) => ({ id: d.id, name: d.name }));
|
|
1453
|
+
return (await eb.sandboxes.list()).map((s) => ({ id: s.sandboxId, name: s.name, status: s.status }));
|
|
1454
|
+
})();
|
|
1455
|
+
p.catch(() => cache.delete(kind));
|
|
1456
|
+
cache.set(kind, p);
|
|
1457
|
+
}
|
|
1458
|
+
return p;
|
|
1459
|
+
}
|
|
1460
|
+
async function resolveRef(ctx, kind, ref) {
|
|
1461
|
+
if (looksLikeId(kind, ref)) return ref;
|
|
1462
|
+
const r = matchRef(kind, ref, await listRefs(ctx, kind));
|
|
1463
|
+
if (r.ok) return r.id;
|
|
1464
|
+
if (r.reason === "not_found") {
|
|
1465
|
+
throw new CliError(t(`No ${NOUN()[kind]} with id or name "${ref}".`, `No hay ${NOUN()[kind]} con id o nombre "${ref}".`), EXIT.API, `${t("List them with", "Enl\xEDstalos con")}: ${LS_HINT[kind]}`, "not_found", 404);
|
|
1466
|
+
}
|
|
1467
|
+
const shown = r.matches.slice(0, 10).map((m) => ` ${m.id}${m.status ? ` (${m.status})` : ""}`);
|
|
1468
|
+
if (r.matches.length > 10) shown.push(t(` \u2026and ${r.matches.length - 10} more`, ` \u2026y ${r.matches.length - 10} m\xE1s`));
|
|
1469
|
+
throw new CliError(
|
|
1470
|
+
t(`"${ref}" matches ${r.matches.length} ${NOUNS()[kind]}. Use the id:`, `"${ref}" coincide con ${r.matches.length} ${NOUNS()[kind]}. Usa el id:`),
|
|
1471
|
+
EXIT.USAGE,
|
|
1472
|
+
`${shown.join("\n")}
|
|
1473
|
+
${t("List them with", "Enl\xEDstalos con")}: ${LS_HINT[kind]}`,
|
|
1474
|
+
"ambiguous"
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
async function resolveRefs(ctx, key) {
|
|
1478
|
+
const spec = REF_ARGS[key];
|
|
1479
|
+
const ref = spec ? ctx.args[spec.index] : void 0;
|
|
1480
|
+
if (!spec || !ref) return;
|
|
1481
|
+
ctx.args[spec.index] = await resolveRef(ctx, spec.kind, ref);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1380
1484
|
// src/commands/machines.ts
|
|
1381
1485
|
var SECRETS_USAGE = "easybits machines secrets <ls|set|unset> <machine> [--dotenv <path> | NAME]";
|
|
1382
1486
|
var machines = {
|
|
@@ -1405,6 +1509,104 @@ var machines = {
|
|
|
1405
1509
|
);
|
|
1406
1510
|
}
|
|
1407
1511
|
},
|
|
1512
|
+
launch: {
|
|
1513
|
+
aliases: ["create", "new"],
|
|
1514
|
+
summary: "Create a machine and put an app on it in one step (or redeploy onto an existing one)",
|
|
1515
|
+
usage: "easybits machines launch (--repo <url> | --archive <url|file> | --machine <machine>) [--tier micro] [--name <name>] [--prebuilt] [--start <cmd>] [--port 3000] [--env K=V]... [--secret NAME]... [--data <path>]... [--domain <host>]",
|
|
1516
|
+
options: {
|
|
1517
|
+
repo: { type: "string", value: "url", description: "Git repo to clone (clean URL; a token goes in --repo-token)" },
|
|
1518
|
+
branch: { type: "string", value: "name", description: "Branch to clone" },
|
|
1519
|
+
"repo-token": { type: "string", value: "$secret:NAME", description: "Token for a private repo; best as $secret:NAME from your vault" },
|
|
1520
|
+
archive: { type: "string", value: "url|file", description: "A .tar.gz/.zip of the app: URL, or a local file that gets uploaded first" },
|
|
1521
|
+
machine: { type: "string", value: "machine", description: "Deploy onto this existing machine instead of creating one" },
|
|
1522
|
+
tier: { type: "string", value: "tier", description: "Size for a new machine: nano, micro (default), estandar, focus, performance\u2026" },
|
|
1523
|
+
name: { type: "string", value: "name", description: "Human label" },
|
|
1524
|
+
"app-dir": { type: "string", value: "dir", description: "Where the app lives in the machine (default /app)" },
|
|
1525
|
+
build: { type: "string", value: "cmd", description: "Build command (default: npm ci && npm run build)" },
|
|
1526
|
+
start: { type: "string", value: "cmd", description: "Start command (default: npm start)" },
|
|
1527
|
+
port: { type: "string", value: "port", description: "Port the app listens on (default 3000)" },
|
|
1528
|
+
prebuilt: { type: "boolean", description: "The code is already built: skip the build, just start it" },
|
|
1529
|
+
env: { type: "string", multiple: true, value: "K=V", description: "Environment variable, non-secret (repeatable)" },
|
|
1530
|
+
secret: { type: "string", multiple: true, value: "NAME", description: "Vault secret the app needs, by name (repeatable)" },
|
|
1531
|
+
data: { type: "string", multiple: true, value: "path", description: "Path the nightly backup copies (repeatable). Without it nothing is backed up" },
|
|
1532
|
+
domain: { type: "string", value: "host", description: "Domain to attach; the output says which DNS record to create" },
|
|
1533
|
+
message: { type: "string", short: "m", value: "text", description: "Release note" }
|
|
1534
|
+
},
|
|
1535
|
+
examples: [
|
|
1536
|
+
"easybits machines launch --repo https://github.com/you/shop.git --tier micro --domain shop.example.com",
|
|
1537
|
+
"easybits machines launch --archive ./build.tgz --prebuilt --tier nano --name shop --start 'npm start'",
|
|
1538
|
+
"easybits machines launch --machine shop --archive ./build.tgz --prebuilt -m v2 # redeploy"
|
|
1539
|
+
],
|
|
1540
|
+
async run(ctx) {
|
|
1541
|
+
const repo = str(ctx, "repo");
|
|
1542
|
+
let archiveUrl = str(ctx, "archive");
|
|
1543
|
+
const machineRef = str(ctx, "machine");
|
|
1544
|
+
if (!repo && !archiveUrl && !machineRef) {
|
|
1545
|
+
throw usageError(t("Give a source: --repo, --archive or --machine.", "Pasa una fuente: --repo, --archive o --machine."), this.usage);
|
|
1546
|
+
}
|
|
1547
|
+
if (repo && archiveUrl) throw usageError(t("--repo and --archive are exclusive.", "--repo y --archive se excluyen."), this.usage);
|
|
1548
|
+
if (machineRef && str(ctx, "tier")) {
|
|
1549
|
+
throw usageError(t("--tier is only for a new machine (resize = redeploy_machine).", "--tier s\xF3lo aplica a una m\xE1quina nueva (cambiar tama\xF1o = redeploy_machine)."), this.usage);
|
|
1550
|
+
}
|
|
1551
|
+
const eb = await getClient(ctx);
|
|
1552
|
+
const sandboxId = machineRef ? await resolveRef(ctx, "sandbox", machineRef) : void 0;
|
|
1553
|
+
if (archiveUrl && !/^https?:\/\//.test(archiveUrl)) {
|
|
1554
|
+
if (!existsSync6(archiveUrl)) throw usageError(t(`File not found: ${archiveUrl}`, `No existe el archivo: ${archiveUrl}`), this.usage);
|
|
1555
|
+
const size = statSync2(archiveUrl).size;
|
|
1556
|
+
const contentType = archiveUrl.endsWith(".zip") ? "application/zip" : "application/gzip";
|
|
1557
|
+
const up = await eb.uploadFile({ fileName: basename2(archiveUrl), contentType, size, access: "public" });
|
|
1558
|
+
const res = await fetch(up.putUrl, { method: "PUT", body: readFileSync6(archiveUrl), headers: { "Content-Type": contentType } });
|
|
1559
|
+
if (!res.ok) throw new CliError(t(`Upload failed: storage answered ${res.status}`, `Fall\xF3 la subida: el almacenamiento contest\xF3 ${res.status}`), 1, void 0, "upload_failed", res.status);
|
|
1560
|
+
archiveUrl = up.file.url;
|
|
1561
|
+
if (!archiveUrl) throw new CliError(t("The upload returned no public URL.", "La subida no devolvi\xF3 una URL p\xFAblica."), 1, void 0, "upload_failed");
|
|
1562
|
+
}
|
|
1563
|
+
const env = pairs(list(ctx, "env"), this.usage);
|
|
1564
|
+
const secretNames = list(ctx, "secret");
|
|
1565
|
+
const dataPaths = list(ctx, "data");
|
|
1566
|
+
const r = await eb.machines.launch({
|
|
1567
|
+
repo,
|
|
1568
|
+
branch: str(ctx, "branch"),
|
|
1569
|
+
repoToken: str(ctx, "repo-token"),
|
|
1570
|
+
archiveUrl,
|
|
1571
|
+
sandboxId,
|
|
1572
|
+
tier: str(ctx, "tier"),
|
|
1573
|
+
name: str(ctx, "name"),
|
|
1574
|
+
appDir: str(ctx, "app-dir"),
|
|
1575
|
+
buildCommand: str(ctx, "build"),
|
|
1576
|
+
startCommand: str(ctx, "start"),
|
|
1577
|
+
port: int(ctx, "port", this.usage),
|
|
1578
|
+
prebuilt: bool(ctx, "prebuilt") || void 0,
|
|
1579
|
+
env: Object.keys(env).length ? env : void 0,
|
|
1580
|
+
secretNames: secretNames.length ? secretNames : void 0,
|
|
1581
|
+
dataPaths: dataPaths.length ? dataPaths : void 0,
|
|
1582
|
+
domain: str(ctx, "domain"),
|
|
1583
|
+
message: str(ctx, "message")
|
|
1584
|
+
});
|
|
1585
|
+
if (r.checkoutUrl) {
|
|
1586
|
+
emit(ctx, r, () => {
|
|
1587
|
+
console.log(t("Your account has no plan: pay the machine here and it is created by itself:", "Tu cuenta no tiene plan: paga la m\xE1quina aqu\xED y se crea sola:"));
|
|
1588
|
+
console.log(` ${r.checkoutUrl}`);
|
|
1589
|
+
console.log(t("Then deploy onto it: easybits machines launch --machine <id> \u2026", "Luego despliega encima: easybits machines launch --machine <id> \u2026"));
|
|
1590
|
+
});
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
if (r.exitCode !== 0) {
|
|
1594
|
+
throw new CliError(
|
|
1595
|
+
t(`Launch failed (exit ${r.exitCode}) on ${r.sandboxId}`, `Fall\xF3 el lanzamiento (exit ${r.exitCode}) en ${r.sandboxId}`),
|
|
1596
|
+
1,
|
|
1597
|
+
r.buildOutput?.slice(-2e3),
|
|
1598
|
+
"launch_failed"
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
emit(ctx, r, () => {
|
|
1602
|
+
console.log(`${r.sandboxId} v${r.version} ${r.url}`);
|
|
1603
|
+
if (r.domain) {
|
|
1604
|
+
console.log(`${t("Domain", "Dominio")}: ${r.domain.domain} \u2192 ${r.domain.url}`);
|
|
1605
|
+
console.log(`DNS: ${JSON.stringify(r.domain.dns)}`);
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
},
|
|
1408
1610
|
deploy: {
|
|
1409
1611
|
summary: "Publish the machine's current app code as a new release",
|
|
1410
1612
|
usage: "easybits machines deploy <machine> [--message <text>]",
|
|
@@ -1576,11 +1778,11 @@ var domains = {
|
|
|
1576
1778
|
};
|
|
1577
1779
|
|
|
1578
1780
|
// src/commands/db.ts
|
|
1579
|
-
import { existsSync as
|
|
1781
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
1580
1782
|
|
|
1581
1783
|
// src/photos.ts
|
|
1582
1784
|
import { createHash as createHash2 } from "crypto";
|
|
1583
|
-
import { readFileSync as
|
|
1785
|
+
import { readFileSync as readFileSync7, readdirSync, statSync as statSync3 } from "fs";
|
|
1584
1786
|
import { extname as extname2, join as join3 } from "path";
|
|
1585
1787
|
var PHOTO_MAX_BYTES = 10 * 1024 * 1024;
|
|
1586
1788
|
var WHATSAPP_MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -1600,7 +1802,7 @@ function photoFiles(dir) {
|
|
|
1600
1802
|
for (const name of readdirSync(dir).sort()) {
|
|
1601
1803
|
if (name.startsWith(".")) continue;
|
|
1602
1804
|
const path = join3(dir, name);
|
|
1603
|
-
const st =
|
|
1805
|
+
const st = statSync3(path);
|
|
1604
1806
|
if (!st.isFile()) continue;
|
|
1605
1807
|
if (st.size === 0) {
|
|
1606
1808
|
rejected.push({ file: name, reason: "empty" });
|
|
@@ -1610,7 +1812,7 @@ function photoFiles(dir) {
|
|
|
1610
1812
|
rejected.push({ file: name, reason: "too_large" });
|
|
1611
1813
|
continue;
|
|
1612
1814
|
}
|
|
1613
|
-
const bytes =
|
|
1815
|
+
const bytes = readFileSync7(path);
|
|
1614
1816
|
const type = imageTypeOf(bytes);
|
|
1615
1817
|
if (!type) {
|
|
1616
1818
|
rejected.push({ file: name, reason: "not_an_image" });
|
|
@@ -1670,106 +1872,6 @@ function parseLinkStats(columns, row) {
|
|
|
1670
1872
|
return columns.map((column, i) => ({ column, permanent: n(i * 4), expiring: n(i * 4 + 1), external: n(i * 4 + 2), empty: n(i * 4 + 3) })).filter((s) => s.permanent + s.expiring + s.external > 0);
|
|
1671
1873
|
}
|
|
1672
1874
|
|
|
1673
|
-
// src/refs.ts
|
|
1674
|
-
var ID_FORMAT = {
|
|
1675
|
-
agent: /^[0-9a-f]{24}$/i,
|
|
1676
|
-
db: /^[0-9a-f]{24}$/i,
|
|
1677
|
-
sandbox: /^sb_[0-9a-z-]+$/i
|
|
1678
|
-
};
|
|
1679
|
-
var looksLikeId = (kind, ref) => ID_FORMAT[kind].test(ref);
|
|
1680
|
-
var REF_ARGS = {
|
|
1681
|
-
"agents get": { index: 0, kind: "agent" },
|
|
1682
|
-
"agents message": { index: 0, kind: "agent" },
|
|
1683
|
-
"agents destroy": { index: 0, kind: "agent" },
|
|
1684
|
-
"agents set": { index: 0, kind: "agent" },
|
|
1685
|
-
"agents files": { index: 1, kind: "agent" },
|
|
1686
|
-
"agents skills": { index: 1, kind: "agent" },
|
|
1687
|
-
"agents mcp": { index: 1, kind: "agent" },
|
|
1688
|
-
"agents restart": { index: 0, kind: "agent" },
|
|
1689
|
-
"agents try": { index: 0, kind: "agent" },
|
|
1690
|
-
"agents logs": { index: 0, kind: "agent" },
|
|
1691
|
-
"agents doctor": { index: 0, kind: "agent" },
|
|
1692
|
-
"agents export": { index: 0, kind: "agent" },
|
|
1693
|
-
"sandboxes get": { index: 0, kind: "sandbox" },
|
|
1694
|
-
"sandboxes exec": { index: 0, kind: "sandbox" },
|
|
1695
|
-
"sandboxes logs": { index: 0, kind: "sandbox" },
|
|
1696
|
-
"sandboxes files": { index: 1, kind: "sandbox" },
|
|
1697
|
-
"sandboxes suspend": { index: 0, kind: "sandbox" },
|
|
1698
|
-
"sandboxes resume": { index: 0, kind: "sandbox" },
|
|
1699
|
-
"sandboxes destroy": { index: 0, kind: "sandbox" },
|
|
1700
|
-
"sandboxes snapshot": { index: 0, kind: "sandbox" },
|
|
1701
|
-
"machines deploy": { index: 0, kind: "sandbox" },
|
|
1702
|
-
"machines releases": { index: 0, kind: "sandbox" },
|
|
1703
|
-
"machines logs": { index: 0, kind: "sandbox" },
|
|
1704
|
-
"machines rollback": { index: 0, kind: "sandbox" },
|
|
1705
|
-
"machines secrets": { index: 1, kind: "sandbox" },
|
|
1706
|
-
"domains ls": { index: 0, kind: "sandbox" },
|
|
1707
|
-
"domains add": { index: 0, kind: "sandbox" },
|
|
1708
|
-
"domains verify": { index: 0, kind: "sandbox" },
|
|
1709
|
-
"domains rm": { index: 0, kind: "sandbox" },
|
|
1710
|
-
"db rm": { index: 0, kind: "db" },
|
|
1711
|
-
"db tables": { index: 0, kind: "db" },
|
|
1712
|
-
"db query": { index: 0, kind: "db" },
|
|
1713
|
-
"db photos": { index: 1, kind: "db" }
|
|
1714
|
-
};
|
|
1715
|
-
function matchRef(kind, ref, items) {
|
|
1716
|
-
if (looksLikeId(kind, ref)) return { ok: true, id: ref };
|
|
1717
|
-
const list2 = items ?? [];
|
|
1718
|
-
if (list2.some((x) => x.id === ref)) return { ok: true, id: ref };
|
|
1719
|
-
const want = ref.trim().toLowerCase();
|
|
1720
|
-
const matches = list2.filter((x) => (x.name ?? "").trim().toLowerCase() === want);
|
|
1721
|
-
if (matches.length === 1) return { ok: true, id: matches[0].id };
|
|
1722
|
-
if (matches.length === 0) return { ok: false, reason: "not_found" };
|
|
1723
|
-
return { ok: false, reason: "ambiguous", matches };
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
// src/resolve.ts
|
|
1727
|
-
var LS_HINT = {
|
|
1728
|
-
agent: "easybits agents ls",
|
|
1729
|
-
sandbox: "easybits sandboxes ls",
|
|
1730
|
-
db: "easybits db ls"
|
|
1731
|
-
};
|
|
1732
|
-
var NOUN = () => ({ agent: t("agent", "agente"), sandbox: t("sandbox or machine", "sandbox o m\xE1quina"), db: t("database", "base de datos") });
|
|
1733
|
-
var NOUNS = () => ({ agent: t("agents", "agentes"), sandbox: t("sandboxes", "sandboxes"), db: t("databases", "bases de datos") });
|
|
1734
|
-
var cache = /* @__PURE__ */ new Map();
|
|
1735
|
-
function listRefs(ctx, kind) {
|
|
1736
|
-
let p = cache.get(kind);
|
|
1737
|
-
if (!p) {
|
|
1738
|
-
p = (async () => {
|
|
1739
|
-
const eb = await getClient(ctx);
|
|
1740
|
-
if (kind === "agent") return (await eb.listAgents()).map((a) => ({ id: a.agentId, name: a.name, status: a.status }));
|
|
1741
|
-
if (kind === "db") return (await eb.listDatabases()).items.map((d) => ({ id: d.id, name: d.name }));
|
|
1742
|
-
return (await eb.sandboxes.list()).map((s) => ({ id: s.sandboxId, name: s.name, status: s.status }));
|
|
1743
|
-
})();
|
|
1744
|
-
p.catch(() => cache.delete(kind));
|
|
1745
|
-
cache.set(kind, p);
|
|
1746
|
-
}
|
|
1747
|
-
return p;
|
|
1748
|
-
}
|
|
1749
|
-
async function resolveRef(ctx, kind, ref) {
|
|
1750
|
-
if (looksLikeId(kind, ref)) return ref;
|
|
1751
|
-
const r = matchRef(kind, ref, await listRefs(ctx, kind));
|
|
1752
|
-
if (r.ok) return r.id;
|
|
1753
|
-
if (r.reason === "not_found") {
|
|
1754
|
-
throw new CliError(t(`No ${NOUN()[kind]} with id or name "${ref}".`, `No hay ${NOUN()[kind]} con id o nombre "${ref}".`), EXIT.API, `${t("List them with", "Enl\xEDstalos con")}: ${LS_HINT[kind]}`, "not_found", 404);
|
|
1755
|
-
}
|
|
1756
|
-
const shown = r.matches.slice(0, 10).map((m) => ` ${m.id}${m.status ? ` (${m.status})` : ""}`);
|
|
1757
|
-
if (r.matches.length > 10) shown.push(t(` \u2026and ${r.matches.length - 10} more`, ` \u2026y ${r.matches.length - 10} m\xE1s`));
|
|
1758
|
-
throw new CliError(
|
|
1759
|
-
t(`"${ref}" matches ${r.matches.length} ${NOUNS()[kind]}. Use the id:`, `"${ref}" coincide con ${r.matches.length} ${NOUNS()[kind]}. Usa el id:`),
|
|
1760
|
-
EXIT.USAGE,
|
|
1761
|
-
`${shown.join("\n")}
|
|
1762
|
-
${t("List them with", "Enl\xEDstalos con")}: ${LS_HINT[kind]}`,
|
|
1763
|
-
"ambiguous"
|
|
1764
|
-
);
|
|
1765
|
-
}
|
|
1766
|
-
async function resolveRefs(ctx, key) {
|
|
1767
|
-
const spec = REF_ARGS[key];
|
|
1768
|
-
const ref = spec ? ctx.args[spec.index] : void 0;
|
|
1769
|
-
if (!spec || !ref) return;
|
|
1770
|
-
ctx.args[spec.index] = await resolveRef(ctx, spec.kind, ref);
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
1875
|
// src/commands/db.ts
|
|
1774
1876
|
async function findDb(ctx, id) {
|
|
1775
1877
|
const hit = (await listRefs(ctx, "db")).find((d) => d.id === id);
|
|
@@ -1901,7 +2003,7 @@ var db = {
|
|
|
1901
2003
|
const keyCol = str(ctx, "key-column");
|
|
1902
2004
|
const dir = str(ctx, "dir");
|
|
1903
2005
|
if (!tableName || !keyCol || !dir) throw usageError(t("Missing --table, --key-column or --dir.", "Faltan --table, --key-column o --dir."), this.usage);
|
|
1904
|
-
if (!
|
|
2006
|
+
if (!existsSync7(dir) || !statSync4(dir).isDirectory()) throw usageError(t(`Not a folder: ${dir}`, `No es una carpeta: ${dir}`), this.usage);
|
|
1905
2007
|
const { photos, rejected } = photoFiles(dir);
|
|
1906
2008
|
const eb = await getClient(ctx);
|
|
1907
2009
|
const hit = await findDb(ctx, ref);
|
|
@@ -1948,7 +2050,7 @@ var db = {
|
|
|
1948
2050
|
let url = urls.get(photo.sha);
|
|
1949
2051
|
if (!url) {
|
|
1950
2052
|
const up = await eb.uploadFile({ fileName: `${photo.sha.slice(0, 32)}.${photo.ext}`, contentType: photo.mime, size: photo.bytes, access: "public" });
|
|
1951
|
-
const res = await fetch(up.putUrl, { method: "PUT", body:
|
|
2053
|
+
const res = await fetch(up.putUrl, { method: "PUT", body: readFileSync8(photo.path), headers: { "Content-Type": photo.mime } });
|
|
1952
2054
|
if (!res.ok) throw new Error(t(`storage answered ${res.status}`, `el almacenamiento contest\xF3 ${res.status}`));
|
|
1953
2055
|
url = up.file.url;
|
|
1954
2056
|
if (!url) throw new Error(t("the API returned no public link", "la API no devolvi\xF3 liga p\xFAblica"));
|
|
@@ -2010,7 +2112,7 @@ var db = {
|
|
|
2010
2112
|
};
|
|
2011
2113
|
|
|
2012
2114
|
// src/commands/agents.ts
|
|
2013
|
-
import { existsSync as
|
|
2115
|
+
import { existsSync as existsSync11, readFileSync as readFileSync12, statSync as statSync7 } from "fs";
|
|
2014
2116
|
|
|
2015
2117
|
// src/api.ts
|
|
2016
2118
|
import { EasybitsError as EasybitsError2, resolveBaseUrl as resolveBaseUrl4 } from "@easybits.cloud/sdk";
|
|
@@ -2040,8 +2142,8 @@ async function api(ctx, method, path, body, opts = {}) {
|
|
|
2040
2142
|
var encodePath = (p) => p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/");
|
|
2041
2143
|
|
|
2042
2144
|
// src/commands/agents-config.ts
|
|
2043
|
-
import { existsSync as
|
|
2044
|
-
import { basename as
|
|
2145
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync9, readdirSync as readdirSync2, statSync as statSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
2146
|
+
import { basename as basename3, dirname, join as join4, relative, resolve } from "path";
|
|
2045
2147
|
var WORK_DIR = "/data/work";
|
|
2046
2148
|
var MACHINE_TEMPLATES = /* @__PURE__ */ new Set(["ghosty-lite", "goose"]);
|
|
2047
2149
|
var SKILLS_DIR = "/data/agent/skills";
|
|
@@ -2120,8 +2222,8 @@ function readLocalText(path, usage2) {
|
|
|
2120
2222
|
if (process.stdin.isTTY) throw usageError(t("Expected the content on stdin.", "Se esperaba el contenido por stdin."), usage2);
|
|
2121
2223
|
return readStdin().then((b) => b.toString("utf8"));
|
|
2122
2224
|
}
|
|
2123
|
-
if (!
|
|
2124
|
-
return
|
|
2225
|
+
if (!existsSync8(path)) throw usageError(t(`File not found: ${path}`, `No existe el archivo: ${path}`), usage2);
|
|
2226
|
+
return readFileSync9(path, "utf8");
|
|
2125
2227
|
}
|
|
2126
2228
|
function parseMcpFile(text, usage2) {
|
|
2127
2229
|
let j;
|
|
@@ -2336,8 +2438,8 @@ var files2 = {
|
|
|
2336
2438
|
if (!rest.length) throw usageError(t("Give one or more local files.", "Pasa uno o m\xE1s archivos locales."), FILES_USAGE2);
|
|
2337
2439
|
const to = (str(ctx, "to") ?? "").replace(/^\/+|\/+$/g, "");
|
|
2338
2440
|
const plan = rest.map((local) => {
|
|
2339
|
-
if (!
|
|
2340
|
-
return { local, path: to ? `${to}/${
|
|
2441
|
+
if (!existsSync8(local) || !statSync5(local).isFile()) throw usageError(t(`File not found: ${local}`, `No existe el archivo: ${local}`), FILES_USAGE2);
|
|
2442
|
+
return { local, path: to ? `${to}/${basename3(local)}` : basename3(local), bytes: statSync5(local).size };
|
|
2341
2443
|
});
|
|
2342
2444
|
if (bool(ctx, "dry-run")) {
|
|
2343
2445
|
emit(ctx, { agentId: id, dryRun: true, upload: plan }, () => {
|
|
@@ -2348,7 +2450,7 @@ var files2 = {
|
|
|
2348
2450
|
}
|
|
2349
2451
|
const done = [];
|
|
2350
2452
|
for (const p of plan) {
|
|
2351
|
-
const r = await api(ctx, "PUT", `/agents/${id}/files/${encodePath(p.path)}`,
|
|
2453
|
+
const r = await api(ctx, "PUT", `/agents/${id}/files/${encodePath(p.path)}`, readFileSync9(p.local), { raw: true });
|
|
2352
2454
|
done.push({ local: p.local, ...r });
|
|
2353
2455
|
if (!ctx.json) console.log(`${t("Uploaded", "Subido")} ${p.local} \u2192 ${WORK_DIR}/${p.path} (${fmtBytes(p.bytes)})`);
|
|
2354
2456
|
}
|
|
@@ -2378,7 +2480,7 @@ function readSkillDir(dir) {
|
|
|
2378
2480
|
if (e.name.startsWith(".") || e.name === "node_modules") continue;
|
|
2379
2481
|
const p = join4(d, e.name);
|
|
2380
2482
|
if (e.isDirectory()) visit(p);
|
|
2381
|
-
else if (e.isFile() && relative(dir, p) !== "SKILL.md") assets.push({ name: relative(dir, p).split("\\").join("/"), contentBase64:
|
|
2483
|
+
else if (e.isFile() && relative(dir, p) !== "SKILL.md") assets.push({ name: relative(dir, p).split("\\").join("/"), contentBase64: readFileSync9(p).toString("base64") });
|
|
2382
2484
|
}
|
|
2383
2485
|
};
|
|
2384
2486
|
visit(dir);
|
|
@@ -2442,11 +2544,11 @@ var skills = {
|
|
|
2442
2544
|
const dir = str(ctx, "dir");
|
|
2443
2545
|
if (!!file === !!dir) throw usageError(t("Pass --file SKILL.md or --dir <folder>.", "Pasa --file SKILL.md o --dir <carpeta>."), SKILLS_USAGE);
|
|
2444
2546
|
const mdPath = file ?? join4(dir, "SKILL.md");
|
|
2445
|
-
if (!
|
|
2446
|
-
const markdown =
|
|
2547
|
+
if (!existsSync8(mdPath)) throw usageError(t(`File not found: ${mdPath}`, `No existe el archivo: ${mdPath}`), SKILLS_USAGE);
|
|
2548
|
+
const markdown = readFileSync9(mdPath, "utf8");
|
|
2447
2549
|
const fm = skillFrontmatter(markdown);
|
|
2448
2550
|
if (fm.error) throw usageError(`${mdPath}: ${fm.error}`, SKILLS_USAGE);
|
|
2449
|
-
const slug = str(ctx, "slug") ?? (fm.name && SLUG_RE.test(fm.name) ? fm.name :
|
|
2551
|
+
const slug = str(ctx, "slug") ?? (fm.name && SLUG_RE.test(fm.name) ? fm.name : basename3(resolve(dir ?? dirname(mdPath))).toLowerCase());
|
|
2450
2552
|
if (!SLUG_RE.test(slug)) throw usageError(t(`Invalid slug "${slug}" ([a-z0-9-], max 64). Pass --slug.`, `Slug inv\xE1lido "${slug}" ([a-z0-9-], m\xE1x 64). Pasa --slug.`), SKILLS_USAGE);
|
|
2451
2553
|
const assets = dir ? readSkillDir(dir) : [];
|
|
2452
2554
|
const plan = { agentId: id, slug, files: ["SKILL.md", ...assets.map((a) => a.name)], restart: bool(ctx, "restart") };
|
|
@@ -2703,10 +2805,10 @@ var exportAgent = {
|
|
|
2703
2805
|
}
|
|
2704
2806
|
};
|
|
2705
2807
|
function readExport(path, usage2) {
|
|
2706
|
-
if (!
|
|
2808
|
+
if (!existsSync8(path)) throw usageError(t(`File not found: ${path}`, `No existe el archivo: ${path}`), usage2);
|
|
2707
2809
|
let x;
|
|
2708
2810
|
try {
|
|
2709
|
-
x = JSON.parse(
|
|
2811
|
+
x = JSON.parse(readFileSync9(path, "utf8"));
|
|
2710
2812
|
} catch (e) {
|
|
2711
2813
|
throw usageError(t(`${path} is not JSON: ${e.message}`, `${path} no es JSON: ${e.message}`), usage2);
|
|
2712
2814
|
}
|
|
@@ -2751,12 +2853,12 @@ async function applyExport(ctx, id, x, opts) {
|
|
|
2751
2853
|
}
|
|
2752
2854
|
|
|
2753
2855
|
// src/commands/spec.ts
|
|
2754
|
-
import { existsSync as
|
|
2856
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync11, statSync as statSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
2755
2857
|
import { homedir as homedir3 } from "os";
|
|
2756
2858
|
import { dirname as dirname2, join as join6, resolve as resolve2 } from "path";
|
|
2757
2859
|
|
|
2758
2860
|
// src/specfile.ts
|
|
2759
|
-
import { existsSync as
|
|
2861
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, readdirSync as readdirSync3 } from "fs";
|
|
2760
2862
|
import { join as join5, relative as relative2 } from "path";
|
|
2761
2863
|
function walkLocal(root) {
|
|
2762
2864
|
const out = [];
|
|
@@ -2768,20 +2870,20 @@ function walkLocal(root) {
|
|
|
2768
2870
|
else if (e.isFile()) out.push(relative2(root, p).split("\\").join("/"));
|
|
2769
2871
|
}
|
|
2770
2872
|
};
|
|
2771
|
-
if (
|
|
2873
|
+
if (existsSync9(root)) visit(root);
|
|
2772
2874
|
return out;
|
|
2773
2875
|
}
|
|
2774
2876
|
function readUploads(dir) {
|
|
2775
2877
|
const skills2 = {};
|
|
2776
2878
|
const skillsRoot = join5(dir, "skills");
|
|
2777
|
-
if (
|
|
2879
|
+
if (existsSync9(skillsRoot)) {
|
|
2778
2880
|
for (const e of readdirSync3(skillsRoot, { withFileTypes: true })) {
|
|
2779
2881
|
if (!e.isDirectory() || e.name.startsWith(".")) continue;
|
|
2780
|
-
skills2[e.name] = walkLocal(join5(skillsRoot, e.name)).map((path) => ({ path, contentBase64:
|
|
2882
|
+
skills2[e.name] = walkLocal(join5(skillsRoot, e.name)).map((path) => ({ path, contentBase64: readFileSync10(join5(skillsRoot, e.name, path)).toString("base64") }));
|
|
2781
2883
|
}
|
|
2782
2884
|
}
|
|
2783
2885
|
const filesRoot = join5(dir, "files");
|
|
2784
|
-
const files3 = Object.fromEntries(walkLocal(filesRoot).map((p) => [p,
|
|
2886
|
+
const files3 = Object.fromEntries(walkLocal(filesRoot).map((p) => [p, readFileSync10(join5(filesRoot, p)).toString("base64")]));
|
|
2785
2887
|
return { ...Object.keys(skills2).length ? { skills: skills2 } : {}, ...Object.keys(files3).length ? { files: files3 } : {} };
|
|
2786
2888
|
}
|
|
2787
2889
|
function secretsFor(text, env = process.env) {
|
|
@@ -2857,13 +2959,13 @@ ${t("Edit it, then", "Ed\xEDtalo y luego")}: easybits apply ${out} --dry-run`
|
|
|
2857
2959
|
}
|
|
2858
2960
|
};
|
|
2859
2961
|
function readTarget(target, usage2) {
|
|
2860
|
-
if (!
|
|
2861
|
-
if (
|
|
2862
|
-
const name = SPEC_NAMES.find((n) =>
|
|
2962
|
+
if (!existsSync10(target)) throw usageError(t(`Not found: ${target}`, `No existe: ${target}`), usage2);
|
|
2963
|
+
if (statSync6(target).isDirectory()) {
|
|
2964
|
+
const name = SPEC_NAMES.find((n) => existsSync10(join6(target, n)));
|
|
2863
2965
|
if (!name) throw usageError(t(`${target} has no agent.yaml.`, `${target} no tiene agent.yaml.`), usage2);
|
|
2864
|
-
return { text:
|
|
2966
|
+
return { text: readFileSync11(join6(target, name), "utf8"), dir: target };
|
|
2865
2967
|
}
|
|
2866
|
-
return { text:
|
|
2968
|
+
return { text: readFileSync11(target, "utf8") };
|
|
2867
2969
|
}
|
|
2868
2970
|
var line = (c) => `${c.op} ${c.what}`;
|
|
2869
2971
|
var printPlan = (plan) => console.log(plan.map(line).join("\n"));
|
|
@@ -2984,7 +3086,7 @@ var apply = {
|
|
|
2984
3086
|
// src/commands/agents.ts
|
|
2985
3087
|
function isLegacyExport(path) {
|
|
2986
3088
|
try {
|
|
2987
|
-
return
|
|
3089
|
+
return existsSync11(path) && !statSync7(path).isDirectory() && /"kind"\s*:\s*"easybits\.agent"/.test(readFileSync12(path, "utf8"));
|
|
2988
3090
|
} catch {
|
|
2989
3091
|
return false;
|
|
2990
3092
|
}
|
|
@@ -3051,9 +3153,9 @@ var agents = {
|
|
|
3051
3153
|
if (promptInline != null && promptFile) throw usageError(t("Use --prompt or --prompt-file, not both.", "Usa --prompt o --prompt-file, no los dos."), this.usage);
|
|
3052
3154
|
const mode = str(ctx, "prompt-mode");
|
|
3053
3155
|
if (mode && mode !== "append" && mode !== "replace") throw usageError(t("--prompt-mode must be append or replace.", "--prompt-mode debe ser append o replace."), this.usage);
|
|
3054
|
-
if (promptFile && !
|
|
3156
|
+
if (promptFile && !existsSync11(promptFile)) throw usageError(t(`File not found: ${promptFile}`, `No existe el archivo: ${promptFile}`), this.usage);
|
|
3055
3157
|
const mcpFile = str(ctx, "mcp-file");
|
|
3056
|
-
if (mcpFile && !
|
|
3158
|
+
if (mcpFile && !existsSync11(mcpFile)) throw usageError(t(`File not found: ${mcpFile}`, `No existe el archivo: ${mcpFile}`), this.usage);
|
|
3057
3159
|
if (bool(ctx, "copy-files") && !like && !from) throw usageError(t("--copy-files needs --like or --from.", "--copy-files necesita --like o --from."), this.usage);
|
|
3058
3160
|
if (from && !isLegacyExport(from)) {
|
|
3059
3161
|
await applyTarget(ctx, from, { create: true, name: str(ctx, "name"), dryRun: bool(ctx, "dry-run"), usage: this.usage });
|
|
@@ -3063,7 +3165,7 @@ var agents = {
|
|
|
3063
3165
|
const template = str(ctx, "template") ?? source?.template;
|
|
3064
3166
|
if (!template) throw usageError(t("Missing --template (or --like / --from).", "Falta --template (o --like / --from)."), this.usage);
|
|
3065
3167
|
const env = await envFrom(ctx, this.usage);
|
|
3066
|
-
const prompt = promptInline ?? (promptFile ?
|
|
3168
|
+
const prompt = promptInline ?? (promptFile ? readFileSync12(promptFile, "utf8") : source?.systemPrompt);
|
|
3067
3169
|
const promptMode = mode ?? source?.systemPromptMode;
|
|
3068
3170
|
const multiline = !!prompt && /[\r\n]/.test(prompt.trimEnd());
|
|
3069
3171
|
const promptAfter = multiline ? prompt : void 0;
|
|
@@ -3072,7 +3174,7 @@ var agents = {
|
|
|
3072
3174
|
}
|
|
3073
3175
|
if (prompt && !multiline) env.SYSTEM_PROMPT = prompt.trimEnd();
|
|
3074
3176
|
if (promptMode && (prompt || mode) && !multiline) env.SYSTEM_PROMPT_MODE = promptMode;
|
|
3075
|
-
const mcpServers = mcpFile ? parseMcpFile(
|
|
3177
|
+
const mcpServers = mcpFile ? parseMcpFile(readFileSync12(mcpFile, "utf8"), this.usage) : source?.mcpServers;
|
|
3076
3178
|
if (mcpServers && hasMasked(mcpServers)) {
|
|
3077
3179
|
throw usageError(t(`${from ?? "the source"} has masked MCP values (\u2026***).`, `${from ?? "la fuente"} trae valores del MCP tapados (\u2026***).`), t("Re-export with --show-secrets, or pass --mcp-file", "Vuelve a exportar con --show-secrets, o pasa --mcp-file"));
|
|
3078
3180
|
}
|
|
@@ -3164,7 +3266,7 @@ var agents = {
|
|
|
3164
3266
|
};
|
|
3165
3267
|
|
|
3166
3268
|
// src/commands/completion.ts
|
|
3167
|
-
import { mkdirSync as mkdirSync5, readFileSync as
|
|
3269
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
|
|
3168
3270
|
import { homedir as homedir4 } from "os";
|
|
3169
3271
|
import { dirname as dirname3, join as join7 } from "path";
|
|
3170
3272
|
var GLOBAL_FLAGS = ["--json", "--token", "--lang", "--help", "--version"];
|
|
@@ -3207,7 +3309,7 @@ var cacheFile = () => join7(process.env.XDG_CACHE_HOME || join7(homedir4(), ".ca
|
|
|
3207
3309
|
async function namesOf(ctx, kind) {
|
|
3208
3310
|
let cache2 = {};
|
|
3209
3311
|
try {
|
|
3210
|
-
cache2 = JSON.parse(
|
|
3312
|
+
cache2 = JSON.parse(readFileSync13(cacheFile(), "utf8"));
|
|
3211
3313
|
const c = cache2[kind];
|
|
3212
3314
|
if (c && Date.now() - c.at < 5 * 6e4) return c.names;
|
|
3213
3315
|
} catch {
|
|
@@ -3334,13 +3436,13 @@ var docs = {
|
|
|
3334
3436
|
};
|
|
3335
3437
|
|
|
3336
3438
|
// src/commands/doctor.ts
|
|
3337
|
-
import { existsSync as
|
|
3439
|
+
import { existsSync as existsSync12, statSync as statSync8 } from "fs";
|
|
3338
3440
|
import { homedir as homedir6 } from "os";
|
|
3339
3441
|
import { join as join9 } from "path";
|
|
3340
3442
|
import { resolveBaseUrl as resolveBaseUrl6 } from "@easybits.cloud/sdk";
|
|
3341
3443
|
|
|
3342
3444
|
// src/update.ts
|
|
3343
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
3445
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
3344
3446
|
import { homedir as homedir5 } from "os";
|
|
3345
3447
|
import { dirname as dirname4, join as join8 } from "path";
|
|
3346
3448
|
var FILE = join8(process.env.XDG_CONFIG_HOME || join8(homedir5(), ".config"), "easybits", "update.json");
|
|
@@ -3355,7 +3457,7 @@ function newer(a, b) {
|
|
|
3355
3457
|
var updateCheckDisabled = () => Boolean(process.env.EASYBITS_NO_UPDATE_CHECK || process.env.CI);
|
|
3356
3458
|
function readCache() {
|
|
3357
3459
|
try {
|
|
3358
|
-
return JSON.parse(
|
|
3460
|
+
return JSON.parse(readFileSync14(FILE, "utf8"));
|
|
3359
3461
|
} catch {
|
|
3360
3462
|
return {};
|
|
3361
3463
|
}
|
|
@@ -3390,7 +3492,7 @@ async function updateNotice(current2) {
|
|
|
3390
3492
|
}
|
|
3391
3493
|
|
|
3392
3494
|
// src/commands/doctor.ts
|
|
3393
|
-
var VERSION = true ? "0.
|
|
3495
|
+
var VERSION = true ? "0.14.1" : "dev";
|
|
3394
3496
|
var doctor2 = {
|
|
3395
3497
|
name: "doctor",
|
|
3396
3498
|
group: "Account",
|
|
@@ -3434,8 +3536,8 @@ var doctor2 = {
|
|
|
3434
3536
|
}
|
|
3435
3537
|
}
|
|
3436
3538
|
const rcPath = join9(homedir6(), ".easybitsrc");
|
|
3437
|
-
if (
|
|
3438
|
-
const mode =
|
|
3539
|
+
if (existsSync12(rcPath)) {
|
|
3540
|
+
const mode = statSync8(rcPath).mode & 511;
|
|
3439
3541
|
const ok2 = (mode & 63) === 0;
|
|
3440
3542
|
checks.push({ check: "rc-file", ok: ok2, detail: `${rcPath} ${mode.toString(8).padStart(3, "0")}`, ...ok2 ? {} : { hint: t(`It holds tokens. Run: chmod 600 ${rcPath}`, `Guarda tokens. Corre: chmod 600 ${rcPath}`) } });
|
|
3441
3543
|
}
|
|
@@ -3620,6 +3722,23 @@ var HELP_ES = {
|
|
|
3620
3722
|
"List your permanent machines": "Enlista tus m\xE1quinas permanentes",
|
|
3621
3723
|
"Publish the machine's current app code as a new release": "Publica el c\xF3digo actual de la app como un release nuevo",
|
|
3622
3724
|
"Release note": "Nota del release",
|
|
3725
|
+
"Create a machine and put an app on it in one step (or redeploy onto an existing one)": "Crea una m\xE1quina y le pone la app en un paso (o redespliega sobre una existente)",
|
|
3726
|
+
"Git repo to clone (clean URL; a token goes in --repo-token)": "Repo git a clonar (URL limpia; el token va en --repo-token)",
|
|
3727
|
+
"Branch to clone": "Rama a clonar",
|
|
3728
|
+
"Token for a private repo; best as $secret:NAME from your vault": "Token de un repo privado; mejor como $secret:NOMBRE de tu vault",
|
|
3729
|
+
"A .tar.gz/.zip of the app: URL, or a local file that gets uploaded first": "Un .tar.gz/.zip de la app: URL, o un archivo local que se sube primero",
|
|
3730
|
+
"Deploy onto this existing machine instead of creating one": "Despliega sobre esta m\xE1quina existente en vez de crear una",
|
|
3731
|
+
"Size for a new machine: nano, micro (default), estandar, focus, performance\u2026": "Tama\xF1o de una m\xE1quina nueva: nano, micro (default), estandar, focus, performance\u2026",
|
|
3732
|
+
"Human label": "Nombre para personas",
|
|
3733
|
+
"Where the app lives in the machine (default /app)": "D\xF3nde vive la app en la m\xE1quina (default /app)",
|
|
3734
|
+
"Build command (default: npm ci && npm run build)": "Comando de build (default: npm ci && npm run build)",
|
|
3735
|
+
"Start command (default: npm start)": "Comando de arranque (default: npm start)",
|
|
3736
|
+
"Port the app listens on (default 3000)": "Puerto en el que escucha la app (default 3000)",
|
|
3737
|
+
"The code is already built: skip the build, just start it": "El c\xF3digo ya viene compilado: sin build, s\xF3lo arranca",
|
|
3738
|
+
"Vault secret the app needs, by name (repeatable)": "Secreto del vault que necesita la app, por nombre (repetible)",
|
|
3739
|
+
"Path the nightly backup copies (repeatable). Without it nothing is backed up": "Ruta que copia el respaldo nocturno (repetible). Sin ella no se respalda nada",
|
|
3740
|
+
"Domain to attach; the output says which DNS record to create": "Dominio a pegar; la salida dice qu\xE9 registro DNS crear",
|
|
3741
|
+
"redeploy": "redespliegue",
|
|
3623
3742
|
"same thing, shorter": "lo mismo, m\xE1s corto",
|
|
3624
3743
|
"List releases, newest first": "Enlista los releases, el m\xE1s nuevo primero",
|
|
3625
3744
|
"How many": "Cu\xE1ntos",
|
|
@@ -3871,7 +3990,7 @@ function normalizeArgs(input) {
|
|
|
3871
3990
|
}
|
|
3872
3991
|
|
|
3873
3992
|
// src/index.ts
|
|
3874
|
-
var VERSION2 = true ? "0.
|
|
3993
|
+
var VERSION2 = true ? "0.14.1" : "dev";
|
|
3875
3994
|
var GLOBAL_OPTIONS = {
|
|
3876
3995
|
json: { type: "boolean" },
|
|
3877
3996
|
token: { type: "string" },
|
package/package.json
CHANGED