@signaliz/sdk 1.0.16 → 1.0.18

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;
@@ -1060,8 +1175,17 @@ function printCampaignAgentBuildStatus(status) {
1060
1175
  if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
1061
1176
  console.log(`Status: ${status.status}`);
1062
1177
  console.log(`Phase: ${status.currentPhase || "N/A"}`);
1178
+ const terminalState = asRecord(status.terminalState);
1179
+ if (terminalState.kind) {
1180
+ console.log(`Terminal state: ${terminalState.kind} (${terminalState.label || "no label"})`);
1181
+ if (terminalState.heartbeatAgeSeconds !== void 0 && terminalState.heartbeatAgeSeconds !== null) {
1182
+ console.log(`Heartbeat age: ${terminalState.heartbeatAgeSeconds}s`);
1183
+ }
1184
+ }
1063
1185
  console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
1186
+ printCampaignCustomerRowCounts(status);
1064
1187
  console.log(`Artifacts: ${status.artifactCount}`);
1188
+ if (status.campaignBuildId) printCampaignArtifactDownload(status, status.campaignBuildId);
1065
1189
  if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
1066
1190
  if (Array.isArray(status.warnings) && status.warnings.length > 0) {
1067
1191
  console.log(`Warnings: ${status.warnings.slice(0, 3).join("; ")}`);
@@ -1069,10 +1193,34 @@ function printCampaignAgentBuildStatus(status) {
1069
1193
  if (Array.isArray(status.errors) && status.errors.length > 0) {
1070
1194
  console.log(`Errors: ${status.errors.slice(0, 3).join("; ")}`);
1071
1195
  }
1072
- if (status.status === "completed") {
1196
+ if (status.status === "completed" && status.nextAction) {
1197
+ console.log(`Next: ${status.nextAction}`);
1198
+ } else if (status.status === "completed") {
1073
1199
  console.log(`Next: signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
1200
+ } else if (status.status === "pending_approval" && status.approvalAction) {
1201
+ console.log(`Next: ${status.approvalAction}`);
1202
+ } else if (status.status === "pending_approval" && status.nextAction) {
1203
+ console.log(`Next: ${status.nextAction}`);
1074
1204
  } else if (status.status === "pending_approval") {
1075
1205
  console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
1206
+ } else if (terminalState.safeNextAction) {
1207
+ console.log(`Next: ${terminalState.safeNextAction}`);
1208
+ }
1209
+ }
1210
+ function printCampaignCustomerRowCounts(status) {
1211
+ const counts = status?.customerRowCounts || status?.customer_row_counts;
1212
+ if (!counts || typeof counts !== "object") return;
1213
+ const value = (camel, snake) => counts[camel] ?? counts[snake] ?? "n/a";
1214
+ const requested = value("requestedTarget", "requested_target");
1215
+ 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")}`);
1216
+ const shortfalls = [
1217
+ ["accepted", value("acceptedShortfall", "accepted_shortfall")],
1218
+ ["usable", value("usableShortfall", "usable_shortfall")],
1219
+ ["QA-ready", value("qaReadyShortfall", "qa_ready_shortfall")],
1220
+ ["delivery", value("deliveryShortfall", "delivery_shortfall")]
1221
+ ].filter(([, count]) => typeof count === "number" && count > 0);
1222
+ if (shortfalls.length > 0) {
1223
+ console.log(`Shortfalls: ${shortfalls.map(([label, count]) => `${label} ${count}`).join(", ")}`);
1076
1224
  }
1077
1225
  }
1078
1226
  function printCampaignAgentBuildReview(review) {
@@ -1080,16 +1228,20 @@ function printCampaignAgentBuildReview(review) {
1080
1228
  console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
1081
1229
  console.log(`Status: ${summary.status || review.status?.status}`);
1082
1230
  console.log(`Phase: ${summary.phase || review.status?.currentPhase || "N/A"}`);
1231
+ console.log(`Terminal state: ${summary.terminalState || review.status?.terminalState?.kind || "unknown"}`);
1083
1232
  console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
1084
1233
  console.log(`Qualified: ${summary.qualifiedRows || 0}`);
1085
1234
  console.log(`Emails: ${summary.rowsWithEmail || 0}`);
1086
1235
  console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
1087
1236
  console.log(`Artifacts: ${summary.artifactCount || 0}`);
1237
+ printCampaignAgentNorthStarScorecard(review.northStarScorecard);
1238
+ if (review.campaignBuildId) printCampaignArtifactDownload(review.status, review.campaignBuildId);
1088
1239
  console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
1089
1240
  if (Array.isArray(review.gates) && review.gates.length > 0) {
1090
1241
  console.log("\nGates:");
1091
1242
  for (const gate of review.gates) {
1092
- console.log(`- ${gate.passed ? "PASS" : "BLOCKED"} ${gate.label}: ${gate.detail}`);
1243
+ const status = String(gate.status || (gate.passed ? "pass" : "blocked")).toUpperCase();
1244
+ console.log(`- ${status} ${gate.label}: ${gate.detail}`);
1093
1245
  }
1094
1246
  }
1095
1247
  const warnings = Array.isArray(summary.warnings) ? summary.warnings : [];
@@ -1103,9 +1255,32 @@ function printCampaignAgentBuildReview(review) {
1103
1255
  for (const action of nextActions) console.log(`- ${action}`);
1104
1256
  }
1105
1257
  }
1258
+ function printCampaignAgentNorthStarScorecard(scorecard) {
1259
+ const card = asRecord(scorecard);
1260
+ if (!card.version) return;
1261
+ const score = card.score === null || card.score === void 0 ? "pending" : `${card.score}%`;
1262
+ console.log(`North Star: ${String(card.status || "unknown")} (${score})`);
1263
+ if (card.moatState) console.log(`Moat state: ${card.moatState}`);
1264
+ const metrics = Array.isArray(card.metrics) ? card.metrics : [];
1265
+ if (metrics.length > 0) {
1266
+ console.log("\nNorth Star gates:");
1267
+ for (const metric of metrics.slice(0, 12)) {
1268
+ const item = asRecord(metric);
1269
+ console.log(`- ${String(item.status || "review").toUpperCase()} ${item.label || item.id}: ${item.detail || ""}`);
1270
+ }
1271
+ }
1272
+ }
1106
1273
  function formatCampaignAgentRows(rows) {
1107
1274
  return rows.map((row) => {
1108
1275
  const data = asRecord(row.data);
1276
+ const copyData = asRecord(data.copy);
1277
+ const rawCopy = asRecord(data.raw_copy);
1278
+ const copy = {
1279
+ subject: data.subject || copyData.subject || rawCopy.subject || null,
1280
+ opener: data.opener || copyData.opener || rawCopy.opener || null,
1281
+ body: data.body || copyData.body || rawCopy.body || null,
1282
+ cta: data.cta || copyData.cta || rawCopy.cta || null
1283
+ };
1109
1284
  const fallbackName = `${data.first_name || ""} ${data.last_name || ""}`.trim() || null;
1110
1285
  return {
1111
1286
  ...row,
@@ -1115,7 +1290,8 @@ function formatCampaignAgentRows(rows) {
1115
1290
  company: data.company_name ?? null,
1116
1291
  domain: data.company_domain ?? null,
1117
1292
  score: data.overall_score ?? null,
1118
- has_copy: Boolean(data.subject || data.opener || data.body || data.cta || asRecord(data.raw_copy).subject)
1293
+ copy,
1294
+ has_copy: Boolean(copy.subject || copy.opener || copy.body || copy.cta)
1119
1295
  };
1120
1296
  });
1121
1297
  }
@@ -1133,9 +1309,41 @@ function printCampaignAgentRows(result) {
1133
1309
  segment: row.segment || "",
1134
1310
  score: row.score ?? ""
1135
1311
  })));
1312
+ printCampaignAgentCopySnippets(result.rows);
1136
1313
  console.log(`Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
1137
1314
  if (result.nextCursor) console.log(`Next: signaliz campaign-agent rows ${result.campaignBuildId} --cursor ${result.nextCursor}`);
1138
1315
  }
1316
+ function printCampaignArtifactDownload(status, buildId) {
1317
+ const downloads = Array.isArray(status?.artifactDownloads) ? status.artifactDownloads : Array.isArray(status?.artifact_downloads) ? status.artifact_downloads : [];
1318
+ const download = downloads.find((item) => String(item?.format || item?.artifactType || item?.artifact_type || "").toLowerCase() === "csv") || downloads[0];
1319
+ const url = download?.downloadUrl || download?.download_url || download?.signedUrl || download?.signed_url;
1320
+ if (typeof url === "string" && url.trim()) {
1321
+ const format = download?.format || download?.artifactType || download?.artifact_type || "artifact";
1322
+ const rowCount = Number(download?.rowCount ?? download?.row_count ?? 0);
1323
+ console.log(`Download: ${format}${rowCount > 0 ? `, ${rowCount} rows` : ""}`);
1324
+ console.log(` ${url}`);
1325
+ } else if (Number(status?.artifactCount ?? status?.artifact_count ?? 0) > 0) {
1326
+ console.log(`Next: signaliz campaign download ${buildId} --format csv`);
1327
+ }
1328
+ }
1329
+ function printCampaignAgentCopySnippets(rows, limit = 5) {
1330
+ const rowsWithCopy = rows.filter((row) => {
1331
+ const copy = asRecord(row.copy);
1332
+ return Boolean(copy.subject || copy.opener || copy.body || copy.cta);
1333
+ });
1334
+ if (rowsWithCopy.length === 0) return;
1335
+ console.log("\nCopy:");
1336
+ for (const row of rowsWithCopy.slice(0, limit)) {
1337
+ const copy = asRecord(row.copy);
1338
+ const label = row.email || row.name || row.company || `row ${row.index ?? ""}`.trim();
1339
+ console.log(`- ${label}`);
1340
+ if (copy.subject) console.log(` Subject: ${copy.subject}`);
1341
+ if (copy.opener) console.log(` Opener: ${copy.opener}`);
1342
+ if (copy.body) console.log(` Body: ${copy.body}`);
1343
+ if (copy.cta) console.log(` CTA: ${copy.cta}`);
1344
+ }
1345
+ if (rowsWithCopy.length > limit) console.log(` ...${rowsWithCopy.length - limit} more row(s) with copy`);
1346
+ }
1139
1347
  function asRecord(value) {
1140
1348
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1141
1349
  }
@@ -1171,6 +1379,8 @@ Usage:
1171
1379
  signaliz gtm agent-plan --goal "Build a strategy-template campaign" --strategy-template non-medical-home-care --target-count 500 --json
1172
1380
  signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool --json
1173
1381
  signaliz gtm memory search --query "proof-first vertical gate" --json
1382
+ signaliz gtm feedback instantly-pull --campaign-id <id> --source emails --email-type received --mode emode_all --sort-order asc --confirm-write --json
1383
+ signaliz gtm learning status --campaign-id <id> --json
1174
1384
  signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
1175
1385
  signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
1176
1386
  signaliz campaign-agent memory-kit --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json
@@ -1203,6 +1413,9 @@ Signaliz GTM commands:
1203
1413
  signaliz gtm provider-prepare --provider-id ID [--layer NAME] [--invocation-type webhook|mcp_tool|api] [--json]
1204
1414
  signaliz gtm activate-route --provider-id ID --layer NAME [--confirm] [--json]
1205
1415
  signaliz gtm memory search --query TEXT [--layers a,b] [--provider-chain a,b] [--limit N] [--json]
1416
+ signaliz gtm learning status (--campaign-id ID | --campaign-build-id ID) [--json]
1417
+ 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]
1418
+ signaliz gtm feedback instantly-webhook-prepare (--campaign-id ID | --provider-link-id ID) --confirm-write [--json]
1206
1419
  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
1420
  `);
1208
1421
  }
@@ -1212,16 +1425,16 @@ Signaliz campaign-agent commands:
1212
1425
 
1213
1426
  signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
1214
1427
  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]
1428
+ 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
1429
  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
1430
  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
1431
  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
1432
  signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
1220
1433
  signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
1221
1434
  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]
1435
+ signaliz campaign-agent review <campaign_build_id> [--limit N] [--qualified|--disqualified] [--include-data] [--include-raw] [--json]
1223
1436
  signaliz campaign-agent status <campaign_build_id> [--json]
1224
- signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--json]
1437
+ signaliz campaign-agent rows <campaign_build_id> [--limit N] [--cursor CURSOR] [--qualified|--disqualified] [--include-data] [--include-raw] [--json]
1225
1438
  signaliz campaign-agent artifacts <campaign_build_id> [--json]
1226
1439
  signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
1227
1440