@signaliz/sdk 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,16 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- Signaliz,
4
- createCampaignBuilderAgentRequestTemplate,
5
- createCampaignBuilderApproval,
6
- createCampaignBuilderBuildKit,
7
- createCampaignBuilderMemoryKit
8
- } from "./chunk-5JNKSMNW.mjs";
9
2
 
10
3
  // src/cli.ts
11
4
  import { readFileSync, writeFileSync } from "fs";
12
5
  var apiKey = process.env.SIGNALIZ_API_KEY;
13
6
  var baseUrl = process.env.SIGNALIZ_BASE_URL || process.env.SIGNALIZ_API_URL;
7
+ var sdkModulePromise;
8
+ function loadSdk() {
9
+ sdkModulePromise ?? (sdkModulePromise = import("./index.mjs"));
10
+ return sdkModulePromise;
11
+ }
12
+ async function createSignalizClient() {
13
+ const { Signaliz } = await loadSdk();
14
+ return new Signaliz({ apiKey: apiKey || "offline", baseUrl });
15
+ }
14
16
  async function main() {
15
17
  const command = process.argv[2];
16
18
  if (!command || command === "help" || command === "--help" || command === "-h") {
@@ -23,9 +25,9 @@ async function main() {
23
25
  console.error(" Set it with: export SIGNALIZ_API_KEY=sk_...");
24
26
  process.exit(1);
25
27
  }
26
- const signaliz = new Signaliz({ apiKey: apiKey || "offline", baseUrl });
27
28
  switch (command) {
28
29
  case "test": {
30
+ const signaliz = await createSignalizClient();
29
31
  try {
30
32
  const ws = await signaliz.getWorkspace();
31
33
  console.log(`\u2705 Connected to workspace: ${ws.name} (${ws.creditsRemaining.toLocaleString()} credits remaining)`);
@@ -36,6 +38,7 @@ async function main() {
36
38
  break;
37
39
  }
38
40
  case "tools": {
41
+ const signaliz = await createSignalizClient();
39
42
  try {
40
43
  const tools = await signaliz.listTools();
41
44
  console.log(`
@@ -55,12 +58,13 @@ async function main() {
55
58
  break;
56
59
  }
57
60
  case "gtm": {
61
+ const signaliz = await createSignalizClient();
58
62
  await handleGtmCommand(signaliz, process.argv.slice(3));
59
63
  break;
60
64
  }
61
65
  case "campaign-agent":
62
66
  case "campaign-builder": {
63
- await handleCampaignAgentCommand(signaliz, process.argv.slice(3));
67
+ await handleCampaignAgentCommand(createSignalizClient, process.argv.slice(3));
64
68
  break;
65
69
  }
66
70
  default:
@@ -117,6 +121,101 @@ async function handleGtmCommand(signaliz, argv) {
117
121
  printResult(result, flags);
118
122
  return;
119
123
  }
124
+ if (subcommand === "learning" && argv[1] === "status" || subcommand === "learning-status") {
125
+ const flags = parseFlags(argv.slice(subcommand === "learning" ? 2 : 1));
126
+ const campaignId = stringFlag(flags, "campaign-id");
127
+ const campaignBuildId = stringFlag(flags, "campaign-build-id", "build-id");
128
+ if (!campaignId && !campaignBuildId) {
129
+ throw new Error("gtm learning status requires --campaign-id or --campaign-build-id");
130
+ }
131
+ const result = await signaliz.gtm.campaignLearningStatus({
132
+ campaignId,
133
+ campaignBuildId,
134
+ days: numberFlag(flags, "days"),
135
+ networkDays: numberFlag(flags, "network-days"),
136
+ minSampleSize: numberFlag(flags, "min-sample-size"),
137
+ minWorkspaceCount: numberFlag(flags, "min-workspace-count"),
138
+ minPrivacyK: numberFlag(flags, "min-privacy-k"),
139
+ includeMemory: !booleanFlag(flags, "no-memory"),
140
+ includeNetwork: !booleanFlag(flags, "no-network"),
141
+ writeMode: stringFlag(flags, "write-mode"),
142
+ limit: numberFlag(flags, "limit")
143
+ });
144
+ printResult(result, flags);
145
+ return;
146
+ }
147
+ if (subcommand === "feedback") {
148
+ const feedbackCommand = argv[1];
149
+ if (!feedbackCommand || feedbackCommand === "help" || feedbackCommand === "--help" || feedbackCommand === "-h") {
150
+ printGtmHelp();
151
+ return;
152
+ }
153
+ if (feedbackCommand === "instantly-pull" || feedbackCommand === "pull-instantly") {
154
+ const flags = parseFlags(argv.slice(2));
155
+ const confirmWrite = booleanFlag(flags, "confirm-write");
156
+ const input = {
157
+ source: stringFlag(flags, "source", "pull-source"),
158
+ instantlyProfile: stringFlag(flags, "instantly-profile", "profile"),
159
+ campaignId: stringFlag(flags, "campaign-id"),
160
+ campaignBuildId: stringFlag(flags, "campaign-build-id", "build-id"),
161
+ providerLinkId: stringFlag(flags, "provider-link-id"),
162
+ providerCampaignId: stringFlag(flags, "provider-campaign-id", "instantly-campaign-id"),
163
+ instantlyCampaignId: stringFlag(flags, "instantly-campaign-id"),
164
+ integrationId: stringFlag(flags, "integration-id"),
165
+ cursor: stringFlag(flags, "cursor"),
166
+ from: stringFlag(flags, "from", "since"),
167
+ to: stringFlag(flags, "to", "until"),
168
+ limit: numberFlag(flags, "limit"),
169
+ maxPages: numberFlag(flags, "max-pages"),
170
+ emailType: stringFlag(flags, "email-type"),
171
+ mode: stringFlag(flags, "mode"),
172
+ sortOrder: stringFlag(flags, "sort-order"),
173
+ createMemory: !booleanFlag(flags, "no-create-memory"),
174
+ writeRoutineOutcomes: !booleanFlag(flags, "no-routine-outcomes"),
175
+ dryRun: !confirmWrite || booleanFlag(flags, "dry-run"),
176
+ runBrainCycle: optionalBooleanFlag(flags, "run-brain-cycle", "no-brain-cycle"),
177
+ brainCycleWriteMode: stringFlag(flags, "brain-cycle-write-mode", "write-mode"),
178
+ brainCyclePhases: csvFlag(flags, "brain-cycle-phases", "phases"),
179
+ brainCycleMinIngested: numberFlag(flags, "brain-cycle-min-ingested"),
180
+ brainCycleMinIntervalMinutes: numberFlag(flags, "brain-cycle-min-interval-minutes")
181
+ };
182
+ if (input.dryRun === false && !input.campaignId && !input.campaignBuildId && !input.providerLinkId && !input.providerCampaignId) {
183
+ throw new Error("gtm feedback instantly-pull --confirm-write requires --campaign-id, --campaign-build-id, --provider-link-id, or --provider-campaign-id");
184
+ }
185
+ const result = await signaliz.gtm.pullInstantlyFeedback(input);
186
+ printResult({
187
+ ...asRecord(result),
188
+ cli_policy: input.dryRun ? "CLI defaulted to dry_run. Re-run with --confirm-write to write feedback, memory, cursors, and optional Brain-cycle dispatch." : "Confirmed internal write: feedback/memory/cursor writes are enabled for this pull."
189
+ }, flags);
190
+ return;
191
+ }
192
+ if (feedbackCommand === "instantly-webhook-prepare" || feedbackCommand === "prepare-instantly-webhook") {
193
+ const flags = parseFlags(argv.slice(2));
194
+ if (!booleanFlag(flags, "confirm-write")) {
195
+ throw new Error("gtm feedback instantly-webhook-prepare writes provider-link webhook metadata; pass --confirm-write after review");
196
+ }
197
+ const input = {
198
+ campaignId: stringFlag(flags, "campaign-id"),
199
+ campaignBuildId: stringFlag(flags, "campaign-build-id", "build-id"),
200
+ providerLinkId: stringFlag(flags, "provider-link-id"),
201
+ providerCampaignId: stringFlag(flags, "provider-campaign-id", "instantly-campaign-id"),
202
+ instantlyCampaignId: stringFlag(flags, "instantly-campaign-id"),
203
+ integrationId: stringFlag(flags, "integration-id"),
204
+ providerWorkspaceId: stringFlag(flags, "provider-workspace-id"),
205
+ providerAccountId: stringFlag(flags, "provider-account-id"),
206
+ rotateSecret: booleanFlag(flags, "rotate-secret"),
207
+ runBrainCycle: optionalBooleanFlag(flags, "run-brain-cycle", "no-brain-cycle"),
208
+ brainCycleWriteMode: stringFlag(flags, "brain-cycle-write-mode", "write-mode"),
209
+ brainCyclePhases: csvFlag(flags, "brain-cycle-phases", "phases"),
210
+ brainCycleMinIngested: numberFlag(flags, "brain-cycle-min-ingested"),
211
+ brainCycleMinIntervalMinutes: numberFlag(flags, "brain-cycle-min-interval-minutes")
212
+ };
213
+ const result = await signaliz.gtm.prepareInstantlyFeedbackWebhook(input);
214
+ printResult(result, flags);
215
+ return;
216
+ }
217
+ throw new Error(`Unknown gtm feedback command "${feedbackCommand}". Use instantly-pull or instantly-webhook-prepare.`);
218
+ }
120
219
  if (subcommand === "templates" || subcommand === "strategy-templates") {
121
220
  const flags = parseFlags(argv.slice(1));
122
221
  const result = await signaliz.gtm.campaignStrategyTemplates({
@@ -359,7 +458,7 @@ async function handleGtmCommand(signaliz, argv) {
359
458
  }
360
459
  printGtmHelp();
361
460
  }
362
- async function handleCampaignAgentCommand(signaliz, argv) {
461
+ async function handleCampaignAgentCommand(signalizFactory, argv) {
363
462
  const subcommand = argv[0];
364
463
  if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
365
464
  printCampaignAgentHelp();
@@ -367,7 +466,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
367
466
  }
368
467
  if (["init", "template", "request-template", "new"].includes(subcommand)) {
369
468
  const flags2 = parseFlags(argv.slice(1));
370
- const request2 = campaignAgentRequestTemplateFromFlags(flags2);
469
+ const request2 = await campaignAgentRequestTemplateFromFlags(flags2);
371
470
  const outputFile = stringFlag(flags2, "output-file", "out");
372
471
  if (outputFile) {
373
472
  writeFileSync(outputFile, `${JSON.stringify(request2, null, 2)}
@@ -383,12 +482,13 @@ async function handleCampaignAgentCommand(signaliz, argv) {
383
482
  }
384
483
  if (["kit", "build-kit", "blueprint"].includes(subcommand)) {
385
484
  const flags2 = parseFlags(argv.slice(1));
485
+ const { createCampaignBuilderBuildKit } = await loadSdk();
386
486
  const requestFromFile2 = campaignAgentRequestFileFromFlags(flags2);
387
487
  const fallbackGoal = stringFlag(flags2, "goal", "brief") || stringOrUndefined(requestFromFile2?.goal) || "Build a strategy-template campaign for mature operators in the target ICP.";
388
488
  const request2 = requestFromFile2 ? mergeCampaignAgentRequests(
389
489
  requestFromFile2,
390
490
  campaignAgentRequestFromFlags(fallbackGoal, flags2, { includeDefaults: false })
391
- ) : campaignAgentRequestTemplateFromFlags(flags2);
491
+ ) : await campaignAgentRequestTemplateFromFlags(flags2);
392
492
  const kit = createCampaignBuilderBuildKit({
393
493
  ...request2,
394
494
  includeLocalLeads: booleanFlag(flags2, "use-local-leads"),
@@ -415,12 +515,13 @@ async function handleCampaignAgentCommand(signaliz, argv) {
415
515
  }
416
516
  if (["memory-kit", "seed-kit", "memory"].includes(subcommand)) {
417
517
  const flags2 = parseFlags(argv.slice(1));
518
+ const { createCampaignBuilderMemoryKit } = await loadSdk();
418
519
  const requestFromFile2 = campaignAgentRequestFileFromFlags(flags2);
419
520
  const fallbackGoal = stringFlag(flags2, "goal", "brief") || stringOrUndefined(requestFromFile2?.goal) || "Build a strategy-template campaign for mature operators in the target ICP.";
420
521
  const request2 = requestFromFile2 ? mergeCampaignAgentRequests(
421
522
  requestFromFile2,
422
523
  campaignAgentRequestFromFlags(fallbackGoal, flags2, { includeDefaults: false })
423
- ) : campaignAgentRequestTemplateFromFlags(flags2);
524
+ ) : await campaignAgentRequestTemplateFromFlags(flags2);
424
525
  const kit = createCampaignBuilderMemoryKit({
425
526
  ...request2,
426
527
  includeLocalLeads: booleanFlag(flags2, "use-local-leads"),
@@ -448,12 +549,15 @@ async function handleCampaignAgentCommand(signaliz, argv) {
448
549
  }
449
550
  return;
450
551
  }
451
- if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
452
- await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
552
+ const isReviewCommand = ["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand);
553
+ const isPlanCommand = ["plan", "doctor", "readiness", "preflight", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand);
554
+ if (!isReviewCommand && !isPlanCommand) {
555
+ printCampaignAgentHelp();
453
556
  return;
454
557
  }
455
- if (!["plan", "doctor", "readiness", "preflight", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
456
- printCampaignAgentHelp();
558
+ const signaliz = await signalizFactory();
559
+ if (isReviewCommand) {
560
+ await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
457
561
  return;
458
562
  }
459
563
  const flags = parseFlags(argv.slice(1));
@@ -529,6 +633,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
529
633
  }
530
634
  if (isApprovedBuild) {
531
635
  const approvedTypes = approvedTypesFromFlags(plan, flags);
636
+ const { createCampaignBuilderApproval } = await loadSdk();
532
637
  const approval = createCampaignBuilderApproval(plan, {
533
638
  approvedBy,
534
639
  approvedTypes,
@@ -573,6 +678,8 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
573
678
  cursor: stringFlag(flags, "cursor"),
574
679
  segment: stringFlag(flags, "segment"),
575
680
  rowStatus: stringFlag(flags, "row-status"),
681
+ includeData: optionalBooleanFlag(flags, "include-data"),
682
+ includeRaw: optionalBooleanFlag(flags, "include-raw"),
576
683
  qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
577
684
  });
578
685
  const operatorReview = {
@@ -604,6 +711,8 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
604
711
  cursor: stringFlag(flags, "cursor"),
605
712
  segment: stringFlag(flags, "segment"),
606
713
  rowStatus: stringFlag(flags, "row-status"),
714
+ includeData: optionalBooleanFlag(flags, "include-data"),
715
+ includeRaw: optionalBooleanFlag(flags, "include-raw"),
607
716
  qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
608
717
  });
609
718
  const operatorResult = {
@@ -647,7 +756,7 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
647
756
  if (result.message) console.log(result.message);
648
757
  }
649
758
  }
650
- function campaignAgentRequestTemplateFromFlags(flags) {
759
+ async function campaignAgentRequestTemplateFromFlags(flags) {
651
760
  const goal = stringFlag(flags, "goal", "brief") || "Build a strategy-template campaign for mature operators in the target ICP.";
652
761
  const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
653
762
  const options = {
@@ -656,6 +765,7 @@ function campaignAgentRequestTemplateFromFlags(flags) {
656
765
  includeCustomToolPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-custom-tool-placeholder") || booleanFlag(flags, "include-byo-placeholder"),
657
766
  includeNango: !booleanFlag(flags, "no-nango-catalog")
658
767
  };
768
+ const { createCampaignBuilderAgentRequestTemplate } = await loadSdk();
659
769
  return createCampaignBuilderAgentRequestTemplate(options);
660
770
  }
661
771
  function campaignAgentRequestFileFromFlags(flags) {
@@ -912,6 +1022,11 @@ function booleanFlag(flags, name, defaultValue = false) {
912
1022
  if (Array.isArray(value)) return value.length > 0 ? parseBoolean(value.at(-1), defaultValue) : defaultValue;
913
1023
  return parseBoolean(value, defaultValue);
914
1024
  }
1025
+ function optionalBooleanFlag(flags, trueName, falseName) {
1026
+ if (falseName && flagValue(flags, falseName) !== void 0) return false;
1027
+ if (flagValue(flags, trueName) === void 0) return void 0;
1028
+ return booleanFlag(flags, trueName);
1029
+ }
915
1030
  function parseBoolean(value, defaultValue) {
916
1031
  if (value === void 0) return defaultValue;
917
1032
  if (typeof value === "boolean") return value;
@@ -1061,7 +1176,9 @@ function printCampaignAgentBuildStatus(status) {
1061
1176
  console.log(`Status: ${status.status}`);
1062
1177
  console.log(`Phase: ${status.currentPhase || "N/A"}`);
1063
1178
  console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
1179
+ printCampaignCustomerRowCounts(status);
1064
1180
  console.log(`Artifacts: ${status.artifactCount}`);
1181
+ if (status.campaignBuildId) printCampaignArtifactDownload(status, status.campaignBuildId);
1065
1182
  if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
1066
1183
  if (Array.isArray(status.warnings) && status.warnings.length > 0) {
1067
1184
  console.log(`Warnings: ${status.warnings.slice(0, 3).join("; ")}`);
@@ -1069,12 +1186,34 @@ function printCampaignAgentBuildStatus(status) {
1069
1186
  if (Array.isArray(status.errors) && status.errors.length > 0) {
1070
1187
  console.log(`Errors: ${status.errors.slice(0, 3).join("; ")}`);
1071
1188
  }
1072
- if (status.status === "completed") {
1189
+ if (status.status === "completed" && status.nextAction) {
1190
+ console.log(`Next: ${status.nextAction}`);
1191
+ } else if (status.status === "completed") {
1073
1192
  console.log(`Next: signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
1193
+ } else if (status.status === "pending_approval" && status.approvalAction) {
1194
+ console.log(`Next: ${status.approvalAction}`);
1195
+ } else if (status.status === "pending_approval" && status.nextAction) {
1196
+ console.log(`Next: ${status.nextAction}`);
1074
1197
  } else if (status.status === "pending_approval") {
1075
1198
  console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
1076
1199
  }
1077
1200
  }
1201
+ function printCampaignCustomerRowCounts(status) {
1202
+ const counts = status?.customerRowCounts || status?.customer_row_counts;
1203
+ if (!counts || typeof counts !== "object") return;
1204
+ const value = (camel, snake) => counts[camel] ?? counts[snake] ?? "n/a";
1205
+ const requested = value("requestedTarget", "requested_target");
1206
+ console.log(`Customer rows: accepted ${value("acceptedRows", "accepted_rows")}/${requested}, copied ${value("copiedRows", "copied_rows")}, approval-ready ${value("approvalReadyRows", "approval_ready_rows")}, QA-ready ${value("qaReadyRows", "qa_ready_rows")}, delivered ${value("deliveredRows", "delivered_rows")}`);
1207
+ const shortfalls = [
1208
+ ["accepted", value("acceptedShortfall", "accepted_shortfall")],
1209
+ ["usable", value("usableShortfall", "usable_shortfall")],
1210
+ ["QA-ready", value("qaReadyShortfall", "qa_ready_shortfall")],
1211
+ ["delivery", value("deliveryShortfall", "delivery_shortfall")]
1212
+ ].filter(([, count]) => typeof count === "number" && count > 0);
1213
+ if (shortfalls.length > 0) {
1214
+ console.log(`Shortfalls: ${shortfalls.map(([label, count]) => `${label} ${count}`).join(", ")}`);
1215
+ }
1216
+ }
1078
1217
  function printCampaignAgentBuildReview(review) {
1079
1218
  const summary = asRecord(review.summary);
1080
1219
  console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
@@ -1085,6 +1224,7 @@ function printCampaignAgentBuildReview(review) {
1085
1224
  console.log(`Emails: ${summary.rowsWithEmail || 0}`);
1086
1225
  console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
1087
1226
  console.log(`Artifacts: ${summary.artifactCount || 0}`);
1227
+ if (review.campaignBuildId) printCampaignArtifactDownload(review.status, review.campaignBuildId);
1088
1228
  console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
1089
1229
  if (Array.isArray(review.gates) && review.gates.length > 0) {
1090
1230
  console.log("\nGates:");
@@ -1106,6 +1246,14 @@ function printCampaignAgentBuildReview(review) {
1106
1246
  function formatCampaignAgentRows(rows) {
1107
1247
  return rows.map((row) => {
1108
1248
  const data = asRecord(row.data);
1249
+ const copyData = asRecord(data.copy);
1250
+ const rawCopy = asRecord(data.raw_copy);
1251
+ const copy = {
1252
+ subject: data.subject || copyData.subject || rawCopy.subject || null,
1253
+ opener: data.opener || copyData.opener || rawCopy.opener || null,
1254
+ body: data.body || copyData.body || rawCopy.body || null,
1255
+ cta: data.cta || copyData.cta || rawCopy.cta || null
1256
+ };
1109
1257
  const fallbackName = `${data.first_name || ""} ${data.last_name || ""}`.trim() || null;
1110
1258
  return {
1111
1259
  ...row,
@@ -1115,7 +1263,8 @@ function formatCampaignAgentRows(rows) {
1115
1263
  company: data.company_name ?? null,
1116
1264
  domain: data.company_domain ?? null,
1117
1265
  score: data.overall_score ?? null,
1118
- has_copy: Boolean(data.subject || data.opener || data.body || data.cta || asRecord(data.raw_copy).subject)
1266
+ copy,
1267
+ has_copy: Boolean(copy.subject || copy.opener || copy.body || copy.cta)
1119
1268
  };
1120
1269
  });
1121
1270
  }
@@ -1133,9 +1282,41 @@ function printCampaignAgentRows(result) {
1133
1282
  segment: row.segment || "",
1134
1283
  score: row.score ?? ""
1135
1284
  })));
1285
+ printCampaignAgentCopySnippets(result.rows);
1136
1286
  console.log(`Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
1137
1287
  if (result.nextCursor) console.log(`Next: signaliz campaign-agent rows ${result.campaignBuildId} --cursor ${result.nextCursor}`);
1138
1288
  }
1289
+ function printCampaignArtifactDownload(status, buildId) {
1290
+ const downloads = Array.isArray(status?.artifactDownloads) ? status.artifactDownloads : Array.isArray(status?.artifact_downloads) ? status.artifact_downloads : [];
1291
+ const download = downloads.find((item) => String(item?.format || item?.artifactType || item?.artifact_type || "").toLowerCase() === "csv") || downloads[0];
1292
+ const url = download?.downloadUrl || download?.download_url || download?.signedUrl || download?.signed_url;
1293
+ if (typeof url === "string" && url.trim()) {
1294
+ const format = download?.format || download?.artifactType || download?.artifact_type || "artifact";
1295
+ const rowCount = Number(download?.rowCount ?? download?.row_count ?? 0);
1296
+ console.log(`Download: ${format}${rowCount > 0 ? `, ${rowCount} rows` : ""}`);
1297
+ console.log(` ${url}`);
1298
+ } else if (Number(status?.artifactCount ?? status?.artifact_count ?? 0) > 0) {
1299
+ console.log(`Next: signaliz campaign download ${buildId} --format csv`);
1300
+ }
1301
+ }
1302
+ function printCampaignAgentCopySnippets(rows, limit = 5) {
1303
+ const rowsWithCopy = rows.filter((row) => {
1304
+ const copy = asRecord(row.copy);
1305
+ return Boolean(copy.subject || copy.opener || copy.body || copy.cta);
1306
+ });
1307
+ if (rowsWithCopy.length === 0) return;
1308
+ console.log("\nCopy:");
1309
+ for (const row of rowsWithCopy.slice(0, limit)) {
1310
+ const copy = asRecord(row.copy);
1311
+ const label = row.email || row.name || row.company || `row ${row.index ?? ""}`.trim();
1312
+ console.log(`- ${label}`);
1313
+ if (copy.subject) console.log(` Subject: ${copy.subject}`);
1314
+ if (copy.opener) console.log(` Opener: ${copy.opener}`);
1315
+ if (copy.body) console.log(` Body: ${copy.body}`);
1316
+ if (copy.cta) console.log(` CTA: ${copy.cta}`);
1317
+ }
1318
+ if (rowsWithCopy.length > limit) console.log(` ...${rowsWithCopy.length - limit} more row(s) with copy`);
1319
+ }
1139
1320
  function asRecord(value) {
1140
1321
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1141
1322
  }
@@ -1171,6 +1352,8 @@ Usage:
1171
1352
  signaliz gtm agent-plan --goal "Build a strategy-template campaign" --strategy-template non-medical-home-care --target-count 500 --json
1172
1353
  signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool --json
1173
1354
  signaliz gtm memory search --query "proof-first vertical gate" --json
1355
+ signaliz gtm feedback instantly-pull --campaign-id <id> --source emails --email-type received --mode emode_all --sort-order asc --confirm-write --json
1356
+ signaliz gtm learning status --campaign-id <id> --json
1174
1357
  signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
1175
1358
  signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
1176
1359
  signaliz campaign-agent memory-kit --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json
@@ -1203,6 +1386,9 @@ Signaliz GTM commands:
1203
1386
  signaliz gtm provider-prepare --provider-id ID [--layer NAME] [--invocation-type webhook|mcp_tool|api] [--json]
1204
1387
  signaliz gtm activate-route --provider-id ID --layer NAME [--confirm] [--json]
1205
1388
  signaliz gtm memory search --query TEXT [--layers a,b] [--provider-chain a,b] [--limit N] [--json]
1389
+ signaliz gtm learning status (--campaign-id ID | --campaign-build-id ID) [--json]
1390
+ signaliz gtm feedback instantly-pull (--campaign-id ID | --provider-link-id ID | --provider-campaign-id ID) [--source webhook_events|emails] [--email-type received|sent|manual] [--mode emode_focused|emode_others|emode_all] [--sort-order asc|desc] [--instantly-profile PROFILE] [--confirm-write] [--json]
1391
+ signaliz gtm feedback instantly-webhook-prepare (--campaign-id ID | --provider-link-id ID) --confirm-write [--json]
1206
1392
  signaliz gtm plan --brief TEXT [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--lead-count N] [--layers a,b] [--providers a,b] [--partners clay,instantly,nango] [--target-icp JSON] [--json]
1207
1393
  `);
1208
1394
  }
@@ -1212,16 +1398,16 @@ Signaliz campaign-agent commands:
1212
1398
 
1213
1399
  signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
1214
1400
  signaliz campaign-agent kit [--goal TEXT | --request-file FILE] [--strategy-template ID] [--target-count N] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--output-file FILE] [--json]
1215
- signaliz campaign-agent memory-kit [--goal TEXT | --request-file FILE] [--strategy-template ID] [--source agency|workflow-patterns|instantly-feedback|all] [--seed-manifest-file FILE] [--json]
1401
+ signaliz campaign-agent memory-kit [--goal TEXT | --request-file FILE] [--strategy-template ID] [--source north-star|agency|workflow-patterns|instantly-feedback|all] [--seed-manifest-file FILE] [--json]
1216
1402
  signaliz campaign-agent doctor [--goal TEXT | --request-file FILE] [--strategy-template ID] [--target-count N] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--custom-tool provider:layer:tool[:mcp]] [--json]
1217
1403
  signaliz campaign-agent plan (--goal TEXT | --request-file FILE) [--campaign-name NAME] [--workspace-label NAME] [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--operating-playbooks proof-first-vertical-gate,signal-led-copy-approval] [--target-count N] [--icp JSON] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--preferred-providers signaliz_native,octave] [--partners clay,instantly,nango] [--no-strategy-memory] [--no-kernel-plan] [--no-delivery-risk] [--json]
1218
1404
  signaliz campaign-agent proof (--goal TEXT | --request-file FILE) [--strategy-template ID] [--target-count N] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--idempotency-key KEY] [--json]
1219
1405
  signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
1220
1406
  signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
1221
1407
  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]
1222
- signaliz campaign-agent review <campaign_build_id> [--limit N] [--qualified|--disqualified] [--json]
1408
+ signaliz campaign-agent review <campaign_build_id> [--limit N] [--qualified|--disqualified] [--include-data] [--include-raw] [--json]
1223
1409
  signaliz campaign-agent status <campaign_build_id> [--json]
1224
- signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--json]
1410
+ signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--include-data] [--include-raw] [--json]
1225
1411
  signaliz campaign-agent artifacts <campaign_build_id> [--json]
1226
1412
  signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
1227
1413