@easybits.cloud/cli 0.15.0 → 0.15.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 +11 -0
- package/dist/index.js +142 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -107,6 +107,8 @@ easybits files ls
|
|
|
107
107
|
easybits files upload ./report.pdf
|
|
108
108
|
easybits files rm FILE_ID --yes
|
|
109
109
|
easybits websites ls
|
|
110
|
+
easybits websites create "My shop" --slug my-shop # slug optional
|
|
111
|
+
easybits websites slug my-shop my-store # change it; the old URL 301s
|
|
110
112
|
easybits providers # storage provider (Tigris by default)
|
|
111
113
|
easybits usage
|
|
112
114
|
|
|
@@ -168,6 +170,15 @@ Host *.ghosty
|
|
|
168
170
|
|
|
169
171
|
Full reference: https://www.easybits.cloud/docs#cli · https://www.easybits.cloud/en/docs/cli.md
|
|
170
172
|
|
|
173
|
+
## Changes in 0.15.1
|
|
174
|
+
|
|
175
|
+
- After a `--dry-run`, the last line is the real command (`To apply: …`); without a terminal it
|
|
176
|
+
already carries `--yes` when the command asks for confirmation.
|
|
177
|
+
- A 404 with a reason prints the reason; a bare «Not found» says it may also be missing access
|
|
178
|
+
(another account's resource) and points to `easybits whoami`.
|
|
179
|
+
- The «new version» notice checks npm every hour (it was once a day), and asks again when the
|
|
180
|
+
cache is older than what you have installed.
|
|
181
|
+
|
|
171
182
|
## Changes in 0.15.0
|
|
172
183
|
|
|
173
184
|
- `db rename <db> <new-name> [--skip-prompts] [--dry-run]` (alias `mv`): renames the database (the
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { parseArgs } from "util";
|
|
5
5
|
|
|
6
6
|
// src/commands/account.ts
|
|
7
|
-
import { resolveBaseUrl as
|
|
7
|
+
import { resolveBaseUrl as resolveBaseUrl4 } from "@easybits.cloud/sdk";
|
|
8
8
|
|
|
9
9
|
// src/args.ts
|
|
10
10
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -108,6 +108,17 @@ function notLoggedIn() {
|
|
|
108
108
|
"not_logged_in"
|
|
109
109
|
);
|
|
110
110
|
}
|
|
111
|
+
function isGenericNotFound(body) {
|
|
112
|
+
let msg = body;
|
|
113
|
+
try {
|
|
114
|
+
const j = JSON.parse(body);
|
|
115
|
+
msg = j?.message ?? j?.error ?? j?.detail ?? "";
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
if (typeof msg !== "string") return false;
|
|
119
|
+
const s = msg.trim();
|
|
120
|
+
return !s || s.startsWith("<") || /^(404\s*:?\s*)?not found\.?$/i.test(s);
|
|
121
|
+
}
|
|
111
122
|
function apiMessage(body) {
|
|
112
123
|
try {
|
|
113
124
|
const j = JSON.parse(body);
|
|
@@ -142,6 +153,14 @@ function toCliError(err) {
|
|
|
142
153
|
401
|
|
143
154
|
);
|
|
144
155
|
}
|
|
156
|
+
if (err.status === 404) {
|
|
157
|
+
const hint404 = t(
|
|
158
|
+
"Check the id (list what you have with the matching `ls` command) and that your key is from the account that owns it (easybits whoami).",
|
|
159
|
+
"Revisa el id (enlista lo que tienes con el `ls` que corresponda) y que tu key sea de la cuenta due\xF1a (easybits whoami)."
|
|
160
|
+
);
|
|
161
|
+
if (isGenericNotFound(err.body)) return new CliError(t("Not found \u2014 or you don't have access to it.", "No se encontr\xF3, o no tienes acceso."), EXIT.API, hint404, "not_found", 404);
|
|
162
|
+
return new CliError(message2, EXIT.API, (kind && KIND_HINTS()[kind]) ?? hint404, "not_found", 404);
|
|
163
|
+
}
|
|
145
164
|
const hint = (kind && KIND_HINTS()[kind]) ?? (err.status === 403 ? t("Your key may lack the scope for this action (READ/WRITE/DELETE).", "Tu key quiz\xE1 no tiene el permiso para esto (READ/WRITE/DELETE).") : err.status === 404 ? t("Check the id. List what you have with the matching `ls` command.", "Revisa el id. Enlista lo que tienes con el `ls` que corresponda.") : err.status === 402 ? t("Plan limit reached. See: easybits usage", "Llegaste al l\xEDmite de tu plan. Mira: easybits usage") : void 0);
|
|
146
165
|
return new CliError(`${t("API error", "Error de la API")} ${err.status}: ${message2}`, EXIT.API, hint, "api_error", err.status);
|
|
147
166
|
}
|
|
@@ -284,6 +303,9 @@ function maskSecret(v) {
|
|
|
284
303
|
return v.length <= 8 ? "***" : `${v.slice(0, 4)}\u2026***`;
|
|
285
304
|
}
|
|
286
305
|
|
|
306
|
+
// src/api.ts
|
|
307
|
+
import { EasybitsError as EasybitsError2, resolveBaseUrl as resolveBaseUrl3 } from "@easybits.cloud/sdk";
|
|
308
|
+
|
|
287
309
|
// src/client.ts
|
|
288
310
|
import { EasybitsClient, resolveBaseUrl as resolveBaseUrl2 } from "@easybits.cloud/sdk";
|
|
289
311
|
|
|
@@ -481,6 +503,32 @@ async function getClient(ctx) {
|
|
|
481
503
|
return new EasybitsClient({ apiKey, baseUrl: await resolveBaseUrl2() });
|
|
482
504
|
}
|
|
483
505
|
|
|
506
|
+
// src/api.ts
|
|
507
|
+
async function api(ctx, method, path, body, opts = {}) {
|
|
508
|
+
const token = await resolveCredential(ctx);
|
|
509
|
+
const base = (await resolveBaseUrl3()).replace(/\/$/, "");
|
|
510
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
511
|
+
let payload;
|
|
512
|
+
if (body !== void 0) {
|
|
513
|
+
if (opts.raw) {
|
|
514
|
+
payload = body;
|
|
515
|
+
headers["Content-Type"] = "application/octet-stream";
|
|
516
|
+
} else {
|
|
517
|
+
payload = JSON.stringify(body);
|
|
518
|
+
headers["Content-Type"] = "application/json";
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const res = await fetch(`${base}/api/v2${path}`, { method, headers, body: payload });
|
|
522
|
+
const text = await res.text();
|
|
523
|
+
if (!res.ok) throw new EasybitsError2(res.status, text);
|
|
524
|
+
try {
|
|
525
|
+
return JSON.parse(text);
|
|
526
|
+
} catch {
|
|
527
|
+
return text;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
var encodePath = (p) => p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/");
|
|
531
|
+
|
|
484
532
|
// src/commands/account.ts
|
|
485
533
|
var login = {
|
|
486
534
|
name: "login",
|
|
@@ -573,8 +621,8 @@ Webhooks: ${u.counts.webhooks}`
|
|
|
573
621
|
var websites = {
|
|
574
622
|
name: "websites",
|
|
575
623
|
group: "Storage",
|
|
576
|
-
summary: "
|
|
577
|
-
synopsis: "websites",
|
|
624
|
+
summary: "Static websites: list, create, change slug",
|
|
625
|
+
synopsis: "websites <ls|create|slug>",
|
|
578
626
|
subs: {
|
|
579
627
|
ls: {
|
|
580
628
|
aliases: ["list"],
|
|
@@ -594,10 +642,55 @@ var websites = {
|
|
|
594
642
|
)
|
|
595
643
|
);
|
|
596
644
|
}
|
|
645
|
+
},
|
|
646
|
+
create: {
|
|
647
|
+
summary: "Create an empty static website (optionally with your own slug)",
|
|
648
|
+
usage: "easybits websites create <name> [--slug <slug>]",
|
|
649
|
+
options: { slug: { type: "string", value: "slug", description: "Public slug: /s/<slug>/ (a-z, 0-9, hyphens, 3-60 chars)" } },
|
|
650
|
+
examples: ['easybits websites create "Mi tienda" --slug mi-tienda'],
|
|
651
|
+
async run(ctx) {
|
|
652
|
+
const name = need(ctx, 0, "name", this.usage);
|
|
653
|
+
const slug = str(ctx, "slug");
|
|
654
|
+
const { website } = await api(ctx, "POST", "/websites", { name, ...slug ? { slug } : {} });
|
|
655
|
+
emit(ctx, website, () => console.log(t(`Created ${website.slug} \u2192 ${website.url}`, `Creado ${website.slug} \u2192 ${website.url}`)));
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
slug: {
|
|
659
|
+
summary: "Change a website's slug (the old URL redirects 301 to the new one)",
|
|
660
|
+
usage: "easybits websites slug <websiteId|slug> <new-slug>",
|
|
661
|
+
examples: ["easybits websites slug rio-durmiente mi-tienda"],
|
|
662
|
+
async run(ctx) {
|
|
663
|
+
const ref = need(ctx, 0, "website", this.usage);
|
|
664
|
+
const slug = need(ctx, 1, "new-slug", this.usage);
|
|
665
|
+
const websiteId = await resolveWebsiteId(ctx, ref);
|
|
666
|
+
const { website } = await api(ctx, "PATCH", `/websites/${websiteId}`, { slug });
|
|
667
|
+
emit(ctx, website, () => console.log(t(`Slug changed \u2192 ${website.url}`, `Slug cambiado \u2192 ${website.url}`)));
|
|
668
|
+
}
|
|
597
669
|
}
|
|
598
670
|
},
|
|
599
671
|
defaultSub: "ls"
|
|
600
672
|
};
|
|
673
|
+
function matchWebsite(ref, items) {
|
|
674
|
+
if (/^[0-9a-f]{24}$/i.test(ref)) return ref;
|
|
675
|
+
const r = ref.trim().toLowerCase();
|
|
676
|
+
return items.find((w) => w.slug === r)?.id ?? null;
|
|
677
|
+
}
|
|
678
|
+
async function resolveWebsiteId(ctx, ref) {
|
|
679
|
+
if (/^[0-9a-f]{24}$/i.test(ref)) return ref;
|
|
680
|
+
for (let offset = 0; ; offset += 100) {
|
|
681
|
+
const page = await api(ctx, "GET", `/websites?limit=100&offset=${offset}`);
|
|
682
|
+
const id = matchWebsite(ref, page.items);
|
|
683
|
+
if (id) return id;
|
|
684
|
+
if (page.items.length < 100 || offset + 100 >= page.total) break;
|
|
685
|
+
}
|
|
686
|
+
throw new CliError(
|
|
687
|
+
t(`No website with id or slug "${ref}".`, `No hay sitio con id o slug "${ref}".`),
|
|
688
|
+
EXIT.API,
|
|
689
|
+
`${t("List them with", "Enl\xEDstalos con")}: easybits websites ls`,
|
|
690
|
+
"not_found",
|
|
691
|
+
404
|
|
692
|
+
);
|
|
693
|
+
}
|
|
601
694
|
var providers = {
|
|
602
695
|
name: "providers",
|
|
603
696
|
group: "Storage",
|
|
@@ -641,7 +734,7 @@ var mcp = {
|
|
|
641
734
|
return;
|
|
642
735
|
}
|
|
643
736
|
const apiKey = resolveApiKey(ctx);
|
|
644
|
-
const baseUrl = await
|
|
737
|
+
const baseUrl = await resolveBaseUrl4();
|
|
645
738
|
const config = {
|
|
646
739
|
mcpServers: {
|
|
647
740
|
easybits: {
|
|
@@ -669,7 +762,7 @@ var whoami = {
|
|
|
669
762
|
const source = process.env.EASYBITS_API_KEY ? "env EASYBITS_API_KEY" : ctx.token ? "--token" : readRc().oauth?.accessToken ? "browser session (~/.easybitsrc)" : readRc().apiKey ? "API key (~/.easybitsrc)" : void 0;
|
|
670
763
|
if (!source) throw notLoggedIn();
|
|
671
764
|
const email = await fetchEmail(await resolveCredential(ctx));
|
|
672
|
-
emit(ctx, { email, source, baseUrl: await
|
|
765
|
+
emit(ctx, { email, source, baseUrl: await resolveBaseUrl4() }, () => console.log(`${email ?? t("(unknown email)", "(correo desconocido)")} ${t("via", "por")} ${source}`));
|
|
673
766
|
}
|
|
674
767
|
}
|
|
675
768
|
};
|
|
@@ -683,9 +776,18 @@ import { createInterface } from "readline/promises";
|
|
|
683
776
|
var YES_OPTION = {
|
|
684
777
|
yes: { type: "boolean", short: "y", description: "Skip the confirmation (required without a terminal or with --json)" }
|
|
685
778
|
};
|
|
686
|
-
function sameCommand() {
|
|
687
|
-
const
|
|
688
|
-
return `easybits ${
|
|
779
|
+
function sameCommand(argv2 = process.argv.slice(2)) {
|
|
780
|
+
const quoted = argv2.map((a) => /^[\w@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`);
|
|
781
|
+
return `easybits ${quoted.join(" ")}`;
|
|
782
|
+
}
|
|
783
|
+
function applyCommand(argv2, opts) {
|
|
784
|
+
const rest = argv2.filter((a) => a !== "--dry-run");
|
|
785
|
+
const hasYes = rest.some((a) => a === "--yes" || a === "-y");
|
|
786
|
+
return `${sameCommand(rest)}${opts.needsYes && opts.headless && !hasYes ? " --yes" : ""}`;
|
|
787
|
+
}
|
|
788
|
+
function applyHint(ctx, opts = {}) {
|
|
789
|
+
const cmd = applyCommand(process.argv.slice(2), { headless: !interactive(ctx), needsYes: opts.needsYes });
|
|
790
|
+
return t(`To apply: ${cmd}`, `Para aplicarlo: ${cmd}`);
|
|
689
791
|
}
|
|
690
792
|
async function ask(question) {
|
|
691
793
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -1873,33 +1975,6 @@ function parseLinkStats(columns, row) {
|
|
|
1873
1975
|
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);
|
|
1874
1976
|
}
|
|
1875
1977
|
|
|
1876
|
-
// src/api.ts
|
|
1877
|
-
import { EasybitsError as EasybitsError2, resolveBaseUrl as resolveBaseUrl4 } from "@easybits.cloud/sdk";
|
|
1878
|
-
async function api(ctx, method, path, body, opts = {}) {
|
|
1879
|
-
const token = await resolveCredential(ctx);
|
|
1880
|
-
const base = (await resolveBaseUrl4()).replace(/\/$/, "");
|
|
1881
|
-
const headers = { Authorization: `Bearer ${token}` };
|
|
1882
|
-
let payload;
|
|
1883
|
-
if (body !== void 0) {
|
|
1884
|
-
if (opts.raw) {
|
|
1885
|
-
payload = body;
|
|
1886
|
-
headers["Content-Type"] = "application/octet-stream";
|
|
1887
|
-
} else {
|
|
1888
|
-
payload = JSON.stringify(body);
|
|
1889
|
-
headers["Content-Type"] = "application/json";
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
const res = await fetch(`${base}/api/v2${path}`, { method, headers, body: payload });
|
|
1893
|
-
const text = await res.text();
|
|
1894
|
-
if (!res.ok) throw new EasybitsError2(res.status, text);
|
|
1895
|
-
try {
|
|
1896
|
-
return JSON.parse(text);
|
|
1897
|
-
} catch {
|
|
1898
|
-
return text;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
var encodePath = (p) => p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/");
|
|
1902
|
-
|
|
1903
1978
|
// src/commands/agents-config.ts
|
|
1904
1979
|
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1905
1980
|
import { basename as basename3, dirname, join as join4, relative, resolve } from "path";
|
|
@@ -2138,6 +2213,7 @@ var set = {
|
|
|
2138
2213
|
if (!Object.keys(changes).length) return console.log(t("No changes: the agent already has that prompt.", "Sin cambios: el agente ya tiene ese prompt."));
|
|
2139
2214
|
for (const [k, v] of Object.entries(changes)) console.log(`${k}: ${v.from} \u2192 ${v.to}`);
|
|
2140
2215
|
console.log(t("(dry run: nothing changed)", "(simulaci\xF3n: no cambi\xF3 nada)"));
|
|
2216
|
+
console.log(applyHint(ctx));
|
|
2141
2217
|
});
|
|
2142
2218
|
return;
|
|
2143
2219
|
}
|
|
@@ -2204,6 +2280,7 @@ var files2 = {
|
|
|
2204
2280
|
emit(ctx, { agentId: id, dryRun: true, upload: plan }, () => {
|
|
2205
2281
|
for (const p of plan) console.log(`${p.local} \u2192 ${WORK_DIR}/${p.path} (${fmtBytes(p.bytes)})`);
|
|
2206
2282
|
console.log(t("(dry run: nothing uploaded)", "(simulaci\xF3n: no se subi\xF3 nada)"));
|
|
2283
|
+
console.log(applyHint(ctx));
|
|
2207
2284
|
});
|
|
2208
2285
|
return;
|
|
2209
2286
|
}
|
|
@@ -2220,6 +2297,7 @@ var files2 = {
|
|
|
2220
2297
|
if (bool(ctx, "dry-run")) {
|
|
2221
2298
|
emit(ctx, { agentId: id, dryRun: true, delete: rest }, () => {
|
|
2222
2299
|
for (const p of rest) console.log(`${t("would delete", "borrar\xEDa")} ${WORK_DIR}/${p}`);
|
|
2300
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2223
2301
|
});
|
|
2224
2302
|
return;
|
|
2225
2303
|
}
|
|
@@ -2312,9 +2390,12 @@ var skills = {
|
|
|
2312
2390
|
const assets = dir ? readSkillDir(dir) : [];
|
|
2313
2391
|
const plan = { agentId: id, slug, files: ["SKILL.md", ...assets.map((a) => a.name)], restart: bool(ctx, "restart") };
|
|
2314
2392
|
if (bool(ctx, "dry-run")) {
|
|
2315
|
-
emit(ctx, { ...plan, dryRun: true }, () =>
|
|
2393
|
+
emit(ctx, { ...plan, dryRun: true }, () => {
|
|
2394
|
+
console.log(t(`would add skill ${slug} (${plan.files.length} file(s))${plan.restart ? " and restart" : ""}
|
|
2316
2395
|
(dry run: nothing changed)`, `agregar\xEDa la skill ${slug} (${plan.files.length} archivo(s))${plan.restart ? " y reiniciar\xEDa" : ""}
|
|
2317
|
-
(simulaci\xF3n: no cambi\xF3 nada)`))
|
|
2396
|
+
(simulaci\xF3n: no cambi\xF3 nada)`));
|
|
2397
|
+
console.log(applyHint(ctx));
|
|
2398
|
+
});
|
|
2318
2399
|
return;
|
|
2319
2400
|
}
|
|
2320
2401
|
const r = await api(ctx, "PUT", `/agents/${id}/skills/${slug}`, { markdown, assets });
|
|
@@ -2327,7 +2408,10 @@ var skills = {
|
|
|
2327
2408
|
const slugs = ctx.args.slice(2);
|
|
2328
2409
|
if (!slugs.length) throw usageError(t("Give one or more slugs.", "Pasa uno o m\xE1s slugs."), SKILLS_USAGE);
|
|
2329
2410
|
if (bool(ctx, "dry-run")) {
|
|
2330
|
-
emit(ctx, { agentId: id, dryRun: true, delete: slugs }, () =>
|
|
2411
|
+
emit(ctx, { agentId: id, dryRun: true, delete: slugs }, () => {
|
|
2412
|
+
slugs.forEach((s) => console.log(`${t("would remove skill", "quitar\xEDa la skill")} ${s}`));
|
|
2413
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2414
|
+
});
|
|
2331
2415
|
return;
|
|
2332
2416
|
}
|
|
2333
2417
|
requireYesIfHeadless(ctx);
|
|
@@ -2391,6 +2475,7 @@ var mcp2 = {
|
|
|
2391
2475
|
removed: ${diff.removed.join(", ") || "-"}
|
|
2392
2476
|
changed: ${diff.changed.join(", ") || "-"}`);
|
|
2393
2477
|
console.log(t("(dry run: nothing changed; a real set restarts the agent)", "(simulaci\xF3n: no cambi\xF3 nada; un set de verdad reinicia el agente)"));
|
|
2478
|
+
console.log(applyHint(ctx));
|
|
2394
2479
|
});
|
|
2395
2480
|
return;
|
|
2396
2481
|
}
|
|
@@ -2720,6 +2805,7 @@ var db = {
|
|
|
2720
2805
|
console.log(t(`${hit2.name} (${hit2.id}): ${tables.length} table(s), ${rows} row(s)`, `${hit2.name} (${hit2.id}): ${tables.length} tabla(s), ${rows} fila(s)`));
|
|
2721
2806
|
for (const x of tables) console.log(` ${x.name}: ${x.rows}`);
|
|
2722
2807
|
console.log(t("(dry run: nothing deleted)", "(simulaci\xF3n: no se borr\xF3 nada)"));
|
|
2808
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2723
2809
|
});
|
|
2724
2810
|
return;
|
|
2725
2811
|
}
|
|
@@ -2773,6 +2859,7 @@ var db = {
|
|
|
2773
2859
|
console.log(`${from} \u2192 ${to}`);
|
|
2774
2860
|
printRefs();
|
|
2775
2861
|
console.log(t("(dry run: nothing changed; without --dry-run those prompts are rewritten too)", "(simulaci\xF3n: no cambi\xF3 nada; sin --dry-run tambi\xE9n se reescriben esos prompts)"));
|
|
2862
|
+
console.log(applyHint(ctx));
|
|
2776
2863
|
});
|
|
2777
2864
|
return;
|
|
2778
2865
|
}
|
|
@@ -3115,6 +3202,7 @@ async function applyTarget(ctx, target, o) {
|
|
|
3115
3202
|
for (const s of Object.keys(uploads.skills ?? {})) console.log(`+ skill ${s}`);
|
|
3116
3203
|
for (const f of Object.keys(uploads.files ?? {})) console.log(`+ file ${f}`);
|
|
3117
3204
|
console.log(t("(dry run: nothing created)", "(simulaci\xF3n: no se cre\xF3 nada)"));
|
|
3205
|
+
console.log(applyHint(ctx));
|
|
3118
3206
|
});
|
|
3119
3207
|
return;
|
|
3120
3208
|
}
|
|
@@ -3155,6 +3243,7 @@ async function applyTarget(ctx, target, o) {
|
|
|
3155
3243
|
console.log(
|
|
3156
3244
|
actionable.length ? t("(dry run: nothing changed)", "(simulaci\xF3n: no cambi\xF3 nada)") : plan.plan.length ? t("Nothing to apply (see the ! lines).", "Nada que aplicar (mira los renglones con !).") : t("No changes: the agent already matches the file.", "Sin cambios: el agente ya coincide con el archivo.")
|
|
3157
3245
|
);
|
|
3246
|
+
if (o.dryRun && actionable.length) console.log(applyHint(ctx, { needsYes: true }));
|
|
3158
3247
|
});
|
|
3159
3248
|
return;
|
|
3160
3249
|
}
|
|
@@ -3320,6 +3409,7 @@ var agents = {
|
|
|
3320
3409
|
for (const [k, v] of Object.entries(plan)) console.log(`${k.padEnd(12)} ${Array.isArray(v) ? v.join(", ") || "-" : v ?? "-"}`);
|
|
3321
3410
|
if (source) console.log(t("Env is never copied: pass the engine's keys with --dotenv.", "El env nunca se copia: pasa las llaves del motor con --dotenv."));
|
|
3322
3411
|
console.log(t("(dry run: nothing created)", "(simulaci\xF3n: no se cre\xF3 nada)"));
|
|
3412
|
+
console.log(applyHint(ctx));
|
|
3323
3413
|
});
|
|
3324
3414
|
return;
|
|
3325
3415
|
}
|
|
@@ -3575,7 +3665,7 @@ import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync
|
|
|
3575
3665
|
import { homedir as homedir5 } from "os";
|
|
3576
3666
|
import { dirname as dirname4, join as join8 } from "path";
|
|
3577
3667
|
var FILE = join8(process.env.XDG_CONFIG_HOME || join8(homedir5(), ".config"), "easybits", "update.json");
|
|
3578
|
-
var
|
|
3668
|
+
var TTL = 60 * 60 * 1e3;
|
|
3579
3669
|
var UPGRADE = "npm i -g @easybits.cloud/cli@latest";
|
|
3580
3670
|
function newer(a, b) {
|
|
3581
3671
|
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -3603,10 +3693,14 @@ async function fetchLatest(timeoutMs = 1500) {
|
|
|
3603
3693
|
return null;
|
|
3604
3694
|
}
|
|
3605
3695
|
}
|
|
3606
|
-
|
|
3696
|
+
function cacheFresh(c, current2, now = Date.now()) {
|
|
3697
|
+
if (!c.latest || !c.checkedAt || now - c.checkedAt >= TTL) return false;
|
|
3698
|
+
return !(current2 && current2 !== "dev" && newer(current2, c.latest));
|
|
3699
|
+
}
|
|
3700
|
+
async function latestVersion(current2) {
|
|
3607
3701
|
if (updateCheckDisabled()) return null;
|
|
3608
3702
|
const c = readCache();
|
|
3609
|
-
if (
|
|
3703
|
+
if (cacheFresh(c, current2)) return c.latest;
|
|
3610
3704
|
return await fetchLatest() ?? c.latest ?? null;
|
|
3611
3705
|
}
|
|
3612
3706
|
function cachedNewer(current2) {
|
|
@@ -3616,12 +3710,12 @@ function cachedNewer(current2) {
|
|
|
3616
3710
|
}
|
|
3617
3711
|
async function updateNotice(current2) {
|
|
3618
3712
|
if (current2 === "dev") return null;
|
|
3619
|
-
const latest = await latestVersion();
|
|
3713
|
+
const latest = await latestVersion(current2);
|
|
3620
3714
|
return latest && newer(latest, current2) ? t(`Update available: ${current2} \u2192 ${latest}. Run: ${UPGRADE}`, `Hay versi\xF3n nueva: ${current2} \u2192 ${latest}. Corre: ${UPGRADE}`) : null;
|
|
3621
3715
|
}
|
|
3622
3716
|
|
|
3623
3717
|
// src/commands/doctor.ts
|
|
3624
|
-
var VERSION = true ? "0.15.
|
|
3718
|
+
var VERSION = true ? "0.15.2" : "dev";
|
|
3625
3719
|
var doctor2 = {
|
|
3626
3720
|
name: "doctor",
|
|
3627
3721
|
group: "Account",
|
|
@@ -3908,6 +4002,10 @@ var HELP_ES = {
|
|
|
3908
4002
|
"Upload a local file": "Sube un archivo local",
|
|
3909
4003
|
"Delete a file (soft delete, 7-day trash)": "Borra un archivo (a la papelera 7 d\xEDas)",
|
|
3910
4004
|
"List your static websites": "Enlista tus sitios est\xE1ticos",
|
|
4005
|
+
"Static websites: list, create, change slug": "Sitios est\xE1ticos: enlistar, crear, cambiar slug",
|
|
4006
|
+
"Create an empty static website (optionally with your own slug)": "Crea un sitio est\xE1tico vac\xEDo (con tu propio slug si quieres)",
|
|
4007
|
+
"Public slug: /s/<slug>/ (a-z, 0-9, hyphens, 3-60 chars)": "Slug p\xFAblico: /s/<slug>/ (a-z, 0-9, guiones, 3-60 caracteres)",
|
|
4008
|
+
"Change a website's slug (the old URL redirects 301 to the new one)": "Cambia el slug de un sitio (la URL vieja redirige 301 a la nueva)",
|
|
3911
4009
|
"Show storage providers": "Muestra los proveedores de almacenamiento",
|
|
3912
4010
|
"MCP": "MCP",
|
|
3913
4011
|
"Print the MCP config JSON for your agent or editor": "Imprime el JSON de configuraci\xF3n MCP para tu agente o editor",
|
|
@@ -4125,7 +4223,7 @@ function normalizeArgs(input) {
|
|
|
4125
4223
|
}
|
|
4126
4224
|
|
|
4127
4225
|
// src/index.ts
|
|
4128
|
-
var VERSION2 = true ? "0.15.
|
|
4226
|
+
var VERSION2 = true ? "0.15.2" : "dev";
|
|
4129
4227
|
var GLOBAL_OPTIONS = {
|
|
4130
4228
|
json: { type: "boolean" },
|
|
4131
4229
|
token: { type: "string" },
|
package/package.json
CHANGED