@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.
- package/README.md +1 -1
- package/dist/command-families/program.d.ts +2 -0
- package/dist/command-families/program.js +241 -0
- package/dist/command-families/tables/automation.d.ts +22 -0
- package/dist/command-families/tables/automation.js +250 -0
- package/dist/command-families/tables/bundle-export.d.ts +7 -0
- package/dist/command-families/tables/bundle-export.js +198 -0
- package/dist/command-families/tables/bundle-format.d.ts +66 -0
- package/dist/command-families/tables/bundle-format.js +274 -0
- package/dist/command-families/tables/bundle-import.d.ts +20 -0
- package/dist/command-families/tables/bundle-import.js +260 -0
- package/dist/command-families/tables/display.d.ts +107 -0
- package/dist/command-families/tables/display.js +229 -0
- package/dist/command-families/tables/import-batches.d.ts +26 -0
- package/dist/command-families/tables/import-batches.js +94 -0
- package/dist/command-families/tables/import-columns.d.ts +24 -0
- package/dist/command-families/tables/import-columns.js +131 -0
- package/dist/command-families/tables/import-upload.d.ts +30 -0
- package/dist/command-families/tables/import-upload.js +203 -0
- package/dist/command-families/tables/import-values.d.ts +10 -0
- package/dist/command-families/tables/import-values.js +60 -0
- package/dist/command-families/tables/imports.d.ts +19 -0
- package/dist/command-families/tables/imports.js +200 -0
- package/dist/command-families/tables/options.d.ts +314 -0
- package/dist/command-families/tables/options.js +1 -0
- package/dist/command-families/tables/register-automation.d.ts +2 -0
- package/dist/command-families/tables/register-automation.js +127 -0
- package/dist/command-families/tables/register-external-imports.d.ts +2 -0
- package/dist/command-families/tables/register-external-imports.js +293 -0
- package/dist/command-families/tables/register-files.d.ts +2 -0
- package/dist/command-families/tables/register-files.js +72 -0
- package/dist/command-families/tables/register-followers.d.ts +2 -0
- package/dist/command-families/tables/register-followers.js +73 -0
- package/dist/command-families/tables/register-lifecycle.d.ts +2 -0
- package/dist/command-families/tables/register-lifecycle.js +114 -0
- package/dist/command-families/tables/register-reads.d.ts +2 -0
- package/dist/command-families/tables/register-reads.js +187 -0
- package/dist/command-families/tables/register-relations.d.ts +2 -0
- package/dist/command-families/tables/register-relations.js +244 -0
- package/dist/command-families/tables/register-row-actions.d.ts +2 -0
- package/dist/command-families/tables/register-row-actions.js +53 -0
- package/dist/command-families/tables/register-row-writes.d.ts +2 -0
- package/dist/command-families/tables/register-row-writes.js +140 -0
- package/dist/command-families/tables/register-views.d.ts +2 -0
- package/dist/command-families/tables/register-views.js +83 -0
- package/dist/command-families/tables/register-watchers.d.ts +2 -0
- package/dist/command-families/tables/register-watchers.js +65 -0
- package/dist/command-families/tables/register-webhooks.d.ts +2 -0
- package/dist/command-families/tables/register-webhooks.js +126 -0
- package/dist/command-families/tables/registration-context.d.ts +8 -0
- package/dist/command-families/tables/registration-context.js +1 -0
- package/dist/command-families/tables/registration.d.ts +3 -0
- package/dist/command-families/tables/registration.js +30 -0
- package/dist/command-families/tables/row-selection.d.ts +5 -0
- package/dist/command-families/tables/row-selection.js +82 -0
- package/dist/command-families/tables/send.d.ts +6 -0
- package/dist/command-families/tables/send.js +111 -0
- package/dist/command-manifest.js +1 -0
- package/dist/commands/copilot.js +8 -0
- package/dist/commands/deliverability.js +4 -2
- package/dist/commands/sequences.js +30 -2
- package/dist/commands/tables.d.ts +1 -3
- package/dist/commands/tables.js +1 -3505
- package/dist/credentials.js +1 -1
- package/dist/customer-operation-commands.js +62 -3
- package/dist/help.js +1 -1
- package/dist/index.d.ts +1 -99
- package/dist/index.js +5 -337
- package/dist/knowledge-mirror.js +1 -1
- package/dist/skills.js +4 -2
- package/dist/update.js +2 -1
- package/dist/workspace-placement-commands.d.ts +3 -0
- package/dist/workspace-placement-commands.js +32 -0
- package/node_modules/@oxygen/shared/dist/agent-sessions.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/agent-sessions.js +11 -3
- package/node_modules/@oxygen/shared/dist/agents-enabled.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/agents-enabled.js +51 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +39 -2
- package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/guided-activation.js +5 -5
- package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.js +53 -0
- package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.d.ts +120 -0
- package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.js +48 -0
- package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.d.ts +267 -0
- package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.js +63 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +9 -4
- package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.js +3 -0
- package/node_modules/@oxygen/shared/dist/contracts/teammates.js +17 -15
- package/node_modules/@oxygen/shared/dist/email-tracking-token.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/email-tracking-token.js +1 -0
- package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/feature-gates.js +5 -0
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +46 -0
- package/node_modules/@oxygen/shared/dist/file-import.js +138 -0
- package/node_modules/@oxygen/shared/dist/guided-activation.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/guided-company-files.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/guided-company-files.js +14 -0
- package/node_modules/@oxygen/shared/dist/guided-first-sourcing.d.ts +116 -0
- package/node_modules/@oxygen/shared/dist/guided-first-sourcing.js +11 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.js +42 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.js +38 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.d.ts +147 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.js +83 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.js +44 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.d.ts +7 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.js +13 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.js +34 -0
- package/node_modules/@oxygen/shared/dist/guided-trial-billing.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/guided-trial-billing.js +19 -0
- package/node_modules/@oxygen/shared/dist/index.d.ts +0 -1
- package/node_modules/@oxygen/shared/dist/index.js +0 -6
- package/node_modules/@oxygen/shared/dist/table-limits.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/table-limits.js +6 -0
- package/node_modules/@oxygen/shared/dist/teammates.d.ts +13 -8
- package/node_modules/@oxygen/shared/dist/teammates.js +20 -11
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +78 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/dist/workspace-placement-view.d.ts +149 -0
- package/node_modules/@oxygen/shared/dist/workspace-placement-view.js +101 -0
- package/node_modules/@oxygen/shared/dist/workspace-placement.d.ts +77 -0
- package/node_modules/@oxygen/shared/dist/workspace-placement.js +94 -0
- 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
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* sessions into routines.
|
|
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
|
|
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
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* sessions into routines.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
2
|
+
export const OXYGEN_BUILD_VERSION = "1.1014.1087";
|