@oxygen-agent/cli 1.272.83 → 1.274.15

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 CHANGED
@@ -34,4 +34,4 @@ oxygen update
34
34
 
35
35
  For product documentation, visit https://oxygen-agent.com/docs. For support, visit https://oxygen-agent.com.
36
36
 
37
- Version: 1.272.83
37
+ Version: 1.274.15
package/dist/index.js CHANGED
@@ -4643,6 +4643,52 @@ export function createProgram() {
4643
4643
  ...(options.approve ? { approve: true } : {}),
4644
4644
  },
4645
4645
  }));
4646
+ }))
4647
+ .addCommand(new Command("register")
4648
+ .description("STAFF: register a manually-purchased egress IP (e.g. IPRoyal ISP-dedicated) into this environment's inventory. Secrets never pass here — --credential-ref names the Doppler family EGRESS_CRED_<REF>_USERNAME/_PASSWORD, set separately in Doppler. Register, then `egress assign`, then enable EGRESS_POOL_ENABLED (pool mode fails closed for unassigned mailboxes).")
4649
+ .requiredOption("--host <host>", "Proxy hostname or IP — bare, no scheme/port/credentials.")
4650
+ .requiredOption("--port <port>", "Proxy port (1-65535).")
4651
+ .requiredOption("--credential-ref <ref>", "Doppler credential-family name (A-Z, 0-9, _), e.g. IPROYAL.")
4652
+ .option("--vendor <vendor>", "Vendor slug for inventory provenance.", "iproyal")
4653
+ .option("--protocol <protocol>", "Proxy protocol: http (default), https, or socks5.")
4654
+ .option("--tier <tier>", "shared (default) or dedicated (requires --dedicated-org).")
4655
+ .option("--dedicated-org <orgId>", "Organization id a dedicated-tier IP is reserved for.")
4656
+ .option("--session-label <label>", "Optional vendor session/order label for provenance.")
4657
+ .option("--json", "Print a JSON envelope.")
4658
+ .action(async (options) => {
4659
+ await handleAsyncAction("egress register", options, () => requestOxygen("/api/cli/egress/register", {
4660
+ method: "POST",
4661
+ body: {
4662
+ host: readOption(options.host),
4663
+ port: Number(readOption(options.port)),
4664
+ credential_ref: readOption(options.credentialRef),
4665
+ vendor: readOption(options.vendor),
4666
+ ...(readOption(options.protocol) ? { protocol: readOption(options.protocol) } : {}),
4667
+ ...(readOption(options.tier) ? { tier: readOption(options.tier) } : {}),
4668
+ ...(readOption(options.dedicatedOrg) ? { dedicated_organization_id: readOption(options.dedicatedOrg) } : {}),
4669
+ ...(readOption(options.sessionLabel) ? { session_label: readOption(options.sessionLabel) } : {}),
4670
+ },
4671
+ }));
4672
+ }))
4673
+ .addCommand(new Command("assign")
4674
+ .description("Assign sending mailboxes to inventoried egress IPs — least-loaded across the active pool, or pinned with --ip. Existing open assignments are kept (stable for life; use rotate to re-home a burned IP). Admin/owner role; no spend, 0 credits.")
4675
+ .option("--mailboxes <list>", "Comma-separated mailbox ids or addresses to assign.")
4676
+ .option("--all", "Assign every sending mailbox in the pool that lacks an open assignment.")
4677
+ .option("--ip <egressIpId>", "Pin the targeted mailboxes to this egress IP id (must be active and org-visible).")
4678
+ .option("--json", "Print a JSON envelope.")
4679
+ .action(async (options) => {
4680
+ await handleAsyncAction("egress assign", options, () => {
4681
+ const list = readOption(options.mailboxes);
4682
+ const mailboxes = list ? list.split(",").map((entry) => entry.trim()).filter(Boolean) : [];
4683
+ return requestOxygen("/api/cli/egress/assign", {
4684
+ method: "POST",
4685
+ body: {
4686
+ ...(mailboxes.length > 0 ? { mailboxes } : {}),
4687
+ ...(options.all ? { all: true } : {}),
4688
+ ...(readOption(options.ip) ? { egress_ip_id: readOption(options.ip) } : {}),
4689
+ },
4690
+ });
4691
+ });
4646
4692
  })));
4647
4693
  program
4648
4694
  .command("directory")
@@ -7405,31 +7451,35 @@ export function createProgram() {
7405
7451
  await handleAsyncAction("mailboxes oauth-health", options, () => requestOxygen("/api/cli/mailboxes/oauth-health"));
7406
7452
  }))
