@erdoai/cli 0.4.0 → 0.5.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/dist/index.js +56 -28
- package/package.json +1 -1
- package/scripts/postinstall.mjs +22 -2
package/dist/index.js
CHANGED
|
@@ -293,26 +293,32 @@ var ErdoClient = class {
|
|
|
293
293
|
runHeartbeat(id) {
|
|
294
294
|
return this.request("POST", `/v1/heartbeats/${encodeURIComponent(id)}/run`, {});
|
|
295
295
|
}
|
|
296
|
-
// --- collections ---
|
|
297
|
-
|
|
298
|
-
return this.request("GET", "/v1/
|
|
296
|
+
// --- kv (named key/value stores, a.k.a. collections) ---
|
|
297
|
+
listKVStores() {
|
|
298
|
+
return this.request("GET", "/v1/kv");
|
|
299
299
|
}
|
|
300
|
-
|
|
301
|
-
return this.request("POST", "/v1/
|
|
300
|
+
createKVStore(slug) {
|
|
301
|
+
return this.request("POST", "/v1/kv", { slug });
|
|
302
302
|
}
|
|
303
|
-
|
|
303
|
+
getKVItem(slug, key) {
|
|
304
304
|
return this.request(
|
|
305
305
|
"GET",
|
|
306
|
-
`/v1/
|
|
306
|
+
`/v1/kv/${encodeURIComponent(slug)}/items/${encodeURIComponent(key)}`
|
|
307
307
|
);
|
|
308
308
|
}
|
|
309
|
-
|
|
309
|
+
setKVItem(slug, key, value) {
|
|
310
310
|
return this.request(
|
|
311
311
|
"PUT",
|
|
312
|
-
`/v1/
|
|
312
|
+
`/v1/kv/${encodeURIComponent(slug)}/items/${encodeURIComponent(key)}`,
|
|
313
313
|
{ value }
|
|
314
314
|
);
|
|
315
315
|
}
|
|
316
|
+
deleteKVItem(slug, key) {
|
|
317
|
+
return this.request(
|
|
318
|
+
"DELETE",
|
|
319
|
+
`/v1/kv/${encodeURIComponent(slug)}/items/${encodeURIComponent(key)}`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
316
322
|
// --- agent runs ---
|
|
317
323
|
listAgentRuns(opts) {
|
|
318
324
|
const params = new URLSearchParams();
|
|
@@ -438,19 +444,30 @@ async function browserLogin() {
|
|
|
438
444
|
import { spawnSync } from "child_process";
|
|
439
445
|
var PKG = "@erdoai/cli";
|
|
440
446
|
var MANUAL_HINT = `npm install -g ${PKG}@latest`;
|
|
447
|
+
function parseVersion(v) {
|
|
448
|
+
const [core, pre = ""] = v.split("-", 2);
|
|
449
|
+
const nums = core.split(".").map((s) => Number.parseInt(s, 10) || 0);
|
|
450
|
+
return { nums, pre };
|
|
451
|
+
}
|
|
441
452
|
function isNewer(latest, current) {
|
|
442
|
-
const a = latest
|
|
443
|
-
const b = current
|
|
453
|
+
const a = parseVersion(latest);
|
|
454
|
+
const b = parseVersion(current);
|
|
444
455
|
for (let i = 0; i < 3; i++) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
456
|
+
const x = a.nums[i] ?? 0;
|
|
457
|
+
const y = b.nums[i] ?? 0;
|
|
458
|
+
if (x > y) return true;
|
|
459
|
+
if (x < y) return false;
|
|
460
|
+
}
|
|
461
|
+
if (!a.pre && b.pre) return true;
|
|
462
|
+
if (a.pre && !b.pre) return false;
|
|
463
|
+
return a.pre > b.pre;
|
|
449
464
|
}
|
|
450
465
|
async function update(current) {
|
|
451
466
|
let latest;
|
|
452
467
|
try {
|
|
453
|
-
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest
|
|
468
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, {
|
|
469
|
+
signal: AbortSignal.timeout(1e4)
|
|
470
|
+
});
|
|
454
471
|
if (res.ok) latest = (await res.json()).version;
|
|
455
472
|
} catch {
|
|
456
473
|
}
|
|
@@ -468,6 +485,10 @@ async function update(current) {
|
|
|
468
485
|
// npm is npm.cmd on Windows; needs a shell to resolve.
|
|
469
486
|
shell: process.platform === "win32"
|
|
470
487
|
});
|
|
488
|
+
if (result.error) {
|
|
489
|
+
console.error(`Update failed: ${result.error.message}. Try manually: ${MANUAL_HINT}`);
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
471
492
|
if (result.status !== 0) {
|
|
472
493
|
console.error(`Update failed. Try manually: ${MANUAL_HINT}`);
|
|
473
494
|
process.exit(result.status ?? 1);
|
|
@@ -945,7 +966,7 @@ function readMaybeFile(v) {
|
|
|
945
966
|
if (!v) return void 0;
|
|
946
967
|
return v.startsWith("@") ? readFileSync2(v.slice(1), "utf8") : v;
|
|
947
968
|
}
|
|
948
|
-
pagesCmd.command("deploy").description("Deploy a page (HTML/React); --html/--js/--css accept @file").requiredOption("--title <title>", "page title").requiredOption("--html <htmlOr@file>", "HTML (or @path to a file)").option("--js <jsOr@file>", "JS/JSX (or @path)").option("--css <cssOr@file>", "CSS (or @path)").option("--runtime <runtime>", "react-tailwind (default) or none").option("--datasets <csv>", "dataset slugs the page reads").option("--writable-datasets <csv>", "dataset slugs the page may write via erdo.insertRows").option("--
|
|
969
|
+
pagesCmd.command("deploy").description("Deploy a page (HTML/React); --html/--js/--css accept @file").requiredOption("--title <title>", "page title").requiredOption("--html <htmlOr@file>", "HTML (or @path to a file)").option("--js <jsOr@file>", "JS/JSX (or @path)").option("--css <cssOr@file>", "CSS (or @path)").option("--runtime <runtime>", "react-tailwind (default) or none").option("--datasets <csv>", "dataset slugs the page reads").option("--writable-datasets <csv>", "dataset slugs the page may write via erdo.insertRows").option("--kv <csv>", "named KV-store slugs the page reads").option("--writable-kv <csv>", "named KV-store slugs the page may write").option("--public", "make the page publicly viewable").action(
|
|
949
970
|
async (opts) => {
|
|
950
971
|
try {
|
|
951
972
|
const csv = (v) => v ? v.split(",").map((s) => s.trim()) : void 0;
|
|
@@ -957,8 +978,8 @@ pagesCmd.command("deploy").description("Deploy a page (HTML/React); --html/--js/
|
|
|
957
978
|
runtime: opts.runtime,
|
|
958
979
|
dataset_slugs: csv(opts.datasets),
|
|
959
980
|
writable_dataset_slugs: csv(opts.writableDatasets),
|
|
960
|
-
|
|
961
|
-
|
|
981
|
+
kv_slugs: csv(opts.kv),
|
|
982
|
+
writable_kv_slugs: csv(opts.writableKv),
|
|
962
983
|
public: !!opts.public
|
|
963
984
|
});
|
|
964
985
|
console.log(`${res.id} ${res.public_url || res.url}`);
|
|
@@ -1044,29 +1065,29 @@ autoCmd.command("run <id>").description("Trigger an automation now").action(asyn
|
|
|
1044
1065
|
fail(e);
|
|
1045
1066
|
}
|
|
1046
1067
|
});
|
|
1047
|
-
var
|
|
1048
|
-
|
|
1068
|
+
var kvCmd = program.command("kv").description("Named key/value stores");
|
|
1069
|
+
kvCmd.command("list").description("List KV stores").action(async () => {
|
|
1049
1070
|
try {
|
|
1050
|
-
print(await new ErdoClient().
|
|
1071
|
+
print(await new ErdoClient().listKVStores());
|
|
1051
1072
|
} catch (e) {
|
|
1052
1073
|
fail(e);
|
|
1053
1074
|
}
|
|
1054
1075
|
});
|
|
1055
|
-
|
|
1076
|
+
kvCmd.command("create <slug>").description("Create a named KV store (slug: lowercase letters, digits, hyphens)").action(async (slug) => {
|
|
1056
1077
|
try {
|
|
1057
|
-
print(await new ErdoClient().
|
|
1078
|
+
print(await new ErdoClient().createKVStore(slug));
|
|
1058
1079
|
} catch (e) {
|
|
1059
1080
|
fail(e);
|
|
1060
1081
|
}
|
|
1061
1082
|
});
|
|
1062
|
-
|
|
1083
|
+
kvCmd.command("get <slug> <key>").description("Get a KV item").action(async (slug, key) => {
|
|
1063
1084
|
try {
|
|
1064
|
-
print(await new ErdoClient().
|
|
1085
|
+
print(await new ErdoClient().getKVItem(slug, key));
|
|
1065
1086
|
} catch (e) {
|
|
1066
1087
|
fail(e);
|
|
1067
1088
|
}
|
|
1068
1089
|
});
|
|
1069
|
-
|
|
1090
|
+
kvCmd.command("set <slug> <key> <jsonValue>").description("Set a KV item (value is parsed as JSON, else stored as string)").action(async (slug, key, jsonValue) => {
|
|
1070
1091
|
try {
|
|
1071
1092
|
let value;
|
|
1072
1093
|
try {
|
|
@@ -1074,7 +1095,14 @@ collCmd.command("set <slug> <key> <jsonValue>").description("Set a collection it
|
|
|
1074
1095
|
} catch {
|
|
1075
1096
|
value = jsonValue;
|
|
1076
1097
|
}
|
|
1077
|
-
print(await new ErdoClient().
|
|
1098
|
+
print(await new ErdoClient().setKVItem(slug, key, value));
|
|
1099
|
+
} catch (e) {
|
|
1100
|
+
fail(e);
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
kvCmd.command("delete <slug> <key>").description("Delete a KV item").action(async (slug, key) => {
|
|
1104
|
+
try {
|
|
1105
|
+
print(await new ErdoClient().deleteKVItem(slug, key));
|
|
1078
1106
|
} catch (e) {
|
|
1079
1107
|
fail(e);
|
|
1080
1108
|
}
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
// Friendly getting-started hint, printed once after `npm install -g @erdoai/cli`.
|
|
2
2
|
// Stays quiet in CI and non-interactive installs (and never fails the install).
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
4
6
|
|
|
5
7
|
try {
|
|
6
8
|
// In our own source checkout the package ships `dist` + this script but never
|
|
7
9
|
// `src`, so a sibling `src/` means this is a dev `npm install` — stay quiet.
|
|
8
10
|
const devCheckout = existsSync(new URL("../src", import.meta.url));
|
|
9
11
|
|
|
12
|
+
// Print once per machine: a sentinel under the CLI's config dir (same dir as
|
|
13
|
+
// config.json) suppresses the banner on later installs — notably the global
|
|
14
|
+
// reinstall `erdo update` performs, which would otherwise re-trigger it.
|
|
15
|
+
const configDir = join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "erdo");
|
|
16
|
+
const sentinel = join(configDir, ".welcomed");
|
|
17
|
+
|
|
10
18
|
const quiet =
|
|
11
19
|
devCheckout ||
|
|
20
|
+
// Only greet on a global install — a local/devDependency install must not
|
|
21
|
+
// print the banner or write the sentinel (which would silence the real
|
|
22
|
+
// `npm install -g` welcome later). npm sets this to "true" for `-g`.
|
|
23
|
+
process.env.npm_config_global !== "true" ||
|
|
12
24
|
process.env.CI ||
|
|
13
25
|
process.env.ERDO_NO_POSTINSTALL ||
|
|
14
|
-
!process.stdout.isTTY
|
|
26
|
+
!process.stdout.isTTY ||
|
|
27
|
+
existsSync(sentinel);
|
|
15
28
|
|
|
16
29
|
if (!quiet) {
|
|
30
|
+
try {
|
|
31
|
+
mkdirSync(configDir, { recursive: true });
|
|
32
|
+
writeFileSync(sentinel, "");
|
|
33
|
+
} catch {
|
|
34
|
+
// a read-only home shouldn't suppress the hint or fail the install
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
const c = (code, s) => `\x1b[${code}m${s}\x1b[0m`;
|
|
18
38
|
const b = (s) => c("1", s);
|
|
19
39
|
const dim = (s) => c("2", s);
|