@oxygen-agent/cli 1.1014.985 → 1.1014.1087

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 (131) hide show
  1. package/README.md +1 -1
  2. package/dist/command-families/program.d.ts +2 -0
  3. package/dist/command-families/program.js +241 -0
  4. package/dist/command-families/tables/automation.d.ts +22 -0
  5. package/dist/command-families/tables/automation.js +250 -0
  6. package/dist/command-families/tables/bundle-export.d.ts +7 -0
  7. package/dist/command-families/tables/bundle-export.js +198 -0
  8. package/dist/command-families/tables/bundle-format.d.ts +66 -0
  9. package/dist/command-families/tables/bundle-format.js +274 -0
  10. package/dist/command-families/tables/bundle-import.d.ts +20 -0
  11. package/dist/command-families/tables/bundle-import.js +260 -0
  12. package/dist/command-families/tables/display.d.ts +107 -0
  13. package/dist/command-families/tables/display.js +229 -0
  14. package/dist/command-families/tables/import-batches.d.ts +26 -0
  15. package/dist/command-families/tables/import-batches.js +94 -0
  16. package/dist/command-families/tables/import-columns.d.ts +24 -0
  17. package/dist/command-families/tables/import-columns.js +131 -0
  18. package/dist/command-families/tables/import-upload.d.ts +30 -0
  19. package/dist/command-families/tables/import-upload.js +203 -0
  20. package/dist/command-families/tables/import-values.d.ts +10 -0
  21. package/dist/command-families/tables/import-values.js +60 -0
  22. package/dist/command-families/tables/imports.d.ts +19 -0
  23. package/dist/command-families/tables/imports.js +200 -0
  24. package/dist/command-families/tables/options.d.ts +314 -0
  25. package/dist/command-families/tables/options.js +1 -0
  26. package/dist/command-families/tables/register-automation.d.ts +2 -0
  27. package/dist/command-families/tables/register-automation.js +127 -0
  28. package/dist/command-families/tables/register-external-imports.d.ts +2 -0
  29. package/dist/command-families/tables/register-external-imports.js +293 -0
  30. package/dist/command-families/tables/register-files.d.ts +2 -0
  31. package/dist/command-families/tables/register-files.js +72 -0
  32. package/dist/command-families/tables/register-followers.d.ts +2 -0
  33. package/dist/command-families/tables/register-followers.js +73 -0
  34. package/dist/command-families/tables/register-lifecycle.d.ts +2 -0
  35. package/dist/command-families/tables/register-lifecycle.js +114 -0
  36. package/dist/command-families/tables/register-reads.d.ts +2 -0
  37. package/dist/command-families/tables/register-reads.js +187 -0
  38. package/dist/command-families/tables/register-relations.d.ts +2 -0
  39. package/dist/command-families/tables/register-relations.js +244 -0
  40. package/dist/command-families/tables/register-row-actions.d.ts +2 -0
  41. package/dist/command-families/tables/register-row-actions.js +53 -0
  42. package/dist/command-families/tables/register-row-writes.d.ts +2 -0
  43. package/dist/command-families/tables/register-row-writes.js +140 -0
  44. package/dist/command-families/tables/register-views.d.ts +2 -0
  45. package/dist/command-families/tables/register-views.js +83 -0
  46. package/dist/command-families/tables/register-watchers.d.ts +2 -0
  47. package/dist/command-families/tables/register-watchers.js +65 -0
  48. package/dist/command-families/tables/register-webhooks.d.ts +2 -0
  49. package/dist/command-families/tables/register-webhooks.js +126 -0
  50. package/dist/command-families/tables/registration-context.d.ts +8 -0
  51. package/dist/command-families/tables/registration-context.js +1 -0
  52. package/dist/command-families/tables/registration.d.ts +3 -0
  53. package/dist/command-families/tables/registration.js +30 -0
  54. package/dist/command-families/tables/row-selection.d.ts +5 -0
  55. package/dist/command-families/tables/row-selection.js +82 -0
  56. package/dist/command-families/tables/send.d.ts +6 -0
  57. package/dist/command-families/tables/send.js +111 -0
  58. package/dist/command-manifest.js +1 -0
  59. package/dist/commands/copilot.js +8 -0
  60. package/dist/commands/deliverability.js +4 -2
  61. package/dist/commands/sequences.js +30 -2
  62. package/dist/commands/tables.d.ts +1 -3
  63. package/dist/commands/tables.js +1 -3505
  64. package/dist/credentials.js +1 -1
  65. package/dist/customer-operation-commands.js +62 -3
  66. package/dist/help.js +1 -1
  67. package/dist/index.d.ts +1 -99
  68. package/dist/index.js +5 -337
  69. package/dist/knowledge-mirror.js +1 -1
  70. package/dist/skills.js +4 -2
  71. package/dist/update.js +2 -1
  72. package/dist/workspace-placement-commands.d.ts +3 -0
  73. package/dist/workspace-placement-commands.js +32 -0
  74. package/node_modules/@oxygen/shared/dist/agent-sessions.d.ts +4 -0
  75. package/node_modules/@oxygen/shared/dist/agent-sessions.js +11 -3
  76. package/node_modules/@oxygen/shared/dist/agents-enabled.d.ts +29 -0
  77. package/node_modules/@oxygen/shared/dist/agents-enabled.js +51 -0
  78. package/node_modules/@oxygen/shared/dist/capability-discovery.js +39 -2
  79. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +1 -1
  80. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +1 -1
  81. package/node_modules/@oxygen/shared/dist/contracts/guided-activation.js +5 -5
  82. package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.d.ts +30 -0
  83. package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.js +53 -0
  84. package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.d.ts +120 -0
  85. package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.js +48 -0
  86. package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.d.ts +267 -0
  87. package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.js +63 -0
  88. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
  89. package/node_modules/@oxygen/shared/dist/contracts/operations.js +9 -4
  90. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.d.ts +2 -0
  91. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.js +3 -0
  92. package/node_modules/@oxygen/shared/dist/contracts/teammates.js +17 -15
  93. package/node_modules/@oxygen/shared/dist/email-tracking-token.d.ts +2 -0
  94. package/node_modules/@oxygen/shared/dist/email-tracking-token.js +1 -0
  95. package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +4 -0
  96. package/node_modules/@oxygen/shared/dist/feature-gates.js +5 -0
  97. package/node_modules/@oxygen/shared/dist/file-import.d.ts +46 -0
  98. package/node_modules/@oxygen/shared/dist/file-import.js +138 -0
  99. package/node_modules/@oxygen/shared/dist/guided-activation.d.ts +8 -0
  100. package/node_modules/@oxygen/shared/dist/guided-company-files.d.ts +13 -0
  101. package/node_modules/@oxygen/shared/dist/guided-company-files.js +14 -0
  102. package/node_modules/@oxygen/shared/dist/guided-first-sourcing.d.ts +116 -0
  103. package/node_modules/@oxygen/shared/dist/guided-first-sourcing.js +11 -0
  104. package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.d.ts +4 -0
  105. package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.js +42 -0
  106. package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.d.ts +22 -0
  107. package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.js +38 -0
  108. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.d.ts +147 -0
  109. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.d.ts +12 -0
  110. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.js +83 -0
  111. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.js +44 -0
  112. package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.d.ts +7 -0
  113. package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.js +13 -0
  114. package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.d.ts +4 -0
  115. package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.js +34 -0
  116. package/node_modules/@oxygen/shared/dist/guided-trial-billing.d.ts +26 -0
  117. package/node_modules/@oxygen/shared/dist/guided-trial-billing.js +19 -0
  118. package/node_modules/@oxygen/shared/dist/index.d.ts +0 -1
  119. package/node_modules/@oxygen/shared/dist/index.js +0 -6
  120. package/node_modules/@oxygen/shared/dist/table-limits.d.ts +1 -0
  121. package/node_modules/@oxygen/shared/dist/table-limits.js +6 -0
  122. package/node_modules/@oxygen/shared/dist/teammates.d.ts +13 -8
  123. package/node_modules/@oxygen/shared/dist/teammates.js +20 -11
  124. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +78 -0
  125. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  126. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  127. package/node_modules/@oxygen/shared/dist/workspace-placement-view.d.ts +149 -0
  128. package/node_modules/@oxygen/shared/dist/workspace-placement-view.js +101 -0
  129. package/node_modules/@oxygen/shared/dist/workspace-placement.d.ts +77 -0
  130. package/node_modules/@oxygen/shared/dist/workspace-placement.js +94 -0
  131. package/package.json +1 -1
