@sellable/mcp 0.1.94 → 0.1.95
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/dist/tools/context.d.ts +16 -0
- package/dist/tools/context.js +16 -0
- package/dist/tools/navigation.d.ts +33 -0
- package/dist/tools/navigation.js +161 -10
- package/dist/tools/readiness.d.ts +48 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +39 -0
- package/skills/create-campaign-v2/SKILL.md +1 -1
- package/skills/create-campaign-v2/core/flow.v2.json +24 -2
package/dist/tools/context.d.ts
CHANGED
|
@@ -68,6 +68,22 @@ export declare function getCampaignContext(input: GetCampaignContextInput): Prom
|
|
|
68
68
|
expectedHeadlessStep: string | null;
|
|
69
69
|
headlessCurrentStep: string | null;
|
|
70
70
|
uiStep: string | null;
|
|
71
|
+
orientation: {
|
|
72
|
+
visibleStep: string | null;
|
|
73
|
+
browserStepLabel: string;
|
|
74
|
+
customerSummary: string;
|
|
75
|
+
nextVisibleMilestone: string;
|
|
76
|
+
blockedReason: string | null;
|
|
77
|
+
agentGuidance: string;
|
|
78
|
+
browserCheckpoint: string;
|
|
79
|
+
senderSelectionAllowed: boolean;
|
|
80
|
+
safeToAskSender: boolean;
|
|
81
|
+
};
|
|
82
|
+
watchUrl: {
|
|
83
|
+
urlPresent: boolean;
|
|
84
|
+
signed: boolean;
|
|
85
|
+
redirectPath: string | null;
|
|
86
|
+
};
|
|
71
87
|
table: {
|
|
72
88
|
workflowTableId: string | null;
|
|
73
89
|
checked: boolean;
|
package/dist/tools/context.js
CHANGED
|
@@ -165,6 +165,22 @@ export function markCampaignContextDirty(campaignId, reason) {
|
|
|
165
165
|
expectedHeadlessStep: "create-offer",
|
|
166
166
|
headlessCurrentStep: null,
|
|
167
167
|
uiStep: "plan",
|
|
168
|
+
orientation: {
|
|
169
|
+
visibleStep: "plan",
|
|
170
|
+
browserStepLabel: "Campaign brief",
|
|
171
|
+
customerSummary: "The campaign view is waiting for saved campaign context.",
|
|
172
|
+
nextVisibleMilestone: "Lead source search",
|
|
173
|
+
blockedReason: "Missing campaignContextNotLoaded",
|
|
174
|
+
agentGuidance: "Refresh campaign navigation state before describing the browser.",
|
|
175
|
+
browserCheckpoint: "brief",
|
|
176
|
+
senderSelectionAllowed: false,
|
|
177
|
+
safeToAskSender: false,
|
|
178
|
+
},
|
|
179
|
+
watchUrl: {
|
|
180
|
+
urlPresent: false,
|
|
181
|
+
signed: false,
|
|
182
|
+
redirectPath: null,
|
|
183
|
+
},
|
|
168
184
|
table: {
|
|
169
185
|
workflowTableId: null,
|
|
170
186
|
checked: false,
|
|
@@ -25,6 +25,7 @@ export type CampaignOfferNavigation = {
|
|
|
25
25
|
campaignStatus?: string | null;
|
|
26
26
|
status?: string | null;
|
|
27
27
|
currentStep?: string | null;
|
|
28
|
+
watchUrl?: string | null;
|
|
28
29
|
};
|
|
29
30
|
type NavigationDebugPayload = Record<string, unknown>;
|
|
30
31
|
export declare function logNavigationDebug(event: string, payload?: NavigationDebugPayload, campaignId?: string | null): void;
|
|
@@ -67,6 +68,22 @@ export declare function computeCampaignNavigationStateFromCampaign(campaign: Cam
|
|
|
67
68
|
expectedHeadlessStep: string | null;
|
|
68
69
|
headlessCurrentStep: string | null;
|
|
69
70
|
uiStep: string | null;
|
|
71
|
+
orientation: {
|
|
72
|
+
visibleStep: string | null;
|
|
73
|
+
browserStepLabel: string;
|
|
74
|
+
customerSummary: string;
|
|
75
|
+
nextVisibleMilestone: string;
|
|
76
|
+
blockedReason: string | null;
|
|
77
|
+
agentGuidance: string;
|
|
78
|
+
browserCheckpoint: string;
|
|
79
|
+
senderSelectionAllowed: boolean;
|
|
80
|
+
safeToAskSender: boolean;
|
|
81
|
+
};
|
|
82
|
+
watchUrl: {
|
|
83
|
+
urlPresent: boolean;
|
|
84
|
+
signed: boolean;
|
|
85
|
+
redirectPath: string | null;
|
|
86
|
+
};
|
|
70
87
|
table: {
|
|
71
88
|
workflowTableId: string | null;
|
|
72
89
|
checked: boolean;
|
|
@@ -95,6 +112,22 @@ export declare function getCampaignNavigationState(input: GetCampaignNavigationS
|
|
|
95
112
|
expectedHeadlessStep: string | null;
|
|
96
113
|
headlessCurrentStep: string | null;
|
|
97
114
|
uiStep: string | null;
|
|
115
|
+
orientation: {
|
|
116
|
+
visibleStep: string | null;
|
|
117
|
+
browserStepLabel: string;
|
|
118
|
+
customerSummary: string;
|
|
119
|
+
nextVisibleMilestone: string;
|
|
120
|
+
blockedReason: string | null;
|
|
121
|
+
agentGuidance: string;
|
|
122
|
+
browserCheckpoint: string;
|
|
123
|
+
senderSelectionAllowed: boolean;
|
|
124
|
+
safeToAskSender: boolean;
|
|
125
|
+
};
|
|
126
|
+
watchUrl: {
|
|
127
|
+
urlPresent: boolean;
|
|
128
|
+
signed: boolean;
|
|
129
|
+
redirectPath: string | null;
|
|
130
|
+
};
|
|
98
131
|
table: {
|
|
99
132
|
workflowTableId: string | null;
|
|
100
133
|
checked: boolean;
|
package/dist/tools/navigation.js
CHANGED
|
@@ -301,6 +301,120 @@ function mapHeadlessToUiStep(step) {
|
|
|
301
301
|
}
|
|
302
302
|
return null;
|
|
303
303
|
}
|
|
304
|
+
function describeVisibleStep(step) {
|
|
305
|
+
switch (step) {
|
|
306
|
+
case "plan":
|
|
307
|
+
return {
|
|
308
|
+
label: "Campaign brief",
|
|
309
|
+
summary: "The campaign brief is visible in the campaign view.",
|
|
310
|
+
nextMilestone: "Lead source search",
|
|
311
|
+
guidance: "Confirm the browser-visible campaign state before moving to lead sourcing.",
|
|
312
|
+
checkpoint: "brief",
|
|
313
|
+
};
|
|
314
|
+
case "pick-provider":
|
|
315
|
+
case "contact-search":
|
|
316
|
+
case "signal-discovery":
|
|
317
|
+
return {
|
|
318
|
+
label: "Lead sourcing",
|
|
319
|
+
summary: "Lead source selection or search is visible.",
|
|
320
|
+
nextMilestone: "Lead preview",
|
|
321
|
+
guidance: "Explain the selected lead-source lane and visible search state before continuing.",
|
|
322
|
+
checkpoint: "lead-source",
|
|
323
|
+
};
|
|
324
|
+
case "leads":
|
|
325
|
+
return {
|
|
326
|
+
label: "Lead import",
|
|
327
|
+
summary: "The lead preview or imported review batch is visible.",
|
|
328
|
+
nextMilestone: "Fit filtering and message review",
|
|
329
|
+
guidance: "Confirm the browser-visible campaign state and row batch before filter/message work.",
|
|
330
|
+
checkpoint: "import",
|
|
331
|
+
};
|
|
332
|
+
case "filter-choice":
|
|
333
|
+
case "filter-rules":
|
|
334
|
+
case "filter-leads":
|
|
335
|
+
return {
|
|
336
|
+
label: "Fit filtering",
|
|
337
|
+
summary: "Fit filtering or sample validation is visible.",
|
|
338
|
+
nextMilestone: "Message review or validation",
|
|
339
|
+
guidance: "Explain the visible filter or validation state and wait for the next approved step.",
|
|
340
|
+
checkpoint: "filters",
|
|
341
|
+
};
|
|
342
|
+
case "messages":
|
|
343
|
+
return {
|
|
344
|
+
label: "Message review",
|
|
345
|
+
summary: "Message review or generation is visible.",
|
|
346
|
+
nextMilestone: "10-row validation",
|
|
347
|
+
guidance: "Explain the visible message state before asking for approval or validation.",
|
|
348
|
+
checkpoint: "messages",
|
|
349
|
+
};
|
|
350
|
+
case "settings":
|
|
351
|
+
return {
|
|
352
|
+
label: "Settings",
|
|
353
|
+
summary: "Settings is visible. Sender selection belongs here.",
|
|
354
|
+
nextMilestone: "Safe sender selection",
|
|
355
|
+
guidance: "Select a safe connected sender here only; stop before sequence/start/live send in UAT.",
|
|
356
|
+
checkpoint: "settings",
|
|
357
|
+
};
|
|
358
|
+
case "sequence":
|
|
359
|
+
return {
|
|
360
|
+
label: "Sequence setup",
|
|
361
|
+
summary: "Sequence setup is visible.",
|
|
362
|
+
nextMilestone: "Explicit launch approval",
|
|
363
|
+
guidance: "Do not attach or change sequence state during watch UAT unless explicitly approved.",
|
|
364
|
+
checkpoint: "sequence",
|
|
365
|
+
};
|
|
366
|
+
case "send":
|
|
367
|
+
return {
|
|
368
|
+
label: "Send review",
|
|
369
|
+
summary: "Send review or running status is visible.",
|
|
370
|
+
nextMilestone: "Explicit launch approval",
|
|
371
|
+
guidance: "Do not start the campaign or trigger live send without explicit user confirmation.",
|
|
372
|
+
checkpoint: "send",
|
|
373
|
+
};
|
|
374
|
+
default:
|
|
375
|
+
return {
|
|
376
|
+
label: "Campaign view",
|
|
377
|
+
summary: "The campaign view is loading or waiting for the next saved step.",
|
|
378
|
+
nextMilestone: "Next saved campaign step",
|
|
379
|
+
guidance: "Inspect the browser-visible campaign state before continuing with more tools.",
|
|
380
|
+
checkpoint: "unknown",
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function parseSignedWatchUrl(watchUrl, campaignId) {
|
|
385
|
+
if (!watchUrl) {
|
|
386
|
+
return {
|
|
387
|
+
urlPresent: false,
|
|
388
|
+
signed: false,
|
|
389
|
+
redirectPath: null,
|
|
390
|
+
warning: null,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
const url = new URL(watchUrl);
|
|
395
|
+
const redirect = url.searchParams.get("redirect");
|
|
396
|
+
const decodedRedirect = redirect ? decodeURIComponent(redirect) : null;
|
|
397
|
+
const signed = url.pathname === "/auth/continue" &&
|
|
398
|
+
Boolean(url.searchParams.get("token")) &&
|
|
399
|
+
decodedRedirect === `/campaign-builder/${campaignId}?mode=claude`;
|
|
400
|
+
return {
|
|
401
|
+
urlPresent: true,
|
|
402
|
+
signed,
|
|
403
|
+
redirectPath: decodedRedirect,
|
|
404
|
+
warning: signed
|
|
405
|
+
? null
|
|
406
|
+
: "Watch URL is not a signed /auth/continue watch link for /campaign-builder/{campaignId}?mode=claude.",
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return {
|
|
411
|
+
urlPresent: true,
|
|
412
|
+
signed: false,
|
|
413
|
+
redirectPath: null,
|
|
414
|
+
warning: "Watch URL is malformed; recover a fresh signed /auth/continue watch link before browser handoff.",
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
304
418
|
export const navigationToolDefinitions = [
|
|
305
419
|
{
|
|
306
420
|
name: "get_campaign_navigation_state",
|
|
@@ -401,30 +515,49 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
|
|
|
401
515
|
if (!blockedAt && evaluateTailState) {
|
|
402
516
|
computedStep = isRunningCampaign(campaign) ? "running" : "send";
|
|
403
517
|
}
|
|
404
|
-
const
|
|
518
|
+
const stepForHeadless = blockedAt ?? computedStep;
|
|
519
|
+
const expectedHeadlessStep = stepForHeadless === "campaign-created"
|
|
405
520
|
? "create-offer"
|
|
406
|
-
:
|
|
521
|
+
: stepForHeadless === "provider-search"
|
|
407
522
|
? providerConfig?.currentStep || campaign.leadSourceProvider || null
|
|
408
|
-
:
|
|
523
|
+
: stepForHeadless === "filter-rules"
|
|
409
524
|
? "create-icp-rubric"
|
|
410
|
-
:
|
|
525
|
+
: stepForHeadless === "messages"
|
|
411
526
|
? "messages"
|
|
412
|
-
:
|
|
527
|
+
: stepForHeadless === "settings"
|
|
413
528
|
? "settings"
|
|
414
|
-
:
|
|
529
|
+
: stepForHeadless === "sequence"
|
|
415
530
|
? "sequence"
|
|
416
|
-
:
|
|
531
|
+
: stepForHeadless === "running"
|
|
417
532
|
? "running"
|
|
418
|
-
:
|
|
533
|
+
: stepForHeadless;
|
|
534
|
+
const currentUiStep = mapHeadlessToUiStep(campaign.currentStep);
|
|
535
|
+
const expectedUiStep = mapHeadlessToUiStep(expectedHeadlessStep);
|
|
419
536
|
const stepAligned = !campaign.currentStep || !expectedHeadlessStep
|
|
420
537
|
? null
|
|
421
|
-
: campaign.currentStep === expectedHeadlessStep
|
|
538
|
+
: campaign.currentStep === expectedHeadlessStep ||
|
|
539
|
+
(currentUiStep !== null && currentUiStep === expectedUiStep);
|
|
422
540
|
if (stepAligned === false && campaign.currentStep && expectedHeadlessStep) {
|
|
423
541
|
warnings.push(`Headless step mismatch: expected "${expectedHeadlessStep}" but campaign.currentStep is "${campaign.currentStep}".`);
|
|
424
542
|
}
|
|
425
543
|
if (!providerConfig && campaign.leadSourceProvider) {
|
|
426
544
|
warnings.push(`Provider config not found for "${campaign.leadSourceProvider}".`);
|
|
427
545
|
}
|
|
546
|
+
const uiStep = currentUiStep;
|
|
547
|
+
const orientationStep = uiStep || mapHeadlessToUiStep(expectedHeadlessStep);
|
|
548
|
+
const orientationSource = isRunningCampaign(campaign)
|
|
549
|
+
? {
|
|
550
|
+
label: "Running campaign",
|
|
551
|
+
summary: "The campaign is running and the send review is visible.",
|
|
552
|
+
nextMilestone: "Explicit launch approval",
|
|
553
|
+
guidance: "Confirm the browser-visible campaign state before describing the running status.",
|
|
554
|
+
checkpoint: "send",
|
|
555
|
+
}
|
|
556
|
+
: describeVisibleStep(orientationStep);
|
|
557
|
+
const watchUrlState = parseSignedWatchUrl(campaign.watchUrl, campaign.id);
|
|
558
|
+
if (watchUrlState.warning) {
|
|
559
|
+
warnings.push(watchUrlState.warning);
|
|
560
|
+
}
|
|
428
561
|
const result = {
|
|
429
562
|
campaignId: campaign.id,
|
|
430
563
|
computedStep,
|
|
@@ -432,7 +565,23 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
|
|
|
432
565
|
missing,
|
|
433
566
|
expectedHeadlessStep,
|
|
434
567
|
headlessCurrentStep: campaign.currentStep ?? null,
|
|
435
|
-
uiStep
|
|
568
|
+
uiStep,
|
|
569
|
+
orientation: {
|
|
570
|
+
visibleStep: orientationStep,
|
|
571
|
+
browserStepLabel: orientationSource.label,
|
|
572
|
+
customerSummary: orientationSource.summary,
|
|
573
|
+
nextVisibleMilestone: orientationSource.nextMilestone,
|
|
574
|
+
blockedReason: missing.length > 0 ? `Missing ${missing.join(", ")}` : null,
|
|
575
|
+
agentGuidance: orientationSource.guidance,
|
|
576
|
+
browserCheckpoint: orientationSource.checkpoint,
|
|
577
|
+
senderSelectionAllowed: orientationStep === "settings",
|
|
578
|
+
safeToAskSender: orientationStep === "settings",
|
|
579
|
+
},
|
|
580
|
+
watchUrl: {
|
|
581
|
+
urlPresent: watchUrlState.urlPresent,
|
|
582
|
+
signed: watchUrlState.signed,
|
|
583
|
+
redirectPath: watchUrlState.redirectPath,
|
|
584
|
+
},
|
|
436
585
|
table: {
|
|
437
586
|
workflowTableId: campaign.workflowTableId ?? null,
|
|
438
587
|
checked: options.tableChecked,
|
|
@@ -461,6 +610,8 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
|
|
|
461
610
|
expectedHeadlessStep: result.expectedHeadlessStep,
|
|
462
611
|
headlessCurrentStep: result.headlessCurrentStep,
|
|
463
612
|
uiStep: result.uiStep,
|
|
613
|
+
orientation: result.orientation,
|
|
614
|
+
watchUrl: result.watchUrl,
|
|
464
615
|
table: result.table,
|
|
465
616
|
context: result.context,
|
|
466
617
|
warnings: result.warnings,
|
|
@@ -121,6 +121,22 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
|
|
|
121
121
|
expectedHeadlessStep: string | null;
|
|
122
122
|
headlessCurrentStep: string | null;
|
|
123
123
|
uiStep: string | null;
|
|
124
|
+
orientation: {
|
|
125
|
+
visibleStep: string | null;
|
|
126
|
+
browserStepLabel: string;
|
|
127
|
+
customerSummary: string;
|
|
128
|
+
nextVisibleMilestone: string;
|
|
129
|
+
blockedReason: string | null;
|
|
130
|
+
agentGuidance: string;
|
|
131
|
+
browserCheckpoint: string;
|
|
132
|
+
senderSelectionAllowed: boolean;
|
|
133
|
+
safeToAskSender: boolean;
|
|
134
|
+
};
|
|
135
|
+
watchUrl: {
|
|
136
|
+
urlPresent: boolean;
|
|
137
|
+
signed: boolean;
|
|
138
|
+
redirectPath: string | null;
|
|
139
|
+
};
|
|
124
140
|
table: {
|
|
125
141
|
workflowTableId: string | null;
|
|
126
142
|
checked: boolean;
|
|
@@ -154,6 +170,22 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
|
|
|
154
170
|
expectedHeadlessStep: string | null;
|
|
155
171
|
headlessCurrentStep: string | null;
|
|
156
172
|
uiStep: string | null;
|
|
173
|
+
orientation: {
|
|
174
|
+
visibleStep: string | null;
|
|
175
|
+
browserStepLabel: string;
|
|
176
|
+
customerSummary: string;
|
|
177
|
+
nextVisibleMilestone: string;
|
|
178
|
+
blockedReason: string | null;
|
|
179
|
+
agentGuidance: string;
|
|
180
|
+
browserCheckpoint: string;
|
|
181
|
+
senderSelectionAllowed: boolean;
|
|
182
|
+
safeToAskSender: boolean;
|
|
183
|
+
};
|
|
184
|
+
watchUrl: {
|
|
185
|
+
urlPresent: boolean;
|
|
186
|
+
signed: boolean;
|
|
187
|
+
redirectPath: string | null;
|
|
188
|
+
};
|
|
157
189
|
table: {
|
|
158
190
|
workflowTableId: string | null;
|
|
159
191
|
checked: boolean;
|
|
@@ -189,6 +221,22 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
|
|
|
189
221
|
expectedHeadlessStep: string | null;
|
|
190
222
|
headlessCurrentStep: string | null;
|
|
191
223
|
uiStep: string | null;
|
|
224
|
+
orientation: {
|
|
225
|
+
visibleStep: string | null;
|
|
226
|
+
browserStepLabel: string;
|
|
227
|
+
customerSummary: string;
|
|
228
|
+
nextVisibleMilestone: string;
|
|
229
|
+
blockedReason: string | null;
|
|
230
|
+
agentGuidance: string;
|
|
231
|
+
browserCheckpoint: string;
|
|
232
|
+
senderSelectionAllowed: boolean;
|
|
233
|
+
safeToAskSender: boolean;
|
|
234
|
+
};
|
|
235
|
+
watchUrl: {
|
|
236
|
+
urlPresent: boolean;
|
|
237
|
+
signed: boolean;
|
|
238
|
+
redirectPath: string | null;
|
|
239
|
+
};
|
|
192
240
|
table: {
|
|
193
241
|
workflowTableId: string | null;
|
|
194
242
|
checked: boolean;
|
package/package.json
CHANGED
|
@@ -158,6 +158,45 @@ Never mention MCP namespaces, prompt chunking, plugin cache paths, missing
|
|
|
158
158
|
linked skill versions, runbooks, or local skill files in normal customer-facing
|
|
159
159
|
copy.
|
|
160
160
|
|
|
161
|
+
## Codex Watch Browser Handoff
|
|
162
|
+
|
|
163
|
+
When a campaign tool returns `watchUrl`, treat it as an active browser handoff,
|
|
164
|
+
not only a URL to print. A valid handoff link must be a signed
|
|
165
|
+
`/auth/continue?token=...&redirect=/campaign-builder/{campaignId}?mode=claude`
|
|
166
|
+
URL. `create_campaign.watchUrl`, `create_campaign({ campaignId }).watchUrl`,
|
|
167
|
+
and `get_campaign.watchUrl` are all acceptable only when they return that signed
|
|
168
|
+
shape.
|
|
169
|
+
|
|
170
|
+
In Codex Desktop, when in-app browser control is available, open the returned watch link on the user's behalf. After opening it, inspect the browser-visible campaign state, then explain what the user is seeing before continuing with more campaign tools. Use customer language such as:
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
I’ll open the campaign view and keep it in sync as I build.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
If browser control is unavailable, say so briefly and provide the watch link.
|
|
177
|
+
In VPS or other off-desktop Codex runs, this fallback is the expected handoff for
|
|
178
|
+
the local headed watch observer: make the signed link easy to copy/open, then
|
|
179
|
+
continue with explicit chat progress and `get_campaign_navigation_state`
|
|
180
|
+
orientation checks.
|
|
181
|
+
Use this fallback shape:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
I can’t inspect the campaign browser from this Codex session, so I’ll keep the
|
|
185
|
+
chat steps explicit here. Watch link: {watchUrl}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
If opening the watch link lands on an auth, 404, permission, blank, or visible
|
|
189
|
+
error state, report only what is visible, recover a fresh signed watch link once
|
|
190
|
+
with `create_campaign({ campaignId })` or `get_campaign`, and try that link. Do
|
|
191
|
+
not claim the browser was opened, inspected, or synchronized unless the visible
|
|
192
|
+
browser state was actually observed. Do not claim the browser was opened unless
|
|
193
|
+
it was opened and observed.
|
|
194
|
+
|
|
195
|
+
After every `update_campaign({ campaignId, currentStep })`, use
|
|
196
|
+
`get_campaign_navigation_state` when available as a compact orientation check:
|
|
197
|
+
match the browser-visible step to the saved campaign state, explain the current
|
|
198
|
+
state in one sentence, and only then continue. Sender selection belongs at Settings after message approval and 10-row validation. Do not attach a sequence, start the campaign, or trigger a live send unless the user explicitly confirms that launch action outside UAT.
|
|
199
|
+
|
|
161
200
|
## Names To Use
|
|
162
201
|
|
|
163
202
|
Use these exact public names so Claude Code and Codex do not drift:
|
|
@@ -100,7 +100,7 @@ Optional debug/UAT draft directory, disabled in normal customer runs:
|
|
|
100
100
|
`awaiting-user-greenlight` for Settings. Do not advance `currentStep` backward.
|
|
101
101
|
- After the shell is minted, normal resume paths read the CampaignOffer first.
|
|
102
102
|
Use debug files to explain or reconstruct work, not to decide whether a
|
|
103
|
-
post-mint gate is allowed.
|
|
103
|
+
post-mint gate is allowed. validation/debug artifacts are not durable campaign
|
|
104
104
|
state.
|
|
105
105
|
- The campaign shell may receive setup state before import: approved brief text,
|
|
106
106
|
campaign-attached provider searches/selections, the bounded review-batch
|
|
@@ -307,6 +307,14 @@
|
|
|
307
307
|
"campaignBrief"
|
|
308
308
|
],
|
|
309
309
|
"watchUrlSource": "create_campaign.watchUrl",
|
|
310
|
+
"requiredWatchUrlShape": "signed /auth/continue?token=...&redirect=/campaign-builder/{campaignId}?mode=claude",
|
|
311
|
+
"codexBrowserHandoff": {
|
|
312
|
+
"openWhenAvailable": true,
|
|
313
|
+
"inspectBeforeContinuing": true,
|
|
314
|
+
"explainVisibleStateBeforeContinuing": true,
|
|
315
|
+
"fallbackMustNotClaimInspection": true,
|
|
316
|
+
"recoverFreshSignedLinkOnceOnOpenFailure": true
|
|
317
|
+
},
|
|
310
318
|
"immediateNextMainChatLine": "Cool, let's find leads."
|
|
311
319
|
}
|
|
312
320
|
],
|
|
@@ -1415,13 +1423,26 @@
|
|
|
1415
1423
|
"when": "after_message_approved_before_import",
|
|
1416
1424
|
"fields": [
|
|
1417
1425
|
"campaignBrief with ## Approved Message Template, Token Fill Rules, Token Fill Examples",
|
|
1418
|
-
"currentStep:validate-sample",
|
|
1419
1426
|
"useMessagingTemplate:true"
|
|
1420
1427
|
],
|
|
1421
1428
|
"requiredBeforeImport": false,
|
|
1422
1429
|
"onFailure": "stop_before_import_or_enrichment",
|
|
1423
1430
|
"requiredBeforeCascade": true,
|
|
1424
1431
|
"writesCampaignState": "campaignBrief.Approved Message Template"
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
"action": "advance_watch_to_validation_after_message_approval",
|
|
1435
|
+
"tool": "update_campaign",
|
|
1436
|
+
"requires": [
|
|
1437
|
+
"campaignId",
|
|
1438
|
+
"message-review-decision.md"
|
|
1439
|
+
],
|
|
1440
|
+
"requiredValues": {
|
|
1441
|
+
"currentStep": "validate-sample"
|
|
1442
|
+
},
|
|
1443
|
+
"when": "after_update_campaign_brief_succeeds",
|
|
1444
|
+
"requiredBeforeCascade": true,
|
|
1445
|
+
"writesCampaignState": "currentStep:validate-sample"
|
|
1425
1446
|
}
|
|
1426
1447
|
],
|
|
1427
1448
|
"requiredArtifacts": [
|
|
@@ -1439,7 +1460,8 @@
|
|
|
1439
1460
|
"AskUserQuestion",
|
|
1440
1461
|
"request_user_input",
|
|
1441
1462
|
"get_subskill_prompt",
|
|
1442
|
-
"update_campaign_brief"
|
|
1463
|
+
"update_campaign_brief",
|
|
1464
|
+
"update_campaign"
|
|
1443
1465
|
],
|
|
1444
1466
|
"doNotAllow": [
|
|
1445
1467
|
"create_campaign",
|