@oxygen-agent/cli 1.1014.1035 → 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 (59) hide show
  1. package/README.md +1 -1
  2. package/dist/command-manifest.js +1 -0
  3. package/dist/commands/deliverability.js +2 -0
  4. package/dist/commands/sequences.js +30 -2
  5. package/dist/credentials.js +1 -1
  6. package/dist/customer-operation-commands.js +62 -3
  7. package/dist/help.js +1 -1
  8. package/dist/index.d.ts +0 -97
  9. package/dist/index.js +0 -98
  10. package/dist/workspace-placement-commands.d.ts +3 -0
  11. package/dist/workspace-placement-commands.js +32 -0
  12. package/node_modules/@oxygen/shared/dist/agent-sessions.js +1 -1
  13. package/node_modules/@oxygen/shared/dist/agents-enabled.js +5 -2
  14. package/node_modules/@oxygen/shared/dist/capability-discovery.js +23 -5
  15. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +1 -1
  16. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +1 -1
  17. package/node_modules/@oxygen/shared/dist/contracts/guided-activation.js +5 -5
  18. package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.d.ts +30 -0
  19. package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.js +53 -0
  20. package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.d.ts +120 -0
  21. package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.js +48 -0
  22. package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.d.ts +267 -0
  23. package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.js +63 -0
  24. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
  25. package/node_modules/@oxygen/shared/dist/contracts/operations.js +9 -4
  26. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.d.ts +2 -0
  27. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.js +3 -0
  28. package/node_modules/@oxygen/shared/dist/contracts/teammates.js +7 -7
  29. package/node_modules/@oxygen/shared/dist/email-tracking-token.d.ts +2 -0
  30. package/node_modules/@oxygen/shared/dist/email-tracking-token.js +1 -0
  31. package/node_modules/@oxygen/shared/dist/file-import.d.ts +46 -0
  32. package/node_modules/@oxygen/shared/dist/file-import.js +138 -0
  33. package/node_modules/@oxygen/shared/dist/guided-activation.d.ts +8 -0
  34. package/node_modules/@oxygen/shared/dist/guided-company-files.d.ts +13 -0
  35. package/node_modules/@oxygen/shared/dist/guided-company-files.js +14 -0
  36. package/node_modules/@oxygen/shared/dist/guided-first-sourcing.d.ts +116 -0
  37. package/node_modules/@oxygen/shared/dist/guided-first-sourcing.js +11 -0
  38. package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.d.ts +4 -0
  39. package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.js +42 -0
  40. package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.d.ts +22 -0
  41. package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.js +38 -0
  42. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.d.ts +147 -0
  43. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.d.ts +12 -0
  44. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.js +83 -0
  45. package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.js +44 -0
  46. package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.d.ts +7 -0
  47. package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.js +13 -0
  48. package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.d.ts +4 -0
  49. package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.js +34 -0
  50. package/node_modules/@oxygen/shared/dist/guided-trial-billing.d.ts +26 -0
  51. package/node_modules/@oxygen/shared/dist/guided-trial-billing.js +19 -0
  52. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +78 -0
  53. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  54. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  55. package/node_modules/@oxygen/shared/dist/workspace-placement-view.d.ts +149 -0
  56. package/node_modules/@oxygen/shared/dist/workspace-placement-view.js +101 -0
  57. package/node_modules/@oxygen/shared/dist/workspace-placement.d.ts +77 -0
  58. package/node_modules/@oxygen/shared/dist/workspace-placement.js +94 -0
  59. package/package.json +1 -1