@@ -0,0 +1,83 @@
1
+ import { createGuidedOnboardingJourney, GUIDED_ONBOARDING_STEPS, } from "./guided-onboarding-journey.js";
2
+ /** Synthetic component/test data only. Never substitute this for hosted receipts. */
3
+ export const GUIDED_ONBOARDING_FIXTURE_NAMES = [
4
+ "part1_initial", "research_running", "company_review", "audience_question", "technology_relationships",
5
+ "prospects_ready", "prospects_partial", "prospects_empty", "prospects_unavailable", "prospects_failed", "research_failed",
6
+ "credits_exhausted", "checkout_pending", "billing_unavailable", "part2_trial", "part2_paid", "linkedin_skipped", "tour_paused_back", "complete",
7
+ ];
8
+ export function createGuidedOnboardingFixture(name) {
9
+ const fixture = {
10
+ fixture_only: true, label: `Synthetic onboarding fixture: ${name}`, activation_revision: 7,
11
+ journey: createGuidedOnboardingJourney(),
12
+ eligibility: { state: "checkout_required", basis: null, subscription_id: null, observed_at: "2026-10-16T12:00:00.000Z", trial_ends_at: null },
13
+ };
14
+ const { journey, eligibility } = fixture;
15
+ if (name === "research_running") {
16
+ journey.step = "company_research";
17
+ journey.research = { status: "running", run_id: "fixture-research-run", knowledge_page_ids: [], fault: null };
18
+ }
19
+ else if (name === "company_review") {
20
+ journey.step = "company_review";
21
+ journey.answers.company_review = { statement: "Synthetic company statement for panel tests.", profile_revision: "3" };
22
+ journey.research = { status: "completed", run_id: "fixture-research-run", knowledge_page_ids: ["fixture-company-page"], fault: null };
23
+ }
24
+ else if (name === "audience_question") {
25
+ journey.step = "audience_markets";
26
+ journey.answers.audience_company_size = { values: ["11–50"] };
27
+ journey.answers.audience_markets = { values: ["Germany", "Custom test market"] };
28
+ }
29
+ else if (name === "technology_relationships") {
30
+ journey.step = "signals";
31
+ journey.answers.signals = {
32
+ hiring: { mode: "selected", values: ["Revenue Operations Manager"] },
33
+ technology: { mode: "selected", values: [
34
+ { name: "Apollo", relationship: "replaces" },
35
+ { name: "Apollo", relationship: "integrates_with" },
36
+ ] },
37
+ };
38
+ }
39
+ else if (name.startsWith("prospects_")) {
40
+ journey.step = "prospects";
41
+ journey.prospects.status = name === "prospects_ready" ? "ready" : name === "prospects_partial" ? "partial"
42
+ : name === "prospects_unavailable" ? "unavailable" : name === "prospects_failed" ? "failed" : "empty";
43
+ journey.prospects.table_id = "fixture-prospects-table";
44
+ if (name === "prospects_ready" || name === "prospects_partial") {
45
+ journey.prospects.ingestion_run_ids = ["fixture-prospects-ingestion"];
46
+ journey.prospects.people = Array.from({ length: name === "prospects_ready" ? 5 : 2 }, (_, index) => ({
47
+ row_id: `fixture-person-${index + 1}`, person_key: `fixture-key-${index + 1}`,
48
+ name: `Example Buyer ${index + 1}`, title: "Example sales leader", company: "Example Company",
49
+ linkedin_url: null, sources: [{ url: "https://example.test/source", title: "Synthetic source — not provider evidence" }],
50
+ fit: { rationale: "Synthetic fit explanation for layout tests.", criteria: ["example persona"] },
51
+ }));
52
+ }
53
+ }
54
+ else if (name === "research_failed" || name === "credits_exhausted") {
55
+ journey.step = "company_research";
56
+ journey.research.status = name === "research_failed" ? "failed" : "credits_exhausted";
57
+ journey.research.fault = { code: name === "research_failed" ? "research_unavailable" : "insufficient_credits", retryable: name === "research_failed" };
58
+ }
59
+ else if (name === "checkout_pending" || name === "billing_unavailable") {
60
+ journey.step = "trial";
61
+ eligibility.state = name === "checkout_pending" ? "checkout_pending" : "unavailable";
62
+ }
63
+ else if (["part2_trial", "part2_paid", "linkedin_skipped", "tour_paused_back", "complete"].includes(name)) {
64
+ journey.step = name === "complete" ? "complete" : name === "linkedin_skipped" ? "campaign" : name === "tour_paused_back" ? "tour" : "welcome";
65
+ eligibility.state = "eligible";
66
+ eligibility.basis = name === "part2_paid" ? "paid" : "trial";
67
+ eligibility.subscription_id = "fixture-subscription";
68
+ eligibility.trial_ends_at = eligibility.basis === "trial" ? "2026-10-23T12:00:00.000Z" : null;
69
+ if (name === "linkedin_skipped")
70
+ journey.answers.linkedin = { choice: "skip" };
71
+ }
72
+ const index = GUIDED_ONBOARDING_STEPS.indexOf(journey.step);
73
+ journey.completed_steps = GUIDED_ONBOARDING_STEPS.slice(0, index);
74
+ if (index > GUIDED_ONBOARDING_STEPS.indexOf("company_review")) {
75
+ journey.answers.company_review = { statement: "Synthetic reviewed company statement.", profile_revision: "3" };
76
+ journey.company_confirmation = { profile_revision: "3", statement_digest: "a".repeat(64), confirmed_at: "2026-10-16T12:00:00.000Z" };
77
+ }
78
+ if (name === "tour_paused_back") {
79
+ journey.answers.tour = { visited: ["overview", "leads", "sourcing"] };
80
+ journey.navigation = { paused: true, tour_active_stop: "leads" };
81
+ }
82
+ return fixture;
83
+ }
@@ -0,0 +1,44 @@
1
+ /** Full DEV onboarding, approved by Philipp on 2026-10-16.
2
+ * Browser-safe vocabulary. Native owners, never navigation or caller assertions,
3
+ * establish research results, billing eligibility and resource authority. */
4
+ export const GUIDED_ONBOARDING_JOURNEY_VERSION = 1;
5
+ export const GUIDED_ONBOARDING_PART1_STEPS = [
6
+ "company_context", "company_research", "company_review",
7
+ "audience_company_size", "audience_markets", "audience_industries", "audience_personas",
8
+ "signals", "prospects", "trial",
9
+ ];
10
+ export const GUIDED_ONBOARDING_PART2_STEPS = [
11
+ "welcome", "daily_rhythm", "linkedin", "campaign", "sequence", "routines", "tour",
12
+ ];
13
+ export const GUIDED_ONBOARDING_STEPS = [
14
+ ...GUIDED_ONBOARDING_PART1_STEPS, ...GUIDED_ONBOARDING_PART2_STEPS, "complete",
15
+ ];
16
+ export function guidedOnboardingPart(step) {
17
+ if (step === "complete")
18
+ return "complete";
19
+ if (GUIDED_ONBOARDING_PART1_STEPS.includes(step))
20
+ return "part1";
21
+ if (GUIDED_ONBOARDING_PART2_STEPS.includes(step))
22
+ return "part2";
23
+ throw new TypeError("Unknown onboarding step.");
24
+ }
25
+ export const GUIDED_ONBOARDING_TECHNOLOGY_RELATIONSHIPS = ["uses", "replaces", "integrates_with"];
26
+ /** Free initialization; creates no research, chat turn, subscription or resource. */
27
+ export function createGuidedOnboardingJourney() {
28
+ return {
29
+ version: GUIDED_ONBOARDING_JOURNEY_VERSION, generation: 1, step: "company_context",
30
+ completed_steps: [], navigation: { paused: false, tour_active_stop: null }, answers: {}, company_confirmation: null,
31
+ research: { status: "not_started", run_id: null, knowledge_page_ids: [], fault: null },
32
+ prospects: { status: "not_started", table_id: null, ingestion_run_ids: [], people: [], fault: null },
33
+ };
34
+ }
35
+ /** Old saved v1 records have no current-stop evidence. Never guess from visited[]. */
36
+ export function normalizeSavedGuidedOnboardingJourney(journey) {
37
+ if (journey.navigation === undefined)
38
+ return { ...journey, navigation: { paused: false, tour_active_stop: null } };
39
+ const navigation = journey.navigation;
40
+ if (!navigation || typeof navigation.paused !== "boolean" || (navigation.tour_active_stop !== null
41
+ && !["overview", "leads", "sourcing", "sequence"].includes(navigation.tour_active_stop)))
42
+ throw new TypeError("Invalid saved onboarding navigation.");
43
+ return journey;
44
+ }
@@ -0,0 +1,7 @@
1
+ import type { GuidedOnboardingProspectLimitation, GuidedOnboardingProspects } from "./guided-onboarding-journey.js";
2
+ /** Bind actual D result.targeting.limitations, never infer support from success,
3
+ * an empty people list, a legacy absence, or a general fault. Preserve native
4
+ * result status/fit/source/ingestion truth and the compatible fault unchanged. */
5
+ export declare function projectGuidedOnboardingProspects(prospects: GuidedOnboardingProspects, limitations: unknown): GuidedOnboardingProspects & {
6
+ limitations: GuidedOnboardingProspectLimitation[];
7
+ };
@@ -0,0 +1,13 @@
1
+ import { OxygenError } from "./cli-result.js";
2
+ import { arr, bool, enumOf, obj, str, validateContract } from "./contracts/schema.js";
3
+ const limitationsContract = obj({ limitations: arr(obj({ field: str({ minLength: 1 }), code: enumOf(["unsupported_filter"]),
4
+ blocking: bool(), message: str({ minLength: 1 }), values: arr(str()), suggestions: arr(str()) }, { required: ["field", "code", "blocking", "message", "values", "suggestions"] })) }, { required: ["limitations"] });
5
+ /** Bind actual D result.targeting.limitations, never infer support from success,
6
+ * an empty people list, a legacy absence, or a general fault. Preserve native
7
+ * result status/fit/source/ingestion truth and the compatible fault unchanged. */
8
+ export function projectGuidedOnboardingProspects(prospects, limitations) {
9
+ const checked = validateContract(limitationsContract, { limitations }, { unknown: "reject", overMax: "reject" });
10
+ if (!checked.ok)
11
+ throw new OxygenError("onboarding_preview_diagnostics_invalid", "The preview could not describe its supported targeting. Review your saved criteria before retrying.");
12
+ return { ...prospects, limitations: checked.value.limitations.map(item => ({ ...item, values: [...item.values], suggestions: [...item.suggestions] })) };
13
+ }
@@ -0,0 +1,4 @@
1
+ import type { GuidedOnboardingAnswers } from "./guided-onboarding-journey.js";
2
+ /** Same product with distinct relationships is intentional, not a duplicate.
3
+ * This normalizes saved intent, never claims that a provider supports a filter. */
4
+ export declare function normalizeGuidedOnboardingSignals(value: unknown): NonNullable<GuidedOnboardingAnswers["signals"]>;
@@ -0,0 +1,34 @@
1
+ import { OxygenError } from "./cli-result.js";
2
+ import { validateContract } from "./contracts/schema.js";
3
+ import { GUIDED_ONBOARDING_SIGNALS_CONTRACT } from "./contracts/guided-onboarding-journey.js";
4
+ const fail = () => {
5
+ throw new OxygenError("invalid_onboarding_answer", "Choose hiring roles and technologies with uses, replaces or integrates_with, or explicitly choose none.", { exitCode: 2 });
6
+ };
7
+ const displayName = (name) => name.normalize("NFKC").trim().replace(/\s+/gu, " ");
8
+ /** Same product with distinct relationships is intentional, not a duplicate.
9
+ * This normalizes saved intent, never claims that a provider supports a filter. */
10
+ export function normalizeGuidedOnboardingSignals(value) {
11
+ const parsed = validateContract(GUIDED_ONBOARDING_SIGNALS_CONTRACT, value, { unknown: "reject", overMax: "reject" });
12
+ if (!parsed.ok)
13
+ return fail();
14
+ const { hiring, technology } = parsed.value;
15
+ if ((hiring.mode === "none") !== (hiring.values.length === 0)
16
+ || (technology.mode === "none") !== (technology.values.length === 0))
17
+ return fail();
18
+ const roles = hiring.values.map(displayName);
19
+ if (roles.some(role => !role))
20
+ return fail();
21
+ const seen = new Set();
22
+ const technologies = [];
23
+ for (const item of technology.values) {
24
+ const name = displayName(item.name);
25
+ if (!name)
26
+ return fail();
27
+ const key = JSON.stringify([name.toLowerCase(), item.relationship]);
28
+ if (seen.has(key))
29
+ continue;
30
+ seen.add(key);
31
+ technologies.push({ name, relationship: item.relationship });
32
+ }
33
+ return { hiring: { mode: hiring.mode, values: roles }, technology: { mode: technology.mode, values: technologies } };
34
+ }
@@ -0,0 +1,26 @@
1
+ /** DEV onboarding offer. Existing subscription terms and production acquisition stay intact. */
2
+ export declare const GUIDED_TRIAL_OFFER: {
3
+ readonly key: "guided_onboarding_v2";
4
+ readonly plan: "oxygen_49";
5
+ readonly currency: "usd";
6
+ readonly trial_days: 7;
7
+ readonly trial_credits: 2000;
8
+ readonly amount_due_now_cents: 0;
9
+ readonly monthly_price_cents: 4900;
10
+ readonly card_required: true;
11
+ readonly early_charge_allowed: false;
12
+ };
13
+ export declare function guidedTrialAcquisitionEnabled(env?: Record<string, string | undefined>): boolean;
14
+ export declare function isGuidedTrialSubscription(metadata: Record<string, unknown> | null | undefined): boolean;
15
+ export type GuidedTrialBilling = {
16
+ offer: typeof GUIDED_TRIAL_OFFER;
17
+ eligible: boolean;
18
+ checkout_allowed: boolean;
19
+ state: "trial" | "paid" | "checkout_required" | "trial_unavailable" | "subscription_pending";
20
+ billing_owner_organization_id: string;
21
+ subscription_id: string | null;
22
+ trial_ends_at: string | null;
23
+ cancellation_scheduled: boolean;
24
+ spendable_credits: number;
25
+ funded_work_paused: boolean;
26
+ };
@@ -0,0 +1,19 @@
1
+ import { guidedActivationEnabled } from "./guided-activation.js";
2
+ /** DEV onboarding offer. Existing subscription terms and production acquisition stay intact. */
3
+ export const GUIDED_TRIAL_OFFER = {
4
+ key: "guided_onboarding_v2",
5
+ plan: "oxygen_49",
6
+ currency: "usd",
7
+ trial_days: 7,
8
+ trial_credits: 2_000,
9
+ amount_due_now_cents: 0,
10
+ monthly_price_cents: 4_900,
11
+ card_required: true,
12
+ early_charge_allowed: false,
13
+ };
14
+ export function guidedTrialAcquisitionEnabled(env = process.env) {
15
+ return guidedActivationEnabled(env);
16
+ }
17
+ export function isGuidedTrialSubscription(metadata) {
18
+ return metadata?.oxygen_trial_offer === GUIDED_TRIAL_OFFER.key;
19
+ }
@@ -110,7 +110,6 @@ export * from "./workflow-trigger-label.js";
110
110
  export * from "./workspace-event-catalog.js";
