@oxygen-agent/cli 1.1010.650 → 1.1010.905
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 +1 -1
- package/dist/auto-update.d.ts +129 -0
- package/dist/auto-update.js +392 -0
- package/dist/command-manifest.js +15 -1
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.js +6 -3
- package/dist/functions-commands.js +1 -1
- package/dist/http-client.js +28 -4
- package/dist/inbox-needs-reply-notice.d.ts +12 -0
- package/dist/inbox-needs-reply-notice.js +51 -0
- package/dist/index.js +756 -177
- package/dist/run-wait.d.ts +3 -1
- package/dist/run-wait.js +19 -5
- package/dist/skills.js +48 -22
- package/dist/streamed-file-import.d.ts +58 -0
- package/dist/streamed-file-import.js +115 -0
- package/dist/update.d.ts +29 -0
- package/dist/update.js +62 -16
- package/dist/workflow-plan-limit-notices.d.ts +8 -0
- package/dist/workflow-plan-limit-notices.js +28 -0
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +3 -3
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +50 -2
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +94 -2
- package/node_modules/@oxygen/shared/dist/billing.d.ts +247 -37
- package/node_modules/@oxygen/shared/dist/billing.js +418 -45
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +66 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +6 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +6 -6
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +90 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +167 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.js +361 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.js +65 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.d.ts +51 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.js +101 -0
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.d.ts +27 -0
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.js +27 -0
- package/node_modules/@oxygen/shared/dist/error-redaction.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -1
- package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +10 -1
- package/node_modules/@oxygen/shared/dist/feature-gates.js +12 -1
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +13 -1
- package/node_modules/@oxygen/shared/dist/file-import.js +33 -6
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +73 -3
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +246 -24
- package/node_modules/@oxygen/shared/dist/import-limits.d.ts +25 -1
- package/node_modules/@oxygen/shared/dist/import-limits.js +35 -2
- package/node_modules/@oxygen/shared/dist/index.d.ts +4 -23
- package/node_modules/@oxygen/shared/dist/index.js +4 -43
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +114 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +150 -0
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +17 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +55 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +19 -2
- package/node_modules/@oxygen/shared/dist/plan-band.d.ts +234 -0
- package/node_modules/@oxygen/shared/dist/plan-band.js +312 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.d.ts +77 -7
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +87 -7
- package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +219 -0
- package/node_modules/@oxygen/shared/dist/plan-limits-view.js +330 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +335 -126
- package/node_modules/@oxygen/shared/dist/plan-limits.js +277 -86
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +158 -49
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +139 -41
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +42 -23
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +56 -37
- package/node_modules/@oxygen/shared/dist/process-resource.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/process-resource.js +25 -0
- package/node_modules/@oxygen/shared/dist/provider-http-error.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/provider-http-error.js +27 -0
- package/node_modules/@oxygen/shared/dist/repricing.d.ts +257 -0
- package/node_modules/@oxygen/shared/dist/repricing.js +721 -0
- package/node_modules/@oxygen/shared/dist/semver.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/semver.js +41 -0
- package/node_modules/@oxygen/shared/dist/sending-limits.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/sending-limits.js +43 -0
- package/node_modules/@oxygen/shared/dist/sending-seats.d.ts +18 -15
- package/node_modules/@oxygen/shared/dist/sending-seats.js +22 -17
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +4 -1
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +57 -8
- package/node_modules/@oxygen/shared/dist/spend-safety.js +64 -11
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +33 -1
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +71 -1
- package/node_modules/@oxygen/shared/dist/table-capacity.d.ts +68 -10
- package/node_modules/@oxygen/shared/dist/table-capacity.js +85 -4
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +13 -5
- package/node_modules/@oxygen/shared/dist/telemetry-resource.d.ts +40 -0
- package/node_modules/@oxygen/shared/dist/telemetry-resource.js +35 -0
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +41 -2
- package/node_modules/@oxygen/shared/dist/trace-context.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/trace-context.js +88 -0
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/ugc.js +29 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -3
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +14 -27
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +5 -0
- package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +3 -3
- package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +15 -1
- package/node_modules/@oxygen/workflows/dist/graph/types.js +15 -1
- package/node_modules/@oxygen/workflows/dist/index.d.ts +45 -0
- package/node_modules/@oxygen/workflows/dist/index.js +152 -2
- package/node_modules/@oxygen/workflows/dist/usage-estimate.d.ts +10 -1
- package/node_modules/@oxygen/workflows/dist/usage-estimate.js +33 -29
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.d.ts +0 -64
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.js +0 -90
|
@@ -1,13 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
export declare const WORKSPACE_TABLE_CAPACITY: Readonly<{
|
|
8
|
-
tableRowLimit: 3000000;
|
|
9
|
-
workspaceRowLimit: 25000000;
|
|
1
|
+
import type { PlanBand } from "./plan-band.js";
|
|
2
|
+
import { type RepricingOptions } from "./repricing.js";
|
|
3
|
+
export type WorkspaceTableCapacityLimits = {
|
|
4
|
+
tableRowLimit: number;
|
|
5
|
+
workspaceRowLimit: number;
|
|
10
6
|
workspaceDatabaseWarningBytes: number;
|
|
11
7
|
workspaceDatabaseLimitBytes: number;
|
|
12
|
-
}
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The envelope every workspace had before storage scaled with plan size, and
|
|
11
|
+
* still the value in force for any workspace whose plan-resolved limits have not
|
|
12
|
+
* been written to its tenant yet. The tenant capacity trigger falls back to these
|
|
13
|
+
* exact numbers when its per-workspace limit columns are NULL (tenant migration
|
|
14
|
+
* `0451_workspace_capacity_plan_limits.sql`,
|
|
15
|
+
* enforced by `0452_workspace_capacity_plan_limit_enforcement.sql`); a test pins the two together.
|
|
16
|
+
*/
|
|
17
|
+
export declare const WORKSPACE_TABLE_CAPACITY: Readonly<WorkspaceTableCapacityLimits>;
|
|
13
18
|
export declare const WORKSPACE_TABLE_DATABASE_STORAGE_SCOPE: "postgres_workspace_tables_heap_indexes_toast";
|
|
19
|
+
/** Two thirds of the hard limit, rounded down (PROPOSED P-48, repricing spec § 4.1). */
|
|
20
|
+
export declare function workspaceDatabaseWarningBytesFor(limitBytes: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Storage by plan size, as ratified (decision L1, 2026-09-26; repricing spec
|
|
23
|
+
* § 4.1). This is the target ladder, not what is in force: see
|
|
24
|
+
* `resolveWorkspaceTableCapacity`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const PLAN_BAND_TABLE_CAPACITY_TARGETS: Readonly<Record<PlanBand, WorkspaceTableCapacityLimits>>;
|
|
27
|
+
/**
|
|
28
|
+
* Rows per Table above today's 3,000,000 ship only after a capacity test at 5M
|
|
29
|
+
* and 10M rows per Table. The workspace totals of these bands (rows and
|
|
30
|
+
* database) are already in force (decision F.1, 2026-09-27, amending L1, which
|
|
31
|
+
* had gated both); shipping a band's rows per Table is removing it from this list.
|
|
32
|
+
*/
|
|
33
|
+
export declare const PLAN_BANDS_AWAITING_TABLE_ROW_CAPACITY_TEST: readonly PlanBand[];
|
|
34
|
+
/**
|
|
35
|
+
* The storage limits in force for a plan band right now.
|
|
36
|
+
*
|
|
37
|
+
* - A limit that tightens (free, $49, $99) is a scheduled 2026-09 repricing value
|
|
38
|
+
* (`storage.<band>.*` in `REPRICING_2026_09_SCHEDULE`): today's envelope until
|
|
39
|
+
* the effective-date switch, the ratified ladder from it on.
|
|
40
|
+
* - A band awaiting the rows-per-Table capacity test has its ladder workspace
|
|
41
|
+
* totals and keeps today's rows per Table.
|
|
42
|
+
* - Every other band is already at its ladder value.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveWorkspaceTableCapacity(band: PlanBand, options?: RepricingOptions): WorkspaceTableCapacityLimits;
|
|
45
|
+
/**
|
|
46
|
+
* Where a band's storage stands against its ratified ladder (decision F.2):
|
|
47
|
+
*
|
|
48
|
+
* - `in_force`: the band's values are in force; nothing is pending.
|
|
49
|
+
* - `scheduled`: the 2026-09 repricing moves them to `target` at `effectiveAt`.
|
|
50
|
+
* - `awaiting_capacity_test`: `target` applies once the rows-per-Table capacity
|
|
51
|
+
* test at that size passes; there is no date.
|
|
52
|
+
*
|
|
53
|
+
* A cut is reported only once an operator has set the repricing switch to a
|
|
54
|
+
* valid future instant. While the switch is unset or invalid a cutting band
|
|
55
|
+
* reads `in_force` and no target is revealed, the rule `describeRepricingSchedule`
|
|
56
|
+
* follows for every other scheduled value.
|
|
57
|
+
*/
|
|
58
|
+
export type WorkspaceTableCapacityStatus = {
|
|
59
|
+
status: "in_force";
|
|
60
|
+
effectiveAt: null;
|
|
61
|
+
target: null;
|
|
62
|
+
} | {
|
|
63
|
+
status: "scheduled";
|
|
64
|
+
effectiveAt: Date;
|
|
65
|
+
target: WorkspaceTableCapacityLimits;
|
|
66
|
+
} | {
|
|
67
|
+
status: "awaiting_capacity_test";
|
|
68
|
+
effectiveAt: null;
|
|
69
|
+
target: WorkspaceTableCapacityLimits;
|
|
70
|
+
};
|
|
71
|
+
export declare function describeWorkspaceTableCapacityStatus(band: PlanBand, options?: RepricingOptions): WorkspaceTableCapacityStatus;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { findRepricedValue, readRepricingSwitch, repricedValue, } from "./repricing.js";
|
|
1
2
|
const GIB = 1024 ** 3;
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The envelope every workspace had before storage scaled with plan size, and
|
|
5
|
+
* still the value in force for any workspace whose plan-resolved limits have not
|
|
6
|
+
* been written to its tenant yet. The tenant capacity trigger falls back to these
|
|
7
|
+
* exact numbers when its per-workspace limit columns are NULL (tenant migration
|
|
8
|
+
* `0451_workspace_capacity_plan_limits.sql`,
|
|
9
|
+
* enforced by `0452_workspace_capacity_plan_limit_enforcement.sql`); a test pins the two together.
|
|
7
10
|
*/
|
|
8
11
|
export const WORKSPACE_TABLE_CAPACITY = Object.freeze({
|
|
9
12
|
tableRowLimit: 3_000_000,
|
|
@@ -12,3 +15,81 @@ export const WORKSPACE_TABLE_CAPACITY = Object.freeze({
|
|
|
12
15
|
workspaceDatabaseLimitBytes: 30 * GIB,
|
|
13
16
|
});
|
|
14
17
|
export const WORKSPACE_TABLE_DATABASE_STORAGE_SCOPE = "postgres_workspace_tables_heap_indexes_toast";
|
|
18
|
+
/** Two thirds of the hard limit, rounded down (PROPOSED P-48, repricing spec § 4.1). */
|
|
19
|
+
export function workspaceDatabaseWarningBytesFor(limitBytes) {
|
|
20
|
+
return Math.floor((limitBytes * 2) / 3);
|
|
21
|
+
}
|
|
22
|
+
function ladderRow(tableRowLimit, workspaceRowLimit, databaseGib) {
|
|
23
|
+
const workspaceDatabaseLimitBytes = databaseGib * GIB;
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
tableRowLimit,
|
|
26
|
+
workspaceRowLimit,
|
|
27
|
+
workspaceDatabaseWarningBytes: workspaceDatabaseWarningBytesFor(workspaceDatabaseLimitBytes),
|
|
28
|
+
workspaceDatabaseLimitBytes,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Storage by plan size, as ratified (decision L1, 2026-09-26; repricing spec
|
|
33
|
+
* § 4.1). This is the target ladder, not what is in force: see
|
|
34
|
+
* `resolveWorkspaceTableCapacity`.
|
|
35
|
+
*/
|
|
36
|
+
export const PLAN_BAND_TABLE_CAPACITY_TARGETS = Object.freeze({
|
|
37
|
+
free: ladderRow(100_000, 1_000_000, 2),
|
|
38
|
+
"49": ladderRow(1_000_000, 5_000_000, 10),
|
|
39
|
+
"99": ladderRow(2_000_000, 10_000_000, 20),
|
|
40
|
+
"199": ladderRow(3_000_000, 25_000_000, 30),
|
|
41
|
+
"499": ladderRow(3_000_000, 25_000_000, 30),
|
|
42
|
+
"999": ladderRow(5_000_000, 50_000_000, 60),
|
|
43
|
+
"1999": ladderRow(10_000_000, 100_000_000, 120),
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Rows per Table above today's 3,000,000 ship only after a capacity test at 5M
|
|
47
|
+
* and 10M rows per Table. The workspace totals of these bands (rows and
|
|
48
|
+
* database) are already in force (decision F.1, 2026-09-27, amending L1, which
|
|
49
|
+
* had gated both); shipping a band's rows per Table is removing it from this list.
|
|
50
|
+
*/
|
|
51
|
+
export const PLAN_BANDS_AWAITING_TABLE_ROW_CAPACITY_TEST = Object.freeze(["999", "1999"]);
|
|
52
|
+
const STORAGE_FIELDS = [
|
|
53
|
+
["tableRowLimit", "table_row_limit"],
|
|
54
|
+
["workspaceRowLimit", "workspace_row_limit"],
|
|
55
|
+
["workspaceDatabaseWarningBytes", "workspace_database_warning_bytes"],
|
|
56
|
+
["workspaceDatabaseLimitBytes", "workspace_database_limit_bytes"],
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* The storage limits in force for a plan band right now.
|
|
60
|
+
*
|
|
61
|
+
* - A limit that tightens (free, $49, $99) is a scheduled 2026-09 repricing value
|
|
62
|
+
* (`storage.<band>.*` in `REPRICING_2026_09_SCHEDULE`): today's envelope until
|
|
63
|
+
* the effective-date switch, the ratified ladder from it on.
|
|
64
|
+
* - A band awaiting the rows-per-Table capacity test has its ladder workspace
|
|
65
|
+
* totals and keeps today's rows per Table.
|
|
66
|
+
* - Every other band is already at its ladder value.
|
|
67
|
+
*/
|
|
68
|
+
export function resolveWorkspaceTableCapacity(band, options = {}) {
|
|
69
|
+
const target = PLAN_BAND_TABLE_CAPACITY_TARGETS[band];
|
|
70
|
+
if (PLAN_BANDS_AWAITING_TABLE_ROW_CAPACITY_TEST.includes(band)) {
|
|
71
|
+
return Object.freeze({ ...target, tableRowLimit: WORKSPACE_TABLE_CAPACITY.tableRowLimit });
|
|
72
|
+
}
|
|
73
|
+
const resolved = { ...target };
|
|
74
|
+
for (const [field, key] of STORAGE_FIELDS) {
|
|
75
|
+
const scheduled = findRepricedValue(`storage.${band}.${key}`);
|
|
76
|
+
if (scheduled && typeof scheduled.before === "number" && typeof scheduled.after === "number") {
|
|
77
|
+
resolved[field] = repricedValue({ before: scheduled.before, after: scheduled.after }, options);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return Object.freeze(resolved);
|
|
81
|
+
}
|
|
82
|
+
export function describeWorkspaceTableCapacityStatus(band, options = {}) {
|
|
83
|
+
if (PLAN_BANDS_AWAITING_TABLE_ROW_CAPACITY_TEST.includes(band)) {
|
|
84
|
+
return { status: "awaiting_capacity_test", effectiveAt: null, target: PLAN_BAND_TABLE_CAPACITY_TARGETS[band] };
|
|
85
|
+
}
|
|
86
|
+
const state = readRepricingSwitch(options);
|
|
87
|
+
if (state.status === "scheduled") {
|
|
88
|
+
const current = resolveWorkspaceTableCapacity(band, options);
|
|
89
|
+
const target = resolveWorkspaceTableCapacity(band, { ...options, now: state.effectiveAt });
|
|
90
|
+
if (STORAGE_FIELDS.some(([field]) => current[field] !== target[field])) {
|
|
91
|
+
return { status: "scheduled", effectiveAt: state.effectiveAt, target };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { status: "in_force", effectiveAt: null, target: null };
|
|
95
|
+
}
|
|
@@ -46,6 +46,12 @@ export type TelemetryExportObserverOptions = {
|
|
|
46
46
|
windowMs?: number | undefined;
|
|
47
47
|
now?: (() => number) | undefined;
|
|
48
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* Copies the optional reader-facing exporter methods (FORWARDED_METHODS) from
|
|
51
|
+
* `inner` onto `wrapper`, bound to `inner`. Every exporter wrapper in this
|
|
52
|
+
* package uses it, so a method the SDK starts probing is added in one place.
|
|
53
|
+
*/
|
|
54
|
+
export declare function forwardExporterMethods(inner: object, wrapper: Record<string, unknown>): void;
|
|
49
55
|
/** Origin + path only: never query strings, fragments or URL credentials. */
|
|
50
56
|
export declare function telemetryEndpointForLog(endpoint: string): string;
|
|
51
57
|
/**
|
|
@@ -12,6 +12,18 @@ const FORWARDED_METHODS = [
|
|
|
12
12
|
"selectAggregationTemporality",
|
|
13
13
|
"selectAggregation",
|
|
14
14
|
];
|
|
15
|
+
/**
|
|
16
|
+
* Copies the optional reader-facing exporter methods (FORWARDED_METHODS) from
|
|
17
|
+
* `inner` onto `wrapper`, bound to `inner`. Every exporter wrapper in this
|
|
18
|
+
* package uses it, so a method the SDK starts probing is added in one place.
|
|
19
|
+
*/
|
|
20
|
+
export function forwardExporterMethods(inner, wrapper) {
|
|
21
|
+
for (const method of FORWARDED_METHODS) {
|
|
22
|
+
const fn = inner[method];
|
|
23
|
+
if (typeof fn === "function")
|
|
24
|
+
wrapper[method] = fn.bind(inner);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
15
27
|
/** Origin + path only: never query strings, fragments or URL credentials. */
|
|
16
28
|
export function telemetryEndpointForLog(endpoint) {
|
|
17
29
|
try {
|
|
@@ -187,11 +199,7 @@ export function observeTelemetryExporter(inner, options) {
|
|
|
187
199
|
return inner.shutdown();
|
|
188
200
|
},
|
|
189
201
|
};
|
|
190
|
-
|
|
191
|
-
const fn = inner[method];
|
|
192
|
-
if (typeof fn === "function")
|
|
193
|
-
observed[method] = fn.bind(inner);
|
|
194
|
-
}
|
|
202
|
+
forwardExporterMethods(inner, observed);
|
|
195
203
|
return observed;
|
|
196
204
|
}
|
|
197
205
|
const DROPPED_SPANS_MESSAGE = /^Dropped (\d+) spans because maxQueueSize reached$/;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which OTel resource each telemetry destination of this process receives.
|
|
3
|
+
*
|
|
4
|
+
* A process has ONE TracerProvider / MeterProvider and therefore one resource,
|
|
5
|
+
* but up to two destinations: Axiom (the managed-era store, whose dashboards and
|
|
6
|
+
* monitors filter on `deployment.environment == 'production'`) and the opt-in
|
|
7
|
+
* OTLP collector (DEV1 SigNoz, whose production receiver keeps only
|
|
8
|
+
* `deployment.environment == 'prod'` rows and whose dev receiver only `dev`).
|
|
9
|
+
*
|
|
10
|
+
* Production is the one tier where the two labels disagree, so production is the
|
|
11
|
+
* one tier that splits: the SDK resource stays exactly what a production process
|
|
12
|
+
* without a collector exports (the Axiom label, resource auto-detection on), and
|
|
13
|
+
* the collector's exporters swap in `collectorAttributes` — declared attributes
|
|
14
|
+
* only, never detected ones, because Node's process detector copies argv
|
|
15
|
+
* verbatim. Every other tier (dev, shadow, managed) keeps its single shared
|
|
16
|
+
* resource exactly as before.
|
|
17
|
+
*/
|
|
18
|
+
export type TelemetryResourcePlan = {
|
|
19
|
+
/** The SDK resource's `deployment.environment`: what Axiom receives. */
|
|
20
|
+
deploymentEnvironment: string;
|
|
21
|
+
/** The SDK resource attributes. */
|
|
22
|
+
resourceAttributes: Record<string, string>;
|
|
23
|
+
/** False when the collector shares the SDK resource, so nothing is detected into it. */
|
|
24
|
+
autoDetectResources: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Set only when the collector must see a different resource than Axiom: the
|
|
27
|
+
* declared attributes plus the process identity, labelled with the tier.
|
|
28
|
+
*/
|
|
29
|
+
collectorAttributes: Record<string, string> | null;
|
|
30
|
+
};
|
|
31
|
+
export type TelemetryResourcePlanInput = {
|
|
32
|
+
/** Every resource attribute except `deployment.environment`. */
|
|
33
|
+
declared: Record<string, string>;
|
|
34
|
+
/** The surface's managed fallback chain, used when OXYGEN_DEPLOY_ENV is unset. */
|
|
35
|
+
managedEnvironment: string;
|
|
36
|
+
/** True when OXYGEN_OTLP_ENDPOINT is configured for this process. */
|
|
37
|
+
collectorConfigured: boolean;
|
|
38
|
+
env?: NodeJS.ProcessEnv;
|
|
39
|
+
};
|
|
40
|
+
export declare function planTelemetryResource({ declared, managedEnvironment, collectorConfigured, env, }: TelemetryResourcePlanInput): TelemetryResourcePlan;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { deployEnvTelemetryEnvironment, resolveDeployEnv } from "./deploy-env.js";
|
|
2
|
+
import { processResourceIdentity } from "./process-resource.js";
|
|
3
|
+
export function planTelemetryResource({ declared, managedEnvironment, collectorConfigured, env = process.env, }) {
|
|
4
|
+
// The label a process without a collector has always exported: `production`
|
|
5
|
+
// on selfhost-prod, `development` on shadow/dev, the managed chain otherwise.
|
|
6
|
+
const axiomEnvironment = deployEnvTelemetryEnvironment(env) ?? managedEnvironment;
|
|
7
|
+
const withEnvironment = (environment, attributes) => ({
|
|
8
|
+
...attributes,
|
|
9
|
+
"deployment.environment": environment,
|
|
10
|
+
});
|
|
11
|
+
if (!collectorConfigured) {
|
|
12
|
+
return {
|
|
13
|
+
deploymentEnvironment: axiomEnvironment,
|
|
14
|
+
resourceAttributes: withEnvironment(axiomEnvironment, declared),
|
|
15
|
+
autoDetectResources: true,
|
|
16
|
+
collectorAttributes: null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const collectorEnvironment = env.OXYGEN_DEPLOY_ENV?.trim() ? resolveDeployEnv(env).tier : axiomEnvironment;
|
|
20
|
+
const collectorAttributes = withEnvironment(collectorEnvironment, { ...processResourceIdentity(), ...declared });
|
|
21
|
+
if (collectorEnvironment === "prod") {
|
|
22
|
+
return {
|
|
23
|
+
deploymentEnvironment: axiomEnvironment,
|
|
24
|
+
resourceAttributes: withEnvironment(axiomEnvironment, declared),
|
|
25
|
+
autoDetectResources: true,
|
|
26
|
+
collectorAttributes,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
deploymentEnvironment: collectorEnvironment,
|
|
31
|
+
resourceAttributes: collectorAttributes,
|
|
32
|
+
autoDetectResources: false,
|
|
33
|
+
collectorAttributes: null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type TelemetryAttributes = Record<string, unknown>;
|
|
2
2
|
export type WithTelemetrySpanOptions = {
|
|
3
3
|
isTransient?: (error: unknown) => boolean;
|
|
4
|
+
traceparent?: string | null | undefined;
|
|
4
5
|
};
|
|
5
6
|
export declare function withTelemetrySpan<T>(tracerName: string, name: string, attributes: TelemetryAttributes | undefined, fn: () => Promise<T>, options?: WithTelemetrySpanOptions): Promise<T>;
|
|
6
7
|
/**
|
|
@@ -18,5 +19,13 @@ export declare function setActiveTelemetryAttributes(attributes: TelemetryAttrib
|
|
|
18
19
|
export declare function markActiveTelemetryError(message: string, attributes?: TelemetryAttributes): void;
|
|
19
20
|
export declare function recordTelemetryCounter(name: string, value?: number, attributes?: TelemetryAttributes): void;
|
|
20
21
|
export declare function recordTelemetryHistogram(name: string, value: number, attributes?: TelemetryAttributes): void;
|
|
22
|
+
/**
|
|
23
|
+
* Records the latest observed value of a level (a queue depth, a pool size).
|
|
24
|
+
* A synchronous gauge rather than an observable one: the callers already sample
|
|
25
|
+
* on their own cadence (the BullMQ relay reads Redis counts every 10s), and a
|
|
26
|
+
* collection-time callback would have to reach into that loop's state. The
|
|
27
|
+
* exported point is the last value recorded before each export.
|
|
28
|
+
*/
|
|
29
|
+
export declare function recordTelemetryGauge(name: string, value: number, attributes?: TelemetryAttributes): void;
|
|
21
30
|
export declare function commonTelemetryAttributes(attributes?: TelemetryAttributes): TelemetryAttributes;
|
|
22
31
|
export declare function metricSafeAttributes(attributes?: TelemetryAttributes): TelemetryAttributes;
|
|
@@ -3,14 +3,21 @@ import { deployEnvTelemetryEnvironment, deployPlatformAttribute } from "./deploy
|
|
|
3
3
|
import { errorId } from "./log.js";
|
|
4
4
|
import { normalizeTelemetryAttributes } from "./redaction.js";
|
|
5
5
|
import { redactSqlParameters, sqlErrorTelemetryAttributes } from "./sql-error.js";
|
|
6
|
+
import { remoteParentContext } from "./trace-context.js";
|
|
6
7
|
import { OXYGEN_VERSION } from "./version.js";
|
|
7
8
|
const counterCache = new Map();
|
|
8
9
|
const histogramCache = new Map();
|
|
10
|
+
const gaugeCache = new Map();
|
|
9
11
|
// skipcq: JS-0116 — `async` keeps synchronous setup throws (getTracer / attribute
|
|
10
12
|
// normalization) as rejections so the Promise<T> contract holds for all callers.
|
|
11
13
|
export async function withTelemetrySpan(tracerName, name, attributes, fn, options) {
|
|
12
14
|
const tracer = trace.getTracer(tracerName, OXYGEN_VERSION);
|
|
13
|
-
|
|
15
|
+
const remote = options?.traceparent ? remoteParentContext(options.traceparent) : null;
|
|
16
|
+
const spanOptions = {
|
|
17
|
+
attributes: normalizeTelemetryAttributes(commonTelemetryAttributes(remote ? { ...attributes, "oxygen.trace.propagated": true } : attributes)),
|
|
18
|
+
...(remote && remote.links.length > 0 ? { links: remote.links } : {}),
|
|
19
|
+
};
|
|
20
|
+
const run = async (span) => {
|
|
14
21
|
try {
|
|
15
22
|
return await fn();
|
|
16
23
|
}
|
|
@@ -37,7 +44,10 @@ export async function withTelemetrySpan(tracerName, name, attributes, fn, option
|
|
|
37
44
|
finally {
|
|
38
45
|
span.end();
|
|
39
46
|
}
|
|
40
|
-
}
|
|
47
|
+
};
|
|
48
|
+
return remote
|
|
49
|
+
? tracer.startActiveSpan(name, spanOptions, remote.context, run)
|
|
50
|
+
: tracer.startActiveSpan(name, spanOptions, run);
|
|
41
51
|
}
|
|
42
52
|
/**
|
|
43
53
|
* The active global span's trace id: the join key into SigNoz/Axiom traces.
|
|
@@ -84,6 +94,23 @@ export function recordTelemetryHistogram(name, value, attributes) {
|
|
|
84
94
|
const histogram = getHistogram(name);
|
|
85
95
|
histogram.record(value, normalizeTelemetryAttributes(metricSafeAttributes(commonTelemetryAttributes(attributes))));
|
|
86
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Records the latest observed value of a level (a queue depth, a pool size).
|
|
99
|
+
* A synchronous gauge rather than an observable one: the callers already sample
|
|
100
|
+
* on their own cadence (the BullMQ relay reads Redis counts every 10s), and a
|
|
101
|
+
* collection-time callback would have to reach into that loop's state. The
|
|
102
|
+
* exported point is the last value recorded before each export.
|
|
103
|
+
*/
|
|
104
|
+
export function recordTelemetryGauge(name, value, attributes) {
|
|
105
|
+
if (!Number.isFinite(value))
|
|
106
|
+
return;
|
|
107
|
+
let gauge = gaugeCache.get(name);
|
|
108
|
+
if (!gauge) {
|
|
109
|
+
gauge = getMeter().createGauge(name);
|
|
110
|
+
gaugeCache.set(name, gauge);
|
|
111
|
+
}
|
|
112
|
+
gauge.record(value, normalizeTelemetryAttributes(metricSafeAttributes(commonTelemetryAttributes(attributes))));
|
|
113
|
+
}
|
|
87
114
|
export function commonTelemetryAttributes(attributes) {
|
|
88
115
|
const workerProcess = isWorkerProcess();
|
|
89
116
|
// Each attribute reads an ordered env-var fallback chain that differs by
|
|
@@ -199,7 +226,19 @@ const METRIC_SAFE_ATTRIBUTE_KEYS = new Set([
|
|
|
199
226
|
"worker.cycle.slow",
|
|
200
227
|
"table_action.lane",
|
|
201
228
|
"tenant.ticket_reason",
|
|
229
|
+
// oxygen.worker.tenant_queue_wait_ms: the ticket's narrow scope
|
|
230
|
+
// (copilot | publishing | none) and the tenant's plan band (the seven bands
|
|
231
|
+
// plus "unresolved"), which the worker-share target is read by. Closed enums.
|
|
232
|
+
"tenant.wake_kind",
|
|
233
|
+
"tenant.plan_band",
|
|
202
234
|
"queue.stalled",
|
|
235
|
+
// BullMQ execution queue dimensions (oxygen.worker.queue.*). `queue.lane` is
|
|
236
|
+
// the closed EXECUTION_LANES enum, `queue.role` the lane or "relay",
|
|
237
|
+
// `queue.state` one of BullMQ's five job-count states. Never the execution id
|
|
238
|
+
// or tenant id: those stay on the worker.job span and the lifecycle log.
|
|
239
|
+
"queue.lane",
|
|
240
|
+
"queue.role",
|
|
241
|
+
"queue.state",
|
|
203
242
|
"scope",
|
|
204
243
|
"rail",
|
|
205
244
|
"overall_status",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Context, type Link, type SpanContext } from "@opentelemetry/api";
|
|
2
|
+
/** Parses a W3C `traceparent`; anything malformed or all-zero yields null. */
|
|
3
|
+
export declare function parseTraceparent(value: unknown): SpanContext | null;
|
|
4
|
+
/** The validated traceparent, or undefined — for optional fields that must drop bad input. */
|
|
5
|
+
export declare function validTraceparent(value: unknown): string | undefined;
|
|
6
|
+
export declare function formatTraceparent(spanContext: SpanContext | undefined | null): string | null;
|
|
7
|
+
/** The `traceparent` of the currently active span, or null outside any span. */
|
|
8
|
+
export declare function activeTraceparent(): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* The parent context for a span that continues a stored traceparent.
|
|
11
|
+
*
|
|
12
|
+
* The remote span becomes the PARENT, so request -> job -> provider.* reads as
|
|
13
|
+
* one trace; whatever span was active (a worker cycle, the BullMQ runtime) is
|
|
14
|
+
* kept as a LINK so the scheduling side stays navigable. Every non-span context
|
|
15
|
+
* value (baggage, suppression flags) is preserved. Null for a missing or
|
|
16
|
+
* invalid traceparent: the caller then starts an ordinary child of the active
|
|
17
|
+
* context.
|
|
18
|
+
*/
|
|
19
|
+
export declare function remoteParentContext(traceparent: unknown): {
|
|
20
|
+
context: Context;
|
|
21
|
+
links: Link[];
|
|
22
|
+
} | null;
|
|
23
|
+
/**
|
|
24
|
+
* Links the active span to a stored enqueue traceparent. For work that is
|
|
25
|
+
* already inside its execution span (a BullMQ `bullmq.execute`) and only learns
|
|
26
|
+
* the enqueuing request once it has loaded its own row: a link joins the two
|
|
27
|
+
* traces without a second per-job span. Returns whether a link was added.
|
|
28
|
+
*/
|
|
29
|
+
export declare function linkActiveSpanToTraceparent(traceparent: unknown): boolean;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { context, isSpanContextValid, trace, } from "@opentelemetry/api";
|
|
2
|
+
/**
|
|
3
|
+
* W3C Trace Context carried across the durable enqueue boundary.
|
|
4
|
+
*
|
|
5
|
+
* A web request that enqueues work (a table-action run, a BullMQ execution) and
|
|
6
|
+
* the worker that later executes it run in different processes, minutes apart,
|
|
7
|
+
* with Postgres in between. Nothing propagated the OTel context across that gap,
|
|
8
|
+
* so a provider call made by the worker lived in a worker trace that could not
|
|
9
|
+
* be joined to the request that paid for it. The enqueuing request stores a
|
|
10
|
+
* `traceparent` string next to its correlation `trace_id`; the worker parents
|
|
11
|
+
* its job span on it (see `withTelemetrySpan`'s `traceparent` option).
|
|
12
|
+
*
|
|
13
|
+
* The value is built from and parsed into a span context directly rather than
|
|
14
|
+
* through the globally registered propagator: the propagator is whatever the
|
|
15
|
+
* host SDK installed (or a no-op in tests and in a process without telemetry),
|
|
16
|
+
* and a stored value must mean the same thing on every reader.
|
|
17
|
+
*/
|
|
18
|
+
// Version 00 only: a later version may append fields this reader cannot judge.
|
|
19
|
+
// Lowercase hex per the spec; all-zero trace/parent ids are explicitly invalid.
|
|
20
|
+
const TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
|
|
21
|
+
/** Parses a W3C `traceparent`; anything malformed or all-zero yields null. */
|
|
22
|
+
export function parseTraceparent(value) {
|
|
23
|
+
if (typeof value !== "string")
|
|
24
|
+
return null;
|
|
25
|
+
const match = TRACEPARENT_PATTERN.exec(value);
|
|
26
|
+
if (!match)
|
|
27
|
+
return null;
|
|
28
|
+
const spanContext = {
|
|
29
|
+
traceId: match[1],
|
|
30
|
+
spanId: match[2],
|
|
31
|
+
traceFlags: Number.parseInt(match[3], 16),
|
|
32
|
+
isRemote: true,
|
|
33
|
+
};
|
|
34
|
+
return isSpanContextValid(spanContext) ? spanContext : null;
|
|
35
|
+
}
|
|
36
|
+
/** The validated traceparent, or undefined — for optional fields that must drop bad input. */
|
|
37
|
+
export function validTraceparent(value) {
|
|
38
|
+
return parseTraceparent(value) ? value : undefined;
|
|
39
|
+
}
|
|
40
|
+
export function formatTraceparent(spanContext) {
|
|
41
|
+
if (!spanContext || !isSpanContextValid(spanContext))
|
|
42
|
+
return null;
|
|
43
|
+
const flags = (spanContext.traceFlags & 0xff).toString(16).padStart(2, "0");
|
|
44
|
+
return `00-${spanContext.traceId}-${spanContext.spanId}-${flags}`;
|
|
45
|
+
}
|
|
46
|
+
/** The `traceparent` of the currently active span, or null outside any span. */
|
|
47
|
+
export function activeTraceparent() {
|
|
48
|
+
return formatTraceparent(trace.getActiveSpan()?.spanContext());
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The parent context for a span that continues a stored traceparent.
|
|
52
|
+
*
|
|
53
|
+
* The remote span becomes the PARENT, so request -> job -> provider.* reads as
|
|
54
|
+
* one trace; whatever span was active (a worker cycle, the BullMQ runtime) is
|
|
55
|
+
* kept as a LINK so the scheduling side stays navigable. Every non-span context
|
|
56
|
+
* value (baggage, suppression flags) is preserved. Null for a missing or
|
|
57
|
+
* invalid traceparent: the caller then starts an ordinary child of the active
|
|
58
|
+
* context.
|
|
59
|
+
*/
|
|
60
|
+
export function remoteParentContext(traceparent) {
|
|
61
|
+
const remote = parseTraceparent(traceparent);
|
|
62
|
+
if (!remote)
|
|
63
|
+
return null;
|
|
64
|
+
const active = context.active();
|
|
65
|
+
const current = trace.getSpanContext(active);
|
|
66
|
+
return {
|
|
67
|
+
context: trace.setSpanContext(active, remote),
|
|
68
|
+
links: current && isSpanContextValid(current)
|
|
69
|
+
? [{ context: current, attributes: { "oxygen.link.kind": "worker.dispatch" } }]
|
|
70
|
+
: [],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Links the active span to a stored enqueue traceparent. For work that is
|
|
75
|
+
* already inside its execution span (a BullMQ `bullmq.execute`) and only learns
|
|
76
|
+
* the enqueuing request once it has loaded its own row: a link joins the two
|
|
77
|
+
* traces without a second per-job span. Returns whether a link was added.
|
|
78
|
+
*/
|
|
79
|
+
export function linkActiveSpanToTraceparent(traceparent) {
|
|
80
|
+
const remote = parseTraceparent(traceparent);
|
|
81
|
+
const span = trace.getActiveSpan();
|
|
82
|
+
if (!remote || !span || !isSpanContextValid(span.spanContext()))
|
|
83
|
+
return false;
|
|
84
|
+
if (span.spanContext().traceId === remote.traceId)
|
|
85
|
+
return false;
|
|
86
|
+
span.addLink({ context: remote, attributes: { "oxygen.link.kind": "enqueue" } });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
@@ -150,3 +150,18 @@ export type UgcVoiceImport = {
|
|
|
150
150
|
};
|
|
151
151
|
export declare const UGC_MONTHLY_CREATOR_CREDITS = 10000;
|
|
152
152
|
export declare const UGC_SPONSORED_LINKEDIN_SEATS = 1;
|
|
153
|
+
/**
|
|
154
|
+
* One label for a sponsor's row (`view=sponsorship`) on every surface, the web
|
|
155
|
+
* Creators tab and the MCP widget alike: a card sponsorship waiting on its
|
|
156
|
+
* checkout reads differently from one waiting on the provider, and a stopped
|
|
157
|
+
* renewal says so while its paid period runs.
|
|
158
|
+
*/
|
|
159
|
+
export declare function ugcSponsorshipStatusLabel(row: {
|
|
160
|
+
status: string;
|
|
161
|
+
checkout_url?: string | null;
|
|
162
|
+
cancellation_pending?: boolean;
|
|
163
|
+
}): string;
|
|
164
|
+
/** What confirming a credit-sponsorship quote does for one creator (`participants[].state`). */
|
|
165
|
+
export declare const UGC_SPONSORSHIP_PLAN_LABELS: Readonly<Record<string, string>>;
|
|
166
|
+
/** When a new credit sponsorship's reservation starts (`participants[].reservation_starts`). */
|
|
167
|
+
export declare const UGC_RESERVATION_START_LABELS: Readonly<Record<string, string>>;
|
|
@@ -10,3 +10,32 @@ export function ugcPostingTarget(program) {
|
|
|
10
10
|
}
|
|
11
11
|
export const UGC_MONTHLY_CREATOR_CREDITS = 10_000;
|
|
12
12
|
export const UGC_SPONSORED_LINKEDIN_SEATS = 1;
|
|
13
|
+
/**
|
|
14
|
+
* One label for a sponsor's row (`view=sponsorship`) on every surface, the web
|
|
15
|
+
* Creators tab and the MCP widget alike: a card sponsorship waiting on its
|
|
16
|
+
* checkout reads differently from one waiting on the provider, and a stopped
|
|
17
|
+
* renewal says so while its paid period runs.
|
|
18
|
+
*/
|
|
19
|
+
export function ugcSponsorshipStatusLabel(row) {
|
|
20
|
+
if (row.cancellation_pending)
|
|
21
|
+
return "Renewal stopping";
|
|
22
|
+
if (row.status === "active")
|
|
23
|
+
return "Sponsored";
|
|
24
|
+
if (row.status === "pending")
|
|
25
|
+
return row.checkout_url ? "Checkout open" : "Pending";
|
|
26
|
+
if (row.status === "cancelled")
|
|
27
|
+
return "Renewal stopped";
|
|
28
|
+
return "Not sponsored";
|
|
29
|
+
}
|
|
30
|
+
/** What confirming a credit-sponsorship quote does for one creator (`participants[].state`). */
|
|
31
|
+
export const UGC_SPONSORSHIP_PLAN_LABELS = {
|
|
32
|
+
new: "Starts",
|
|
33
|
+
already_active: "Already sponsored",
|
|
34
|
+
stripe_period_running: "Moves to credits when the card period ends",
|
|
35
|
+
checkout_open: "Card checkout still open; cancel it first",
|
|
36
|
+
};
|
|
37
|
+
/** When a new credit sponsorship's reservation starts (`participants[].reservation_starts`). */
|
|
38
|
+
export const UGC_RESERVATION_START_LABELS = {
|
|
39
|
+
now: "Now",
|
|
40
|
+
when_linkedin_connects: "When they connect LinkedIn",
|
|
41
|
+
};
|
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export declare const OXYGEN_VERSION: string;
|
|
2
|
-
export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.
|
|
3
|
-
export declare const MANAGED_INBOX_MINIMUM_CLI_VERSION = "1.326.2";
|
|
4
|
-
export declare const SUPPORT_AGENT_REPLY_MINIMUM_CLI_VERSION = "1.747.0";
|
|
2
|
+
export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.906.0";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OXYGEN_BUILD_VERSION = "1.1010.
|
|
1
|
+
export declare const OXYGEN_BUILD_VERSION = "1.1010.905";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// GENERATED by scripts/ci/version-stamp.mjs from VERSION + git history. Do not edit; do not commit.
|
|
2
|
-
export const OXYGEN_BUILD_VERSION = "1.1010.
|
|
2
|
+
export const OXYGEN_BUILD_VERSION = "1.1010.905";
|
|
@@ -26,7 +26,8 @@ export const OXYGEN_VERSION = OXYGEN_BUILD_VERSION;
|
|
|
26
26
|
// So floors LAG one release: publish the CLI in release N, raise the floor to it in
|
|
27
27
|
// release N+1. And a contract change that breaks ONE surface belongs on that
|
|
28
28
|
// surface — pass `minimumCliVersion` to requireCliIdentity/requireCliOrWebIdentity
|
|
29
|
-
// (
|
|
29
|
+
// (declare it here as <SURFACE>_MINIMUM_CLI_VERSION, above the global floor; the
|
|
30
|
+
// release gate checks it too). A per-route floor fails one command
|
|
30
31
|
// safely; a global floor fails the whole product. OXY-4091.
|
|
31
32
|
//
|
|
32
33
|
// 1.328.1: paid table action runs and background columns run require
|
|
@@ -34,29 +35,15 @@ export const OXYGEN_VERSION = OXYGEN_BUILD_VERSION;
|
|
|
34
35
|
// 1.328.1: LinkedIn → Sequencer rename moved the CLI/API/MCP surface
|
|
35
36
|
// (oxygen sequences|inbox|senders, /api/cli/{sequences,inbox,senders}) and
|
|
36
37
|
// removed the old /api/cli/linkedin/* routes — older CLIs would 404.
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
// on THIS route only. The floor lags one release per OXY-4091: the 1.326.2 CLI
|
|
50
|
-
// publishes from the 1.326.x prod deploy, and this floor rides the 1.330.0 release —
|
|
51
|
-
// so it can never exceed npm's newest CLI. (1.298.0 was the prior credits→Stripe
|
|
52
|
-
// contract move.) Do NOT raise the global OXYGEN_MINIMUM_CLI_VERSION for this.
|
|
53
|
-
export const MANAGED_INBOX_MINIMUM_CLI_VERSION = "1.326.2";
|
|
54
|
-
// Per-surface floor for guarded Plain agent reply + Done. CLI 1.747.0 is the
|
|
55
|
-
// first client that declares --agent, binds the latest customer-visible
|
|
56
|
-
// conversation-head message and
|
|
57
|
-
// body-authenticated preview token, carries the live agent_done_token into the
|
|
58
|
-
// separate Done confirmation, and never falls through to the retired resolve
|
|
59
|
-
// shape. This floor MUST remain dormant in production until 1.747.0 has been
|
|
60
|
-
// published by the preceding release per OXY-4091; the live feature gate is the
|
|
61
|
-
// rollout boundary that preserves that two-phase ordering.
|
|
62
|
-
export const SUPPORT_AGENT_REPLY_MINIMUM_CLI_VERSION = "1.747.0";
|
|
38
|
+
// 1.906.0 (2026-09-27): the floor had sat at 1.181.0, below both of those
|
|
39
|
+
// breaks, so CLIs that could no longer run paid actions or reach the Sequencer
|
|
40
|
+
// were still admitted. 1.906.0 has been the npm `latest` since 2026-08-29, far
|
|
41
|
+
// behind today's latest, so the lag rule holds. Measured before the raise
|
|
42
|
+
// (PostHog `cli_command_run`, PROD, 14 days): 9 of 87 active organizations
|
|
43
|
+
// were newest on an older CLI; each gets `cli_update_required` and one
|
|
44
|
+
// `oxygen update` away from working. CLIs that ship packages/cli/src/auto-update.ts
|
|
45
|
+
// update themselves on that rejection and re-run the command, so later raises
|
|
46
|
+
// stop costing a manual step — the lag rule still applies unchanged. The raise
|
|
47
|
+
// also retired both per-route floors, managed inboxes (1.326.2) and the guarded
|
|
48
|
+
// support agent reply (1.747.0): below the global floor they could refuse no one.
|
|
49
|
+
export const OXYGEN_MINIMUM_CLI_VERSION = "1.906.0";
|