@oxygen-agent/cli 1.922.14 → 1.948.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 (65) hide show
  1. package/README.md +1 -1
  2. package/dist/admin-primary-providers-render.d.ts +18 -0
  3. package/dist/admin-primary-providers-render.js +371 -0
  4. package/dist/command-manifest.js +30 -2
  5. package/dist/functions-commands.d.ts +6 -0
  6. package/dist/functions-commands.js +56 -0
  7. package/dist/help.js +1 -0
  8. package/dist/http-client.d.ts +4 -0
  9. package/dist/http-client.js +49 -2
  10. package/dist/index.js +515 -92
  11. package/dist/ugc-commands.d.ts +6 -0
  12. package/dist/ugc-commands.js +1089 -0
  13. package/dist/visual-commands.d.ts +6 -0
  14. package/dist/visual-commands.js +57 -0
  15. package/dist/visual-render-wait.d.ts +3 -0
  16. package/dist/visual-render-wait.js +56 -0
  17. package/node_modules/@oxygen/shared/dist/byok-connect.d.ts +48 -0
  18. package/node_modules/@oxygen/shared/dist/byok-connect.js +92 -0
  19. package/node_modules/@oxygen/shared/dist/capability-discovery.js +77 -13
  20. package/node_modules/@oxygen/shared/dist/email-dsn.d.ts +60 -0
  21. package/node_modules/@oxygen/shared/dist/email-dsn.js +120 -0
  22. package/node_modules/@oxygen/shared/dist/email-warmup-readiness.d.ts +64 -0
  23. package/node_modules/@oxygen/shared/dist/email-warmup-readiness.js +90 -0
  24. package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +2 -0
  25. package/node_modules/@oxygen/shared/dist/feature-gates.js +3 -0
  26. package/node_modules/@oxygen/shared/dist/index.d.ts +10 -0
  27. package/node_modules/@oxygen/shared/dist/index.js +10 -0
  28. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +50 -21
  29. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +47 -21
  30. package/node_modules/@oxygen/shared/dist/knowledge-constants.d.ts +1 -1
  31. package/node_modules/@oxygen/shared/dist/knowledge-constants.js +3 -2
  32. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +1 -1
  33. package/node_modules/@oxygen/shared/dist/langfuse.d.ts +8 -3
  34. package/node_modules/@oxygen/shared/dist/langfuse.js +185 -121
  35. package/node_modules/@oxygen/shared/dist/llm-payload.d.ts +10 -0
  36. package/node_modules/@oxygen/shared/dist/llm-payload.js +54 -0
  37. package/node_modules/@oxygen/shared/dist/llm-usage.d.ts +11 -0
  38. package/node_modules/@oxygen/shared/dist/llm-usage.js +30 -0
  39. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +6 -0
  40. package/node_modules/@oxygen/shared/dist/object-storage.js +5 -0
  41. package/node_modules/@oxygen/shared/dist/product-analytics-core.d.ts +98 -0
  42. package/node_modules/@oxygen/shared/dist/product-analytics-core.js +159 -0
  43. package/node_modules/@oxygen/shared/dist/product-analytics-environment.d.ts +18 -0
  44. package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +46 -0
  45. package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +92 -0
  46. package/node_modules/@oxygen/shared/dist/product-analytics-events.js +96 -0
  47. package/node_modules/@oxygen/shared/dist/provider-balance-signal.d.ts +113 -0
  48. package/node_modules/@oxygen/shared/dist/provider-balance-signal.js +158 -0
  49. package/node_modules/@oxygen/shared/dist/sequence-failures.d.ts +12 -0
  50. package/node_modules/@oxygen/shared/dist/sequence-failures.js +24 -0
  51. package/node_modules/@oxygen/shared/dist/sequences.d.ts +16 -0
  52. package/node_modules/@oxygen/shared/dist/sequences.js +54 -0
  53. package/node_modules/@oxygen/shared/dist/ugc.d.ts +133 -0
  54. package/node_modules/@oxygen/shared/dist/ugc.js +2 -0
  55. package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.d.ts +9 -0
  56. package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.js +33 -0
  57. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  58. package/node_modules/@oxygen/shared/dist/version.js +1 -1
  59. package/node_modules/@oxygen/shared/dist/visual-render.d.ts +30 -0
  60. package/node_modules/@oxygen/shared/dist/visual-render.js +55 -0
  61. package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +43 -0
  62. package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +126 -0
  63. package/node_modules/@oxygen/shared/package.json +10 -0
  64. package/node_modules/@oxygen/workflows/dist/graph/lint.js +22 -0
  65. package/package.json +1 -1
