@signaliz/cli 1.0.10 → 1.0.12

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.
Files changed (2) hide show
  1. package/dist/bin.js +283 -0
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -1077,6 +1077,16 @@ Campaign Builder:
1077
1077
  campaign-agent dry-run Execute build_campaign with dry_run=true
1078
1078
  campaign-agent build-approved
1079
1079
  Launch only after explicit approval metadata
1080
+ campaign-agent review <id>
1081
+ Review rows, artifacts, and delivery gates
1082
+ campaign-agent status <id>
1083
+ Inspect a campaign-agent build
1084
+ campaign-agent rows <id>
1085
+ Retrieve reviewable rows
1086
+ campaign-agent artifacts <id>
1087
+ List generated artifacts
1088
+ campaign-agent approve <id>
1089
+ Approve a reviewed delivery destination
1080
1090
 
1081
1091
  campaign scope Scope a workspace/account campaign into a markdown brief + dry-run args
1082
1092
  --prompt "..." Campaign request or outcome (required)
@@ -2785,6 +2795,11 @@ Strategy-template campaign builder:
2785
2795
  commit-plan Dry-run or write a reviewed GTM campaign object
2786
2796
  dry-run Execute build_campaign with dry_run=true
2787
2797
  build-approved Launch only after explicit approval metadata
2798
+ review Review status, rows, artifacts, and delivery gates
2799
+ status Inspect a campaign-agent build
2800
+ rows Retrieve reviewable campaign-agent rows
2801
+ artifacts List generated artifacts
2802
+ approve Approve a reviewed delivery destination
2788
2803
 
2789
2804
  Examples:
2790
2805
  signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
@@ -2794,6 +2809,9 @@ Examples:
2794
2809
  signaliz campaign-agent dry-run --goal "Build a local services campaign" --target-count 250 --use-local-leads --json
2795
2810
  signaliz campaign-agent build-approved --goal "Build a strategy-template campaign" --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500
2796
2811
  signaliz campaign-agent build-approved --request-file campaign-builder-agent-request.json --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500 --wait --approve-delivery --delivery-destination-type json
2812
+ signaliz campaign-agent review <campaign_build_id> --limit 100 --json
2813
+ signaliz campaign-agent status <campaign_build_id> --json
2814
+ signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
2797
2815
 
2798
2816
  Plan options:
2799
2817
  --goal TEXT Campaign goal or brief
@@ -2846,6 +2864,10 @@ async function campaignAgent(sub, rest) {
2846
2864
  process.stdout.write(CAMPAIGN_AGENT_HELP);
2847
2865
  return;
2848
2866
  }
