@signaliz/cli 1.0.12 → 1.0.13
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/bin.js +180 -4
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1071,6 +1071,7 @@ Campaign Builder:
|
|
|
1071
1071
|
Merge a private-safe strategy template
|
|
1072
1072
|
--builtins a,b lead_generation,local_leads,email_finding,email_verification,signals
|
|
1073
1073
|
--custom-tool ROUTE BYO route: provider:layer:tool[:mcp]
|
|
1074
|
+
campaign-agent doctor Inspect built-in lanes, BYO routes, Memory, Brain, and approvals
|
|
1074
1075
|
campaign-agent proof Prove memory, plan, approvals, and build dry-run without spend
|
|
1075
1076
|
campaign-agent commit-plan
|
|
1076
1077
|
Dry-run or write a reviewed GTM campaign object
|
|
@@ -2791,6 +2792,7 @@ var CAMPAIGN_AGENT_HELP = `signaliz campaign-agent <command> [options]
|
|
|
2791
2792
|
Strategy-template campaign builder:
|
|
2792
2793
|
init Emit reusable CampaignBuilderAgentRequest JSON
|
|
2793
2794
|
plan Compose an approval-gated strategy-template MCP flow
|
|
2795
|
+
doctor Inspect built-in lanes, BYO routes, Memory, Brain, and approvals
|
|
2794
2796
|
proof Prove memory, plan, approvals, and build dry-run without spend
|
|
2795
2797
|
commit-plan Dry-run or write a reviewed GTM campaign object
|
|
2796
2798
|
dry-run Execute build_campaign with dry_run=true
|
|
@@ -2803,6 +2805,7 @@ Strategy-template campaign builder:
|
|
|
2803
2805
|
|
|
2804
2806
|
Examples:
|
|
2805
2807
|
signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
|
|
2808
|
+
signaliz campaign-agent doctor --request-file campaign-request.json --json
|
|
2806
2809
|
signaliz campaign-agent plan --goal "Build a strategy-template campaign for my ICP" --strategy-template non-medical-home-care --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
|
|
2807
2810
|
signaliz campaign-agent proof --goal "Build a strategy-template campaign for my ICP" --strategy-template non-medical-home-care --target-count 100 --json
|
|
2808
2811
|
signaliz campaign-agent plan --request-file campaign-builder-agent-request.json --target-count 250 --json
|
|
@@ -2868,7 +2871,7 @@ async function campaignAgent(sub, rest) {
|
|
|
2868
2871
|
await campaignAgentReview(sub, rest);
|
|
2869
2872
|
return;
|
|
2870
2873
|
}
|
|
2871
|
-
if (!["init", "template", "request-template", "new", "plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(sub)) {
|
|
2874
|
+
if (!["init", "template", "request-template", "new", "plan", "doctor", "readiness", "preflight", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(sub)) {
|
|
2872
2875
|
process.stdout.write(CAMPAIGN_AGENT_HELP);
|
|
2873
2876
|
return;
|
|
2874
2877
|
}
|
|
@@ -2886,7 +2889,8 @@ async function campaignAgent(sub, rest) {
|
|
|
2886
2889
|
return;
|
|
2887
2890
|
}
|
|
2888
2891
|
const requestFromFile = campaignAgentRequestFileFromFlags(flags);
|
|
2889
|
-
const
|
|
2892
|
+
const isDoctor = sub === "doctor" || sub === "readiness" || sub === "preflight";
|
|
2893
|
+
const goal = commandStringFlag(flags, "goal", "brief") || promptArg(rest) || campaignAgentStringValue(requestFromFile?.goal) || (isDoctor ? "Build a strategy-template campaign for the target ICP." : void 0);
|
|
2890
2894
|
if (!goal) die(`campaign-agent ${sub} requires --goal or a request file with goal`);
|
|
2891
2895
|
const isApprovedBuild = sub === "build-approved" || sub === "launch-approved";
|
|
2892
2896
|
const isCommitPlan = sub === "commit-plan";
|
|
@@ -2905,13 +2909,19 @@ async function campaignAgent(sub, rest) {
|
|
|
2905
2909
|
requestFromFile,
|
|
2906
2910
|
campaignAgentRequestFromFlags(goal, flags, { includeDefaults: !requestFromFile })
|
|
2907
2911
|
);
|
|
2908
|
-
const
|
|
2912
|
+
const planOptions = {
|
|
2909
2913
|
discoverCapabilities: !commandBooleanFlag(flags, "skip-discovery"),
|
|
2910
2914
|
scopeCampaign: !commandBooleanFlag(flags, "skip-scope"),
|
|
2911
2915
|
includeStrategyMemoryStatus: !commandBooleanFlag(flags, "no-strategy-memory"),
|
|
2912
2916
|
includeKernelPlan: !commandBooleanFlag(flags, "no-kernel-plan"),
|
|
2913
2917
|
includeDeliveryRisk: !commandBooleanFlag(flags, "no-delivery-risk")
|
|
2914
|
-
}
|
|
2918
|
+
};
|
|
2919
|
+
if (isDoctor) {
|
|
2920
|
+
const readiness = await agent.readiness?.(request, planOptions) || createCampaignAgentReadiness(await agent.createPlan(request, planOptions));
|
|
2921
|
+
if (!readiness.summary?.ready) process.exitCode = 1;
|
|
2922
|
+
return output(readiness, () => printCampaignAgentReadiness(readiness));
|
|
2923
|
+
}
|
|
2924
|
+
const plan = await agent.createPlan(request, planOptions);
|
|
2915
2925
|
if (sub === "proof" || sub === "smoke") {
|
|
2916
2926
|
const result = await agent.dryRunPlan(plan, {
|
|
2917
2927
|
idempotencyKey: commandStringFlag(flags, "idempotency-key")
|
|
@@ -3334,6 +3344,172 @@ function createCampaignAgentApproval(plan, input) {
|
|
|
3334
3344
|
approvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3335
3345
|
};
|
|
3336
3346
|
}
|
|
3347
|
+
function createCampaignAgentReadiness(plan) {
|
|
3348
|
+
const lanes = firstArray(plan?.routes).map((route) => {
|
|
3349
|
+
const builtIn = campaignAgentBuiltInForRoute(route);
|
|
3350
|
+
const customRoute = route?.provider !== "signaliz" && route?.provider !== "csv" && !builtIn;
|
|
3351
|
+
const prepareStep = firstArray(plan?.mcpFlow).find(
|
|
3352
|
+
(step) => step?.tool === "gtm_provider_recipe_prepare" && record(step?.arguments).provider_id === route?.provider
|
|
3353
|
+
);
|
|
3354
|
+
const activateStep = firstArray(plan?.mcpFlow).find(
|
|
3355
|
+
(step) => step?.tool === "gtm_provider_route_activate" && record(step?.arguments).provider_id === route?.provider
|
|
3356
|
+
);
|
|
3357
|
+
const activationArgs = record(activateStep?.arguments);
|
|
3358
|
+
const readOnlySetup = !customRoute || prepareStep?.readOnly === true && activateStep?.readOnly === true && activationArgs.dry_run === true && activationArgs.confirm === false;
|
|
3359
|
+
const blockers2 = [
|
|
3360
|
+
customRoute && !prepareStep ? `${route?.label || route?.provider} is missing provider recipe setup.` : void 0,
|
|
3361
|
+
customRoute && !activateStep ? `${route?.label || route?.provider} is missing provider route dry-run setup.` : void 0,
|
|
3362
|
+
customRoute && !readOnlySetup ? `${route?.label || route?.provider} route setup must stay read-only before approval.` : void 0,
|
|
3363
|
+
route?.mode === "required" && !route?.toolName && customRoute ? `${route?.label || route?.provider} is required but has no tool name.` : void 0
|
|
3364
|
+
].filter(Boolean);
|
|
3365
|
+
return {
|
|
3366
|
+
id: route?.id || `${route?.provider}-${route?.layer}`,
|
|
3367
|
+
label: route?.label || campaignAgentReadinessLaneLabel(route, builtIn),
|
|
3368
|
+
layer: route?.layer,
|
|
3369
|
+
gtmLayers: firstArray(route?.gtmLayers).length ? route.gtmLayers : [route?.gtmLayer].filter(Boolean),
|
|
3370
|
+
provider: route?.provider,
|
|
3371
|
+
toolName: route?.toolName,
|
|
3372
|
+
mode: route?.mode || "if_available",
|
|
3373
|
+
builtIn,
|
|
3374
|
+
approvalRequired: route?.approvalRequired === true || firstArray(plan?.approvals).some((approval) => approval?.routeId === route?.id),
|
|
3375
|
+
customRoute,
|
|
3376
|
+
readOnlySetup,
|
|
3377
|
+
ready: blockers2.length === 0,
|
|
3378
|
+
blockers: blockers2,
|
|
3379
|
+
nextAction: customRoute ? `Review ${route?.provider} route setup before launch approval.` : void 0
|
|
3380
|
+
};
|
|
3381
|
+
});
|
|
3382
|
+
const builtInLanes = lanes.filter((lane) => lane.builtIn);
|
|
3383
|
+
const customRoutes = lanes.filter((lane) => lane.customRoute);
|
|
3384
|
+
const strategyMemory = record(plan?.strategyMemoryStatus);
|
|
3385
|
+
const deliveryRisk = record(record(plan?.buildRequest).deliveryRisk);
|
|
3386
|
+
const risk = record(deliveryRisk.risk);
|
|
3387
|
+
const riskLevel = String(risk.risk_level || risk.riskLevel || "").toLowerCase();
|
|
3388
|
+
const riskBlockers = firstArray(deliveryRisk.blockers);
|
|
3389
|
+
const gates = [
|
|
3390
|
+
{
|
|
3391
|
+
id: "campaign_plan_created",
|
|
3392
|
+
label: "Campaign plan created",
|
|
3393
|
+
passed: Boolean(plan?.planId && firstArray(plan?.mcpFlow).length),
|
|
3394
|
+
detail: plan?.planId ? `Plan ${plan.planId} has ${firstArray(plan?.mcpFlow).length} MCP step(s).` : "No campaign-builder plan was created."
|
|
3395
|
+
},
|
|
3396
|
+
{
|
|
3397
|
+
id: "built_in_lanes_ready",
|
|
3398
|
+
label: "Built-in lanes ready",
|
|
3399
|
+
passed: builtInLanes.length > 0 && builtInLanes.every((lane) => lane.ready),
|
|
3400
|
+
detail: `${builtInLanes.filter((lane) => lane.ready).length}/${builtInLanes.length} Signaliz built-in lane(s) are present.`
|
|
3401
|
+
},
|
|
3402
|
+
{
|
|
3403
|
+
id: "strategy_memory_ready",
|
|
3404
|
+
label: "Strategy memory ready",
|
|
3405
|
+
passed: !plan?.strategyMemoryStatus || strategyMemory.ready !== false,
|
|
3406
|
+
detail: plan?.strategyMemoryStatus ? "Strategy memory readiness was checked." : "Strategy memory readiness was not requested."
|
|
3407
|
+
},
|
|
3408
|
+
{
|
|
3409
|
+
id: "kernel_plan_attached",
|
|
3410
|
+
label: "Kernel plan attached",
|
|
3411
|
+
passed: Object.keys(record(plan?.kernelPlan)).length > 0,
|
|
3412
|
+
detail: Object.keys(record(plan?.kernelPlan)).length > 0 ? "Kernel planner evidence is attached." : "Kernel planner evidence is not attached."
|
|
3413
|
+
},
|
|
3414
|
+
{
|
|
3415
|
+
id: "delivery_risk_clear",
|
|
3416
|
+
label: "Delivery risk clear",
|
|
3417
|
+
passed: Object.keys(deliveryRisk).length === 0 || riskBlockers.length === 0 && !["high", "critical", "blocked"].includes(riskLevel),
|
|
3418
|
+
detail: Object.keys(deliveryRisk).length === 0 ? "Delivery risk preflight was not requested." : `Delivery risk is ${riskLevel || "available"} with ${riskBlockers.length} blocker(s).`
|
|
3419
|
+
},
|
|
3420
|
+
{
|
|
3421
|
+
id: "custom_routes_prepared",
|
|
3422
|
+
label: "Custom routes prepared",
|
|
3423
|
+
passed: customRoutes.every((lane) => lane.ready),
|
|
3424
|
+
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.`
|
|
3425
|
+
},
|
|
3426
|
+
{
|
|
3427
|
+
id: "approval_gates_present",
|
|
3428
|
+
label: "Approval gates present",
|
|
3429
|
+
passed: firstArray(plan?.approvals).length > 0,
|
|
3430
|
+
detail: firstArray(plan?.approvals).length > 0 ? `${firstArray(plan?.approvals).length} approval gate(s) are attached.` : "No approval gates are attached."
|
|
3431
|
+
}
|
|
3432
|
+
];
|
|
3433
|
+
const blockers = [
|
|
3434
|
+
...gates.filter((gate) => !gate.passed).map((gate) => gate.detail),
|
|
3435
|
+
...lanes.flatMap((lane) => lane.blockers || [])
|
|
3436
|
+
];
|
|
3437
|
+
const ready = blockers.length === 0;
|
|
3438
|
+
return {
|
|
3439
|
+
plan,
|
|
3440
|
+
lanes,
|
|
3441
|
+
gates,
|
|
3442
|
+
summary: {
|
|
3443
|
+
ready,
|
|
3444
|
+
score: Math.round(gates.filter((gate) => gate.passed).length / gates.length * 100),
|
|
3445
|
+
targetCount: plan?.targetCount,
|
|
3446
|
+
estimatedCredits: plan?.estimatedCredits,
|
|
3447
|
+
builtInLanesReady: builtInLanes.filter((lane) => lane.ready).length,
|
|
3448
|
+
builtInLanesTotal: builtInLanes.length,
|
|
3449
|
+
customRoutesReady: customRoutes.filter((lane) => lane.ready).length,
|
|
3450
|
+
customRoutesTotal: customRoutes.length,
|
|
3451
|
+
approvalGateCount: firstArray(plan?.approvals).length,
|
|
3452
|
+
blockers,
|
|
3453
|
+
warnings: firstArray(plan?.warnings)
|
|
3454
|
+
},
|
|
3455
|
+
nextActions: ready ? [
|
|
3456
|
+
"signaliz campaign-agent proof --request-file campaign-request.json --json",
|
|
3457
|
+
"signaliz campaign-agent commit-plan --request-file campaign-request.json --json",
|
|
3458
|
+
`signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch --approve-all --approved-by operator@example.com --spend-limit ${plan?.estimatedCredits || 0}`
|
|
3459
|
+
] : ["signaliz campaign-agent plan --request-file campaign-request.json --json"]
|
|
3460
|
+
};
|
|
3461
|
+
}
|
|
3462
|
+
function campaignAgentBuiltInForRoute(route) {
|
|
3463
|
+
const map = {
|
|
3464
|
+
"signaliz-lead-generation": "lead_generation",
|
|
3465
|
+
"signaliz-local-leads": "local_leads",
|
|
3466
|
+
"signaliz-email-finding": "email_finding",
|
|
3467
|
+
"signaliz-email-verification": "email_verification",
|
|
3468
|
+
"signaliz-signals": "signals"
|
|
3469
|
+
};
|
|
3470
|
+
return map[String(route?.id || "")];
|
|
3471
|
+
}
|
|
3472
|
+
function campaignAgentReadinessLaneLabel(route, builtIn) {
|
|
3473
|
+
const labels = {
|
|
3474
|
+
lead_generation: "Signaliz lead generation",
|
|
3475
|
+
local_leads: "Signaliz local leads",
|
|
3476
|
+
email_finding: "Signaliz email finding",
|
|
3477
|
+
email_verification: "Signaliz email verification",
|
|
3478
|
+
signals: "Signaliz signals"
|
|
3479
|
+
};
|
|
3480
|
+
return builtIn ? labels[builtIn] : `${route?.provider || "custom"} ${route?.layer || "route"}`;
|
|
3481
|
+
}
|
|
3482
|
+
function printCampaignAgentReadiness(readiness) {
|
|
3483
|
+
const summary = record(readiness.summary);
|
|
3484
|
+
const plan = record(readiness.plan);
|
|
3485
|
+
console.log(`Readiness: ${summary.ready === true ? "ready" : "blocked"} (${summary.score || 0}%)`);
|
|
3486
|
+
if (plan.campaignName) console.log(`Campaign: ${plan.campaignName}`);
|
|
3487
|
+
if (summary.targetCount !== void 0) console.log(`Target: ${summary.targetCount}`);
|
|
3488
|
+
if (summary.estimatedCredits !== void 0) console.log(`Estimated credits: ${summary.estimatedCredits}`);
|
|
3489
|
+
console.log(`Built-ins: ${summary.builtInLanesReady || 0}/${summary.builtInLanesTotal || 0}`);
|
|
3490
|
+
console.log(`BYO routes: ${summary.customRoutesReady || 0}/${summary.customRoutesTotal || 0}`);
|
|
3491
|
+
console.log(`Approval gates: ${summary.approvalGateCount || 0}`);
|
|
3492
|
+
const gates = firstArray(readiness.gates);
|
|
3493
|
+
if (gates.length) {
|
|
3494
|
+
console.log("\nGates:");
|
|
3495
|
+
for (const gate of gates) console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
|
|
3496
|
+
}
|
|
3497
|
+
const lanes = firstArray(readiness.lanes);
|
|
3498
|
+
if (lanes.length) {
|
|
3499
|
+
console.log("\nLanes:");
|
|
3500
|
+
for (const lane of lanes) console.log(`- ${lane.ready ? "READY" : "BLOCKED"} ${lane.label}: ${lane.toolName || lane.provider}`);
|
|
3501
|
+
}
|
|
3502
|
+
const blockers = firstArray(summary.blockers);
|
|
3503
|
+
if (blockers.length) {
|
|
3504
|
+
console.log("\nBlockers:");
|
|
3505
|
+
for (const blocker of blockers.slice(0, 8)) console.log(`- ${blocker}`);
|
|
3506
|
+
}
|
|
3507
|
+
const nextActions = firstArray(readiness.nextActions);
|
|
3508
|
+
if (nextActions.length) {
|
|
3509
|
+
console.log("\nNext:");
|
|
3510
|
+
for (const action of nextActions) console.log(`- ${action}`);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3337
3513
|
function printCampaignAgentPlan(plan) {
|
|
3338
3514
|
console.log(`Plan: ${plan.campaignName || plan.goal || plan.planId}`);
|
|
3339
3515
|
if (plan.planId) console.log(`Plan ID: ${plan.planId}`);
|