@signaliz/cli 1.0.5 → 1.0.8

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.
Files changed (3) hide show
  1. package/README.md +86 -0
  2. package/dist/bin.js +1360 -45
  3. package/package.json +14 -3
package/dist/bin.js CHANGED
@@ -150,15 +150,28 @@ var promptValueFlags = /* @__PURE__ */ new Set([
150
150
  "attachment-fields",
151
151
  "attachment-file",
152
152
  "attachment-url",
153
+ "account-context",
154
+ "account-context-file",
155
+ "account-label",
156
+ "approved-by",
157
+ "approved-route-ids",
158
+ "approved-types",
159
+ "approval-notes",
160
+ "allowed-integrations",
153
161
  "blueprint",
154
162
  "brain-config-file",
155
163
  "brain-config-json",
164
+ "brain-defaults",
156
165
  "build-id",
157
166
  "cadence",
158
167
  "campaign-build-id",
159
168
  "campaign-id",
160
169
  "campaign-brief",
170
+ "campaign-name",
161
171
  "brief",
172
+ "builtins",
173
+ "builtin-tools",
174
+ "byo-tool",
162
175
  "company-domains",
163
176
  "company-domain",
164
177
  "company-name",
@@ -166,12 +179,15 @@ var promptValueFlags = /* @__PURE__ */ new Set([
166
179
  "context-json",
167
180
  "copy-file",
168
181
  "copy-json",
182
+ "custom-tool",
183
+ "customer-tool",
169
184
  "destination",
170
185
  "destinations",
171
186
  "days",
172
187
  "dedup-keys",
173
188
  "delivery-file",
174
189
  "delivery-json",
190
+ "delivery-risk",
175
191
  "delivery-risk-file",
176
192
  "delivery-risk-json",
177
193
  "domains",
@@ -184,6 +200,9 @@ var promptValueFlags = /* @__PURE__ */ new Set([
184
200
  "input-json",
185
201
  "instantly-campaign-id",
186
202
  "idempotency-key",
203
+ "icp",
204
+ "integration-display-name",
205
+ "integration-route",
187
206
  "judge-model",
188
207
  "layer",
189
208
  "layers",
@@ -193,6 +212,8 @@ var promptValueFlags = /* @__PURE__ */ new Set([
193
212
  "max-concurrency",
194
213
  "max-retries",
195
214
  "max-tokens",
215
+ "max-credits",
216
+ "max-credits-without-approval",
196
217
  "memory-limit",
197
218
  "memory-type",
198
219
  "model",
@@ -202,17 +223,21 @@ var promptValueFlags = /* @__PURE__ */ new Set([
202
223
  "nango-connection-id",
203
224
  "network-days",
204
225
  "output-format",
226
+ "output-file",
205
227
  "output-fields",
206
228
  "output-fields-file",
207
229
  "outcome-type",
208
230
  "pdf-engine",
209
231
  "pdf-url",
210
232
  "phases",
233
+ "privacy-mode",
211
234
  "policy-file",
212
235
  "policy-json",
236
+ "partners",
213
237
  "provider",
214
238
  "providers",
215
239
  "preferred-providers",
240
+ "provider-display-name",
216
241
  "provider-account-id",
217
242
  "provider-campaign-id",
218
243
  "provider-config-key",
@@ -222,8 +247,10 @@ var promptValueFlags = /* @__PURE__ */ new Set([
222
247
  "provider-workspace-id",
223
248
  "qualification-file",
224
249
  "qualification-json",
250
+ "request-file",
225
251
  "records-file",
226
252
  "records-json",
253
+ "revenue-motion",
227
254
  "readiness-json",
228
255
  "rationale",
229
256
  "route-config-json",
@@ -232,22 +259,36 @@ var promptValueFlags = /* @__PURE__ */ new Set([
232
259
  "search",
233
260
  "send-config-file",
234
261
  "send-config-json",
262
+ "signaliz-tools",
235
263
  "signals-file",
236
264
  "signals-json",
265
+ "spend-limit",
266
+ "spend-limit-credits",
237
267
  "status",
238
268
  "status-url",
269
+ "source",
270
+ "strategy-model",
271
+ "strategy-template",
239
272
  "system-prompt",
240
273
  "target-count",
274
+ "target-icp",
241
275
  "target-icp-file",
242
276
  "target-icp-json",
243
277
  "temperature",
244
278
  "tool-name",
245
279
  "url",
280
+ "user-display-name",
281
+ "user-email",
246
282
  "video-url",
247
283
  "write-mode",
248
284
  "workspace-connection-id",
249
285
  "workspace-integration-id",
286
+ "workspace-label",
250
287
  "workspace-mcp-server-id",
288
+ "workspace-context",
289
+ "workspace-context-file",
290
+ "icp-file",
291
+ "brain-defaults-file",
251
292
  "memory-dimension-filters-file",
252
293
  "memory-dimension-filters-json",
253
294
  "metadata-file",
@@ -272,6 +313,84 @@ function promptArg(rest) {
272
313
  }
273
314
  return parts.join(" ").trim() || void 0;
274
315
  }
316
+ function parseCommandFlags(argv) {
317
+ const flags = {};
318
+ for (let i = 0; i < argv.length; i += 1) {
319
+ const token = argv[i];
320
+ if (!token.startsWith("--")) continue;
321
+ const eq = token.indexOf("=");
322
+ const name = normalizeCommandFlagName(eq >= 0 ? token.slice(2, eq) : token.slice(2));
323
+ const value = eq >= 0 ? token.slice(eq + 1) : argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : true;
324
+ const current = flags[name];
325
+ if (current === void 0) {
326
+ flags[name] = value;
327
+ } else if (Array.isArray(current)) {
328
+ current.push(String(value));
329
+ } else {
330
+ flags[name] = [String(current), String(value)];
331
+ }
332
+ }
333
+ return flags;
334
+ }
335
+ function normalizeCommandFlagName(name) {
336
+ return name.replace(/_/g, "-");
337
+ }
338
+ function commandFlagValue(flags, ...names) {
339
+ for (const name of names.map(normalizeCommandFlagName)) {
340
+ if (flags[name] !== void 0) return flags[name];
341
+ }
342
+ return void 0;
343
+ }
344
+ function commandStringFlag(flags, ...names) {
345
+ const value = commandFlagValue(flags, ...names);
346
+ if (Array.isArray(value)) return value.at(-1);
347
+ if (value === void 0 || typeof value === "boolean") return void 0;
348
+ const trimmed = String(value).trim();
349
+ return trimmed || void 0;
350
+ }
351
+ function commandNumberFlag(flags, ...names) {
352
+ const value = commandStringFlag(flags, ...names);
353
+ if (!value) return void 0;
354
+ const parsed = Number(value);
355
+ if (!Number.isFinite(parsed)) die(`Expected numeric value for --${names[0]}`);
356
+ return parsed;
357
+ }
358
+ function commandBooleanFlag(flags, name, defaultValue = false) {
359
+ const value = commandFlagValue(flags, name);
360
+ if (value === void 0) return defaultValue;
361
+ if (Array.isArray(value)) return value.length > 0 ? parseCommandBoolean(value.at(-1), defaultValue) : defaultValue;
362
+ return parseCommandBoolean(value, defaultValue);
363
+ }
364
+ function parseCommandBoolean(value, defaultValue) {
365
+ if (value === void 0) return defaultValue;
366
+ if (typeof value === "boolean") return value;
367
+ return !["0", "false", "no", "off"].includes(value.toLowerCase());
368
+ }
369
+ function commandCsvFlag(flags, ...names) {
370
+ const value = commandFlagValue(flags, ...names);
371
+ const values = Array.isArray(value) ? value : value === void 0 || typeof value === "boolean" ? [] : [value];
372
+ const parsed = values.flatMap((item) => String(item).split(",").map((part) => part.trim()).filter(Boolean));
373
+ return parsed.length > 0 ? parsed : void 0;
374
+ }
375
+ function repeatedCommandStringFlag(flags, ...names) {
376
+ const value = commandFlagValue(flags, ...names);
377
+ if (Array.isArray(value)) return value.map(String).map((item) => item.trim()).filter(Boolean);
378
+ if (value === void 0 || typeof value === "boolean") return [];
379
+ const trimmed = String(value).trim();
380
+ return trimmed ? [trimmed] : [];
381
+ }
382
+ function commandJsonObjectFlag(flags, ...names) {
383
+ const value = commandStringFlag(flags, ...names);
384
+ if (!value) return void 0;
385
+ return parseJsonObjectFromString(value, `--${names[0]}`);
386
+ }
387
+ function parseJsonObjectFromString(value, label) {
388
+ const parsed = JSON.parse(value);
389
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
390
+ die(`${label} must be a JSON object`);
391
+ }
392
+ return parsed;
393
+ }
275
394
  function output(data, humanFn) {
276
395
  if (jsonMode()) {
277
396
  console.log(JSON.stringify(data, null, 2));
@@ -706,7 +825,7 @@ function getSdk() {
706
825
  try {
707
826
  const { Signaliz } = require("@signaliz/sdk");
708
827
  const sdk = createSdk(Signaliz);
709
- if (sdk.campaigns?.buildCampaign && sdk.ops?.listOutputSinks && sdk.leads?.generate && sdk.emails?.verify && sdk.ai?.multiModel && sdk.gtm?.campaignBuildPlan && sdk.gtm?.commitCampaignBuildPlan && sdk.gtm?.prepareCampaignBuildExecution && sdk.gtm?.listNangoTools && sdk.gtm?.callNangoTool && sdk.gtm?.getNangoActionResult && sdk.getPlatformHealth) return sdk;
828
+ if (sdk.campaigns?.buildCampaign && sdk.ops?.listOutputSinks && sdk.leads?.generate && sdk.emails?.verify && sdk.ai?.multiModel && sdk.gtm?.campaignBuildPlan && sdk.gtm?.campaignStrategyTemplates && sdk.gtm?.campaignStartContext && sdk.gtm?.campaignAgentPlan && sdk.gtm?.commitCampaignBuildPlan && sdk.gtm?.prepareCampaignBuildExecution && sdk.gtm?.prepareProviderRecipe && sdk.gtm?.activateProviderRoute && sdk.gtm?.createNangoConnectSession && sdk.gtm?.listNangoTools && sdk.gtm?.callNangoTool && sdk.gtm?.getNangoActionResult && sdk.campaignBuilderAgent?.createPlan && sdk.campaignBuilderAgent?.commitPlan && sdk.campaignBuilderAgent?.dryRunPlan && sdk.campaignBuilderAgent?.buildApprovedPlan && sdk.getPlatformHealth) return sdk;
710
829
  primaryError = new Error("SDK missing required GTM workflow APIs");
711
830
  } catch (err) {
712
831
  primaryError = err;
@@ -732,19 +851,23 @@ var HELP = `signaliz <command> [options]
732
851
 
733
852
  Quick Start:
734
853
  signaliz auth login
854
+
855
+ No-spend agent path:
735
856
  signaliz start
736
857
  signaliz build "Build a campaign for industrial maintenance buyers"
737
858
  signaliz connect
738
859
  signaliz audit
739
860
  signaliz improve <campaign_id>
740
- signaliz prove
861
+ signaliz prove # alias: signaliz proof
741
862
  signaliz health
742
863
  signaliz tools
864
+
865
+ Spendful path after review:
743
866
  signaliz ops plan "Monitor key accounts daily and alert Slack"
744
867
  signaliz ops create "Build 100 verified VP Sales leads" --confirm-spend
745
868
  signaliz autopilot
746
- signaliz execute "Launch a CMM-style campaign for my ICP" --dry-run
747
- signaliz campaign build --prompt "VP Sales at B2B SaaS" --target-count 100
869
+ signaliz execute "Launch a strategy-template campaign for my ICP" --dry-run
870
+ signaliz campaign build --prompt "VP Sales at B2B SaaS" --target-count 100 --dry-run
748
871
  signaliz campaign build --prompt "VP Sales at B2B SaaS" --confirm-spend
749
872
  signaliz campaign status <campaign_build_id>
750
873
  signaliz campaign rows <campaign_build_id> --limit 100
@@ -760,13 +883,14 @@ Auth:
760
883
  start Recommend where to begin across Build, Connect, Audit, Improve, and Ops proof
761
884
  --campaign-brief "..." Optional brief for the suggested campaign-plan command
762
885
  --json Machine-readable onboarding state
886
+ --include-raw Include full raw MCP diagnostics in JSON output
763
887
 
764
888
  Simple Jobs:
765
889
  build "brief" Plan a campaign without spending credits
766
890
  connect Inspect blocked provider/tool routes
767
891
  audit Find previous campaigns to audit
768
892
  improve <campaign_id> Plan Brain learning for a campaign
769
- prove Prove Ops delivery readiness
893
+ prove/proof Prove Ops delivery readiness
770
894
 
771
895
  Discovery:
772
896
  tools List available MCP tools
@@ -825,6 +949,26 @@ GTM Kernel:
825
949
  --campaign-id ID Optional campaign scope
826
950
  --days N Lookback window, default server-side
827
951
  --include-samples Include diagnostic samples when supported
952
+ gtm templates List private-safe campaign strategy templates
953
+ --query TEXT Optional text filter
954
+ --strategy-template ID
955
+ Inspect one template
956
+ gtm start-context Build read-only campaign-start MCP runbook
957
+ --strategy-template ID
958
+ Merge a private-safe strategy template
959
+ --target-count N Desired lead count
960
+ gtm strategy-memory Inspect strategy/workflow memory readiness
961
+ --strategy-template ID
962
+ Verify a private-safe strategy template
963
+ --include-samples Include sanitized memory sample metadata
964
+ gtm agent-template Build hosted reusable campaign request JSON
965
+ --strategy-template ID
966
+ Merge a private-safe strategy template
967
+ --with-byo-placeholder
968
+ Add an editable custom MCP route placeholder
969
+ gtm agent-plan Build one-call campaign-agent MCP runbook
970
+ --builtins a,b Native lanes: lead_generation, local_leads, email_finding, email_verification, signals
971
+ --custom-tool ROUTE BYO route: provider:layer:tool[:mcp]
828
972
  gtm plan "brief" Compose a read-only GTM Kernel campaign build plan
829
973
  --layers a,b Optional GTM layers to plan
830
974
  --target-count N Desired lead count
@@ -872,6 +1016,10 @@ GTM Kernel:
872
1016
  gtm route-preview Preview the effective provider route for a layer
873
1017
  --campaign-id ID Optional campaign scope
874
1018
  --layer LAYER Required campaign layer
1019
+ gtm provider-prepare Build read-only BYO provider setup plan
1020
+ --provider-id ID Required provider ID
1021
+ --layer LAYER Optional route preview layer
1022
+ --invocation-type T webhook|mcp_tool|api|airbyte|managed_integration|manual
875
1023
  gtm activate-route Dry-run or confirm provider route setup
876
1024
  --provider-id ID Required provider ID
877
1025
  --layer LAYER Single layer, or use --layers a,b
@@ -887,6 +1035,9 @@ Native GTM Data Sources:
887
1035
  gtm find "<intent>" Auto-route a free-text intent to the right capability
888
1036
  gtm run --capability ID Run a GTM capability (use --query, --urls, --confirm-spend)
889
1037
  gtm status <job_id> Check GTM job status
1038
+ gtm nango connect Start Nango Connect auth for a provider
1039
+ --provider-id ID Provider to authorize, e.g. apollo, hubspot
1040
+ --integration-id ID Optional Nango integration/provider-config key
890
1041
  gtm nango tools List Nango action tools for a workspace connection
891
1042
  --workspace-connection-id ID
892
1043
  Signaliz workspace connection id
@@ -911,10 +1062,26 @@ Email:
911
1062
  email status <job_id> Check async email job status
912
1063
 
913
1064
  Campaign Builder:
914
- campaign scope Scope a client campaign into a markdown brief + dry-run args
1065
+ campaign-agent init Emit reusable CampaignBuilderAgentRequest JSON
1066
+ --output-file FILE Optional request file to write
1067
+ campaign-agent plan Compose an approval-gated strategy-template MCP flow
1068
+ --goal "..." Campaign goal or brief
1069
+ --request-file FILE Reusable JSON CampaignBuilderAgentRequest
1070
+ --strategy-template ID
1071
+ Merge a private-safe strategy template
1072
+ --builtins a,b lead_generation,local_leads,email_finding,email_verification,signals
1073
+ --custom-tool ROUTE BYO route: provider:layer:tool[:mcp]
1074
+ campaign-agent proof Prove memory, plan, approvals, and build dry-run without spend
1075
+ campaign-agent commit-plan
1076
+ Dry-run or write a reviewed GTM campaign object
1077
+ campaign-agent dry-run Execute build_campaign with dry_run=true
1078
+ campaign-agent build-approved
1079
+ Launch only after explicit approval metadata
1080
+
1081
+ campaign scope Scope a workspace/account campaign into a markdown brief + dry-run args
915
1082
  --prompt "..." Campaign request or outcome (required)
916
- --client-name NAME Client/customer name
917
- --client-context-file FILE
1083
+ --account-label NAME Workspace/account label
1084
+ --account-context-file FILE
918
1085
  Markdown/notes with ICP, exclusions, offer, proof, approvals
919
1086
  --target-count N Desired target count
920
1087
  --destinations csv,instantly,slack
@@ -928,6 +1095,7 @@ Campaign Builder:
928
1095
  --dry-run Validate and plan without launching spendful work
929
1096
  --allow-downscale Allow oversized target counts to be clamped
930
1097
  --confirm-spend Acknowledge spendful generation after approval prompts
1098
+ --no-progress Hide wait-mode progress on stderr
931
1099
  --webhook-url URL Webhook delivery endpoint
932
1100
  --input-file FILE JSON config file (overrides flags)
933
1101
  --wait Poll until completion
@@ -1068,17 +1236,41 @@ New-user path:
1068
1236
  signaliz auth login
1069
1237
  signaliz gtm context
1070
1238
  signaliz gtm bootstrap --include-samples
1239
+ signaliz gtm templates
1240
+ signaliz gtm start-context --strategy-template non-medical-home-care --json
1241
+ signaliz gtm strategy-memory --strategy-template non-medical-home-care --include-samples --json
1242
+ signaliz gtm agent-template --strategy-template non-medical-home-care --target-count 250 --with-byo-placeholder --json
1243
+ signaliz gtm agent-plan --strategy-template non-medical-home-care --target-count 100 --json
1071
1244
  signaliz gtm plan "Find CTOs at Series B fintech companies" --target-count 100 --json > plan.json
1072
1245
  signaliz gtm commit-plan --plan-file plan.json
1073
1246
  signaliz gtm commit-plan --plan-file plan.json --confirm
1074
1247
  signaliz gtm integrations --include-planned
1248
+ signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool
1075
1249
  signaliz gtm activate-route --provider-id instantly --layer sender
1076
1250
  signaliz gtm prepare-build <campaign_id> --build-input --json > build-args.json
1077
1251
  signaliz campaign build --input-file build-args.json --confirm-spend
1252
+ signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
1253
+ signaliz campaign-agent plan --goal "Build a strategy-template campaign for my ICP" --strategy-template non-medical-home-care --json
1254
+ signaliz campaign-agent dry-run --goal "Build a strategy-template campaign for my ICP" --target-count 100 --json
1078
1255
 
1079
1256
  Read-only planning:
1080
1257
  context Inspect GTM Kernel workspace context
1081
1258
  bootstrap Inspect Kernel + Brain readiness gates
1259
+ templates List private-safe campaign strategy templates
1260
+ start-context Build read-only Memory, Brain, risk, and route runbook
1261
+ strategy-memory Inspect strategy/workflow memory readiness
1262
+ agent-template Build hosted reusable campaign request JSON
1263
+ --goal TEXT Campaign goal or brief
1264
+ --strategy-template ID
1265
+ Strategy template to merge
1266
+ --with-byo-placeholder
1267
+ Add an editable custom MCP route placeholder
1268
+ agent-plan Build one-call campaign-agent MCP runbook
1269
+ --goal TEXT Campaign goal or brief
1270
+ --strategy-template ID
1271
+ Strategy template to merge
1272
+ --builtins a,b Native lanes to include
1273
+ --custom-tool ROUTE BYO route: provider:layer:tool[:mcp]
1082
1274
  plan "brief" Compose Memory, Brain, failure, and provider-route plan
1083
1275
  --campaign-id ID Optional existing campaign scope
1084
1276
  --campaign-build-id ID
@@ -1113,6 +1305,7 @@ Status and repair:
1113
1305
  execution <id> Inspect execution/provider readiness
1114
1306
  integrations Inspect provider activation cards
1115
1307
  route-preview Preview effective route for a layer
1308
+ provider-prepare Build read-only recipe, route, and preview arguments
1116
1309
  activate-route Dry-run or confirm provider route setup
1117
1310
  feedback-webhook Prepare feedback ingress
1118
1311
  learning <id> Plan Brain learning
@@ -1153,6 +1346,132 @@ Options:
1153
1346
  --include-samples Include safe sample rows/evidence where available
1154
1347
  --min-sample-size N Minimum sample size for Brain/readiness checks
1155
1348
  --json Machine-readable output
1349
+ `,
1350
+ templates: `signaliz gtm templates [options]
1351
+
1352
+ List private-safe campaign strategy templates that can be merged into
1353
+ gtm_campaign_build_plan with --strategy-template.
1354
+
1355
+ Options:
1356
+ --query TEXT Filter by ICP, motion, provider, or keyword
1357
+ --strategy-template ID Inspect one template
1358
+ --summary Return compact summaries instead of full ICP details
1359
+ --json Machine-readable output
1360
+ `,
1361
+ "strategy-templates": `signaliz gtm strategy-templates [options]
1362
+
1363
+ Alias for signaliz gtm templates.
1364
+ `,
1365
+ "start-context": `signaliz gtm start-context [options]
1366
+
1367
+ Build a read-only MCP runbook for the campaign start: ranked memory, Brain
1368
+ defaults, delivery risk, failure patterns, provider-route previews, and final
1369
+ gtm_campaign_build_plan arguments.
1370
+
1371
+ Options:
1372
+ --brief TEXT Campaign request or goal
1373
+ --campaign-id ID Optional existing campaign scope
1374
+ --campaign-build-id ID Optional Campaign Builder build scope
1375
+ --strategy-template ID Strategy template to merge
1376
+ --target-count N Desired lead count
1377
+ --layers a,b GTM layers to include
1378
+ --preferred-providers a,b
1379
+ Provider preferences for route planning
1380
+ --target-icp-json JSON Structured ICP object
1381
+ --target-icp-file FILE Structured ICP JSON file
1382
+ --no-memory Skip workspace memory call
1383
+ --no-brain Skip Brain defaults call
1384
+ --no-provider-routes Skip provider-route calls
1385
+ --no-failure-patterns Skip Brain failure-pattern call
1386
+ --no-delivery-risk Skip delivery-risk call
1387
+ --json Machine-readable output
1388
+ `,
1389
+ start: `signaliz gtm start [options]
1390
+
1391
+ Alias for signaliz gtm start-context.
1392
+ `,
1393
+ "strategy-memory": `signaliz gtm strategy-memory [options]
1394
+
1395
+ Inspect private-safe strategy/workflow memory readiness before campaign planning.
1396
+
1397
+ Options:
1398
+ --query TEXT Campaign goal or memory query
1399
+ --strategy-template ID Strategy template to verify
1400
+ --target-icp-json JSON Structured ICP object
1401
+ --target-icp-file FILE Structured ICP JSON file
1402
+ --memory-dimension-filters-json JSON
1403
+ Structured memory filters
1404
+ --include-samples Include sanitized memory sample metadata
1405
+ --no-sources Omit source-group details
1406
+ --json Machine-readable output
1407
+ `,
1408
+ "memory-status": `signaliz gtm memory-status [options]
1409
+
1410
+ Alias for signaliz gtm strategy-memory.
1411
+ `,
1412
+ "strategy-memory-status": `signaliz gtm strategy-memory-status [options]
1413
+
1414
+ Alias for signaliz gtm strategy-memory.
1415
+ `,
1416
+ "agent-template": `signaliz gtm agent-template [options]
1417
+
1418
+ Build hosted reusable CampaignBuilderAgentRequest JSON from a strategy template,
1419
+ Signaliz-native lanes, private memory settings, Nango catalog preference, and an
1420
+ optional editable BYO integration placeholder.
1421
+
1422
+ Options:
1423
+ --goal TEXT Campaign goal or brief
1424
+ --campaign-name NAME Optional private-safe campaign label
1425
+ --workspace-label NAME Optional private-safe workspace/account label
1426
+ --account-context TEXT Optional private-safe ICP, offer, or approval context
1427
+ --strategy-template ID Strategy template to merge
1428
+ --operating-playbooks a,b
1429
+ Optional playbook slugs to apply with the template
1430
+ --target-count N Desired lead/account count
1431
+ --target-icp-json JSON Structured ICP object
1432
+ --target-icp-file FILE Structured ICP JSON file
1433
+ --builtins a,b lead_generation,local_leads,email_finding,email_verification,signals
1434
+ --use-local-leads Add the local_leads native lane
1435
+ --with-byo-placeholder Add an editable custom MCP route placeholder
1436
+ --preferred-providers a,b
1437
+ Provider preferences or BYO provider ids
1438
+ --privacy-mode MODE workspace_only, anonymized_patterns, opt_in_network
1439
+ --destination TYPE json, csv, webhook
1440
+ --json Machine-readable output
1441
+ `,
1442
+ "campaign-agent-template": `signaliz gtm campaign-agent-template [options]
1443
+
1444
+ Alias for signaliz gtm agent-template.
1445
+ `,
1446
+ "request-template": `signaliz gtm request-template [options]
1447
+
1448
+ Alias for signaliz gtm agent-template.
1449
+ `,
1450
+ "agent-plan": `signaliz gtm agent-plan [options]
1451
+
1452
+ Build a one-call, read-only campaign-agent MCP runbook from a strategy template,
1453
+ Signaliz-native lanes, Memory, Brain, Nango discovery, and BYO integration routes.
1454
+
1455
+ Options:
1456
+ --goal TEXT Campaign goal or brief
1457
+ --campaign-name NAME Optional private-safe campaign label
1458
+ --campaign-id ID Optional existing campaign scope
1459
+ --campaign-build-id ID Optional Campaign Builder build scope
1460
+ --strategy-template ID Strategy template to merge
1461
+ --target-count N Desired lead/account count
1462
+ --target-icp-json JSON Structured ICP object
1463
+ --target-icp-file FILE Structured ICP JSON file
1464
+ --builtins a,b lead_generation,local_leads,email_finding,email_verification,signals
1465
+ --use-local-leads Add the local_leads native lane
1466
+ --custom-tool ROUTE BYO route: provider:layer:tool[:mcp] or key=value pairs
1467
+ --preferred-providers a,b
1468
+ Provider preferences or BYO provider ids
1469
+ --no-delivery-risk Skip delivery-risk preflight
1470
+ --json Machine-readable output
1471
+ `,
1472
+ "campaign-agent-plan": `signaliz gtm campaign-agent-plan [options]
1473
+
1474
+ Alias for signaliz gtm agent-plan.
1156
1475
  `,
1157
1476
  plan: `signaliz gtm plan "campaign brief" [options]
1158
1477
 
@@ -1162,10 +1481,16 @@ defaults, failure intelligence, provider routes, and approval boundaries.
1162
1481
  Options:
1163
1482
  --campaign-id ID Optional existing campaign scope
1164
1483
  --campaign-build-id ID Optional Campaign Builder build scope
1484
+ --strategy-template ID Strategy template: industrial-ot-resilience, non-medical-home-care, agency-founder-led, cloud-infrastructure-displacement
1165
1485
  --target-count N Desired lead count
1166
1486
  --layers a,b GTM layers to include
1167
1487
  --preferred-providers a,b
1168
1488
  Provider preferences for route planning
1489
+ --strategy-model custom Optional custom strategy model override
1490
+ --partners a,b Partner/tool ecosystem hints
1491
+ --no-agency-patterns Disable default private strategy pattern hints
1492
+ --no-workflow-patterns Disable default workflow table pattern hints
1493
+ --no-nango-catalog Skip Nango tool catalog discovery
1169
1494
  --target-icp-json JSON Structured ICP object
1170
1495
  --target-icp-file FILE Structured ICP JSON file
1171
1496
  --include-planned Include planned/needs-setup providers
@@ -1176,7 +1501,7 @@ Options:
1176
1501
  --json Machine-readable output
1177
1502
 
1178
1503
  Safe next step:
1179
- signaliz gtm plan "Find CTOs at fintech startups" --target-count 100 --json > plan.json
1504
+ signaliz gtm plan "Find CTOs at fintech startups" --strategy-template cloud-infrastructure-displacement --target-count 100 --json > plan.json
1180
1505
  signaliz gtm commit-plan --plan-file plan.json
1181
1506
  `,
1182
1507
  "build-plan": `signaliz gtm build-plan "campaign brief" [options]
@@ -1322,6 +1647,34 @@ Options:
1322
1647
  "preview-route": `signaliz gtm preview-route --layer <layer> [options]
1323
1648
 
1324
1649
  Alias for signaliz gtm route-preview.
1650
+ `,
1651
+ "provider-prepare": `signaliz gtm provider-prepare --provider-id <provider_id> [options]
1652
+
1653
+ Build a read-only BYO provider setup plan. Returns exact recipe, route,
1654
+ preview, and activation arguments without writing state or calling providers.
1655
+
1656
+ Options:
1657
+ --provider-id ID Provider id, for example customer_mcp
1658
+ --provider-name NAME Display name for the provider
1659
+ --layer NAME Layer to preview route setup for
1660
+ --layers a,b Recipe layer capabilities
1661
+ --invocation-type TYPE webhook|mcp_tool|api|airbyte|managed_integration|manual
1662
+ --auth-strategy TYPE none|integration_key|mcp_auth|webhook_secret|session_vault|byo_runtime
1663
+ --endpoint-url URL Webhook or API endpoint
1664
+ --workspace-mcp-server-id ID
1665
+ Existing workspace MCP server reference
1666
+ --workspace-connection-id ID
1667
+ Existing workspace connection reference
1668
+ --no-signaliz-fallback Disable Signaliz fallback for route preview
1669
+ --json Machine-readable output
1670
+ `,
1671
+ "prepare-provider": `signaliz gtm prepare-provider --provider-id <provider_id> [options]
1672
+
1673
+ Alias for signaliz gtm provider-prepare.
1674
+ `,
1675
+ "recipe-prepare": `signaliz gtm recipe-prepare --provider-id <provider_id> [options]
1676
+
1677
+ Alias for signaliz gtm provider-prepare.
1325
1678
  `,
1326
1679
  "activate-route": `signaliz gtm activate-route --provider-id <provider_id> --layer <layer> [options]
1327
1680
 
@@ -1497,14 +1850,14 @@ Run: signaliz ops help <command>
1497
1850
  return OPS_COMMAND_HELP[sub] || opsHelpFor(void 0);
1498
1851
  }
1499
1852
  var CAMPAIGN_COMMAND_HELP = {
1500
- scope: `signaliz campaign scope --prompt "client campaign request" [options]
1853
+ scope: `signaliz campaign scope --prompt "campaign request" [options]
1501
1854
 
1502
- Turn a client/campaign brief into a markdown scope, Brain preflight, and
1855
+ Turn a campaign brief into a markdown scope, Brain preflight, and
1503
1856
  ready-to-run build_campaign dry-run arguments.
1504
1857
 
1505
1858
  Options:
1506
- --client-name NAME Client/customer name
1507
- --client-context-file FILE
1859
+ --account-label NAME Workspace/account label
1860
+ --account-context-file FILE
1508
1861
  Markdown notes with ICP, exclusions, offer, proof, approvals
1509
1862
  --target-count N Desired target count
1510
1863
  --destinations a,b json,csv,webhook,instantly,slack,airbyte,nango
@@ -1747,6 +2100,16 @@ async function start() {
1747
2100
  const bootstrap = bootstrapState.ok ? record(bootstrapState.data) : {};
1748
2101
  const integrations = integrationsState.ok ? record(integrationsState.data) : {};
1749
2102
  const integrationSummary = record(integrations.summary);
2103
+ const integrationLayers = firstArray(
2104
+ integrations.layers || integrations.route_cards || integrations.items || integrations.routes
2105
+ );
2106
+ const providerBlockers = integrationLayers.filter((layer) => layer.ready === false || layer.status === "needs_route" || layer.status === "blocked").map((layer) => ({
2107
+ layer: layer.layer,
2108
+ label: layer.label || layer.layer,
2109
+ status: layer.status || (layer.ready === false ? "blocked" : "unknown"),
2110
+ blockers: firstArray(record(layer.readiness).blockers || layer.blockers),
2111
+ next_tools: firstArray(layer.next_tools || layer.nextTools)
2112
+ }));
1750
2113
  const gates = firstArray(bootstrap.gates);
1751
2114
  const readyGates = gates.filter((gate) => gate.ready === true || gate.status === "ready").length;
1752
2115
  const blockedLayers = Number(integrationSummary.blocked_layers || 0);
@@ -1792,7 +2155,8 @@ async function start() {
1792
2155
  kernel_gates_total: gates.length,
1793
2156
  provider_layers_ready: readyLayers,
1794
2157
  provider_layers_total: totalLayers,
1795
- provider_layers_blocked: blockedLayers
2158
+ provider_layers_blocked: blockedLayers,
2159
+ provider_blockers: providerBlockers
1796
2160
  },
1797
2161
  next_move: {
1798
2162
  title: nextMove,
@@ -1800,13 +2164,15 @@ async function start() {
1800
2164
  command: nextCommand
1801
2165
  },
1802
2166
  safe_commands: commands,
1803
- raw_status: {
1804
- workspace: workspaceState,
1805
- platform: platformState,
1806
- ops_proof: proofState,
1807
- gtm_bootstrap: bootstrapState,
1808
- gtm_integrations: integrationsState
1809
- }
2167
+ ...hasFlag("include-raw") || hasFlag("verbose") ? {
2168
+ raw_status: {
2169
+ workspace: workspaceState,
2170
+ platform: platformState,
2171
+ ops_proof: proofState,
2172
+ gtm_bootstrap: bootstrapState,
2173
+ gtm_integrations: integrationsState
2174
+ }
2175
+ } : {}
1810
2176
  };
1811
2177
  return output(result, () => {
1812
2178
  console.log("Signaliz start");
@@ -2098,17 +2464,24 @@ async function campaignBuild() {
2098
2464
  if (hasFlag("wait")) {
2099
2465
  if (!result.campaignBuildId) die("Campaign build did not return a campaign_build_id to poll");
2100
2466
  info("\nPolling for completion...");
2467
+ let lastProgressLine = "";
2101
2468
  const finalStatus = await sdk.campaigns.waitForCompletion(result.campaignBuildId, {
2102
2469
  intervalMs: 5e3,
2103
2470
  onStatus: (s) => {
2104
- if (!jsonMode()) {
2105
- process.stderr.write(
2106
- `\r [${s.status}] phase=${s.currentPhase ?? "N/A"} rows=${s.recordsSucceeded}/${s.recordsTotal} artifacts=${s.artifactCount} `
2107
- );
2471
+ if (hasFlag("no-progress")) return;
2472
+ const line = `[${s.status}] phase=${s.currentPhase ?? "N/A"} rows=${s.recordsSucceeded}/${s.recordsTotal} artifacts=${s.artifactCount}`;
2473
+ if (jsonMode()) {
2474
+ if (line !== lastProgressLine) {
2475
+ process.stderr.write(`signaliz campaign build: ${line}
2476
+ `);
2477
+ lastProgressLine = line;
2478
+ }
2479
+ return;
2108
2480
  }
2481
+ process.stderr.write(`\r ${line} `);
2109
2482
  }
2110
2483
  });
2111
- if (!jsonMode()) process.stderr.write("\n");
2484
+ if (!jsonMode() && !hasFlag("no-progress")) process.stderr.write("\n");
2112
2485
  output(jsonMode() ? { initial: result, final: finalStatus } : finalStatus, () => {
2113
2486
  console.log(`
2114
2487
  \u2713 Build ${finalStatus.status}`);
@@ -2124,15 +2497,15 @@ async function campaignScope() {
2124
2497
  const sdk = getSdk();
2125
2498
  const promptText = flagArg("prompt") || positionalAfter("scope");
2126
2499
  if (!promptText) {
2127
- die('--prompt is required. Example: signaliz campaign scope --prompt "Build a Vali-style home care campaign"');
2500
+ die('--prompt is required. Example: signaliz campaign scope --prompt "Build a home-care strategy home care campaign"');
2128
2501
  }
2129
- const contextFile = flagArg("client-context-file");
2502
+ const contextFile = flagArg("account-context-file") || flagArg("workspace-context-file");
2130
2503
  const targetCount = numberFlag("target-count");
2131
2504
  const destinations = csvFlag("destinations")?.map((type) => ({ type }));
2132
2505
  const result = await sdk.campaigns.scopeCampaign({
2133
2506
  prompt: promptText,
2134
- clientName: flagArg("client-name"),
2135
- clientContext: contextFile ? (0, import_node_fs.readFileSync)(contextFile, "utf8") : flagArg("client-context"),
2507
+ accountLabel: flagArg("account-label") || flagArg("workspace-label"),
2508
+ accountContext: contextFile ? (0, import_node_fs.readFileSync)(contextFile, "utf8") : flagArg("account-context") || flagArg("workspace-context"),
2136
2509
  campaignGoal: flagArg("campaign-goal"),
2137
2510
  targetCount,
2138
2511
  destinations,
@@ -2169,6 +2542,11 @@ async function campaignStatus() {
2169
2542
  console.log(`Phase: ${status.currentPhase || "N/A"}`);
2170
2543
  console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
2171
2544
  console.log(`Artifacts: ${status.artifactCount}`);
2545
+ if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
2546
+ if (status.staleRunningPhase) {
2547
+ const age = typeof status.phaseAgeSeconds === "number" ? `${status.phaseAgeSeconds}s` : "unknown age";
2548
+ console.log(`Stale: acquisition has reported no row progress for ${age}`);
2549
+ }
2172
2550
  if (status.warnings.length) {
2173
2551
  console.log(`Warnings: ${status.warnings.length}`);
2174
2552
  for (const warning of status.warnings.slice(0, 3)) console.log(` - ${warning}`);
@@ -2179,6 +2557,8 @@ async function campaignStatus() {
2179
2557
  }
2180
2558
  if (status.status === "completed") {
2181
2559
  hint(`signaliz campaign rows ${buildId} --limit 100`);
2560
+ } else if (status.staleRunningPhase && status.triggerRunId) {
2561
+ hint(`signaliz ops run-status ${status.triggerRunId} --watch`);
2182
2562
  } else if (status.status === "running" || status.status === "queued") {
2183
2563
  hint(`signaliz campaign status ${buildId} (poll again in ~10s)`);
2184
2564
  } else if (status.status === "pending_approval") {
@@ -2209,7 +2589,7 @@ async function campaignRows() {
2209
2589
  if (hasFlag("qualified")) opts.qualified = true;
2210
2590
  if (hasFlag("disqualified")) opts.qualified = false;
2211
2591
  const result = await sdk.campaigns.getCampaignBuildRows(buildId, opts);
2212
- allRows.push(...result.rows);
2592
+ allRows.push(...formatCampaignRowsForOperator(result.rows));
2213
2593
  nextCursor = result.nextCursor;
2214
2594
  page++;
2215
2595
  info(` Fetched page ${page}: ${result.rows.length} rows (total: ${allRows.length})`);
@@ -2233,26 +2613,73 @@ async function campaignRows() {
2233
2613
  if (hasFlag("qualified")) opts.qualified = true;
2234
2614
  if (hasFlag("disqualified")) opts.qualified = false;
2235
2615
  const result = await sdk.campaigns.getCampaignBuildRows(buildId, opts);
2236
- output(result, () => {
2237
- if (result.rows.length === 0) {
2616
+ const operatorResult = {
2617
+ ...result,
2618
+ rows: formatCampaignRowsForOperator(result.rows)
2619
+ };
2620
+ output(operatorResult, () => {
2621
+ if (operatorResult.rows.length === 0) {
2238
2622
  console.log("No rows found.");
2239
2623
  return;
2240
2624
  }
2241
- console.table(result.rows.map((r) => ({
2242
- email: r.data?.email || "",
2243
- name: r.data?.full_name || `${r.data?.first_name || ""} ${r.data?.last_name || ""}`.trim(),
2244
- company: r.data?.company_name || r.data?.company_domain || "",
2625
+ console.table(operatorResult.rows.map((r) => ({
2626
+ email: r.email || "",
2627
+ name: r.name || "",
2628
+ title: r.title || "",
2629
+ company: r.company || r.domain || "",
2245
2630
  segment: r.segment || "",
2246
- status: r.status || ""
2631
+ status: r.status || "",
2632
+ score: r.score ?? ""
2247
2633
  })));
2248
2634
  console.log(`
2249
- Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
2250
- if (result.nextCursor) {
2251
- hint(`signaliz campaign rows ${buildId} --limit ${limit} --cursor ${result.nextCursor}`);
2635
+ Showing ${operatorResult.rows.length} row(s)${operatorResult.hasMore ? " (more available)" : ""}`);
2636
+ if (operatorResult.nextCursor) {
2637
+ hint(`signaliz campaign rows ${buildId} --limit ${limit} --cursor ${operatorResult.nextCursor}`);
2252
2638
  }
2253
2639
  });
2254
2640
  }
2255
2641
  }
2642
+ function formatCampaignRowsForOperator(rows) {
2643
+ return rows.map((row) => {
2644
+ const rowRecord = record(row);
2645
+ const data = record(rowRecord.data);
2646
+ const rawCopy = record(data.raw_copy);
2647
+ const copy = {
2648
+ subject: data.subject || rawCopy.subject || null,
2649
+ opener: data.opener || rawCopy.opener || null,
2650
+ body: data.body || rawCopy.body || null,
2651
+ cta: data.cta || rawCopy.cta || null,
2652
+ engine: data.copy_engine || rawCopy.engine || null,
2653
+ model: data.copy_model || null
2654
+ };
2655
+ return {
2656
+ ...rowRecord,
2657
+ email: data.email || null,
2658
+ name: data.full_name || `${data.first_name || ""} ${data.last_name || ""}`.trim() || null,
2659
+ title: data.title || null,
2660
+ company: data.company_name || null,
2661
+ domain: data.company_domain || null,
2662
+ industry: data.industry || null,
2663
+ linkedin_url: data.linkedin_url || null,
2664
+ score: data.overall_score ?? null,
2665
+ company_fit_score: data.company_fit_score ?? null,
2666
+ contact_fit_score: data.contact_fit_score ?? null,
2667
+ signal_relevance_score: data.signal_relevance_score ?? null,
2668
+ reason_codes: firstArray(data.reason_codes),
2669
+ disqualifiers: firstArray(data.disqualifiers),
2670
+ signal: data.signal_title ? {
2671
+ type: data.signal_type || null,
2672
+ title: data.signal_title,
2673
+ summary: data.signal_summary || null,
2674
+ date: data.signal_date || null,
2675
+ confidence: data.signal_confidence ?? null,
2676
+ source_url: data.signal_source_url || null
2677
+ } : null,
2678
+ copy,
2679
+ has_copy: Boolean(copy.subject || copy.opener || copy.body || copy.cta)
2680
+ };
2681
+ });
2682
+ }
2256
2683
  async function campaignArtifacts() {
2257
2684
  const buildId = positionalAfter("artifacts") || flagArg("campaign-build-id");
2258
2685
  if (!buildId) die("Usage: signaliz campaign artifacts <campaign_build_id>");
@@ -2335,6 +2762,617 @@ async function campaign(sub) {
2335
2762
  Available: scope, build, status, rows, artifacts, approve, cancel`);
2336
2763
  }
2337
2764
  }
2765
+ var CAMPAIGN_AGENT_APPROVAL_TYPES = [
2766
+ "memory_retrieval",
2767
+ "spend",
2768
+ "customer_tool",
2769
+ "external_write",
2770
+ "delivery",
2771
+ "launch"
2772
+ ];
2773
+ var CAMPAIGN_AGENT_TEMPLATE_PLAYBOOKS = {
2774
+ "industrial-ot-resilience": ["net-new-suppressed-list", "proof-first-vertical-gate", "signal-led-copy-approval"],
2775
+ "non-medical-home-care": ["proof-first-vertical-gate", "domain-first-recovery", "table-workflow-handoff"],
2776
+ "agency-founder-led": ["net-new-suppressed-list", "signal-led-copy-approval", "table-workflow-handoff"],
2777
+ "cloud-infrastructure-displacement": ["proof-first-vertical-gate", "domain-first-recovery", "signal-led-copy-approval"]
2778
+ };
2779
+ var CAMPAIGN_AGENT_HELP = `signaliz campaign-agent <command> [options]
2780
+
2781
+ Strategy-template campaign builder:
2782
+ init Emit reusable CampaignBuilderAgentRequest JSON
2783
+ plan Compose an approval-gated strategy-template MCP flow
2784
+ proof Prove memory, plan, approvals, and build dry-run without spend
2785
+ commit-plan Dry-run or write a reviewed GTM campaign object
2786
+ dry-run Execute build_campaign with dry_run=true
2787
+ build-approved Launch only after explicit approval metadata
2788
+
2789
+ Examples:
2790
+ signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
2791
+ signaliz campaign-agent plan --goal "Build a strategy-template campaign for my ICP" --strategy-template non-medical-home-care --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
2792
+ signaliz campaign-agent proof --goal "Build a strategy-template campaign for my ICP" --strategy-template non-medical-home-care --target-count 100 --json
2793
+ signaliz campaign-agent plan --request-file campaign-builder-agent-request.json --target-count 250 --json
2794
+ signaliz campaign-agent dry-run --goal "Build a local services campaign" --target-count 250 --use-local-leads --json
2795
+ signaliz campaign-agent build-approved --goal "Build a strategy-template campaign" --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500
2796
+
2797
+ Plan options:
2798
+ --goal TEXT Campaign goal or brief
2799
+ --output-file FILE Write init output to a reusable request JSON file
2800
+ --request-file FILE Reusable JSON CampaignBuilderAgentRequest; flags override file fields
2801
+ --campaign-name NAME Optional campaign label
2802
+ --workspace-label NAME Optional workspace/account label
2803
+ --account-context TEXT Optional ICP, offer, exclusion, or approval context
2804
+ --strategy-template ID Strategy template to merge
2805
+ --target-count N Desired lead/account count
2806
+ --icp JSON Structured ICP object
2807
+ --builtins a,b lead_generation,local_leads,email_finding,email_verification,signals
2808
+ --use-local-leads Add the local_leads built-in lane
2809
+ --custom-tool ROUTE BYO route: provider:layer:tool[:mcp] or key=value pairs
2810
+ --with-byo-placeholder Add an editable custom MCP route placeholder during init
2811
+ --preferred-providers a,b
2812
+ Provider preferences or BYO provider ids
2813
+ --no-strategy-patterns Disable default private strategy memory hints
2814
+ --no-workflow-patterns Disable default workflow memory hints
2815
+ --no-strategy-memory Skip live strategy-memory readiness proof
2816
+ --no-kernel-plan Skip live gtm_campaign_build_plan evidence
2817
+ --no-delivery-risk Skip live delivery-risk evidence
2818
+
2819
+ Approval options:
2820
+ --confirm-write Required to write commit-plan
2821
+ --confirm-launch Required for build-approved
2822
+ --approved-by EMAIL Required approval identity for writes/launches
2823
+ --approve-all Approve every required approval type in the plan
2824
+ --approved-types a,b Approve selected types
2825
+ --spend-limit N Maximum approved credits
2826
+ --commit-before-launch Commit the reviewed plan before launch
2827
+ --idempotency-key KEY Idempotency key for write/launch calls
2828
+ --json Machine-readable output
2829
+ `;
2830
+ async function campaignAgent(sub, rest) {
2831
+ if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
2832
+ process.stdout.write(CAMPAIGN_AGENT_HELP);
2833
+ return;
2834
+ }
2835
+ if (isHelpRequest(rest)) {
2836
+ process.stdout.write(CAMPAIGN_AGENT_HELP);
2837
+ return;
2838
+ }
2839
+ if (!["init", "template", "request-template", "new", "plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(sub)) {
2840
+ process.stdout.write(CAMPAIGN_AGENT_HELP);
2841
+ return;
2842
+ }
2843
+ const flags = parseCommandFlags(rest);
2844
+ if (["init", "template", "request-template", "new"].includes(sub)) {
2845
+ const request2 = campaignAgentRequestTemplateFromFlags(flags, rest);
2846
+ const outputFile = commandStringFlag(flags, "output-file", "out");
2847
+ if (outputFile) {
2848
+ (0, import_node_fs.writeFileSync)(outputFile, `${JSON.stringify(request2, null, 2)}
2849
+ `, "utf8");
2850
+ }
2851
+ if (jsonMode() || !outputFile) return output(request2);
2852
+ console.log(`Campaign request template written: ${outputFile}`);
2853
+ console.log(`Next: signaliz campaign-agent plan --request-file ${outputFile} --json`);
2854
+ return;
2855
+ }
2856
+ const requestFromFile = campaignAgentRequestFileFromFlags(flags);
2857
+ const goal = commandStringFlag(flags, "goal", "brief") || promptArg(rest) || campaignAgentStringValue(requestFromFile?.goal);
2858
+ if (!goal) die(`campaign-agent ${sub} requires --goal or a request file with goal`);
2859
+ const isApprovedBuild = sub === "build-approved" || sub === "launch-approved";
2860
+ const isCommitPlan = sub === "commit-plan";
2861
+ const isConfirmedCommit = isCommitPlan && commandBooleanFlag(flags, "confirm-write");
2862
+ const approvedBy = commandStringFlag(flags, "approved-by");
2863
+ if (isApprovedBuild) {
2864
+ if (!commandBooleanFlag(flags, "confirm-launch")) die(`campaign-agent ${sub} requires --confirm-launch`);
2865
+ if (!approvedBy) die(`campaign-agent ${sub} requires --approved-by`);
2866
+ }
2867
+ if (isConfirmedCommit && !approvedBy) {
2868
+ die("campaign-agent commit-plan --confirm-write requires --approved-by");
2869
+ }
2870
+ const sdk = getSdk();
2871
+ const agent = sdk.campaignBuilderAgent;
2872
+ const request = mergeCampaignAgentRequests(
2873
+ requestFromFile,
2874
+ campaignAgentRequestFromFlags(goal, flags, { includeDefaults: !requestFromFile })
2875
+ );
2876
+ const plan = await agent.createPlan(request, {
2877
+ discoverCapabilities: !commandBooleanFlag(flags, "skip-discovery"),
2878
+ scopeCampaign: !commandBooleanFlag(flags, "skip-scope"),
2879
+ includeStrategyMemoryStatus: !commandBooleanFlag(flags, "no-strategy-memory"),
2880
+ includeKernelPlan: !commandBooleanFlag(flags, "no-kernel-plan"),
2881
+ includeDeliveryRisk: !commandBooleanFlag(flags, "no-delivery-risk")
2882
+ });
2883
+ if (sub === "proof" || sub === "smoke") {
2884
+ const result = await agent.dryRunPlan(plan, {
2885
+ idempotencyKey: commandStringFlag(flags, "idempotency-key")
2886
+ });
2887
+ const proof = createCampaignAgentProofReceipt(plan, result);
2888
+ if (!proof.success) process.exitCode = 1;
2889
+ return output(proof, () => printCampaignAgentProof(proof));
2890
+ }
2891
+ if (isCommitPlan) {
2892
+ const result = await agent.commitPlan(plan, {
2893
+ confirm: isConfirmedCommit,
2894
+ dryRun: !isConfirmedCommit,
2895
+ approvedBy,
2896
+ idempotencyKey: commandStringFlag(flags, "idempotency-key"),
2897
+ rationale: commandStringFlag(flags, "rationale")
2898
+ });
2899
+ return output({ plan, result }, () => printCampaignAgentExecution(plan, result));
2900
+ }
2901
+ if (sub === "dry-run") {
2902
+ const result = await agent.dryRunPlan(plan, {
2903
+ idempotencyKey: commandStringFlag(flags, "idempotency-key")
2904
+ });
2905
+ return output({ plan, result }, () => printCampaignAgentExecution(plan, result));
2906
+ }
2907
+ if (isApprovedBuild) {
2908
+ const approval = createCampaignAgentApproval(plan, {
2909
+ approvedBy,
2910
+ approvedTypes: campaignAgentApprovedTypesFromFlags(plan, flags),
2911
+ spendLimitCredits: commandNumberFlag(flags, "spend-limit", "spend-limit-credits", "max-credits"),
2912
+ approvedRouteIds: campaignAgentApprovedRouteIdsFromFlags(plan, flags),
2913
+ notes: commandStringFlag(flags, "approval-notes", "notes")
2914
+ });
2915
+ const result = await agent.buildApprovedPlan(plan, approval, {
2916
+ idempotencyKey: commandStringFlag(flags, "idempotency-key"),
2917
+ commitBeforeLaunch: commandBooleanFlag(flags, "commit-before-launch")
2918
+ });
2919
+ return output({ plan, approval, result }, () => printCampaignAgentExecution(plan, result));
2920
+ }
2921
+ return output(plan, () => printCampaignAgentPlan(plan));
2922
+ }
2923
+ function campaignAgentRequestTemplateFromFlags(flags, rest) {
2924
+ const goal = commandStringFlag(flags, "goal", "brief") || promptArg(rest) || "Build a strategy-template campaign for mature operators in the target ICP.";
2925
+ const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
2926
+ request.strategyTemplate = request.strategyTemplate || "non-medical-home-care";
2927
+ if (!Array.isArray(request.operatingPlaybooks)) {
2928
+ request.operatingPlaybooks = CAMPAIGN_AGENT_TEMPLATE_PLAYBOOKS[String(request.strategyTemplate)] || [];
2929
+ }
2930
+ request.campaignName = request.campaignName || "Strategy Template Campaign";
2931
+ request.accountLabel = request.accountLabel || "Workspace Campaign";
2932
+ request.accountContext = request.accountContext || "Use private workspace memory, current suppression rules, verified-email quality gates, and approval-gated provider routes.";
2933
+ request.targetCount = request.targetCount || 250;
2934
+ request.icp = request.icp || {
2935
+ personas: ["Operations leader", "Founder", "Revenue leader"],
2936
+ industries: ["B2B services", "Vertical software", "Local operators"],
2937
+ geographies: ["United States"],
2938
+ keywords: ["growth", "operations", "customer acquisition"],
2939
+ requireVerifiedEmail: true
2940
+ };
2941
+ const builtIns = new Set(campaignAgentStringArray(request.builtIns) || [
2942
+ "lead_generation",
2943
+ "email_finding",
2944
+ "email_verification",
2945
+ "signals"
2946
+ ]);
2947
+ if (commandBooleanFlag(flags, "use-local-leads")) builtIns.add("local_leads");
2948
+ request.builtIns = [...builtIns];
2949
+ if (!Array.isArray(request.integrations) && (commandBooleanFlag(flags, "with-byo-placeholder") || commandBooleanFlag(flags, "include-byo-placeholder") || commandBooleanFlag(flags, "include-custom-tool-placeholder"))) {
2950
+ request.integrations = [{
2951
+ provider: "custom_mcp",
2952
+ layer: "enrichment",
2953
+ gtmLayers: ["company_enrichment"],
2954
+ mode: "if_available",
2955
+ toolName: "workspace_enrich",
2956
+ mcpServerName: "workspace-mcp",
2957
+ label: "Workspace enrichment MCP",
2958
+ approvalRequired: true,
2959
+ rationale: "Editable custom MCP route placeholder for workspace-owned enrichment."
2960
+ }];
2961
+ }
2962
+ const preferredProviders = new Set(campaignAgentStringArray(request.preferredProviders) || []);
2963
+ if (!commandBooleanFlag(flags, "no-nango-catalog")) preferredProviders.add("nango");
2964
+ request.preferredProviders = [...preferredProviders];
2965
+ request.memory = mergeCampaignAgentRecords({
2966
+ enabled: true,
2967
+ useWorkspaceHistory: true,
2968
+ useNetworkPatterns: false,
2969
+ privacyMode: "anonymized_patterns",
2970
+ queries: [{
2971
+ query: `${request.strategyTemplate} campaign reply patterns, objections, qualification gates, and verified-email QA`,
2972
+ scopes: ["workspace", "operator_notes"],
2973
+ topK: 10,
2974
+ required: true,
2975
+ rationale: "Load approved private strategy and workflow patterns before campaign planning."
2976
+ }]
2977
+ }, record(request.memory));
2978
+ request.agencyContext = mergeCampaignAgentRecords({
2979
+ strategyModel: "strategy_template",
2980
+ includeStrategyPatterns: true,
2981
+ includeWorkflowPatterns: true,
2982
+ includeNangoCatalog: !commandBooleanFlag(flags, "no-nango-catalog"),
2983
+ partnerEcosystem: commandBooleanFlag(flags, "no-nango-catalog") ? ["signaliz"] : ["signaliz", "nango"]
2984
+ }, record(request.agencyContext));
2985
+ request.signalizDefaults = mergeCampaignAgentRecords({
2986
+ delivery: {
2987
+ enabled: true,
2988
+ destinationType: "json",
2989
+ approvalRequired: true
2990
+ }
2991
+ }, record(request.signalizDefaults));
2992
+ request.approvalPolicy = mergeCampaignAgentRecords({
2993
+ requireHumanApproval: true,
2994
+ maxCreditsWithoutApproval: 0,
2995
+ requireApprovalFor: CAMPAIGN_AGENT_APPROVAL_TYPES
2996
+ }, record(request.approvalPolicy));
2997
+ return compactCampaignAgentRequest(request);
2998
+ }
2999
+ function campaignAgentRequestFileFromFlags(flags) {
3000
+ const file = commandStringFlag(flags, "request-file", "input-file", "campaign-file");
3001
+ if (!file) return void 0;
3002
+ const parsed = readJsonValue(file);
3003
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3004
+ die("--request-file must point to a JSON object");
3005
+ }
3006
+ return parsed;
3007
+ }
3008
+ function campaignAgentRequestFromFlags(goal, flags, options = {}) {
3009
+ const includeDefaults = options.includeDefaults !== false;
3010
+ const request = {
3011
+ goal,
3012
+ campaignName: commandStringFlag(flags, "campaign-name", "name"),
3013
+ accountLabel: commandStringFlag(flags, "workspace-label", "account-label"),
3014
+ strategyTemplate: commandStringFlag(flags, "strategy-template", "template"),
3015
+ accountContext: commandStringFlag(flags, "account-context", "workspace-context"),
3016
+ targetCount: commandNumberFlag(flags, "target-count", "lead-count"),
3017
+ gtmCampaignId: commandStringFlag(flags, "gtm-campaign-id", "campaign-id"),
3018
+ icp: campaignAgentJsonObjectInput(flags, ["icp", "target-icp"], ["icp-file", "target-icp-file"]),
3019
+ brainDefaults: campaignAgentJsonObjectInput(flags, ["brain-defaults"], ["brain-defaults-file"]),
3020
+ deliveryRisk: campaignAgentJsonObjectInput(flags, ["delivery-risk"], ["delivery-risk-file"]),
3021
+ builtIns: campaignAgentBuiltInsFromFlags(flags),
3022
+ operatingPlaybooks: commandCsvFlag(flags, "operating-playbooks", "playbooks"),
3023
+ integrations: campaignAgentCustomToolRoutesFromFlags(flags),
3024
+ preferredProviders: commandCsvFlag(flags, "preferred-providers", "providers")
3025
+ };
3026
+ if (includeDefaults || commandFlagValue(flags, "strategy-model", "no-strategy-patterns", "no-agency-patterns", "no-workflow-patterns", "no-clay-patterns", "no-nango-catalog", "partners", "revenue-motion") !== void 0) {
3027
+ request.agencyContext = {
3028
+ strategyModel: commandStringFlag(flags, "strategy-model"),
3029
+ includeStrategyPatterns: !commandBooleanFlag(flags, "no-strategy-patterns") && !commandBooleanFlag(flags, "no-agency-patterns"),
3030
+ includeWorkflowPatterns: !commandBooleanFlag(flags, "no-workflow-patterns") && !commandBooleanFlag(flags, "no-clay-patterns"),
3031
+ includeNangoCatalog: !commandBooleanFlag(flags, "no-nango-catalog"),
3032
+ partnerEcosystem: commandCsvFlag(flags, "partners"),
3033
+ revenueMotion: commandStringFlag(flags, "revenue-motion")
3034
+ };
3035
+ }
3036
+ if (includeDefaults || commandFlagValue(flags, "no-memory", "no-workspace-history", "use-network-patterns", "privacy-mode") !== void 0) {
3037
+ request.memory = {
3038
+ enabled: !commandBooleanFlag(flags, "no-memory"),
3039
+ useWorkspaceHistory: !commandBooleanFlag(flags, "no-workspace-history"),
3040
+ useNetworkPatterns: commandBooleanFlag(flags, "use-network-patterns"),
3041
+ privacyMode: commandStringFlag(flags, "privacy-mode")
3042
+ };
3043
+ }
3044
+ if (includeDefaults || commandFlagValue(flags, "max-credits", "no-delivery", "destination") !== void 0) {
3045
+ request.signalizDefaults = {
3046
+ maxCredits: commandNumberFlag(flags, "max-credits"),
3047
+ delivery: {
3048
+ enabled: !commandBooleanFlag(flags, "no-delivery"),
3049
+ destinationType: commandStringFlag(flags, "destination"),
3050
+ approvalRequired: true
3051
+ }
3052
+ };
3053
+ }
3054
+ if (includeDefaults || commandFlagValue(flags, "no-human-approval", "max-credits-without-approval") !== void 0) {
3055
+ request.approvalPolicy = {
3056
+ requireHumanApproval: !commandBooleanFlag(flags, "no-human-approval"),
3057
+ maxCreditsWithoutApproval: commandNumberFlag(flags, "max-credits-without-approval"),
3058
+ requireApprovalFor: CAMPAIGN_AGENT_APPROVAL_TYPES
3059
+ };
3060
+ }
3061
+ return compactCampaignAgentRequest(request);
3062
+ }
3063
+ function mergeCampaignAgentRequests(base, override) {
3064
+ if (!base) return override;
3065
+ return compactCampaignAgentRequest({
3066
+ ...base,
3067
+ ...override,
3068
+ icp: mergeCampaignAgentRecords(record(base.icp), record(override.icp)),
3069
+ memory: mergeCampaignAgentRecords(record(base.memory), record(override.memory)),
3070
+ agencyContext: mergeCampaignAgentRecords(record(base.agencyContext), record(override.agencyContext)),
3071
+ signalizDefaults: mergeCampaignAgentRecords(record(base.signalizDefaults), record(override.signalizDefaults)),
3072
+ approvalPolicy: mergeCampaignAgentRecords(record(base.approvalPolicy), record(override.approvalPolicy)),
3073
+ constraints: mergeCampaignAgentRecords(record(base.constraints), record(override.constraints)),
3074
+ workspaceContext: mergeCampaignAgentRecords(record(base.workspaceContext), record(override.workspaceContext)),
3075
+ builtIns: override.builtIns ?? base.builtIns,
3076
+ operatingPlaybooks: override.operatingPlaybooks ?? base.operatingPlaybooks,
3077
+ integrations: override.integrations ?? base.integrations,
3078
+ customerTools: override.customerTools ?? base.customerTools,
3079
+ preferredProviders: override.preferredProviders ?? base.preferredProviders
3080
+ });
3081
+ }
3082
+ function mergeCampaignAgentRecords(base, override) {
3083
+ const merged = { ...base, ...override };
3084
+ return Object.keys(merged).length ? merged : void 0;
3085
+ }
3086
+ function compactCampaignAgentRequest(record2) {
3087
+ return Object.fromEntries(Object.entries(record2).filter(([, value]) => value !== void 0));
3088
+ }
3089
+ function campaignAgentJsonObjectInput(flags, inlineNames, fileNames) {
3090
+ const inline = commandJsonObjectFlag(flags, ...inlineNames);
3091
+ if (inline) return inline;
3092
+ const file = commandStringFlag(flags, ...fileNames);
3093
+ if (!file) return void 0;
3094
+ const parsed = readJsonValue(file);
3095
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3096
+ die(`--${fileNames[0]} must point to a JSON object`);
3097
+ }
3098
+ return parsed;
3099
+ }
3100
+ function campaignAgentBuiltInsFromFlags(flags) {
3101
+ const explicit = commandCsvFlag(flags, "builtins", "builtin-tools", "signaliz-tools");
3102
+ const hasBuiltinFlag = Boolean(
3103
+ explicit?.length || commandFlagValue(flags, "use-local-leads") !== void 0 || commandFlagValue(flags, "no-lead-generation") !== void 0 || commandFlagValue(flags, "no-email-finding") !== void 0 || commandFlagValue(flags, "no-verification") !== void 0 || commandFlagValue(flags, "no-signals") !== void 0
3104
+ );
3105
+ if (!hasBuiltinFlag) return void 0;
3106
+ const builtIns = new Set(explicit?.length ? explicit : ["lead_generation", "email_finding", "email_verification", "signals"]);
3107
+ if (commandBooleanFlag(flags, "use-local-leads")) builtIns.add("local_leads");
3108
+ if (commandBooleanFlag(flags, "no-lead-generation")) builtIns.delete("lead_generation");
3109
+ if (commandBooleanFlag(flags, "no-email-finding")) builtIns.delete("email_finding");
3110
+ if (commandBooleanFlag(flags, "no-verification")) builtIns.delete("email_verification");
3111
+ if (commandBooleanFlag(flags, "no-signals")) builtIns.delete("signals");
3112
+ return [...builtIns];
3113
+ }
3114
+ function campaignAgentCustomToolRoutesFromFlags(flags) {
3115
+ const values = repeatedCommandStringFlag(flags, "custom-tool", "customer-tool", "byo-tool", "integration-route");
3116
+ const routes = values.map(parseCampaignAgentCustomToolRoute);
3117
+ return routes.length ? routes : void 0;
3118
+ }
3119
+ function parseCampaignAgentCustomToolRoute(raw) {
3120
+ const route = raw.trim().startsWith("{") ? parseJsonObjectFromString(raw, "--custom-tool") : raw.includes("=") ? campaignAgentKeyValueObject(raw) : campaignAgentColonRouteObject(raw);
3121
+ const provider = String(route.provider ?? route.provider_id ?? route.providerId ?? "custom_mcp");
3122
+ const layer = normalizeCampaignAgentLayer(String(route.layer ?? route.use_for_layer ?? route.useForLayer ?? "enrichment"));
3123
+ const label = campaignAgentStringValue(route.label ?? route.name) ?? provider;
3124
+ return {
3125
+ provider,
3126
+ layer,
3127
+ gtmLayers: campaignAgentStringArray(route.gtm_layers ?? route.gtmLayers ?? route.capabilities),
3128
+ mode: normalizeCampaignAgentRouteMode(String(route.mode ?? "required")),
3129
+ toolName: campaignAgentStringValue(route.tool ?? route.tool_name ?? route.toolName),
3130
+ mcpServerName: campaignAgentStringValue(route.mcp ?? route.server ?? route.mcp_server_name ?? route.mcpServerName),
3131
+ label,
3132
+ approvalRequired: campaignAgentOptionalBoolean(route.approval_required ?? route.approvalRequired, true),
3133
+ config: {
3134
+ provider_id: route.provider_id ?? route.providerId,
3135
+ available_tools: campaignAgentStringArray(route.available_tools ?? route.availableTools ?? route.tools),
3136
+ raw: raw.trim()
3137
+ },
3138
+ rationale: `${label} is a user-provided campaign-builder route declared from the CLI.`
3139
+ };
3140
+ }
3141
+ function campaignAgentColonRouteObject(raw) {
3142
+ const [provider, layer, tool, mcp] = raw.split(":").map((part) => part.trim()).filter(Boolean);
3143
+ if (!provider || !layer) die("Expected --custom-tool provider:layer:tool[:mcp] or key=value pairs");
3144
+ return { provider, layer, tool, mcp };
3145
+ }
3146
+ function campaignAgentKeyValueObject(raw) {
3147
+ const parsed = {};
3148
+ for (const segment of raw.split(",")) {
3149
+ const eq = segment.indexOf("=");
3150
+ if (eq < 0) continue;
3151
+ parsed[segment.slice(0, eq).trim().replace(/-/g, "_")] = segment.slice(eq + 1).trim();
3152
+ }
3153
+ return parsed;
3154
+ }
3155
+ function normalizeCampaignAgentLayer(value) {
3156
+ const normalized = value.trim().toLowerCase().replace(/-/g, "_");
3157
+ const allowed = ["workspace_context", "memory", "source", "enrichment", "qualification", "copy", "delivery", "feedback", "approval"];
3158
+ if (!allowed.includes(normalized)) {
3159
+ die(`Unknown campaign-builder layer "${value}". Use source, enrichment, qualification, copy, delivery, feedback, or approval.`);
3160
+ }
3161
+ return normalized;
3162
+ }
3163
+ function normalizeCampaignAgentRouteMode(value) {
3164
+ const normalized = value.trim().toLowerCase().replace(/-/g, "_");
3165
+ return ["required", "if_available", "fallback", "disabled"].includes(normalized) ? normalized : "required";
3166
+ }
3167
+ function campaignAgentStringArray(value) {
3168
+ const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
3169
+ const parsed = values.flatMap((item) => String(item).split(/[|,]/).map((part) => part.trim()).filter(Boolean));
3170
+ return parsed.length ? parsed : void 0;
3171
+ }
3172
+ function campaignAgentStringValue(value) {
3173
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
3174
+ }
3175
+ function campaignAgentOptionalBoolean(value, defaultValue) {
3176
+ if (value === void 0) return defaultValue;
3177
+ if (typeof value === "boolean") return value;
3178
+ return parseCommandBoolean(String(value), defaultValue);
3179
+ }
3180
+ function campaignAgentApprovedTypesFromFlags(plan, flags) {
3181
+ const requested = commandCsvFlag(flags, "approved-types", "approve-types");
3182
+ if (requested?.length) return requested;
3183
+ if (!commandBooleanFlag(flags, "approve-all")) {
3184
+ die("campaign-agent build-approved requires --approve-all or --approved-types");
3185
+ }
3186
+ const types = Array.isArray(plan?.approvals) ? plan.approvals.map((item) => item?.type).filter(Boolean) : [];
3187
+ return [...new Set(types.length ? types : CAMPAIGN_AGENT_APPROVAL_TYPES)];
3188
+ }
3189
+ function campaignAgentApprovedRouteIdsFromFlags(plan, flags) {
3190
+ const requested = commandCsvFlag(flags, "approved-route-ids", "route-ids");
3191
+ if (requested?.length) return requested;
3192
+ if (!commandBooleanFlag(flags, "approve-all")) return void 0;
3193
+ const routeIds = Array.isArray(plan?.approvals) ? plan.approvals.map((item) => item?.routeId).filter(Boolean) : [];
3194
+ return routeIds.length ? routeIds : void 0;
3195
+ }
3196
+ function createCampaignAgentApproval(plan, input) {
3197
+ return {
3198
+ ...input,
3199
+ planId: plan?.planId,
3200
+ approvedAt: (/* @__PURE__ */ new Date()).toISOString()
3201
+ };
3202
+ }
3203
+ function printCampaignAgentPlan(plan) {
3204
+ console.log(`Plan: ${plan.campaignName || plan.goal || plan.planId}`);
3205
+ if (plan.planId) console.log(`Plan ID: ${plan.planId}`);
3206
+ if (plan.targetCount !== void 0) console.log(`Target: ${plan.targetCount}`);
3207
+ if (plan.estimatedCredits !== void 0) console.log(`Estimated credits: ${plan.estimatedCredits}`);
3208
+ const memory = record(plan.memory);
3209
+ console.log(`Memory: ${memory.enabled === false ? "disabled" : memory.privacyMode || "workspace_only"}`);
3210
+ const playbooks = Array.isArray(plan.operatingPlaybooks) ? plan.operatingPlaybooks : [];
3211
+ console.log(`Playbooks: ${playbooks.map((item) => item.slug).filter(Boolean).join(", ") || "none"}`);
3212
+ console.log(`Strategy memory: ${plan.strategyMemoryStatus ? record(plan.strategyMemoryStatus).ready === false ? "needs seeding" : "ready" : "not loaded"}`);
3213
+ console.log(`Kernel plan: ${plan.kernelPlan ? "loaded" : "not loaded"}`);
3214
+ const approvals = Array.isArray(plan.approvals) ? plan.approvals : [];
3215
+ console.log(`Approvals: ${approvals.map((item) => item.type).filter(Boolean).join(", ") || "none"}`);
3216
+ const warnings = Array.isArray(plan.warnings) ? plan.warnings : [];
3217
+ if (warnings.length) console.log(`Warnings: ${warnings.join("; ")}`);
3218
+ const flow = Array.isArray(plan.mcpFlow) ? plan.mcpFlow : [];
3219
+ if (flow.length) {
3220
+ console.log("\nMCP flow:");
3221
+ for (const step of flow) {
3222
+ console.log(`- ${step.id || step.tool}: ${step.tool}${step.approvalRequired ? " (approval required)" : ""}`);
3223
+ }
3224
+ }
3225
+ }
3226
+ function printCampaignAgentExecution(plan, result) {
3227
+ printCampaignAgentPlan(plan);
3228
+ console.log("\nResult:");
3229
+ console.log(JSON.stringify(result, null, 2));
3230
+ }
3231
+ function createCampaignAgentProofReceipt(plan, result) {
3232
+ const strategyMemory = record(plan.strategyMemoryStatus);
3233
+ const dryRunResult = record(result);
3234
+ const approvals = firstArray(plan.approvals);
3235
+ const flow = firstArray(plan.mcpFlow);
3236
+ const memoryReady = plan.strategyMemoryStatus ? strategyMemory.ready !== false : false;
3237
+ const dryRunCompleted = dryRunResult.dryRun === true || dryRunResult.dry_run === true || dryRunResult.status === "dry_run";
3238
+ const noLaunch = dryRunCompleted && !dryRunResult.campaignBuildId && !dryRunResult.campaign_build_id;
3239
+ const gates = [
3240
+ {
3241
+ id: "strategy_memory_ready",
3242
+ passed: memoryReady,
3243
+ ready: strategyMemory.ready ?? null,
3244
+ blocker_count: firstArray(strategyMemory.blockers).length
3245
+ },
3246
+ {
3247
+ id: "campaign_plan_ready",
3248
+ passed: Boolean(plan.planId && flow.length > 0),
3249
+ plan_id: plan.planId ?? null,
3250
+ flow_steps: flow.length
3251
+ },
3252
+ {
3253
+ id: "approval_gates_present",
3254
+ passed: approvals.length > 0,
3255
+ approval_types: approvals.map((approval) => approval?.type).filter(Boolean)
3256
+ },
3257
+ {
3258
+ id: "dry_run_completed",
3259
+ passed: dryRunCompleted,
3260
+ status: dryRunResult.status ?? null,
3261
+ current_phase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null
3262
+ },
3263
+ {
3264
+ id: "no_spendful_launch",
3265
+ passed: noLaunch,
3266
+ campaign_build_id: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null
3267
+ }
3268
+ ];
3269
+ return {
3270
+ receipt_version: "campaign-agent-proof.v1",
3271
+ source: "signaliz campaign-agent proof",
3272
+ success: gates.every((gate) => gate.passed),
3273
+ safety: {
3274
+ spendful_tools_called: false,
3275
+ external_writes_called: false,
3276
+ sender_loads_called: false,
3277
+ email_sends_called: false,
3278
+ dry_run_only: true
3279
+ },
3280
+ campaign: {
3281
+ plan_id: plan.planId,
3282
+ campaign_name: plan.campaignName,
3283
+ strategy_template: campaignAgentStrategyTemplate(plan),
3284
+ target_count: plan.targetCount,
3285
+ estimated_credits: plan.estimatedCredits,
3286
+ operating_playbooks: firstArray(plan.operatingPlaybooks).map((playbook) => playbook?.slug).filter(Boolean)
3287
+ },
3288
+ gates,
3289
+ strategy_memory_status: summarizeCampaignAgentStrategyMemory(strategyMemory),
3290
+ dry_run_result: summarizeCampaignAgentDryRun(dryRunResult),
3291
+ recommended_next_actions: [
3292
+ "Review the plan, approvals, and dry-run result.",
3293
+ "Use campaign-agent commit-plan --confirm-write only after review.",
3294
+ "Use campaign-agent build-approved only with --confirm-launch, approval identity, approval types, and spend limit.",
3295
+ "When an approved build reaches pending_approval, review rows and run campaign approve <campaign_build_id> --destination-type json."
3296
+ ]
3297
+ };
3298
+ }
3299
+ function campaignAgentString(...values) {
3300
+ for (const value of values) {
3301
+ if (typeof value === "string" && value.trim()) return value;
3302
+ }
3303
+ return null;
3304
+ }
3305
+ function campaignAgentStrategyTemplate(plan) {
3306
+ const buildRequest = record(plan.buildRequest);
3307
+ const strategyMemory = record(plan.strategyMemoryStatus);
3308
+ const statusTemplate = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
3309
+ const statusTemplateRecord = record(statusTemplate);
3310
+ const flowTemplate = firstArray(plan.mcpFlow).map((step) => record(record(step).arguments).strategy_template ?? record(record(step).arguments).strategyTemplate).find((value) => typeof value === "string" && value.trim());
3311
+ return campaignAgentString(
3312
+ buildRequest.strategyTemplate,
3313
+ buildRequest.strategy_template,
3314
+ statusTemplate,
3315
+ statusTemplateRecord.slug,
3316
+ statusTemplateRecord.id,
3317
+ flowTemplate
3318
+ );
3319
+ }
3320
+ function summarizeCampaignAgentStrategyMemory(strategyMemory) {
3321
+ if (Object.keys(strategyMemory).length === 0) return { ready: false };
3322
+ const template = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
3323
+ const templateRecord = record(template);
3324
+ const coverage = record(strategyMemory.coverage);
3325
+ const sourceGroups = firstArray(strategyMemory.source_groups, strategyMemory.sourceGroups).map((group) => {
3326
+ const sourceGroup = record(group);
3327
+ return {
3328
+ id: sourceGroup.id ?? null,
3329
+ required: sourceGroup.required ?? null,
3330
+ ready: sourceGroup.ready ?? null,
3331
+ counts: record(sourceGroup.counts)
3332
+ };
3333
+ });
3334
+ return {
3335
+ ready: strategyMemory.ready ?? null,
3336
+ read_only: strategyMemory.read_only ?? strategyMemory.readOnly ?? null,
3337
+ source_tool: campaignAgentString(strategyMemory.source_tool, strategyMemory.sourceTool),
3338
+ strategy_template: {
3339
+ slug: campaignAgentString(template, templateRecord.slug, templateRecord.id),
3340
+ label: campaignAgentString(templateRecord.label)
3341
+ },
3342
+ coverage: {
3343
+ required_groups_ready: coverage.required_groups_ready ?? coverage.requiredGroupsReady ?? null,
3344
+ required_groups_total: coverage.required_groups_total ?? coverage.requiredGroupsTotal ?? null,
3345
+ source_groups_ready: coverage.source_groups_ready ?? coverage.sourceGroupsReady ?? null,
3346
+ source_groups_total: coverage.source_groups_total ?? coverage.sourceGroupsTotal ?? null,
3347
+ knowledge_docs: coverage.knowledge_docs ?? coverage.knowledgeDocs ?? null,
3348
+ memories: coverage.memories ?? null
3349
+ },
3350
+ source_groups: sourceGroups,
3351
+ blocker_count: firstArray(strategyMemory.blockers).length,
3352
+ warning_count: firstArray(strategyMemory.warnings).length
3353
+ };
3354
+ }
3355
+ function summarizeCampaignAgentDryRun(dryRunResult) {
3356
+ return {
3357
+ dryRun: dryRunResult.dryRun ?? dryRunResult.dry_run ?? null,
3358
+ status: dryRunResult.status ?? null,
3359
+ currentPhase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null,
3360
+ campaignBuildId: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null,
3361
+ plannedTargetCount: dryRunResult.plannedTargetCount ?? dryRunResult.planned_target_count ?? null
3362
+ };
3363
+ }
3364
+ function printCampaignAgentProof(proof) {
3365
+ console.log(`Campaign-agent proof: ${proof.success ? "passed" : "failed"}`);
3366
+ const campaign2 = record(proof.campaign);
3367
+ if (campaign2.plan_id) console.log(`Plan ID: ${campaign2.plan_id}`);
3368
+ if (campaign2.strategy_template) console.log(`Strategy template: ${campaign2.strategy_template}`);
3369
+ if (campaign2.target_count !== void 0) console.log(`Target: ${campaign2.target_count}`);
3370
+ console.log("\nGates:");
3371
+ for (const gate of firstArray(proof.gates)) {
3372
+ console.log(`- ${gate.id}: ${gate.passed ? "passed" : "failed"}`);
3373
+ }
3374
+ console.log("\nSafety: dry-run only; no spendful launch, external write, sender load, or email send.");
3375
+ }
2338
3376
  async function lead(sub, rest) {
2339
3377
  const sdk = getSdk();
2340
3378
  if (sub === "generate") {
@@ -2427,19 +3465,219 @@ async function gtm(sub, rest) {
2427
3465
  return;
2428
3466
  }
2429
3467
  const sdk = getSdk();
3468
+ if (sub === "start-context" || sub === "start") {
3469
+ const campaignBrief = promptArg(rest) || flagArg("campaign-brief") || flagArg("brief") || flagArg("goal");
3470
+ const strategyTemplate = flagArg("strategy-template") || flagArg("template");
3471
+ const targetIcp = readJsonObjectInput("target-icp-json", "target-icp-file");
3472
+ if (!campaignBrief && !flagArg("campaign-id") && !flagArg("campaign-build-id") && !flagArg("build-id") && !strategyTemplate && !targetIcp) {
3473
+ die('Usage: signaliz gtm start-context "campaign brief" [--strategy-template ID] [--target-count N] [--json]');
3474
+ }
3475
+ const result = await sdk.gtm.campaignStartContext({
3476
+ campaignId: flagArg("campaign-id"),
3477
+ campaignBuildId: flagArg("campaign-build-id") || flagArg("build-id"),
3478
+ campaignBrief,
3479
+ strategyTemplate,
3480
+ targetIcp,
3481
+ leadCount: numberFlag("lead-count") || numberFlag("target-count"),
3482
+ layers: csvFlag("layers"),
3483
+ preferredProviders: csvFlag("preferred-providers") || csvFlag("providers"),
3484
+ memoryDimensionFilters: readJsonObjectInput("memory-dimension-filters-json", "memory-dimension-filters-file"),
3485
+ requireMemoryDimensionMatch: hasFlag("require-memory-dimension-match") || void 0,
3486
+ includeMemory: !hasFlag("no-memory"),
3487
+ includeBrain: !hasFlag("no-brain"),
3488
+ includeProviderRoutes: !hasFlag("no-provider-routes"),
3489
+ includeFailurePatterns: !hasFlag("no-failure-patterns"),
3490
+ includeDeliveryRisk: !hasFlag("no-delivery-risk"),
3491
+ includeGlobalBrain: !hasFlag("no-global-brain"),
3492
+ includePlannedProviders: !hasFlag("no-planned-providers"),
3493
+ days: numberFlag("days"),
3494
+ minConfidence: numberFlag("min-confidence"),
3495
+ minSampleSize: numberFlag("min-sample-size"),
3496
+ limit: numberFlag("limit")
3497
+ });
3498
+ return output(result, () => {
3499
+ const runbook = Array.isArray(result.runbook) ? result.runbook : [];
3500
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
3501
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
3502
+ const readyCount = runbook.filter((step) => step.ready).length;
3503
+ console.log(blockers.length ? "GTM campaign start context: blocked" : "GTM campaign start context: ready");
3504
+ console.log(` Ready: ${readyCount}/${runbook.length} read-only calls`);
3505
+ console.log(` Safety: read-only; no credits spent, no provider writes, no send/export approval`);
3506
+ console.log(` Blockers: ${blockers.length}`);
3507
+ console.log(` Warnings: ${warnings.length}`);
3508
+ if (runbook.length) {
3509
+ console.log(" Runbook:");
3510
+ for (const step of runbook.slice(0, 6)) {
3511
+ console.log(` - ${step.tool || step.name || "unknown_tool"}${step.ready === false ? " [blocked]" : ""}`);
3512
+ }
3513
+ }
3514
+ if (blockers.length) {
3515
+ for (const blocker of blockers.slice(0, 5)) console.log(`- ${blocker}`);
3516
+ } else {
3517
+ hint("Review the read-only runbook, then run signaliz gtm plan with the same brief/template.");
3518
+ }
3519
+ });
3520
+ }
3521
+ if (sub === "templates" || sub === "strategy-templates") {
3522
+ const result = await sdk.gtm.campaignStrategyTemplates({
3523
+ strategyTemplate: flagArg("strategy-template") || flagArg("template"),
3524
+ query: flagArg("query") || flagArg("q"),
3525
+ includeDetails: !hasFlag("summary")
3526
+ });
3527
+ return output(result, () => {
3528
+ const templates = Array.isArray(result.templates) ? result.templates : [];
3529
+ console.log("GTM campaign strategy templates");
3530
+ for (const template of templates) {
3531
+ console.log(`- ${template.label || template.slug} (${template.slug})`);
3532
+ if (template.default_lead_count !== void 0) console.log(` Default lead count: ${template.default_lead_count}`);
3533
+ if (Array.isArray(template.preferred_providers)) console.log(` Providers: ${template.preferred_providers.join(", ")}`);
3534
+ if (template.usage?.cli) console.log(` CLI: ${template.usage.cli}`);
3535
+ }
3536
+ if (!templates.length) console.log("No strategy templates matched.");
3537
+ hint('Use one with: signaliz gtm plan "campaign brief" --strategy-template <slug> --json');
3538
+ });
3539
+ }
3540
+ if (sub === "strategy-memory" || sub === "memory-status" || sub === "strategy-memory-status") {
3541
+ const flags = parseCommandFlags(rest);
3542
+ const result = await sdk.gtm.campaignStrategyMemoryStatus({
3543
+ strategyTemplate: commandStringFlag(flags, "strategy-template", "template"),
3544
+ query: commandStringFlag(flags, "query", "goal", "q") || promptArg(rest),
3545
+ campaignBrief: commandStringFlag(flags, "brief", "campaign-brief"),
3546
+ targetIcp: readJsonObjectInput("target-icp-json", "target-icp-file") || campaignAgentJsonObjectInput(flags, ["icp", "target-icp"], ["icp-file", "target-icp-file"]),
3547
+ memoryDimensionFilters: readJsonObjectInput("memory-dimension-filters-json", "memory-dimension-filters-file"),
3548
+ requireMemoryDimensionMatch: commandBooleanFlag(flags, "require-memory-dimension-match") || void 0,
3549
+ includeSamples: commandBooleanFlag(flags, "include-samples") || void 0,
3550
+ includeSources: commandBooleanFlag(flags, "no-sources") ? false : void 0,
3551
+ days: commandNumberFlag(flags, "days"),
3552
+ limit: commandNumberFlag(flags, "limit")
3553
+ });
3554
+ return output(result, () => {
3555
+ const coverage = result.coverage || {};
3556
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
3557
+ const groups = Array.isArray(result.source_groups) ? result.source_groups : [];
3558
+ console.log(result.ready ? "GTM strategy memory: ready" : "GTM strategy memory: needs seeding");
3559
+ console.log(` Knowledge docs: ${coverage.knowledge_docs ?? 0}`);
3560
+ console.log(` Memories: ${coverage.memories ?? 0}`);
3561
+ console.log(` Required: ${coverage.required_groups_ready ?? 0}/${coverage.required_groups_total ?? 0}`);
3562
+ console.log(` Blockers: ${blockers.length}`);
3563
+ if (groups.length) {
3564
+ console.log(" Source groups:");
3565
+ for (const group of groups.slice(0, 6)) {
3566
+ console.log(` - ${group.label || group.id}: ${group.ready ? "ready" : "missing"}`);
3567
+ }
3568
+ }
3569
+ hint("Use the returned memory_search_request before gtm agent-plan or gtm plan.");
3570
+ });
3571
+ }
3572
+ if (sub === "agent-template" || sub === "campaign-agent-template" || sub === "request-template") {
3573
+ const flags = parseCommandFlags(rest);
3574
+ const goal = commandStringFlag(flags, "goal", "brief", "campaign-brief") || promptArg(rest);
3575
+ const targetIcp = readJsonObjectInput("target-icp-json", "target-icp-file") || campaignAgentJsonObjectInput(flags, ["icp", "target-icp"], ["icp-file", "target-icp-file"]);
3576
+ const result = await sdk.gtm.campaignAgentRequestTemplate({
3577
+ goal,
3578
+ campaignName: commandStringFlag(flags, "campaign-name", "name"),
3579
+ accountLabel: commandStringFlag(flags, "workspace-label", "account-label"),
3580
+ accountContext: commandStringFlag(flags, "account-context", "workspace-context"),
3581
+ strategyTemplate: commandStringFlag(flags, "strategy-template", "template"),
3582
+ operatingPlaybooks: commandCsvFlag(flags, "operating-playbooks", "playbooks"),
3583
+ targetIcp,
3584
+ targetCount: commandNumberFlag(flags, "target-count", "lead-count"),
3585
+ builtIns: campaignAgentBuiltInsFromFlags(flags),
3586
+ includeLocalLeads: commandBooleanFlag(flags, "use-local-leads") || commandBooleanFlag(flags, "include-local-leads") || void 0,
3587
+ includeByoPlaceholder: commandBooleanFlag(flags, "with-byo-placeholder") || commandBooleanFlag(flags, "include-byo-placeholder") || void 0,
3588
+ includeNangoCatalog: !commandBooleanFlag(flags, "no-nango-catalog"),
3589
+ preferredProviders: commandCsvFlag(flags, "preferred-providers", "providers"),
3590
+ privacyMode: commandStringFlag(flags, "privacy-mode"),
3591
+ destinationType: commandStringFlag(flags, "destination", "destination-type")
3592
+ });
3593
+ return output(result, () => {
3594
+ const request = result.request || {};
3595
+ console.log("GTM campaign request template: ready");
3596
+ console.log(` Campaign: ${request.campaignName || commandStringFlag(flags, "campaign-name", "name") || "Strategy Template Campaign"}`);
3597
+ console.log(` Target: ${request.targetCount || commandNumberFlag(flags, "target-count", "lead-count") || "n/a"}`);
3598
+ console.log(` Safety: read-only; no credits spent, no provider calls, no writes`);
3599
+ if (result.next_mcp_call?.tool) console.log(` Next MCP: ${result.next_mcp_call.tool}`);
3600
+ hint("Save request_json, then run signaliz campaign-agent plan --request-file campaign-builder-agent-request.json --json.");
3601
+ });
3602
+ }
3603
+ if (sub === "agent-plan" || sub === "campaign-agent-plan") {
3604
+ const flags = parseCommandFlags(rest);
3605
+ const goal = commandStringFlag(flags, "goal", "brief", "campaign-brief") || promptArg(rest);
3606
+ const strategyTemplate = commandStringFlag(flags, "strategy-template", "template");
3607
+ const targetIcp = readJsonObjectInput("target-icp-json", "target-icp-file") || campaignAgentJsonObjectInput(flags, ["icp", "target-icp"], ["icp-file", "target-icp-file"]);
3608
+ if (!goal && !commandStringFlag(flags, "campaign-id") && !commandStringFlag(flags, "campaign-build-id", "build-id") && !strategyTemplate && !targetIcp) {
3609
+ die('Usage: signaliz gtm agent-plan --goal "campaign brief" [--strategy-template ID] [--target-count N] [--json]');
3610
+ }
3611
+ const result = await sdk.gtm.campaignAgentPlan({
3612
+ goal,
3613
+ campaignName: commandStringFlag(flags, "campaign-name", "name"),
3614
+ campaignId: commandStringFlag(flags, "campaign-id"),
3615
+ campaignBuildId: commandStringFlag(flags, "campaign-build-id", "build-id"),
3616
+ strategyTemplate,
3617
+ operatingPlaybooks: commandCsvFlag(flags, "operating-playbooks", "playbooks"),
3618
+ accountContext: commandStringFlag(flags, "account-context", "workspace-context"),
3619
+ targetIcp,
3620
+ targetCount: commandNumberFlag(flags, "target-count", "lead-count"),
3621
+ builtIns: campaignAgentBuiltInsFromFlags(flags),
3622
+ useLocalLeads: commandBooleanFlag(flags, "use-local-leads") || void 0,
3623
+ layers: commandCsvFlag(flags, "layers"),
3624
+ preferredProviders: commandCsvFlag(flags, "preferred-providers", "providers"),
3625
+ customTools: campaignAgentCustomToolRoutesFromFlags(flags),
3626
+ strategyModel: commandStringFlag(flags, "strategy-model"),
3627
+ includeStrategyPatterns: !commandBooleanFlag(flags, "no-strategy-patterns"),
3628
+ includeWorkflowPatterns: !commandBooleanFlag(flags, "no-workflow-patterns"),
3629
+ includeNangoCatalog: !commandBooleanFlag(flags, "no-nango-catalog"),
3630
+ partnerEcosystem: commandCsvFlag(flags, "partner-ecosystem", "partners"),
3631
+ memoryDimensionFilters: readJsonObjectInput("memory-dimension-filters-json", "memory-dimension-filters-file"),
3632
+ requireMemoryDimensionMatch: commandBooleanFlag(flags, "require-memory-dimension-match") || void 0,
3633
+ includeMemory: !commandBooleanFlag(flags, "no-memory"),
3634
+ includeBrain: !commandBooleanFlag(flags, "no-brain"),
3635
+ includeProviderRoutes: !commandBooleanFlag(flags, "no-provider-routes"),
3636
+ includeFailurePatterns: !commandBooleanFlag(flags, "no-failure-patterns"),
3637
+ includeDeliveryRisk: !commandBooleanFlag(flags, "no-delivery-risk"),
3638
+ includePlannedProviders: !commandBooleanFlag(flags, "no-planned-providers"),
3639
+ days: commandNumberFlag(flags, "days"),
3640
+ limit: commandNumberFlag(flags, "limit")
3641
+ });
3642
+ return output(result, () => {
3643
+ const flow = Array.isArray(result.mcp_flow) ? result.mcp_flow : [];
3644
+ const approvals = Array.isArray(result.required_approvals) ? result.required_approvals : [];
3645
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
3646
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
3647
+ console.log(blockers.length ? "GTM campaign agent plan: blocked" : "GTM campaign agent plan: ready for review");
3648
+ console.log(` Plan ID: ${result.plan_id || "n/a"}`);
3649
+ console.log(` Campaign: ${result.campaign?.name || goal || "strategy-template campaign"}`);
3650
+ console.log(` Safety: read-only; no credits spent, no provider writes, no send/export approval`);
3651
+ console.log(` Flow: ${flow.length} MCP steps`);
3652
+ console.log(` Approvals: ${approvals.length}`);
3653
+ console.log(` Blockers: ${blockers.length}`);
3654
+ console.log(` Warnings: ${warnings.length}`);
3655
+ if (flow.length) {
3656
+ console.log(" Next MCP flow:");
3657
+ for (const step of flow.slice(0, 6)) console.log(` - ${step.tool || step.name || "unknown_tool"}`);
3658
+ }
3659
+ hint("Review the runbook, then call gtm_campaign_build_plan and dry-run gtm_campaign_build_plan_commit.");
3660
+ });
3661
+ }
2430
3662
  if (sub === "plan" || sub === "build-plan" || sub === "campaign-plan") {
2431
3663
  const campaignBrief = promptArg(rest) || flagArg("campaign-brief") || flagArg("brief");
2432
3664
  if (!campaignBrief && !flagArg("campaign-id") && !flagArg("campaign-build-id") && !flagArg("build-id")) {
2433
- die('Usage: signaliz gtm plan "campaign brief" [--target-count N] [--layers a,b] [--preferred-providers a,b]');
3665
+ die('Usage: signaliz gtm plan "campaign brief" [--strategy-template ID] [--target-count N] [--layers a,b] [--preferred-providers a,b]');
2434
3666
  }
2435
3667
  const result = await sdk.gtm.campaignBuildPlan({
2436
3668
  campaignId: flagArg("campaign-id"),
2437
3669
  campaignBuildId: flagArg("campaign-build-id") || flagArg("build-id"),
2438
3670
  campaignBrief,
3671
+ strategyTemplate: flagArg("strategy-template") || flagArg("template"),
2439
3672
  targetIcp: readJsonObjectInput("target-icp-json", "target-icp-file"),
2440
3673
  leadCount: numberFlag("lead-count") || numberFlag("target-count"),
2441
3674
  layers: csvFlag("layers"),
2442
3675
  preferredProviders: csvFlag("preferred-providers") || csvFlag("providers"),
3676
+ strategyModel: flagArg("strategy-model"),
3677
+ includeStrategyPatterns: !hasFlag("no-strategy-patterns") && !hasFlag("no-agency-patterns"),
3678
+ includeWorkflowPatterns: !hasFlag("no-workflow-patterns") && !hasFlag("no-clay-patterns"),
3679
+ includeNangoCatalog: !hasFlag("no-nango-catalog"),
3680
+ partnerEcosystem: csvFlag("partner-ecosystem") || csvFlag("partners"),
2443
3681
  memoryDimensionFilters: readJsonObjectInput("memory-dimension-filters-json", "memory-dimension-filters-file"),
2444
3682
  requireMemoryDimensionMatch: hasFlag("require-memory-dimension-match") || void 0,
2445
3683
  includeMemory: !hasFlag("no-memory"),
@@ -2930,6 +4168,52 @@ async function gtm(sub, rest) {
2930
4168
  hint("signaliz gtm activate-route --provider-id <provider> --layer <layer> --campaign-id <campaign_id>");
2931
4169
  });
2932
4170
  }
4171
+ if (sub === "provider-prepare" || sub === "prepare-provider" || sub === "recipe-prepare" || sub === "prepare-recipe") {
4172
+ const providerId = flagArg("provider-id") || flagArg("provider") || rest[0];
4173
+ if (!providerId) die("Usage: signaliz gtm provider-prepare --provider-id <provider_id> [--layer <layer>] [--json]");
4174
+ const result = await sdk.gtm.prepareProviderRecipe({
4175
+ providerId,
4176
+ providerName: flagArg("provider-name") || flagArg("name"),
4177
+ description: flagArg("description"),
4178
+ layerCapabilities: csvFlag("layer-capabilities") || csvFlag("layers"),
4179
+ invocationType: flagArg("invocation-type"),
4180
+ authStrategy: flagArg("auth-strategy"),
4181
+ endpointUrl: flagArg("endpoint-url"),
4182
+ httpMethod: flagArg("http-method"),
4183
+ secretRef: flagArg("secret-ref"),
4184
+ workspaceIntegrationId: flagArg("workspace-integration-id"),
4185
+ workspaceMcpServerId: flagArg("workspace-mcp-server-id"),
4186
+ workspaceConnectionId: flagArg("workspace-connection-id"),
4187
+ requestTemplate: readJsonObjectInput("request-template-json", "request-template-file"),
4188
+ responseMapping: readJsonObjectInput("response-mapping-json", "response-mapping-file"),
4189
+ inputSchema: readJsonObjectInput("input-schema-json", "input-schema-file"),
4190
+ outputSchema: readJsonObjectInput("output-schema-json", "output-schema-file"),
4191
+ readiness: readJsonObjectInput("readiness-json", "readiness-file"),
4192
+ metadata: readJsonObjectInput("metadata-json", "metadata-file"),
4193
+ layer: flagArg("layer"),
4194
+ campaignId: flagArg("campaign-id"),
4195
+ useSignalizFallback: !hasFlag("no-signaliz-fallback"),
4196
+ priority: numberFlag("priority"),
4197
+ status: flagArg("status"),
4198
+ sampleRecords: flagArg("records-file") ? readJsonValue(flagArg("records-file")) : void 0,
4199
+ context: readJsonObjectInput("context-json", "context-file")
4200
+ });
4201
+ return output(result, () => {
4202
+ const recipeArgs = result.recipe_arguments || result.recipeArgs || {};
4203
+ const routeArgs = result.route_arguments || result.routeArgs || {};
4204
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
4205
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
4206
+ console.log("GTM provider setup plan");
4207
+ console.log(` Provider: ${providerId}`);
4208
+ console.log(` Layer: ${flagArg("layer") || (Array.isArray(recipeArgs.layer_capabilities) ? recipeArgs.layer_capabilities[0] : "not specified")}`);
4209
+ console.log(" Safety: read-only; no recipe, route, provider call, or external write");
4210
+ if (recipeArgs.provider_id) console.log(` Recipe: ${recipeArgs.provider_id}`);
4211
+ if (routeArgs.layer) console.log(` Route: ${routeArgs.layer}`);
4212
+ if (blockers.length) console.log(` Blockers: ${blockers.join("; ")}`);
4213
+ if (warnings.length) console.log(` Warnings: ${warnings.join("; ")}`);
4214
+ hint("Review the recipe and route arguments, then run signaliz gtm activate-route as a dry-run.");
4215
+ });
4216
+ }
2933
4217
  if (sub === "activate-route" || sub === "route-activate") {
2934
4218
  const providerId = flagArg("provider-id") || rest[0];
2935
4219
  if (!providerId) die("Usage: signaliz gtm activate-route --provider-id <provider_id> --layer <layer> [--confirm]");
@@ -3026,7 +4310,7 @@ async function gtm(sub, rest) {
3026
4310
  });
3027
4311
  }
3028
4312
  if (sub === "find") {
3029
- const intent = rest.join(" ").trim() || flagArg("intent") || "";
4313
+ const intent = promptArg(rest) || flagArg("intent") || "";
3030
4314
  if (!intent) die('Usage: signaliz gtm find "<free-text intent>"');
3031
4315
  const result = await sdk.leads.findGtmCapability(intent);
3032
4316
  return output(result, () => {
@@ -3074,7 +4358,7 @@ ${i + 1}. ${m.capability_id} (score ${m.score}) \u2014 ${m.label}`);
3074
4358
  const result = await sdk.leads.checkStatus(jobId);
3075
4359
  return output(result);
3076
4360
  }
3077
- die("Usage: signaliz gtm <context|bootstrap|plan|commit-plan|prepare-build|campaigns|campaign|existing-campaigns|audit-existing|memory|learning|execution|integrations|activate-route|list|find|run|status|nango>");
4361
+ die("Usage: signaliz gtm <context|bootstrap|strategy-memory|agent-template|agent-plan|plan|commit-plan|prepare-build|campaigns|campaign|existing-campaigns|audit-existing|memory|learning|execution|integrations|provider-prepare|activate-route|list|find|run|status|nango>");
3078
4362
  }
3079
4363
  function nangoActionInput() {
3080
4364
  const fromFile = readJsonFlag("input-file");
@@ -3091,11 +4375,40 @@ function nangoBaseOptions() {
3091
4375
  nangoConnectionId: flagArg("nango-connection-id")
3092
4376
  };
3093
4377
  }
4378
+ function nangoConnectOptions() {
4379
+ return {
4380
+ providerId: flagArg("provider-id") || flagArg("provider"),
4381
+ integrationId: flagArg("integration-id") || flagArg("provider-config-key"),
4382
+ providerDisplayName: flagArg("provider-display-name") || flagArg("provider-name"),
4383
+ integrationDisplayName: flagArg("integration-display-name"),
4384
+ allowedIntegrations: csvFlag("allowed-integrations"),
4385
+ surface: flagArg("surface") || "gtm_kernel",
4386
+ source: flagArg("source") || "signaliz_cli",
4387
+ userEmail: flagArg("user-email"),
4388
+ userDisplayName: flagArg("user-display-name")
4389
+ };
4390
+ }
3094
4391
  function nangoStatusUrl(result) {
3095
4392
  return result?.status_url || result?.statusUrl || result?.nango_result?.status_url || result?.nango_result?.statusUrl;
3096
4393
  }
3097
4394
  async function gtmNango(sub, rest) {
3098
4395
  const sdk = getSdk();
4396
+ if (sub === "connect" || sub === "auth" || sub === "authorize") {
4397
+ const options = nangoConnectOptions();
4398
+ if (!options.providerId && !options.integrationId && (!options.allowedIntegrations || options.allowedIntegrations.length === 0)) {
4399
+ die("Usage: signaliz gtm nango connect --provider-id <provider> [--integration-id <key>] [--allowed-integrations a,b]");
4400
+ }
4401
+ const result = await sdk.gtm.createNangoConnectSession(options);
4402
+ return output(result, () => {
4403
+ console.log(`Nango connect session: ${result?.status || "created"}`);
4404
+ if (result?.provider_id || options.providerId) console.log(` Provider: ${result?.provider_id || options.providerId}`);
4405
+ if (result?.integration_id || options.integrationId) console.log(` Integration: ${result?.integration_id || options.integrationId}`);
4406
+ if (result?.connect_link || result?.auth_window_url) console.log(` Auth link: ${result.connect_link || result.auth_window_url}`);
4407
+ if (result?.expires_at) console.log(` Expires: ${result.expires_at}`);
4408
+ if (result?.next_action) console.log(` Next: ${result.next_action}`);
4409
+ hint("After authorization finishes, run signaliz gtm nango tools --workspace-connection-id <id> --provider-config-key <key>");
4410
+ });
4411
+ }
3099
4412
  if (!sub || sub === "tools" || sub === "list") {
3100
4413
  const result = await sdk.gtm.listNangoTools({
3101
4414
  ...nangoBaseOptions(),
@@ -3148,7 +4461,7 @@ async function gtmNango(sub, rest) {
3148
4461
  if (nextStatusUrl) console.log(` Status URL: ${nextStatusUrl}`);
3149
4462
  });
3150
4463
  }
3151
- die("Usage: signaliz gtm nango <tools|call|result>");
4464
+ die("Usage: signaliz gtm nango <connect|tools|call|result>");
3152
4465
  }
3153
4466
  async function email(sub, rest) {
3154
4467
  const sdk = getSdk();
@@ -4088,6 +5401,8 @@ async function main() {
4088
5401
  case "email":
4089
5402
  case "emails":
4090
5403
  return email(rest[0], rest.slice(1));
5404
+ case "campaign-agent":
5405
+ return campaignAgent(rest[0], rest.slice(1));
4091
5406
  case "campaign": {
4092
5407
  const sub = rest[0];
4093
5408
  if (!sub || sub === "--help" || sub === "-h") {