111
111
  export * from "./notetaker-events.js";
112
112
  export * from "./workspace-agents.js";
113
- export declare const MAX_ROW_LOOP_WRITE_ROWS = 500;
114
113
  export * from "./semver.js";
115
114
  export * from "./ugc.js";
116
115
  export * from "./ugc-amplification-identity.js";
@@ -121,12 +121,6 @@ export * from "./workflow-trigger-label.js";
121
121
  export * from "./workspace-event-catalog.js";
122
122
  export * from "./notetaker-events.js";
123
123
  export * from "./workspace-agents.js";
124
- // Maximum rows a single row-loop write (insert/upsert/preview) may process. The
125
- // row-loop engine issues one DB round-trip per row, so a 500-row write already
126
- // approaches request timeouts (~50s observed in prod); larger batches must use
127
- // the COPY-based bulk engine. Tenant-db enforces this and the CLI/API row caps
128
- // reference it so they never advertise a batch the row-loop will reject.
129
- export const MAX_ROW_LOOP_WRITE_ROWS = 500;
130
124
  export * from "./semver.js";
131
125
  export * from "./ugc.js";
132
126
  export * from "./ugc-amplification-identity.js";
@@ -3,6 +3,7 @@ export declare const MAX_TABLE_ACTION_RUN_ROWS = 500000;
3
3
  export declare const MAX_FORMULA_ACTION_RUN_ROWS = 1000000;
