@erdoai/cli 0.30.0 → 0.31.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.
Files changed (2) hide show
  1. package/dist/index.js +62 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -203,6 +203,16 @@ var ErdoClient = class {
203
203
  listOrganizations() {
204
204
  return this.request("GET", "/v1/organizations");
205
205
  }
206
+ // --- API tokens (user credentials; default_org is only the header-absent fallback) ---
207
+ createToken(input) {
208
+ return this.request("POST", "/v1/tokens", input);
209
+ }
210
+ listTokens() {
211
+ return this.request("GET", "/v1/tokens");
212
+ }
213
+ revokeToken(id) {
214
+ return this.request("DELETE", `/v1/tokens/${encodeURIComponent(id)}`);
215
+ }
206
216
  getAutonomyMode() {
207
217
  return this.request("GET", "/v1/autonomy-mode");
208
218
  }
@@ -1166,6 +1176,55 @@ org.command("autonomy [mode]").description("Show or set the org's engine-autonom
1166
1176
  fail(e);
1167
1177
  }
1168
1178
  });
1179
+ var tokenCmd = program.command("token").description("Manage your API tokens (account-level credentials)");
1180
+ tokenCmd.command("create").description("Mint a new API token; the secret is printed ONCE").requiredOption("--name <name>", "a label for the token").option("--expires-days <n>", "days until expiry (default: 30)", (v) => parseInt(v, 10)).option("--org <idOrSlug>", "the token's default org (defaults to your active org; must be one you belong to)").action(async (opts) => {
1181
+ try {
1182
+ const res = await new ErdoClient().createToken({
1183
+ name: opts.name,
1184
+ expires_in_days: opts.expiresDays ?? 30,
1185
+ organization_id: opts.org
1186
+ });
1187
+ process.stderr.write(
1188
+ "Store this token now \u2014 it is shown only once and cannot be retrieved again.\n"
1189
+ );
1190
+ console.log(res.token);
1191
+ process.stderr.write(
1192
+ `
1193
+ id: ${res.id}
1194
+ hint: ${res.hint}
1195
+ expires: ${res.expires_at}
1196
+ default org: ${res.default_org ? `${res.default_org.name} (${res.default_org.id})` : "(none)"}
1197
+ This token acts as you in any org you belong to; pass --org on a command to target another.
1198
+ `
1199
+ );
1200
+ } catch (e) {
1201
+ fail(e);
1202
+ }
1203
+ });
1204
+ tokenCmd.command("list").description("List your API tokens (never shows the secret)").action(async () => {
1205
+ try {
1206
+ const { tokens } = await new ErdoClient().listTokens();
1207
+ if (tokens.length === 0) {
1208
+ console.log("No API tokens. Create one with: erdo token create --name <name>");
1209
+ return;
1210
+ }
1211
+ for (const t of tokens) {
1212
+ const org2 = t.default_org ? t.default_org.name || t.default_org.id : "-";
1213
+ const used = t.last_used_at ?? "never";
1214
+ console.log(`${t.id} ${t.name || "-"} ${t.hint} default-org:${org2} expires:${t.expires_at} used:${used}`);
1215
+ }
1216
+ } catch (e) {
1217
+ fail(e);
1218
+ }
1219
+ });
1220
+ tokenCmd.command("revoke <id>").description("Revoke an API token by id").action(async (id) => {
1221
+ try {
1222
+ await new ErdoClient().revokeToken(id);
1223
+ console.log(`revoked: ${id}`);
1224
+ } catch (e) {
1225
+ fail(e);
1226
+ }
1227
+ });
1169
1228
  var evalCmd = program.command("eval").description("Run and manage evals");
1170
1229
  evalCmd.command("suites").description("List eval suites in the active org (+ global)").action(async () => {
1171
1230
  try {
@@ -2387,11 +2446,11 @@ analytics.command("query <hogql>").description("Run a read-only HogQL query agai
2387
2446
  fail(e);
2388
2447
  }
2389
2448
  });
2390
- var OPERATORS = ["equals", "not_equals", "greater_than", "less_than", "contains", "between"];
2449
+ var OPERATORS = ["equals", "not_equals", "greater_than", "less_than", "contains", "not_contains", "between"];
2391
2450
  function parseCondition(s) {
2392
2451
  const m = s.trim().match(/^(\S+)\s+(\S+)\s+([\s\S]+)$/);
2393
2452
  if (!m) {
2394
- fail(new Error(`invalid --where ${JSON.stringify(s)}; expected '<column> <operator> <value>', e.g. 'email contains @example.com'`));
2453
+ fail(new Error(`invalid --where ${JSON.stringify(s)}; expected '<column> <operator> <value>', e.g. 'email not_contains @example.com'`));
2395
2454
  }
2396
2455
  const [, column, operator, value] = m;
2397
2456
  if (!OPERATORS.includes(operator)) {
@@ -2486,7 +2545,7 @@ pipelinesCmd.command("get <slug>").description("Show one event pipeline \u2014 s
2486
2545
  });
2487
2546
  filterCmd.command("add <slug>").description("Add a filter to a dataset (default-on unless --no-default)").requiredOption(
2488
2547
  "--where <condition>",
2489
- "a '<column> <operator> <value>' condition (repeatable, AND-combined), e.g. --where 'email contains @example.com'. Operators: " + OPERATORS.join(", ") + " (for 'between' use 'col between 10,100')",
2548
+ "a '<column> <operator> <value>' condition (repeatable, AND-combined). A filter KEEPS matching rows, so exclude by matching what you want to keep: --where 'email not_contains @example.com' (label 'Exclude test submissions') hides the test rows; --where 'email contains @acme.com' would keep ONLY @acme.com rows. Operators: " + OPERATORS.join(", ") + " (for 'between' use 'col between 10,100')",
2490
2549
  collect,
2491
2550
  []
2492
2551
  ).option("--name <name>", "optional human-readable label, e.g. 'Exclude test submissions'").option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erdoai/cli",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "Erdo CLI \u2014 drive datasets, pages, and evals from the terminal or CI",
5
5
  "type": "module",
6
6
  "bin": {