@@ -0,0 +1,64 @@
1
+ /**
2
+ * PURE warm-up readiness rule: what daily cold volume a sending mailbox can
3
+ * actually carry, given its warm-up age rather than a provider's opinion of it.
4
+ *
5
+ * WHY it lives in @oxygen/shared and not next to the other email-health rules in
6
+ * @oxygen/integrations: the tenant rollup computes this per mailbox, and
7
+ * @oxygen/tenant-db must never import @oxygen/integrations (integrations depends
8
+ * on tenant-db). Duplicating the thresholds so each package could own a copy is
9
+ * exactly how two surfaces start recommending different numbers, so the rule is
10
+ * defined once here and re-exported from
11
+ * packages/integrations/src/email-health/health-state.ts, which stays the
12
+ * email-health surface every caller reads.
13
+ *
14
+ * DIRECTIONAL, like everything else in the deliverability cluster: it produces a
15
+ * recommendation and a launch-preview warning. It never clamps a cap, never
16
+ * pauses a mailbox, and never changes what a sequence sends.
17
+ */
18
+ /** Below this warm-up day a mailbox should carry only the starter cold volume. */
19
+ export declare const WARMUP_EARLY_DAY_LIMIT = 14;
20
+ /** Below this warm-up day a mailbox should stay at the reduced cold volume. */
21
+ export declare const WARMUP_ESTABLISHED_DAY_LIMIT = 28;
22
+ /** Recommended cold sends/day before day 14 (and for an un-warmed young mailbox). */
23
+ export declare const WARMUP_EARLY_DAILY_CAP = 5;
24
+ /** Recommended cold sends/day between day 14 and day 28. */
25
+ export declare const WARMUP_ESTABLISHED_DAILY_CAP = 10;
26
+ /** A warm-up health score under this is treated as "not ready for volume". */
27
+ export declare const WARMUP_HEALTH_SCORE_FLOOR = 60;
28
+ /** Hard-bounce rate above which a fleet is burning its domains, not just its list. */
29
+ export declare const HARD_BOUNCE_RATE_CEILING = 0.03;
30
+ /** Below this send volume a bounce rate is noise, not a signal. */
31
+ export declare const HARD_BOUNCE_RATE_MIN_SENDS = 20;
32
+ /**
33
+ * The DIRECTIONAL per-mailbox daily cold-send ceiling warm-up readiness supports,
34
+ * or null when nothing in the evidence argues for holding volume back.
35
+ *
36
+ * Pure — the caller resolves `mailboxAgeDays` from created_at, so this stays
37
+ * clock-free and identical on every surface.
38
+ *
39
+ * - warm-up day < 14 -> 5/day
40
+ * - mailbox younger than 28 days, with either no active
41
+ * warm-up or no warm-up day reported at all -> 5/day
42
+ * - warm-up day < 28 -> 10/day
43
+ * - warm-up health score < 60 -> at most 5/day
44
+ * - otherwise -> null (no advice)
45
+ *
46
+ * The second rule is the one that matters for a freshly provisioned fleet: a
47
+ * mailbox whose warm-up never started (state "unknown") reports no day at all,
48
+ * and a rule keyed only on the day number would have said nothing about the exact
49
+ * mailboxes most likely to get blocked.
50
+ */
51
+ export declare function recommendedDailyCapForWarmup(input: {
52
+ warmupState?: string | null;
53
+ warmupDay?: number | null;
54
+ warmupHealthScore?: number | null;
55
+ mailboxAgeDays?: number | null;
56
+ }): number | null;
57
+ /**
58
+ * True when a hard-bounce count is high enough, over enough sends, to be a real
59
+ * reputation problem rather than list noise.
60
+ */
61
+ export declare function hardBounceRateIsHigh(input: {
62
+ hardBounces: number;
63
+ coldSends: number;
64
+ }): boolean;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * PURE warm-up readiness rule: what daily cold volume a sending mailbox can
3
+ * actually carry, given its warm-up age rather than a provider's opinion of it.
4
+ *
5
+ * WHY it lives in @oxygen/shared and not next to the other email-health rules in
6
+ * @oxygen/integrations: the tenant rollup computes this per mailbox, and
7
+ * @oxygen/tenant-db must never import @oxygen/integrations (integrations depends
8
+ * on tenant-db). Duplicating the thresholds so each package could own a copy is
9
+ * exactly how two surfaces start recommending different numbers, so the rule is
10
+ * defined once here and re-exported from
11
+ * packages/integrations/src/email-health/health-state.ts, which stays the
12
+ * email-health surface every caller reads.
13
+ *
14
+ * DIRECTIONAL, like everything else in the deliverability cluster: it produces a
15
+ * recommendation and a launch-preview warning. It never clamps a cap, never
16
+ * pauses a mailbox, and never changes what a sequence sends.
17
+ */
18
+ /** Below this warm-up day a mailbox should carry only the starter cold volume. */
19
+ export const WARMUP_EARLY_DAY_LIMIT = 14;
20
+ /** Below this warm-up day a mailbox should stay at the reduced cold volume. */
21
+ export const WARMUP_ESTABLISHED_DAY_LIMIT = 28;
22
+ /** Recommended cold sends/day before day 14 (and for an un-warmed young mailbox). */
23
+ export const WARMUP_EARLY_DAILY_CAP = 5;
24
+ /** Recommended cold sends/day between day 14 and day 28. */
25
+ export const WARMUP_ESTABLISHED_DAILY_CAP = 10;
26
+ /** A warm-up health score under this is treated as "not ready for volume". */
27
+ export const WARMUP_HEALTH_SCORE_FLOOR = 60;
28
+ /** Hard-bounce rate above which a fleet is burning its domains, not just its list. */
29
+ export const HARD_BOUNCE_RATE_CEILING = 0.03;
30
+ /** Below this send volume a bounce rate is noise, not a signal. */
31
+ export const HARD_BOUNCE_RATE_MIN_SENDS = 20;
32
+ /** Warm-up states in which a vendor is actively conditioning the mailbox. */
33
+ const ACTIVE_WARMUP_STATES = new Set(["warming", "active"]);
34
+ function finiteOrNull(value) {
35
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
36
+ }
37
+ /**
38
+ * The DIRECTIONAL per-mailbox daily cold-send ceiling warm-up readiness supports,
39
+ * or null when nothing in the evidence argues for holding volume back.
40
+ *
41
+ * Pure — the caller resolves `mailboxAgeDays` from created_at, so this stays
42
+ * clock-free and identical on every surface.
43
+ *
44
+ * - warm-up day < 14 -> 5/day
45
+ * - mailbox younger than 28 days, with either no active
46
+ * warm-up or no warm-up day reported at all -> 5/day
47
+ * - warm-up day < 28 -> 10/day
48
+ * - warm-up health score < 60 -> at most 5/day
49
+ * - otherwise -> null (no advice)
50
+ *
51
+ * The second rule is the one that matters for a freshly provisioned fleet: a
52
+ * mailbox whose warm-up never started (state "unknown") reports no day at all,
53
+ * and a rule keyed only on the day number would have said nothing about the exact
54
+ * mailboxes most likely to get blocked.
55
+ */
56
+ export function recommendedDailyCapForWarmup(input) {
57
+ const day = finiteOrNull(input.warmupDay);
58
+ const ageDays = finiteOrNull(input.mailboxAgeDays);
59
+ const healthScore = finiteOrNull(input.warmupHealthScore);
60
+ const warmingNow = ACTIVE_WARMUP_STATES.has((input.warmupState ?? "").trim().toLowerCase());
61
+ let cap = null;
62
+ if (day !== null && day < WARMUP_EARLY_DAY_LIMIT) {
63
+ cap = WARMUP_EARLY_DAILY_CAP;
64
+ }
65
+ else if (ageDays !== null &&
66
+ ageDays < WARMUP_ESTABLISHED_DAY_LIMIT &&
67
+ (day === null || !warmingNow)) {
68
+ // A rail that reports "warming" but no day number proves nothing about how
69
+ // far the ramp got, so age still governs. Gating this on !warmingNow alone
70
+ // left exactly that mailbox — enrolled, young, no telemetry — with no advice.
71
+ cap = WARMUP_EARLY_DAILY_CAP;
72
+ }
73
+ else if (day !== null && day < WARMUP_ESTABLISHED_DAY_LIMIT) {
74
+ cap = WARMUP_ESTABLISHED_DAILY_CAP;
75
+ }
76
+ if (healthScore !== null && healthScore < WARMUP_HEALTH_SCORE_FLOOR) {
77
+ cap = cap === null ? WARMUP_EARLY_DAILY_CAP : Math.min(cap, WARMUP_EARLY_DAILY_CAP);
78
+ }
79
+ return cap;
80
+ }
81
+ /**
82
+ * True when a hard-bounce count is high enough, over enough sends, to be a real
83
+ * reputation problem rather than list noise.
84
+ */
85
+ export function hardBounceRateIsHigh(input) {
86
+ if (!Number.isFinite(input.coldSends) || input.coldSends < HARD_BOUNCE_RATE_MIN_SENDS) {
87
+ return false;
88
+ }
89
+ return input.hardBounces / input.coldSends > HARD_BOUNCE_RATE_CEILING;
90
+ }
@@ -61,6 +61,8 @@ export type FeatureGateResolution = {
61
61
  * - OXYGEN_PUBLISHING_ENABLED — (b). Fail-closed production switch for posting
62
62
  * to real provider accounts (`apps/web/src/app/(app)/(dashboard)/publishing/
63
63
  * data.ts`). Wrong "on" = public posts from customer accounts.
64
+ * - OXYGEN_UGC_ENABLED — (b). Cross-workspace public posting and sponsored
65
+ * paid jobs use a local fail-closed switch independent of flag services.
64
66
  * - OXYGEN_WORKER_AUTOSCALE — (b). Arms the worker fleet autoscaler, which STOPS
65
67
  * production Machines (`apps/worker/src/fleet-autoscaler.ts`). Its worst wrong
66
68
  * value takes the fleet down while work is queued, so it must never depend on a
@@ -52,6 +52,8 @@
52
52
  * - OXYGEN_PUBLISHING_ENABLED — (b). Fail-closed production switch for posting
53
53
  * to real provider accounts (`apps/web/src/app/(app)/(dashboard)/publishing/
54
54
  * data.ts`). Wrong "on" = public posts from customer accounts.
55
+ * - OXYGEN_UGC_ENABLED — (b). Cross-workspace public posting and sponsored
56
+ * paid jobs use a local fail-closed switch independent of flag services.
55
57
  * - OXYGEN_WORKER_AUTOSCALE — (b). Arms the worker fleet autoscaler, which STOPS
56
58
  * production Machines (`apps/worker/src/fleet-autoscaler.ts`). Its worst wrong
57
59
  * value takes the fleet down while work is queued, so it must never depend on a
@@ -67,6 +69,7 @@
67
69
  export const NEVER_FLAGGABLE = [
68
70
  "OXYGEN_WORKER_AUTOSCALE",
69
71
  "OXYGEN_PUBLISHING_ENABLED",
72
+ "OXYGEN_UGC_ENABLED",
70
73
  "OXYGEN_AGENTS_ENABLED",
71
74
  "OXYGEN_TELEMETRY_ENABLED",
72
75
  "OXYGEN_LOG_SHIPPING_ENABLED",
@@ -2,8 +2,10 @@ export { MANAGED_INBOX_MINIMUM_CLI_VERSION, OXYGEN_MINIMUM_CLI_VERSION, OXYGEN_V
2
2
  export { WORKFLOW_TRIGGER_AUTO_PAUSE_METADATA_KEYS, clearWorkflowTriggerAutoPauseMetadata, } from "./workflow-trigger-metadata.js";
3
3
  export { WORKFLOW_STATUS_CHANGE_METADATA_KEY, type WorkflowStatusChange, type WorkflowStatusChangeActor, type WorkflowStatusChangeSource, describeWorkflowStatusChange, formatWorkflowStatusChangeTimestamp, parseWorkflowStatusChange, readWorkflowStatusChange, } from "./workflow-status-change.js";
4
4
  export * from "./billing.js";
5
+ export * from "./visual-render.js";
5
6
  export * from "./billing-anchors.js";
6
7
  export * from "./budget-scopes.js";
8
+ export * from "./byok-connect.js";
7
9
  export * from "./capability-discovery.js";
8
10
  export * from "./user-capability-routing.js";
9
11
  export * from "./plan-capabilities.js";
@@ -11,6 +13,7 @@ export * from "./plan-limits.js";
11
13
  export * from "./sending-seats.js";
12
14
  export * from "./sending-seat-capacity.js";
13
15
  export * from "./plain-support-events.js";
16
+ export * from "./provider-balance-signal.js";
14
17
  export * from "./provider-funding-errors.js";
15
18
  export * from "./publishing-limits.js";
16
19
  export * from "./spend-safety.js";
@@ -27,12 +30,17 @@ export * from "./copilot-journeys.js";
27
30
  export * from "./copilot-plan.js";
28
31
  export * from "./credit-guidance.js";
29
32
  export * from "./directory.js";
33
+ export * from "./email-dsn.js";
34
+ export * from "./email-warmup-readiness.js";
30
35
  export * from "./email-tracking-token.js";
31
36
  export * from "./email-unsubscribe-token.js";
32
37
  export * from "./error-redaction.js";
33
38
  export * from "./future-signup-events.js";
34
39
  export * from "./future-signup-lifecycle-projection.js";
35
40
  export * from "./feature-gates.js";
41
+ export * from "./product-analytics-core.js";
42
+ export * from "./product-analytics-environment.js";
43
+ export * from "./product-analytics-events.js";
36
44
  export * from "./hosted-ai.js";
37
45
  export * from "./identifiers.js";
38
46
  export * from "./knowledge-constants.js";
@@ -41,6 +49,7 @@ export * from "./knowledge-links.js";
41
49
  export * from "./knowledge-markdown.js";
42
50
  export * from "./knowledge-seed-content.js";
43
51
  export * from "./langfuse.js";
52
+ export * from "./llm-usage.js";
44
53
  export * from "./linkedin-mentions.js";
45
54
  export * from "./linkedin-post-url.js";
46
55
  export * from "./linkedin-quota-denial.js";
@@ -109,3 +118,4 @@ export declare function compareSemver(a: string, b: string): -1 | 0 | 1;
109
118
  export declare function isVersionGreater(a: string, b: string): boolean;
110
119
  /** True when `a` is a strictly lesser semantic version than `b`. */
111
120
  export declare function isVersionLess(a: string, b: string): boolean;
121
+ export * from "./ugc.js";
@@ -2,8 +2,10 @@ export { MANAGED_INBOX_MINIMUM_CLI_VERSION, OXYGEN_MINIMUM_CLI_VERSION, OXYGEN_V
2
2
  export { WORKFLOW_TRIGGER_AUTO_PAUSE_METADATA_KEYS, clearWorkflowTriggerAutoPauseMetadata, } from "./workflow-trigger-metadata.js";
3
3
  export { WORKFLOW_STATUS_CHANGE_METADATA_KEY, describeWorkflowStatusChange, formatWorkflowStatusChangeTimestamp, parseWorkflowStatusChange, readWorkflowStatusChange, } from "./workflow-status-change.js";
4
4
  export * from "./billing.js";
5
+ export * from "./visual-render.js";
5
6
  export * from "./billing-anchors.js";
6
7
  export * from "./budget-scopes.js";
8
+ export * from "./byok-connect.js";
7
9
  export * from "./capability-discovery.js";
8
10
  export * from "./user-capability-routing.js";
9
11
  export * from "./plan-capabilities.js";
@@ -11,6 +13,7 @@ export * from "./plan-limits.js";
11
13
  export * from "./sending-seats.js";
12
14
  export * from "./sending-seat-capacity.js";
13
15
  export * from "./plain-support-events.js";
16
+ export * from "./provider-balance-signal.js";
14
17
  export * from "./provider-funding-errors.js";
15
18
  export * from "./publishing-limits.js";
16
19
  export * from "./spend-safety.js";
@@ -27,12 +30,17 @@ export * from "./copilot-journeys.js";
27
30
  export * from "./copilot-plan.js";
28
31
  export * from "./credit-guidance.js";
29
32
  export * from "./directory.js";
33
+ export * from "./email-dsn.js";
34
+ export * from "./email-warmup-readiness.js";
30
35
  export * from "./email-tracking-token.js";
31
36
  export * from "./email-unsubscribe-token.js";
32
37
  export * from "./error-redaction.js";
33
38
  export * from "./future-signup-events.js";
34
39
  export * from "./future-signup-lifecycle-projection.js";
35
40
  export * from "./feature-gates.js";
41
+ export * from "./product-analytics-core.js";
42
+ export * from "./product-analytics-environment.js";
43
+ export * from "./product-analytics-events.js";
36
44
  export * from "./hosted-ai.js";
37
45
  export * from "./identifiers.js";
38
46
  export * from "./knowledge-constants.js";
@@ -41,6 +49,7 @@ export * from "./knowledge-links.js";
41
49
  export * from "./knowledge-markdown.js";
42
50
  export * from "./knowledge-seed-content.js";
43
51
  export * from "./langfuse.js";
52
+ export * from "./llm-usage.js";
44
53
  export * from "./linkedin-mentions.js";
45
54
  export * from "./linkedin-post-url.js";
46
55
  export * from "./linkedin-quota-denial.js";
@@ -145,3 +154,4 @@ export function isVersionGreater(a, b) {
145
154
  export function isVersionLess(a, b) {
146
155
  return compareSemver(a, b) < 0;
147
156
  }
157
+ export * from "./ugc.js";
@@ -2,28 +2,35 @@
2
2
  * Knowledge bootstrap — the once-per-workspace, automatic company research pass.
3
3
  *
4
4
  * WHAT IT IS. Exactly once in a workspace's life, OXYGEN researches the customer's
5
- * OWN company from the domain we already resolved at org creation
6
- * (control-DB `organizations.iconDomain`, `iconStatus = 'ok'`), then fills the typed
7
- * company profile (`ox_context.company_profile`) and writes one cited wiki page.
8
- * A founder who signs up should not face an empty Knowledge Graph and have to type
9
- * their own positioning back at us; every grounded AI action downstream (message
10
- * drafts, AI columns, agent runs) reads that profile, so an empty one degrades the
11
- * whole product's first hour.
5
+ * OWN company from the domain the creator typed when the workspace was created
6
+ * (control-DB `organizations.iconDomain`), then fills the typed company profile
7
+ * (`ox_context.company_profile`) and writes one cited wiki page. A founder who
8
+ * signs up should not face an empty Knowledge Graph and have to type their own
9
+ * positioning back at us; every grounded AI action downstream (message drafts, AI
10
+ * columns, agent runs) reads that profile, so an empty one degrades the whole
11
+ * product's first hour.
12
12
  *
13
13
  * WHY THIS IS NOT A VIOLATION OF THE PAID-ACTIONS RULE. `CLAUDE.md` says never run
14
14
  * paid provider actions unless the user explicitly asks. This slice is a deliberate,
15
- * founder-approved exception: signup IS the standing authorization, the same way an
16
- * armed table-webhook auto-run configuration is scoped standing permission for the
17
- * columns it queues. The exception is defensible ONLY because every one of the
18
- * following properties holds. They are load-bearing — do not drop one for
15
+ * founder-approved exception: naming the company at workspace creation IS the
16
+ * standing authorization, the same way an armed table-webhook auto-run
17
+ * configuration is scoped standing permission for the columns it queues — and
18
+ * since 2026-09-11 the pass is OXYGEN-funded, so it never draws down the
19
+ * customer's balance at all. The exception is defensible ONLY because every one of
20
+ * the following properties holds. They are load-bearing — do not drop one for
19
21
  * convenience, and if you remove one, the exception no longer stands:
20
22
  *
21
23
  * 1. CAPPED — `KNOWLEDGE_BOOTSTRAP_MAX_CREDITS` is a hard ceiling on the whole
22
24
  * pass, with `KNOWLEDGE_BOOTSTRAP_ENRICHMENT_MAX_CREDITS` a tighter
23
- * sub-ceiling on the provider (external-money) half.
24
- * 2. CONSENTED — it runs only for a workspace whose own domain we already derived
25
- * at signup; a personal-email signup is `skipped_personal_email`
26
- * upstream and never reaches here, so we never research a stranger.
25
+ * sub-ceiling on the provider (external-money) half. The cap bounds
26
+ * OXYGEN's own money now, and it is the same number.
27
+ * 2. AUTHORIZED — it runs only for a workspace whose creator typed the company
28
+ * website into the REQUIRED field at workspace creation; that
29
+ * entry is recorded as `knowledge_bootstrap_consent` (source
30
+ * `workspace_creation`) and read FAIL-CLOSED, so a workspace that
31
+ * predates the field is never researched and a personal-email
32
+ * signup with no website never reaches the worker. We never
33
+ * research a stranger.
27
34
  * 3. JOURNALLED — the marker below records status, timing, run id, credits and the
28
35
  * domain in `knowledge_state.watermarks`; the URLs read land as
29
36
  * immutable `page_sources` rows plus an `ingest` knowledge_log
@@ -36,6 +43,14 @@
36
43
  * ordinary revisioned wiki writes a human can revert.
37
44
  * 6. EXACTLY-ONCE — the marker is claimed with a conditional UPDATE, so N worker
38
45
  * replicas polling one tenant produce one run, never N runs.
46
+ * 7. OXYGEN-FUNDED — the automatic pass meters managed credits through the ordinary
47
+ * tool and AI-column lanes (so the cap, the marker and the run row
48
+ * all stay honest), and the worker then grants exactly the credits
49
+ * it used back to the workspace as an idempotent `bonus` ledger
50
+ * row keyed by the run (`KNOWLEDGE_BOOTSTRAP_COVERAGE_IDEMPOTENCY_PREFIX`).
51
+ * The customer's balance nets to zero and both rows are visible in
52
+ * their ledger. Only the AUTOMATIC pass is covered: a requested
53
+ * `--live --max-credits` re-run is the customer's own paid action.
39
54
  *
40
55
  * CAP ARITHMETIC (prices re-read from packages/integrations/src/cogs-rates.ts —
41
56
  * confirm them there rather than trusting this comment after a re-pricing):
@@ -52,8 +67,9 @@
52
67
  * overall ceiling.
53
68
  * Hard cap 300 cr — 85 cr nominal plus room for two retried synthesis
54
69
  * passes. 3% of the 10,000-credit signup grant
55
- * (FREE_SIGNUP_GRANT_CREDITS, ./billing.ts), so the
56
- * pass can never eat a founder's trial.
70
+ * (FREE_SIGNUP_GRANT_CREDITS, ./billing.ts), which is
71
+ * the headroom the balance gate needs even though the
72
+ * spend is granted back.
57
73
  *
58
74
  * The obvious implementation — firecrawl.map + 3x firecrawl.scrape — costs
59
75
  * 4 x 40 = 160 cr for the SAME job, because Firecrawl bills per page. exa.contents
@@ -164,9 +180,11 @@ export type KnowledgeBootstrapMarker = {
164
180
  linkedin_url?: string | null;
165
181
  };
166
182
  /**
167
- * Control-DB `organizations.metadata` key carrying the workspace's recorded consent
168
- * to the automatic research pass. Written once at signup by the setup surface; read
169
- * by the worker cycle before anything is spent.
183
+ * Control-DB `organizations.metadata` key carrying the workspace's recorded
184
+ * authorization for the automatic research pass. Written once, when the creator
185
+ * names the company website at workspace creation (`source: "workspace_creation"`;
186
+ * rows written by the retired `/setup` checkbox carry `source: "signup"` and stay
187
+ * valid); read by the worker cycle before anything is spent.
170
188
  *
171
189
  * It lives in shared, not in either caller, so the writer and the reader cannot
172
190
  * drift onto two different key names — a silent drift there would either deny every
@@ -178,7 +196,10 @@ export declare const KNOWLEDGE_BOOTSTRAP_CONSENT_METADATA_KEY = "knowledge_boots
178
196
  export type KnowledgeBootstrapConsent = {
179
197
  /** ISO timestamp consent was recorded. Must parse; a marker that does not is not consent. */
180
198
  granted_at: string;
181
- /** Where it came from, e.g. `signup`. Informational. */
199
+ /**
200
+ * Where it came from: `workspace_creation` (the required website field on the
201
+ * create-workspace screen) or the retired `signup` checkbox. Informational.
202
+ */
182
203
  source: string | null;
183
204
  /** Clerk user who accepted, when the surface knows. Informational. */
184
205
  granted_by_clerk_user_id: string | null;
@@ -227,6 +248,14 @@ export declare const KNOWLEDGE_BOOTSTRAP_LINKEDIN_METADATA_KEY = "company_linked
227
248
  * dead and the workspace is recoverable through the product.
228
249
  */
229
250
  export declare const KNOWLEDGE_BOOTSTRAP_STUCK_AFTER_MS: number;
251
+ /**
252
+ * Idempotency-key prefix for the ledger row that hands an automatic pass's
253
+ * credits back to the workspace (property 7 above). The key is
254
+ * `${prefix}:${run_id}`, so one pass is covered exactly once no matter how many
255
+ * times the worker revisits the outcome, and a `--force` re-run — a different
256
+ * run — is covered only if it was itself automatic.
257
+ */
258
+ export declare const KNOWLEDGE_BOOTSTRAP_COVERAGE_IDEMPOTENCY_PREFIX = "knowledge_bootstrap_coverage";
230
259
  /**
231
260
  * The one wiki page a bootstrap authors. A stable slug is what makes a re-armed pass
232
261
  * REVISE the note rather than litter the wiki with `company-research-2`.
@@ -2,28 +2,35 @@
2
2
  * Knowledge bootstrap — the once-per-workspace, automatic company research pass.
3
3
  *
4
4
  * WHAT IT IS. Exactly once in a workspace's life, OXYGEN researches the customer's
5
- * OWN company from the domain we already resolved at org creation
6
- * (control-DB `organizations.iconDomain`, `iconStatus = 'ok'`), then fills the typed
7
- * company profile (`ox_context.company_profile`) and writes one cited wiki page.
8
- * A founder who signs up should not face an empty Knowledge Graph and have to type
9
- * their own positioning back at us; every grounded AI action downstream (message
10
- * drafts, AI columns, agent runs) reads that profile, so an empty one degrades the
11
- * whole product's first hour.
5
+ * OWN company from the domain the creator typed when the workspace was created
6
+ * (control-DB `organizations.iconDomain`), then fills the typed company profile
7
+ * (`ox_context.company_profile`) and writes one cited wiki page. A founder who
8
+ * signs up should not face an empty Knowledge Graph and have to type their own
9
+ * positioning back at us; every grounded AI action downstream (message drafts, AI
10
+ * columns, agent runs) reads that profile, so an empty one degrades the whole
11
+ * product's first hour.
12
12
  *
13
13
  * WHY THIS IS NOT A VIOLATION OF THE PAID-ACTIONS RULE. `CLAUDE.md` says never run
14
14
  * paid provider actions unless the user explicitly asks. This slice is a deliberate,
15
- * founder-approved exception: signup IS the standing authorization, the same way an
16
- * armed table-webhook auto-run configuration is scoped standing permission for the
17
- * columns it queues. The exception is defensible ONLY because every one of the
18
- * following properties holds. They are load-bearing — do not drop one for
15
+ * founder-approved exception: naming the company at workspace creation IS the
16
+ * standing authorization, the same way an armed table-webhook auto-run
17
+ * configuration is scoped standing permission for the columns it queues — and
18
+ * since 2026-09-11 the pass is OXYGEN-funded, so it never draws down the
19
+ * customer's balance at all. The exception is defensible ONLY because every one of
20
+ * the following properties holds. They are load-bearing — do not drop one for
19
21
  * convenience, and if you remove one, the exception no longer stands:
20
22
  *
21
23
  * 1. CAPPED — `KNOWLEDGE_BOOTSTRAP_MAX_CREDITS` is a hard ceiling on the whole
22
24
  * pass, with `KNOWLEDGE_BOOTSTRAP_ENRICHMENT_MAX_CREDITS` a tighter
23
- * sub-ceiling on the provider (external-money) half.
24
- * 2. CONSENTED — it runs only for a workspace whose own domain we already derived
25
- * at signup; a personal-email signup is `skipped_personal_email`
26
- * upstream and never reaches here, so we never research a stranger.
25
+ * sub-ceiling on the provider (external-money) half. The cap bounds
26
+ * OXYGEN's own money now, and it is the same number.
27
+ * 2. AUTHORIZED — it runs only for a workspace whose creator typed the company
28
+ * website into the REQUIRED field at workspace creation; that
29
+ * entry is recorded as `knowledge_bootstrap_consent` (source
30
+ * `workspace_creation`) and read FAIL-CLOSED, so a workspace that
31
+ * predates the field is never researched and a personal-email
32
+ * signup with no website never reaches the worker. We never
33
+ * research a stranger.
27
34
  * 3. JOURNALLED — the marker below records status, timing, run id, credits and the
28
35
  * domain in `knowledge_state.watermarks`; the URLs read land as
29
36
  * immutable `page_sources` rows plus an `ingest` knowledge_log
@@ -36,6 +43,14 @@
36
43
  * ordinary revisioned wiki writes a human can revert.
37
44
  * 6. EXACTLY-ONCE — the marker is claimed with a conditional UPDATE, so N worker
38
45
  * replicas polling one tenant produce one run, never N runs.
46
+ * 7. OXYGEN-FUNDED — the automatic pass meters managed credits through the ordinary
47
+ * tool and AI-column lanes (so the cap, the marker and the run row
48
+ * all stay honest), and the worker then grants exactly the credits
49
+ * it used back to the workspace as an idempotent `bonus` ledger
50
+ * row keyed by the run (`KNOWLEDGE_BOOTSTRAP_COVERAGE_IDEMPOTENCY_PREFIX`).
51
+ * The customer's balance nets to zero and both rows are visible in
52
+ * their ledger. Only the AUTOMATIC pass is covered: a requested
53
+ * `--live --max-credits` re-run is the customer's own paid action.
39
54
  *
40
55
  * CAP ARITHMETIC (prices re-read from packages/integrations/src/cogs-rates.ts —
41
56
  * confirm them there rather than trusting this comment after a re-pricing):
@@ -52,8 +67,9 @@
52
67
  * overall ceiling.
53
68
  * Hard cap 300 cr — 85 cr nominal plus room for two retried synthesis
54
69
  * passes. 3% of the 10,000-credit signup grant
55
- * (FREE_SIGNUP_GRANT_CREDITS, ./billing.ts), so the
56
- * pass can never eat a founder's trial.
70
+ * (FREE_SIGNUP_GRANT_CREDITS, ./billing.ts), which is
71
+ * the headroom the balance gate needs even though the
72
+ * spend is granted back.
57
73
  *
58
74
  * The obvious implementation — firecrawl.map + 3x firecrawl.scrape — costs
59
75
  * 4 x 40 = 160 cr for the SAME job, because Firecrawl bills per page. exa.contents
@@ -132,12 +148,14 @@ export function isKnowledgeBootstrapStatus(value) {
132
148
  KNOWLEDGE_BOOTSTRAP_STATUSES.includes(value));
133
149
  }
134
150
  // ---------------------------------------------------------------------------
135
- // Consent (property 2 of the exception above, made explicit)
151
+ // Authorization (property 2 of the exception above, made explicit)
136
152
  // ---------------------------------------------------------------------------
137
153
  /**
138
- * Control-DB `organizations.metadata` key carrying the workspace's recorded consent
139
- * to the automatic research pass. Written once at signup by the setup surface; read
140
- * by the worker cycle before anything is spent.
154
+ * Control-DB `organizations.metadata` key carrying the workspace's recorded
155
+ * authorization for the automatic research pass. Written once, when the creator
156
+ * names the company website at workspace creation (`source: "workspace_creation"`;
157
+ * rows written by the retired `/setup` checkbox carry `source: "signup"` and stay
158
+ * valid); read by the worker cycle before anything is spent.
141
159
  *
142
160
  * It lives in shared, not in either caller, so the writer and the reader cannot
143
161
  * drift onto two different key names — a silent drift there would either deny every
@@ -208,6 +226,14 @@ export const KNOWLEDGE_BOOTSTRAP_LINKEDIN_METADATA_KEY = "company_linkedin_url";
208
226
  * dead and the workspace is recoverable through the product.
209
227
  */
210
228
  export const KNOWLEDGE_BOOTSTRAP_STUCK_AFTER_MS = 60 * 60 * 1000;
229
+ /**
230
+ * Idempotency-key prefix for the ledger row that hands an automatic pass's
231
+ * credits back to the workspace (property 7 above). The key is
232
+ * `${prefix}:${run_id}`, so one pass is covered exactly once no matter how many
233
+ * times the worker revisits the outcome, and a `--force` re-run — a different
234
+ * run — is covered only if it was itself automatic.
235
+ */
236
+ export const KNOWLEDGE_BOOTSTRAP_COVERAGE_IDEMPOTENCY_PREFIX = "knowledge_bootstrap_coverage";
211
237
  // ---------------------------------------------------------------------------
212
238
  // Write targets (what a bootstrap actually changes)
213
239
  // ---------------------------------------------------------------------------
@@ -3,7 +3,7 @@ export type KnowledgePageType = typeof KNOWLEDGE_PAGE_TYPES[number];
3
3
  export declare const KNOWLEDGE_META_PAGE_TYPES: readonly ["schema", "source_summary", "report"];
4
4
  export declare const KNOWLEDGE_PAGE_STATUSES: readonly ["draft", "active", "archived"];
5
5
  export type KnowledgePageStatus = typeof KNOWLEDGE_PAGE_STATUSES[number];
6
- export declare const RESERVED_KNOWLEDGE_SLUGS: readonly ["index", "log", "schema", "company-profile", "readme"];
6
+ export declare const RESERVED_KNOWLEDGE_SLUGS: readonly ["index", "log", "schema", "company-profile", "readme", "new"];
7
7
  export declare const KNOWLEDGE_SLUG_MAX_LENGTH = 120;
8
8
  export declare const KNOWLEDGE_SLUG_PATTERN: RegExp;
9
9
  export declare function isValidKnowledgeSlug(value: string): boolean;
@@ -32,17 +32,18 @@ export const KNOWLEDGE_PAGE_TYPES = [
32
32
  export const KNOWLEDGE_META_PAGE_TYPES = ["schema", "source_summary", "report"];
33
33
  export const KNOWLEDGE_PAGE_STATUSES = ["draft", "active", "archived"];
34
34
  // Slugs the write path refuses (the scaffold seeder may create `schema`): they are
35
- // computed projections or virtual pages, never ordinary rows.
35
+ // computed projections, virtual pages, or static UI routes, never ordinary rows.
36
36
  export const RESERVED_KNOWLEDGE_SLUGS = [
37
37
  "index",
38
38
  "log",
39
39
  "schema",
40
40
  "company-profile",
41
41
  "readme",
42
+ "new",
42
43
  ];
43
44
  export const KNOWLEDGE_SLUG_MAX_LENGTH = 120;
44
45
  // Flat kebab grammar: lowercase alphanumeric + dashes, no leading/trailing dash,
45
- // no slashes (pages are a flat namespace; the graph, tags, and types organize).
46
+ // no slashes (slugs are a flat namespace; folders, the graph, tags, and types organize).
46
47
  export const KNOWLEDGE_SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,119}$/;
47
48
  export function isValidKnowledgeSlug(value) {
48
49
  return KNOWLEDGE_SLUG_PATTERN.test(value);
@@ -84,7 +84,7 @@ Index-first → open only relevant pages → answer citing slugs → file durabl
84
84
  | \`schema\` | describes the wiki itself (this page) |
85
85
 
86
86
  ## Slugs
87
- Flat kebab: lowercase alphanumerics + dashes, no slashes, ≤120 chars. **Immutable once created** — choose the durable name (\`competitor-clay\`, not \`clay-notes-july\`). No folders; types, tags, and wikilinks organize. Reserved (never create): \`index\`, \`log\`, \`schema\`, \`company-profile\`, \`readme\`.
87
+ Flat kebab: lowercase alphanumerics + dashes, no slashes, ≤120 chars. **Immutable once created** — choose the durable name (\`competitor-clay\`, not \`clay-notes-july\`). Nested folders organize pages in the explorer without changing slugs or wikilinks; types and tags provide additional organization. Reserved (never create): \`index\`, \`log\`, \`schema\`, \`company-profile\`, \`readme\`, \`new\`.
88
88
 
89
89
  ## Wikilinks
90
90
  Wrap a slug in double square brackets to link it. Three forms all resolve to the same page — bare (\`slug\`), aliased (\`slug|display text\`), and heading-anchored (\`slug#heading\`) — because the alias and the heading are stripped before lookup. **Linking to a page that doesn't exist yet is good** — the dashed node is a visible to-do. Every page should link out (avoid dead-ends) and be linked to (avoid orphans).
@@ -39,6 +39,7 @@ export type LlmSpanBody = {
39
39
  };
40
40
  export type LlmGenerationBody = LlmSpanBody & {
41
41
  model?: string | null;
42
+ modelParameters?: Record<string, unknown>;
42
43
  completionStartTime?: Date | null;
43
44
  usageDetails?: Record<string, number>;
44
45
  costDetails?: Record<string, number>;
@@ -74,6 +75,7 @@ export type LlmTracingClient = {
74
75
  trace(body: LlmTraceBody): void;
75
76
  span(body: LlmSpanBody): void;
76
77
  generation(body: LlmGenerationBody): void;
78
+ embedding(body: LlmGenerationBody): void;
77
79
  event(body: LlmEventBody): void;
78
80
  /**
79
81
  * Attach a score to an existing trace.
@@ -90,9 +92,9 @@ export type LlmTracingClient = {
90
92
  * describes.
91
93
  */
92
94
  score(body: LlmScoreBody): Promise<boolean>;
93
- /** Never rejects; bounded at ~5s. */
95
+ /** Never rejects; bounded at 5s on workers, 15s in serverless after(). */
94
96
  flush(): Promise<void>;
95
- /** Flush + stop background timers. Never rejects; bounded at ~5s. */
97
+ /** Flush + stop timers. Same worker/serverless bound as flush(). */
96
98
  shutdown(): Promise<void>;
97
99
  };
98
100
  /**
@@ -114,7 +116,7 @@ export declare function resolveLlmTracingEnvironment(env?: EnvMap): string;
114
116
  * the SDK's own implementation so the two can never drift.
115
117
  */
116
118
  export declare function llmTraceIdForSeed(seed: string): string;
117
- export type LlmEmissionKind = "span" | "generation" | "event";
119
+ export type LlmEmissionKind = "span" | "generation" | "embedding" | "event";
118
120
  /** v5 correlating attributes, propagated onto the emitted observation. */
119
121
  export type LlmCorrelation = {
120
122
  traceName?: string;
@@ -124,6 +126,9 @@ export type LlmCorrelation = {
124
126
  };
125
127
  export type LlmEmission = {
126
128
  kind: LlmEmissionKind;
129
+ observationId?: string;
130
+ parentObservationId?: string;
131
+ isRoot?: boolean;
127
132
  /** External seed (turn/run id) — hashed into the W3C trace id. */
128
133
  traceSeed: string;
129
134
  name: string;