4
4
  export declare const MAX_FORMULA_ACTION_RUN_ITEMS = 5000000;
5
5
  export declare const MAX_WORKSPACE_ROW_DELETE_ROWS = 50000;
6
+ export declare const MAX_ROW_LOOP_WRITE_ROWS = 500;
6
7
  /**
7
8
  * Maximum requested row concurrency for one table action run. Native BullMQ
8
9
  * persists at most this many slot heads. Actual execution also shares worker
@@ -5,6 +5,12 @@ export const MAX_TABLE_ACTION_RUN_ROWS = 500_000;
5
5
  export const MAX_FORMULA_ACTION_RUN_ROWS = 1_000_000;
6
6
  export const MAX_FORMULA_ACTION_RUN_ITEMS = 5_000_000;
7
7
  export const MAX_WORKSPACE_ROW_DELETE_ROWS = 50_000;
8
+ // Maximum rows a single row-loop write (insert/upsert/preview) may process. The
9
+ // row-loop engine issues one DB round-trip per row, so a 500-row write already
10
+ // approaches request timeouts (~50s observed in prod); larger batches must use
11
+ // the COPY-based bulk engine. Tenant-db enforces this and the CLI/API row caps
12
+ // reference it so they never advertise a batch the row-loop will reject.
13
+ export const MAX_ROW_LOOP_WRITE_ROWS = 500;
8
14
  /**
9
15
  * Maximum requested row concurrency for one table action run. Native BullMQ
10
16
  * persists at most this many slot heads. Actual execution also shares worker
@@ -1,15 +1,19 @@
1
1
  /**
2
- * AI teammates (ADR 0032): Agents people talk to, each person in one ongoing
3
- * private chat per teammate, on the Copilot runtime. Each is its owner's until
4
- * shared with teammates (Tim, 2026-10-14); the first one is everyone's.
2
+ * AI teammates (ADR 0032): Agents people talk to in one ongoing shared chat
3
+ * per Workspace Oxygent, on the Copilot runtime. Explicit Personal Oxygents
4
+ * are creator-only; the first one stays Workspace (Philipp, 2026-10-16).
5
5
  *
6
- * Staff-only on dev. `OXYGEN_TEAMMATES_ENABLED` is the switch; when it is
7
- * unset the feature follows the Ongoing Agent sessions staff gate, which the
8
- * dev web and worker already receive, because teammates re-scope those
9
- * sessions into routines. Production and shadow never qualify.
6
+ * Staff only: on dev, and in production's staff workspaces, the ones Agents run
7
+ * in (`agentsEnabledIn`; Tim, 2026-10-16). `OXYGEN_TEAMMATES_ENABLED` is the
8
+ * switch; when it is unset the feature follows the Ongoing Agent sessions staff
9
+ * gate, because teammates re-scope those sessions into routines. Shadow never
10
+ * qualifies.
10
11
  */
