@signaliz/sdk 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.
- package/README.md +16 -0
- package/dist/{chunk-2EXN3RAX.mjs → chunk-XJQ6KGNQ.mjs} +184 -0
- package/dist/cli.js +362 -1
- package/dist/cli.mjs +179 -2
- package/dist/index.d.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +184 -0
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +184 -0
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,18 @@ console.log(plan.strategyMemoryStatus?.ready);
|
|
|
98
98
|
console.log(plan.mcpFlow.filter((step) =>
|
|
99
99
|
['gtm_provider_recipe_prepare', 'gtm_provider_route_activate'].includes(step.tool)
|
|
100
100
|
));
|
|
101
|
+
|
|
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
|
+
});
|
|
106
|
+
const finalStatus = await signaliz.campaignBuilderAgent.getBuildStatus('campaign_build_id');
|
|
107
|
+
const reviewRows = await signaliz.campaignBuilderAgent.getBuildRows('campaign_build_id', {
|
|
108
|
+
limit: 100,
|
|
109
|
+
qualified: true,
|
|
110
|
+
});
|
|
111
|
+
const artifacts = await signaliz.campaignBuilderAgent.listBuildArtifacts('campaign_build_id');
|
|
112
|
+
console.log(review.summary.readyForDeliveryApproval);
|
|
101
113
|
```
|
|
102
114
|
|
|
103
115
|
The CLI can run the same request shape from a reusable JSON file, with flags
|
|
@@ -115,6 +127,10 @@ npx @signaliz/sdk campaign-agent plan \
|
|
|
115
127
|
--request-file campaign-request.json \
|
|
116
128
|
--target-count 250 \
|
|
117
129
|
--json
|
|
130
|
+
|
|
131
|
+
npx @signaliz/sdk campaign-agent status campaign_build_id --json
|
|
132
|
+
npx @signaliz/sdk campaign-agent review campaign_build_id --limit 100 --json
|
|
133
|
+
npx @signaliz/sdk campaign-agent rows campaign_build_id --limit 100 --json
|
|
118
134
|
```
|
|
119
135
|
|
|
120
136
|
Use the hosted MCP campaign-agent planner when you want Signaliz to return the
|
|
@@ -1847,6 +1847,42 @@ var CampaignBuilderAgent = class {
|
|
|
1847
1847
|
}
|
|
1848
1848
|
return result;
|
|
1849
1849
|
}
|
|
1850
|
+
async getBuildStatus(campaignBuildId) {
|
|
1851
|
+
return this.getCampaignBuildStatus(campaignBuildId);
|
|
1852
|
+
}
|
|
1853
|
+
async getBuildRows(campaignBuildId, options = {}) {
|
|
1854
|
+
const filters = compact({
|
|
1855
|
+
segment: options.segment,
|
|
1856
|
+
qualified: options.qualified,
|
|
1857
|
+
row_status: options.rowStatus
|
|
1858
|
+
});
|
|
1859
|
+
const args = compact({
|
|
1860
|
+
campaign_build_id: campaignBuildId,
|
|
1861
|
+
page_size: options.limit,
|
|
1862
|
+
cursor: options.cursor
|
|
1863
|
+
});
|
|
1864
|
+
if (Object.keys(filters).length > 0) args.filters = filters;
|
|
1865
|
+
const data = await this.callMcp("get_campaign_build_rows", args);
|
|
1866
|
+
return mapAgentCampaignRowsResult(data);
|
|
1867
|
+
}
|
|
1868
|
+
async listBuildArtifacts(campaignBuildId) {
|
|
1869
|
+
const data = await this.callMcp("list_campaign_build_artifacts", {
|
|
1870
|
+
campaign_build_id: campaignBuildId
|
|
1871
|
+
});
|
|
1872
|
+
return Array.isArray(data.artifacts) ? data.artifacts.map(mapAgentCampaignArtifact) : [];
|
|
1873
|
+
}
|
|
1874
|
+
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1875
|
+
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
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
|
+
}
|
|
1850
1886
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1851
1887
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1852
1888
|
campaign_build_id: campaignBuildId
|
|
@@ -3240,6 +3276,154 @@ function mapAgentCampaignBuildStatus(data) {
|
|
|
3240
3276
|
completedAt: stringValue(data.completed_at) ?? null
|
|
3241
3277
|
};
|
|
3242
3278
|
}
|
|
3279
|
+
function mapAgentCampaignRowsResult(data) {
|
|
3280
|
+
const rows = Array.isArray(data.rows) ? data.rows : [];
|
|
3281
|
+
return {
|
|
3282
|
+
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
3283
|
+
rows: rows.map((row, index) => {
|
|
3284
|
+
const record = asRecord(row);
|
|
3285
|
+
return {
|
|
3286
|
+
index: numberOrUndefined2(record.index) ?? index,
|
|
3287
|
+
status: stringValue(record.status) ?? stringValue(record.row_status) ?? "unknown",
|
|
3288
|
+
qualified: record.qualified !== false,
|
|
3289
|
+
segment: stringValue(record.segment) ?? null,
|
|
3290
|
+
data: nullableRecord(record.data) ?? record
|
|
3291
|
+
};
|
|
3292
|
+
}),
|
|
3293
|
+
count: numberOrUndefined2(data.count) ?? rows.length,
|
|
3294
|
+
pageSize: numberOrUndefined2(data.page_size) ?? rows.length,
|
|
3295
|
+
nextCursor: stringValue(data.next_cursor) ?? null,
|
|
3296
|
+
hasMore: data.has_more === true
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
function mapAgentCampaignArtifact(data) {
|
|
3300
|
+
return {
|
|
3301
|
+
id: stringValue(data.id) ?? "",
|
|
3302
|
+
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
3303
|
+
artifactType: stringValue(data.artifact_type) ?? "",
|
|
3304
|
+
destination: stringValue(data.destination) ?? "",
|
|
3305
|
+
storagePath: stringValue(data.storage_path) ?? "",
|
|
3306
|
+
signedUrl: stringValue(data.signed_url) ?? null,
|
|
3307
|
+
rowCount: numberOrUndefined2(data.row_count) ?? 0,
|
|
3308
|
+
checksum: stringValue(data.checksum) ?? null,
|
|
3309
|
+
metadata: nullableRecord(data.metadata) ?? {},
|
|
3310
|
+
createdAt: stringValue(data.created_at) ?? ""
|
|
3311
|
+
};
|
|
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
|
+
}
|
|
3243
3427
|
function diagnosticMessages2(value) {
|
|
3244
3428
|
if (!Array.isArray(value)) return [];
|
|
3245
3429
|
return value.map((item) => {
|
package/dist/cli.js
CHANGED
|
@@ -1853,6 +1853,42 @@ var CampaignBuilderAgent = class {
|
|
|
1853
1853
|
}
|
|
1854
1854
|
return result;
|
|
1855
1855
|
}
|
|
1856
|
+
async getBuildStatus(campaignBuildId) {
|
|
1857
|
+
return this.getCampaignBuildStatus(campaignBuildId);
|
|
1858
|
+
}
|
|
1859
|
+
async getBuildRows(campaignBuildId, options = {}) {
|
|
1860
|
+
const filters = compact({
|
|
1861
|
+
segment: options.segment,
|
|
1862
|
+
qualified: options.qualified,
|
|
1863
|
+
row_status: options.rowStatus
|
|
1864
|
+
});
|
|
1865
|
+
const args = compact({
|
|
1866
|
+
campaign_build_id: campaignBuildId,
|
|
1867
|
+
page_size: options.limit,
|
|
1868
|
+
cursor: options.cursor
|
|
1869
|
+
});
|
|
1870
|
+
if (Object.keys(filters).length > 0) args.filters = filters;
|
|
1871
|
+
const data = await this.callMcp("get_campaign_build_rows", args);
|
|
1872
|
+
return mapAgentCampaignRowsResult(data);
|
|
1873
|
+
}
|
|
1874
|
+
async listBuildArtifacts(campaignBuildId) {
|
|
1875
|
+
const data = await this.callMcp("list_campaign_build_artifacts", {
|
|
1876
|
+
campaign_build_id: campaignBuildId
|
|
1877
|
+
});
|
|
1878
|
+
return Array.isArray(data.artifacts) ? data.artifacts.map(mapAgentCampaignArtifact) : [];
|
|
1879
|
+
}
|
|
1880
|
+
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1881
|
+
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
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
|
+
}
|
|
1856
1892
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1857
1893
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1858
1894
|
campaign_build_id: campaignBuildId
|
|
@@ -3246,6 +3282,154 @@ function mapAgentCampaignBuildStatus(data) {
|
|
|
3246
3282
|
completedAt: stringValue(data.completed_at) ?? null
|
|
3247
3283
|
};
|
|
3248
3284
|
}
|
|
3285
|
+
function mapAgentCampaignRowsResult(data) {
|
|
3286
|
+
const rows = Array.isArray(data.rows) ? data.rows : [];
|
|
3287
|
+
return {
|
|
3288
|
+
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
3289
|
+
rows: rows.map((row, index) => {
|
|
3290
|
+
const record = asRecord(row);
|
|
3291
|
+
return {
|
|
3292
|
+
index: numberOrUndefined2(record.index) ?? index,
|
|
3293
|
+
status: stringValue(record.status) ?? stringValue(record.row_status) ?? "unknown",
|
|
3294
|
+
qualified: record.qualified !== false,
|
|
3295
|
+
segment: stringValue(record.segment) ?? null,
|
|
3296
|
+
data: nullableRecord(record.data) ?? record
|
|
3297
|
+
};
|
|
3298
|
+
}),
|
|
3299
|
+
count: numberOrUndefined2(data.count) ?? rows.length,
|
|
3300
|
+
pageSize: numberOrUndefined2(data.page_size) ?? rows.length,
|
|
3301
|
+
nextCursor: stringValue(data.next_cursor) ?? null,
|
|
3302
|
+
hasMore: data.has_more === true
|
|
3303
|
+
};
|
|
3304
|
+
}
|
|
3305
|
+
function mapAgentCampaignArtifact(data) {
|
|
3306
|
+
return {
|
|
3307
|
+
id: stringValue(data.id) ?? "",
|
|
3308
|
+
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
3309
|
+
artifactType: stringValue(data.artifact_type) ?? "",
|
|
3310
|
+
destination: stringValue(data.destination) ?? "",
|
|
3311
|
+
storagePath: stringValue(data.storage_path) ?? "",
|
|
3312
|
+
signedUrl: stringValue(data.signed_url) ?? null,
|
|
3313
|
+
rowCount: numberOrUndefined2(data.row_count) ?? 0,
|
|
3314
|
+
checksum: stringValue(data.checksum) ?? null,
|
|
3315
|
+
metadata: nullableRecord(data.metadata) ?? {},
|
|
3316
|
+
createdAt: stringValue(data.created_at) ?? ""
|
|
3317
|
+
};
|
|
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
|
+
}
|
|
3249
3433
|
function diagnosticMessages2(value) {
|
|
3250
3434
|
if (!Array.isArray(value)) return [];
|
|
3251
3435
|
return value.map((item) => {
|
|
@@ -6619,6 +6803,10 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6619
6803
|
}
|
|
6620
6804
|
return;
|
|
6621
6805
|
}
|
|
6806
|
+
if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
|
|
6807
|
+
await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
|
|
6808
|
+
return;
|
|
6809
|
+
}
|
|
6622
6810
|
if (!["plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
|
|
6623
6811
|
printCampaignAgentHelp();
|
|
6624
6812
|
return;
|
|
@@ -6718,6 +6906,90 @@ async function handleCampaignAgentCommand(signaliz, argv) {
|
|
|
6718
6906
|
printCampaignAgentPlan(plan);
|
|
6719
6907
|
}
|
|
6720
6908
|
}
|
|
6909
|
+
async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
|
|
6910
|
+
const flags = parseFlags(argv);
|
|
6911
|
+
const buildId = argv[0] && !argv[0].startsWith("--") ? argv[0] : stringFlag(flags, "campaign-build-id", "build-id");
|
|
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
|
+
}
|
|
6935
|
+
if (subcommand === "status") {
|
|
6936
|
+
const status = await signaliz.campaignBuilderAgent.getBuildStatus(buildId);
|
|
6937
|
+
if (booleanFlag(flags, "json")) {
|
|
6938
|
+
printJson(status);
|
|
6939
|
+
} else {
|
|
6940
|
+
printCampaignAgentBuildStatus(status);
|
|
6941
|
+
}
|
|
6942
|
+
return;
|
|
6943
|
+
}
|
|
6944
|
+
if (subcommand === "rows") {
|
|
6945
|
+
const result2 = await signaliz.campaignBuilderAgent.getBuildRows(buildId, {
|
|
6946
|
+
limit: numberFlag(flags, "limit"),
|
|
6947
|
+
cursor: stringFlag(flags, "cursor"),
|
|
6948
|
+
segment: stringFlag(flags, "segment"),
|
|
6949
|
+
rowStatus: stringFlag(flags, "row-status"),
|
|
6950
|
+
qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
|
|
6951
|
+
});
|
|
6952
|
+
const operatorResult = {
|
|
6953
|
+
...result2,
|
|
6954
|
+
rows: formatCampaignAgentRows(result2.rows)
|
|
6955
|
+
};
|
|
6956
|
+
if (booleanFlag(flags, "json")) {
|
|
6957
|
+
printJson(operatorResult);
|
|
6958
|
+
} else {
|
|
6959
|
+
printCampaignAgentRows(operatorResult);
|
|
6960
|
+
}
|
|
6961
|
+
return;
|
|
6962
|
+
}
|
|
6963
|
+
if (subcommand === "artifacts") {
|
|
6964
|
+
const artifacts = await signaliz.campaignBuilderAgent.listBuildArtifacts(buildId);
|
|
6965
|
+
if (booleanFlag(flags, "json")) {
|
|
6966
|
+
printJson(artifacts);
|
|
6967
|
+
} else if (artifacts.length === 0) {
|
|
6968
|
+
console.log("No artifacts yet.");
|
|
6969
|
+
console.log(`Next: signaliz campaign-agent status ${buildId}`);
|
|
6970
|
+
} else {
|
|
6971
|
+
for (const artifact of artifacts) {
|
|
6972
|
+
console.log(`${artifact.artifactType || "artifact"}: ${artifact.rowCount} rows${artifact.signedUrl ? `
|
|
6973
|
+
${artifact.signedUrl}` : ""}`);
|
|
6974
|
+
}
|
|
6975
|
+
}
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6978
|
+
const destinationType = stringFlag(flags, "destination-type", "delivery-destination-type", "type");
|
|
6979
|
+
if (!destinationType || !["json", "csv", "webhook"].includes(destinationType)) {
|
|
6980
|
+
throw new Error("campaign-agent approve requires --destination-type json|csv|webhook");
|
|
6981
|
+
}
|
|
6982
|
+
const result = await signaliz.campaignBuilderAgent.approveDelivery(buildId, destinationType, {
|
|
6983
|
+
destinationId: stringFlag(flags, "destination-id", "delivery-destination-id"),
|
|
6984
|
+
destinationConfig: jsonObjectFlag(flags, "destination-config", "delivery-config")
|
|
6985
|
+
});
|
|
6986
|
+
if (booleanFlag(flags, "json")) {
|
|
6987
|
+
printJson(result);
|
|
6988
|
+
} else {
|
|
6989
|
+
console.log(`Delivery ${result.status}: ${result.destinationType}`);
|
|
6990
|
+
if (result.message) console.log(result.message);
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6721
6993
|
function campaignAgentRequestTemplateFromFlags(flags) {
|
|
6722
6994
|
const goal = stringFlag(flags, "goal", "brief") || "Build a strategy-template campaign for mature operators in the target ICP.";
|
|
6723
6995
|
const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
|
|
@@ -7054,6 +7326,87 @@ function printCampaignAgentExecution(payload, flags) {
|
|
|
7054
7326
|
console.log("\nResult:");
|
|
7055
7327
|
printJson(payload.result);
|
|
7056
7328
|
}
|
|
7329
|
+
function printCampaignAgentBuildStatus(status) {
|
|
7330
|
+
console.log(`Campaign: ${status.name || status.campaignBuildId}`);
|
|
7331
|
+
if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
|
|
7332
|
+
console.log(`Status: ${status.status}`);
|
|
7333
|
+
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
7334
|
+
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
7335
|
+
console.log(`Artifacts: ${status.artifactCount}`);
|
|
7336
|
+
if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
|
|
7337
|
+
if (Array.isArray(status.warnings) && status.warnings.length > 0) {
|
|
7338
|
+
console.log(`Warnings: ${status.warnings.slice(0, 3).join("; ")}`);
|
|
7339
|
+
}
|
|
7340
|
+
if (Array.isArray(status.errors) && status.errors.length > 0) {
|
|
7341
|
+
console.log(`Errors: ${status.errors.slice(0, 3).join("; ")}`);
|
|
7342
|
+
}
|
|
7343
|
+
if (status.status === "completed") {
|
|
7344
|
+
console.log(`Next: signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
|
|
7345
|
+
} else if (status.status === "pending_approval") {
|
|
7346
|
+
console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
7347
|
+
}
|
|
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
|
+
}
|
|
7377
|
+
function formatCampaignAgentRows(rows) {
|
|
7378
|
+
return rows.map((row) => {
|
|
7379
|
+
const data = asRecord4(row.data);
|
|
7380
|
+
const fallbackName = `${data.first_name || ""} ${data.last_name || ""}`.trim() || null;
|
|
7381
|
+
return {
|
|
7382
|
+
...row,
|
|
7383
|
+
email: data.email ?? null,
|
|
7384
|
+
name: data.full_name ?? fallbackName,
|
|
7385
|
+
title: data.title ?? null,
|
|
7386
|
+
company: data.company_name ?? null,
|
|
7387
|
+
domain: data.company_domain ?? null,
|
|
7388
|
+
score: data.overall_score ?? null,
|
|
7389
|
+
has_copy: Boolean(data.subject || data.opener || data.body || data.cta || asRecord4(data.raw_copy).subject)
|
|
7390
|
+
};
|
|
7391
|
+
});
|
|
7392
|
+
}
|
|
7393
|
+
function printCampaignAgentRows(result) {
|
|
7394
|
+
if (!Array.isArray(result.rows) || result.rows.length === 0) {
|
|
7395
|
+
console.log("No rows found.");
|
|
7396
|
+
return;
|
|
7397
|
+
}
|
|
7398
|
+
console.table(result.rows.map((row) => ({
|
|
7399
|
+
email: row.email || "",
|
|
7400
|
+
name: row.name || "",
|
|
7401
|
+
title: row.title || "",
|
|
7402
|
+
company: row.company || row.domain || "",
|
|
7403
|
+
status: row.status || "",
|
|
7404
|
+
segment: row.segment || "",
|
|
7405
|
+
score: row.score ?? ""
|
|
7406
|
+
})));
|
|
7407
|
+
console.log(`Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
|
|
7408
|
+
if (result.nextCursor) console.log(`Next: signaliz campaign-agent rows ${result.campaignBuildId} --cursor ${result.nextCursor}`);
|
|
7409
|
+
}
|
|
7057
7410
|
function asRecord4(value) {
|
|
7058
7411
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7059
7412
|
}
|
|
@@ -7230,6 +7583,9 @@ Usage:
|
|
|
7230
7583
|
signaliz campaign-agent dry-run --goal "Build a strategy-template campaign..." --target-count 500 --use-local-leads --json
|
|
7231
7584
|
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign..." --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500
|
|
7232
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
|
|
7587
|
+
signaliz campaign-agent status <campaign_build_id> --json
|
|
7588
|
+
signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
|
|
7233
7589
|
|
|
7234
7590
|
Environment:
|
|
7235
7591
|
SIGNALIZ_API_KEY Your API key (not required for campaign-agent init)
|
|
@@ -7261,8 +7617,13 @@ Signaliz campaign-agent commands:
|
|
|
7261
7617
|
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
7262
7618
|
signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
|
|
7263
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]
|
|
7621
|
+
signaliz campaign-agent status <campaign_build_id> [--json]
|
|
7622
|
+
signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--json]
|
|
7623
|
+
signaliz campaign-agent artifacts <campaign_build_id> [--json]
|
|
7624
|
+
signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
|
|
7264
7625
|
|
|
7265
|
-
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
|
|
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.
|
|
7266
7627
|
`);
|
|
7267
7628
|
}
|
|
7268
7629
|
main().catch((e) => {
|