2867
+ if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(sub)) {
2868
+ await campaignAgentReview(sub, rest);
2869
+ return;
2870
+ }
2849
2871
  if (!["init", "template", "request-template", "new", "plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(sub)) {
2850
2872
  process.stdout.write(CAMPAIGN_AGENT_HELP);
2851
2873
  return;
@@ -2949,6 +2971,89 @@ async function campaignAgent(sub, rest) {
2949
2971
  }
2950
2972
  return output(plan, () => printCampaignAgentPlan(plan));
2951
2973
  }
2974
+ async function campaignAgentReview(sub, rest) {
2975
+ const flags = parseCommandFlags(rest);
2976
+ const buildId = rest[0] && !rest[0].startsWith("--") ? rest[0] : commandStringFlag(flags, "campaign-build-id", "build-id");
2977
+ if (!buildId) die(`campaign-agent ${sub} requires <campaign_build_id> or --campaign-build-id`);
2978
+ const sdk = getSdk();
2979
+ const agent = sdk.campaignBuilderAgent;
2980
+ const campaigns = sdk.campaigns || {};
2981
+ if (sub === "review") {
2982
+ const rowOptions = {
2983
+ limit: commandNumberFlag(flags, "limit") ?? 100,
2984
+ cursor: commandStringFlag(flags, "cursor"),
2985
+ segment: commandStringFlag(flags, "segment"),
2986
+ rowStatus: commandStringFlag(flags, "row-status"),
2987
+ qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
2988
+ };
2989
+ const review = await agent.reviewBuild?.(buildId, rowOptions) || await campaignAgentBuildReviewFromCampaignApis(agent, campaigns, buildId, rowOptions);
2990
+ const operatorReview = {
2991
+ ...review,
2992
+ rows: {
2993
+ ...review.rows,
2994
+ rows: formatCampaignRowsForOperator(review.rows?.rows || [])
2995
+ }
2996
+ };
2997
+ return output(operatorReview, () => printCampaignAgentBuildReview(operatorReview));
2998
+ }
2999
+ if (sub === "status") {
3000
+ const status = await (agent.getBuildStatus?.bind(agent) || campaigns.status?.bind(campaigns) || campaigns.getCampaignBuildStatus?.bind(campaigns))?.(buildId);
3001
+ if (!status) die("campaign-agent status requires a compatible @signaliz/sdk campaign status API");
3002
+ return output(status, () => printCampaignAgentBuildStatus(status));
3003
+ }
3004
+ if (sub === "rows") {
3005
+ const rowOptions = {
3006
+ limit: commandNumberFlag(flags, "limit"),
3007
+ cursor: commandStringFlag(flags, "cursor"),
3008
+ segment: commandStringFlag(flags, "segment"),
3009
+ rowStatus: commandStringFlag(flags, "row-status"),
3010
+ qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
3011
+ };
3012
+ const result2 = await (agent.getBuildRows?.bind(agent) || campaigns.rows?.bind(campaigns) || campaigns.getCampaignBuildRows?.bind(campaigns))?.(buildId, rowOptions);
3013
+ if (!result2) die("campaign-agent rows requires a compatible @signaliz/sdk campaign rows API");
3014
+ const operatorResult = {
3015
+ ...result2,
3016
+ rows: formatCampaignRowsForOperator(result2.rows)
3017
+ };
3018
+ return output(operatorResult, () => printCampaignAgentRows(operatorResult));
3019
+ }
3020
+ if (sub === "artifacts") {
3021
+ const artifacts = await (agent.listBuildArtifacts?.bind(agent) || campaigns.artifacts?.bind(campaigns) || campaigns.listCampaignBuildArtifacts?.bind(campaigns))?.(buildId);
3022
+ if (!artifacts) die("campaign-agent artifacts requires a compatible @signaliz/sdk campaign artifacts API");
3023
+ return output(artifacts, () => {
3024
+ if (artifacts.length === 0) {
3025
+ console.log("No artifacts yet.");
3026
+ hint(`signaliz campaign-agent status ${buildId}`);
3027
+ return;
3028
+ }
3029
+ for (const artifact of artifacts) {
3030
+ console.log(`${artifact.artifactType || "artifact"} - ${artifact.rowCount} rows${artifact.signedUrl ? `
3031
+ ${artifact.signedUrl}` : ""}`);
3032
+ }
3033
+ });
3034
+ }
3035
+ const destinationType = commandStringFlag(flags, "destination-type", "delivery-destination-type", "type");
3036
+ if (!destinationType || !["json", "csv", "webhook"].includes(destinationType)) {
3037
+ die("campaign-agent approve requires --destination-type json|csv|webhook");
3038
+ }
3039
+ const deliveryOptions = {
3040
+ destinationId: commandStringFlag(flags, "destination-id", "delivery-destination-id"),
3041
+ destinationConfig: campaignAgentJsonObjectInput(flags, ["destination-config", "delivery-config"], ["destination-config-file", "delivery-config-file"])
3042
+ };
3043
+ const result = await (agent.approveDelivery?.bind(agent) || campaigns.approveCampaignDelivery?.bind(campaigns))?.(buildId, destinationType, deliveryOptions);
3044
+ if (!result) die("campaign-agent approve requires a compatible @signaliz/sdk campaign delivery API");
3045
+ return output(result, () => {
3046
+ console.log(`Delivery ${result.status}: ${result.destinationType}`);
3047
+ if (result.message) console.log(result.message);
3048
+ });
3049
+ }
3050
+ async function campaignAgentBuildReviewFromCampaignApis(agent, campaigns, buildId, rowOptions) {
3051
+ const status = await (agent.getBuildStatus?.bind(agent) || campaigns.status?.bind(campaigns) || campaigns.getCampaignBuildStatus?.bind(campaigns))?.(buildId);
3052
+ const rows = await (agent.getBuildRows?.bind(agent) || campaigns.rows?.bind(campaigns) || campaigns.getCampaignBuildRows?.bind(campaigns))?.(buildId, rowOptions);
3053
+ const artifacts = await (agent.listBuildArtifacts?.bind(agent) || campaigns.artifacts?.bind(campaigns) || campaigns.listCampaignBuildArtifacts?.bind(campaigns))?.(buildId);
3054
+ if (!status || !rows || !artifacts) die("campaign-agent review requires compatible @signaliz/sdk build status, rows, and artifacts APIs");
3055
+ return createCampaignAgentBuildReview(status, rows, artifacts);
3056
+ }
2952
3057
  function campaignAgentRequestTemplateFromFlags(flags, rest) {
2953
3058
  const goal = commandStringFlag(flags, "goal", "brief") || promptArg(rest) || "Build a strategy-template campaign for mature operators in the target ICP.";
2954
3059
  const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
@@ -3257,6 +3362,184 @@ function printCampaignAgentExecution(plan, result) {
3257
3362
  console.log("\nResult:");
3258
3363
  console.log(JSON.stringify(result, null, 2));
3259
3364
  }
3365
+ function printCampaignAgentBuildStatus(status) {
3366
+ console.log(`Campaign: ${status.name || status.campaignBuildId}`);
3367
+ if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
3368
+ console.log(`Status: ${status.status}`);
3369
+ console.log(`Phase: ${status.currentPhase || "N/A"}`);
3370
+ console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
3371
+ console.log(`Artifacts: ${status.artifactCount}`);
3372
+ if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
3373
+ if (Array.isArray(status.warnings) && status.warnings.length) {
3374
+ console.log(`Warnings: ${status.warnings.length}`);
3375
+ for (const warning of status.warnings.slice(0, 3)) console.log(` - ${warning}`);
3376
+ }
3377
+ if (Array.isArray(status.errors) && status.errors.length) {
3378
+ console.log(`Errors: ${status.errors.length}`);
3379
+ for (const error of status.errors.slice(0, 3)) console.log(` - ${error}`);
3380
+ }
3381
+ if (status.status === "completed") {
3382
+ hint(`signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
3383
+ } else if (status.status === "pending_approval") {
3384
+ hint(`signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
3385
+ } else if ((status.status === "running" || status.status === "queued") && status.triggerRunId) {
3386
+ hint(`signaliz ops run-status ${status.triggerRunId} --watch`);
3387
+ }
3388
+ }
3389
+ function printCampaignAgentBuildReview(review) {
3390
+ const summary = record(review.summary);
3391
+ const status = record(review.status);
3392
+ console.log(`Campaign: ${status.name || review.campaignBuildId}`);
3393
+ console.log(`Status: ${summary.status || status.status}`);
3394
+ console.log(`Phase: ${summary.phase || status.currentPhase || "N/A"}`);
3395
+ console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
3396
+ console.log(`Qualified: ${summary.qualifiedRows || 0}`);
3397
+ console.log(`Emails: ${summary.rowsWithEmail || 0}`);
3398
+ console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
3399
+ console.log(`Artifacts: ${summary.artifactCount || 0}`);
3400
+ console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
3401
+ const gates = Array.isArray(review.gates) ? review.gates : [];
3402
+ if (gates.length) {
3403
+ console.log("\nGates:");
3404
+ for (const gate of gates) {
3405
+ console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
3406
+ }
3407
+ }
3408
+ const warnings = Array.isArray(summary.warnings) ? summary.warnings : [];
3409
+ if (warnings.length) {
3410
+ console.log("\nWarnings:");
3411
+ for (const warning of warnings.slice(0, 5)) console.log(`- ${warning}`);
3412
+ }
3413
+ const nextActions = Array.isArray(review.nextActions) ? review.nextActions : [];
3414
+ if (nextActions.length) {
3415
+ console.log("\nNext:");
3416
+ for (const action of nextActions) console.log(`- ${action}`);
3417
+ }
3418
+ }
3419
+ function createCampaignAgentBuildReview(status, rows, artifacts) {
3420
+ const rowList = Array.isArray(rows?.rows) ? rows.rows : [];
3421
+ const sampledRows = rowList.length;
3422
+ const availableRows = Number(rows?.count || sampledRows);
3423
+ const qualifiedRows = rowList.filter((row) => row?.qualified !== false).length;
3424
+ const operatorRows = formatCampaignRowsForOperator(rowList);
3425
+ const rowsWithEmail = operatorRows.filter((row) => Boolean(row.email)).length;
3426
+ const copyReadyRows = operatorRows.filter((row) => Boolean(row.has_copy || row.status === "copy_ready")).length;
3427
+ const artifactCount = artifacts.length || Number(status?.artifactCount || status?.artifact_count || 0);
3428
+ const buildStatus = String(status?.status || "unknown");
3429
+ const gates = [
3430
+ {
3431
+ id: "build_completed",
3432
+ label: "Build completed",
3433
+ passed: buildStatus === "completed",
3434
+ detail: buildStatus === "completed" ? "The campaign build is completed." : `The campaign build is ${buildStatus}; review again after completion.`
3435
+ },
3436
+ {
3437
+ id: "rows_available",
3438
+ label: "Rows available",
3439
+ passed: sampledRows > 0,
3440
+ detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
3441
+ },
3442
+ {
3443
+ id: "qualified_sample",
3444
+ label: "Sample rows qualified",
3445
+ passed: sampledRows > 0 && qualifiedRows === sampledRows,
3446
+ detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
3447
+ },
3448
+ {
3449
+ id: "email_coverage",
3450
+ label: "Email coverage",
3451
+ passed: sampledRows > 0 && rowsWithEmail === sampledRows,
3452
+ detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
3453
+ },
3454
+ {
3455
+ id: "artifact_available",
3456
+ label: "Artifact available",
3457
+ passed: artifactCount > 0,
3458
+ detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
3459
+ },
3460
+ {
3461
+ id: "no_failed_rows",
3462
+ label: "No failed rows",
3463
+ passed: Number(status?.recordsFailed || status?.records_failed || 0) === 0,
3464
+ detail: Number(status?.recordsFailed || status?.records_failed || 0) === 0 ? "The build reports zero failed rows." : `${status.recordsFailed || status.records_failed} row(s) failed during the build.`
3465
+ }
3466
+ ];
3467
+ const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
3468
+ const warnings = [
3469
+ rows?.hasMore || rows?.has_more ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
3470
+ sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
3471
+ ...Array.isArray(status?.warnings) ? status.warnings : []
3472
+ ].filter(Boolean);
3473
+ const readyForDeliveryApproval = blockedReasons.length === 0;
3474
+ return {
3475
+ campaignBuildId: status.campaignBuildId || status.campaign_build_id || rows.campaignBuildId || rows.campaign_build_id || "",
3476
+ status,
3477
+ rows,
3478
+ artifacts,
3479
+ gates,
3480
+ summary: {
3481
+ status: buildStatus,
3482
+ phase: status.currentPhase || status.current_phase || null,
3483
+ sampledRows,
3484
+ availableRows,
3485
+ qualifiedRows,
3486
+ rowsWithEmail,
3487
+ copyReadyRows,
3488
+ artifactCount,
3489
+ readyForDeliveryApproval,
3490
+ blockedReasons,
3491
+ warnings
3492
+ },
3493
+ nextActions: campaignAgentReviewNextActions(status, readyForDeliveryApproval)
3494
+ };
3495
+ }
3496
+ function campaignAgentReviewNextActions(status, readyForDeliveryApproval) {
3497
+ const buildId = status.campaignBuildId || status.campaign_build_id;
3498
+ const buildStatus = String(status.status || "unknown");
3499
+ if (!buildId) return [];
3500
+ if (buildStatus === "completed" && readyForDeliveryApproval) {
3501
+ return [
3502
+ `signaliz campaign-agent approve ${buildId} --destination-type json`,
3503
+ `signaliz campaign-agent artifacts ${buildId}`
3504
+ ];
3505
+ }
3506
+ if (buildStatus === "completed") {
3507
+ return [
3508
+ `signaliz campaign-agent rows ${buildId} --limit 100`,
3509
+ `signaliz campaign-agent artifacts ${buildId}`
3510
+ ];
3511
+ }
3512
+ if (buildStatus === "pending_approval") {
3513
+ return [
3514
+ `signaliz campaign-agent rows ${buildId} --limit 100`,
3515
+ `signaliz campaign-agent approve ${buildId} --destination-type json`
3516
+ ];
3517
+ }
3518
+ if ((buildStatus === "queued" || buildStatus === "running") && status.triggerRunId) {
3519
+ return [`signaliz ops run-status ${status.triggerRunId} --watch`];
3520
+ }
3521
+ return [`signaliz campaign-agent status ${buildId}`];
3522
+ }
3523
+ function printCampaignAgentRows(result) {
3524
+ if (!Array.isArray(result.rows) || result.rows.length === 0) {
3525
+ console.log("No rows found.");
3526
+ return;
3527
+ }
3528
+ console.table(result.rows.map((row) => ({
3529
+ email: row.email || "",
3530
+ name: row.name || "",
3531
+ title: row.title || "",
3532
+ company: row.company || row.domain || "",
3533
+ segment: row.segment || "",
3534
+ status: row.status || "",
3535
+ score: row.score ?? ""
3536
+ })));
3537
+ console.log(`
3538
+ Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
3539
+ if (result.nextCursor) {
3540
+ hint(`signaliz campaign-agent rows ${result.campaignBuildId} --limit ${result.pageSize || 50} --cursor ${result.nextCursor}`);
3541
+ }
3542
+ }
3260
3543
  function createCampaignAgentProofReceipt(plan, result) {
3261
3544
  const strategyMemory = record(plan.strategyMemoryStatus);
3262
3545
  const dryRunResult = record(result);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Signaliz CLI — GTM Kernel, Nango routes, MCP, and enrichment operations.",
5
5
  "bin": {
6
6
  "signaliz": "dist/bin.js"