11
12
  export declare function teammatesEnabled(env?: Record<string, string | undefined>): boolean;
13
+ /** Whether this workspace has Oxygents. */
14
+ export declare function teammatesEnabledIn(organizationId: string | null | undefined, env?: Record<string, string | undefined>): boolean;
12
15
  export declare function teammatesAvailableTo(env: Record<string, string | undefined>, viewer: {
16
+ organizationId: string | null;
13
17
  email: string | null | undefined;
14
18
  member: boolean;
15
19
  oxygenRole?: string | null | undefined;
@@ -40,7 +44,7 @@ export declare function isTeammateAvatarColor(value: unknown): value is Teammate
40
44
  * Who may use an Oxygent besides its owner, the way Grok Bot shares a Bot
41
45
  * (Tim, 2026-10-14: "make agents accessible to your team mates that you can
42
46
  * collaborate with your team mates"). A collaborator chats with it and uses its
43
- * skills, in a chat of their own; a manager also changes its profile and who
47
+ * skills, in the shared chat; a manager also changes its profile and who
44
48
  * has access. Deleting it stays with its owner or a workspace admin.
45
49
  */
46
50
  export declare const TEAMMATE_SHARE_ROLES: readonly ["collaborator", "manager"];
@@ -57,6 +61,7 @@ export declare function isTeammateShareRole(value: unknown): value is TeammateSh
57
61
  */
58
62
  export declare function teammateAccessRole(teammate: {
59
63
  slug: string;
64
+ visibility?: "workspace" | "personal";
60
65
  ownerActorId: string | null;
61
66
  everyone: TeammateShareRole | null;
62
67
  personal: TeammateShareRole | null;
@@ -1,27 +1,34 @@
1
+ import { agentsEnabled, agentsEnabledIn } from "./agents-enabled.js";
1
2
  import { guidedActivationEnabled } from "./guided-activation.js";
2
3
  import { isStaffEmail } from "./staff.js";
3
4
  /**
4
- * AI teammates (ADR 0032): Agents people talk to, each person in one ongoing
5
- * private chat per teammate, on the Copilot runtime. Each is its owner's until
6
- * shared with teammates (Tim, 2026-10-14); the first one is everyone's.
5
+ * AI teammates (ADR 0032): Agents people talk to in one ongoing shared chat
6
+ * per Workspace Oxygent, on the Copilot runtime. Explicit Personal Oxygents
7
+ * are creator-only; the first one stays Workspace (Philipp, 2026-10-16).
7
8
  *
8
- * Staff-only on dev. `OXYGEN_TEAMMATES_ENABLED` is the switch; when it is
9
- * unset the feature follows the Ongoing Agent sessions staff gate, which the
10
- * dev web and worker already receive, because teammates re-scope those
11
- * sessions into routines. Production and shadow never qualify.
9
+ * Staff only: on dev, and in production's staff workspaces, the ones Agents run
10
+ * in (`agentsEnabledIn`; Tim, 2026-10-16). `OXYGEN_TEAMMATES_ENABLED` is the
11
+ * switch; when it is unset the feature follows the Ongoing Agent sessions staff
12
+ * gate, because teammates re-scope those sessions into routines. Shadow never
13
+ * qualifies.
12
14
  */
13
15
  export function teammatesEnabled(env = process.env) {
14
- if (env.OXYGEN_DEPLOY_ENV !== "selfhost-dev")
16
+ if (env.OXYGEN_DEPLOY_ENV !== "selfhost-dev" && env.OXYGEN_DEPLOY_ENV !== "selfhost-prod")
15
17
  return false;
16
- if (env.OXYGEN_AGENTS_ENABLED?.trim().toLowerCase() !== "true")
18
+ if (!agentsEnabled(env))
17
19
  return false;
18
20
  const flag = env.OXYGEN_TEAMMATES_ENABLED?.trim().toLowerCase();
19
21
  if (flag)
20
22
  return flag === "staff";
21
23
  return env.OXYGEN_AGENT_SESSIONS_ENABLED === "staff";
22
24
  }
25
+ /** Whether this workspace has Oxygents. */
26
+ export function teammatesEnabledIn(organizationId, env = process.env) {
27
+ return teammatesEnabled(env) && agentsEnabledIn(organizationId, env);
28
+ }
23
29
  export function teammatesAvailableTo(env, viewer) {
24
- return teammatesEnabled(env) && viewer.member && viewer.oxygenRole !== "client" && (guidedActivationEnabled(env) || isStaffEmail(viewer.email, env));
30
+ return teammatesEnabledIn(viewer.organizationId, env) && viewer.member && viewer.oxygenRole !== "client"
31
+ && (guidedActivationEnabled(env) || isStaffEmail(viewer.email, env));
25
32
  }
26
33
  /**
27
34
  * The Workspace Agent's slug. Every workspace's first Oxygent is that Agent: an
@@ -57,7 +64,7 @@ export function isTeammateAvatarColor(value) {
57
64
  * Who may use an Oxygent besides its owner, the way Grok Bot shares a Bot
58
65
  * (Tim, 2026-10-14: "make agents accessible to your team mates that you can
59
66
  * collaborate with your team mates"). A collaborator chats with it and uses its
60
- * skills, in a chat of their own; a manager also changes its profile and who
67
+ * skills, in the shared chat; a manager also changes its profile and who
61
68
  * has access. Deleting it stays with its owner or a workspace admin.
62
69
  */
63
70
  export const TEAMMATE_SHARE_ROLES = ["collaborator", "manager"];
@@ -76,6 +83,8 @@ export function teammateAccessRole(teammate, actorId) {
76
83
  return "manager";
77
84
  if (teammate.ownerActorId && teammate.ownerActorId === actorId)
78
85
  return "owner";
86
+ if (teammate.visibility === "personal")
87
+ return null;
79
88
  if (teammate.everyone === "manager" || teammate.personal === "manager")
80
89
  return "manager";
81
90
  if (teammate.everyone === "collaborator" || teammate.personal === "collaborator")
@@ -14,6 +14,22 @@ export function capabilityDiscoveryRecovery(query, surface) {
14
14
  // connection routes.
15
15
  export function inferUserCapabilityRoute(query) {
16
16
  const normalized = query.toLowerCase().replace(/[_-]+/g, " ");
17
+ const journeyAction = savedOnboardingJourneyAction(normalized);
18
+ if (journeyAction) {
19
+ const route = getCapabilityRouteMatch("agents");
20
+ if (route) {
21
+ const recommendedTools = [`oxygen_onboarding_journey_${journeyAction}`, ...(journeyAction === "get" ? [] : ["oxygen_onboarding_journey_get"])];
22
+ const recommendedCommands = [`onboarding journey ${journeyAction}`, ...(journeyAction === "get" ? [] : ["onboarding journey get"])];
23
+ return { ...route, recommendedTools, recommendedCommands, card: { ...route.card,
24
+ owns: "Creator-private saved guided onboarding answers, current step and pause/resume position.",
25
+ notFor: "Human workspace invitations or permissions, destructive workspace reset, paid Oxygent Start or routine execution.",
26
+ gatewayTools: recommendedTools, gatewayCommands: recommendedCommands,
27
+ posture: journeyAction === "get" ? "read_only" : "workspace_write",
28
+ execution: journeyAction === "get" ? "Read saved onboarding and its current native step. This read starts no research, model, billing reconciliation or message send."
29
+ : "Read activationId and current revision first, then hydrate the selected native operation. Use a stable mutation_id; Back and non-destructive restart preserve resources and funding. Company answers prepare native sources and existing bounded research consent. Discovery executes nothing and supplies no approval or billing authority.",
30
+ } };
31
+ }
32
+ }
17
33
  // Exact native session activation must outrank the generic Agent gateways.
18
34
  // Discovery supplies no approval, preview token or invented session binding.
19
35
  if (/\bagent session activate\b/.test(normalized)
@@ -61,6 +77,23 @@ export function inferUserCapabilityRoute(query) {
61
77
  recommendedCommands: ["context profile get", "knowledge bootstrap status", "onboarding activation status"],
62
78
  exactCommand: "oxygen context profile get --json", exactMcpCall: { tool: "oxygen_context_profile_get", arguments: {} } };
63
79
  }
80
+ // Explicit guided-journey discovery precedes the individual campaign,
81
+ // review and routine nouns that describe its later steps. Consulting keeps
82
+ // the ordinary onboarding card; this recommendation advertises DEV only.
83
+ if (isGuidedOnboardingDiscoveryIntent(normalized)) {
84
+ const route = getCapabilityRouteMatch("onboarding-and-copilot");
85
+ if (route) {
86
+ const recommendedTools = ["oxygen_onboarding_activation_status", "oxygen_onboarding_journey_get"];
87
+ const recommendedCommands = ["onboarding activation status", "onboarding journey get"];
88
+ return { ...route, recommendedTools, recommendedCommands, card: { ...route.card,
89
+ owns: "Creator-owned DEV guided onboarding answers, native resources, current step and saved navigation.",
90
+ notFor: "Production onboarding execution, human membership or ordinary GTM consulting.",
91
+ posture: "read_only", gatewayTools: recommendedTools, gatewayCommands: recommendedCommands,
92
+ execution: "DEV-only two-part guided onboarding; unavailable in production, shadow, local or production-data workspaces. Read your activation first, then use its activationId to read the saved journey and revision. If absent, inspect the free activation-start schema and choose own_agent or oxygent. Resume the native step; answers, prospects, TEST billing, campaigns and routines retain their own schemas, eligibility and approvals. These reads start no research, checkout, model, schedule or send. Ordinary GTM consulting remains with Recipes/Copilot.",
93
+ }, exactCommand: "oxygen onboarding activation status --json",
94
+ exactMcpCall: { tool: "oxygen_onboarding_activation_status", arguments: {} } };
95
+ }
96
+ }
64
97
  if ((/\b(?:linkedin|sequence|campaign)\b/.test(normalized) && /\b(?:preview|review|readiness)\b/.test(normalized)
65
98
  && /\b(?:launch|start)\b/.test(normalized) && /\b(?:approval|send limits?|caps?)\b/.test(normalized))
66
99
  || (isLinkedInCampaignIntent(normalized) && /\breadiness\b/.test(normalized) && /\bpreview\b/.test(normalized))) {
@@ -159,6 +192,38 @@ export function inferUserCapabilityRoute(query) {
159
192
  // intent is exactly what this wrapper exists to answer.
160
193
  return getCapabilityRouteMatch("connected-integrations") ?? route;
161
194
  }
195
+ /** Saved progress is distinct from general signup research, attended Start,
196
+ * routine schedules and human membership. Pause wins over a simultaneous resume. */
197
+ function savedOnboardingJourneyAction(query) {
198
+ if (!/\bonboarding\b/.test(query) || !/\b(?:journey|guided|answers?|steps?|tour)\b/.test(query)
199
+ || /\b(?:invite|members?|membership|permissions?|roles?|human|colleague|coworker|delete|destroy|wipe)\b/.test(query))
200
+ return null;
201
+ if (/\b(?:pause|paused|navigation)\b/.test(query) || (/\btour\b/.test(query) && /\bresume\b/.test(query)))
202
+ return "navigation";
203
+ if (/\brestart\b/.test(query))
204
+ return "restart";
205
+ if (/\bback\b/.test(query))
206
+ return "back";
207
+ if (/\bsave\b/.test(query))
208
+ return "save";
209
+ if (/\b(?:resume|read|get)\b/.test(query))
210
+ return "get";
211
+ return null;
212
+ }
213
+ /** A saved action is handled first. This is discovery of the multi-step
214
+ * product journey, not generic advice about improving a GTM operation. */
215
+ function isGuidedOnboardingDiscoveryIntent(query) {
216
+ if (!/\bonboarding\b/.test(query)
217
+ || /\b(?:invite|members?|membership|permissions?|roles?|human|colleague|coworker|delete|destroy|wipe|paid)\b/.test(query))
218
+ return false;
219
+ if (/^(?:guided )?onboarding$/.test(query.trim()))
220
+ return true;
221
+ return /\b(?:first sourcing|daily rhythm)\b/.test(query)
222
+ || (/\b(?:guide|guided|journey|part [12])\b/.test(query)
223
+ && /\b(?:business|company|icp|personas?|prospects?|trial|campaign|sequence|briefing)\b/.test(query))
224
+ || (/\b(?:trial|prospects?|personas?)\b/.test(query)
225
+ && /\b(?:context|icp|campaign|sequence)\b/.test(query));
226
+ }
162
227
  function isCompanyOnboardingContextIntent(query) {
163
228
  return /\bonboard\w*\b/.test(query)
164
229
  && /\bcompany\b/.test(query)
@@ -266,6 +331,19 @@ function oxygentsRoute(normalized) {
266
331
  const group = /\bgroups?\b/.test(normalized);
267
332
  const verb = (group ? OXYGENT_GROUP_VERBS : OXYGENT_VERBS).find(([, words]) => words.test(normalized))?.[0]
268
333
  ?? (group ? "groups" : "list");
334
+ // Visibility discovery asks about the contract, not existing conversations.
335
+ // Keep the shared router's create/update/access recommendations even when
336
+ // the product noun would otherwise select the roster or "history" GET.
337
+ // Explicit content reads and other operations retain their native verbs.
338
+ const privacy = /\b(?:visibility|personal|workspace|private|shared)\b/.test(normalized);
339
+ const rosterRead = /\b(?:list|inventory|roster)\b|\bwhich\b.*\b(?:have|available)\b/.test(normalized);
340
+ const contentRead = /\b(?:read|see|view|show|transcript)\b/.test(normalized);
341
+ const contentSend = /\b(?:messages?|ask|tell|send|talk|continue|resume|handoff|delegat\w*)\b|\b(?:chat with|hand\w* off)\b/.test(normalized);
342
+ if (!group && privacy && ((verb === "list" && !rosterRead) || verb === "create"
343
+ || (verb === "update" && /\bvisibility\b/.test(normalized))
344
+ || (verb === "get" && !contentRead) || (verb === "message" && !contentSend))) {
345
+ return inferCapabilityRoute(normalized);
346
+ }
269
347
  // Sharing is read and changed as a pair: who has access, then share.
270
348
  const pair = verb === "share" ? ["access"] : verb === "access" ? ["share"] : [];
271
349
  // A group's id comes from its list; the roster reads follow every ask.
@@ -1 +1 @@
1
- export declare const OXYGEN_BUILD_VERSION = "1.1014.985";
1
+ export declare const OXYGEN_BUILD_VERSION = "1.1014.1087";
@@ -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.1014.985";
2
+ export const OXYGEN_BUILD_VERSION = "1.1014.1087";