@erdoai/cli 0.33.0 → 0.35.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 +168 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -241,6 +241,25 @@ var ErdoClient = class {
|
|
|
241
241
|
setAutonomyMode(mode) {
|
|
242
242
|
return this.request("PUT", "/v1/autonomy-mode", { mode });
|
|
243
243
|
}
|
|
244
|
+
// --- Manager accounts: operate many client (managed) orgs with ONE manager key ---
|
|
245
|
+
// The manager is your active org; you must be an admin/owner of it. A managed org
|
|
246
|
+
// is a client tenant you provision and operate. The manager key (createManagerKey)
|
|
247
|
+
// is a single credential that acts inside any managed org via X-Organization-ID.
|
|
248
|
+
listManagedOrganizations() {
|
|
249
|
+
return this.request("GET", "/v1/managed-organizations");
|
|
250
|
+
}
|
|
251
|
+
createManagedOrganization(input) {
|
|
252
|
+
return this.request("POST", "/v1/managed-organizations", input);
|
|
253
|
+
}
|
|
254
|
+
revokeManagedOrganization(slug) {
|
|
255
|
+
return this.request(
|
|
256
|
+
"DELETE",
|
|
257
|
+
`/v1/managed-organizations/${encodeURIComponent(slug)}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
createManagerKey() {
|
|
261
|
+
return this.request("POST", "/v1/manager-key");
|
|
262
|
+
}
|
|
244
263
|
// Run a read-only HogQL query against the org's page-analytics events. Rows are
|
|
245
264
|
// positional per columns; enabled:false means page analytics is off for the org
|
|
246
265
|
// (not zero traffic). A rejected query surfaces PostHog's message as the error.
|
|
@@ -488,6 +507,22 @@ var ErdoClient = class {
|
|
|
488
507
|
input
|
|
489
508
|
);
|
|
490
509
|
}
|
|
510
|
+
// --- activity feed ---
|
|
511
|
+
// The unified, ranked, read-only feed: attention items, approvals, workstream
|
|
512
|
+
// events, catalog updates, and urgent cause-clusters. Respond via
|
|
513
|
+
// respondAttentionItem / decideApproval — this is a view only.
|
|
514
|
+
listActivityFeed(params) {
|
|
515
|
+
const q = new URLSearchParams();
|
|
516
|
+
if (params?.limit) q.set("limit", String(params.limit));
|
|
517
|
+
if (params?.offset) q.set("offset", String(params.offset));
|
|
518
|
+
if (params?.categories) q.set("categories", params.categories);
|
|
519
|
+
if (params?.scope) q.set("scope", params.scope);
|
|
520
|
+
const qs = q.toString();
|
|
521
|
+
return this.request(
|
|
522
|
+
"GET",
|
|
523
|
+
`/v1/activity/feed${qs ? `?${qs}` : ""}`
|
|
524
|
+
);
|
|
525
|
+
}
|
|
491
526
|
// --- knowledge review queue ---
|
|
492
527
|
listReviewItems(params) {
|
|
493
528
|
const q = new URLSearchParams();
|
|
@@ -752,9 +787,11 @@ var ErdoClient = class {
|
|
|
752
787
|
return this.request("POST", "/v1/pages", input);
|
|
753
788
|
}
|
|
754
789
|
// Start a review of external page URLs with the real landing critic; returns a
|
|
755
|
-
// review id immediately (poll getPageReview for the typed findings).
|
|
756
|
-
|
|
757
|
-
|
|
790
|
+
// review id immediately (poll getPageReview for the typed findings). goal is
|
|
791
|
+
// the operator's optional declared campaign goal — it steers which conversion
|
|
792
|
+
// principles apply, and a page whose evident form contradicts it is a finding.
|
|
793
|
+
reviewPages(urls, goal) {
|
|
794
|
+
return this.request("POST", "/v1/page-reviews", goal ? { urls, goal } : { urls });
|
|
758
795
|
}
|
|
759
796
|
getPageReview(id) {
|
|
760
797
|
return this.request("GET", `/v1/page-reviews/${encodeURIComponent(id)}`);
|
|
@@ -1221,6 +1258,61 @@ org.command("autonomy [mode]").description("Show or set the org's engine-autonom
|
|
|
1221
1258
|
fail(e);
|
|
1222
1259
|
}
|
|
1223
1260
|
});
|
|
1261
|
+
var managed = org.command("managed").description("Operate client orgs via a manager account");
|
|
1262
|
+
managed.command("list").description("List the client orgs your org manages").action(async () => {
|
|
1263
|
+
try {
|
|
1264
|
+
const { organizations } = await new ErdoClient().listManagedOrganizations();
|
|
1265
|
+
if (organizations.length === 0) {
|
|
1266
|
+
console.log("No managed orgs. Create one with: erdo org managed create --name <name>");
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
for (const o of organizations) {
|
|
1270
|
+
console.log(`${o.slug || "-"} ${o.name} ${o.role} ${o.id}`);
|
|
1271
|
+
}
|
|
1272
|
+
} catch (e) {
|
|
1273
|
+
fail(e);
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
managed.command("create").description("Provision a new client org managed by your org").requiredOption("--name <name>", "display name for the new managed org").option("--slug <slug>", "desired slug (a unique suffix is appended if it collides)").action(async (opts) => {
|
|
1277
|
+
try {
|
|
1278
|
+
const o = await new ErdoClient().createManagedOrganization({ name: opts.name, slug: opts.slug });
|
|
1279
|
+
console.log(`Created managed org: ${o.name}`);
|
|
1280
|
+
console.log(`slug: ${o.slug}
|
|
1281
|
+
id: ${o.id}`);
|
|
1282
|
+
process.stderr.write(
|
|
1283
|
+
`Operate it with the manager key by passing --org ${o.slug} on any command (e.g. erdo --org ${o.slug} datasets list).
|
|
1284
|
+
`
|
|
1285
|
+
);
|
|
1286
|
+
} catch (e) {
|
|
1287
|
+
fail(e);
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
managed.command("revoke <slug>").description("Stop managing a client org (removes access; keeps an audit record)").action(async (slug) => {
|
|
1291
|
+
try {
|
|
1292
|
+
await new ErdoClient().revokeManagedOrganization(slug);
|
|
1293
|
+
console.log(`revoked: ${slug}`);
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
fail(e);
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
managed.command("key").description("Mint (or rotate) your manager key \u2014 one credential for every managed org; shown ONCE").action(async () => {
|
|
1299
|
+
try {
|
|
1300
|
+
const res = await new ErdoClient().createManagerKey();
|
|
1301
|
+
process.stderr.write(
|
|
1302
|
+
"Store this manager key now \u2014 it is shown only once and cannot be retrieved again.\n"
|
|
1303
|
+
);
|
|
1304
|
+
console.log(res.token);
|
|
1305
|
+
process.stderr.write(
|
|
1306
|
+
`
|
|
1307
|
+
token id: ${res.token_id}
|
|
1308
|
+
expires: ${res.expires_at}
|
|
1309
|
+
This key operates every org you manage; target one with X-Organization-ID (or \`erdo --org <slug> \u2026\`). Running this again rotates the key.
|
|
1310
|
+
`
|
|
1311
|
+
);
|
|
1312
|
+
} catch (e) {
|
|
1313
|
+
fail(e);
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1224
1316
|
var tokenCmd = program.command("token").description("Manage your API tokens (account-level credentials)");
|
|
1225
1317
|
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) => {
|
|
1226
1318
|
try {
|
|
@@ -2224,6 +2316,74 @@ attnCmd.command("respond <id>").description(
|
|
|
2224
2316
|
}
|
|
2225
2317
|
}
|
|
2226
2318
|
);
|
|
2319
|
+
function activityLine(it) {
|
|
2320
|
+
const handle = it.slug || it.id;
|
|
2321
|
+
const parts = [it.title || it.type];
|
|
2322
|
+
if (it.summary && it.summary !== it.title) {
|
|
2323
|
+
const s = it.summary.replace(/\s+/g, " ").trim();
|
|
2324
|
+
parts.push(`\u2014 ${s.length > 80 ? `${s.slice(0, 79)}\u2026` : s}`);
|
|
2325
|
+
}
|
|
2326
|
+
return ` ${handle} ${parts.join(" ")}`;
|
|
2327
|
+
}
|
|
2328
|
+
function activityAction(it) {
|
|
2329
|
+
if (it.type === "approval_request") return `erdo approvals decide ${it.id} --approve|--reject`;
|
|
2330
|
+
return `erdo attention respond ${it.slug || it.id}`;
|
|
2331
|
+
}
|
|
2332
|
+
function renderActivityFeed(feed) {
|
|
2333
|
+
const items = feed.items ?? [];
|
|
2334
|
+
const needs = items.filter((it) => it.needs_action);
|
|
2335
|
+
if (needs.length > 0) {
|
|
2336
|
+
console.log("NEEDS YOU");
|
|
2337
|
+
for (const it of needs) {
|
|
2338
|
+
const sev = it.severity ? `[${it.severity}] ` : "";
|
|
2339
|
+
console.log(` ${sev}${it.title || it.type}`);
|
|
2340
|
+
console.log(` ${activityAction(it)}`);
|
|
2341
|
+
}
|
|
2342
|
+
console.log("");
|
|
2343
|
+
}
|
|
2344
|
+
const clusters = feed.urgent_clusters ?? [];
|
|
2345
|
+
if (clusters.length > 0) {
|
|
2346
|
+
console.log("URGENT");
|
|
2347
|
+
if (feed.flood_summary) console.log(` ${feed.flood_summary}`);
|
|
2348
|
+
for (const c of clusters) console.log(` \u2022 ${c.summary} (${c.count})`);
|
|
2349
|
+
console.log("");
|
|
2350
|
+
}
|
|
2351
|
+
const rest = items.filter((it) => !it.needs_action && !it.clustered);
|
|
2352
|
+
if (rest.length > 0) {
|
|
2353
|
+
console.log("RECENT");
|
|
2354
|
+
for (const it of rest) console.log(activityLine(it));
|
|
2355
|
+
console.log("");
|
|
2356
|
+
}
|
|
2357
|
+
if (needs.length === 0 && clusters.length === 0 && rest.length === 0) {
|
|
2358
|
+
console.log("Nothing in the feed.");
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2361
|
+
console.log(`${items.length} shown \xB7 ${feed.total} total`);
|
|
2362
|
+
}
|
|
2363
|
+
program.command("activity").alias("feed").description(
|
|
2364
|
+
"The unified activity feed \u2014 needs-you items first, then urgent cause-clusters, then recent activity. Read-only: respond with `erdo attention respond` / `erdo approvals decide`."
|
|
2365
|
+
).option("-n, --limit <n>", "max items (default 20, max 100)", (v) => parseInt(v, 10)).option("--offset <n>", "pagination offset", (v) => parseInt(v, 10)).option(
|
|
2366
|
+
"--categories <list>",
|
|
2367
|
+
"comma-separated: attention,approval,workstream,catalog,job,heartbeat (default excludes runs)"
|
|
2368
|
+
).option("--scope <scope>", "following | all (default all)").option("--json", "raw JSON response").action(
|
|
2369
|
+
async (opts) => {
|
|
2370
|
+
try {
|
|
2371
|
+
const feed = await new ErdoClient().listActivityFeed({
|
|
2372
|
+
limit: opts.limit,
|
|
2373
|
+
offset: opts.offset,
|
|
2374
|
+
categories: opts.categories,
|
|
2375
|
+
scope: opts.scope
|
|
2376
|
+
});
|
|
2377
|
+
if (opts.json) {
|
|
2378
|
+
print(feed);
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
renderActivityFeed(feed);
|
|
2382
|
+
} catch (e) {
|
|
2383
|
+
fail(e);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
);
|
|
2227
2387
|
var reviewsCmd = program.command("reviews").description(
|
|
2228
2388
|
"The Knowledge Review queue \u2014 knowledge patches the critic proposes, investigations, and deduplicated failure signals awaiting a human decision"
|
|
2229
2389
|
);
|
|
@@ -2399,10 +2559,13 @@ pagesCmd.command("get <id>").description("Show an artifact").action(async (id) =
|
|
|
2399
2559
|
});
|
|
2400
2560
|
pagesCmd.command("review <url...>").description(
|
|
2401
2561
|
"Review external landing page URLs with Erdo's real conversion critic \u2014 typed defects (severity, issue, why it costs conversions, evidence, fix) plus strengths, judged from fold + full-page captures on desktop and mobile. Returns a review id; use --wait to poll and print the findings."
|
|
2402
|
-
).option("--wait", "poll until the review is ready, then print the findings").
|
|
2562
|
+
).option("--wait", "poll until the review is ready, then print the findings").option(
|
|
2563
|
+
"--goal <goal>",
|
|
2564
|
+
"what the page's campaign is trying to achieve ('book demos', 'brand awareness for a launch') \u2014 steers which conversion principles apply; a page whose evident form contradicts the goal is itself a finding"
|
|
2565
|
+
).action(async (urls, opts) => {
|
|
2403
2566
|
try {
|
|
2404
2567
|
const client = new ErdoClient();
|
|
2405
|
-
const started = await client.reviewPages(urls);
|
|
2568
|
+
const started = await client.reviewPages(urls, opts.goal);
|
|
2406
2569
|
if (!opts.wait) {
|
|
2407
2570
|
print(started);
|
|
2408
2571
|
return;
|