@erdoai/cli 0.65.0 → 0.67.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 +100 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -396,6 +396,22 @@ var ErdoClient = class {
396
396
  `/v1/received-emails${qs ? `?${qs}` : ""}`
397
397
  );
398
398
  }
399
+ // The audited outbound side of email. Listing omits bodies; get reads the
400
+ // exact stored message. The scalar filters use the GET mirror of the same
401
+ // service that backs MCP's erdo_list_emails.
402
+ listSentEmails(params) {
403
+ const q = new URLSearchParams();
404
+ if (params?.to) q.set("to", params.to);
405
+ if (params?.since) q.set("since", params.since);
406
+ if (params?.search) q.set("search", params.search);
407
+ if (params?.limit) q.set("limit", String(params.limit));
408
+ if (params?.offset) q.set("offset", String(params.offset));
409
+ const qs = q.toString();
410
+ return this.request("GET", `/v1/emails${qs ? `?${qs}` : ""}`);
411
+ }
412
+ getSentEmail(emailID) {
413
+ return this.request("GET", `/v1/emails/${encodeURIComponent(emailID)}`);
414
+ }
399
415
  // Run a read-only HogQL query against the org's page-analytics events. Rows are
400
416
  // positional per columns; enabled:false means page analytics is off for the org
401
417
  // (not zero traffic). A rejected query surfaces PostHog's message as the error.
@@ -448,7 +464,7 @@ var ErdoClient = class {
448
464
  `/v1/evals/suites/${encodeURIComponent(slug)}/cases/${encodeURIComponent(caseName)}`
449
465
  );
450
466
  }
451
- runEvalSuite(slug, concurrency, commitSha, frontendCommitSha, backendCommitSha, source, modelOverride) {
467
+ runEvalSuite(slug, concurrency, commitSha, frontendCommitSha, backendCommitSha, source, modelOverride, rotateCases) {
452
468
  return this.request(
453
469
  "POST",
454
470
  `/v1/evals/suites/${encodeURIComponent(slug)}/run`,
@@ -458,7 +474,8 @@ var ErdoClient = class {
458
474
  frontend_commit_sha: frontendCommitSha,
459
475
  backend_commit_sha: backendCommitSha,
460
476
  source,
461
- model_override: modelOverride
477
+ model_override: modelOverride,
478
+ rotate_cases: rotateCases
462
479
  }
463
480
  );
464
481
  }
@@ -514,6 +531,14 @@ var ErdoClient = class {
514
531
  `/v1/pages/restore/${encodeURIComponent(id)}`
515
532
  );
516
533
  }
534
+ // Copy a page: the deploy endpoint's clone mode. clone_from_page_id makes
535
+ // POST /v1/pages copy an existing page server-side instead of taking content.
536
+ clonePage(id, input) {
537
+ return this.request("POST", "/v1/pages", {
538
+ clone_from_page_id: id,
539
+ title: input?.title
540
+ });
541
+ }
517
542
  // --- workstreams ---
518
543
  listWorkstreams(status) {
519
544
  const q = new URLSearchParams();
@@ -2527,7 +2552,13 @@ evalCmd.command("create <name>").description("Create a suite (in the active org)
2527
2552
  }
2528
2553
  }
2529
2554
  );