@@ -0,0 +1,147 @@
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 declare const GUIDED_ONBOARDING_JOURNEY_VERSION: 1;
5
+ export declare const GUIDED_ONBOARDING_PART1_STEPS: readonly ["company_context", "company_research", "company_review", "audience_company_size", "audience_markets", "audience_industries", "audience_personas", "signals", "prospects", "trial"];
6
+ export declare const GUIDED_ONBOARDING_PART2_STEPS: readonly ["welcome", "daily_rhythm", "linkedin", "campaign", "sequence", "routines", "tour"];
7
+ export declare const GUIDED_ONBOARDING_STEPS: readonly ["company_context", "company_research", "company_review", "audience_company_size", "audience_markets", "audience_industries", "audience_personas", "signals", "prospects", "trial", "welcome", "daily_rhythm", "linkedin", "campaign", "sequence", "routines", "tour", "complete"];
8
+ export type GuidedOnboardingStep = typeof GUIDED_ONBOARDING_STEPS[number];
9
+ export type GuidedOnboardingPart = "part1" | "part2" | "complete";
10
+ export declare function guidedOnboardingPart(step: GuidedOnboardingStep): GuidedOnboardingPart;
11
+ export type GuidedOnboardingChoice = {
12
+ values: string[];
13
+ };
14
+ export type GuidedOnboardingSignal = {
15
+ mode: "none" | "selected";
16
+ values: string[];
17
+ };
18
+ export declare const GUIDED_ONBOARDING_TECHNOLOGY_RELATIONSHIPS: readonly ["uses", "replaces", "integrates_with"];
19
+ export type GuidedOnboardingTechnologyRelationship = typeof GUIDED_ONBOARDING_TECHNOLOGY_RELATIONSHIPS[number];
20
+ export type GuidedOnboardingTechnology = {
21
+ name: string;
22
+ relationship: GuidedOnboardingTechnologyRelationship;
23
+ };
24
+ export type GuidedOnboardingTechnologySignal = {
25
+ mode: "none" | "selected";
26
+ values: GuidedOnboardingTechnology[];
27
+ };
28
+ export type GuidedOnboardingAnswers = {
29
+ company_context?: {
30
+ website: string | null;
31
+ name: string;
32
+ description: string;
33
+ context_links: string[];
34
+ file_ids: string[];
35
+ };
36
+ /** Saving a statement alone is not its native confirmation receipt. */
37
+ company_review?: {
38
+ statement: string;
39
+ profile_revision: string;
40
+ };
41
+ audience_company_size?: GuidedOnboardingChoice;
42
+ audience_markets?: GuidedOnboardingChoice;
43
+ audience_industries?: GuidedOnboardingChoice;
44
+ audience_personas?: GuidedOnboardingChoice;
45
+ signals?: {
46
+ hiring: GuidedOnboardingSignal;
47
+ technology: GuidedOnboardingTechnologySignal;
48
+ };
49
+ prospects?: {
50
+ decision: "continue" | "refine";
51
+ feedback: string;
52
+ };
53
+ /** Connect is an intent. Only the native sender owner can prove a connection. */
54
+ linkedin?: {
55
+ choice: "connect" | "skip";
56
+ };
57
+ /** A draft remains a valid outcome on the optional LinkedIn branch. */
58
+ sequence?: {
59
+ decision: "review" | "keep_draft";
60
+ };
61
+ tour?: {
62
+ visited: Array<"overview" | "leads" | "sourcing" | "sequence">;
63
+ };
64
+ };
65
+ export type GuidedOnboardingResearchStatus = "not_started" | "running" | "completed" | "partial" | "unavailable" | "failed" | "credits_exhausted";
66
+ export type GuidedOnboardingResearch = {
67
+ status: GuidedOnboardingResearchStatus;
68
+ run_id: string | null;
69
+ knowledge_page_ids: string[];
70
+ /** Fixed customer-safe code only. Provider diagnostics remain in their owner. */
71
+ fault: {
72
+ code: string;
73
+ retryable: boolean;
74
+ } | null;
75
+ };
76
+ export type GuidedOnboardingProspect = {
77
+ row_id: string;
78
+ person_key: string;
79
+ name: string;
80
+ title: string;
81
+ company: string;
82
+ linkedin_url: string | null;
83
+ sources: Array<{
84
+ url: string;
85
+ title: string;
86
+ }>;
87
+ fit: {
88
+ rationale: string;
89
+ criteria: string[];
90
+ };
91
+ };
92
+ export type GuidedOnboardingProspectLimitation = {
93
+ field: string;
94
+ code: "unsupported_filter";
95
+ blocking: boolean;
96
+ message: string;
97
+ values: string[];
98
+ suggestions: string[];
99
+ };
100
+ export type GuidedOnboardingProspects = {
101
+ status: "not_started" | "running" | "ready" | "partial" | "empty" | "unavailable" | "failed" | "credits_exhausted";
102
+ table_id: string | null;
103
+ ingestion_run_ids: string[];
104
+ /** Up to five native source-backed people; an empty array is never success. */
105
+ people: GuidedOnboardingProspect[];
106
+ /** Absent in legacy receipts means unknown, never proof of supported filters.
107
+ * Current D projections supply actual structured diagnostics, including []. */
108
+ limitations?: GuidedOnboardingProspectLimitation[];
109
+ fault: {
110
+ code: string;
111
+ retryable: boolean;
112
+ } | null;
113
+ };
114
+ /** Read projection from native billing, not an accepted browser mutation field.
115
+ * I owns the actual test Checkout/subscription/grant producer and its signatures. */
116
+ export type GuidedOnboardingEligibility = {
117
+ state: "unverified" | "checkout_required" | "checkout_pending" | "eligible" | "unavailable";
118
+ basis: "paid" | "trial" | null;
119
+ subscription_id: string | null;
120
+ observed_at: string | null;
121
+ trial_ends_at: string | null;
122
+ };
123
+ export type GuidedOnboardingJourney = {
124
+ version: typeof GUIDED_ONBOARDING_JOURNEY_VERSION;
125
+ /** Increments on non-destructive restart; activation revision guards writes. */
126
+ generation: number;
127
+ step: GuidedOnboardingStep;
128
+ completed_steps: GuidedOnboardingStep[];
129
+ /** Presentation state is authoritative and independent of deduplicated history. */
130
+ navigation: {
131
+ paused: boolean;
132
+ tour_active_stop: "overview" | "leads" | "sourcing" | "sequence" | null;
133
+ };
134
+ answers: GuidedOnboardingAnswers;
135
+ /** Native confirmation binds the actual typed company profile revision. */
136
+ company_confirmation: {
137
+ profile_revision: string;
138
+ statement_digest: string;
139
+ confirmed_at: string;
140
+ } | null;
141
+ research: GuidedOnboardingResearch;
142
+ prospects: GuidedOnboardingProspects;
143
+ };
144
+ /** Free initialization; creates no research, chat turn, subscription or resource. */
145
+ export declare function createGuidedOnboardingJourney(): GuidedOnboardingJourney;
146
+ /** Old saved v1 records have no current-stop evidence. Never guess from visited[]. */
147
+ export declare function normalizeSavedGuidedOnboardingJourney(journey: GuidedOnboardingJourney): GuidedOnboardingJourney;
@@ -0,0 +1,12 @@
1
+ import { type GuidedOnboardingJourney, type GuidedOnboardingEligibility } from "./guided-onboarding-journey.js";
2
+ /** Synthetic component/test data only. Never substitute this for hosted receipts. */
3
+ export declare const GUIDED_ONBOARDING_FIXTURE_NAMES: readonly ["part1_initial", "research_running", "company_review", "audience_question", "technology_relationships", "prospects_ready", "prospects_partial", "prospects_empty", "prospects_unavailable", "prospects_failed", "research_failed", "credits_exhausted", "checkout_pending", "billing_unavailable", "part2_trial", "part2_paid", "linkedin_skipped", "tour_paused_back", "complete"];
4
+ export type GuidedOnboardingFixtureName = typeof GUIDED_ONBOARDING_FIXTURE_NAMES[number];
5
+ export type GuidedOnboardingFixture = {
6
+ fixture_only: true;
7
+ label: string;
8
+ activation_revision: number;
9
+ journey: GuidedOnboardingJourney;
10
+ eligibility: GuidedOnboardingEligibility;
11
+ };
12
+ export declare function createGuidedOnboardingFixture(name: GuidedOnboardingFixtureName): GuidedOnboardingFixture;
@@ -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
+ }
@@ -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.1035";
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.1035";
2
+ export const OXYGEN_BUILD_VERSION = "1.1014.1087";