@oxygen-agent/cli 1.987.20 → 1.1010.1

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 (176) hide show
  1. package/README.md +1 -1
  2. package/dist/admin-primary-providers-render.d.ts +0 -2
  3. package/dist/admin-primary-providers-render.js +1 -1
  4. package/dist/browser-login.js +1 -4
  5. package/dist/column-decision-options.d.ts +20 -0
  6. package/dist/column-decision-options.js +54 -0
  7. package/dist/command-manifest.d.ts +3 -2
  8. package/dist/command-manifest.js +25 -2
  9. package/dist/credentials.d.ts +1 -1
  10. package/dist/functions-commands.js +13 -9
  11. package/dist/help.d.ts +8 -0
  12. package/dist/help.js +46 -0
  13. package/dist/index.js +2751 -242
  14. package/dist/knowledge-mirror.d.ts +2 -2
  15. package/dist/runtime.d.ts +0 -15
  16. package/dist/runtime.js +1 -1
  17. package/dist/search-ai-filter-notice.d.ts +17 -0
  18. package/dist/search-ai-filter-notice.js +38 -0
  19. package/dist/session.d.ts +4 -3
  20. package/dist/skills.d.ts +8 -7
  21. package/dist/skills.js +58 -20
  22. package/dist/transcript.d.ts +2 -1
  23. package/dist/util.d.ts +10 -1
  24. package/dist/util.js +14 -2
  25. package/node_modules/@oxygen/cli-ugc/dist/commands.js +296 -140
  26. package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +9 -0
  27. package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +34 -0
  28. package/node_modules/@oxygen/formula/dist/coerce.d.ts +10 -0
  29. package/node_modules/@oxygen/formula/dist/coerce.js +10 -0
  30. package/node_modules/@oxygen/formula/dist/formula-functions.js +65 -0
  31. package/node_modules/@oxygen/formula/dist/hash.d.ts +19 -0
  32. package/node_modules/@oxygen/formula/dist/hash.js +199 -0
  33. package/node_modules/@oxygen/formula/dist/value-cleaners.d.ts +6 -1
  34. package/node_modules/@oxygen/formula/dist/value-cleaners.js +10 -26
  35. package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +13 -0
  36. package/node_modules/@oxygen/shared/dist/array-utils.d.ts +5 -0
  37. package/node_modules/@oxygen/shared/dist/array-utils.js +11 -0
  38. package/node_modules/@oxygen/shared/dist/billing.d.ts +99 -22
  39. package/node_modules/@oxygen/shared/dist/billing.js +195 -40
  40. package/node_modules/@oxygen/shared/dist/byok-connect.js +5 -0
  41. package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +27 -0
  42. package/node_modules/@oxygen/shared/dist/capability-discovery.js +311 -28
  43. package/node_modules/@oxygen/shared/dist/cli-http-error.d.ts +8 -0
  44. package/node_modules/@oxygen/shared/dist/cli-http-error.js +8 -0
  45. package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
  46. package/node_modules/@oxygen/shared/dist/column-autofill.d.ts +52 -0
  47. package/node_modules/@oxygen/shared/dist/column-autofill.js +62 -0
  48. package/node_modules/@oxygen/shared/dist/column-decision.d.ts +50 -0
  49. package/node_modules/@oxygen/shared/dist/column-decision.js +228 -0
  50. package/node_modules/@oxygen/shared/dist/column-output-fields.js +2 -6
  51. package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +113 -0
  52. package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +548 -0
  53. package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +6 -6
  54. package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +6 -6
  55. package/node_modules/@oxygen/shared/dist/cutover-freeze.d.ts +26 -0
  56. package/node_modules/@oxygen/shared/dist/cutover-freeze.js +52 -0
  57. package/node_modules/@oxygen/shared/dist/data-suppliers.d.ts +57 -0
  58. package/node_modules/@oxygen/shared/dist/data-suppliers.js +59 -0
  59. package/node_modules/@oxygen/shared/dist/deploy-env.d.ts +74 -0
  60. package/node_modules/@oxygen/shared/dist/deploy-env.js +82 -0
  61. package/node_modules/@oxygen/shared/dist/dnc-rules.d.ts +130 -0
  62. package/node_modules/@oxygen/shared/dist/dnc-rules.js +221 -0
  63. package/node_modules/@oxygen/shared/dist/enrichment-intents.d.ts +107 -0
  64. package/node_modules/@oxygen/shared/dist/enrichment-intents.js +809 -0
  65. package/node_modules/@oxygen/shared/dist/error-message.d.ts +1 -0
  66. package/node_modules/@oxygen/shared/dist/error-message.js +3 -0
  67. package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -3
  68. package/node_modules/@oxygen/shared/dist/external-write-policy.d.ts +33 -0
  69. package/node_modules/@oxygen/shared/dist/external-write-policy.js +68 -0
  70. package/node_modules/@oxygen/shared/dist/format-percent.d.ts +8 -0
  71. package/node_modules/@oxygen/shared/dist/format-percent.js +13 -0
  72. package/node_modules/@oxygen/shared/dist/freemail-domains.d.ts +81 -0
  73. package/node_modules/@oxygen/shared/dist/freemail-domains.js +157 -0
  74. package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.d.ts +1 -0
  75. package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.js +1 -1
  76. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +60 -4
  77. package/node_modules/@oxygen/shared/dist/hosted-ai.js +125 -10
  78. package/node_modules/@oxygen/shared/dist/index.d.ts +15 -0
  79. package/node_modules/@oxygen/shared/dist/index.js +15 -0
  80. package/node_modules/@oxygen/shared/dist/json-path.js +1 -3
  81. package/node_modules/@oxygen/shared/dist/knowledge-bases.js +1 -3
  82. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +2 -2
  83. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +2 -2
  84. package/node_modules/@oxygen/shared/dist/langfuse.d.ts +44 -1
  85. package/node_modules/@oxygen/shared/dist/langfuse.js +416 -14
  86. package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +33 -0
  87. package/node_modules/@oxygen/shared/dist/linkedin-countries.js +361 -0
  88. package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.d.ts +24 -0
  89. package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.js +276 -0
  90. package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.d.ts +2 -0
  91. package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.js +5 -0
  92. package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.d.ts +44 -0
  93. package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.js +116 -0
  94. package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +96 -0
  95. package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +123 -0
  96. package/node_modules/@oxygen/shared/dist/llm-durable-capture.d.ts +24 -0
  97. package/node_modules/@oxygen/shared/dist/llm-durable-capture.js +89 -0
  98. package/node_modules/@oxygen/shared/dist/llm-prompts.d.ts +75 -0
  99. package/node_modules/@oxygen/shared/dist/llm-prompts.js +161 -0
  100. package/node_modules/@oxygen/shared/dist/log-sink-selector.d.ts +39 -0
  101. package/node_modules/@oxygen/shared/dist/log-sink-selector.js +56 -0
  102. package/node_modules/@oxygen/shared/dist/log.d.ts +1 -0
  103. package/node_modules/@oxygen/shared/dist/log.js +6 -1
  104. package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +90 -0
  105. package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.js +130 -0
  106. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +17 -0
  107. package/node_modules/@oxygen/shared/dist/object-storage.js +21 -0
  108. package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +24 -0
  109. package/node_modules/@oxygen/shared/dist/operational-telemetry.js +73 -0
  110. package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +79 -0
  111. package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +366 -0
  112. package/node_modules/@oxygen/shared/dist/plan-capabilities.js +1 -0
  113. package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +23 -22
  114. package/node_modules/@oxygen/shared/dist/plan-limits.js +45 -18
  115. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +48 -41
  116. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +36 -25
  117. package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +22 -22
  118. package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +40 -34
  119. package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +9 -0
  120. package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +36 -2
  121. package/node_modules/@oxygen/shared/dist/product-analytics-events.js +36 -1
  122. package/node_modules/@oxygen/shared/dist/rate-window.d.ts +5 -0
  123. package/node_modules/@oxygen/shared/dist/rate-window.js +8 -0
  124. package/node_modules/@oxygen/shared/dist/redaction.js +4 -1
  125. package/node_modules/@oxygen/shared/dist/research-output-contract.js +1 -3
  126. package/node_modules/@oxygen/shared/dist/scraper-lane-credential.d.ts +18 -0
  127. package/node_modules/@oxygen/shared/dist/scraper-lane-credential.js +23 -0
  128. package/node_modules/@oxygen/shared/dist/search-vocab.js +4 -5
  129. package/node_modules/@oxygen/shared/dist/select-options.js +6 -1
  130. package/node_modules/@oxygen/shared/dist/sequence-failures.js +1 -5
  131. package/node_modules/@oxygen/shared/dist/sequences.d.ts +23 -0
  132. package/node_modules/@oxygen/shared/dist/sequences.js +115 -5
  133. package/node_modules/@oxygen/shared/dist/signup-lead-payload.d.ts +80 -0
  134. package/node_modules/@oxygen/shared/dist/signup-lead-payload.js +198 -0
  135. package/node_modules/@oxygen/shared/dist/social-capabilities.d.ts +6 -0
  136. package/node_modules/@oxygen/shared/dist/social-capabilities.js +25 -16
  137. package/node_modules/@oxygen/shared/dist/social-post-metrics-core.d.ts +32 -0
  138. package/node_modules/@oxygen/shared/dist/social-post-metrics-core.js +32 -0
  139. package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.d.ts +31 -0
  140. package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.js +103 -0
  141. package/node_modules/@oxygen/shared/dist/social-post-metrics-series.d.ts +96 -0
  142. package/node_modules/@oxygen/shared/dist/social-post-metrics-series.js +213 -0
  143. package/node_modules/@oxygen/shared/dist/social-post-metrics-x.d.ts +13 -0
  144. package/node_modules/@oxygen/shared/dist/social-post-metrics-x.js +78 -0
  145. package/node_modules/@oxygen/shared/dist/social-post-metrics.d.ts +36 -0
  146. package/node_modules/@oxygen/shared/dist/social-post-metrics.js +51 -0
  147. package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +22 -10
  148. package/node_modules/@oxygen/shared/dist/spend-safety.js +15 -21
  149. package/node_modules/@oxygen/shared/dist/sql-rows.d.ts +1 -0
  150. package/node_modules/@oxygen/shared/dist/sql-rows.js +3 -0
  151. package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +36 -0
  152. package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +184 -0
  153. package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.d.ts +41 -0
  154. package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.js +44 -0
  155. package/node_modules/@oxygen/shared/dist/table-limits.d.ts +3 -0
  156. package/node_modules/@oxygen/shared/dist/table-limits.js +3 -0
  157. package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +94 -0
  158. package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +298 -0
  159. package/node_modules/@oxygen/shared/dist/telemetry.d.ts +11 -0
  160. package/node_modules/@oxygen/shared/dist/telemetry.js +28 -2
  161. package/node_modules/@oxygen/shared/dist/type-guards.d.ts +22 -0
  162. package/node_modules/@oxygen/shared/dist/type-guards.js +35 -0
  163. package/node_modules/@oxygen/shared/dist/ugc.d.ts +22 -11
  164. package/node_modules/@oxygen/shared/dist/ugc.js +10 -0
  165. package/node_modules/@oxygen/shared/dist/value-readers.d.ts +21 -0
  166. package/node_modules/@oxygen/shared/dist/value-readers.js +59 -0
  167. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -0
  168. package/node_modules/@oxygen/shared/dist/version.generated.js +2 -0
  169. package/node_modules/@oxygen/shared/dist/version.js +8 -1
  170. package/node_modules/@oxygen/shared/dist/workspace-event-catalog.js +0 -23
  171. package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +29 -0
  172. package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +31 -0
  173. package/node_modules/@oxygen/shared/package.json +59 -0
  174. package/node_modules/@oxygen/workflows/dist/graph/expression.js +2 -5
  175. package/node_modules/@oxygen/workflows/dist/graph/params.js +1 -1
  176. package/package.json +3 -2