2530
- evalCmd.command("run <slug>").description("Run a suite; --watch polls until it completes").option("-w, --watch", "poll until the run finishes and print results").option("-c, --concurrency <n>", "parallel cases", (v) => parseInt(v, 10)).option("--commit-sha <sha>", "full 40-character Git commit SHA to associate with the run").option("--frontend-commit-sha <sha>", "frontend revision in the evaluated production snapshot").option("--backend-commit-sha <sha>", "backend revision in the evaluated production snapshot").option("--source <source>", "staff-only run source: post_deploy, nightly, or rollback").option("--model <model>", "pin the suite's agent to a model for this run (e.g. glm-5.3) \u2014 for model comparisons").action(async (slug, opts) => {
2555
+ evalCmd.command("run <slug>").description("Run a suite; --watch polls until it completes").option("-w, --watch", "poll until the run finishes and print results").option("-c, --concurrency <n>", "parallel cases", (v) => parseInt(v, 10)).option("--commit-sha <sha>", "full 40-character Git commit SHA to associate with the run").option("--frontend-commit-sha <sha>", "frontend revision in the evaluated production snapshot").option("--backend-commit-sha <sha>", "backend revision in the evaluated production snapshot").option("--source <source>", "staff-only run source: post_deploy, nightly, or rollback").option("--model <model>", "pin the suite's agent to a model for this run (e.g. glm-5.3) \u2014 for model comparisons").option("--rotate-cases <n>", "run a rotating subset of n cases (deterministic per suite + UTC day) instead of all cases", (v) => {
2556
+ const parsed = parseInt(v, 10);
2557
+ if (isNaN(parsed) || parsed < 0) {
2558
+ throw new Error(`--rotate-cases must be a non-negative integer, got "${v}"`);
2559
+ }
2560
+ return parsed;
2561
+ }).action(async (slug, opts) => {
2531
2562
  try {
2532
2563
  const api = new ErdoClient();
2533
2564
  const { suite } = await api.getEvalSuite(slug);
@@ -2550,7 +2581,8 @@ evalCmd.command("run <slug>").description("Run a suite; --watch polls until it c
2550
2581
  opts.frontendCommitSha,
2551
2582
  opts.backendCommitSha,
2552
2583
  opts.source,
2553
- opts.model
2584
+ opts.model,
2585
+ opts.rotateCases
2554
2586
  );
2555
2587
  console.log(`run_id: ${run_id}`);
2556
2588
  if (!opts.watch) return;
@@ -3807,6 +3839,24 @@ pagesCmd.command("restore <id>").description("Restore a previously deleted page
3807
3839
  fail(e);
3808
3840
  }
3809
3841
  });
3842
+ pagesCmd.command("clone <id>").description(
3843
+ "Copy a page. The copy is byte-identical and starts private (publish state is never inherited); the source's lead-form pipelines are duplicated onto it and the ids in its content rewritten, so it captures its own leads"
3844
+ ).option("--title <title>", 'title for the copy (default: "Copy of <source title>")').option("--json", "print the full JSON, including the cloned pipelines and id rewrites").action(async (id, opts) => {
3845
+ try {
3846
+ const res = await new ErdoClient().clonePage(id, { title: opts.title });
3847
+ if (opts.json) {
3848
+ print(res);
3849
+ return;
3850
+ }
3851
+ console.log(`${res.id} ${res.url}`);
3852
+ for (const p of res.cloned_pipelines || []) {
3853
+ console.error(`cloned pipeline: ${p.source_id} -> ${p.id}${p.slug ? ` (${p.slug})` : ""}`);
3854
+ }
3855
+ for (const note of res.notes || []) console.error(`note: ${note}`);
3856
+ } catch (e) {
3857
+ fail(e);
3858
+ }
3859
+ });
3810
3860
  pagesCmd.command("get <id>").description("Show an artifact").action(async (id) => {
3811
3861
  try {
3812
3862
  print(await new ErdoClient().getArtifact(id));
@@ -4079,6 +4129,52 @@ emailCmd.command("received").description(
4079
4129
  fail(e);
4080
4130
  }
4081
4131
  });
4132
+ var sentEmailsCmd = emailCmd.command("sent").description("Read the audited outbound email log and provider delivery evidence");
4133
+ sentEmailsCmd.command("list").description("List sent email, newest first, including immutable delivered_at evidence").option("--to <email>", "only mail sent to this address").option("--since <timestamp>", "only mail created at or after this RFC 3339 timestamp").option("--search <text>", "case-insensitive subject substring").option("--limit <n>", "page size (default 25, max 200)").option("--offset <n>", "rows to skip").option("--json", "print the raw JSON result instead of a table").action(
4134
+ async (opts) => {
4135
+ try {
4136
+ const res = await new ErdoClient().listSentEmails({
4137
+ to: opts.to,
4138
+ since: opts.since,
4139
+ search: opts.search,
4140
+ limit: opts.limit ? Number(opts.limit) : void 0,
4141
+ offset: opts.offset ? Number(opts.offset) : void 0
4142
+ });
4143
+ if (opts.json) {
4144
+ print(res);
4145
+ return;
4146
+ }
4147
+ const emails = res.emails ?? [];
4148
+ if (emails.length === 0) {
4149
+ console.log("No sent email matches those filters.");
4150
+ return;
4151
+ }
4152
+ printAlignedTable(
4153
+ ["id", "to", "subject", "status", "delivered at", "latest event", "sent at"],
4154
+ emails.map((email) => [
4155
+ email.id,
4156
+ email.to,
4157
+ email.subject,
4158
+ email.status_reason ? `${email.status}: ${email.status_reason}` : email.status,
4159
+ email.delivered_at ?? "",
4160
+ email.last_delivery_event_at ?? "",
4161
+ email.sent_at ?? ""
4162
+ ])
4163
+ );
4164
+ process.stderr.write(`showing ${emails.length} of ${res.total} matching message(s)
4165
+ `);
4166
+ } catch (e) {
4167
+ fail(e);
4168
+ }
4169
+ }
4170
+ );
4171
+ sentEmailsCmd.command("get <emailID>").description("Read one sent email, including exact bodies and delivery evidence").action(async (emailID) => {
4172
+ try {
4173
+ print(await new ErdoClient().getSentEmail(emailID));
4174
+ } catch (e) {
4175
+ fail(e);
4176
+ }
4177
+ });
4082
4178
  var datasetsCmd = program.command("datasets").description("Datasets");
4083
4179
  datasetsCmd.command("list").description("List datasets").option(
4084
4180
  "--class <class>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erdoai/cli",
3
- "version": "0.65.0",
3
+ "version": "0.67.0",
4
4
  "description": "Erdo CLI — drive datasets, pages, and evals from the terminal or CI",
5
5
  "type": "module",
6
6
  "bin": {