@easybits.cloud/cli 0.15.0 → 0.15.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 +9 -0
- package/dist/index.js +59 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -168,6 +168,15 @@ Host *.ghosty
|
|
|
168
168
|
|
|
169
169
|
Full reference: https://www.easybits.cloud/docs#cli · https://www.easybits.cloud/en/docs/cli.md
|
|
170
170
|
|
|
171
|
+
## Changes in 0.15.1
|
|
172
|
+
|
|
173
|
+
- After a `--dry-run`, the last line is the real command (`To apply: …`); without a terminal it
|
|
174
|
+
already carries `--yes` when the command asks for confirmation.
|
|
175
|
+
- A 404 with a reason prints the reason; a bare «Not found» says it may also be missing access
|
|
176
|
+
(another account's resource) and points to `easybits whoami`.
|
|
177
|
+
- The «new version» notice checks npm every hour (it was once a day), and asks again when the
|
|
178
|
+
cache is older than what you have installed.
|
|
179
|
+
|
|
171
180
|
## Changes in 0.15.0
|
|
172
181
|
|
|
173
182
|
- `db rename <db> <new-name> [--skip-prompts] [--dry-run]` (alias `mv`): renames the database (the
|
package/dist/index.js
CHANGED
|
@@ -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
|
}
|
|
@@ -683,9 +702,18 @@ import { createInterface } from "readline/promises";
|
|
|
683
702
|
var YES_OPTION = {
|
|
684
703
|
yes: { type: "boolean", short: "y", description: "Skip the confirmation (required without a terminal or with --json)" }
|
|
685
704
|
};
|
|
686
|
-
function sameCommand() {
|
|
687
|
-
const
|
|
688
|
-
return `easybits ${
|
|
705
|
+
function sameCommand(argv2 = process.argv.slice(2)) {
|
|
706
|
+
const quoted = argv2.map((a) => /^[\w@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`);
|
|
707
|
+
return `easybits ${quoted.join(" ")}`;
|
|
708
|
+
}
|
|
709
|
+
function applyCommand(argv2, opts) {
|
|
710
|
+
const rest = argv2.filter((a) => a !== "--dry-run");
|
|
711
|
+
const hasYes = rest.some((a) => a === "--yes" || a === "-y");
|
|
712
|
+
return `${sameCommand(rest)}${opts.needsYes && opts.headless && !hasYes ? " --yes" : ""}`;
|
|
713
|
+
}
|
|
714
|
+
function applyHint(ctx, opts = {}) {
|
|
715
|
+
const cmd = applyCommand(process.argv.slice(2), { headless: !interactive(ctx), needsYes: opts.needsYes });
|
|
716
|
+
return t(`To apply: ${cmd}`, `Para aplicarlo: ${cmd}`);
|
|
689
717
|
}
|
|
690
718
|
async function ask(question) {
|
|
691
719
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -2138,6 +2166,7 @@ var set = {
|
|
|
2138
2166
|
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
2167
|
for (const [k, v] of Object.entries(changes)) console.log(`${k}: ${v.from} \u2192 ${v.to}`);
|
|
2140
2168
|
console.log(t("(dry run: nothing changed)", "(simulaci\xF3n: no cambi\xF3 nada)"));
|
|
2169
|
+
console.log(applyHint(ctx));
|
|
2141
2170
|
});
|
|
2142
2171
|
return;
|
|
2143
2172
|
}
|
|
@@ -2204,6 +2233,7 @@ var files2 = {
|
|
|
2204
2233
|
emit(ctx, { agentId: id, dryRun: true, upload: plan }, () => {
|
|
2205
2234
|
for (const p of plan) console.log(`${p.local} \u2192 ${WORK_DIR}/${p.path} (${fmtBytes(p.bytes)})`);
|
|
2206
2235
|
console.log(t("(dry run: nothing uploaded)", "(simulaci\xF3n: no se subi\xF3 nada)"));
|
|
2236
|
+
console.log(applyHint(ctx));
|
|
2207
2237
|
});
|
|
2208
2238
|
return;
|
|
2209
2239
|
}
|
|
@@ -2220,6 +2250,7 @@ var files2 = {
|
|
|
2220
2250
|
if (bool(ctx, "dry-run")) {
|
|
2221
2251
|
emit(ctx, { agentId: id, dryRun: true, delete: rest }, () => {
|
|
2222
2252
|
for (const p of rest) console.log(`${t("would delete", "borrar\xEDa")} ${WORK_DIR}/${p}`);
|
|
2253
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2223
2254
|
});
|
|
2224
2255
|
return;
|
|
2225
2256
|
}
|
|
@@ -2312,9 +2343,12 @@ var skills = {
|
|
|
2312
2343
|
const assets = dir ? readSkillDir(dir) : [];
|
|
2313
2344
|
const plan = { agentId: id, slug, files: ["SKILL.md", ...assets.map((a) => a.name)], restart: bool(ctx, "restart") };
|
|
2314
2345
|
if (bool(ctx, "dry-run")) {
|
|
2315
|
-
emit(ctx, { ...plan, dryRun: true }, () =>
|
|
2346
|
+
emit(ctx, { ...plan, dryRun: true }, () => {
|
|
2347
|
+
console.log(t(`would add skill ${slug} (${plan.files.length} file(s))${plan.restart ? " and restart" : ""}
|
|
2316
2348
|
(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)`))
|
|
2349
|
+
(simulaci\xF3n: no cambi\xF3 nada)`));
|
|
2350
|
+
console.log(applyHint(ctx));
|
|
2351
|
+
});
|
|
2318
2352
|
return;
|
|
2319
2353
|
}
|
|
2320
2354
|
const r = await api(ctx, "PUT", `/agents/${id}/skills/${slug}`, { markdown, assets });
|
|
@@ -2327,7 +2361,10 @@ var skills = {
|
|
|
2327
2361
|
const slugs = ctx.args.slice(2);
|
|
2328
2362
|
if (!slugs.length) throw usageError(t("Give one or more slugs.", "Pasa uno o m\xE1s slugs."), SKILLS_USAGE);
|
|
2329
2363
|
if (bool(ctx, "dry-run")) {
|
|
2330
|
-
emit(ctx, { agentId: id, dryRun: true, delete: slugs }, () =>
|
|
2364
|
+
emit(ctx, { agentId: id, dryRun: true, delete: slugs }, () => {
|
|
2365
|
+
slugs.forEach((s) => console.log(`${t("would remove skill", "quitar\xEDa la skill")} ${s}`));
|
|
2366
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2367
|
+
});
|
|
2331
2368
|
return;
|
|
2332
2369
|
}
|
|
2333
2370
|
requireYesIfHeadless(ctx);
|
|
@@ -2391,6 +2428,7 @@ var mcp2 = {
|
|
|
2391
2428
|
removed: ${diff.removed.join(", ") || "-"}
|
|
2392
2429
|
changed: ${diff.changed.join(", ") || "-"}`);
|
|
2393
2430
|
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)"));
|
|
2431
|
+
console.log(applyHint(ctx));
|
|
2394
2432
|
});
|
|
2395
2433
|
return;
|
|
2396
2434
|
}
|
|
@@ -2720,6 +2758,7 @@ var db = {
|
|
|
2720
2758
|
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
2759
|
for (const x of tables) console.log(` ${x.name}: ${x.rows}`);
|
|
2722
2760
|
console.log(t("(dry run: nothing deleted)", "(simulaci\xF3n: no se borr\xF3 nada)"));
|
|
2761
|
+
console.log(applyHint(ctx, { needsYes: true }));
|
|
2723
2762
|
});
|
|
2724
2763
|
return;
|
|
2725
2764
|
}
|
|
@@ -2773,6 +2812,7 @@ var db = {
|
|
|
2773
2812
|
console.log(`${from} \u2192 ${to}`);
|
|
2774
2813
|
printRefs();
|
|
2775
2814
|
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)"));
|
|
2815
|
+
console.log(applyHint(ctx));
|
|
2776
2816
|
});
|
|
2777
2817
|
return;
|
|
2778
2818
|
}
|
|
@@ -3115,6 +3155,7 @@ async function applyTarget(ctx, target, o) {
|
|
|
3115
3155
|
for (const s of Object.keys(uploads.skills ?? {})) console.log(`+ skill ${s}`);
|
|
3116
3156
|
for (const f of Object.keys(uploads.files ?? {})) console.log(`+ file ${f}`);
|
|
3117
3157
|
console.log(t("(dry run: nothing created)", "(simulaci\xF3n: no se cre\xF3 nada)"));
|
|
3158
|
+
console.log(applyHint(ctx));
|
|
3118
3159
|
});
|
|
3119
3160
|
return;
|
|
3120
3161
|
}
|
|
@@ -3155,6 +3196,7 @@ async function applyTarget(ctx, target, o) {
|
|
|
3155
3196
|
console.log(
|
|
3156
3197
|
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
3198
|
);
|
|
3199
|
+
if (o.dryRun && actionable.length) console.log(applyHint(ctx, { needsYes: true }));
|
|
3158
3200
|
});
|
|
3159
3201
|
return;
|
|
3160
3202
|
}
|
|
@@ -3320,6 +3362,7 @@ var agents = {
|
|
|
3320
3362
|
for (const [k, v] of Object.entries(plan)) console.log(`${k.padEnd(12)} ${Array.isArray(v) ? v.join(", ") || "-" : v ?? "-"}`);
|
|
3321
3363
|
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
3364
|
console.log(t("(dry run: nothing created)", "(simulaci\xF3n: no se cre\xF3 nada)"));
|
|
3365
|
+
console.log(applyHint(ctx));
|
|
3323
3366
|
});
|
|
3324
3367
|
return;
|
|
3325
3368
|
}
|
|
@@ -3575,7 +3618,7 @@ import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync
|
|
|
3575
3618
|
import { homedir as homedir5 } from "os";
|
|
3576
3619
|
import { dirname as dirname4, join as join8 } from "path";
|
|
3577
3620
|
var FILE = join8(process.env.XDG_CONFIG_HOME || join8(homedir5(), ".config"), "easybits", "update.json");
|
|
3578
|
-
var
|
|
3621
|
+
var TTL = 60 * 60 * 1e3;
|
|
3579
3622
|
var UPGRADE = "npm i -g @easybits.cloud/cli@latest";
|
|
3580
3623
|
function newer(a, b) {
|
|
3581
3624
|
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -3603,10 +3646,14 @@ async function fetchLatest(timeoutMs = 1500) {
|
|
|
3603
3646
|
return null;
|
|
3604
3647
|
}
|
|
3605
3648
|
}
|
|
3606
|
-
|
|
3649
|
+
function cacheFresh(c, current2, now = Date.now()) {
|
|
3650
|
+
if (!c.latest || !c.checkedAt || now - c.checkedAt >= TTL) return false;
|
|
3651
|
+
return !(current2 && current2 !== "dev" && newer(current2, c.latest));
|
|
3652
|
+
}
|
|
3653
|
+
async function latestVersion(current2) {
|
|
3607
3654
|
if (updateCheckDisabled()) return null;
|
|
3608
3655
|
const c = readCache();
|
|
3609
|
-
if (
|
|
3656
|
+
if (cacheFresh(c, current2)) return c.latest;
|
|
3610
3657
|
return await fetchLatest() ?? c.latest ?? null;
|
|
3611
3658
|
}
|
|
3612
3659
|
function cachedNewer(current2) {
|
|
@@ -3616,12 +3663,12 @@ function cachedNewer(current2) {
|
|
|
3616
3663
|
}
|
|
3617
3664
|
async function updateNotice(current2) {
|
|
3618
3665
|
if (current2 === "dev") return null;
|
|
3619
|
-
const latest = await latestVersion();
|
|
3666
|
+
const latest = await latestVersion(current2);
|
|
3620
3667
|
return latest && newer(latest, current2) ? t(`Update available: ${current2} \u2192 ${latest}. Run: ${UPGRADE}`, `Hay versi\xF3n nueva: ${current2} \u2192 ${latest}. Corre: ${UPGRADE}`) : null;
|
|
3621
3668
|
}
|
|
3622
3669
|
|
|
3623
3670
|
// src/commands/doctor.ts
|
|
3624
|
-
var VERSION = true ? "0.15.
|
|
3671
|
+
var VERSION = true ? "0.15.1" : "dev";
|
|
3625
3672
|
var doctor2 = {
|
|
3626
3673
|
name: "doctor",
|
|
3627
3674
|
group: "Account",
|
|
@@ -4125,7 +4172,7 @@ function normalizeArgs(input) {
|
|
|
4125
4172
|
}
|
|
4126
4173
|
|
|
4127
4174
|
// src/index.ts
|
|
4128
|
-
var VERSION2 = true ? "0.15.
|
|
4175
|
+
var VERSION2 = true ? "0.15.1" : "dev";
|
|
4129
4176
|
var GLOBAL_OPTIONS = {
|
|
4130
4177
|
json: { type: "boolean" },
|
|
4131
4178
|
token: { type: "string" },
|
package/package.json
CHANGED