@signaliz/cli 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/dist/bin.js +193 -11
- 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,21 +2909,32 @@ 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
|
+
}
|
|
2915
2924
|
if (sub === "proof" || sub === "smoke") {
|
|
2916
|
-
const
|
|
2925
|
+
const proof = typeof agent.proof === "function" ? await agent.proof(request, {
|
|
2926
|
+
...planOptions,
|
|
2917
2927
|
idempotencyKey: commandStringFlag(flags, "idempotency-key")
|
|
2918
|
-
})
|
|
2919
|
-
|
|
2928
|
+
}) : await (async () => {
|
|
2929
|
+
const plan2 = await agent.createPlan(request, planOptions);
|
|
2930
|
+
return createCampaignAgentProofReceipt(plan2, await agent.dryRunPlan(plan2, {
|
|
2931
|
+
idempotencyKey: commandStringFlag(flags, "idempotency-key")
|
|
2932
|
+
}));
|
|
2933
|
+
})();
|
|
2920
2934
|
if (!proof.success) process.exitCode = 1;
|
|
2921
2935
|
return output(proof, () => printCampaignAgentProof(proof));
|
|
2922
2936
|
}
|
|
2937
|
+
const plan = await agent.createPlan(request, planOptions);
|
|
2923
2938
|
if (isCommitPlan) {
|
|
2924
2939
|
const result = await agent.commitPlan(plan, {
|
|
2925
2940
|
confirm: isConfirmedCommit,
|
|
@@ -3334,6 +3349,172 @@ function createCampaignAgentApproval(plan, input) {
|
|
|
3334
3349
|
approvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3335
3350
|
};
|
|
3336
3351
|
}
|
|
3352
|
+
function createCampaignAgentReadiness(plan) {
|
|
3353
|
+
const lanes = firstArray(plan?.routes).map((route) => {
|
|
3354
|
+
const builtIn = campaignAgentBuiltInForRoute(route);
|
|
3355
|
+
const customRoute = route?.provider !== "signaliz" && route?.provider !== "csv" && !builtIn;
|
|
3356
|
+
const prepareStep = firstArray(plan?.mcpFlow).find(
|
|
3357
|
+
(step) => step?.tool === "gtm_provider_recipe_prepare" && record(step?.arguments).provider_id === route?.provider
|
|
3358
|
+
);
|
|
3359
|
+
const activateStep = firstArray(plan?.mcpFlow).find(
|
|
3360
|
+
(step) => step?.tool === "gtm_provider_route_activate" && record(step?.arguments).provider_id === route?.provider
|
|
3361
|
+
);
|
|
3362
|
+
const activationArgs = record(activateStep?.arguments);
|
|
3363
|
+
const readOnlySetup = !customRoute || prepareStep?.readOnly === true && activateStep?.readOnly === true && activationArgs.dry_run === true && activationArgs.confirm === false;
|
|
3364
|
+
const blockers2 = [
|
|
3365
|
+
customRoute && !prepareStep ? `${route?.label || route?.provider} is missing provider recipe setup.` : void 0,
|
|
3366
|
+
customRoute && !activateStep ? `${route?.label || route?.provider} is missing provider route dry-run setup.` : void 0,
|
|
3367
|
+
customRoute && !readOnlySetup ? `${route?.label || route?.provider} route setup must stay read-only before approval.` : void 0,
|
|
3368
|
+
route?.mode === "required" && !route?.toolName && customRoute ? `${route?.label || route?.provider} is required but has no tool name.` : void 0
|
|
3369
|
+
].filter(Boolean);
|
|
3370
|
+
return {
|
|
3371
|
+
id: route?.id || `${route?.provider}-${route?.layer}`,
|
|
3372
|
+
label: route?.label || campaignAgentReadinessLaneLabel(route, builtIn),
|
|
3373
|
+
layer: route?.layer,
|
|
3374
|
+
gtmLayers: firstArray(route?.gtmLayers).length ? route.gtmLayers : [route?.gtmLayer].filter(Boolean),
|
|
3375
|
+
provider: route?.provider,
|
|
3376
|
+
toolName: route?.toolName,
|
|
3377
|
+
mode: route?.mode || "if_available",
|
|
3378
|
+
builtIn,
|
|
3379
|
+
approvalRequired: route?.approvalRequired === true || firstArray(plan?.approvals).some((approval) => approval?.routeId === route?.id),
|
|
3380
|
+
customRoute,
|
|
3381
|
+
readOnlySetup,
|
|
3382
|
+
ready: blockers2.length === 0,
|
|
3383
|
+
blockers: blockers2,
|
|
3384
|
+
nextAction: customRoute ? `Review ${route?.provider} route setup before launch approval.` : void 0
|
|
3385
|
+
};
|
|
3386
|
+
});
|
|
3387
|
+
const builtInLanes = lanes.filter((lane) => lane.builtIn);
|
|
3388
|
+
const customRoutes = lanes.filter((lane) => lane.customRoute);
|
|
3389
|
+
const strategyMemory = record(plan?.strategyMemoryStatus);
|
|
3390
|
+
const deliveryRisk = record(record(plan?.buildRequest).deliveryRisk);
|
|
3391
|
+
const risk = record(deliveryRisk.risk);
|
|
3392
|
+
const riskLevel = String(risk.risk_level || risk.riskLevel || "").toLowerCase();
|
|
3393
|
+
const riskBlockers = firstArray(deliveryRisk.blockers);
|
|
3394
|
+
const gates = [
|
|
3395
|
+
{
|
|
3396
|
+
id: "campaign_plan_created",
|
|
3397
|
+
label: "Campaign plan created",
|
|
3398
|
+
passed: Boolean(plan?.planId && firstArray(plan?.mcpFlow).length),
|
|
3399
|
+
detail: plan?.planId ? `Plan ${plan.planId} has ${firstArray(plan?.mcpFlow).length} MCP step(s).` : "No campaign-builder plan was created."
|
|
3400
|
+
},
|
|
3401
|
+
{
|
|
3402
|
+
id: "built_in_lanes_ready",
|
|
3403
|
+
label: "Built-in lanes ready",
|
|
3404
|
+
passed: builtInLanes.length > 0 && builtInLanes.every((lane) => lane.ready),
|
|
3405
|
+
detail: `${builtInLanes.filter((lane) => lane.ready).length}/${builtInLanes.length} Signaliz built-in lane(s) are present.`
|
|
3406
|
+
},
|
|
3407
|
+
{
|
|
3408
|
+
id: "strategy_memory_ready",
|
|
3409
|
+
label: "Strategy memory ready",
|
|
3410
|
+
passed: !plan?.strategyMemoryStatus || strategyMemory.ready !== false,
|
|
3411
|
+
detail: plan?.strategyMemoryStatus ? "Strategy memory readiness was checked." : "Strategy memory readiness was not requested."
|
|
3412
|
+
},
|
|
3413
|
+
{
|
|
3414
|
+
id: "kernel_plan_attached",
|
|
3415
|
+
label: "Kernel plan attached",
|
|
3416
|
+
passed: Object.keys(record(plan?.kernelPlan)).length > 0,
|
|
3417
|
+
detail: Object.keys(record(plan?.kernelPlan)).length > 0 ? "Kernel planner evidence is attached." : "Kernel planner evidence is not attached."
|
|
3418
|
+
},
|
|
3419
|
+
{
|
|
3420
|
+
id: "delivery_risk_clear",
|
|
3421
|
+
label: "Delivery risk clear",
|
|
3422
|
+
passed: Object.keys(deliveryRisk).length === 0 || riskBlockers.length === 0 && !["high", "critical", "blocked"].includes(riskLevel),
|
|
3423
|
+
detail: Object.keys(deliveryRisk).length === 0 ? "Delivery risk preflight was not requested." : `Delivery risk is ${riskLevel || "available"} with ${riskBlockers.length} blocker(s).`
|
|
3424
|
+
},
|
|
3425
|
+
{
|
|
3426
|
+
id: "custom_routes_prepared",
|
|
3427
|
+
label: "Custom routes prepared",
|
|
3428
|
+
passed: customRoutes.every((lane) => lane.ready),
|
|
3429
|
+
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.`
|
|
3430
|
+
},
|
|
3431
|
+
{
|
|
3432
|
+
id: "approval_gates_present",
|
|
3433
|
+
label: "Approval gates present",
|
|
3434
|
+
passed: firstArray(plan?.approvals).length > 0,
|
|
3435
|
+
detail: firstArray(plan?.approvals).length > 0 ? `${firstArray(plan?.approvals).length} approval gate(s) are attached.` : "No approval gates are attached."
|
|
3436
|
+
}
|
|
3437
|
+
];
|
|
3438
|
+
const blockers = [
|
|
3439
|
+
...gates.filter((gate) => !gate.passed).map((gate) => gate.detail),
|
|
3440
|
+
...lanes.flatMap((lane) => lane.blockers || [])
|
|
3441
|
+
];
|
|
3442
|
+
const ready = blockers.length === 0;
|
|
3443
|
+
return {
|
|
3444
|
+
plan,
|
|
3445
|
+
lanes,
|
|
3446
|
+
gates,
|
|
3447
|
+
summary: {
|
|
3448
|
+
ready,
|
|
3449
|
+
score: Math.round(gates.filter((gate) => gate.passed).length / gates.length * 100),
|
|
3450
|
+
targetCount: plan?.targetCount,
|
|
3451
|
+
estimatedCredits: plan?.estimatedCredits,
|
|
3452
|
+
builtInLanesReady: builtInLanes.filter((lane) => lane.ready).length,
|
|
3453
|
+
builtInLanesTotal: builtInLanes.length,
|
|
3454
|
+
customRoutesReady: customRoutes.filter((lane) => lane.ready).length,
|
|
3455
|
+
customRoutesTotal: customRoutes.length,
|
|
3456
|
+
approvalGateCount: firstArray(plan?.approvals).length,
|
|
3457
|
+
blockers,
|
|
3458
|
+
warnings: firstArray(plan?.warnings)
|
|
3459
|
+
},
|
|
3460
|
+
nextActions: ready ? [
|
|
3461
|
+
"signaliz campaign-agent proof --request-file campaign-request.json --json",
|
|
3462
|
+
"signaliz campaign-agent commit-plan --request-file campaign-request.json --json",
|
|
3463
|
+
`signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch --approve-all --approved-by operator@example.com --spend-limit ${plan?.estimatedCredits || 0}`
|
|
3464
|
+
] : ["signaliz campaign-agent plan --request-file campaign-request.json --json"]
|
|
3465
|
+
};
|
|
3466
|
+
}
|
|
3467
|
+
function campaignAgentBuiltInForRoute(route) {
|
|
3468
|
+
const map = {
|
|
3469
|
+
"signaliz-lead-generation": "lead_generation",
|
|
3470
|
+
"signaliz-local-leads": "local_leads",
|
|
3471
|
+
"signaliz-email-finding": "email_finding",
|
|
3472
|
+
"signaliz-email-verification": "email_verification",
|
|
3473
|
+
"signaliz-signals": "signals"
|
|
3474
|
+
};
|
|
3475
|
+
return map[String(route?.id || "")];
|
|
3476
|
+
}
|
|
3477
|
+
function campaignAgentReadinessLaneLabel(route, builtIn) {
|
|
3478
|
+
const labels = {
|
|
3479
|
+
lead_generation: "Signaliz lead generation",
|
|
3480
|
+
local_leads: "Signaliz local leads",
|
|
3481
|
+
email_finding: "Signaliz email finding",
|
|
3482
|
+
email_verification: "Signaliz email verification",
|
|
3483
|
+
signals: "Signaliz signals"
|
|
3484
|
+
};
|
|
3485
|
+
return builtIn ? labels[builtIn] : `${route?.provider || "custom"} ${route?.layer || "route"}`;
|
|
3486
|
+
}
|
|
3487
|
+
function printCampaignAgentReadiness(readiness) {
|
|
3488
|
+
const summary = record(readiness.summary);
|
|
3489
|
+
const plan = record(readiness.plan);
|
|
3490
|
+
console.log(`Readiness: ${summary.ready === true ? "ready" : "blocked"} (${summary.score || 0}%)`);
|
|
3491
|
+
if (plan.campaignName) console.log(`Campaign: ${plan.campaignName}`);
|
|
3492
|
+
if (summary.targetCount !== void 0) console.log(`Target: ${summary.targetCount}`);
|
|
3493
|
+
if (summary.estimatedCredits !== void 0) console.log(`Estimated credits: ${summary.estimatedCredits}`);
|
|
3494
|
+
console.log(`Built-ins: ${summary.builtInLanesReady || 0}/${summary.builtInLanesTotal || 0}`);
|
|
3495
|
+
console.log(`BYO routes: ${summary.customRoutesReady || 0}/${summary.customRoutesTotal || 0}`);
|
|
3496
|
+
console.log(`Approval gates: ${summary.approvalGateCount || 0}`);
|
|
3497
|
+
const gates = firstArray(readiness.gates);
|
|
3498
|
+
if (gates.length) {
|
|
3499
|
+
console.log("\nGates:");
|
|
3500
|
+
for (const gate of gates) console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
|
|
3501
|
+
}
|
|
3502
|
+
const lanes = firstArray(readiness.lanes);
|
|
3503
|
+
if (lanes.length) {
|
|
3504
|
+
console.log("\nLanes:");
|
|
3505
|
+
for (const lane of lanes) console.log(`- ${lane.ready ? "READY" : "BLOCKED"} ${lane.label}: ${lane.toolName || lane.provider}`);
|
|
3506
|
+
}
|
|
3507
|
+
const blockers = firstArray(summary.blockers);
|
|
3508
|
+
if (blockers.length) {
|
|
3509
|
+
console.log("\nBlockers:");
|
|
3510
|
+
for (const blocker of blockers.slice(0, 8)) console.log(`- ${blocker}`);
|
|
3511
|
+
}
|
|
3512
|
+
const nextActions = firstArray(readiness.nextActions);
|
|
3513
|
+
if (nextActions.length) {
|
|
3514
|
+
console.log("\nNext:");
|
|
3515
|
+
for (const action of nextActions) console.log(`- ${action}`);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3337
3518
|
function printCampaignAgentPlan(plan) {
|
|
3338
3519
|
console.log(`Plan: ${plan.campaignName || plan.goal || plan.planId}`);
|
|
3339
3520
|
if (plan.planId) console.log(`Plan ID: ${plan.planId}`);
|
|
@@ -5570,18 +5751,19 @@ async function simpleJob(cmd, rest) {
|
|
|
5570
5751
|
if (isHelpRequest(rest) || !promptArg(rest) && !flagArg("prompt") && !flagArg("brief") && !flagArg("campaign-brief")) {
|
|
5571
5752
|
process.stdout.write(`signaliz build "campaign brief" [options]
|
|
5572
5753
|
|
|
5573
|
-
|
|
5754
|
+
Run the campaign-agent proof path: strategy memory, Kernel plan, approvals, and
|
|
5755
|
+
a forced build_campaign dry-run without spend or provider writes.
|
|
5574
5756
|
|
|
5575
5757
|
Examples:
|
|
5576
5758
|
signaliz build "Build a campaign for industrial maintenance buyers" --target-count 50
|
|
5577
|
-
signaliz build "
|
|
5759
|
+
signaliz build "Build a strategy-template campaign for local operators" --strategy-template non-medical-home-care --use-local-leads --json
|
|
5578
5760
|
|
|
5579
5761
|
Equivalent:
|
|
5580
|
-
signaliz
|
|
5762
|
+
signaliz campaign-agent proof "campaign brief"
|
|
5581
5763
|
`);
|
|
5582
5764
|
return;
|
|
5583
5765
|
}
|
|
5584
|
-
return
|
|
5766
|
+
return campaignAgent("proof", rest);
|
|
5585
5767
|
}
|
|
5586
5768
|
if (cmd === "connect") {
|
|
5587
5769
|
if (isHelpRequest(rest)) {
|