@signaliz/sdk 1.0.11 → 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.
- package/README.md +5 -0
- package/dist/{chunk-QQW6DZQ4.mjs → chunk-XJQ6KGNQ.mjs} +123 -0
- package/dist/cli.js +177 -2
- package/dist/cli.mjs +55 -3
- package/dist/index.d.mts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +123 -0
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +123 -0
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,12 +100,16 @@ console.log(plan.mcpFlow.filter((step) =>
|
|
|
100
100
|
));
|
|
101
101
|
|
|
102
102
|
// After an approved launch, keep review and delivery in the agent surface.
|
|
103
|
+
const review = await signaliz.campaignBuilderAgent.reviewBuild('campaign_build_id', {
|
|
104
|
+
limit: 100,
|
|
105
|
+
});
|
|
103
106
|
const finalStatus = await signaliz.campaignBuilderAgent.getBuildStatus('campaign_build_id');
|
|
104
107
|
const reviewRows = await signaliz.campaignBuilderAgent.getBuildRows('campaign_build_id', {
|
|
105
108
|
limit: 100,
|
|
106
109
|
qualified: true,
|
|
107
110
|
});
|
|
108
111
|
const artifacts = await signaliz.campaignBuilderAgent.listBuildArtifacts('campaign_build_id');
|
|
112
|
+
console.log(review.summary.readyForDeliveryApproval);
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
The CLI can run the same request shape from a reusable JSON file, with flags
|
|
@@ -125,6 +129,7 @@ npx @signaliz/sdk campaign-agent plan \
|
|
|
125
129
|
--json
|
|
126
130
|
|
|
127
131
|
npx @signaliz/sdk campaign-agent status campaign_build_id --json
|
|
132
|
+
npx @signaliz/sdk campaign-agent review campaign_build_id --limit 100 --json
|
|
128
133
|
npx @signaliz/sdk campaign-agent rows campaign_build_id --limit 100 --json
|
|
129
134
|
```
|
|
130
135
|
|
|
@@ -1874,6 +1874,15 @@ var CampaignBuilderAgent = class {
|
|
|
1874
1874
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1875
1875
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1876
1876
|
}
|
|
1877
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1878
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1879
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1880
|
+
...options,
|
|
1881
|
+
limit: options.limit ?? 100
|
|
1882
|
+
});
|
|
1883
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1884
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1885
|
+
}
|
|
1877
1886
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1878
1887
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1879
1888
|
campaign_build_id: campaignBuildId
|
|
@@ -3301,6 +3310,120 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3301
3310
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3302
3311
|
};
|
|
3303
3312
|
}
|
|
3313
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3314
|
+
const sampledRows = rows.rows.length;
|
|
3315
|
+
const availableRows = rows.count || sampledRows;
|
|
3316
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3317
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3318
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3319
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3320
|
+
const gates = [
|
|
3321
|
+
{
|
|
3322
|
+
id: "build_completed",
|
|
3323
|
+
label: "Build completed",
|
|
3324
|
+
passed: status.status === "completed",
|
|
3325
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3326
|
+
},
|
|
3327
|
+
{
|
|
3328
|
+
id: "rows_available",
|
|
3329
|
+
label: "Rows available",
|
|
3330
|
+
passed: sampledRows > 0,
|
|
3331
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3332
|
+
},
|
|
3333
|
+
{
|
|
3334
|
+
id: "qualified_sample",
|
|
3335
|
+
label: "Sample rows qualified",
|
|
3336
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3337
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3338
|
+
},
|
|
3339
|
+
{
|
|
3340
|
+
id: "email_coverage",
|
|
3341
|
+
label: "Email coverage",
|
|
3342
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3343
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3344
|
+
},
|
|
3345
|
+
{
|
|
3346
|
+
id: "artifact_available",
|
|
3347
|
+
label: "Artifact available",
|
|
3348
|
+
passed: artifactCount > 0,
|
|
3349
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3350
|
+
},
|
|
3351
|
+
{
|
|
3352
|
+
id: "no_failed_rows",
|
|
3353
|
+
label: "No failed rows",
|
|
3354
|
+
passed: status.recordsFailed === 0,
|
|
3355
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3356
|
+
}
|
|
3357
|
+
];
|
|
3358
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3359
|
+
const warnings = [
|
|
3360
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3361
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3362
|
+
...status.warnings
|
|
3363
|
+
].filter((item) => Boolean(item));
|
|
3364
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3365
|
+
return {
|
|
3366
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3367
|
+
status,
|
|
3368
|
+
rows,
|
|
3369
|
+
artifacts,
|
|
3370
|
+
gates,
|
|
3371
|
+
summary: {
|
|
3372
|
+
status: status.status,
|
|
3373
|
+
phase: status.currentPhase,
|
|
3374
|
+
sampledRows,
|
|
3375
|
+
availableRows,
|
|
3376
|
+
qualifiedRows,
|
|
3377
|
+
rowsWithEmail,
|
|
3378
|
+
copyReadyRows,
|
|
3379
|
+
artifactCount,
|
|
3380
|
+
readyForDeliveryApproval,
|
|
3381
|
+
blockedReasons,
|
|
3382
|
+
warnings
|
|
3383
|
+
},
|
|
3384
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3388
|
+
const buildId = status.campaignBuildId;
|
|
3389
|
+
if (!buildId) return [];
|
|
3390
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3391
|
+
return [
|
|
3392
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3393
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3394
|
+
];
|
|
3395
|
+
}
|
|
3396
|
+
if (status.status === "completed") {
|
|
3397
|
+
return [
|
|
3398
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3399
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3400
|
+
];
|
|
3401
|
+
}
|
|
3402
|
+
if (status.status === "pending_approval") {
|
|
3403
|
+
return [
|
|
3404
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3405
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3406
|
+
];
|
|
3407
|
+
}
|
|
3408
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3409
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3410
|
+
}
|
|
3411
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3412
|
+
}
|
|
3413
|
+
function campaignReviewRowHasEmail(row) {
|
|
3414
|
+
const data = asRecord(row.data);
|
|
3415
|
+
return Boolean(
|
|
3416
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3417
|
+
);
|
|
3418
|
+
}
|
|
3419
|
+
function campaignReviewRowHasCopy(row) {
|
|
3420
|
+
const data = asRecord(row.data);
|
|
3421
|
+
const copy = asRecord(data.copy);
|
|
3422
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3423
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3424
|
+
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)
|
|
3425
|
+
);
|
|
3426
|
+
}
|
|
3304
3427
|
function diagnosticMessages2(value) {
|
|
3305
3428
|
if (!Array.isArray(value)) return [];
|
|
3306
3429
|
return value.map((item) => {
|
package/dist/cli.js
CHANGED
|
@@ -1880,6 +1880,15 @@ var CampaignBuilderAgent = class {
|
|
|
1880
1880
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1881
1881
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1882
1882
|
}
|
|
1883
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1884
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1885
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1886
|
+
...options,
|
|
1887
|
+
limit: options.limit ?? 100
|
|
1888
|
+
});
|
|
1889
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1890
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1891
|
+
}
|
|
1883
1892
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1884
1893
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1885
1894
|
campaign_build_id: campaignBuildId
|
|
@@ -3307,6 +3316,120 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3307
3316
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3308
3317
|
};
|
|
3309
3318
|
}
|
|
3319
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3320
|
+
const sampledRows = rows.rows.length;
|
|
3321
|
+
const availableRows = rows.count || sampledRows;
|
|
3322
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3323
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3324
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3325
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3326
|
+
const gates = [
|
|
3327
|
+
{
|
|
3328
|
+
id: "build_completed",
|
|
3329
|
+
label: "Build completed",
|
|
3330
|
+
passed: status.status === "completed",
|
|
3331
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3332
|
+
},
|
|
3333
|
+
{
|
|
3334
|
+
id: "rows_available",
|
|
3335
|
+
label: "Rows available",
|
|
3336
|
+
passed: sampledRows > 0,
|
|
3337
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3338
|
+
},
|
|
3339
|
+
{
|
|
3340
|
+
id: "qualified_sample",
|
|
3341
|
+
label: "Sample rows qualified",
|
|
3342
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3343
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3344
|
+
},
|
|
3345
|
+
{
|
|
3346
|
+
id: "email_coverage",
|
|
3347
|
+
label: "Email coverage",
|
|
3348
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3349
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3350
|
+
},
|
|
3351
|
+
{
|
|
3352
|
+
id: "artifact_available",
|
|
3353
|
+
label: "Artifact available",
|
|
3354
|
+
passed: artifactCount > 0,
|
|
3355
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3356
|
+
},
|
|
3357
|
+
{
|
|
3358
|
+
id: "no_failed_rows",
|
|
3359
|
+
label: "No failed rows",
|
|
3360
|
+
passed: status.recordsFailed === 0,
|
|
3361
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3362
|
+
}
|
|
3363
|
+
];
|
|
3364
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3365
|
+
const warnings = [
|
|
3366
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3367
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3368
|
+
...status.warnings
|
|
3369
|
+
].filter((item) => Boolean(item));
|
|
3370
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3371
|
+
return {
|
|
3372
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3373
|
+
status,
|
|
3374
|
+
rows,
|
|
3375
|
+
artifacts,
|
|
3376
|
+
gates,
|
|
3377
|
+
summary: {
|
|
3378
|
+
status: status.status,
|
|
3379
|
+
phase: status.currentPhase,
|
|
3380
|
+
sampledRows,
|
|
3381
|
+
availableRows,
|
|
3382
|
+
qualifiedRows,
|
|
3383
|
+
rowsWithEmail,
|
|
3384
|
+
copyReadyRows,
|
|
3385
|
+
artifactCount,
|
|
3386
|
+
readyForDeliveryApproval,
|
|
3387
|
+
blockedReasons,
|
|
3388
|
+
warnings
|
|
3389
|
+
},
|
|
3390
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3393
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3394
|
+
const buildId = status.campaignBuildId;
|
|
3395
|
+
if (!buildId) return [];
|
|
3396
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3397
|
+
return [
|
|
3398
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3399
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3400
|
+
];
|
|
3401
|
+
}
|
|
3402
|
+
if (status.status === "completed") {
|
|
3403
|
+
return [
|
|
3404
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3405
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3406
|
+
];
|
|
3407
|
+
}
|
|
3408
|
+
if (status.status === "pending_approval") {
|
|
3409
|
+
return [
|
|
3410
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3411
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3412
|
+
];
|
|
3413
|
+
}
|
|
3414
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3415
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3416
|
+
}
|
|
3417
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3418
|
+
}
|
|
3419
|
+
function campaignReviewRowHasEmail(row) {
|
|
3420
|
+
const data = asRecord(row.data);
|
|
3421
|
+
return Boolean(
|
|
3422
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3423
|
+
);
|
|
3424
|
+
}
|
|
3425
|
+
function campaignReviewRowHasCopy(row) {
|
|
3426
|
+
const data = asRecord(row.data);
|
|
3427
|
+
const copy = asRecord(data.copy);
|
|
3428
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3429
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3430
|
+
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
|
+
);
|
|
3432
|
+
}
|
|
3310
3433
|
function diagnosticMessages2(value) {
|
|
3311
3434
|
if (!Array.isArray(value)) return [];
|
|
3312
3435
|
return value.map((item) => {
|
|
@@ -6680,7 +6803,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6680
6803
|
}
|
|
6681
6804
|
return;
|
|
6682
6805
|
}
|
|
6683
|
-
if (["status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
|
|
6806
|
+
if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
|
|
6684
6807
|
await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
|
|
6685
6808
|
return;
|
|
6686
6809
|
}
|
|
@@ -6787,6 +6910,28 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
|
|
|
6787
6910
|
const flags = parseFlags(argv);
|
|
6788
6911
|
const buildId = argv[0] && !argv[0].startsWith("--") ? argv[0] : stringFlag(flags, "campaign-build-id", "build-id");
|
|
6789
6912
|
if (!buildId) throw new Error(`campaign-agent ${subcommand} requires <campaign_build_id> or --campaign-build-id`);
|
|
6913
|
+
if (subcommand === "review") {
|
|
6914
|
+
const review = await signaliz.campaignBuilderAgent.reviewBuild(buildId, {
|
|
6915
|
+
limit: numberFlag(flags, "limit") ?? 100,
|
|
6916
|
+
cursor: stringFlag(flags, "cursor"),
|
|
6917
|
+
segment: stringFlag(flags, "segment"),
|
|
6918
|
+
rowStatus: stringFlag(flags, "row-status"),
|
|
6919
|
+
qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
|
|
6920
|
+
});
|
|
6921
|
+
const operatorReview = {
|
|
6922
|
+
...review,
|
|
6923
|
+
rows: {
|
|
6924
|
+
...review.rows,
|
|
6925
|
+
rows: formatCampaignAgentRows(review.rows.rows)
|
|
6926
|
+
}
|
|
6927
|
+
};
|
|
6928
|
+
if (booleanFlag(flags, "json")) {
|
|
6929
|
+
printJson(operatorReview);
|
|
6930
|
+
} else {
|
|
6931
|
+
printCampaignAgentBuildReview(operatorReview);
|
|
6932
|
+
}
|
|
6933
|
+
return;
|
|
6934
|
+
}
|
|
6790
6935
|
if (subcommand === "status") {
|
|
6791
6936
|
const status = await signaliz.campaignBuilderAgent.getBuildStatus(buildId);
|
|
6792
6937
|
if (booleanFlag(flags, "json")) {
|
|
@@ -7201,6 +7346,34 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
7201
7346
|
console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
7202
7347
|
}
|
|
7203
7348
|
}
|
|
7349
|
+
function printCampaignAgentBuildReview(review) {
|
|
7350
|
+
const summary = asRecord4(review.summary);
|
|
7351
|
+
console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
|
|
7352
|
+
console.log(`Status: ${summary.status || review.status?.status}`);
|
|
7353
|
+
console.log(`Phase: ${summary.phase || review.status?.currentPhase || "N/A"}`);
|
|
7354
|
+
console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
|
|
7355
|
+
console.log(`Qualified: ${summary.qualifiedRows || 0}`);
|
|
7356
|
+
console.log(`Emails: ${summary.rowsWithEmail || 0}`);
|
|
7357
|
+
console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
|
|
7358
|
+
console.log(`Artifacts: ${summary.artifactCount || 0}`);
|
|
7359
|
+
console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
|
|
7360
|
+
if (Array.isArray(review.gates) && review.gates.length > 0) {
|
|
7361
|
+
console.log("\nGates:");
|
|
7362
|
+
for (const gate of review.gates) {
|
|
7363
|
+
console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
|
|
7364
|
+
}
|
|
7365
|
+
}
|
|
7366
|
+
const warnings = Array.isArray(summary.warnings) ? summary.warnings : [];
|
|
7367
|
+
if (warnings.length > 0) {
|
|
7368
|
+
console.log("\nWarnings:");
|
|
7369
|
+
for (const warning of warnings.slice(0, 5)) console.log(`- ${warning}`);
|
|
7370
|
+
}
|
|
7371
|
+
const nextActions = Array.isArray(review.nextActions) ? review.nextActions : [];
|
|
7372
|
+
if (nextActions.length > 0) {
|
|
7373
|
+
console.log("\nNext:");
|
|
7374
|
+
for (const action of nextActions) console.log(`- ${action}`);
|
|
7375
|
+
}
|
|
7376
|
+
}
|
|
7204
7377
|
function formatCampaignAgentRows(rows) {
|
|
7205
7378
|
return rows.map((row) => {
|
|
7206
7379
|
const data = asRecord4(row.data);
|
|
@@ -7410,6 +7583,7 @@ Usage:
|
|
|
7410
7583
|
signaliz campaign-agent dry-run --goal "Build a strategy-template campaign..." --target-count 500 --use-local-leads --json
|
|
7411
7584
|
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign..." --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500
|
|
7412
7585
|
signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500 --wait --approve-delivery --delivery-destination-type json
|
|
7586
|
+
signaliz campaign-agent review <campaign_build_id> --limit 100 --json
|
|
7413
7587
|
signaliz campaign-agent status <campaign_build_id> --json
|
|
7414
7588
|
signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
|
|
7415
7589
|
|
|
@@ -7443,12 +7617,13 @@ Signaliz campaign-agent commands:
|
|
|
7443
7617
|
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
7444
7618
|
signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
|
|
7445
7619
|
signaliz campaign-agent build-approved (--goal TEXT | --request-file FILE) --confirm-launch --approved-by EMAIL (--approve-all | --approved-types a,b) [--commit-before-launch] [--spend-limit N] [--approved-route-ids a,b] [--wait] [--approve-delivery] [--delivery-destination-type json|csv|webhook] [--idempotency-key KEY] [--json]
|
|
7620
|
+
signaliz campaign-agent review <campaign_build_id> [--limit N] [--qualified|--disqualified] [--json]
|
|
7446
7621
|
signaliz campaign-agent status <campaign_build_id> [--json]
|
|
7447
7622
|
signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--json]
|
|
7448
7623
|
signaliz campaign-agent artifacts <campaign_build_id> [--json]
|
|
7449
7624
|
signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
|
|
7450
7625
|
|
|
7451
|
-
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 status, rows,
|
|
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.
|
|
7452
7627
|
`);
|
|
7453
7628
|
}
|
|
7454
7629
|
main().catch((e) => {
|
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Signaliz,
|
|
4
4
|
createCampaignBuilderAgentRequestTemplate,
|
|
5
5
|
createCampaignBuilderApproval
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XJQ6KGNQ.mjs";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { readFileSync, writeFileSync } from "fs";
|
|
@@ -379,7 +379,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
379
379
|
}
|
|
380
380
|
return;
|
|
381
381
|
}
|
|
382
|
-
if (["status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
|
|
382
|
+
if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
|
|
383
383
|
await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
@@ -486,6 +486,28 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
|
|
|
486
486
|
const flags = parseFlags(argv);
|
|
487
487
|
const buildId = argv[0] && !argv[0].startsWith("--") ? argv[0] : stringFlag(flags, "campaign-build-id", "build-id");
|
|
488
488
|
if (!buildId) throw new Error(`campaign-agent ${subcommand} requires <campaign_build_id> or --campaign-build-id`);
|
|
489
|
+
if (subcommand === "review") {
|
|
490
|
+
const review = await signaliz.campaignBuilderAgent.reviewBuild(buildId, {
|
|
491
|
+
limit: numberFlag(flags, "limit") ?? 100,
|
|
492
|
+
cursor: stringFlag(flags, "cursor"),
|
|
493
|
+
segment: stringFlag(flags, "segment"),
|
|
494
|
+
rowStatus: stringFlag(flags, "row-status"),
|
|
495
|
+
qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
|
|
496
|
+
});
|
|
497
|
+
const operatorReview = {
|
|
498
|
+
...review,
|
|
499
|
+
rows: {
|
|
500
|
+
...review.rows,
|
|
501
|
+
rows: formatCampaignAgentRows(review.rows.rows)
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
if (booleanFlag(flags, "json")) {
|
|
505
|
+
printJson(operatorReview);
|
|
506
|
+
} else {
|
|
507
|
+
printCampaignAgentBuildReview(operatorReview);
|
|
508
|
+
}
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
489
511
|
if (subcommand === "status") {
|
|
490
512
|
const status = await signaliz.campaignBuilderAgent.getBuildStatus(buildId);
|
|
491
513
|
if (booleanFlag(flags, "json")) {
|
|
@@ -900,6 +922,34 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
900
922
|
console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
901
923
|
}
|
|
902
924
|
}
|
|
925
|
+
function printCampaignAgentBuildReview(review) {
|
|
926
|
+
const summary = asRecord(review.summary);
|
|
927
|
+
console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
|
|
928
|
+
console.log(`Status: ${summary.status || review.status?.status}`);
|
|
929
|
+
console.log(`Phase: ${summary.phase || review.status?.currentPhase || "N/A"}`);
|
|
930
|
+
console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
|
|
931
|
+
console.log(`Qualified: ${summary.qualifiedRows || 0}`);
|
|
932
|
+
console.log(`Emails: ${summary.rowsWithEmail || 0}`);
|
|
933
|
+
console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
|
|
934
|
+
console.log(`Artifacts: ${summary.artifactCount || 0}`);
|
|
935
|
+
console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
|
|
936
|
+
if (Array.isArray(review.gates) && review.gates.length > 0) {
|
|
937
|
+
console.log("\nGates:");
|
|
938
|
+
for (const gate of review.gates) {
|
|
939
|
+
console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
const warnings = Array.isArray(summary.warnings) ? summary.warnings : [];
|
|
943
|
+
if (warnings.length > 0) {
|
|
944
|
+
console.log("\nWarnings:");
|
|
945
|
+
for (const warning of warnings.slice(0, 5)) console.log(`- ${warning}`);
|
|
946
|
+
}
|
|
947
|
+
const nextActions = Array.isArray(review.nextActions) ? review.nextActions : [];
|
|
948
|
+
if (nextActions.length > 0) {
|
|
949
|
+
console.log("\nNext:");
|
|
950
|
+
for (const action of nextActions) console.log(`- ${action}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
903
953
|
function formatCampaignAgentRows(rows) {
|
|
904
954
|
return rows.map((row) => {
|
|
905
955
|
const data = asRecord(row.data);
|
|
@@ -1109,6 +1159,7 @@ Usage:
|
|
|
1109
1159
|
signaliz campaign-agent dry-run --goal "Build a strategy-template campaign..." --target-count 500 --use-local-leads --json
|
|
1110
1160
|
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign..." --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500
|
|
1111
1161
|
signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500 --wait --approve-delivery --delivery-destination-type json
|
|
1162
|
+
signaliz campaign-agent review <campaign_build_id> --limit 100 --json
|
|
1112
1163
|
signaliz campaign-agent status <campaign_build_id> --json
|
|
1113
1164
|
signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
|
|
1114
1165
|
|
|
@@ -1142,12 +1193,13 @@ Signaliz campaign-agent commands:
|
|
|
1142
1193
|
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
1143
1194
|
signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
|
|
1144
1195
|
signaliz campaign-agent build-approved (--goal TEXT | --request-file FILE) --confirm-launch --approved-by EMAIL (--approve-all | --approved-types a,b) [--commit-before-launch] [--spend-limit N] [--approved-route-ids a,b] [--wait] [--approve-delivery] [--delivery-destination-type json|csv|webhook] [--idempotency-key KEY] [--json]
|
|
1196
|
+
signaliz campaign-agent review <campaign_build_id> [--limit N] [--qualified|--disqualified] [--json]
|
|
1145
1197
|
signaliz campaign-agent status <campaign_build_id> [--json]
|
|
1146
1198
|
signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--json]
|
|
1147
1199
|
signaliz campaign-agent artifacts <campaign_build_id> [--json]
|
|
1148
1200
|
signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
|
|
1149
1201
|
|
|
1150
|
-
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 status, rows,
|
|
1202
|
+
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.
|
|
1151
1203
|
`);
|
|
1152
1204
|
}
|
|
1153
1205
|
main().catch((e) => {
|
package/dist/index.d.mts
CHANGED
|
@@ -1094,6 +1094,38 @@ interface CampaignBuilderApprovedRunResult {
|
|
|
1094
1094
|
finalStatus?: CampaignBuildStatus;
|
|
1095
1095
|
deliveryApproval?: ApproveDeliveryResult;
|
|
1096
1096
|
}
|
|
1097
|
+
interface CampaignBuilderBuildReviewOptions extends CampaignRowsOptions {
|
|
1098
|
+
/** Number of rows to sample for review. Defaults to 100. */
|
|
1099
|
+
limit?: number;
|
|
1100
|
+
}
|
|
1101
|
+
interface CampaignBuilderBuildReviewGate {
|
|
1102
|
+
id: string;
|
|
1103
|
+
label: string;
|
|
1104
|
+
passed: boolean;
|
|
1105
|
+
detail: string;
|
|
1106
|
+
}
|
|
1107
|
+
interface CampaignBuilderBuildReviewSummary {
|
|
1108
|
+
status: string;
|
|
1109
|
+
phase: string | null;
|
|
1110
|
+
sampledRows: number;
|
|
1111
|
+
availableRows: number;
|
|
1112
|
+
qualifiedRows: number;
|
|
1113
|
+
rowsWithEmail: number;
|
|
1114
|
+
copyReadyRows: number;
|
|
1115
|
+
artifactCount: number;
|
|
1116
|
+
readyForDeliveryApproval: boolean;
|
|
1117
|
+
blockedReasons: string[];
|
|
1118
|
+
warnings: string[];
|
|
1119
|
+
}
|
|
1120
|
+
interface CampaignBuilderBuildReview {
|
|
1121
|
+
campaignBuildId: string;
|
|
1122
|
+
status: CampaignBuildStatus;
|
|
1123
|
+
rows: CampaignRowsResult;
|
|
1124
|
+
artifacts: CampaignArtifact[];
|
|
1125
|
+
gates: CampaignBuilderBuildReviewGate[];
|
|
1126
|
+
summary: CampaignBuilderBuildReviewSummary;
|
|
1127
|
+
nextActions: string[];
|
|
1128
|
+
}
|
|
1097
1129
|
declare const DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS: Required<Pick<SignalizCampaignBuilderDefaults, 'requireVerifiedEmail' | 'dedupKeys' | 'allowDownscale'>> & SignalizCampaignBuilderDefaults;
|
|
1098
1130
|
declare const DEFAULT_CAMPAIGN_BUILDER_BUILT_INS: CampaignBuilderBuiltInTool[];
|
|
1099
1131
|
declare const DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES: CampaignBuilderApprovalType[];
|
|
@@ -1114,6 +1146,7 @@ declare class CampaignBuilderAgent {
|
|
|
1114
1146
|
destinationId?: string;
|
|
1115
1147
|
destinationConfig?: UnknownRecord$1;
|
|
1116
1148
|
}): Promise<ApproveDeliveryResult>;
|
|
1149
|
+
reviewBuild(campaignBuildId: string, options?: CampaignBuilderBuildReviewOptions): Promise<CampaignBuilderBuildReview>;
|
|
1117
1150
|
private getCampaignBuildStatus;
|
|
1118
1151
|
private waitForCampaignBuildStatus;
|
|
1119
1152
|
private approveCampaignDelivery;
|
package/dist/index.d.ts
CHANGED
|
@@ -1094,6 +1094,38 @@ interface CampaignBuilderApprovedRunResult {
|
|
|
1094
1094
|
finalStatus?: CampaignBuildStatus;
|
|
1095
1095
|
deliveryApproval?: ApproveDeliveryResult;
|
|
1096
1096
|
}
|
|
1097
|
+
interface CampaignBuilderBuildReviewOptions extends CampaignRowsOptions {
|
|
1098
|
+
/** Number of rows to sample for review. Defaults to 100. */
|
|
1099
|
+
limit?: number;
|
|
1100
|
+
}
|
|
1101
|
+
interface CampaignBuilderBuildReviewGate {
|
|
1102
|
+
id: string;
|
|
1103
|
+
label: string;
|
|
1104
|
+
passed: boolean;
|
|
1105
|
+
detail: string;
|
|
1106
|
+
}
|
|
1107
|
+
interface CampaignBuilderBuildReviewSummary {
|
|
1108
|
+
status: string;
|
|
1109
|
+
phase: string | null;
|
|
1110
|
+
sampledRows: number;
|
|
1111
|
+
availableRows: number;
|
|
1112
|
+
qualifiedRows: number;
|
|
1113
|
+
rowsWithEmail: number;
|
|
1114
|
+
copyReadyRows: number;
|
|
1115
|
+
artifactCount: number;
|
|
1116
|
+
readyForDeliveryApproval: boolean;
|
|
1117
|
+
blockedReasons: string[];
|
|
1118
|
+
warnings: string[];
|
|
1119
|
+
}
|
|
1120
|
+
interface CampaignBuilderBuildReview {
|
|
1121
|
+
campaignBuildId: string;
|
|
1122
|
+
status: CampaignBuildStatus;
|
|
1123
|
+
rows: CampaignRowsResult;
|
|
1124
|
+
artifacts: CampaignArtifact[];
|
|
1125
|
+
gates: CampaignBuilderBuildReviewGate[];
|
|
1126
|
+
summary: CampaignBuilderBuildReviewSummary;
|
|
1127
|
+
nextActions: string[];
|
|
1128
|
+
}
|
|
1097
1129
|
declare const DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS: Required<Pick<SignalizCampaignBuilderDefaults, 'requireVerifiedEmail' | 'dedupKeys' | 'allowDownscale'>> & SignalizCampaignBuilderDefaults;
|
|
1098
1130
|
declare const DEFAULT_CAMPAIGN_BUILDER_BUILT_INS: CampaignBuilderBuiltInTool[];
|
|
1099
1131
|
declare const DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES: CampaignBuilderApprovalType[];
|
|
@@ -1114,6 +1146,7 @@ declare class CampaignBuilderAgent {
|
|
|
1114
1146
|
destinationId?: string;
|
|
1115
1147
|
destinationConfig?: UnknownRecord$1;
|
|
1116
1148
|
}): Promise<ApproveDeliveryResult>;
|
|
1149
|
+
reviewBuild(campaignBuildId: string, options?: CampaignBuilderBuildReviewOptions): Promise<CampaignBuilderBuildReview>;
|
|
1117
1150
|
private getCampaignBuildStatus;
|
|
1118
1151
|
private waitForCampaignBuildStatus;
|
|
1119
1152
|
private approveCampaignDelivery;
|
package/dist/index.js
CHANGED
|
@@ -1923,6 +1923,15 @@ var CampaignBuilderAgent = class {
|
|
|
1923
1923
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1924
1924
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1925
1925
|
}
|
|
1926
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1927
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1928
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1929
|
+
...options,
|
|
1930
|
+
limit: options.limit ?? 100
|
|
1931
|
+
});
|
|
1932
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1933
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1934
|
+
}
|
|
1926
1935
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1927
1936
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1928
1937
|
campaign_build_id: campaignBuildId
|
|
@@ -3350,6 +3359,120 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3350
3359
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3351
3360
|
};
|
|
3352
3361
|
}
|
|
3362
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3363
|
+
const sampledRows = rows.rows.length;
|
|
3364
|
+
const availableRows = rows.count || sampledRows;
|
|
3365
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3366
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3367
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3368
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3369
|
+
const gates = [
|
|
3370
|
+
{
|
|
3371
|
+
id: "build_completed",
|
|
3372
|
+
label: "Build completed",
|
|
3373
|
+
passed: status.status === "completed",
|
|
3374
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3375
|
+
},
|
|
3376
|
+
{
|
|
3377
|
+
id: "rows_available",
|
|
3378
|
+
label: "Rows available",
|
|
3379
|
+
passed: sampledRows > 0,
|
|
3380
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3381
|
+
},
|
|
3382
|
+
{
|
|
3383
|
+
id: "qualified_sample",
|
|
3384
|
+
label: "Sample rows qualified",
|
|
3385
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3386
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3387
|
+
},
|
|
3388
|
+
{
|
|
3389
|
+
id: "email_coverage",
|
|
3390
|
+
label: "Email coverage",
|
|
3391
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3392
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3393
|
+
},
|
|
3394
|
+
{
|
|
3395
|
+
id: "artifact_available",
|
|
3396
|
+
label: "Artifact available",
|
|
3397
|
+
passed: artifactCount > 0,
|
|
3398
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3399
|
+
},
|
|
3400
|
+
{
|
|
3401
|
+
id: "no_failed_rows",
|
|
3402
|
+
label: "No failed rows",
|
|
3403
|
+
passed: status.recordsFailed === 0,
|
|
3404
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3405
|
+
}
|
|
3406
|
+
];
|
|
3407
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3408
|
+
const warnings = [
|
|
3409
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3410
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3411
|
+
...status.warnings
|
|
3412
|
+
].filter((item) => Boolean(item));
|
|
3413
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3414
|
+
return {
|
|
3415
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3416
|
+
status,
|
|
3417
|
+
rows,
|
|
3418
|
+
artifacts,
|
|
3419
|
+
gates,
|
|
3420
|
+
summary: {
|
|
3421
|
+
status: status.status,
|
|
3422
|
+
phase: status.currentPhase,
|
|
3423
|
+
sampledRows,
|
|
3424
|
+
availableRows,
|
|
3425
|
+
qualifiedRows,
|
|
3426
|
+
rowsWithEmail,
|
|
3427
|
+
copyReadyRows,
|
|
3428
|
+
artifactCount,
|
|
3429
|
+
readyForDeliveryApproval,
|
|
3430
|
+
blockedReasons,
|
|
3431
|
+
warnings
|
|
3432
|
+
},
|
|
3433
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3437
|
+
const buildId = status.campaignBuildId;
|
|
3438
|
+
if (!buildId) return [];
|
|
3439
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3440
|
+
return [
|
|
3441
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3442
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3443
|
+
];
|
|
3444
|
+
}
|
|
3445
|
+
if (status.status === "completed") {
|
|
3446
|
+
return [
|
|
3447
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3448
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3449
|
+
];
|
|
3450
|
+
}
|
|
3451
|
+
if (status.status === "pending_approval") {
|
|
3452
|
+
return [
|
|
3453
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3454
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3455
|
+
];
|
|
3456
|
+
}
|
|
3457
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3458
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3459
|
+
}
|
|
3460
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3461
|
+
}
|
|
3462
|
+
function campaignReviewRowHasEmail(row) {
|
|
3463
|
+
const data = asRecord(row.data);
|
|
3464
|
+
return Boolean(
|
|
3465
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3468
|
+
function campaignReviewRowHasCopy(row) {
|
|
3469
|
+
const data = asRecord(row.data);
|
|
3470
|
+
const copy = asRecord(data.copy);
|
|
3471
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3472
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3473
|
+
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)
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
3353
3476
|
function diagnosticMessages2(value) {
|
|
3354
3477
|
if (!Array.isArray(value)) return [];
|
|
3355
3478
|
return value.map((item) => {
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -1897,6 +1897,15 @@ var CampaignBuilderAgent = class {
|
|
|
1897
1897
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1898
1898
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1899
1899
|
}
|
|
1900
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1901
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1902
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1903
|
+
...options,
|
|
1904
|
+
limit: options.limit ?? 100
|
|
1905
|
+
});
|
|
1906
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1907
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1908
|
+
}
|
|
1900
1909
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1901
1910
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1902
1911
|
campaign_build_id: campaignBuildId
|
|
@@ -3223,6 +3232,120 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3223
3232
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3224
3233
|
};
|
|
3225
3234
|
}
|
|
3235
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3236
|
+
const sampledRows = rows.rows.length;
|
|
3237
|
+
const availableRows = rows.count || sampledRows;
|
|
3238
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3239
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3240
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3241
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3242
|
+
const gates = [
|
|
3243
|
+
{
|
|
3244
|
+
id: "build_completed",
|
|
3245
|
+
label: "Build completed",
|
|
3246
|
+
passed: status.status === "completed",
|
|
3247
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3248
|
+
},
|
|
3249
|
+
{
|
|
3250
|
+
id: "rows_available",
|
|
3251
|
+
label: "Rows available",
|
|
3252
|
+
passed: sampledRows > 0,
|
|
3253
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3254
|
+
},
|
|
3255
|
+
{
|
|
3256
|
+
id: "qualified_sample",
|
|
3257
|
+
label: "Sample rows qualified",
|
|
3258
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3259
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3260
|
+
},
|
|
3261
|
+
{
|
|
3262
|
+
id: "email_coverage",
|
|
3263
|
+
label: "Email coverage",
|
|
3264
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3265
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3266
|
+
},
|
|
3267
|
+
{
|
|
3268
|
+
id: "artifact_available",
|
|
3269
|
+
label: "Artifact available",
|
|
3270
|
+
passed: artifactCount > 0,
|
|
3271
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3272
|
+
},
|
|
3273
|
+
{
|
|
3274
|
+
id: "no_failed_rows",
|
|
3275
|
+
label: "No failed rows",
|
|
3276
|
+
passed: status.recordsFailed === 0,
|
|
3277
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3278
|
+
}
|
|
3279
|
+
];
|
|
3280
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3281
|
+
const warnings = [
|
|
3282
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3283
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3284
|
+
...status.warnings
|
|
3285
|
+
].filter((item) => Boolean(item));
|
|
3286
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3287
|
+
return {
|
|
3288
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3289
|
+
status,
|
|
3290
|
+
rows,
|
|
3291
|
+
artifacts,
|
|
3292
|
+
gates,
|
|
3293
|
+
summary: {
|
|
3294
|
+
status: status.status,
|
|
3295
|
+
phase: status.currentPhase,
|
|
3296
|
+
sampledRows,
|
|
3297
|
+
availableRows,
|
|
3298
|
+
qualifiedRows,
|
|
3299
|
+
rowsWithEmail,
|
|
3300
|
+
copyReadyRows,
|
|
3301
|
+
artifactCount,
|
|
3302
|
+
readyForDeliveryApproval,
|
|
3303
|
+
blockedReasons,
|
|
3304
|
+
warnings
|
|
3305
|
+
},
|
|
3306
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3310
|
+
const buildId = status.campaignBuildId;
|
|
3311
|
+
if (!buildId) return [];
|
|
3312
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3313
|
+
return [
|
|
3314
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3315
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3316
|
+
];
|
|
3317
|
+
}
|
|
3318
|
+
if (status.status === "completed") {
|
|
3319
|
+
return [
|
|
3320
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3321
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3322
|
+
];
|
|
3323
|
+
}
|
|
3324
|
+
if (status.status === "pending_approval") {
|
|
3325
|
+
return [
|
|
3326
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3327
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3328
|
+
];
|
|
3329
|
+
}
|
|
3330
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3331
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3332
|
+
}
|
|
3333
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3334
|
+
}
|
|
3335
|
+
function campaignReviewRowHasEmail(row) {
|
|
3336
|
+
const data = asRecord(row.data);
|
|
3337
|
+
return Boolean(
|
|
3338
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3339
|
+
);
|
|
3340
|
+
}
|
|
3341
|
+
function campaignReviewRowHasCopy(row) {
|
|
3342
|
+
const data = asRecord(row.data);
|
|
3343
|
+
const copy = asRecord(data.copy);
|
|
3344
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3345
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3346
|
+
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)
|
|
3347
|
+
);
|
|
3348
|
+
}
|
|
3226
3349
|
function diagnosticMessages2(value) {
|
|
3227
3350
|
if (!Array.isArray(value)) return [];
|
|
3228
3351
|
return value.map((item) => {
|
package/dist/mcp-config.mjs
CHANGED