@@ -3,6 +3,17 @@ export type WithTelemetrySpanOptions = {
3
3
  isTransient?: (error: unknown) => boolean;
4
4
  };
5
5
  export declare function withTelemetrySpan<T>(tracerName: string, name: string, attributes: TelemetryAttributes | undefined, fn: () => Promise<T>, options?: WithTelemetrySpanOptions): Promise<T>;
6
+ /**
7
+ * The active global span's trace id: the join key into SigNoz/Axiom traces.
8
+ * Null when no valid span is active (a BullMQ job outside any span, a test).
9
+ */
10
+ export declare function activeTelemetryTraceId(): string | null;
11
+ /**
12
+ * Run `fn` inside a new span only when no span is active, so work that already
13
+ * sits under a request/cycle span keeps that trace and uncorrelated background
14
+ * work (BullMQ jobs) still gets one trace id to cross-link from Langfuse.
15
+ */
16
+ export declare function withTelemetrySpanIfNone<T>(tracerName: string, name: string, attributes: TelemetryAttributes | undefined, fn: () => Promise<T>): Promise<T>;
6
17
  export declare function setActiveTelemetryAttributes(attributes: TelemetryAttributes): void;
7
18
  export declare function markActiveTelemetryError(message: string, attributes?: TelemetryAttributes): void;
