@signaliz/sdk 1.0.15 → 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,30 +1,33 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- Signaliz,
4
- createCampaignBuilderAgentRequestTemplate,
5
- createCampaignBuilderApproval,
6
- createCampaignBuilderBuildKit
7
- } from "./chunk-6OZWMAV3.mjs";
8
2
 
9
3
  // src/cli.ts
10
4
  import { readFileSync, writeFileSync } from "fs";
11
5
  var apiKey = process.env.SIGNALIZ_API_KEY;
12
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
+ }
13
16
  async function main() {
14
17
  const command = process.argv[2];
15
18
  if (!command || command === "help" || command === "--help" || command === "-h") {
16
19
  printHelp();
17
20
  return;
18
21
  }
19
- const offlineCampaignAgentTemplate = (command === "campaign-agent" || command === "campaign-builder") && ["init", "template", "request-template", "new", "kit", "build-kit", "blueprint"].includes(String(process.argv[3] || ""));
22
+ const offlineCampaignAgentTemplate = (command === "campaign-agent" || command === "campaign-builder") && ["init", "template", "request-template", "new", "kit", "build-kit", "blueprint", "memory-kit", "seed-kit", "memory"].includes(String(process.argv[3] || ""));
20
23
  if (!apiKey && !offlineCampaignAgentTemplate) {
21
24
  console.error("\u274C SIGNALIZ_API_KEY environment variable is required.");
22
25
  console.error(" Set it with: export SIGNALIZ_API_KEY=sk_...");
23
26
  process.exit(1);
24
27
  }
25
- const signaliz = new Signaliz({ apiKey: apiKey || "offline", baseUrl });
26
28
  switch (command) {
27
29
  case "test": {
30
+ const signaliz = await createSignalizClient();
28
31
  try {
29
32
  const ws = await signaliz.getWorkspace();
30
33
  console.log(`\u2705 Connected to workspace: ${ws.name} (${ws.creditsRemaining.toLocaleString()} credits remaining)`);
@@ -35,6 +38,7 @@ async function main() {
35
38
  break;
36
39
  }
37
40
  case "tools": {
41
+ const signaliz = await createSignalizClient();
38
42
  try {
39
43
  const tools = await signaliz.listTools();
40
44
  console.log(`
@@ -54,12 +58,13 @@ async function main() {
54
58
  break;
55
59
  }
56
60
  case "gtm": {
61
+ const signaliz = await createSignalizClient();
57
62
  await handleGtmCommand(signaliz, process.argv.slice(3));
58
63
  break;
59
64
  }
60
65
  case "campaign-agent":
61
66
  case "campaign-builder": {
62
- await handleCampaignAgentCommand(signaliz, process.argv.slice(3));
67
+ await handleCampaignAgentCommand(createSignalizClient, process.argv.slice(3));
63
68
  break;
64
69
  }
65
70
  default:
@@ -116,6 +121,101 @@ async function handleGtmCommand(signaliz, argv) {
116
121
  printResult(result, flags);
117
122
  return;
118
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
+ }
119
219
  if (subcommand === "templates" || subcommand === "strategy-templates") {
120
220
  const flags = parseFlags(argv.slice(1));
121
221
  const result = await signaliz.gtm.campaignStrategyTemplates({
@@ -358,7 +458,7 @@ async function handleGtmCommand(signaliz, argv) {
358
458
  }
359
459
  printGtmHelp();
360
460
  }
361
- async function handleCampaignAgentCommand(signaliz, argv) {
461
+ async function handleCampaignAgentCommand(signalizFactory, argv) {
362
462
  const subcommand = argv[0];
363
463
  if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
364
464
  printCampaignAgentHelp();
@@ -366,7 +466,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
366
466
  }
367
467
  if (["init", "template", "request-template", "new"].includes(subcommand)) {
368
468
  const flags2 = parseFlags(argv.slice(1));
369
- const request2 = campaignAgentRequestTemplateFromFlags(flags2);
469
+ const request2 = await campaignAgentRequestTemplateFromFlags(flags2);
370
470
  const outputFile = stringFlag(flags2, "output-file", "out");
371
471
  if (outputFile) {
372
472
  writeFileSync(outputFile, `${JSON.stringify(request2, null, 2)}
@@ -382,12 +482,13 @@ async function handleCampaignAgentCommand(signaliz, argv) {
382
482
  }
383
483
  if (["kit", "build-kit", "blueprint"].includes(subcommand)) {
384
484
  const flags2 = parseFlags(argv.slice(1));
485
+ const { createCampaignBuilderBuildKit } = await loadSdk();
385
486
  const requestFromFile2 = campaignAgentRequestFileFromFlags(flags2);
386
487
  const fallbackGoal = stringFlag(flags2, "goal", "brief") || stringOrUndefined(requestFromFile2?.goal) || "Build a strategy-template campaign for mature operators in the target ICP.";
387
488
  const request2 = requestFromFile2 ? mergeCampaignAgentRequests(
388
489
  requestFromFile2,
389
490
  campaignAgentRequestFromFlags(fallbackGoal, flags2, { includeDefaults: false })
390
- ) : campaignAgentRequestTemplateFromFlags(flags2);
491
+ ) : await campaignAgentRequestTemplateFromFlags(flags2);
391
492
  const kit = createCampaignBuilderBuildKit({
392
493
  ...request2,
393
494
  includeLocalLeads: booleanFlag(flags2, "use-local-leads"),
@@ -412,14 +513,53 @@ async function handleCampaignAgentCommand(signaliz, argv) {
412
513
  }
413
514
  return;
414
515
  }
415
- if (["review", "status", "rows", "artifacts", "approve", "approve-delivery"].includes(subcommand)) {
416
- await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
516
+ if (["memory-kit", "seed-kit", "memory"].includes(subcommand)) {
517
+ const flags2 = parseFlags(argv.slice(1));
518
+ const { createCampaignBuilderMemoryKit } = await loadSdk();
519
+ const requestFromFile2 = campaignAgentRequestFileFromFlags(flags2);
520
+ const fallbackGoal = stringFlag(flags2, "goal", "brief") || stringOrUndefined(requestFromFile2?.goal) || "Build a strategy-template campaign for mature operators in the target ICP.";
521
+ const request2 = requestFromFile2 ? mergeCampaignAgentRequests(
522
+ requestFromFile2,
523
+ campaignAgentRequestFromFlags(fallbackGoal, flags2, { includeDefaults: false })
524
+ ) : await campaignAgentRequestTemplateFromFlags(flags2);
525
+ const kit = createCampaignBuilderMemoryKit({
526
+ ...request2,
527
+ includeLocalLeads: booleanFlag(flags2, "use-local-leads"),
528
+ includeCustomToolPlaceholder: booleanFlag(flags2, "with-byo-placeholder") || booleanFlag(flags2, "include-custom-tool-placeholder") || booleanFlag(flags2, "include-byo-placeholder"),
529
+ includeNango: !booleanFlag(flags2, "no-nango-catalog"),
530
+ requestFile: stringFlag(flags2, "request-output-file", "request-file-name") || stringFlag(flags2, "request-file") || "campaign-request.json",
531
+ seedManifestFile: stringFlag(flags2, "seed-manifest-file", "manifest") || ".gtm-kernel-import-state/campaign-memory-dry-run.json",
532
+ source: stringFlag(flags2, "source", "memory-source", "seed-source"),
533
+ workspaceId: stringFlag(flags2, "workspace-id"),
534
+ cliPackage: stringFlag(flags2, "cli-package"),
535
+ sdkPackage: stringFlag(flags2, "sdk-package")
536
+ });
537
+ const outputFile = stringFlag(flags2, "output-file", "kit-file", "out");
538
+ if (outputFile) {
539
+ writeFileSync(outputFile, `${JSON.stringify(kit, null, 2)}
540
+ `, "utf8");
541
+ }
542
+ if (booleanFlag(flags2, "json")) {
543
+ printJson(kit);
544
+ } else if (!outputFile) {
545
+ printCampaignAgentMemoryKit(kit);
546
+ } else {
547
+ console.log(`Campaign memory kit written: ${outputFile}`);
548
+ console.log(`Next: ${kit.cli_commands.find((command) => command.id === "memory_status")?.command}`);
549
+ }
417
550
  return;
418
551
  }
419
- if (!["plan", "doctor", "readiness", "preflight", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
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) {
420
555
  printCampaignAgentHelp();
421
556
  return;
422
557
  }
558
+ const signaliz = await signalizFactory();
559
+ if (isReviewCommand) {
560
+ await handleCampaignAgentReviewCommand(signaliz, subcommand, argv.slice(1));
561
+ return;
562
+ }
423
563
  const flags = parseFlags(argv.slice(1));
424
564
  const isDoctor = subcommand === "doctor" || subcommand === "readiness" || subcommand === "preflight";
425
565
  const requestFromFile = campaignAgentRequestFileFromFlags(flags);
@@ -493,6 +633,7 @@ async function handleCampaignAgentCommand(signaliz, argv) {
493
633
  }
494
634
  if (isApprovedBuild) {
495
635
  const approvedTypes = approvedTypesFromFlags(plan, flags);
636
+ const { createCampaignBuilderApproval } = await loadSdk();
496
637
  const approval = createCampaignBuilderApproval(plan, {
497
638
  approvedBy,
498
639
  approvedTypes,
@@ -537,6 +678,8 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
537
678
  cursor: stringFlag(flags, "cursor"),
538
679
  segment: stringFlag(flags, "segment"),
539
680
  rowStatus: stringFlag(flags, "row-status"),
681
+ includeData: optionalBooleanFlag(flags, "include-data"),
682
+ includeRaw: optionalBooleanFlag(flags, "include-raw"),
540
683
  qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
541
684
  });
542
685
  const operatorReview = {
@@ -568,6 +711,8 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
568
711
  cursor: stringFlag(flags, "cursor"),
569
712
  segment: stringFlag(flags, "segment"),
570
713
  rowStatus: stringFlag(flags, "row-status"),
714
+ includeData: optionalBooleanFlag(flags, "include-data"),
715
+ includeRaw: optionalBooleanFlag(flags, "include-raw"),
571
716
  qualified: booleanFlag(flags, "qualified") ? true : booleanFlag(flags, "disqualified") ? false : void 0
572
717
  });
573
718
  const operatorResult = {
@@ -611,7 +756,7 @@ async function handleCampaignAgentReviewCommand(signaliz, subcommand, argv) {
611
756
  if (result.message) console.log(result.message);
612
757
  }
613
758
  }
614
- function campaignAgentRequestTemplateFromFlags(flags) {
759
+ async function campaignAgentRequestTemplateFromFlags(flags) {
615
760
  const goal = stringFlag(flags, "goal", "brief") || "Build a strategy-template campaign for mature operators in the target ICP.";
616
761
  const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
617
762
  const options = {
@@ -620,6 +765,7 @@ function campaignAgentRequestTemplateFromFlags(flags) {
620
765
  includeCustomToolPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-custom-tool-placeholder") || booleanFlag(flags, "include-byo-placeholder"),
621
766
  includeNango: !booleanFlag(flags, "no-nango-catalog")
622
767
  };
768
+ const { createCampaignBuilderAgentRequestTemplate } = await loadSdk();
623
769
  return createCampaignBuilderAgentRequestTemplate(options);
624
770
  }
625
771
  function campaignAgentRequestFileFromFlags(flags) {
@@ -876,6 +1022,11 @@ function booleanFlag(flags, name, defaultValue = false) {
876
1022
  if (Array.isArray(value)) return value.length > 0 ? parseBoolean(value.at(-1), defaultValue) : defaultValue;
877
1023
  return parseBoolean(value, defaultValue);
878
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
+ }
879
1030
  function parseBoolean(value, defaultValue) {
880
1031
  if (value === void 0) return defaultValue;
881
1032
  if (typeof value === "boolean") return value;
@@ -957,6 +1108,26 @@ function printCampaignAgentBuildKit(kit) {
957
1108
  console.log("\nNext:");
958
1109
  for (const action of kit.next_actions.slice(0, 4)) console.log(`- ${action}`);
959
1110
  }
1111
+ function printCampaignAgentMemoryKit(kit) {
1112
+ console.log(`Campaign memory kit: ${kit.strategy_template || "custom strategy"}`);
1113
+ console.log(`Request file: ${kit.request_file}`);
1114
+ console.log(`Seed manifest: ${kit.seed_manifest_file}`);
1115
+ console.log(`Sources: ${kit.memory_sources.map((source) => source.id).join(", ") || "none"}`);
1116
+ console.log(`Playbooks: ${kit.operating_playbooks.join(", ") || "none"}`);
1117
+ console.log("\nCLI:");
1118
+ for (const command of kit.cli_commands.slice(0, 4)) {
1119
+ console.log(`- ${command.label}: ${command.command}`);
1120
+ }
1121
+ console.log("\nMCP:");
1122
+ for (const call of kit.mcp_calls.slice(0, 3)) {
1123
+ console.log(`- ${call.tool}: ${call.safety}`);
1124
+ }
1125
+ console.log("\nSeed runner:");
1126
+ console.log(`- Dry run: ${kit.seed_runner.dry_run_command}`);
1127
+ if (kit.seed_runner.verify_manifest_command) console.log(`- Verify: ${kit.seed_runner.verify_manifest_command}`);
1128
+ console.log("\nNext:");
1129
+ for (const action of kit.next_actions.slice(0, 4)) console.log(`- ${action}`);
1130
+ }
960
1131
  function printCampaignAgentExecution(payload, flags) {
961
1132
  if (booleanFlag(flags, "json")) {
962
1133
  printJson(payload);
@@ -1005,7 +1176,9 @@ function printCampaignAgentBuildStatus(status) {
1005
1176
  console.log(`Status: ${status.status}`);
1006
1177
  console.log(`Phase: ${status.currentPhase || "N/A"}`);
1007
1178
  console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
1179
+ printCampaignCustomerRowCounts(status);
1008
1180
  console.log(`Artifacts: ${status.artifactCount}`);
1181
+ if (status.campaignBuildId) printCampaignArtifactDownload(status, status.campaignBuildId);
1009
1182
  if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
1010
1183
  if (Array.isArray(status.warnings) && status.warnings.length > 0) {
1011
1184
  console.log(`Warnings: ${status.warnings.slice(0, 3).join("; ")}`);
@@ -1013,12 +1186,34 @@ function printCampaignAgentBuildStatus(status) {
1013
1186
  if (Array.isArray(status.errors) && status.errors.length > 0) {
1014
1187
  console.log(`Errors: ${status.errors.slice(0, 3).join("; ")}`);
1015
1188
  }
1016
- if (status.status === "completed") {
1189
+ if (status.status === "completed" && status.nextAction) {
1190
+ console.log(`Next: ${status.nextAction}`);
1191
+ } else if (status.status === "completed") {
1017
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}`);
1018
1197
  } else if (status.status === "pending_approval") {
1019
1198
  console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
1020
1199
  }
1021
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
+ }
1022
1217
  function printCampaignAgentBuildReview(review) {
1023
1218
  const summary = asRecord(review.summary);
1024
1219
  console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
@@ -1029,6 +1224,7 @@ function printCampaignAgentBuildReview(review) {
1029
1224
  console.log(`Emails: ${summary.rowsWithEmail || 0}`);
1030
1225
  console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
1031
1226
  console.log(`Artifacts: ${summary.artifactCount || 0}`);
1227
+ if (review.campaignBuildId) printCampaignArtifactDownload(review.status, review.campaignBuildId);
1032
1228
  console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
1033
1229
  if (Array.isArray(review.gates) && review.gates.length > 0) {
1034
1230
  console.log("\nGates:");
@@ -1050,6 +1246,14 @@ function printCampaignAgentBuildReview(review) {
1050
1246
  function formatCampaignAgentRows(rows) {
1051
1247
  return rows.map((row) => {
1052
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
+ };
1053
1257
  const fallbackName = `${data.first_name || ""} ${data.last_name || ""}`.trim() || null;
1054
1258
  return {
1055
1259
  ...row,
@@ -1059,7 +1263,8 @@ function formatCampaignAgentRows(rows) {
1059
1263
  company: data.company_name ?? null,
1060
1264
  domain: data.company_domain ?? null,
1061
1265
  score: data.overall_score ?? null,
1062
- 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)
1063
1268
  };
1064
1269
  });
1065
1270
  }
@@ -1077,9 +1282,41 @@ function printCampaignAgentRows(result) {
1077
1282
  segment: row.segment || "",
1078
1283
  score: row.score ?? ""
1079
1284
  })));
1285
+ printCampaignAgentCopySnippets(result.rows);
1080
1286
  console.log(`Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
1081
1287
  if (result.nextCursor) console.log(`Next: signaliz campaign-agent rows ${result.campaignBuildId} --cursor ${result.nextCursor}`);
1082
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
+ }
1083
1320
  function asRecord(value) {
1084
1321
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1085
1322
  }
@@ -1115,8 +1352,11 @@ Usage:
1115
1352
  signaliz gtm agent-plan --goal "Build a strategy-template campaign" --strategy-template non-medical-home-care --target-count 500 --json
1116
1353
  signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool --json
1117
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
1118
1357
  signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
1119
1358
  signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
1359
+ signaliz campaign-agent memory-kit --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json
1120
1360
  signaliz campaign-agent doctor --request-file campaign-request.json --json
1121
1361
  signaliz campaign-agent plan --goal "Build a strategy-template campaign..." --strategy-template industrial-ot-resilience --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
1122
1362
  signaliz campaign-agent proof --goal "Build a strategy-template campaign..." --strategy-template non-medical-home-care --target-count 100 --json
@@ -1146,6 +1386,9 @@ Signaliz GTM commands:
1146
1386
  signaliz gtm provider-prepare --provider-id ID [--layer NAME] [--invocation-type webhook|mcp_tool|api] [--json]
1147
1387
  signaliz gtm activate-route --provider-id ID --layer NAME [--confirm] [--json]
1148
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]
1149
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]
1150
1393
  `);
1151
1394
  }
@@ -1155,15 +1398,16 @@ Signaliz campaign-agent commands:
1155
1398
 
1156
1399
  signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
1157
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]
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]
1158
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]
1159
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]
1160
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]
1161
1405
  signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
1162
1406
  signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
1163
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]
1164
- 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]
1165
1409
  signaliz campaign-agent status <campaign_build_id> [--json]
1166
- 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]
1167
1411
  signaliz campaign-agent artifacts <campaign_build_id> [--json]
1168
1412
  signaliz campaign-agent approve <campaign_build_id> --destination-type json|csv|webhook [--destination-config JSON] [--json]
1169
1413