7407
7453
  .addCommand(new Command("warmup")
7408
- .description("Mailbox warmup via Instantly (BYOK — Instantly bills your account, 0 Oxygen credits).")
7454
+ .description("Mailbox warmup via Instantly — BYOK over your connected Instantly account, or --billing-mode managed via the OXYGEN-managed Instantly workspace (both 0 Oxygen credits).")
7409
7455
  .addCommand(new Command("enable")
7410
- .description("Enable Instantly warmup for sending mailboxes and stamp each mailbox's warmup state. Targets the whole pool unless --mailboxes is given.")
7456
+ .description("Enable Instantly warmup for sending mailboxes and stamp each mailbox's warmup state. Targets the whole pool unless --mailboxes is given. Omit --billing-mode for automatic: BYOK when your Instantly is connected, else managed when enabled on the deployment.")
7411
7457
  .option("--mailboxes <list>", "Comma-separated mailbox ids or addresses to warm. Omit to warm the whole pool.")
7412
- .option("--connection <id>", "Instantly connection id. Defaults to the org's active Instantly connection.")
7458
+ .option("--connection <id>", "Instantly connection id (forces BYOK). Defaults to the org's active Instantly connection.")
7459
+ .option("--billing-mode <mode>", "byok = your Instantly connection; managed = the OXYGEN-managed Instantly workspace.")
7413
7460
  .option("--dry-run", "Simulate without calling Instantly (mailboxes marked pending).")
7414
7461
  .option("--json", "Print a JSON envelope.")
7415
7462
  .action(async (options) => {
7416
7463
  await handleAsyncAction("mailboxes warmup enable", options, () => {
7417
7464
  const mailboxes = readCsvOption(options.mailboxes);
7418
7465
  const connection = readOption(options.connection);
7466
+ const billingMode = readOption(options.billingMode);
7419
7467
  return requestOxygen("/api/cli/mailboxes/warmup", {
7420
7468
  method: "POST",
7421
7469
  body: {
7422
7470
  ...(mailboxes.length > 0 ? { mailboxes } : {}),
7423
7471
  ...(connection ? { connection_id: connection } : {}),
7472
+ ...(billingMode ? { billing_mode: billingMode } : {}),
7424
7473
  ...(options.dryRun ? { dry_run: true } : {}),
7425
7474
  },
7426
7475
  });
7427
7476
  });
7428
7477
  }))
7429
7478
  .addCommand(new Command("status")
7430
- .description("Sync Instantly's warmup analytics into the pool, updating each mailbox's warmup state. Targets the whole pool unless --mailboxes is given.")
7479
+ .description("Sync Instantly's warmup analytics into the pool, updating each mailbox's warmup state. Targets the whole pool unless --mailboxes is given. Omit --billing-mode for automatic: BYOK when connected, else managed when enabled.")
7431
7480
  .option("--mailboxes <list>", "Comma-separated mailbox ids or addresses to sync. Omit to sync the whole pool.")
7432
- .option("--connection <id>", "Instantly connection id. Defaults to the org's active Instantly connection.")
7481
+ .option("--connection <id>", "Instantly connection id (forces BYOK). Defaults to the org's active Instantly connection.")
7482
+ .option("--billing-mode <mode>", "byok = your Instantly connection; managed = the OXYGEN-managed Instantly workspace.")
7433
7483
  .option("--dry-run", "Skip the Instantly call (mailboxes marked pending).")
7434
7484
  .option("--json", "Print a JSON envelope.")
7435
7485
  .action(async (options) => {
@@ -7441,6 +7491,9 @@ export function createProgram() {
7441
7491
  const connection = readOption(options.connection);
7442
7492
  if (connection)
7443
7493
  params.set("connection_id", connection);
7494
+ const billingMode = readOption(options.billingMode);
7495
+ if (billingMode)
7496
+ params.set("billing_mode", billingMode);
7444
7497
  if (options.dryRun)
7445
7498
  params.set("dry_run", "true");
7446
7499
  const suffix = params.toString();
@@ -7497,14 +7550,15 @@ export function createProgram() {
7497
7550
  await handleAsyncAction("mailboxes order-status", options, () => requestOxygen(`/api/cli/mailboxes/orders/${encodeURIComponent(order)}`));
7498
7551
  })));
7499
7552
  program.addCommand(new Command("deliverability")
7500
- .description("External email deliverability: fleet reputation health and DIRECTIONAL inbox-placement (spam) tests. Placement tests are approval-gated paid runs (managed = 2 credits, BYOK = 0); fail closed with 409 when no health provider is connected.")
7553
+ .description("External email deliverability: fleet reputation health and DIRECTIONAL inbox-placement (spam) tests via EmailGuard or Zapmail. Placement tests are approval-gated paid runs (managed bills Oxygen credits; BYOK = 0 Oxygen credits — Zapmail BYOK bills your Zapmail wallet ~$2/test); fail closed with 409 when no health provider is connected.")
7501
7554
  .addCommand(new Command("placement-test")
7502
7555
  .description("Directional inbox-placement (spam) tests: run, list, and get. Results estimate inbox-vs-spam landing from seed inboxes.")
7503
7556
  .addCommand(new Command("run")
7504
- .description("Start a placement test for one sending mailbox. Without --approved this returns a PREVIEW (billing mode + credits_required). Re-run with --approved and --max-credits >= credits_required to send.")
7557
+ .description("Start a placement test for one sending mailbox. Without --approved this returns a PREVIEW (billing mode + credits_required). Re-run with --approved and --max-credits >= credits_required to send. Zapmail runs test Zapmail-hosted mailboxes ONLY, compose their own probe (subject/body ignored), and complete async (2-24h).")
7505
7558
  .argument("<mailbox>", "Sending mailbox address to test (e.g. ada@send.acme.com).")
7506
- .option("--subject <subject>", "Optional subject for the seed message.")
7507
- .option("--body <text>", "Optional plain-text body for the seed message.")
7559
+ .option("--provider <provider>", "Health provider: emailguard or zapmail. Omit to auto-resolve (Zapmail-hosted mailboxes route to zapmail, else emailguard).")
7560
+ .option("--subject <subject>", "Optional subject for the seed message (zapmail ignores it beyond labeling the test).")
7561
+ .option("--body <text>", "Optional plain-text body for the seed message (ignored by zapmail).")
7508
7562
  .option("--approved", "Actually run the test (otherwise a preview is returned).")
7509
7563
  .option("--max-credits <n>", "Credit cap the caller accepts (must be >= credits_required for managed runs).")
7510
7564
  .option("--json", "Print a JSON envelope.")
@@ -7513,6 +7567,7 @@ export function createProgram() {
7513
7567
  method: "POST",
7514
7568
  body: {
7515
7569
  mailbox,
7570
+ ...(readOption(options.provider) ? { provider: readOption(options.provider) } : {}),
7516
7571
  ...(readOption(options.subject) ? { subject: readOption(options.subject) } : {}),
7517
7572
  ...(readOption(options.body) ? { body_text: readOption(options.body) } : {}),
7518
7573
  ...(options.approved ? { approved: true } : {}),
@@ -7521,7 +7576,7 @@ export function createProgram() {
7521
7576
  }));
7522
7577
  }))
7523
7578
  .addCommand(new Command("list")
7524
- .description("List recent directional inbox-placement tests with status, billing mode, seed set, score, and credits used.")
7579
+ .description("List recent directional inbox-placement tests with status, health provider, billing mode, seed set, score, and credits used.")
7525
7580
  .option("--limit <n>", "Max rows (default 50, cap 200).")
7526
7581
  .option("--json", "Print a JSON envelope.")
7527
7582
  .action(async (options) => {
@@ -7531,7 +7586,7 @@ export function createProgram() {
7531
7586
  });
7532
7587
  }))
7533
7588
  .addCommand(new Command("get")
7534
- .description("Get one directional inbox-placement test by id — status, seed inboxes, per-provider results, and score.")
7589
+ .description("Get one directional inbox-placement test by id — status, health provider, seed inboxes, per-provider results, and score. Zapmail results land async (2-24h); keep polling while status is awaiting_results.")
7535
7590
  .argument("<id>", "Placement test id.")
7536
7591
  .option("--json", "Print a JSON envelope.")
7537
7592
  .action(async (id, options) => {
@@ -119,7 +119,7 @@ export declare const BASE_PRICING_PLANS: {
119
119
  readonly description: "Custom procurement, invoicing, limits, and rollout support.";
120
120
  readonly ctaLabel: "Talk to us";
121
121
  readonly contactHref: "https://cal.com/tim-scheuer-mxbib9/45";
122
- readonly features: readonly ["Custom monthly usage pool", "Custom automation action allowance", "Phone number enrichment", "Custom AI-key and provider routing policies", "SSO, invoicing, and procurement support"];
122
+ readonly features: readonly ["Everything in Team", "Custom usage limits", "Volume pricing", "Custom invoicing and billing", "Dedicated support"];
123
123
  };
124
124
  };
125
125
  export declare const PUBLIC_PLAN_ORDER: readonly PlanTier[];
@@ -126,11 +126,11 @@ export const BASE_PRICING_PLANS = {
126
126
  ctaLabel: "Talk to us",
127
127
  contactHref: CONTACT_SALES_URL,
128
128
  features: [
129
- "Custom monthly usage pool",
130
- "Custom automation action allowance",
131
- "Phone number enrichment",
132
- "Custom AI-key and provider routing policies",
133
- "SSO, invoicing, and procurement support",
129
+ "Everything in Team",
130
+ "Custom usage limits",
131
+ "Volume pricing",
132
+ "Custom invoicing and billing",
133
+ "Dedicated support",
134
134
  ],
135
135
  },
136
136
  };
@@ -1,2 +1,2 @@
1
- export declare const OXYGEN_VERSION = "1.272.83";
1
+ export declare const OXYGEN_VERSION = "1.274.15";
2
2
  export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.181.0";
@@ -1,4 +1,4 @@
1
- export const OXYGEN_VERSION = "1.272.83";
1
+ export const OXYGEN_VERSION = "1.274.15";
2
2
  // Bump this only when deployed CLI/API contracts require a newer CLI.
3
3
  // 1.181.0: paid table action runs and background columns run require
4
4
  // approved=true in addition to max_credits; older CLIs cannot send the flag.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.272.83",
3
+ "version": "1.274.15",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",