8
19
  export declare function recordTelemetryCounter(name: string, value?: number, attributes?: TelemetryAttributes): void;
@@ -1,4 +1,5 @@
1
- import { SpanStatusCode, metrics, trace, } from "@opentelemetry/api";
1
+ import { SpanStatusCode, isSpanContextValid, metrics, trace, } from "@opentelemetry/api";
2
+ import { deployEnvTelemetryEnvironment, deployPlatformAttribute } from "./deploy-env.js";
2
3
  import { errorId } from "./log.js";
3
4
  import { normalizeTelemetryAttributes } from "./redaction.js";
4
5
  import { redactSqlParameters, sqlErrorTelemetryAttributes } from "./sql-error.js";
@@ -38,6 +39,24 @@ export async function withTelemetrySpan(tracerName, name, attributes, fn, option
38
39
  }
39
40
  });
40
41
  }
42
+ /**
43
+ * The active global span's trace id: the join key into SigNoz/Axiom traces.
44
+ * Null when no valid span is active (a BullMQ job outside any span, a test).
45
+ */
46
+ export function activeTelemetryTraceId() {
47
+ const spanContext = trace.getActiveSpan()?.spanContext();
48
+ return spanContext && isSpanContextValid(spanContext) ? spanContext.traceId : null;
49
+ }
50
+ /**
51
+ * Run `fn` inside a new span only when no span is active, so work that already
52
+ * sits under a request/cycle span keeps that trace and uncorrelated background
53
+ * work (BullMQ jobs) still gets one trace id to cross-link from Langfuse.
54
+ */
55
+ export async function withTelemetrySpanIfNone(tracerName, name, attributes, fn) {
56
+ if (activeTelemetryTraceId())
57
+ return await fn();
58
+ return await withTelemetrySpan(tracerName, name, attributes, fn);
59
+ }
41
60
  export function setActiveTelemetryAttributes(attributes) {
42
61
  const span = trace.getActiveSpan();
43
62
  if (!span)
@@ -73,7 +92,14 @@ export function commonTelemetryAttributes(attributes) {
73
92
  const pick = (workerKeys, webKeys) => pickEnvBySurface(workerProcess, workerKeys, webKeys);
74
93
  return {
75
94
  "oxygen.version": OXYGEN_VERSION,
76
- "deployment.environment": pick(["FLY_ENVIRONMENT", "NODE_ENV"], ["VERCEL_ENV", "NODE_ENV"]),
95
+ // Which infrastructure this process runs on, so a self-hosted span is
96
+ // never mistaken for a managed one while both targets are live.
97
+ "oxygen.platform": deployPlatformAttribute(),
98
+ // OXYGEN_DEPLOY_ENV is consulted first and is the only signal a self-hosted
99
+ // box has: it carries neither FLY_ENVIRONMENT nor VERCEL_ENV, so without
100
+ // this the whole fleet would report its NODE_ENV and collapse prod, shadow
101
+ // and dev into one bucket. Unset leaves the managed chain untouched.
102
+ "deployment.environment": deployEnvTelemetryEnvironment() ?? pick(["FLY_ENVIRONMENT", "NODE_ENV"], ["VERCEL_ENV", "NODE_ENV"]),
77
103
  // deployment.sha stays the deploy artifact id: the Fly registry image ref on
78
104
  // the worker (release cross-reference), VERCEL_GIT_COMMIT_SHA on the web. The
79
105
  // worker's image ref is NOT a git commit, so deployment.git_sha carries the
@@ -13,3 +13,25 @@
13
13
  * `Record<string, unknown>`. Rejects `null`, arrays, and every primitive.
14
14
  */
15
15
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
16
+ /**
17
+ * `value` as a `Record<string, unknown>` when it is a non-null, non-array
18
+ * object, else null.
19
+ */
20
+ export declare function asRecordOrNull(value: unknown): Record<string, unknown> | null;
21
+ /** Alias of {@link asRecordOrNull} for call sites that spell it `asRecord`. */
22
+ export declare const asRecord: typeof asRecordOrNull;
23
+ /**
24
+ * `value` as a `Record<string, unknown>`, falling back to an empty object.
25
+ * Deliberately masks "absent" and "present but wrong shape" the same way its
26
+ * call sites always have — use {@link asRecordOrNull} when that matters.
27
+ */
28
+ export declare function asRecordOrEmpty(value: unknown): Record<string, unknown>;
29
+ /** Finite number, else null. Does not parse numeric strings. */
30
+ export declare function readFiniteNumber(value: unknown): number | null;
31
+ /** Trimmed non-empty string, else null. */
32
+ export declare function readTrimmedString(value: unknown): string | null;
33
+ /**
34
+ * Trimmed non-empty string, else null — additionally coercing a number to its
35
+ * string form. Distinct from {@link readTrimmedString}, which rejects numbers.
36
+ */
37
+ export declare function readCoercedString(value: unknown): string | null;
@@ -15,3 +15,38 @@
15
15
  export function isRecord(value) {
16
16
  return typeof value === "object" && value !== null && !Array.isArray(value);
17
17
  }
18
+ /**
19
+ * `value` as a `Record<string, unknown>` when it is a non-null, non-array
20
+ * object, else null.
21
+ */
22
+ export function asRecordOrNull(value) {
23
+ return isRecord(value) ? value : null;
24
+ }
25
+ /** Alias of {@link asRecordOrNull} for call sites that spell it `asRecord`. */
26
+ export const asRecord = asRecordOrNull;
27
+ /**
28
+ * `value` as a `Record<string, unknown>`, falling back to an empty object.
29
+ * Deliberately masks "absent" and "present but wrong shape" the same way its
30
+ * call sites always have — use {@link asRecordOrNull} when that matters.
31
+ */
32
+ export function asRecordOrEmpty(value) {
33
+ return isRecord(value) ? value : {};
34
+ }
35
+ /** Finite number, else null. Does not parse numeric strings. */
36
+ export function readFiniteNumber(value) {
37
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
38
+ }
39
+ /** Trimmed non-empty string, else null. */
40
+ export function readTrimmedString(value) {
41
+ return typeof value === "string" && value.trim() ? value.trim() : null;
42
+ }
43
+ /**
44
+ * Trimmed non-empty string, else null — additionally coercing a number to its
45
+ * string form. Distinct from {@link readTrimmedString}, which rejects numbers.
46
+ */
47
+ export function readCoercedString(value) {
48
+ if (typeof value !== "string" && typeof value !== "number")
49
+ return null;
50
+ const trimmed = String(value).trim();
51
+ return trimmed ? trimmed : null;
52
+ }
@@ -1,5 +1,20 @@
1
1
  /** UGC is a Publishing capability. These are projections, never a second Posts store. */
2
2
  export type UgcApprovalMode = "creator" | "delegated";
3
+ /** Per calendar week or month, or `total`: N posts over the program's lifetime. */
4
+ export type UgcPostingTargetPeriod = "week" | "month" | "total";
5
+ export type UgcPostingTarget = {
6
+ count: number;
7
+ period: UgcPostingTargetPeriod;
8
+ };
9
+ export declare const UGC_POSTING_TARGET_MAX = 100;
10
+ export declare const UGC_POSTING_TARGET_PERIODS: readonly ["week", "month", "total"];
11
+ /** The operator-written creator brief is short by design (Philipp, 2026-09-23). */
12
+ export declare const UGC_PROGRAM_BRIEF_MAX_CHARS = 1200;
13
+ /** The program's target as its API shape, or null when none is set. */
14
+ export declare function ugcPostingTarget(program: {
15
+ postingTargetCount?: number | null | undefined;
16
+ postingTargetPeriod?: UgcPostingTargetPeriod | null | undefined;
17
+ }): UgcPostingTarget | null;
3
18
  export type UgcProgram = {
4
19
  id: string;
5
20
  name: string;
@@ -10,20 +25,17 @@ export type UgcProgram = {
10
25
  peerEngagementEnabled?: boolean;
11
26
  peerEngagementVersion?: number;
12
27
  peerEngagementEffectiveAt?: Date | null;
28
+ /** The product's icon, found from its site at create; null for older programs. */
29
+ iconUrl?: string | null;
30
+ /** Short operator-written creator brief; drafts are grounded in it. */
31
+ brief?: string | null;
32
+ /** Posts each creator is expected to publish per period; both null when unset. */
33
+ postingTargetCount?: number | null;
34
+ postingTargetPeriod?: UgcPostingTargetPeriod | null;
13
35
  status: "active" | "archived";
14
36
  createdAt: Date;
15
37
  updatedAt: Date;
16
38
  };
17
- export type UgcBrief = {
18
- id: string;
19
- programId: string;
20
- title: string;
21
- prompt: string;
22
- questions: string[];
23
- cycle: string | null;
24
- createdAt: Date;
25
- updatedAt: Date;
26
- };
27
39
  export type UgcPostProjection = {
28
40
  /** Public author identity from the exact participation, never a private profile corpus. */
29
41
  authorLinkedinUrl?: string;
@@ -84,7 +96,6 @@ export type UgcPostLink = {
84
96
  masterOrgId: string;
85
97
  brandApprovalRequired: boolean;
86
98
  sourcePostId: string;
87
- briefId: string | null;
88
99
  attribution: Record<string, unknown>;
89
100
  projection: UgcPostProjection;
90
101
  sourceRevision: string;
@@ -1,2 +1,12 @@
1
+ export const UGC_POSTING_TARGET_MAX = 100;
2
+ export const UGC_POSTING_TARGET_PERIODS = ["week", "month", "total"];
3
+ /** The operator-written creator brief is short by design (Philipp, 2026-09-23). */
4
+ export const UGC_PROGRAM_BRIEF_MAX_CHARS = 1200;
5
+ /** The program's target as its API shape, or null when none is set. */
6
+ export function ugcPostingTarget(program) {
7
+ return program.postingTargetCount && program.postingTargetPeriod
8
+ ? { count: program.postingTargetCount, period: program.postingTargetPeriod }
9
+ : null;
10
+ }
1
11
  export const UGC_MONTHLY_CREATOR_CREDITS = 10_000;
2
12
  export const UGC_SPONSORED_LINKEDIN_SEATS = 1;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Canonical readers that coerce an `unknown` value (or a field of an untyped
3
+ * record) into a string/number, used across every OXYGEN package.
4
+ */
5
+ /** Trimmed non-empty string, else null. */
6
+ export declare function readString(value: unknown): string | null;
7
+ /** The first key in `keys` whose value is a non-empty string, trimmed. */
8
+ export declare function readFirstString(source: Record<string, unknown>, keys: string[]): string | null;
9
+ /** The first key in `keys` on `record` holding a non-empty string, trimmed. */
10
+ export declare function readStringField(record: Record<string, unknown>, keys: string[]): string | null;
11
+ /** Walk a dot-separated path through nested records; undefined when it breaks. */
12
+ export declare function readByPath(value: unknown, path: string): unknown;
13
+ /** Trimmed non-empty string, else null. */
14
+ export declare function readStringValue(value: unknown): string | null;
15
+ /**
16
+ * Non-empty string returned VERBATIM: emptiness is tested on the trimmed form
17
+ * but the original value is returned, so stored values keep their whitespace.
18
+ */
19
+ export declare function readStringValueUntrimmed(value: unknown): string | null;
20
+ /** Finite number, else null. Does not parse numeric strings. */
21
+ export declare function readNumberValue(value: unknown): number | null;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Canonical readers that coerce an `unknown` value (or a field of an untyped
3
+ * record) into a string/number, used across every OXYGEN package.
4
+ */
5
+ import { isRecord } from "./type-guards.js";
6
+ /** Trimmed non-empty string, else null. */
7
+ export function readString(value) {
8
+ return typeof value === "string" && value.trim() ? value.trim() : null;
9
+ }
10
+ /** The first key in `keys` whose value is a non-empty string, trimmed. */
11
+ export function readFirstString(source, keys) {
12
+ for (const key of keys) {
13
+ const value = source[key];
14
+ if (typeof value !== "string")
15
+ continue;
16
+ const trimmed = value.trim();
17
+ if (trimmed)
18
+ return trimmed;
19
+ }
20
+ return null;
21
+ }
22
+ /** The first key in `keys` on `record` holding a non-empty string, trimmed. */
23
+ export function readStringField(record, keys) {
24
+ for (const key of keys) {
25
+ const value = record[key];
26
+ if (typeof value === "string" && value.trim())
27
+ return value.trim();
28
+ }
29
+ return null;
30
+ }
31
+ /** Walk a dot-separated path through nested records; undefined when it breaks. */
32
+ export function readByPath(value, path) {
33
+ if (!path)
34
+ return value;
35
+ let current = value;
36
+ for (const segment of path.split(".")) {
37
+ if (!segment)
38
+ continue;
39
+ if (!isRecord(current))
40
+ return undefined;
41
+ current = current[segment];
42
+ }
43
+ return current;
44
+ }
45
+ /** Trimmed non-empty string, else null. */
46
+ export function readStringValue(value) {
47
+ return typeof value === "string" && value.trim() ? value.trim() : null;
48
+ }
49
+ /**
50
+ * Non-empty string returned VERBATIM: emptiness is tested on the trimmed form
51
+ * but the original value is returned, so stored values keep their whitespace.
52
+ */
53
+ export function readStringValueUntrimmed(value) {
54
+ return typeof value === "string" && value.trim() ? value : null;
55
+ }
56
+ /** Finite number, else null. Does not parse numeric strings. */
57
+ export function readNumberValue(value) {
58
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
59
+ }
@@ -0,0 +1 @@
1
+ export declare const OXYGEN_BUILD_VERSION = "1.1010.1";
@@ -0,0 +1,2 @@
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.1";
@@ -1,6 +1,13 @@
1
+ import { OXYGEN_BUILD_VERSION } from "./version.generated.js";
1
2
  // Release metadata is a string API: a new version must not change the exported
2
3
  // declaration type and invalidate every dependent package's compiler state.
3
- export const OXYGEN_VERSION = "1.987.20";
4
+ //
5
+ // The value is DERIVED, never pinned per commit: the repo-root `VERSION` file
6
+ // holds the series (`1.<minor>`) and the patch is the distance from the commit
7
+ // that last touched it. scripts/ci/version-stamp.mjs writes
8
+ // ./version.generated.ts (gitignored) at build, test and publish time. Change
9
+ // the series by editing VERSION; there is nothing to bump here.
10
+ export const OXYGEN_VERSION = OXYGEN_BUILD_VERSION;
4
11
  // The GLOBAL CLI compatibility floor: the oldest CLI allowed to call any
5
12
  // operational route. Raising it hard-rejects every older CLI from the entire
6
13
  // product, so it obeys one law, enforced by scripts/ci/cli-min-version-gate.mjs:
@@ -3,7 +3,6 @@ import { CRM_SIGNAL_WORKFLOW_EVENT_DEFINITIONS, CRM_WORKFLOW_EVENT_SOURCE, } fro
3
3
  import { SEQUENCE_CONTACT_ACTIVITY_EVENT, SEQUENCE_CRM_EVENT_DEFINITIONS, SEQUENCE_WORKFLOW_EVENT_SOURCE, } from "./sequence-crm-events.js";
4
4
  import { SEQUENCE_ENROLLMENT_TERMINAL_EVENT, SEQUENCE_TERMINAL_EVENT_SOURCE, SEQUENCE_TERMINAL_STATUSES, } from "./sequence-terminal-events.js";
5
5
  import { NOTETAKER_MEETING_COMPLETED_EVENT, NOTETAKER_MEETING_COMPLETED_PAYLOAD_FIELDS, NOTETAKER_WORKFLOW_EVENT_SOURCE, } from "./notetaker-events.js";
6
- import { PLAIN_SUPPORT_MESSAGE_RECEIVED_EVENT, PLAIN_SUPPORT_MESSAGE_RECEIVED_PAYLOAD_FIELDS, PLAIN_SUPPORT_WORKFLOW_EVENT_SOURCE, } from "./plain-support-events.js";
7
6
  export const WORKSPACE_EVENT_PRODUCER_READINESS_REQUIREMENTS = [
8
7
  "always",
9
8
  "notetaker_enabled",
@@ -107,15 +106,6 @@ export const WORKSPACE_EVENT_PRODUCERS = [
107
106
  readiness: "notetaker_enabled",
108
107
  payloadFields: NOTETAKER_MEETING_COMPLETED_PAYLOAD_FIELDS,
109
108
  },
110
- {
111
- id: "plain_support.message_received",
112
- source: PLAIN_SUPPORT_WORKFLOW_EVENT_SOURCE,
113
- event: PLAIN_SUPPORT_MESSAGE_RECEIVED_EVENT,
114
- delivery: "direct_durable_write",
115
- idempotency: "The verified Plain event id deduplicates metadata-only support delivery.",
116
- readiness: "always",
117
- payloadFields: PLAIN_SUPPORT_MESSAGE_RECEIVED_PAYLOAD_FIELDS,
118
- },
119
109
  ];
120
110
  const workspaceEventProducersById = new Map(WORKSPACE_EVENT_PRODUCERS.map((producer) => [producer.id, producer]));
121
111
  export function getWorkspaceEventProducer(producerId) {
@@ -224,18 +214,6 @@ const crmSignalEntries = CRM_SIGNAL_WORKFLOW_EVENT_DEFINITIONS.map((definition)
224
214
  description: definition.description,
225
215
  payloadFields: definition.payloadFields,
226
216
  }));
227
- const plainSupportEntries = [
228
- {
229
- id: "plain_support.message_received",
230
- producerId: "plain_support.message_received",
231
- source: PLAIN_SUPPORT_WORKFLOW_EVENT_SOURCE,
232
- event: PLAIN_SUPPORT_MESSAGE_RECEIVED_EVENT,
233
- group: "Support · Plain",
234
- label: "Customer message received",
235
- description: "A customer sent a Chat, email, Slack, Microsoft Teams, or Discord message into a canonical Plain Thread. The event contains routing metadata only; customer content remains in Plain.",
236
- payloadFields: PLAIN_SUPPORT_MESSAGE_RECEIVED_PAYLOAD_FIELDS,
237
- },
238
- ];
239
217
  const notetakerEntries = [
240
218
  {
241
219
  id: "notetaker.meeting_completed",
@@ -257,6 +235,5 @@ export const WORKSPACE_EVENT_CATALOG = [
257
235
  ...sequenceTerminalEntries,
258
236
  ...crmActivityEntries,
259
237
  ...crmSignalEntries,
260
- ...plainSupportEntries,
261
238
  ...notetakerEntries,
262
239
  ];
@@ -32,6 +32,35 @@ export declare function readWorkspaceFileObject(input: {
32
32
  mimeType: WorkspaceStoredFileMimeType;
33
33
  signal?: AbortSignal;
34
34
  }): Promise<Uint8Array>;
35
+ /** How long a presigned workspace-file upload stays valid. Long enough for 100 MiB on a slow link. */
36
+ export declare const WORKSPACE_FILE_UPLOAD_PRESIGN_SECONDS = 900;
37
+ /**
38
+ * A presigned PUT for an opaque workspace file whose bytes never pass through
39
+ * the API.
40
+ *
41
+ * The base64-in-JSON path is bounded by the JSON body ceiling (2,000,000
42
+ * bytes, so ~1.5 MB of file) and, on managed production, by the platform's
43
+ * request-body limit — while the store itself allows 100 MiB. The browser and
44
+ * the CLI PUT the bytes straight to object storage instead; the caller declares
45
+ * the size and digest up front (the reservation needs both), and completion
46
+ * runs readWorkspaceFileObject, the same verified readback every stored file
47
+ * gets, so an upload that does not match what was declared is never finalized.
48
+ *
49
+ * `content-type` is signed (the SDK's default is to leave it unsigned) so the
50
+ * stored object's type is the opaque one this store expects; `content-length`
51
+ * is signed by the presigner from ContentLength.
52
+ */
53
+ export declare function presignWorkspaceFileUpload(input: {
54
+ organizationId: string;
55
+ fileId: string;
56
+ fileName: string;
57
+ sizeBytes: number;
58
+ }): Promise<{
59
+ uploadUrl: string;
60
+ storageKey: string;
61
+ expiresInSeconds: number;
62
+ contentType: WorkspaceStoredFileMimeType;
63
+ }>;
35
64
  /** Immutable PUT followed by bounded readback. A matching existing object is a safe retry. */
36
65
  export declare function putWorkspaceFileObject(input: {
37
66
  organizationId: string;
@@ -1,6 +1,7 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { createHash } from "node:crypto";
3
3
  import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
4
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
4
5
  import { OxygenError } from "./cli-result.js";
5
6
  import { resolveObjectStorageClient } from "./object-storage.js";
6
7
  export const WORKSPACE_VISUAL_SOURCE_MAX_BYTES = 1_500_000;
@@ -112,6 +113,36 @@ export async function readWorkspaceFileObject(input) {
112
113
  stream.destroy?.();
113
114
  }
114
115
  }
116
+ /** How long a presigned workspace-file upload stays valid. Long enough for 100 MiB on a slow link. */
117
+ export const WORKSPACE_FILE_UPLOAD_PRESIGN_SECONDS = 900;
118
+ /**
119
+ * A presigned PUT for an opaque workspace file whose bytes never pass through
120
+ * the API.
121
+ *
122
+ * The base64-in-JSON path is bounded by the JSON body ceiling (2,000,000
123
+ * bytes, so ~1.5 MB of file) and, on managed production, by the platform's
124
+ * request-body limit — while the store itself allows 100 MiB. The browser and
125
+ * the CLI PUT the bytes straight to object storage instead; the caller declares
126
+ * the size and digest up front (the reservation needs both), and completion
127
+ * runs readWorkspaceFileObject, the same verified readback every stored file
128
+ * gets, so an upload that does not match what was declared is never finalized.
129
+ *
130
+ * `content-type` is signed (the SDK's default is to leave it unsigned) so the
131
+ * stored object's type is the opaque one this store expects; `content-length`
132
+ * is signed by the presigner from ContentLength.
133
+ */
134
+ export async function presignWorkspaceFileUpload(input) {
135
+ if (!Number.isSafeInteger(input.sizeBytes) || input.sizeBytes < 0 || input.sizeBytes > WORKSPACE_OPAQUE_FILE_MAX_BYTES) {
136
+ throw new OxygenError("workspace_file_too_large", "File exceeds 100 MiB.");
137
+ }
138
+ const storageKey = buildWorkspaceFileObjectKey(input);
139
+ const { client, bucket } = resolveObjectStorageClient();
140
+ const contentType = "application/octet-stream";
141
+ const uploadUrl = await getSignedUrl(client, new PutObjectCommand({
142
+ Bucket: bucket, Key: storageKey, ContentLength: input.sizeBytes, ContentType: contentType,
143
+ }), { expiresIn: WORKSPACE_FILE_UPLOAD_PRESIGN_SECONDS, signableHeaders: new Set(["content-type"]) });
144
+ return { uploadUrl, storageKey, expiresInSeconds: WORKSPACE_FILE_UPLOAD_PRESIGN_SECONDS, contentType };
145
+ }
115
146
  /** Immutable PUT followed by bounded readback. A matching existing object is a safe retry. */
116
147
  export async function putWorkspaceFileObject(input) {
117
148
  input.signal?.throwIfAborted();
@@ -96,6 +96,16 @@
96
96
  "import": "./dist/person-name.js",
97
97
  "default": "./dist/person-name.js"
98
98
  },
99
+ "./linkedin-countries": {
100
+ "types": "./dist/linkedin-countries.d.ts",
101
+ "import": "./dist/linkedin-countries.js",
102
+ "default": "./dist/linkedin-countries.js"
103
+ },
104
+ "./freemail-domains": {
105
+ "types": "./dist/freemail-domains.d.ts",
106
+ "import": "./dist/freemail-domains.js",
107
+ "default": "./dist/freemail-domains.js"
108
+ },
99
109
  "./select-options": {
100
110
  "types": "./dist/select-options.d.ts",
101
111
  "import": "./dist/select-options.js",
@@ -121,6 +131,21 @@
121
131
  "import": "./dist/cli-result.js",
122
132
  "default": "./dist/cli-result.js"
123
133
  },
134
+ "./type-guards": {
135
+ "types": "./dist/type-guards.d.ts",
136
+ "import": "./dist/type-guards.js",
137
+ "default": "./dist/type-guards.js"
138
+ },
139
+ "./value-readers": {
140
+ "types": "./dist/value-readers.d.ts",
141
+ "import": "./dist/value-readers.js",
142
+ "default": "./dist/value-readers.js"
143
+ },
144
+ "./timing": {
145
+ "types": "./dist/timing.d.ts",
146
+ "import": "./dist/timing.js",
147
+ "default": "./dist/timing.js"
148
+ },
124
149
  "./custom-http-safety": {
125
150
  "types": "./dist/custom-http-safety.d.ts",
126
151
  "import": "./dist/custom-http-safety.js",
@@ -141,6 +166,11 @@
141
166
  "import": "./dist/signup-lead-webhook.js",
142
167
  "default": "./dist/signup-lead-webhook.js"
143
168
  },
169
+ "./signup-lead-payload": {
170
+ "types": "./dist/signup-lead-payload.d.ts",
171
+ "import": "./dist/signup-lead-payload.js",
172
+ "default": "./dist/signup-lead-payload.js"
173
+ },
144
174
  "./knowledge-constants": {
145
175
  "types": "./dist/knowledge-constants.d.ts",
146
176
  "import": "./dist/knowledge-constants.js",
@@ -225,6 +255,35 @@
225
255
  "types": "./dist/workspace-file-storage.d.ts",
226
256
  "import": "./dist/workspace-file-storage.js",
227
257
  "default": "./dist/workspace-file-storage.js"
258
+ },
259
+ "./company-enrichment-fields": {
260
+ "types": "./dist/company-enrichment-fields.d.ts",
261
+ "import": "./dist/company-enrichment-fields.js",
262
+ "default": "./dist/company-enrichment-fields.js"
263
+ },
264
+ "./*": {
265
+ "types": "./dist/*.d.ts",
266
+ "import": "./dist/*.js",
267
+ "default": "./dist/*.js"
268
+ },
269
+ "./enrichment-intents": {
270
+ "types": "./dist/enrichment-intents.d.ts",
271
+ "import": "./dist/enrichment-intents.js",
272
+ "default": "./dist/enrichment-intents.js"
273
+ },
274
+ "./log": {
275
+ "types": "./dist/log.d.ts",
276
+ "import": "./dist/log.js",
277
+ "default": "./dist/log.js"
278
+ },
279
+ "./linkedin-sequences": {
280
+ "types": "./dist/linkedin-sequences.d.ts",
281
+ "import": "./dist/linkedin-sequences.js",
282
+ "default": "./dist/linkedin-sequences.js"
283
+ },
284
+ "./provider-balance-signal": {
285
+ "types": "./dist/provider-balance-signal.d.ts",
286
+ "import": "./dist/provider-balance-signal.js"
228
287
  }
229
288
  },
230
289
  "dependencies": {}
@@ -13,7 +13,7 @@
13
13
  // - Reading is prototype-safe. Path segments are matched against own properties
14
14
  // only, and the segments that reach JavaScript object internals
15
15
  // (__proto__ / constructor / prototype) are rejected outright.
16
- import { analyzeFormulaDependencies, evaluateFormulaInScope, formulaExpressionError, } from "@oxygen/formula";
16
+ import { analyzeFormulaDependencies, evaluateFormulaInScope, formulaExpressionError, isRecord, } from "@oxygen/formula";
17
17
  /** A deterministic authoring/data error; retrying the same revision cannot repair it. */
18
18
  export class WorkflowValueCoercionError extends Error {
19
19
  coercion;
@@ -587,7 +587,7 @@ function lookupFormulaIdentifier(scope, identifier) {
587
587
  if (BLOCKED_PATH_SEGMENTS.has(identifier))
588
588
  return { found: false };
589
589
  const input = scope.trigger?.input;
590
- if (isPlainObject(input) && Object.prototype.hasOwnProperty.call(input, identifier)) {
590
+ if (isRecord(input) && Object.prototype.hasOwnProperty.call(input, identifier)) {
591
591
  return { found: true, value: input[identifier] };
592
592
  }
593
593
  const node = readSegment(scope.steps, identifier);
@@ -627,9 +627,6 @@ function isCoalescibleWorkflowFormulaPath(scope, identifier) {
627
627
  }
628
628
  return false;
629
629
  }
630
- function isPlainObject(value) {
631
- return typeof value === "object" && value !== null && !Array.isArray(value);
632
- }
633
630
  // ---------------------------------------------------------------------------
634
631
  // Conditions
635
632
  // ---------------------------------------------------------------------------
@@ -28,7 +28,7 @@ export const ANY_OF_REQUIREMENTS = {
28
28
  * Empty means ready.
29
29
  */
30
30
  export function missingToolParams(input) {
31
- const { toolId, fields, params, closed } = input;
31
+ const { toolId, fields, params } = input;
32
32
  const label = (name) => fields.find((field) => field.name === name)?.title ?? name;
33
33
  // An unknown key suppresses the missing-required report, because a misspelled
34
34
  // name is simultaneously an unknown key AND the reason a required field looks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.987.20",
3
+ "version": "1.1010.1",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -32,12 +32,13 @@
32
32
  "README.md"
33
33
  ],
34
34
  "dependencies": {
35
- "@aws-sdk/client-s3": "3.1050.0",
35
+ "@aws-sdk/client-s3": "3.1136.0",
36
36
  "@aws-sdk/s3-request-presigner": "3.1050.0",
37
37
  "@langfuse/core": "^5.11.0",
38
38
  "@langfuse/otel": "^5.11.0",
39
39
  "@langfuse/tracing": "^5.11.0",
40
40
  "@opentelemetry/api": "1.9.1",
41
+ "@opentelemetry/otlp-transformer": "0.221.0",
41
42
  "@opentelemetry/resources": "2.10.0",
42
43
  "@opentelemetry/sdk-trace-base": "2.10.0",
43
44
  "commander": "14.0.3",