@oxygen-agent/cli 1.1014.1343 → 1.1014.1451
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.js +2 -0
- package/dist/command-families/tables/register-reads.js +1 -1
- package/dist/command-manifest.js +1 -0
- package/dist/command-support.js +4 -2
- package/dist/commands/blueprints.js +10 -6
- package/dist/commands/clay-migration.d.ts +3 -0
- package/dist/commands/clay-migration.js +22 -0
- package/dist/commands/crm.js +5 -2
- package/dist/commands/dashboards.js +4 -2
- package/dist/commands/db.js +1 -1
- package/dist/commands/directory.js +7 -4
- package/dist/commands/domains.js +1 -1
- package/dist/commands/inbox.js +5 -2
- package/dist/commands/prompts.js +4 -2
- package/dist/commands/publishing.js +5 -2
- package/dist/commands/sequences.js +13 -4
- package/dist/commands/support.js +30 -19
- package/dist/customer-operation-commands.js +0 -42
- package/dist/http-client.js +4 -1
- package/dist/workspace-placement-commands.js +1 -1
- package/node_modules/@oxygen/shared/dist/capability-args.d.ts +19 -0
- package/node_modules/@oxygen/shared/dist/capability-args.js +73 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +15 -2
- package/node_modules/@oxygen/shared/dist/clay-migration-auth-state.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/clay-migration-auth-state.js +15 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +2 -1
- package/node_modules/@oxygen/shared/dist/contracts/clay-migration.d.ts +71 -0
- package/node_modules/@oxygen/shared/dist/contracts/clay-migration.js +60 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +4 -6
- package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.d.ts +5 -1
- package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.js +25 -2
- package/node_modules/@oxygen/shared/dist/contracts/teammates.js +1 -1
- package/node_modules/@oxygen/shared/dist/dev-eval-context.js +1 -0
- package/node_modules/@oxygen/shared/dist/enrollment-origin.d.ts +3 -1
- package/node_modules/@oxygen/shared/dist/enrollment-origin.js +2 -0
- package/node_modules/@oxygen/shared/dist/guided-activation.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/guided-onboarding-company-context.d.ts +9 -2
- package/node_modules/@oxygen/shared/dist/guided-trial-billing.d.ts +10 -2
- package/node_modules/@oxygen/shared/dist/guided-trial-billing.js +2 -5
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +8 -4
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +1 -0
- package/node_modules/@oxygen/shared/dist/onboarding-plays.d.ts +68 -0
- package/node_modules/@oxygen/shared/dist/onboarding-plays.js +114 -0
- package/node_modules/@oxygen/shared/dist/onboarding-research.d.ts +42 -0
- package/node_modules/@oxygen/shared/dist/onboarding-research.js +62 -0
- package/node_modules/@oxygen/shared/dist/placement-copy.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/placement-copy.js +16 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +8 -0
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +30 -2
- package/node_modules/@oxygen/shared/dist/sequences.js +67 -7
- package/node_modules/@oxygen/shared/dist/teammates.d.ts +3 -1
- package/node_modules/@oxygen/shared/dist/teammates.js +4 -2
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +19 -40
- 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.js +4 -0
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.d.ts +0 -30
- package/node_modules/@oxygen/shared/dist/contracts/guided-company-files.js +0 -53
- package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.d.ts +0 -120
- package/node_modules/@oxygen/shared/dist/contracts/guided-first-sourcing.js +0 -48
- package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.d.ts +0 -267
- package/node_modules/@oxygen/shared/dist/contracts/guided-onboarding-journey.js +0 -63
- package/node_modules/@oxygen/shared/dist/guided-company-files.d.ts +0 -13
- package/node_modules/@oxygen/shared/dist/guided-company-files.js +0 -14
- package/node_modules/@oxygen/shared/dist/guided-first-sourcing.d.ts +0 -116
- package/node_modules/@oxygen/shared/dist/guided-first-sourcing.js +0 -11
- package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.d.ts +0 -4
- package/node_modules/@oxygen/shared/dist/guided-onboarding-answers.js +0 -42
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.d.ts +0 -147
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.d.ts +0 -12
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.fixture.js +0 -83
- package/node_modules/@oxygen/shared/dist/guided-onboarding-journey.js +0 -44
- package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.d.ts +0 -7
- package/node_modules/@oxygen/shared/dist/guided-onboarding-prospects.js +0 -13
- package/node_modules/@oxygen/shared/dist/guided-onboarding-recommendations.d.ts +0 -54
- package/node_modules/@oxygen/shared/dist/guided-onboarding-recommendations.js +0 -100
- package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.d.ts +0 -4
- package/node_modules/@oxygen/shared/dist/guided-onboarding-signals.js +0 -34
|
@@ -1,147 +0,0 @@
|
|
|
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;
|
|
@@ -1,12 +0,0 @@
|
|
|
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;
|
|
@@ -1,83 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { GuidedOnboardingAnswers } from "./guided-onboarding-journey.js";
|
|
2
|
-
export declare const ONBOARDING_AUDIENCE_QUESTIONS: {
|
|
3
|
-
readonly audience_company_size: "What size companies do you sell to?";
|
|
4
|
-
readonly audience_markets: "Which markets do you serve?";
|
|
5
|
-
readonly audience_industries: "Which industries fit your customers?";
|
|
6
|
-
readonly audience_personas: "Who buys from you?";
|
|
7
|
-
};
|
|
8
|
-
export type OnboardingAudienceStep = keyof typeof ONBOARDING_AUDIENCE_QUESTIONS;
|
|
9
|
-
export type OnboardingRecommendation = {
|
|
10
|
-
values: string[];
|
|
11
|
-
rationale: string;
|
|
12
|
-
source_revision: number;
|
|
13
|
-
source_page?: {
|
|
14
|
-
id: string;
|
|
15
|
-
slug: string;
|
|
16
|
-
};
|
|
17
|
-
sources: Array<{
|
|
18
|
-
id: string;
|
|
19
|
-
url: string;
|
|
20
|
-
title: string | null;
|
|
21
|
-
}>;
|
|
22
|
-
};
|
|
23
|
-
export declare const ONBOARDING_DRAFT_FILTER_PAGES: {
|
|
24
|
-
readonly audience_company_size: "filter-company-size";
|
|
25
|
-
readonly audience_markets: "filter-regions";
|
|
26
|
-
readonly audience_industries: "filter-industries";
|
|
27
|
-
readonly audience_personas: "filter-job-titles";
|
|
28
|
-
};
|
|
29
|
-
export type OnboardingDraftFilterPage = {
|
|
30
|
-
id: string;
|
|
31
|
-
slug: string;
|
|
32
|
-
revision: number;
|
|
33
|
-
body: string;
|
|
34
|
-
data: unknown;
|
|
35
|
-
};
|
|
36
|
-
export type OnboardingRecommendations = Partial<Record<OnboardingAudienceStep, OnboardingRecommendation>> & {
|
|
37
|
-
signals?: {
|
|
38
|
-
answer: NonNullable<GuidedOnboardingAnswers["signals"]>;
|
|
39
|
-
source_revision: number;
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
/** The background research's target-customer projection, never the company's
|
|
43
|
-
* own headcount/industry or a generic catalog. Recommendations are unsaved drafts. */
|
|
44
|
-
export declare function guidedOnboardingRecommendations(profile: {
|
|
45
|
-
revision: number;
|
|
46
|
-
data: {
|
|
47
|
-
icp?: Record<string, unknown>;
|
|
48
|
-
};
|
|
49
|
-
} | null | undefined, evidence?: OnboardingRecommendation["sources"], draft?: {
|
|
50
|
-
domain: string | null;
|
|
51
|
-
pages: OnboardingDraftFilterPage[];
|
|
52
|
-
}): OnboardingRecommendations;
|
|
53
|
-
/** Only deliberate, saved answers enter shared chat history; no sealed research. */
|
|
54
|
-
export declare function onboardingAnswerPost(answers: GuidedOnboardingAnswers): string | null;
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { asRecordOrEmpty } from "./type-guards.js";
|
|
2
|
-
export const ONBOARDING_AUDIENCE_QUESTIONS = {
|
|
3
|
-
audience_company_size: "What size companies do you sell to?",
|
|
4
|
-
audience_markets: "Which markets do you serve?",
|
|
5
|
-
audience_industries: "Which industries fit your customers?",
|
|
6
|
-
audience_personas: "Who buys from you?",
|
|
7
|
-
};
|
|
8
|
-
export const ONBOARDING_DRAFT_FILTER_PAGES = {
|
|
9
|
-
audience_company_size: "filter-company-size", audience_markets: "filter-regions",
|
|
10
|
-
audience_industries: "filter-industries", audience_personas: "filter-job-titles",
|
|
11
|
-
};
|
|
12
|
-
function values(value) {
|
|
13
|
-
const list = typeof value === "string" ? [value] : Array.isArray(value) ? value : [];
|
|
14
|
-
const unique = new Map();
|
|
15
|
-
for (const item of list) {
|
|
16
|
-
if (typeof item !== "string")
|
|
17
|
-
continue;
|
|
18
|
-
const text = item.normalize("NFKC").trim().replace(/\s+/gu, " ");
|
|
19
|
-
if (text && text.length <= 160)
|
|
20
|
-
unique.set(text.toLowerCase(), text);
|
|
21
|
-
}
|
|
22
|
-
return [...unique.values()];
|
|
23
|
-
}
|
|
24
|
-
/** The background research's target-customer projection, never the company's
|
|
25
|
-
* own headcount/industry or a generic catalog. Recommendations are unsaved drafts. */
|
|
26
|
-
export function guidedOnboardingRecommendations(profile, evidence = [], draft) {
|
|
27
|
-
const icp = profile?.data.icp ?? {};
|
|
28
|
-
const candidates = {
|
|
29
|
-
audience_company_size: icp.company_sizes ?? icp.company_size,
|
|
30
|
-
audience_markets: icp.markets ?? icp.geographies,
|
|
31
|
-
audience_industries: icp.industries,
|
|
32
|
-
audience_personas: icp.buyer_personas ?? icp.buyer_titles,
|
|
33
|
-
};
|
|
34
|
-
const sources = evidence.filter(source => {
|
|
35
|
-
try {
|
|
36
|
-
const url = new URL(source.url);
|
|
37
|
-
return url.protocol === "https:" && !url.username && !url.password;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}).slice(0, 8);
|
|
43
|
-
const result = {};
|
|
44
|
-
for (const [step, candidate] of Object.entries(candidates)) {
|
|
45
|
-
const key = step;
|
|
46
|
-
const page = candidate === undefined && draft?.domain ? draft.pages.find(page => page.slug === ONBOARDING_DRAFT_FILTER_PAGES[key]
|
|
47
|
-
&& asRecordOrEmpty(asRecordOrEmpty(page.data).brain_draft).domain === draft.domain) : undefined;
|
|
48
|
-
const provenance = asRecordOrEmpty(asRecordOrEmpty(page?.data).brain_draft);
|
|
49
|
-
const selected = values(page ? [...page.body.matchAll(/^- ([^\r\n]+)$/gm)].map(match => match[1]) : candidate).slice(0, 3);
|
|
50
|
-
if (!selected.length)
|
|
51
|
-
continue;
|
|
52
|
-
const references = page ? values(provenance.source_urls).flatMap((url, index) => {
|
|
53
|
-
try {
|
|
54
|
-
const parsed = new URL(url);
|
|
55
|
-
return parsed.protocol === "https:" && !parsed.username && !parsed.password ? [{ id: `${page.id}:${index}`, url, title: null }] : [];
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
}) : sources;
|
|
61
|
-
result[key] = { values: selected,
|
|
62
|
-
rationale: `I'd start with ${selected.join(", ")} from your ${page ? "draft" : "saved"} target-customer research. Confirm this starting audience or adjust it.`,
|
|
63
|
-
source_revision: page?.revision ?? profile.revision, sources: references,
|
|
64
|
-
...(page ? { source_page: { id: page.id, slug: page.slug } } : {}) };
|
|
65
|
-
}
|
|
66
|
-
const hiring = values(icp.hiring_roles).slice(0, 3);
|
|
67
|
-
const relationships = new Set(["uses", "integrates_with", "replaces"]);
|
|
68
|
-
const technology = (Array.isArray(icp.technology_relationships) ? icp.technology_relationships : []).flatMap(item => {
|
|
69
|
-
if (!item || typeof item !== "object" || !relationships.has(item.relationship))
|
|
70
|
-
return [];
|
|
71
|
-
const name = values(item.name)[0];
|
|
72
|
-
return name ? [{ name, relationship: item.relationship }] : [];
|
|
73
|
-
}).slice(0, 3);
|
|
74
|
-
if (hiring.length || technology.length)
|
|
75
|
-
result.signals = { source_revision: profile.revision,
|
|
76
|
-
answer: { hiring: { mode: hiring.length ? "selected" : "none", values: hiring },
|
|
77
|
-
technology: { mode: technology.length ? "selected" : "none", values: technology } } };
|
|
78
|
-
return result;
|
|
79
|
-
}
|
|
80
|
-
/** Only deliberate, saved answers enter shared chat history; no sealed research. */
|
|
81
|
-
export function onboardingAnswerPost(answers) {
|
|
82
|
-
for (const [step, question] of Object.entries(ONBOARDING_AUDIENCE_QUESTIONS)) {
|
|
83
|
-
const answer = answers[step];
|
|
84
|
-
if (answer)
|
|
85
|
-
return `${question}\n\nConfirmed: ${answer.values.join(", ")}`;
|
|
86
|
-
}
|
|
87
|
-
if (answers.company_context) {
|
|
88
|
-
const answer = answers.company_context;
|
|
89
|
-
return `Your company\n\n${[answer.name, answer.website, answer.description].filter(Boolean).join("\n")}`;
|
|
90
|
-
}
|
|
91
|
-
if (answers.company_review)
|
|
92
|
-
return `Your company\n\nConfirmed: ${answers.company_review.statement}`;
|
|
93
|
-
if (answers.signals) {
|
|
94
|
-
const signals = answers.signals;
|
|
95
|
-
const selected = [...signals.hiring.values.map(role => `Hiring: ${role}`),
|
|
96
|
-
...signals.technology.values.map(item => `${item.name} (${item.relationship})`)];
|
|
97
|
-
return `Which signals matter to you?\n\nConfirmed: ${selected.length ? selected.join(", ") : "No signals for now"}`;
|
|
98
|
-
}
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
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"]>;
|
|
@@ -1,34 +0,0 @@
|
|
|
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
|
-
}
|