@oxygen-agent/cli 1.839.8 → 1.844.6

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.839.8
37
+ Version: 1.844.6
package/dist/index.js CHANGED
@@ -8797,6 +8797,12 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
8797
8797
  const suffix = range && range !== "30d" ? `?range=${encodeURIComponent(range)}` : "";
8798
8798
  return requestOxygen(`/api/cli/admin/kpis${suffix}`);
8799
8799
  });
8800
+ }))
8801
+ .addCommand(new Command("egress")
8802
+ .description("Read-only Fly email-egress overview: shared IP, dedicated workspace apps and IPs, liveness, image drift, billing, and stuck orders. OXYGEN staff only.")
8803
+ .option("--json", "Print a JSON envelope.")
8804
+ .action(async (options) => {
8805
+ await handleAsyncAction("admin egress", options, () => requestOxygen("/api/cli/admin/egress"));
8800
8806
  }))
8801
8807
  .addCommand(new Command("costs")
8802
8808
  .description("Show provider costs (COGS) per workspace. Staff only.")
@@ -239,7 +239,7 @@ export declare const BASE_PRICING_PLANS: {
239
239
  readonly description: "Custom procurement, invoicing, limits, and rollout support.";
240
240
  readonly ctaLabel: "Talk to us";
241
241
  readonly contactHref: "mailto:support@oxygen-agent.com";
242
- readonly features: readonly ["Everything in Team", "Custom usage limits", "Volume pricing", "Custom invoicing and billing", "Dedicated support"];
242
+ readonly features: readonly ["Everything in Team", "Custom usage limits", "Volume pricing", "Dedicated support"];
243
243
  readonly monthlyPriceCents: number | null;
244
244
  readonly monthlyCredits: number | null;
245
245
  readonly weeklyCreditsLimit: number | null;
@@ -360,7 +360,6 @@ export const BASE_PRICING_PLANS = {
360
360
  "Everything in Team",
361
361
  "Custom usage limits",
362
362
  "Volume pricing",
363
- "Custom invoicing and billing",
364
363
  "Dedicated support",
365
364
  ],
366
365
  },
@@ -67,6 +67,7 @@ export * from "./schedule-label.js";
67
67
  export * from "./social-capabilities.js";
68
68
  export * from "./signup-lead-deliveries.js";
69
69
  export * from "./sql-error.js";
70
+ export * from "./postgres-text.js";
70
71
  export * from "./tags.js";
71
72
  export * from "./telemetry.js";
72
73
  export * from "./tenant-database-secret.js";
@@ -78,6 +78,7 @@ export * from "./schedule-label.js";
78
78
  export * from "./social-capabilities.js";
79
79
  export * from "./signup-lead-deliveries.js";
80
80
  export * from "./sql-error.js";
81
+ export * from "./postgres-text.js";
81
82
  export * from "./tags.js";
82
83
  export * from "./telemetry.js";
83
84
  export * from "./tenant-database-secret.js";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Remove Unicode code units PostgreSQL cannot store in text/jsonb.
3
+ *
4
+ * JavaScript strings may contain U+0000 and unpaired UTF-16 surrogates. JSON.stringify
5
+ * accepts both (escaping them), but PostgreSQL rejects U+0000 and malformed surrogate
6
+ * escapes with SQLSTATE 22P05/22P02. Provider payloads are untrusted text, so sanitize
7
+ * at the persistence boundary while preserving every valid Unicode scalar value.
8
+ */
9
+ export declare function sanitizePostgresText(value: string): string;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Remove Unicode code units PostgreSQL cannot store in text/jsonb.
3
+ *
4
+ * JavaScript strings may contain U+0000 and unpaired UTF-16 surrogates. JSON.stringify
5
+ * accepts both (escaping them), but PostgreSQL rejects U+0000 and malformed surrogate
6
+ * escapes with SQLSTATE 22P05/22P02. Provider payloads are untrusted text, so sanitize
7
+ * at the persistence boundary while preserving every valid Unicode scalar value.
8
+ */
9
+ export function sanitizePostgresText(value) {
10
+ let sanitized = "";
11
+ let changed = false;
12
+ for (let index = 0; index < value.length; index += 1) {
13
+ const code = value.charCodeAt(index);
14
+ if (code === 0) {
15
+ changed = true;
16
+ continue;
17
+ }
18
+ if (code >= 0xd800 && code <= 0xdbff) {
19
+ const next = value.charCodeAt(index + 1);
20
+ if (next >= 0xdc00 && next <= 0xdfff) {
21
+ sanitized += value[index] ?? "";
22
+ sanitized += value[index + 1] ?? "";
23
+ index += 1;
24
+ }
25
+ else {
26
+ changed = true;
27
+ }
28
+ continue;
29
+ }
30
+ if (code >= 0xdc00 && code <= 0xdfff) {
31
+ changed = true;
32
+ continue;
33
+ }
34
+ sanitized += value[index] ?? "";
35
+ }
36
+ return changed ? sanitized : value;
37
+ }
@@ -263,20 +263,27 @@ function categoryFromSqlstate(code) {
263
263
  return "schema_drift";
264
264
  return SQLSTATE_CLASS_CAUSES.get(code.slice(0, 2)) ?? null;
265
265
  }
266
- // Walk the Error.cause chain (bounded) and return the first non-null value the
267
- // reader extracts. drizzle wraps the pg error on `.cause`, and custom wrappers
268
- // can nest deeper, so a single-level read misses the actionable DB fields when
269
- // the chain is two or more deep (OXY-38).
270
- const MAX_CAUSE_DEPTH = 5;
266
+ // Walk the bounded error graph and return the first non-null value the reader
267
+ // extracts. drizzle wraps the driver error on `.cause`; Neon's HTTP driver then
268
+ // stores its transport error on `.sourceError`, and AggregateError uses
269
+ // `.errors`. Following only `cause` mislabeled Neon fetch/socket failures as
270
+ // deterministic `unknown` SQL errors (tenant_due_work, 2026-08-24).
271
+ const MAX_ERROR_GRAPH_NODES = 12;
271
272
  function readCauseChain(error, read) {
272
- let current = error;
273
- for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
274
- if (!current || typeof current !== "object")
275
- return null;
276
- const value = read(current);
273
+ const pending = [error];
274
+ const seen = new Set();
275
+ for (let visited = 0; pending.length > 0 && visited < MAX_ERROR_GRAPH_NODES; visited += 1) {
276
+ const current = pending.shift();
277
+ if (!current || typeof current !== "object" || seen.has(current))
278
+ continue;
279
+ seen.add(current);
280
+ const record = current;
281
+ const value = read(record);
277
282
  if (value !== null)
278
283
  return value;
279
- current = current.cause;
284
+ pending.push(record.cause, record.sourceError);
285
+ if (Array.isArray(record.errors))
286
+ pending.push(...record.errors);
280
287
  }
281
288
  return null;
282
289
  }
@@ -1,4 +1,4 @@
1
- export declare const OXYGEN_VERSION = "1.839.8";
1
+ export declare const OXYGEN_VERSION = "1.844.6";
2
2
  export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.181.0";
3
3
  export declare const MANAGED_INBOX_MINIMUM_CLI_VERSION = "1.326.2";
4
4
  export declare const SUPPORT_AGENT_REPLY_MINIMUM_CLI_VERSION = "1.747.0";
@@ -1,4 +1,4 @@
1
- export const OXYGEN_VERSION = "1.839.8";
1
+ export const OXYGEN_VERSION = "1.844.6";
2
2
  // The GLOBAL CLI compatibility floor: the oldest CLI allowed to call any
3
3
  // operational route. Raising it hard-rejects every older CLI from the entire
4
4
  // product, so it obeys one law, enforced by scripts/ci/cli-min-version-gate.mjs:
@@ -91,6 +91,11 @@
91
91
  "import": "./dist/custom-http-safety.js",
92
92
  "default": "./dist/custom-http-safety.js"
93
93
  },
94
+ "./redaction": {
95
+ "types": "./dist/redaction.d.ts",
96
+ "import": "./dist/redaction.js",
97
+ "default": "./dist/redaction.js"
98
+ },
94
99
  "./search-vocab": {
95
100
  "types": "./dist/search-vocab.d.ts",
96
101
  "import": "./dist/search-vocab.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.839.8",
3
+ "version": "1.844.6",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",