@signaliz/sdk 1.0.12 → 1.0.14
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 +23 -0
- package/dist/{chunk-XJQ6KGNQ.mjs → chunk-EVFQETTN.mjs} +302 -0
- package/dist/cli.js +354 -139
- package/dist/cli.mjs +55 -140
- package/dist/index.d.mts +75 -1
- package/dist/index.d.ts +75 -1
- package/dist/index.js +304 -0
- package/dist/index.mjs +5 -1
- package/dist/mcp-config.js +300 -0
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1197,6 +1197,13 @@ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
|
|
|
1197
1197
|
"email_verification",
|
|
1198
1198
|
"signals"
|
|
1199
1199
|
];
|
|
1200
|
+
var CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS = {
|
|
1201
|
+
lead_generation: "signaliz-lead-generation",
|
|
1202
|
+
local_leads: "signaliz-local-leads",
|
|
1203
|
+
email_finding: "signaliz-email-finding",
|
|
1204
|
+
email_verification: "signaliz-email-verification",
|
|
1205
|
+
signals: "signaliz-signals"
|
|
1206
|
+
};
|
|
1200
1207
|
var DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES = [
|
|
1201
1208
|
"memory_retrieval",
|
|
1202
1209
|
"spend",
|
|
@@ -1693,6 +1700,17 @@ var CampaignBuilderAgent = class {
|
|
|
1693
1700
|
}
|
|
1694
1701
|
return plan;
|
|
1695
1702
|
}
|
|
1703
|
+
async readiness(request, options = {}) {
|
|
1704
|
+
const plan = await this.createPlan(request, options);
|
|
1705
|
+
return createCampaignBuilderReadiness(plan);
|
|
1706
|
+
}
|
|
1707
|
+
async proof(request, options = {}) {
|
|
1708
|
+
const plan = await this.createPlan(request, options);
|
|
1709
|
+
const result = await this.dryRunPlan(plan, {
|
|
1710
|
+
idempotencyKey: options.idempotencyKey
|
|
1711
|
+
});
|
|
1712
|
+
return createCampaignBuilderProofReceipt(plan, result);
|
|
1713
|
+
}
|
|
1696
1714
|
async commitPlan(plan, options = {}) {
|
|
1697
1715
|
const writeMode = options.confirm === true && options.dryRun === false;
|
|
1698
1716
|
if (writeMode && !options.approvedBy) {
|
|
@@ -2053,6 +2071,157 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2053
2071
|
warnings: context.warnings ?? []
|
|
2054
2072
|
};
|
|
2055
2073
|
}
|
|
2074
|
+
function createCampaignBuilderReadiness(plan) {
|
|
2075
|
+
const lanes = plan.routes.map((route) => createCampaignBuilderReadinessLane(route, plan));
|
|
2076
|
+
const builtInLanes = lanes.filter((lane) => lane.builtIn);
|
|
2077
|
+
const customRoutes = lanes.filter((lane) => lane.customRoute);
|
|
2078
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2079
|
+
const deliveryRisk = asRecord(plan.buildRequest.deliveryRisk);
|
|
2080
|
+
const deliveryRiskBlockers = arrayOfStrings(deliveryRisk.blockers) ?? [];
|
|
2081
|
+
const deliveryRiskValue = asRecord(deliveryRisk.risk);
|
|
2082
|
+
const deliveryRiskLevel = stringValue(deliveryRiskValue.risk_level ?? deliveryRiskValue.riskLevel);
|
|
2083
|
+
const memoryReady = !plan.strategyMemoryStatus || strategyMemory.ready !== false;
|
|
2084
|
+
const kernelPlanReady = Object.keys(asRecord(plan.kernelPlan)).length > 0;
|
|
2085
|
+
const deliveryRiskReady = !plan.buildRequest.deliveryRisk || deliveryRiskBlockers.length === 0 && !["high", "critical", "blocked"].includes(String(deliveryRiskLevel ?? "").toLowerCase());
|
|
2086
|
+
const builtInsReady = builtInLanes.length > 0 && builtInLanes.every((lane) => lane.ready);
|
|
2087
|
+
const customRoutesReady = customRoutes.every((lane) => lane.ready);
|
|
2088
|
+
const approvalGatesReady = plan.approvals.length > 0;
|
|
2089
|
+
const gates = [
|
|
2090
|
+
{
|
|
2091
|
+
id: "campaign_plan_created",
|
|
2092
|
+
label: "Campaign plan created",
|
|
2093
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
2094
|
+
detail: plan.planId ? `Plan ${plan.planId} has ${plan.mcpFlow.length} MCP step(s).` : "No campaign-builder plan was created."
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
id: "built_in_lanes_ready",
|
|
2098
|
+
label: "Built-in lanes ready",
|
|
2099
|
+
passed: builtInsReady,
|
|
2100
|
+
detail: `${builtInLanes.filter((lane) => lane.ready).length}/${builtInLanes.length} Signaliz built-in lane(s) are present.`
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
id: "strategy_memory_ready",
|
|
2104
|
+
label: "Strategy memory ready",
|
|
2105
|
+
passed: memoryReady,
|
|
2106
|
+
detail: plan.strategyMemoryStatus ? "Strategy memory readiness was checked." : "Strategy memory readiness was not requested."
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
id: "kernel_plan_attached",
|
|
2110
|
+
label: "Kernel plan attached",
|
|
2111
|
+
passed: kernelPlanReady,
|
|
2112
|
+
detail: kernelPlanReady ? "Kernel planner evidence is attached." : "Kernel planner evidence is not attached."
|
|
2113
|
+
},
|
|
2114
|
+
{
|
|
2115
|
+
id: "delivery_risk_clear",
|
|
2116
|
+
label: "Delivery risk clear",
|
|
2117
|
+
passed: deliveryRiskReady,
|
|
2118
|
+
detail: plan.buildRequest.deliveryRisk ? `Delivery risk is ${deliveryRiskLevel || "available"} with ${deliveryRiskBlockers.length} blocker(s).` : "Delivery risk preflight was not requested."
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
id: "custom_routes_prepared",
|
|
2122
|
+
label: "Custom routes prepared",
|
|
2123
|
+
passed: customRoutesReady,
|
|
2124
|
+
detail: customRoutes.length === 0 ? "No BYO routes were requested." : `${customRoutes.filter((lane) => lane.ready).length}/${customRoutes.length} BYO route(s) have read-only setup steps.`
|
|
2125
|
+
},
|
|
2126
|
+
{
|
|
2127
|
+
id: "approval_gates_present",
|
|
2128
|
+
label: "Approval gates present",
|
|
2129
|
+
passed: approvalGatesReady,
|
|
2130
|
+
detail: approvalGatesReady ? `${plan.approvals.length} approval gate(s) are attached.` : "No approval gates are attached."
|
|
2131
|
+
}
|
|
2132
|
+
];
|
|
2133
|
+
const blockers = [
|
|
2134
|
+
...gates.filter((gate) => !gate.passed).map((gate) => gate.detail),
|
|
2135
|
+
...lanes.flatMap((lane) => lane.blockers)
|
|
2136
|
+
];
|
|
2137
|
+
const score = gates.length === 0 ? 0 : Math.round(gates.filter((gate) => gate.passed).length / gates.length * 100);
|
|
2138
|
+
const ready = blockers.length === 0;
|
|
2139
|
+
return {
|
|
2140
|
+
plan,
|
|
2141
|
+
lanes,
|
|
2142
|
+
gates,
|
|
2143
|
+
summary: {
|
|
2144
|
+
ready,
|
|
2145
|
+
score,
|
|
2146
|
+
targetCount: plan.targetCount,
|
|
2147
|
+
estimatedCredits: plan.estimatedCredits,
|
|
2148
|
+
builtInLanesReady: builtInLanes.filter((lane) => lane.ready).length,
|
|
2149
|
+
builtInLanesTotal: builtInLanes.length,
|
|
2150
|
+
customRoutesReady: customRoutes.filter((lane) => lane.ready).length,
|
|
2151
|
+
customRoutesTotal: customRoutes.length,
|
|
2152
|
+
approvalGateCount: plan.approvals.length,
|
|
2153
|
+
blockers,
|
|
2154
|
+
warnings: plan.warnings
|
|
2155
|
+
},
|
|
2156
|
+
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
function createCampaignBuilderProofReceipt(plan, result) {
|
|
2160
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2161
|
+
const dryRunResult = asRecord(result);
|
|
2162
|
+
const memoryReady = plan.strategyMemoryStatus ? strategyMemory.ready !== false : false;
|
|
2163
|
+
const dryRunCompleted = dryRunResult.dryRun === true || dryRunResult.dry_run === true || dryRunResult.status === "dry_run";
|
|
2164
|
+
const noLaunch = dryRunCompleted && !dryRunResult.campaignBuildId && !dryRunResult.campaign_build_id;
|
|
2165
|
+
const gates = [
|
|
2166
|
+
{
|
|
2167
|
+
id: "strategy_memory_ready",
|
|
2168
|
+
passed: memoryReady,
|
|
2169
|
+
ready: strategyMemory.ready ?? null,
|
|
2170
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
id: "campaign_plan_ready",
|
|
2174
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
2175
|
+
plan_id: plan.planId,
|
|
2176
|
+
flow_steps: plan.mcpFlow.length
|
|
2177
|
+
},
|
|
2178
|
+
{
|
|
2179
|
+
id: "approval_gates_present",
|
|
2180
|
+
passed: plan.approvals.length > 0,
|
|
2181
|
+
approval_types: plan.approvals.map((approval) => approval.type)
|
|
2182
|
+
},
|
|
2183
|
+
{
|
|
2184
|
+
id: "dry_run_completed",
|
|
2185
|
+
passed: dryRunCompleted,
|
|
2186
|
+
status: dryRunResult.status ?? null,
|
|
2187
|
+
current_phase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
id: "no_spendful_launch",
|
|
2191
|
+
passed: noLaunch,
|
|
2192
|
+
campaign_build_id: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null
|
|
2193
|
+
}
|
|
2194
|
+
];
|
|
2195
|
+
return {
|
|
2196
|
+
receipt_version: "campaign-agent-proof.v1",
|
|
2197
|
+
source: "signaliz.campaignBuilderAgent.proof",
|
|
2198
|
+
success: gates.every((gate) => gate.passed),
|
|
2199
|
+
safety: {
|
|
2200
|
+
spendful_tools_called: false,
|
|
2201
|
+
external_writes_called: false,
|
|
2202
|
+
sender_loads_called: false,
|
|
2203
|
+
email_sends_called: false,
|
|
2204
|
+
dry_run_only: true
|
|
2205
|
+
},
|
|
2206
|
+
campaign: {
|
|
2207
|
+
plan_id: plan.planId,
|
|
2208
|
+
campaign_name: plan.campaignName,
|
|
2209
|
+
strategy_template: campaignBuilderProofStrategyTemplate(plan),
|
|
2210
|
+
target_count: plan.targetCount,
|
|
2211
|
+
estimated_credits: plan.estimatedCredits,
|
|
2212
|
+
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
2213
|
+
},
|
|
2214
|
+
gates,
|
|
2215
|
+
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
2216
|
+
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
2217
|
+
recommended_next_actions: [
|
|
2218
|
+
"Review the plan, approvals, and dry-run result.",
|
|
2219
|
+
"Use campaign-agent commit-plan --confirm-write only after review.",
|
|
2220
|
+
"Use campaign-agent build-approved only with --confirm-launch, approval identity, approval types, and spend limit.",
|
|
2221
|
+
"When an approved build reaches pending_approval, review rows and approve delivery through the Campaigns SDK."
|
|
2222
|
+
]
|
|
2223
|
+
};
|
|
2224
|
+
}
|
|
2056
2225
|
function getMissingCampaignBuilderApprovals(plan, approval) {
|
|
2057
2226
|
if (approval.planId !== plan.planId) {
|
|
2058
2227
|
return plan.approvals;
|
|
@@ -3430,6 +3599,137 @@ function campaignReviewRowHasCopy(row) {
|
|
|
3430
3599
|
stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(data.opener) || stringValue(data.body) || stringValue(data.cta) || stringValue(copy.subject) || stringValue(copy.body) || stringValue(rawCopy.subject) || stringValue(rawCopy.body)
|
|
3431
3600
|
);
|
|
3432
3601
|
}
|
|
3602
|
+
function createCampaignBuilderReadinessLane(route, plan) {
|
|
3603
|
+
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
3604
|
+
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
3605
|
+
const prepareStep = plan.mcpFlow.find(
|
|
3606
|
+
(step) => step.tool === "gtm_provider_recipe_prepare" && step.arguments.provider_id === route.provider
|
|
3607
|
+
);
|
|
3608
|
+
const activateStep = plan.mcpFlow.find(
|
|
3609
|
+
(step) => step.tool === "gtm_provider_route_activate" && step.arguments.provider_id === route.provider
|
|
3610
|
+
);
|
|
3611
|
+
const readOnlySetup = !customRoute || prepareStep?.readOnly === true && activateStep?.readOnly === true && activateStep.arguments.dry_run === true && activateStep.arguments.confirm === false;
|
|
3612
|
+
const blockers = [
|
|
3613
|
+
customRoute && !prepareStep ? `${route.label ?? route.provider} is missing provider recipe setup.` : void 0,
|
|
3614
|
+
customRoute && !activateStep ? `${route.label ?? route.provider} is missing provider route dry-run setup.` : void 0,
|
|
3615
|
+
customRoute && !readOnlySetup ? `${route.label ?? route.provider} route setup must stay read-only before approval.` : void 0,
|
|
3616
|
+
route.mode === "required" && !route.toolName && customRoute ? `${route.label ?? route.provider} is required but has no tool name.` : void 0
|
|
3617
|
+
].filter((item) => Boolean(item));
|
|
3618
|
+
return {
|
|
3619
|
+
id: route.id ?? `${route.provider}-${route.layer}`,
|
|
3620
|
+
label: route.label ?? readinessLaneLabel(route, builtIn),
|
|
3621
|
+
layer: route.layer,
|
|
3622
|
+
gtmLayers: gtmLayersForRoute(route),
|
|
3623
|
+
provider: route.provider,
|
|
3624
|
+
toolName: route.toolName,
|
|
3625
|
+
mode: route.mode ?? "if_available",
|
|
3626
|
+
builtIn,
|
|
3627
|
+
approvalRequired: route.approvalRequired === true || plan.approvals.some((approval) => approval.routeId === route.id),
|
|
3628
|
+
customRoute,
|
|
3629
|
+
readOnlySetup,
|
|
3630
|
+
ready: blockers.length === 0,
|
|
3631
|
+
blockers,
|
|
3632
|
+
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
function campaignBuilderBuiltInForRoute(route) {
|
|
3636
|
+
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
3637
|
+
}
|
|
3638
|
+
function readinessLaneLabel(route, builtIn) {
|
|
3639
|
+
if (builtIn) {
|
|
3640
|
+
const labels = {
|
|
3641
|
+
lead_generation: "Signaliz lead generation",
|
|
3642
|
+
local_leads: "Signaliz local leads",
|
|
3643
|
+
email_finding: "Signaliz email finding",
|
|
3644
|
+
email_verification: "Signaliz email verification",
|
|
3645
|
+
signals: "Signaliz signals"
|
|
3646
|
+
};
|
|
3647
|
+
return labels[builtIn];
|
|
3648
|
+
}
|
|
3649
|
+
return `${route.provider} ${route.layer}`;
|
|
3650
|
+
}
|
|
3651
|
+
function campaignReadinessNextActions(plan, ready, customRouteCount) {
|
|
3652
|
+
const requestHint = "--request-file campaign-request.json";
|
|
3653
|
+
if (ready) {
|
|
3654
|
+
return [
|
|
3655
|
+
`signaliz campaign-agent proof ${requestHint} --json`,
|
|
3656
|
+
`signaliz campaign-agent commit-plan ${requestHint} --json`,
|
|
3657
|
+
`signaliz campaign-agent build-approved ${requestHint} --confirm-launch --approve-all --approved-by operator@example.com --spend-limit ${plan.estimatedCredits}`
|
|
3658
|
+
];
|
|
3659
|
+
}
|
|
3660
|
+
const actions = [
|
|
3661
|
+
plan.strategyMemoryStatus && asRecord(plan.strategyMemoryStatus).ready === false ? "signaliz gtm strategy-memory --strategy-template <strategy_template> --include-samples --json" : void 0,
|
|
3662
|
+
customRouteCount > 0 ? "Review BYO provider recipe and route dry-run steps in the readiness packet." : void 0,
|
|
3663
|
+
`signaliz campaign-agent plan ${requestHint} --json`
|
|
3664
|
+
];
|
|
3665
|
+
return actions.filter((item) => Boolean(item));
|
|
3666
|
+
}
|
|
3667
|
+
function campaignBuilderProofStrategyTemplate(plan) {
|
|
3668
|
+
const buildRequest = asRecord(plan.buildRequest);
|
|
3669
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
3670
|
+
const statusTemplate = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
3671
|
+
const statusTemplateRecord = asRecord(statusTemplate);
|
|
3672
|
+
const flowTemplate = plan.mcpFlow.map((step) => asRecord(step.arguments).strategy_template ?? asRecord(step.arguments).strategyTemplate).find((value) => typeof value === "string" && value.trim());
|
|
3673
|
+
return firstNonEmptyString(
|
|
3674
|
+
buildRequest.strategyTemplate,
|
|
3675
|
+
buildRequest.strategy_template,
|
|
3676
|
+
statusTemplate,
|
|
3677
|
+
statusTemplateRecord.slug,
|
|
3678
|
+
statusTemplateRecord.id,
|
|
3679
|
+
flowTemplate
|
|
3680
|
+
);
|
|
3681
|
+
}
|
|
3682
|
+
function summarizeCampaignBuilderProofStrategyMemory(strategyMemory) {
|
|
3683
|
+
if (Object.keys(strategyMemory).length === 0) return { ready: false };
|
|
3684
|
+
const template = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
3685
|
+
const templateRecord = asRecord(template);
|
|
3686
|
+
const coverage = asRecord(strategyMemory.coverage);
|
|
3687
|
+
const rawSourceGroups = Array.isArray(strategyMemory.source_groups) ? strategyMemory.source_groups : Array.isArray(strategyMemory.sourceGroups) ? strategyMemory.sourceGroups : [];
|
|
3688
|
+
const sourceGroups = rawSourceGroups.map((group) => {
|
|
3689
|
+
const sourceGroup = asRecord(group);
|
|
3690
|
+
return {
|
|
3691
|
+
id: sourceGroup.id ?? null,
|
|
3692
|
+
required: sourceGroup.required ?? null,
|
|
3693
|
+
ready: sourceGroup.ready ?? null,
|
|
3694
|
+
counts: asRecord(sourceGroup.counts)
|
|
3695
|
+
};
|
|
3696
|
+
});
|
|
3697
|
+
return {
|
|
3698
|
+
ready: strategyMemory.ready ?? null,
|
|
3699
|
+
read_only: strategyMemory.read_only ?? strategyMemory.readOnly ?? null,
|
|
3700
|
+
source_tool: firstNonEmptyString(strategyMemory.source_tool, strategyMemory.sourceTool),
|
|
3701
|
+
strategy_template: {
|
|
3702
|
+
slug: firstNonEmptyString(template, templateRecord.slug, templateRecord.id),
|
|
3703
|
+
label: firstNonEmptyString(templateRecord.label)
|
|
3704
|
+
},
|
|
3705
|
+
coverage: {
|
|
3706
|
+
required_groups_ready: coverage.required_groups_ready ?? coverage.requiredGroupsReady ?? null,
|
|
3707
|
+
required_groups_total: coverage.required_groups_total ?? coverage.requiredGroupsTotal ?? null,
|
|
3708
|
+
source_groups_ready: coverage.source_groups_ready ?? coverage.sourceGroupsReady ?? null,
|
|
3709
|
+
source_groups_total: coverage.source_groups_total ?? coverage.sourceGroupsTotal ?? null,
|
|
3710
|
+
knowledge_docs: coverage.knowledge_docs ?? coverage.knowledgeDocs ?? null,
|
|
3711
|
+
memories: coverage.memories ?? null
|
|
3712
|
+
},
|
|
3713
|
+
source_groups: sourceGroups,
|
|
3714
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0,
|
|
3715
|
+
warning_count: Array.isArray(strategyMemory.warnings) ? strategyMemory.warnings.length : 0
|
|
3716
|
+
};
|
|
3717
|
+
}
|
|
3718
|
+
function summarizeCampaignBuilderProofDryRun(dryRunResult) {
|
|
3719
|
+
return {
|
|
3720
|
+
dryRun: dryRunResult.dryRun ?? dryRunResult.dry_run ?? null,
|
|
3721
|
+
status: dryRunResult.status ?? null,
|
|
3722
|
+
currentPhase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null,
|
|
3723
|
+
campaignBuildId: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null,
|
|
3724
|
+
plannedTargetCount: dryRunResult.plannedTargetCount ?? dryRunResult.planned_target_count ?? null
|
|
3725
|
+
};
|
|
3726
|
+
}
|
|
3727
|
+
function firstNonEmptyString(...values) {
|
|
3728
|
+
for (const value of values) {
|
|
3729
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
3730
|
+
}
|
|
3731
|
+
return null;
|
|
3732
|
+
}
|
|
3433
3733
|
function diagnosticMessages2(value) {
|
|
3434
3734
|
if (!Array.isArray(value)) return [];
|
|
3435
3735
|
return value.map((item) => {
|
|
@@ -6807,13 +7107,14 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6807
7107
|
await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
|
|
6808
7108
|
return;
|
|
6809
7109
|
}
|
|
6810
|
-
if (!["plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
|
|
7110
|
+
if (!["plan", "doctor", "readiness", "preflight", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
|
|
6811
7111
|
printCampaignAgentHelp();
|
|
6812
7112
|
return;
|
|
6813
7113
|
}
|
|
6814
7114
|
const flags = parseFlags(argv.slice(1));
|
|
7115
|
+
const isDoctor = subcommand === "doctor" || subcommand === "readiness" || subcommand === "preflight";
|
|
6815
7116
|
const requestFromFile = campaignAgentRequestFileFromFlags(flags);
|
|
6816
|
-
const goal = stringFlag(flags, "goal", "brief") ?? stringOrUndefined(requestFromFile?.goal);
|
|
7117
|
+
const goal = stringFlag(flags, "goal", "brief") ?? stringOrUndefined(requestFromFile?.goal) ?? (isDoctor ? "Build a strategy-template campaign for the target ICP." : void 0);
|
|
6817
7118
|
if (!goal) throw new Error(`campaign-agent ${subcommand} requires --goal or a request file with goal`);
|
|
6818
7119
|
const isApprovedBuild = subcommand === "build-approved" || subcommand === "launch-approved";
|
|
6819
7120
|
const isCommitPlan = subcommand === "commit-plan";
|
|
@@ -6832,18 +7133,28 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6832
7133
|
requestFromFile,
|
|
6833
7134
|
campaignAgentRequestFromFlags(goal, flags, { includeDefaults: !requestFromFile })
|
|
6834
7135
|
);
|
|
6835
|
-
const
|
|
7136
|
+
const planOptions = {
|
|
6836
7137
|
discoverCapabilities: !booleanFlag(flags, "skip-discovery"),
|
|
6837
7138
|
scopeCampaign: !booleanFlag(flags, "skip-scope"),
|
|
6838
7139
|
includeStrategyMemoryStatus: !booleanFlag(flags, "no-strategy-memory"),
|
|
6839
7140
|
includeKernelPlan: !booleanFlag(flags, "no-kernel-plan"),
|
|
6840
7141
|
includeDeliveryRisk: !booleanFlag(flags, "no-delivery-risk")
|
|
6841
|
-
}
|
|
7142
|
+
};
|
|
7143
|
+
if (isDoctor) {
|
|
7144
|
+
const readiness = await signaliz.campaignBuilderAgent.readiness(request, planOptions);
|
|
7145
|
+
if (booleanFlag(flags, "json")) {
|
|
7146
|
+
printJson(readiness);
|
|
7147
|
+
} else {
|
|
7148
|
+
printCampaignAgentReadiness(readiness);
|
|
7149
|
+
}
|
|
7150
|
+
if (!readiness.summary.ready) process.exitCode = 1;
|
|
7151
|
+
return;
|
|
7152
|
+
}
|
|
6842
7153
|
if (subcommand === "proof" || subcommand === "smoke") {
|
|
6843
|
-
const
|
|
7154
|
+
const proof = await signaliz.campaignBuilderAgent.proof(request, {
|
|
7155
|
+
...planOptions,
|
|
6844
7156
|
idempotencyKey: stringFlag(flags, "idempotency-key")
|
|
6845
7157
|
});
|
|
6846
|
-
const proof = createCampaignAgentProofReceipt(plan, result);
|
|
6847
7158
|
if (booleanFlag(flags, "json")) {
|
|
6848
7159
|
printJson(proof);
|
|
6849
7160
|
} else {
|
|
@@ -6852,6 +7163,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6852
7163
|
if (!proof.success) process.exitCode = 1;
|
|
6853
7164
|
return;
|
|
6854
7165
|
}
|
|
7166
|
+
const plan = await signaliz.campaignBuilderAgent.createPlan(request, planOptions);
|
|
6855
7167
|
if (isCommitPlan) {
|
|
6856
7168
|
const result = await signaliz.campaignBuilderAgent.commitPlan(plan, {
|
|
6857
7169
|
confirm: isConfirmedCommit,
|
|
@@ -7326,6 +7638,39 @@ function printCampaignAgentExecution(payload, flags) {
|
|
|
7326
7638
|
console.log("\nResult:");
|
|
7327
7639
|
printJson(payload.result);
|
|
7328
7640
|
}
|
|
7641
|
+
function printCampaignAgentReadiness(readiness) {
|
|
7642
|
+
const summary = asRecord4(readiness.summary);
|
|
7643
|
+
const plan = readiness.plan;
|
|
7644
|
+
console.log(`Readiness: ${summary.ready === true ? "ready" : "blocked"} (${summary.score ?? 0}%)`);
|
|
7645
|
+
if (plan?.campaignName) console.log(`Campaign: ${plan.campaignName}`);
|
|
7646
|
+
if (summary.targetCount !== void 0) console.log(`Target: ${summary.targetCount}`);
|
|
7647
|
+
if (summary.estimatedCredits !== void 0) console.log(`Estimated credits: ${summary.estimatedCredits}`);
|
|
7648
|
+
console.log(`Built-ins: ${summary.builtInLanesReady ?? 0}/${summary.builtInLanesTotal ?? 0}`);
|
|
7649
|
+
console.log(`BYO routes: ${summary.customRoutesReady ?? 0}/${summary.customRoutesTotal ?? 0}`);
|
|
7650
|
+
console.log(`Approval gates: ${summary.approvalGateCount ?? 0}`);
|
|
7651
|
+
if (Array.isArray(readiness.gates) && readiness.gates.length > 0) {
|
|
7652
|
+
console.log("\nGates:");
|
|
7653
|
+
for (const gate of readiness.gates) {
|
|
7654
|
+
console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
|
|
7655
|
+
}
|
|
7656
|
+
}
|
|
7657
|
+
if (Array.isArray(readiness.lanes) && readiness.lanes.length > 0) {
|
|
7658
|
+
console.log("\nLanes:");
|
|
7659
|
+
for (const lane of readiness.lanes) {
|
|
7660
|
+
console.log(`- ${lane.ready ? "READY" : "BLOCKED"} ${lane.label}: ${lane.toolName || lane.provider}`);
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
const blockers = Array.isArray(summary.blockers) ? summary.blockers : [];
|
|
7664
|
+
if (blockers.length > 0) {
|
|
7665
|
+
console.log("\nBlockers:");
|
|
7666
|
+
for (const blocker of blockers.slice(0, 8)) console.log(`- ${blocker}`);
|
|
7667
|
+
}
|
|
7668
|
+
const nextActions = Array.isArray(readiness.nextActions) ? readiness.nextActions : [];
|
|
7669
|
+
if (nextActions.length > 0) {
|
|
7670
|
+
console.log("\nNext:");
|
|
7671
|
+
for (const action of nextActions) console.log(`- ${action}`);
|
|
7672
|
+
}
|
|
7673
|
+
}
|
|
7329
7674
|
function printCampaignAgentBuildStatus(status) {
|
|
7330
7675
|
console.log(`Campaign: ${status.name || status.campaignBuildId}`);
|
|
7331
7676
|
if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
|
|
@@ -7410,138 +7755,6 @@ function printCampaignAgentRows(result) {
|
|
|
7410
7755
|
function asRecord4(value) {
|
|
7411
7756
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7412
7757
|
}
|
|
7413
|
-
function createCampaignAgentProofReceipt(plan, result) {
|
|
7414
|
-
const strategyMemory = asRecord4(plan.strategyMemoryStatus);
|
|
7415
|
-
const dryRunResult = asRecord4(result);
|
|
7416
|
-
const memoryReady = plan.strategyMemoryStatus ? strategyMemory.ready !== false : false;
|
|
7417
|
-
const dryRunCompleted = dryRunResult.dryRun === true || dryRunResult.dry_run === true || dryRunResult.status === "dry_run";
|
|
7418
|
-
const noLaunch = dryRunCompleted && !dryRunResult.campaignBuildId && !dryRunResult.campaign_build_id;
|
|
7419
|
-
const gates = [
|
|
7420
|
-
{
|
|
7421
|
-
id: "strategy_memory_ready",
|
|
7422
|
-
passed: memoryReady,
|
|
7423
|
-
ready: strategyMemory.ready ?? null,
|
|
7424
|
-
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0
|
|
7425
|
-
},
|
|
7426
|
-
{
|
|
7427
|
-
id: "campaign_plan_ready",
|
|
7428
|
-
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
7429
|
-
plan_id: plan.planId,
|
|
7430
|
-
flow_steps: plan.mcpFlow.length
|
|
7431
|
-
},
|
|
7432
|
-
{
|
|
7433
|
-
id: "approval_gates_present",
|
|
7434
|
-
passed: plan.approvals.length > 0,
|
|
7435
|
-
approval_types: plan.approvals.map((approval) => approval.type)
|
|
7436
|
-
},
|
|
7437
|
-
{
|
|
7438
|
-
id: "dry_run_completed",
|
|
7439
|
-
passed: dryRunCompleted,
|
|
7440
|
-
status: dryRunResult.status ?? null,
|
|
7441
|
-
current_phase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null
|
|
7442
|
-
},
|
|
7443
|
-
{
|
|
7444
|
-
id: "no_spendful_launch",
|
|
7445
|
-
passed: noLaunch,
|
|
7446
|
-
campaign_build_id: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null
|
|
7447
|
-
}
|
|
7448
|
-
];
|
|
7449
|
-
return {
|
|
7450
|
-
receipt_version: "campaign-agent-proof.v1",
|
|
7451
|
-
source: "signaliz campaign-agent proof",
|
|
7452
|
-
success: gates.every((gate) => gate.passed),
|
|
7453
|
-
safety: {
|
|
7454
|
-
spendful_tools_called: false,
|
|
7455
|
-
external_writes_called: false,
|
|
7456
|
-
sender_loads_called: false,
|
|
7457
|
-
email_sends_called: false,
|
|
7458
|
-
dry_run_only: true
|
|
7459
|
-
},
|
|
7460
|
-
campaign: {
|
|
7461
|
-
plan_id: plan.planId,
|
|
7462
|
-
campaign_name: plan.campaignName,
|
|
7463
|
-
strategy_template: campaignAgentStrategyTemplate(plan),
|
|
7464
|
-
target_count: plan.targetCount,
|
|
7465
|
-
estimated_credits: plan.estimatedCredits,
|
|
7466
|
-
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
7467
|
-
},
|
|
7468
|
-
gates,
|
|
7469
|
-
strategy_memory_status: summarizeCampaignAgentStrategyMemory(strategyMemory),
|
|
7470
|
-
dry_run_result: summarizeCampaignAgentDryRun(dryRunResult),
|
|
7471
|
-
recommended_next_actions: [
|
|
7472
|
-
"Review the plan, approvals, and dry-run result.",
|
|
7473
|
-
"Use campaign-agent commit-plan --confirm-write only after review.",
|
|
7474
|
-
"Use campaign-agent build-approved only with --confirm-launch, approval identity, approval types, and spend limit.",
|
|
7475
|
-
"When an approved build reaches pending_approval, review rows and approve delivery through the Campaigns SDK."
|
|
7476
|
-
]
|
|
7477
|
-
};
|
|
7478
|
-
}
|
|
7479
|
-
function campaignAgentString(...values) {
|
|
7480
|
-
for (const value of values) {
|
|
7481
|
-
if (typeof value === "string" && value.trim()) return value;
|
|
7482
|
-
}
|
|
7483
|
-
return null;
|
|
7484
|
-
}
|
|
7485
|
-
function campaignAgentStrategyTemplate(plan) {
|
|
7486
|
-
const buildRequest = asRecord4(plan.buildRequest);
|
|
7487
|
-
const strategyMemory = asRecord4(plan.strategyMemoryStatus);
|
|
7488
|
-
const statusTemplate = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
7489
|
-
const statusTemplateRecord = asRecord4(statusTemplate);
|
|
7490
|
-
const flowTemplate = plan.mcpFlow.map((step) => asRecord4(step.arguments).strategy_template ?? asRecord4(step.arguments).strategyTemplate).find((value) => typeof value === "string" && value.trim());
|
|
7491
|
-
return campaignAgentString(
|
|
7492
|
-
buildRequest.strategyTemplate,
|
|
7493
|
-
buildRequest.strategy_template,
|
|
7494
|
-
statusTemplate,
|
|
7495
|
-
statusTemplateRecord.slug,
|
|
7496
|
-
statusTemplateRecord.id,
|
|
7497
|
-
flowTemplate
|
|
7498
|
-
);
|
|
7499
|
-
}
|
|
7500
|
-
function summarizeCampaignAgentStrategyMemory(strategyMemory) {
|
|
7501
|
-
if (Object.keys(strategyMemory).length === 0) return { ready: false };
|
|
7502
|
-
const template = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
7503
|
-
const templateRecord = asRecord4(template);
|
|
7504
|
-
const coverage = asRecord4(strategyMemory.coverage);
|
|
7505
|
-
const rawSourceGroups = Array.isArray(strategyMemory.source_groups) ? strategyMemory.source_groups : Array.isArray(strategyMemory.sourceGroups) ? strategyMemory.sourceGroups : [];
|
|
7506
|
-
const sourceGroups = rawSourceGroups.map((group) => {
|
|
7507
|
-
const sourceGroup = asRecord4(group);
|
|
7508
|
-
return {
|
|
7509
|
-
id: sourceGroup.id ?? null,
|
|
7510
|
-
required: sourceGroup.required ?? null,
|
|
7511
|
-
ready: sourceGroup.ready ?? null,
|
|
7512
|
-
counts: asRecord4(sourceGroup.counts)
|
|
7513
|
-
};
|
|
7514
|
-
});
|
|
7515
|
-
return {
|
|
7516
|
-
ready: strategyMemory.ready ?? null,
|
|
7517
|
-
read_only: strategyMemory.read_only ?? strategyMemory.readOnly ?? null,
|
|
7518
|
-
source_tool: campaignAgentString(strategyMemory.source_tool, strategyMemory.sourceTool),
|
|
7519
|
-
strategy_template: {
|
|
7520
|
-
slug: campaignAgentString(template, templateRecord.slug, templateRecord.id),
|
|
7521
|
-
label: campaignAgentString(templateRecord.label)
|
|
7522
|
-
},
|
|
7523
|
-
coverage: {
|
|
7524
|
-
required_groups_ready: coverage.required_groups_ready ?? coverage.requiredGroupsReady ?? null,
|
|
7525
|
-
required_groups_total: coverage.required_groups_total ?? coverage.requiredGroupsTotal ?? null,
|
|
7526
|
-
source_groups_ready: coverage.source_groups_ready ?? coverage.sourceGroupsReady ?? null,
|
|
7527
|
-
source_groups_total: coverage.source_groups_total ?? coverage.sourceGroupsTotal ?? null,
|
|
7528
|
-
knowledge_docs: coverage.knowledge_docs ?? coverage.knowledgeDocs ?? null,
|
|
7529
|
-
memories: coverage.memories ?? null
|
|
7530
|
-
},
|
|
7531
|
-
source_groups: sourceGroups,
|
|
7532
|
-
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0,
|
|
7533
|
-
warning_count: Array.isArray(strategyMemory.warnings) ? strategyMemory.warnings.length : 0
|
|
7534
|
-
};
|
|
7535
|
-
}
|
|
7536
|
-
function summarizeCampaignAgentDryRun(dryRunResult) {
|
|
7537
|
-
return {
|
|
7538
|
-
dryRun: dryRunResult.dryRun ?? dryRunResult.dry_run ?? null,
|
|
7539
|
-
status: dryRunResult.status ?? null,
|
|
7540
|
-
currentPhase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null,
|
|
7541
|
-
campaignBuildId: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null,
|
|
7542
|
-
plannedTargetCount: dryRunResult.plannedTargetCount ?? dryRunResult.planned_target_count ?? null
|
|
7543
|
-
};
|
|
7544
|
-
}
|
|
7545
7758
|
function printCampaignAgentProof(proof) {
|
|
7546
7759
|
console.log(`Campaign-agent proof: ${proof.success ? "passed" : "failed"}`);
|
|
7547
7760
|
const campaign = asRecord4(proof.campaign);
|
|
@@ -7576,6 +7789,7 @@ Usage:
|
|
|
7576
7789
|
signaliz gtm memory search --query "proof-first vertical gate" --json
|
|
7577
7790
|
signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
|
|
7578
7791
|
signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
|
|
7792
|
+
signaliz campaign-agent doctor --request-file campaign-request.json --json
|
|
7579
7793
|
signaliz campaign-agent plan --goal "Build a strategy-template campaign..." --strategy-template industrial-ot-resilience --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
|
|
7580
7794
|
signaliz campaign-agent proof --goal "Build a strategy-template campaign..." --strategy-template non-medical-home-care --target-count 100 --json
|
|
7581
7795
|
signaliz campaign-agent plan --request-file examples/campaign-builder-agent-request.json --target-count 250 --json
|
|
@@ -7612,6 +7826,7 @@ function printCampaignAgentHelp() {
|
|
|
7612
7826
|
Signaliz campaign-agent commands:
|
|
7613
7827
|
|
|
7614
7828
|
signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
|
|
7829
|
+
signaliz campaign-agent doctor [--goal TEXT | --request-file FILE] [--strategy-template ID] [--target-count N] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--custom-tool provider:layer:tool[:mcp]] [--json]
|
|
7615
7830
|
signaliz campaign-agent plan (--goal TEXT | --request-file FILE) [--campaign-name NAME] [--workspace-label NAME] [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--operating-playbooks proof-first-vertical-gate,signal-led-copy-approval] [--target-count N] [--icp JSON] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--preferred-providers signaliz_native,octave] [--partners clay,instantly,nango] [--no-strategy-memory] [--no-kernel-plan] [--no-delivery-risk] [--json]
|
|
7616
7831
|
signaliz campaign-agent proof (--goal TEXT | --request-file FILE) [--strategy-template ID] [--target-count N] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--idempotency-key KEY] [--json]
|
|
7617
7832
|
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
@@ -7623,7 +7838,7 @@ Signaliz campaign-agent commands:
|
|
|
7623
7838
|
signaliz campaign-agent artifacts <campaign_build_id> [--json]
|
|
7624
7839
|
signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
|
|
7625
7840
|
|
|
7626
|
-
The init command emits a reusable JSON CampaignBuilderAgentRequest. The plan command composes an approval-gated strategy-template MCP flow. Proof runs the same plan path plus build_campaign dry_run=true and returns a no-spend receipt. Use --request-file to load a reusable request, then override fields such as --target-count or --strategy-template from the command line. Use --strategy-template to merge a private-safe strategy pattern into the plan without exposing private account labels, and --operating-playbooks to add reusable build-loop gates such as proof-first vertical qualification, net-new suppression, cache-first inventory, and signal-led copy approval. Built-ins map to Signaliz-native tools: lead_generation -> generate_leads, local_leads -> generate_local_leads, email_finding -> find_and_verify_emails, email_verification -> verify_emails, signals -> enrich_company_signals. Add BYO tools with --custom-tool provider:layer:tool[:mcp] or key=value pairs such as provider=apollo,layer=source,tool=apollo_search,mcp=apollo. Use --no-strategy-patterns or --no-workflow-patterns to disable default private strategy memory hints. Commit-plan dry-runs by default and writes only with --confirm-write plus approval identity. Dry-run executes build_campaign with dry_run=true. Approved build requires explicit launch confirmation and approval metadata; add --commit-before-launch to persist the reviewed plan as a GTM campaign before launch, --wait to poll until completion or pending approval, and --approve-delivery to approve reviewed webhook delivery after pending_approval. Use review to inspect status, sampled rows, artifacts, and delivery-readiness gates before approving delivery or routing rows to external tools.
|
|
7841
|
+
The init command emits a reusable JSON CampaignBuilderAgentRequest. Doctor returns a readiness packet for built-in lanes, BYO routes, Memory, Brain, Kernel planning, and approval gates. The plan command composes an approval-gated strategy-template MCP flow. Proof runs the same plan path plus build_campaign dry_run=true and returns a no-spend receipt. Use --request-file to load a reusable request, then override fields such as --target-count or --strategy-template from the command line. Use --strategy-template to merge a private-safe strategy pattern into the plan without exposing private account labels, and --operating-playbooks to add reusable build-loop gates such as proof-first vertical qualification, net-new suppression, cache-first inventory, and signal-led copy approval. Built-ins map to Signaliz-native tools: lead_generation -> generate_leads, local_leads -> generate_local_leads, email_finding -> find_and_verify_emails, email_verification -> verify_emails, signals -> enrich_company_signals. Add BYO tools with --custom-tool provider:layer:tool[:mcp] or key=value pairs such as provider=apollo,layer=source,tool=apollo_search,mcp=apollo. Use --no-strategy-patterns or --no-workflow-patterns to disable default private strategy memory hints. Commit-plan dry-runs by default and writes only with --confirm-write plus approval identity. Dry-run executes build_campaign with dry_run=true. Approved build requires explicit launch confirmation and approval metadata; add --commit-before-launch to persist the reviewed plan as a GTM campaign before launch, --wait to poll until completion or pending approval, and --approve-delivery to approve reviewed webhook delivery after pending_approval. Use review to inspect status, sampled rows, artifacts, and delivery-readiness gates before approving delivery or routing rows to external tools.
|
|
7627
7842
|
`);
|
|
7628
7843
|
}
|
|
7629
7844
|
main().catch((e) => {
|