@signaliz/cli 1.0.2 → 1.0.3

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 +111 -4
  2. package/dist/bin.js +1898 -46
  3. package/package.json +4 -4
package/dist/bin.js CHANGED
@@ -214,13 +214,14 @@ var require_dist = __commonJS({
214
214
  details: { responseText: text.slice(0, 500) }
215
215
  });
216
216
  }
217
- if (data.error) {
217
+ const responseError = isRecord(data) && isRecord(data.error) ? data.error : null;
218
+ if (responseError) {
218
219
  const err = new SignalizError({
219
- code: data.error.code?.toString() || data.error.data?.error_code || "MCP_ERROR",
220
- message: data.error.message || "MCP request failed",
221
- errorType: mapMcpErrorType(data.error),
222
- retryAfter: data.error.data?.retry_after,
223
- details: data.error.data
220
+ code: firstString(responseError.code, isRecord(responseError.data) ? responseError.data.error_code : void 0) || "MCP_ERROR",
221
+ message: firstString(responseError.message) || "MCP request failed",
222
+ errorType: mapMcpErrorType(responseError),
223
+ retryAfter: isRecord(responseError.data) && typeof responseError.data.retry_after === "number" ? responseError.data.retry_after : void 0,
224
+ details: isRecord(responseError.data) ? responseError.data : void 0
224
225
  });
225
226
  if (err.isRetryable && attempt < this.maxRetries) {
226
227
  lastError = err;
@@ -297,35 +298,63 @@ var require_dist = __commonJS({
297
298
  }
298
299
  };
299
300
  }
301
+ function isRecord(value) {
302
+ return typeof value === "object" && value !== null;
303
+ }
304
+ function firstString(...values) {
305
+ const value = values.find((item) => typeof item === "string" && item.length > 0);
306
+ return typeof value === "string" ? value : void 0;
307
+ }
308
+ function firstPayloadError(payload) {
309
+ const errors = payload.errors;
310
+ const first = Array.isArray(errors) ? errors[0] : void 0;
311
+ return isRecord(first) ? first : {};
312
+ }
300
313
  function unwrapMcpResponse(data) {
301
- if (data?.result?.structuredContent !== void 0) {
302
- return unwrapMcpPayload(data.result.structuredContent);
314
+ const result = isRecord(data) ? data.result : void 0;
315
+ if (isRecord(result) && result.structuredContent !== void 0) {
316
+ return unwrapMcpPayload(result.structuredContent);
303
317
  }
304
- const text = data?.result?.content?.[0]?.text;
318
+ const content = isRecord(result) ? result.content : void 0;
319
+ const firstContent = Array.isArray(content) ? content[0] : void 0;
320
+ const text = isRecord(firstContent) ? firstContent.text : void 0;
305
321
  if (typeof text === "string") {
306
322
  const parsed = safeJson(text);
307
323
  return unwrapMcpPayload(parsed ?? text);
308
324
  }
309
- return unwrapMcpPayload(data?.result);
325
+ return unwrapMcpPayload(result);
310
326
  }
311
327
  function unwrapMcpPayload(payload) {
312
- if (payload && typeof payload === "object") {
328
+ if (isRecord(payload)) {
313
329
  if (payload.ok === true && Object.prototype.hasOwnProperty.call(payload, "result")) {
314
330
  return payload.result;
315
331
  }
332
+ if (payload.ok === false) {
333
+ const first = firstPayloadError(payload);
334
+ const code = firstString(first.code, payload.error_code, payload.code) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
335
+ throw new SignalizError({
336
+ code,
337
+ message: firstString(first.message, payload.message, payload.summary, payload.error) || "MCP request failed",
338
+ errorType: mapErrorTypeFromCode(code),
339
+ details: {
340
+ ...payload,
341
+ ...isRecord(first.details) ? first.details : {}
342
+ }
343
+ });
344
+ }
316
345
  if (payload.success === true && Object.prototype.hasOwnProperty.call(payload, "data")) {
317
346
  return payload.data;
318
347
  }
319
348
  if (payload.success === false) {
320
- const first = Array.isArray(payload.errors) ? payload.errors[0] ?? {} : {};
321
- const code = first.code || payload.error_code || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
349
+ const first = firstPayloadError(payload);
350
+ const code = firstString(first.code, payload.error_code) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
322
351
  throw new SignalizError({
323
352
  code,
324
- message: first.message || payload.message || payload.summary || "MCP request failed",
353
+ message: firstString(first.message, payload.message, payload.summary) || "MCP request failed",
325
354
  errorType: mapErrorTypeFromCode(code),
326
355
  details: {
327
356
  ...payload,
328
- ...first.details && typeof first.details === "object" ? first.details : {}
357
+ ...isRecord(first.details) ? first.details : {}
329
358
  }
330
359
  });
331
360
  }
@@ -333,8 +362,10 @@ var require_dist = __commonJS({
333
362
  return payload;
334
363
  }
335
364
  function mapMcpErrorType(error) {
336
- const code = String(error?.data?.error_code || error?.code || "");
337
- const message = String(error?.message || "").toLowerCase();
365
+ const errorRecord = isRecord(error) ? error : {};
366
+ const data = isRecord(errorRecord.data) ? errorRecord.data : {};
367
+ const code = String(data.error_code || errorRecord.code || "");
368
+ const message = String(errorRecord.message || "").toLowerCase();
338
369
  if (code === "429" || message.includes("rate limit")) return "rate_limited";
339
370
  if (code === "401" || code === "AUTH_001" || message.includes("auth")) return "auth_expired";
340
371
  if (code === "400" || code === "-32602" || message.includes("invalid")) return "validation";
@@ -895,14 +926,14 @@ var require_dist = __commonJS({
895
926
  async waitForCompletion(campaignBuildId, options) {
896
927
  const interval = options?.intervalMs ?? 5e3;
897
928
  const timeout = options?.timeoutMs ?? 6e5;
898
- const start = Date.now();
929
+ const start2 = Date.now();
899
930
  while (true) {
900
931
  const s = await this.getCampaignBuildStatus(campaignBuildId);
901
932
  options?.onStatus?.(s);
902
933
  if (["completed", "failed", "canceled"].includes(s.status)) {
903
934
  return s;
904
935
  }
905
- if (Date.now() - start > timeout) {
936
+ if (Date.now() - start2 > timeout) {
906
937
  throw new Error(`Campaign build ${campaignBuildId} timed out after ${timeout}ms (status: ${s.status})`);
907
938
  }
908
939
  await new Promise((r) => setTimeout(r, interval));
@@ -2943,6 +2974,10 @@ var require_dist = __commonJS({
2943
2974
  failed30d: numberValue(summary.failed_30d ?? summary.failed30d),
2944
2975
  external_delivered_30d: numberValue(summary.external_delivered_30d ?? summary.externalDelivered30d),
2945
2976
  externalDelivered30d: numberValue(summary.external_delivered_30d ?? summary.externalDelivered30d),
2977
+ nango_proofs_30d: numberValue(summary.nango_proofs_30d ?? summary.nangoProofs30d),
2978
+ nangoProofs30d: numberValue(summary.nango_proofs_30d ?? summary.nangoProofs30d),
2979
+ nango_failures_30d: numberValue(summary.nango_failures_30d ?? summary.nangoFailures30d),
2980
+ nangoFailures30d: numberValue(summary.nango_failures_30d ?? summary.nangoFailures30d),
2946
2981
  airbyte_configured: numberValue(summary.airbyte_configured ?? summary.airbyteConfigured),
2947
2982
  airbyteConfigured: numberValue(summary.airbyte_configured ?? summary.airbyteConfigured),
2948
2983
  airbyte_proofs_30d: numberValue(summary.airbyte_proofs_30d ?? summary.airbyteProofs30d),
@@ -3357,9 +3392,10 @@ var require_dist = __commonJS({
3357
3392
  }
3358
3393
  function buildCreateRoutineBody(params) {
3359
3394
  const { outputSinks, wakeOnEvents, ...rest } = params;
3395
+ const sinks = rest.output_sinks ?? outputSinks;
3360
3396
  return {
3361
3397
  ...rest,
3362
- output_sinks: rest.output_sinks ?? outputSinks,
3398
+ output_sinks: Array.isArray(sinks) ? sinks.map(normalizeOpsSinkRequest) : sinks,
3363
3399
  wake_on_events: rest.wake_on_events ?? wakeOnEvents
3364
3400
  };
3365
3401
  }
@@ -3393,6 +3429,97 @@ var require_dist = __commonJS({
3393
3429
  webhook_url: rest.webhook_url ?? webhookUrl
3394
3430
  };
3395
3431
  }
3432
+ function normalizeOpsSinkRequest(sink) {
3433
+ const {
3434
+ sinkId,
3435
+ connectionId,
3436
+ connectorId,
3437
+ connectorName,
3438
+ deliveryMode,
3439
+ providerConfigKey,
3440
+ integrationId,
3441
+ nangoConnectionId,
3442
+ actionName,
3443
+ nangoAction,
3444
+ proxyPath,
3445
+ nangoProxyPath,
3446
+ fieldMap,
3447
+ requiredFields,
3448
+ writeConfirmed,
3449
+ agentWriteConfirmed,
3450
+ config,
3451
+ ...rest
3452
+ } = sink;
3453
+ const normalizedConfig = normalizeOpsSinkConfigRequest(config);
3454
+ const connection_id = rest.connection_id ?? connectionId;
3455
+ const connector_id = rest.connector_id ?? connectorId;
3456
+ const delivery_mode = rest.delivery_mode ?? deliveryMode;
3457
+ const provider_config_key = rest.provider_config_key ?? providerConfigKey;
3458
+ const integration_id = rest.integration_id ?? integrationId;
3459
+ const nango_connection_id = rest.nango_connection_id ?? nangoConnectionId;
3460
+ const action_name = rest.action_name ?? actionName;
3461
+ const nango_action = rest.nango_action ?? nangoAction;
3462
+ const proxy_path = rest.proxy_path ?? proxyPath;
3463
+ const nango_proxy_path = rest.nango_proxy_path ?? nangoProxyPath;
3464
+ const field_map = rest.field_map ?? fieldMap;
3465
+ const required_fields = rest.required_fields ?? requiredFields;
3466
+ const write_confirmed = rest.write_confirmed ?? writeConfirmed;
3467
+ const agent_write_confirmed = rest.agent_write_confirmed ?? agentWriteConfirmed;
3468
+ if (connection_id !== void 0 && normalizedConfig.connection_id === void 0) normalizedConfig.connection_id = connection_id;
3469
+ if (connector_id !== void 0 && normalizedConfig.connector_id === void 0) normalizedConfig.connector_id = connector_id;
3470
+ if (delivery_mode !== void 0 && normalizedConfig.delivery_mode === void 0) normalizedConfig.delivery_mode = delivery_mode;
3471
+ if (provider_config_key !== void 0 && normalizedConfig.provider_config_key === void 0) normalizedConfig.provider_config_key = provider_config_key;
3472
+ if (integration_id !== void 0 && normalizedConfig.integration_id === void 0) normalizedConfig.integration_id = integration_id;
3473
+ if (nango_connection_id !== void 0 && normalizedConfig.nango_connection_id === void 0) normalizedConfig.nango_connection_id = nango_connection_id;
3474
+ if (action_name !== void 0 && normalizedConfig.action_name === void 0) normalizedConfig.action_name = action_name;
3475
+ if (nango_action !== void 0 && normalizedConfig.nango_action === void 0) normalizedConfig.nango_action = nango_action;
3476
+ if (proxy_path !== void 0 && normalizedConfig.proxy_path === void 0) normalizedConfig.proxy_path = proxy_path;
3477
+ if (nango_proxy_path !== void 0 && normalizedConfig.nango_proxy_path === void 0) normalizedConfig.nango_proxy_path = nango_proxy_path;
3478
+ if (field_map !== void 0 && normalizedConfig.field_map === void 0) normalizedConfig.field_map = field_map;
3479
+ if (required_fields !== void 0 && normalizedConfig.required_fields === void 0) normalizedConfig.required_fields = required_fields;
3480
+ if (write_confirmed !== void 0 && normalizedConfig.write_confirmed === void 0) normalizedConfig.write_confirmed = write_confirmed;
3481
+ if (agent_write_confirmed !== void 0 && normalizedConfig.agent_write_confirmed === void 0) normalizedConfig.agent_write_confirmed = agent_write_confirmed;
3482
+ if (sink.type === "nango" && normalizedConfig.integration_platform === void 0) normalizedConfig.integration_platform = "nango";
3483
+ return {
3484
+ ...rest,
3485
+ sink_id: rest.sink_id ?? sinkId,
3486
+ connection_id,
3487
+ connector_id,
3488
+ connector_name: rest.connector_name ?? connectorName,
3489
+ delivery_mode,
3490
+ provider_config_key,
3491
+ integration_id,
3492
+ nango_connection_id,
3493
+ action_name,
3494
+ nango_action,
3495
+ proxy_path,
3496
+ nango_proxy_path,
3497
+ field_map,
3498
+ required_fields,
3499
+ write_confirmed,
3500
+ agent_write_confirmed,
3501
+ config: normalizedConfig
3502
+ };
3503
+ }
3504
+ function normalizeOpsSinkConfigRequest(config) {
3505
+ const out = { ...config ?? {} };
3506
+ if (out.connection_id === void 0 && out.connectionId !== void 0) out.connection_id = out.connectionId;
3507
+ if (out.connector_id === void 0 && out.connectorId !== void 0) out.connector_id = out.connectorId;
3508
+ if (out.connector_name === void 0 && out.connectorName !== void 0) out.connector_name = out.connectorName;
3509
+ if (out.delivery_mode === void 0 && out.deliveryMode !== void 0) out.delivery_mode = out.deliveryMode;
3510
+ if (out.provider_config_key === void 0 && out.providerConfigKey !== void 0) out.provider_config_key = out.providerConfigKey;
3511
+ if (out.integration_id === void 0 && out.integrationId !== void 0) out.integration_id = out.integrationId;
3512
+ if (out.nango_connection_id === void 0 && out.nangoConnectionId !== void 0) out.nango_connection_id = out.nangoConnectionId;
3513
+ if (out.action_name === void 0 && out.actionName !== void 0) out.action_name = out.actionName;
3514
+ if (out.nango_action === void 0 && out.nangoAction !== void 0) out.nango_action = out.nangoAction;
3515
+ if (out.proxy_path === void 0 && out.proxyPath !== void 0) out.proxy_path = out.proxyPath;
3516
+ if (out.nango_proxy_path === void 0 && out.nangoProxyPath !== void 0) out.nango_proxy_path = out.nangoProxyPath;
3517
+ if (out.field_map === void 0 && out.fieldMap !== void 0) out.field_map = out.fieldMap;
3518
+ if (out.required_fields === void 0 && out.requiredFields !== void 0) out.required_fields = out.requiredFields;
3519
+ if (out.write_confirmed === void 0 && out.writeConfirmed !== void 0) out.write_confirmed = out.writeConfirmed;
3520
+ if (out.agent_write_confirmed === void 0 && out.agentWriteConfirmed !== void 0) out.agent_write_confirmed = out.agentWriteConfirmed;
3521
+ return out;
3522
+ }
3396
3523
  function buildApproveBody(params) {
3397
3524
  const { tokenId, tokenIds, reviewerNotes, ...rest } = params;
3398
3525
  return {
@@ -3537,6 +3664,57 @@ var require_dist = __commonJS({
3537
3664
  limit: options.limit
3538
3665
  });
3539
3666
  }
3667
+ /** Discover existing provider campaigns, starting with live/Kernel-linked Instantly campaigns, before audit or import preview. */
3668
+ async discoverExistingCampaigns(options = {}) {
3669
+ return this.callMcp("gtm_existing_campaign_discover", {
3670
+ provider: options.provider,
3671
+ integration_id: options.integrationId,
3672
+ search: options.search,
3673
+ limit: options.limit,
3674
+ include_kernel_linked: options.includeKernelLinked,
3675
+ include_provider_live: options.includeProviderLive
3676
+ });
3677
+ }
3678
+ /** Run a read-only existing campaign audit with completeness, recommendations, safe next MCP JSON, and approval boundaries. */
3679
+ async auditExistingCampaign(options) {
3680
+ return this.callMcp("gtm_existing_campaign_audit", {
3681
+ campaign_id: options.campaignId,
3682
+ provider: options.provider,
3683
+ provider_campaign_id: options.providerCampaignId,
3684
+ campaign_name: options.campaignName,
3685
+ days: options.days,
3686
+ include_route_preview: options.includeRoutePreview,
3687
+ include_memory: options.includeMemory,
3688
+ include_brain: options.includeBrain
3689
+ });
3690
+ }
3691
+ /** Discover the first matching existing provider campaign, then run the same read-only audit against that match. */
3692
+ async auditExistingCampaignBySearch(options) {
3693
+ const discovery = await this.discoverExistingCampaigns({
3694
+ provider: options.provider,
3695
+ integrationId: options.integrationId,
3696
+ search: options.search,
3697
+ limit: 1,
3698
+ includeKernelLinked: options.includeKernelLinked,
3699
+ includeProviderLive: options.includeProviderLive
3700
+ });
3701
+ const match = discovery.campaigns?.[0];
3702
+ const campaignId = match?.linked_kernel_campaign_id || void 0;
3703
+ const providerCampaignId = match?.provider_campaign_id || void 0;
3704
+ if (!campaignId && !providerCampaignId) {
3705
+ throw new Error(`No existing ${options.provider || discovery.provider || "provider"} campaign matched "${options.search}"`);
3706
+ }
3707
+ return this.auditExistingCampaign({
3708
+ provider: options.provider || discovery.provider || match?.provider,
3709
+ campaignId,
3710
+ providerCampaignId,
3711
+ campaignName: match?.name || match?.linked_kernel_campaign_name || void 0,
3712
+ days: options.days,
3713
+ includeRoutePreview: options.includeRoutePreview,
3714
+ includeMemory: options.includeMemory,
3715
+ includeBrain: options.includeBrain
3716
+ });
3717
+ }
3540
3718
  /** Create a first-class GTM campaign object in the current workspace. */
3541
3719
  async createCampaign(input) {
3542
3720
  return this.callMcp("gtm_campaign_create", campaignCreateArgs(input));
@@ -3742,6 +3920,47 @@ var require_dist = __commonJS({
3742
3920
  brain_cycle_min_interval_minutes: input.brainCycleMinIntervalMinutes
3743
3921
  });
3744
3922
  }
3923
+ /** Preview anonymized Instantly workspace sources registered for Kernel import. */
3924
+ async previewKernelImport(input = {}) {
3925
+ return this.callMcp("gtm_kernel_import_preview", {
3926
+ source_ids: input.sourceIds,
3927
+ include_leads: input.includeLeads,
3928
+ include_replies: input.includeReplies,
3929
+ include_private_copy: input.includePrivateCopy,
3930
+ max_pages: input.maxPages,
3931
+ limit: input.limit
3932
+ });
3933
+ }
3934
+ /** Queue the read-only Instantly-to-GTM Kernel import. Live writes require writeApproved. */
3935
+ async runKernelImport(input = {}) {
3936
+ return this.callMcp("gtm_kernel_import_run", {
3937
+ source_ids: input.sourceIds,
3938
+ dry_run: input.dryRun,
3939
+ write_approved: input.writeApproved,
3940
+ include_leads: input.includeLeads,
3941
+ include_replies: input.includeReplies,
3942
+ include_private_copy: input.includePrivateCopy,
3943
+ private_copy_approved: input.privateCopyApproved,
3944
+ promote_global_patterns: input.promoteGlobalPatterns,
3945
+ min_global_privacy_k: input.minGlobalPrivacyK,
3946
+ max_pages: input.maxPages,
3947
+ limit: input.limit
3948
+ });
3949
+ }
3950
+ /** Queue Brain distillation over imported Instantly memory with abstracted-only outputs. */
3951
+ async runBrainDistillation(input = {}) {
3952
+ return this.callMcp("gtm_brain_distill_run", {
3953
+ source_ids: input.sourceIds,
3954
+ write_mode: input.writeMode,
3955
+ write_approved: input.writeApproved,
3956
+ brain_cycle_phases: input.brainCyclePhases,
3957
+ days: input.days,
3958
+ network_days: input.networkDays,
3959
+ min_sample_size: input.minSampleSize,
3960
+ min_workspace_count: input.minWorkspaceCount,
3961
+ min_privacy_k: input.minPrivacyK
3962
+ });
3963
+ }
3745
3964
  /** Prepare a provider-agnostic feedback webhook URL for Smartlead, HeyReach, Airbyte, or custom sender events. */
3746
3965
  async prepareFeedbackWebhook(input) {
3747
3966
  return this.callMcp("gtm_feedback_webhook_prepare", {
@@ -4169,6 +4388,43 @@ var require_dist = __commonJS({
4169
4388
  context: input.context
4170
4389
  });
4171
4390
  }
4391
+ /** List Nango-backed action tools for a workspace connection without executing them. */
4392
+ async listNangoTools(options = {}) {
4393
+ return this.callMcp("nango_mcp_tools_list", {
4394
+ workspace_connection_id: options.workspaceConnectionId,
4395
+ connection_id: options.connectionId,
4396
+ provider_config_key: options.providerConfigKey,
4397
+ integration_id: options.integrationId,
4398
+ nango_connection_id: options.nangoConnectionId,
4399
+ format: options.format,
4400
+ include_raw: options.includeRaw
4401
+ });
4402
+ }
4403
+ /** Dry-run or execute a Nango-backed action tool through the approval-aware MCP bridge. */
4404
+ async callNangoTool(input) {
4405
+ return this.callMcp("nango_mcp_tool_call", {
4406
+ workspace_connection_id: input.workspaceConnectionId,
4407
+ connection_id: input.connectionId,
4408
+ provider_config_key: input.providerConfigKey,
4409
+ integration_id: input.integrationId,
4410
+ nango_connection_id: input.nangoConnectionId,
4411
+ action_name: input.actionName,
4412
+ tool_name: input.toolName,
4413
+ input: input.input,
4414
+ async: input.async,
4415
+ max_retries: input.maxRetries,
4416
+ dry_run: input.dryRun,
4417
+ confirm: input.confirm,
4418
+ confirm_write: input.confirmWrite
4419
+ });
4420
+ }
4421
+ /** Poll an async Nango action result by action id or status URL. */
4422
+ async getNangoActionResult(input) {
4423
+ return this.callMcp("nango_mcp_action_result_get", {
4424
+ action_id: input.actionId,
4425
+ status_url: input.statusUrl
4426
+ });
4427
+ }
4172
4428
  /** Deliver approved campaign-layer records to a webhook recipe, starting with Clay-style webhooks. */
4173
4429
  async deliverWebhook(input) {
4174
4430
  return this.callMcp("gtm_webhook_deliver", {
@@ -4301,6 +4557,59 @@ var require_dist = __commonJS({
4301
4557
  }
4302
4558
  return out;
4303
4559
  }
4560
+ function inferMcpToolCategory2(toolName) {
4561
+ if (typeof toolName !== "string" || !toolName) return void 0;
4562
+ if (toolName.startsWith("ops_") || toolName === "get_ops_readiness" || toolName === "get_gtm_ops_readiness" || toolName.startsWith("gtm_") || [
4563
+ "list_routines",
4564
+ "create_routine",
4565
+ "update_routine",
4566
+ "run_routine_now",
4567
+ "get_routine",
4568
+ "get_routine_ticks",
4569
+ "get_tick_items",
4570
+ "get_last_tick_items",
4571
+ "chain_routines",
4572
+ "get_chain_status",
4573
+ "launch_campaign",
4574
+ "quickstart_gtm_book",
4575
+ "list_campaigns",
4576
+ "campaign_performance",
4577
+ "tune_campaign",
4578
+ "emit_event",
4579
+ "approvals_list",
4580
+ "list_output_sinks",
4581
+ "create_output_sink",
4582
+ "update_output_sink",
4583
+ "delete_output_sink",
4584
+ "attach_sink_to_routine"
4585
+ ].includes(toolName)) {
4586
+ return "ops";
4587
+ }
4588
+ if ([
4589
+ "find_emails_with_verification",
4590
+ "verify_email",
4591
+ "enrich_company_signals",
4592
+ "company_intelligence",
4593
+ "find_contacts_with_email",
4594
+ "execute_primitive"
4595
+ ].includes(toolName)) {
4596
+ return "enrichment";
4597
+ }
4598
+ if (toolName.includes("icp")) return "icp";
4599
+ if (toolName.startsWith("ai_clean_")) return "data_cleaning";
4600
+ if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
4601
+ if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
4602
+ return void 0;
4603
+ }
4604
+ function asRecord3(value) {
4605
+ return value && typeof value === "object" ? value : void 0;
4606
+ }
4607
+ function asStringArray(value) {
4608
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : void 0;
4609
+ }
4610
+ function asObjectSchema(value) {
4611
+ return asRecord3(value);
4612
+ }
4304
4613
  var Signaliz = class {
4305
4614
  constructor(config) {
4306
4615
  this.client = new HttpClient(config);
@@ -4359,21 +4668,21 @@ var require_dist = __commonJS({
4359
4668
  const data = await this.client.mcp("tools/list", {});
4360
4669
  const tools2 = data?.tools ?? data ?? [];
4361
4670
  return tools2.map((t) => ({
4362
- name: t.name,
4363
- description: (t.description ?? "").slice(0, 120),
4364
- category: t.annotations?.category,
4365
- costCredits: t.annotations?.cost_credits,
4366
- contractVersion: t.annotations?.contract_version ?? t.annotations?.contract?.contract_version,
4367
- permissionLevel: t.annotations?.permission_level ?? t.annotations?.contract?.permission_level,
4368
- authScopes: t.annotations?.auth_scopes ?? t.annotations?.contract?.auth_scopes,
4369
- idempotent: t.annotations?.idempotentHint ?? t.annotations?.idempotent ?? t.annotations?.contract?.idempotent,
4370
- destructive: t.annotations?.destructiveHint ?? t.annotations?.destructive ?? t.annotations?.contract?.destructive,
4371
- retryable: t.annotations?.retryable ?? t.annotations?.contract?.retryable,
4372
- rateLimitKey: t.annotations?.rate_limit_key ?? t.annotations?.contract?.rate_limit_key,
4373
- observability: t.annotations?.observability ?? t.annotations?.contract?.observability,
4374
- inputSchema: t.inputSchema ?? t.input_schema ?? t.annotations?.contract?.input_schema,
4375
- outputSchema: t.outputSchema ?? t.output_schema ?? t.annotations?.contract?.output_schema,
4376
- annotations: t.annotations
4671
+ name: typeof t.name === "string" ? t.name : "",
4672
+ description: String(t.description ?? "").slice(0, 120),
4673
+ category: typeof t.annotations?.category === "string" ? t.annotations.category : inferMcpToolCategory2(t.name),
4674
+ costCredits: typeof t.annotations?.cost_credits === "number" ? t.annotations.cost_credits : void 0,
4675
+ contractVersion: typeof (t.annotations?.contract_version ?? t.annotations?.contract?.contract_version) === "string" ? t.annotations?.contract_version ?? t.annotations?.contract?.contract_version : void 0,
4676
+ permissionLevel: typeof (t.annotations?.permission_level ?? t.annotations?.contract?.permission_level) === "string" ? t.annotations?.permission_level ?? t.annotations?.contract?.permission_level : void 0,
4677
+ authScopes: asStringArray(t.annotations?.auth_scopes ?? t.annotations?.contract?.auth_scopes),
4678
+ idempotent: typeof (t.annotations?.idempotentHint ?? t.annotations?.idempotent ?? t.annotations?.contract?.idempotent) === "boolean" ? t.annotations?.idempotentHint ?? t.annotations?.idempotent ?? t.annotations?.contract?.idempotent : void 0,
4679
+ destructive: typeof (t.annotations?.destructiveHint ?? t.annotations?.destructive ?? t.annotations?.contract?.destructive) === "boolean" ? t.annotations?.destructiveHint ?? t.annotations?.destructive ?? t.annotations?.contract?.destructive : void 0,
4680
+ retryable: typeof (t.annotations?.retryable ?? t.annotations?.contract?.retryable) === "boolean" ? t.annotations?.retryable ?? t.annotations?.contract?.retryable : void 0,
4681
+ rateLimitKey: typeof (t.annotations?.rate_limit_key ?? t.annotations?.contract?.rate_limit_key) === "string" ? t.annotations?.rate_limit_key ?? t.annotations?.contract?.rate_limit_key : void 0,
4682
+ observability: asRecord3(t.annotations?.observability ?? t.annotations?.contract?.observability),
4683
+ inputSchema: asObjectSchema(t.inputSchema ?? t.input_schema ?? t.annotations?.contract?.input_schema),
4684
+ outputSchema: asObjectSchema(t.outputSchema ?? t.output_schema ?? t.annotations?.contract?.output_schema),
4685
+ annotations: asRecord3(t.annotations)
4377
4686
  }));
4378
4687
  }
4379
4688
  /** Discover tools by natural language query */
@@ -4469,40 +4778,194 @@ function readJsonFlag(name) {
4469
4778
  if (!file) return void 0;
4470
4779
  return JSON.parse((0, import_node_fs.readFileSync)(file, "utf8"));
4471
4780
  }
4781
+ function readInlineJsonFlag(name) {
4782
+ const raw = flagArg(name);
4783
+ if (!raw) return void 0;
4784
+ const parsed = JSON.parse(raw);
4785
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4786
+ die(`--${name} must be a JSON object`);
4787
+ }
4788
+ return parsed;
4789
+ }
4790
+ function readJsonObjectInput(inlineFlag, fileFlag) {
4791
+ const inline = readInlineJsonFlag(inlineFlag);
4792
+ if (inline) return inline;
4793
+ const file = flagArg(fileFlag);
4794
+ if (!file) return void 0;
4795
+ const parsed = readJsonValue(file);
4796
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4797
+ die(`--${fileFlag} must point to a JSON object`);
4798
+ }
4799
+ return parsed;
4800
+ }
4801
+ function normalizeCampaignBuildInput(raw) {
4802
+ const source = raw?.build_campaign_arguments || raw?.buildCampaignArguments || raw?.build_campaign_args || raw?.buildCampaignArgs || raw || {};
4803
+ if (!source || typeof source !== "object" || Array.isArray(source)) return {};
4804
+ const get = (snake, camel) => source[snake] ?? source[camel];
4805
+ const nested = (snake, camel) => {
4806
+ const value = get(snake, camel);
4807
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
4808
+ };
4809
+ const policy = nested("policy", "policy");
4810
+ const signals = nested("signals", "signals");
4811
+ const copy = nested("copy", "copy");
4812
+ const delivery = nested("delivery", "delivery");
4813
+ return {
4814
+ name: get("name", "name"),
4815
+ prompt: get("prompt", "prompt"),
4816
+ gtmCampaignId: get("gtm_campaign_id", "gtmCampaignId"),
4817
+ description: get("description", "description"),
4818
+ targetCount: get("target_count", "targetCount"),
4819
+ dryRun: get("dry_run", "dryRun"),
4820
+ allowDownscale: get("allow_downscale", "allowDownscale"),
4821
+ confirmSpend: get("confirm_spend", "confirmSpend"),
4822
+ dedupKeys: get("dedup_keys", "dedupKeys"),
4823
+ brainPreflight: get("brain_preflight", "brainPreflight"),
4824
+ brainDefaults: get("brain_defaults", "brainDefaults"),
4825
+ deliveryRisk: get("delivery_risk", "deliveryRisk"),
4826
+ icp: nested("icp", "icp"),
4827
+ policy: policy ? {
4828
+ ...policy,
4829
+ maxCredits: policy.max_credits ?? policy.maxCredits,
4830
+ verifyEmails: policy.verify_emails ?? policy.verifyEmails
4831
+ } : void 0,
4832
+ signals: signals ? {
4833
+ ...signals,
4834
+ customPrompt: signals.custom_prompt ?? signals.customPrompt,
4835
+ confidenceThreshold: signals.confidence_threshold ?? signals.confidenceThreshold,
4836
+ lookbackDays: signals.lookback_days ?? signals.lookbackDays
4837
+ } : void 0,
4838
+ qualification: nested("qualification", "qualification"),
4839
+ copy: copy ? {
4840
+ ...copy,
4841
+ maxBodyWords: copy.max_body_words ?? copy.maxBodyWords,
4842
+ senderContext: copy.sender_context ?? copy.senderContext,
4843
+ offerContext: copy.offer_context ?? copy.offerContext
4844
+ } : void 0,
4845
+ delivery: delivery ? {
4846
+ ...delivery,
4847
+ destinationType: delivery.destination_type ?? delivery.destinationType,
4848
+ approvalRequired: delivery.approval_required ?? delivery.approvalRequired,
4849
+ includeDisqualified: delivery.include_disqualified ?? delivery.includeDisqualified,
4850
+ destinationConfig: delivery.destination_config ?? delivery.destinationConfig
4851
+ } : void 0,
4852
+ enhancers: nested("enhancers", "enhancers")
4853
+ };
4854
+ }
4472
4855
  var promptValueFlags = /* @__PURE__ */ new Set([
4856
+ "action-id",
4857
+ "action-name",
4858
+ "actor-id",
4859
+ "actor-type",
4473
4860
  "analysis-models",
4474
4861
  "attachment-field",
4475
4862
  "attachment-fields",
4476
4863
  "attachment-file",
4477
4864
  "attachment-url",
4478
4865
  "blueprint",
4866
+ "brain-config-file",
4867
+ "brain-config-json",
4868
+ "build-id",
4479
4869
  "cadence",
4870
+ "campaign-build-id",
4871
+ "campaign-id",
4872
+ "campaign-brief",
4873
+ "brief",
4480
4874
  "company-domains",
4481
4875
  "company-domain",
4482
4876
  "company-name",
4877
+ "connection-id",
4878
+ "context-json",
4879
+ "copy-file",
4880
+ "copy-json",
4483
4881
  "destination",
4484
4882
  "destinations",
4883
+ "days",
4884
+ "dedup-keys",
4885
+ "delivery-file",
4886
+ "delivery-json",
4887
+ "delivery-risk-file",
4888
+ "delivery-risk-json",
4485
4889
  "domains",
4890
+ "enhancers-file",
4891
+ "enhancers-json",
4486
4892
  "file-url",
4893
+ "integration-id",
4487
4894
  "image-url",
4488
4895
  "input-file",
4489
4896
  "input-json",
4897
+ "instantly-campaign-id",
4898
+ "idempotency-key",
4490
4899
  "judge-model",
4900
+ "layer",
4901
+ "layers",
4902
+ "limit",
4903
+ "lead-count",
4904
+ "log-limit",
4491
4905
  "max-concurrency",
4906
+ "max-retries",
4492
4907
  "max-tokens",
4908
+ "memory-limit",
4909
+ "memory-type",
4493
4910
  "model",
4911
+ "name",
4912
+ "min-sample-size",
4913
+ "min-workspace-count",
4914
+ "nango-connection-id",
4915
+ "network-days",
4494
4916
  "output-format",
4495
4917
  "output-fields",
4496
4918
  "output-fields-file",
4919
+ "outcome-type",
4497
4920
  "pdf-engine",
4498
4921
  "pdf-url",
4922
+ "phases",
4923
+ "policy-file",
4924
+ "policy-json",
4925
+ "provider",
4926
+ "providers",
4927
+ "preferred-providers",
4928
+ "provider-account-id",
4929
+ "provider-campaign-id",
4930
+ "provider-config-key",
4931
+ "provider-id",
4932
+ "provider-link-id",
4933
+ "provider-name",
4934
+ "provider-workspace-id",
4935
+ "qualification-file",
4936
+ "qualification-json",
4499
4937
  "records-file",
4500
4938
  "records-json",
4939
+ "readiness-json",
4940
+ "rationale",
4941
+ "route-config-json",
4942
+ "route-status",
4943
+ "secret-ref",
4944
+ "search",
4945
+ "send-config-file",
4946
+ "send-config-json",
4947
+ "signals-file",
4948
+ "signals-json",
4949
+ "status",
4950
+ "status-url",
4501
4951
  "system-prompt",
4502
4952
  "target-count",
4953
+ "target-icp-file",
4954
+ "target-icp-json",
4503
4955
  "temperature",
4956
+ "tool-name",
4504
4957
  "url",
4505
- "video-url"
4958
+ "video-url",
4959
+ "write-mode",
4960
+ "workspace-connection-id",
4961
+ "workspace-integration-id",
4962
+ "workspace-mcp-server-id",
4963
+ "memory-dimension-filters-file",
4964
+ "memory-dimension-filters-json",
4965
+ "metadata-file",
4966
+ "metadata-json",
4967
+ "plan-file",
4968
+ "plan-json"
4506
4969
  ]);
4507
4970
  function promptArg(rest) {
4508
4971
  const explicit = flagArg("prompt");
@@ -4537,6 +5000,26 @@ function hint(msg) {
4537
5000
  if (!jsonMode()) console.log(`
4538
5001
  \u2192 ${msg}`);
4539
5002
  }
5003
+ function labelize(value) {
5004
+ return String(value || "").replace(/[_-]+/g, " ").trim();
5005
+ }
5006
+ function arrayCount(value) {
5007
+ return Array.isArray(value) ? value.length : 0;
5008
+ }
5009
+ function firstExistingCampaignSafeAction(result) {
5010
+ const packet = result?.improvement_packet || result?.audit_packet?.improvement_packet || {};
5011
+ const groups = [
5012
+ packet.fix_before_scale || packet.fixBeforeScale,
5013
+ packet.improve_next || packet.improveNext,
5014
+ packet.verify
5015
+ ];
5016
+ for (const group of groups) {
5017
+ const match = Array.isArray(group) ? group.find((item) => ["read_only", "dry_run"].includes(String(item?.approval_boundary || item?.approvalBoundary || ""))) : null;
5018
+ if (match) return match;
5019
+ }
5020
+ const recommendations = Array.isArray(result?.recommendations) ? result.recommendations : [];
5021
+ return recommendations.find((item) => ["read_only", "dry_run"].includes(String(item?.approval_boundary || item?.approvalBoundary || ""))) || null;
5022
+ }
4540
5023
  function formatToolSafety(tool) {
4541
5024
  const parts = [
4542
5025
  tool.permissionLevel || "unknown",
@@ -4546,6 +5029,53 @@ function formatToolSafety(tool) {
4546
5029
  ].filter(Boolean);
4547
5030
  return parts.join(" | ") || "-";
4548
5031
  }
5032
+ function inferMcpToolCategory(toolName) {
5033
+ if (typeof toolName !== "string" || !toolName) return void 0;
5034
+ if (toolName.startsWith("ops_") || toolName === "get_ops_readiness" || toolName === "get_gtm_ops_readiness" || toolName.startsWith("gtm_") || [
5035
+ "list_routines",
5036
+ "create_routine",
5037
+ "update_routine",
5038
+ "run_routine_now",
5039
+ "get_routine",
5040
+ "get_routine_ticks",
5041
+ "get_tick_items",
5042
+ "get_last_tick_items",
5043
+ "chain_routines",
5044
+ "get_chain_status",
5045
+ "launch_campaign",
5046
+ "quickstart_gtm_book",
5047
+ "list_campaigns",
5048
+ "campaign_performance",
5049
+ "tune_campaign",
5050
+ "emit_event",
5051
+ "approvals_list",
5052
+ "list_output_sinks",
5053
+ "create_output_sink",
5054
+ "update_output_sink",
5055
+ "delete_output_sink",
5056
+ "attach_sink_to_routine"
5057
+ ].includes(toolName)) {
5058
+ return "ops";
5059
+ }
5060
+ if ([
5061
+ "find_emails_with_verification",
5062
+ "verify_email",
5063
+ "enrich_company_signals",
5064
+ "company_intelligence",
5065
+ "find_contacts_with_email",
5066
+ "execute_primitive"
5067
+ ].includes(toolName)) {
5068
+ return "enrichment";
5069
+ }
5070
+ if (toolName.includes("icp")) return "icp";
5071
+ if (toolName.startsWith("ai_clean_")) return "data_cleaning";
5072
+ if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
5073
+ if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
5074
+ return void 0;
5075
+ }
5076
+ function normalizeMcpToolCategory(tool) {
5077
+ return typeof tool.category === "string" ? tool.category : typeof tool.annotations?.category === "string" ? tool.annotations.category : inferMcpToolCategory(tool.name);
5078
+ }
4549
5079
  function printToolMetadata(tool, indent = "") {
4550
5080
  const metadata = [];
4551
5081
  if (tool.contractVersion) metadata.push(`contract ${tool.contractVersion}`);
@@ -4822,7 +5352,7 @@ function getSdk() {
4822
5352
  try {
4823
5353
  const { Signaliz } = require("@signaliz/sdk");
4824
5354
  const sdk = createSdk(Signaliz);
4825
- if (sdk.campaigns?.buildCampaign && sdk.ops?.listOutputSinks && sdk.leads?.generate && sdk.emails?.verify && sdk.ai?.multiModel && sdk.getPlatformHealth) return sdk;
5355
+ 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;
4826
5356
  primaryError = new Error("SDK missing required GTM workflow APIs");
4827
5357
  } catch (err) {
4828
5358
  primaryError = err;
@@ -4848,6 +5378,12 @@ var HELP = `signaliz <command> [options]
4848
5378
 
4849
5379
  Quick Start:
4850
5380
  signaliz auth login
5381
+ signaliz start
5382
+ signaliz build "Build a campaign for industrial maintenance buyers"
5383
+ signaliz connect
5384
+ signaliz audit
5385
+ signaliz improve <campaign_id>
5386
+ signaliz prove
4851
5387
  signaliz health
4852
5388
  signaliz tools
4853
5389
  signaliz /plan "Monitor key accounts daily and alert Slack"
@@ -4867,6 +5403,16 @@ Auth:
4867
5403
  auth workspace clear Clear saved workspace context
4868
5404
  whoami Show current workspace and credits
4869
5405
  health Show workspace health and MCP platform latency/error signals
5406
+ start Recommend where to begin across Build, Connect, Audit, Improve, and Ops proof
5407
+ --campaign-brief "..." Optional brief for the suggested campaign-plan command
5408
+ --json Machine-readable onboarding state
5409
+
5410
+ Simple Jobs:
5411
+ build "brief" Plan a campaign without spending credits
5412
+ connect Inspect blocked provider/tool routes
5413
+ audit Find previous campaigns to audit
5414
+ improve <campaign_id> Plan Brain learning for a campaign
5415
+ prove Prove Ops delivery readiness
4870
5416
 
4871
5417
  Discovery:
4872
5418
  tools List available MCP tools
@@ -4912,11 +5458,95 @@ Lead Generation:
4912
5458
  --confirm-spend Required to launch spendful work
4913
5459
  lead status <job_id> Check lead-generation job status
4914
5460
 
4915
- GTM (31 native data sources \u2014 YouTube, TikTok, Instagram, LinkedIn, Facebook, Google Maps, Indeed, etc.):
5461
+ GTM Kernel:
5462
+ Use this when you want Signaliz to plan, audit, route, approve, and learn from
5463
+ campaigns. Use "signaliz start" first if you are not sure which command to run.
5464
+ gtm context Inspect GTM Kernel workspace context
5465
+ --limit N Max rows per section
5466
+ --no-campaigns Exclude campaign rows
5467
+ --no-memory Exclude memory rows
5468
+ --no-brain Exclude Brain rows
5469
+ --no-connections Exclude connection rows
5470
+ gtm bootstrap Inspect Kernel + Brain readiness gates
5471
+ --campaign-id ID Optional campaign scope
5472
+ --days N Lookback window, default server-side
5473
+ --include-samples Include diagnostic samples when supported
5474
+ gtm plan "brief" Compose a read-only GTM Kernel campaign build plan
5475
+ --layers a,b Optional GTM layers to plan
5476
+ --target-count N Desired lead count
5477
+ --preferred-providers a,b
5478
+ Provider preferences for route planning
5479
+ gtm commit-plan Dry-run or write a reviewed Kernel campaign plan
5480
+ --plan-file FILE JSON output from gtm plan --json
5481
+ --write --confirm Required together for writes; otherwise dry-run
5482
+ gtm prepare-build <id> Derive exact build_campaign dry-run args
5483
+ --target-count N Optional launch target count
5484
+ --allow-downscale Permit smaller launch counts when readiness requires it
5485
+ --build-input Output campaign build input instead of prepare receipt
5486
+ gtm campaigns List first-class GTM Kernel campaigns
5487
+ --status STATUS Optional campaign status
5488
+ --provider PROVIDER Optional linked provider
5489
+ --search TEXT Optional search text
5490
+ gtm campaign <id> Inspect one GTM Kernel campaign
5491
+ gtm existing-campaigns Discover linked/provider campaigns for audit
5492
+ --provider NAME Provider, default instantly
5493
+ --search TEXT Optional campaign search
5494
+ --no-provider-live Skip live provider lookup
5495
+ gtm audit-existing Audit an existing provider campaign
5496
+ --campaign-id ID Optional linked Kernel campaign id
5497
+ --provider-campaign-id ID
5498
+ Existing provider campaign id, e.g. Instantly
5499
+ --search TEXT If no id is provided, discover and audit the first match
5500
+ gtm memory "<query>" Search ranked workspace memory
5501
+ --campaign-id ID Optional campaign scope
5502
+ --outcome-type TYPE Optional desired outcome
5503
+ --memory-type TYPE Optional memory type
5504
+ gtm learning <id> Plan Brain learning for a campaign
5505
+ --include-network Include privacy-safe network lanes
5506
+ --write-mode MODE dry_run or write
5507
+ gtm learning-run <id> Queue ready Brain learning phases
5508
+ --phases a,b Optional phase allow-list
5509
+ --write-mode MODE dry_run or write, default dry_run
5510
+ gtm calibrate <id> Calibrate deliverability predictions
5511
+ --min-sample-size N Default server-side
5512
+ --write Write calibrations/patterns; otherwise dry-run
5513
+ gtm execution <id> Inspect campaign execution/provider readiness
5514
+ gtm integrations Inspect provider activation cards
5515
+ --campaign-id ID Optional campaign scope
5516
+ --layer LAYER Optional layer filter
5517
+ --include-planned Include planned provider presets
5518
+ gtm route-preview Preview the effective provider route for a layer
5519
+ --campaign-id ID Optional campaign scope
5520
+ --layer LAYER Required campaign layer
5521
+ gtm activate-route Dry-run or confirm provider route setup
5522
+ --provider-id ID Required provider ID
5523
+ --layer LAYER Single layer, or use --layers a,b
5524
+ --write --confirm Required together for writes; otherwise dry-run
5525
+ gtm feedback-webhook Prepare feedback webhook and Brain-cycle policy
5526
+ --provider NAME instantly, smartlead, heyreach, airbyte, custom_webhook
5527
+ --campaign-id ID Optional campaign scope
5528
+ --write-mode MODE Brain-cycle mode, default dry_run
5529
+
5530
+ Native GTM Data Sources:
5531
+ Use these when you already know the exact source you want to run.
4916
5532
  gtm list [--category C] List GTM capabilities
4917
5533
  gtm find "<intent>" Auto-route a free-text intent to the right capability
4918
5534
  gtm run --capability ID Run a GTM capability (use --query, --urls, --confirm-spend)
4919
5535
  gtm status <job_id> Check GTM job status
5536
+ gtm nango tools List Nango action tools for a workspace connection
5537
+ --workspace-connection-id ID
5538
+ Signaliz workspace connection id
5539
+ --provider-config-key KEY
5540
+ Optional Nango provider config key
5541
+ gtm nango call <action> Dry-run or execute a Nango action
5542
+ --input-json JSON Action input object
5543
+ --input-file FILE Action input object from a JSON file
5544
+ --execute --confirm Required pair for a confirmed write
5545
+ --async Queue async action execution when supported
5546
+ gtm nango result Poll async Nango action result
5547
+ --action-id ID Nango action id
5548
+ --status-url URL Relative status URL returned by call
5549
+ nango ... Shortcut for gtm nango ...
4920
5550
 
4921
5551
  Email:
4922
5552
  email verify <email> Verify one email address
@@ -4993,7 +5623,7 @@ Ops:
4993
5623
  --blueprint NAME monitor_companies|build_leads|enrich_list|route_signals|launch_campaign
4994
5624
  --target-count N Target row count
4995
5625
  --cadence NAME manual|hourly|daily|weekly
4996
- --destinations a,b Destinations such as slack,csv,google_sheets,webhook
5626
+ --destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
4997
5627
  --company-domains a,b
4998
5628
  Company domains for monitor/list-based Ops
4999
5629
  --ai-prompt TEXT Custom AI enrichment or scoring instruction
@@ -5010,7 +5640,7 @@ Ops:
5010
5640
  --confirm-spend Acknowledge estimated credits/external writes
5011
5641
  --auto-run Run immediately after create when safe
5012
5642
  --no-auto-run Create only
5013
- --destinations a,b Destinations such as slack,csv,google_sheets,webhook
5643
+ --destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
5014
5644
  --company-domains a,b
5015
5645
  Company domains for monitor/list-based Ops
5016
5646
  --ai-prompt TEXT Custom AI enrichment or scoring instruction
@@ -5019,7 +5649,7 @@ Ops:
5019
5649
  ops create "..." Create an Op from a prompt
5020
5650
  --confirm-spend Acknowledge estimated credits/external writes
5021
5651
  --activate Create as active instead of draft
5022
- --destinations a,b Destinations such as slack,csv,google_sheets,webhook
5652
+ --destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
5023
5653
  --company-domains a,b
5024
5654
  Company domains for monitor/list-based Ops
5025
5655
  --ai-prompt TEXT Custom AI enrichment or scoring instruction
@@ -5065,7 +5695,7 @@ Ops:
5065
5695
  --window-hours N Lookback window for recent runs (default: 24)
5066
5696
  --skip-acquisition-probe
5067
5697
  Skip the zero-credit fresh acquisition auth/config probe
5068
- ops connections List active Airbyte/output destinations
5698
+ ops connections List active Airbyte, Nango, and output destinations
5069
5699
  --category NAME Filter by connection category
5070
5700
  --status STATUS Filter by status (default: active)
5071
5701
  ops sinks Alias for ops connections
@@ -5079,7 +5709,7 @@ Ops:
5079
5709
  ops routine <id> items Inspect last tick items
5080
5710
  --state STATE Filter item state, e.g. failed
5081
5711
  ops attach-sink <routine_id> <sink_id>
5082
- Attach an Airbyte/output sink to a routine
5712
+ Attach an Airbyte, Nango, or output sink to a routine
5083
5713
  ops saved list List saved local Ops commands
5084
5714
  ops saved search QUERY Search saved commands by name, prompt, flags, or description
5085
5715
  ops saved save NAME -- <ops command args>
@@ -5104,6 +5734,344 @@ Environment:
5104
5734
  SIGNALIZ_API_URL Override base URL
5105
5735
  SIGNALIZ_WORKSPACE_ID Workspace UUID
5106
5736
  `;
5737
+ var GTM_HELP = `signaliz gtm <command> [options]
5738
+
5739
+ New-user path:
5740
+ signaliz auth login
5741
+ signaliz gtm context
5742
+ signaliz gtm bootstrap --include-samples
5743
+ signaliz gtm plan "Find CTOs at Series B fintech companies" --target-count 100 --json > plan.json
5744
+ signaliz gtm commit-plan --plan-file plan.json
5745
+ signaliz gtm commit-plan --plan-file plan.json --write --confirm
5746
+ signaliz gtm integrations --include-planned
5747
+ signaliz gtm activate-route --provider-id instantly --layer sender
5748
+ signaliz gtm prepare-build <campaign_id> --build-input --json > build-args.json
5749
+ signaliz campaign build --input-file build-args.json
5750
+
5751
+ Read-only planning:
5752
+ context Inspect GTM Kernel workspace context
5753
+ bootstrap Inspect Kernel + Brain readiness gates
5754
+ plan "brief" Compose Memory, Brain, failure, and provider-route plan
5755
+ --campaign-id ID Optional existing campaign scope
5756
+ --campaign-build-id ID
5757
+ Optional Campaign Builder build scope
5758
+ --target-count N Desired lead count
5759
+ --layers a,b GTM layers to include
5760
+ --preferred-providers a,b
5761
+ Provider preferences for route planning
5762
+ --target-icp-json JSON
5763
+ Structured ICP object
5764
+ --include-planned Include planned/needs-setup providers
5765
+ --no-memory Skip workspace memory
5766
+ --no-brain Skip Brain defaults/failure intelligence
5767
+ --no-provider-routes Skip provider route readiness
5768
+ --no-failure-patterns Skip Brain failure-pattern scan
5769
+
5770
+ Reviewed writes:
5771
+ commit-plan Dry-run or write a reviewed campaign plan
5772
+ --plan-file FILE JSON output from gtm plan --json
5773
+ --name NAME Campaign name for the committed object
5774
+ --write --confirm Required together for writes; otherwise dry-run
5775
+ prepare-build Derive exact build_campaign dry-run args
5776
+ <campaign_id> Committed GTM Kernel campaign id
5777
+ --target-count N Optional launch target count
5778
+ --allow-downscale Permit smaller launch counts when readiness requires it
5779
+
5780
+ Status and repair:
5781
+ campaigns List first-class GTM Kernel campaigns
5782
+ campaign <id> Inspect one campaign
5783
+ existing-campaigns Discover existing linked/provider campaigns
5784
+ audit-existing Audit an existing provider campaign
5785
+ execution <id> Inspect execution/provider readiness
5786
+ integrations Inspect provider activation cards
5787
+ route-preview Preview effective route for a layer
5788
+ activate-route Dry-run or confirm provider route setup
5789
+ feedback-webhook Prepare feedback ingress
5790
+ learning <id> Plan Brain learning
5791
+ learning-run <id> Queue Brain learning phases
5792
+ calibrate <id> Calibrate deliverability
5793
+ memory "query" Search ranked workspace memory
5794
+ nango ... List/dry-run/execute Nango-backed API action tools
5795
+
5796
+ Use --json on any command for machine-readable output.
5797
+ `;
5798
+ var GTM_COMMAND_HELP = {
5799
+ context: `signaliz gtm context [options]
5800
+
5801
+ Inspect the active workspace context the GTM Kernel will use.
5802
+
5803
+ Options:
5804
+ --no-memory Skip memory preview
5805
+ --limit N Max memory/context rows to include
5806
+ --json Machine-readable output
5807
+ `,
5808
+ bootstrap: `signaliz gtm bootstrap [options]
5809
+
5810
+ Inspect Kernel, Brain, memory, feedback, and provider-readiness gates before
5811
+ planning or running a campaign.
5812
+
5813
+ Options:
5814
+ --campaign-id ID Optional existing campaign scope
5815
+ --include-samples Include safe sample rows/evidence where available
5816
+ --min-sample-size N Minimum sample size for Brain/readiness checks
5817
+ --json Machine-readable output
5818
+ `,
5819
+ doctor: `signaliz gtm doctor [options]
5820
+
5821
+ Alias for signaliz gtm bootstrap. Use this before any spendful GTM action.
5822
+
5823
+ Options:
5824
+ --campaign-id ID Optional existing campaign scope
5825
+ --include-samples Include safe sample rows/evidence where available
5826
+ --min-sample-size N Minimum sample size for Brain/readiness checks
5827
+ --json Machine-readable output
5828
+ `,
5829
+ plan: `signaliz gtm plan "campaign brief" [options]
5830
+
5831
+ Compose a read-only GTM Kernel campaign plan from workspace memory, Brain
5832
+ defaults, failure intelligence, provider routes, and approval boundaries.
5833
+
5834
+ Options:
5835
+ --campaign-id ID Optional existing campaign scope
5836
+ --campaign-build-id ID Optional Campaign Builder build scope
5837
+ --target-count N Desired lead count
5838
+ --layers a,b GTM layers to include
5839
+ --preferred-providers a,b
5840
+ Provider preferences for route planning
5841
+ --target-icp-json JSON Structured ICP object
5842
+ --target-icp-file FILE Structured ICP JSON file
5843
+ --include-planned Include planned/needs-setup providers
5844
+ --no-memory Skip workspace memory
5845
+ --no-brain Skip Brain defaults/failure intelligence
5846
+ --no-provider-routes Skip provider route readiness
5847
+ --no-failure-patterns Skip Brain failure-pattern scan
5848
+ --json Machine-readable output
5849
+
5850
+ Safe next step:
5851
+ signaliz gtm plan "Find CTOs at fintech startups" --target-count 100 --json > plan.json
5852
+ signaliz gtm commit-plan --plan-file plan.json
5853
+ `,
5854
+ "build-plan": `signaliz gtm build-plan "campaign brief" [options]
5855
+
5856
+ Alias for signaliz gtm plan.
5857
+ `,
5858
+ "campaign-plan": `signaliz gtm campaign-plan "campaign brief" [options]
5859
+
5860
+ Alias for signaliz gtm plan.
5861
+ `,
5862
+ "commit-plan": `signaliz gtm commit-plan --plan-file plan.json [options]
5863
+
5864
+ Dry-run or write a reviewed GTM Kernel campaign plan into a campaign object.
5865
+ Dry-run is the default. Writes require both --write and --confirm.
5866
+
5867
+ Options:
5868
+ --plan-file FILE JSON output from gtm plan --json
5869
+ --plan-json JSON Inline plan JSON
5870
+ --name NAME Campaign name for the committed object
5871
+ --campaign-id ID Override campaign id from the plan snapshot
5872
+ --target-count N Override target lead count
5873
+ --write --confirm Required together for writes; otherwise dry-run
5874
+ --json Machine-readable output
5875
+
5876
+ Safe next step:
5877
+ signaliz gtm commit-plan --plan-file plan.json --write --confirm
5878
+ signaliz gtm prepare-build <campaign_id> --build-input --json > build-args.json
5879
+ signaliz campaign build --input-file build-args.json
5880
+ `,
5881
+ "plan-commit": `signaliz gtm plan-commit --plan-file plan.json [options]
5882
+
5883
+ Alias for signaliz gtm commit-plan.
5884
+ `,
5885
+ "commit-build-plan": `signaliz gtm commit-build-plan --plan-file plan.json [options]
5886
+
5887
+ Alias for signaliz gtm commit-plan.
5888
+ `,
5889
+ "existing-campaigns": `signaliz gtm existing-campaigns [options]
5890
+
5891
+ Discover existing linked/provider campaigns, starting with Instantly, before
5892
+ running a read-only Kernel/Brain audit or history import preview.
5893
+
5894
+ Options:
5895
+ --provider NAME Provider to discover, default instantly
5896
+ --integration-id ID Optional Signaliz integration scope
5897
+ --search TEXT Optional campaign search text
5898
+ --limit N Max campaigns to return
5899
+ --no-kernel-linked Skip Kernel-linked campaign rows
5900
+ --no-provider-live Skip live provider discovery
5901
+ --json Machine-readable output
5902
+ `,
5903
+ "discover-existing": `signaliz gtm discover-existing [options]
5904
+
5905
+ Alias for signaliz gtm existing-campaigns.
5906
+ `,
5907
+ "audit-existing": `signaliz gtm audit-existing [options]
5908
+
5909
+ Run a read-only existing campaign audit with completeness, recommendation cards,
5910
+ analysis surfaces, approval boundaries, and post-action verification JSON.
5911
+
5912
+ Options:
5913
+ --campaign-id ID Optional linked Kernel campaign id
5914
+ --provider NAME Provider, default instantly
5915
+ --provider-campaign-id ID
5916
+ Existing provider campaign id, e.g. Instantly
5917
+ --campaign-name NAME Optional display name for manual provider ids
5918
+ --search TEXT If no id is provided, discover and audit the first match
5919
+ --days N Lookback window
5920
+ --no-route-preview Skip route-preview surfaces
5921
+ --no-memory Skip memory surfaces
5922
+ --no-brain Skip Brain surfaces
5923
+ --json Machine-readable output
5924
+ `,
5925
+ "existing-audit": `signaliz gtm existing-audit [options]
5926
+
5927
+ Alias for signaliz gtm audit-existing.
5928
+ `,
5929
+ "prepare-build": `signaliz gtm prepare-build <campaign_id> [options]
5930
+
5931
+ Derive exact build_campaign arguments from a committed GTM Kernel campaign
5932
+ without creating a build. Dry-run and confirm_spend=false are the defaults.
5933
+
5934
+ Options:
5935
+ --campaign-id ID Campaign id when not passed positionally
5936
+ --target-count N Optional launch target count
5937
+ --allow-downscale Permit smaller launch counts when readiness requires it
5938
+ --dedup-keys a,b Override dedup keys
5939
+ --policy-json JSON Optional spend/policy object
5940
+ --policy-file FILE Optional spend/policy JSON file
5941
+ --delivery-json JSON Optional delivery object
5942
+ --delivery-file FILE Optional delivery JSON file
5943
+ --delivery-risk-json JSON
5944
+ Optional delivery-risk clearance object
5945
+ --delivery-risk-file FILE
5946
+ Optional delivery-risk JSON file
5947
+ --no-brain-context Skip compact Brain context in prepared args
5948
+ --no-delivery-risk-clearance
5949
+ Do not require delivery-risk clearance
5950
+ --write --confirm Prepare approved launch args; otherwise dry-run args
5951
+ --build-input Output campaign build input instead of prepare receipt
5952
+ --json Machine-readable output
5953
+
5954
+ Safe next step:
5955
+ signaliz gtm prepare-build <campaign_id> --build-input --json > build-args.json
5956
+ signaliz campaign build --input-file build-args.json
5957
+ `,
5958
+ "execution-prepare": `signaliz gtm execution-prepare <campaign_id> [options]
5959
+
5960
+ Alias for signaliz gtm prepare-build.
5961
+ `,
5962
+ "prepare-execution": `signaliz gtm prepare-execution <campaign_id> [options]
5963
+
5964
+ Alias for signaliz gtm prepare-build.
5965
+ `,
5966
+ integrations: `signaliz gtm integrations [options]
5967
+
5968
+ Inspect provider activation cards for each GTM layer across routes, recipes,
5969
+ connections, planned providers, and fallback state.
5970
+
5971
+ Options:
5972
+ --campaign-id ID Optional campaign scope
5973
+ --layer NAME Inspect one layer
5974
+ --include-planned Include planned/needs-setup providers
5975
+ --no-connections Skip connection details
5976
+ --json Machine-readable output
5977
+ `,
5978
+ activation: `signaliz gtm activation [options]
5979
+
5980
+ Alias for signaliz gtm integrations.
5981
+ `,
5982
+ "route-preview": `signaliz gtm route-preview --layer <layer> [options]
5983
+
5984
+ Preview the effective provider route for a GTM layer without writing state.
5985
+
5986
+ Options:
5987
+ --campaign-id ID Optional campaign scope
5988
+ --layer NAME GTM layer to preview
5989
+ --records-json JSON Optional sample records
5990
+ --records-file FILE Optional sample records JSON file
5991
+ --context-json JSON Optional route context
5992
+ --json Machine-readable output
5993
+ `,
5994
+ "preview-route": `signaliz gtm preview-route --layer <layer> [options]
5995
+
5996
+ Alias for signaliz gtm route-preview.
5997
+ `,
5998
+ "activate-route": `signaliz gtm activate-route --provider-id <provider_id> --layer <layer> [options]
5999
+
6000
+ Dry-run or confirm provider route setup. Dry-run is the default. Confirmed
6001
+ writes require both --write and --confirm.
6002
+
6003
+ Options:
6004
+ --campaign-id ID Optional campaign scope
6005
+ --provider-id ID Provider to activate, for example instantly
6006
+ --layer NAME Single layer to activate
6007
+ --layers a,b Multiple layers to activate
6008
+ --keep-existing-routes Do not archive competing routes
6009
+ --no-signaliz-fallback Disable Signaliz fallback for this route
6010
+ --write --confirm Required together for writes; otherwise dry-run
6011
+ --json Machine-readable output
6012
+ `,
6013
+ "route-activate": `signaliz gtm route-activate --provider-id <provider_id> --layer <layer> [options]
6014
+
6015
+ Alias for signaliz gtm activate-route.
6016
+ `,
6017
+ execution: `signaliz gtm execution <campaign_id> [options]
6018
+
6019
+ Inspect campaign execution and provider readiness before launch handoff.
6020
+
6021
+ Options:
6022
+ --campaign-id ID Campaign id
6023
+ --campaign-build-id ID Optional Campaign Builder build id
6024
+ --no-provider-readiness Skip provider readiness details
6025
+ --no-feedback Skip feedback details
6026
+ --no-memory Skip memory details
6027
+ --no-log Skip recent log details
6028
+ --json Machine-readable output
6029
+ `,
6030
+ readiness: `signaliz gtm readiness <campaign_id> [options]
6031
+
6032
+ Alias for signaliz gtm execution.
6033
+ `,
6034
+ campaigns: `signaliz gtm campaigns [options]
6035
+
6036
+ List first-class GTM Kernel campaigns.
6037
+
6038
+ Options:
6039
+ --status STATUS Filter by campaign status
6040
+ --provider ID Filter by provider
6041
+ --search TEXT Search campaigns
6042
+ --limit N Max campaigns
6043
+ --include-archived Include archived campaigns
6044
+ --json Machine-readable output
6045
+ `,
6046
+ campaign: `signaliz gtm campaign <campaign_id> [options]
6047
+
6048
+ Inspect one first-class GTM Kernel campaign.
6049
+
6050
+ Options:
6051
+ --log-limit N Max campaign log rows
6052
+ --memory-limit N Max memory rows
6053
+ --json Machine-readable output
6054
+ `,
6055
+ memory: `signaliz gtm memory "query" [options]
6056
+
6057
+ Search ranked workspace memory for GTM evidence.
6058
+
6059
+ Options:
6060
+ --campaign-id ID Optional campaign scope
6061
+ --memory-type TYPE Filter by memory type
6062
+ --outcome-type TYPE Filter by outcome type
6063
+ --days N Lookback window
6064
+ --limit N Max memory rows
6065
+ --json Machine-readable output
6066
+ `
6067
+ };
6068
+ function gtmHelpFor(sub) {
6069
+ if (!sub) return GTM_HELP;
6070
+ return GTM_COMMAND_HELP[sub] || GTM_HELP;
6071
+ }
6072
+ function isHelpRequest(args) {
6073
+ return args[0] === "help" || args.includes("--help") || args.includes("-h");
6074
+ }
5107
6075
  async function authLogin() {
5108
6076
  info("Signaliz Authentication Setup");
5109
6077
  info("\u2500".repeat(40));
@@ -5243,11 +6211,131 @@ async function health() {
5243
6211
  }
5244
6212
  );
5245
6213
  }
6214
+ async function start() {
6215
+ const sdk = getSdk();
6216
+ const read = async (name, fn) => {
6217
+ try {
6218
+ return { name, ok: true, data: await fn() };
6219
+ } catch (err) {
6220
+ return { name, ok: false, error: err instanceof Error ? err.message : String(err) };
6221
+ }
6222
+ };
6223
+ const [workspaceState, platformState, proofState, bootstrapState, integrationsState] = await Promise.all([
6224
+ read("workspace", () => sdk.getWorkspace()),
6225
+ read("platform", () => sdk.getPlatformHealth()),
6226
+ read("ops_proof", () => sdk.ops.proof({ windowHours: numberFlag("window-hours") || numberFlag("lookback-hours") || 720 })),
6227
+ read("gtm_bootstrap", () => sdk.gtm.bootstrapStatus({
6228
+ includeConnections: true,
6229
+ includeSamples: false,
6230
+ limit: numberFlag("limit") || 10
6231
+ })),
6232
+ read("gtm_integrations", () => sdk.gtm.integrationsActivationStatus({
6233
+ includePlanned: true,
6234
+ includeConnections: true
6235
+ }))
6236
+ ]);
6237
+ const workspace = workspaceState.ok ? workspaceState.data : null;
6238
+ const platform = platformState.ok ? platformState.data : null;
6239
+ const proof = proofState.ok ? proofState.data : null;
6240
+ const bootstrap = bootstrapState.ok ? bootstrapState.data : null;
6241
+ const integrations = integrationsState.ok ? integrationsState.data : null;
6242
+ const integrationSummary = integrations?.summary || {};
6243
+ const gates = Array.isArray(bootstrap?.gates) ? bootstrap.gates : [];
6244
+ const readyGates = gates.filter((gate) => gate.ready === true || gate.status === "ready").length;
6245
+ const blockedLayers = Number(integrationSummary.blocked_layers || 0);
6246
+ const readyLayers = Number(integrationSummary.ready_layers || 0);
6247
+ const totalLayers = Number(integrationSummary.total_layers || 0);
6248
+ const proofStatus = String(proof?.status || "unknown");
6249
+ const brief = flagArg("campaign-brief") || flagArg("brief") || "Build a focused campaign for my ICP";
6250
+ let nextMove = "Build a read-only campaign plan";
6251
+ let nextCommand = `signaliz gtm plan ${JSON.stringify(brief)} --target-count 50`;
6252
+ let why = "This is the safest starting point: it plans the campaign, memory, routes, and blockers without spending credits or writing to providers.";
6253
+ if (blockedLayers > 0) {
6254
+ nextMove = "Connect or fix blocked provider routes";
6255
+ nextCommand = "signaliz gtm integrations --include-planned";
6256
+ why = `${blockedLayers} GTM layer${blockedLayers === 1 ? "" : "s"} are blocked. Resolve routes before launch approval or sender/export work.`;
6257
+ } else if (proofStatus === "blocked" || proofStatus === "partial") {
6258
+ nextMove = "Prove Ops delivery before scaling";
6259
+ nextCommand = "signaliz ops proof";
6260
+ why = "Ops has some proof gaps. Use proof before relying on always-on routines or external delivery.";
6261
+ } else if (gates.length && readyGates < gates.length) {
6262
+ nextMove = "Inspect GTM Kernel readiness";
6263
+ nextCommand = "signaliz gtm bootstrap --include-samples";
6264
+ why = `Kernel readiness is ${readyGates}/${gates.length}; inspect the missing gates before committing a campaign.`;
6265
+ }
6266
+ const commands = [
6267
+ { label: "Build a campaign plan", command: `signaliz gtm plan ${JSON.stringify(brief)} --target-count 50`, safety: "read-only" },
6268
+ { label: "Connect tools/routes", command: "signaliz gtm integrations --include-planned", safety: "read-only" },
6269
+ { label: "Audit past campaigns", command: "signaliz gtm existing-campaigns --provider instantly --limit 5", safety: "read-only" },
6270
+ { label: "Prove Ops delivery", command: "signaliz ops proof", safety: "read-only" },
6271
+ { label: "Let Signaliz recommend a motion", command: "signaliz ops autopilot", safety: "read-only" }
6272
+ ];
6273
+ const result = {
6274
+ success: true,
6275
+ mode: "read_only_start",
6276
+ product_positioning: {
6277
+ plain_english: "Signaliz is the GTM brain over any stack. Start in CLI/Codex/MCP for agent-run work; use the UI as the cockpit for humans to inspect, connect, approve, and monitor.",
6278
+ recommended_primary_surface: "CLI/MCP for building and auditing; UI for approvals, route setup, and monitoring."
6279
+ },
6280
+ workspace,
6281
+ platform,
6282
+ readiness: {
6283
+ ops_proof_status: proofStatus,
6284
+ kernel_gates_ready: readyGates,
6285
+ kernel_gates_total: gates.length,
6286
+ provider_layers_ready: readyLayers,
6287
+ provider_layers_total: totalLayers,
6288
+ provider_layers_blocked: blockedLayers
6289
+ },
6290
+ next_move: {
6291
+ title: nextMove,
6292
+ why,
6293
+ command: nextCommand
6294
+ },
6295
+ safe_commands: commands,
6296
+ raw_status: {
6297
+ workspace: workspaceState,
6298
+ platform: platformState,
6299
+ ops_proof: proofState,
6300
+ gtm_bootstrap: bootstrapState,
6301
+ gtm_integrations: integrationsState
6302
+ }
6303
+ };
6304
+ return output(result, () => {
6305
+ console.log("Signaliz start");
6306
+ console.log(" What it is: Signaliz is the GTM brain over any stack.");
6307
+ console.log(" Best surface: CLI/MCP/Codex to build and audit; UI to inspect, connect, approve, and monitor.");
6308
+ if (workspace) {
6309
+ console.log(` Workspace: ${workspace.name} (${workspace.plan})`);
6310
+ console.log(` Credits: ${workspace.creditsRemaining}`);
6311
+ }
6312
+ if (platform) {
6313
+ console.log(` MCP: ${platform.status} | errors ${platform.errorRate} | p95 ${platform.latency.p95}ms`);
6314
+ }
6315
+ console.log("");
6316
+ console.log(`Next safest move: ${nextMove}`);
6317
+ console.log(`Why: ${why}`);
6318
+ console.log(`Run: ${nextCommand}`);
6319
+ console.log("");
6320
+ console.log("Safe starting commands");
6321
+ for (const command of commands) console.log(`- ${command.label}: ${command.command} (${command.safety})`);
6322
+ const failedReads = [workspaceState, platformState, proofState, bootstrapState, integrationsState].filter((item) => !item.ok);
6323
+ if (failedReads.length) {
6324
+ console.log("");
6325
+ console.log("Some read-only checks failed");
6326
+ for (const item of failedReads) console.log(`- ${item.name}: ${item.error}`);
6327
+ }
6328
+ });
6329
+ }
5246
6330
  async function tools() {
5247
6331
  const sdk = getSdk();
5248
6332
  const category = flagArg("category");
5249
6333
  const allTools = await sdk.listTools();
5250
- const filtered = category ? allTools.filter((tool) => tool.category === category) : allTools;
6334
+ const toolsWithCategories = allTools.map((tool) => ({
6335
+ ...tool,
6336
+ category: normalizeMcpToolCategory(tool)
6337
+ }));
6338
+ const filtered = category ? toolsWithCategories.filter((tool) => tool.category === category) : toolsWithCategories;
5251
6339
  output(
5252
6340
  { success: true, data: filtered, count: filtered.length, category },
5253
6341
  () => {
@@ -5423,7 +6511,7 @@ async function campaignBuild() {
5423
6511
  const inputFile = flagArg("input-file");
5424
6512
  if (inputFile) {
5425
6513
  const raw = (0, import_node_fs.readFileSync)(inputFile, "utf8");
5426
- config = JSON.parse(raw);
6514
+ config = normalizeCampaignBuildInput(JSON.parse(raw));
5427
6515
  } else {
5428
6516
  const promptText = flagArg("prompt");
5429
6517
  if (!promptText) {
@@ -5804,7 +6892,577 @@ async function lead(sub, rest) {
5804
6892
  die("Usage: signaliz lead <generate|local|sources|source|status>");
5805
6893
  }
5806
6894
  async function gtm(sub, rest) {
6895
+ if (isHelpRequest(rest)) {
6896
+ process.stdout.write(gtmHelpFor(sub));
6897
+ return;
6898
+ }
5807
6899
  const sdk = getSdk();
6900
+ if (sub === "plan" || sub === "build-plan" || sub === "campaign-plan") {
6901
+ const campaignBrief = promptArg(rest) || flagArg("campaign-brief") || flagArg("brief");
6902
+ if (!campaignBrief && !flagArg("campaign-id") && !flagArg("campaign-build-id") && !flagArg("build-id")) {
6903
+ die('Usage: signaliz gtm plan "campaign brief" [--target-count N] [--layers a,b] [--preferred-providers a,b]');
6904
+ }
6905
+ const result = await sdk.gtm.campaignBuildPlan({
6906
+ campaignId: flagArg("campaign-id"),
6907
+ campaignBuildId: flagArg("campaign-build-id") || flagArg("build-id"),
6908
+ campaignBrief,
6909
+ targetIcp: readJsonObjectInput("target-icp-json", "target-icp-file"),
6910
+ leadCount: numberFlag("lead-count") || numberFlag("target-count"),
6911
+ layers: csvFlag("layers"),
6912
+ preferredProviders: csvFlag("preferred-providers") || csvFlag("providers"),
6913
+ memoryDimensionFilters: readJsonObjectInput("memory-dimension-filters-json", "memory-dimension-filters-file"),
6914
+ requireMemoryDimensionMatch: hasFlag("require-memory-dimension-match") || void 0,
6915
+ includeMemory: !hasFlag("no-memory"),
6916
+ includeBrain: !hasFlag("no-brain"),
6917
+ includeProviderRoutes: !hasFlag("no-provider-routes"),
6918
+ includeFailurePatterns: !hasFlag("no-failure-patterns"),
6919
+ includePlannedProviders: hasFlag("include-planned"),
6920
+ days: numberFlag("days"),
6921
+ limit: numberFlag("limit")
6922
+ });
6923
+ return output(result, () => {
6924
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
6925
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
6926
+ const flow = Array.isArray(result.mcp_flow) ? result.mcp_flow : [];
6927
+ const activation = result.provider_activation?.summary || {};
6928
+ console.log("GTM campaign build plan");
6929
+ console.log(` Brief: ${campaignBrief || result.campaign?.name || result.campaign?.id || "workspace plan"}`);
6930
+ console.log(` Blockers: ${blockers.length}`);
6931
+ console.log(` Warnings: ${warnings.length}`);
6932
+ if (activation.total_layers !== void 0) {
6933
+ console.log(` Routes: ${activation.ready_layers || 0}/${activation.total_layers || 0} layers ready`);
6934
+ }
6935
+ const rankedMemory = result.memory_retrieval?.total_ranked;
6936
+ if (rankedMemory !== void 0) console.log(` Memory: ${rankedMemory} ranked rows`);
6937
+ if (flow.length) {
6938
+ console.log(" Next MCP flow:");
6939
+ for (const step of flow.slice(0, 5)) console.log(` - ${step.tool || step.name || "unknown_tool"}`);
6940
+ }
6941
+ if (blockers.length) console.log(` First blocker: ${blockers[0]}`);
6942
+ hint("Review the plan. Save JSON with --json, then dry-run a commit with signaliz gtm commit-plan --plan-file plan.json");
6943
+ });
6944
+ }
6945
+ if (sub === "commit-plan" || sub === "plan-commit" || sub === "commit-build-plan") {
6946
+ const planSnapshot = readJsonObjectInput("plan-json", "plan-file");
6947
+ const planQuery = planSnapshot?.query && typeof planSnapshot.query === "object" ? planSnapshot.query : {};
6948
+ const planCampaign = planSnapshot?.campaign && typeof planSnapshot.campaign === "object" ? planSnapshot.campaign : {};
6949
+ const campaignBrief = promptArg(rest) || flagArg("campaign-brief") || flagArg("brief") || String(planQuery.campaign_brief || "");
6950
+ const write = hasFlag("write");
6951
+ const confirm = hasFlag("confirm");
6952
+ if (!planSnapshot && !campaignBrief && !flagArg("campaign-id") && !flagArg("campaign-build-id") && !flagArg("build-id")) {
6953
+ die("Usage: signaliz gtm commit-plan --plan-file plan.json [--write --confirm]");
6954
+ }
6955
+ const leadCount = numberFlag("lead-count") || numberFlag("target-count") || Number(planQuery.lead_count) || void 0;
6956
+ const result = await sdk.gtm.commitCampaignBuildPlan({
6957
+ campaignId: flagArg("campaign-id") || planCampaign.id,
6958
+ campaignBuildId: flagArg("campaign-build-id") || flagArg("build-id") || String(planSnapshot?.campaign_build_id || "") || void 0,
6959
+ name: flagArg("name") || planCampaign.name,
6960
+ campaignBrief: campaignBrief || void 0,
6961
+ targetIcp: readJsonObjectInput("target-icp-json", "target-icp-file") || planQuery.target_icp,
6962
+ leadCount,
6963
+ layers: csvFlag("layers") || planQuery.layers,
6964
+ preferredProviders: csvFlag("preferred-providers") || csvFlag("providers") || planQuery.preferred_providers,
6965
+ planSnapshot,
6966
+ sendConfig: readJsonObjectInput("send-config-json", "send-config-file"),
6967
+ brainConfig: readJsonObjectInput("brain-config-json", "brain-config-file"),
6968
+ metadata: readJsonObjectInput("metadata-json", "metadata-file"),
6969
+ status: flagArg("status") || "draft",
6970
+ approvalRequired: !hasFlag("no-approval-required"),
6971
+ actorType: flagArg("actor-type") || "agent",
6972
+ actorId: flagArg("actor-id") || "signaliz_cli",
6973
+ rationale: flagArg("rationale") || "Committed a reviewed GTM campaign build plan through the Signaliz CLI.",
6974
+ idempotencyKey: flagArg("idempotency-key"),
6975
+ dryRun: !(write && confirm),
6976
+ confirm: write && confirm
6977
+ });
6978
+ return output(result, () => {
6979
+ const commitPlan = result.commit_plan || {};
6980
+ const blockers = Array.isArray(result.blockers) ? result.blockers : Array.isArray(commitPlan.blockers) ? commitPlan.blockers : [];
6981
+ const warnings = Array.isArray(result.warnings) ? result.warnings : Array.isArray(commitPlan.warnings) ? commitPlan.warnings : [];
6982
+ console.log("GTM campaign plan commit");
6983
+ console.log(` Mode: ${write && confirm ? "write" : "dry_run"}`);
6984
+ console.log(` Write: ${commitPlan.ready_to_write === false ? "blocked" : commitPlan.ready_to_write === true ? "ready" : "review"}`);
6985
+ if (result.campaign?.id) console.log(` Campaign: ${result.campaign.id}`);
6986
+ if (blockers.length) console.log(` Blockers: ${blockers.join("; ")}`);
6987
+ if (warnings.length) console.log(` Warnings: ${warnings.join("; ")}`);
6988
+ if (!(write && confirm)) hint("Review the dry-run. To write the campaign object: add --write --confirm.");
6989
+ });
6990
+ }
6991
+ if (sub === "prepare-build" || sub === "execution-prepare" || sub === "prepare-execution") {
6992
+ const campaignId = rest[0] || flagArg("campaign-id");
6993
+ if (!campaignId) die("Usage: signaliz gtm prepare-build <campaign_id> [--target-count N] [--json]");
6994
+ const write = hasFlag("write");
6995
+ const confirm = hasFlag("confirm");
6996
+ const result = await sdk.gtm.prepareCampaignBuildExecution({
6997
+ campaignId,
6998
+ targetCount: numberFlag("target-count") || numberFlag("lead-count"),
6999
+ allowDownscale: hasFlag("allow-downscale") || void 0,
7000
+ dryRun: !(write && confirm),
7001
+ confirmSpend: write && confirm,
7002
+ includeBrainContext: !hasFlag("no-brain-context"),
7003
+ requireDeliveryRiskClearance: !hasFlag("no-delivery-risk-clearance"),
7004
+ deliveryRisk: readJsonObjectInput("delivery-risk-json", "delivery-risk-file"),
7005
+ dedupKeys: csvFlag("dedup-keys"),
7006
+ policy: readJsonObjectInput("policy-json", "policy-file"),
7007
+ signals: readJsonObjectInput("signals-json", "signals-file"),
7008
+ qualification: readJsonObjectInput("qualification-json", "qualification-file"),
7009
+ copy: readJsonObjectInput("copy-json", "copy-file"),
7010
+ delivery: readJsonObjectInput("delivery-json", "delivery-file"),
7011
+ enhancers: readJsonObjectInput("enhancers-json", "enhancers-file")
7012
+ });
7013
+ if (hasFlag("build-input")) {
7014
+ return output(normalizeCampaignBuildInput(result));
7015
+ }
7016
+ return output(result, () => {
7017
+ const blockers = Array.isArray(result.blockers) ? result.blockers : [];
7018
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
7019
+ const buildArgs = result.build_campaign_arguments || result.buildCampaignArguments || {};
7020
+ console.log("GTM campaign build prepare");
7021
+ console.log(` Campaign: ${result.campaign?.id || campaignId}`);
7022
+ console.log(` Mode: ${write && confirm ? "approved_launch_args" : "dry_run_args"}`);
7023
+ console.log(` Ready: ${result.ready_to_launch === true ? "yes" : result.ready_to_launch === false ? "no" : "review"}`);
7024
+ if (Object.keys(buildArgs).length) console.log(` Build args: ready`);
7025
+ if (blockers.length) console.log(` Blockers: ${blockers.join("; ")}`);
7026
+ if (warnings.length) console.log(` Warnings: ${warnings.join("; ")}`);
7027
+ if (!(write && confirm)) {
7028
+ hint("Save build input with --build-input --json, then run signaliz campaign build --input-file build-args.json.");
7029
+ }
7030
+ });
7031
+ }
7032
+ if (sub === "context" || sub === "kernel" || sub === "workspace") {
7033
+ const result = await sdk.gtm.context({
7034
+ includeCampaigns: !hasFlag("no-campaigns"),
7035
+ includeMemory: !hasFlag("no-memory"),
7036
+ includeBrain: !hasFlag("no-brain"),
7037
+ includeConnections: !hasFlag("no-connections"),
7038
+ limit: numberFlag("limit")
7039
+ });
7040
+ return output(result, () => {
7041
+ const workspace = result.workspace || {};
7042
+ const connections = result.connections || {};
7043
+ const connectionCount = ["integrations", "mcp_servers", "app_connections", "integration_recipes", "layer_routes"].reduce((sum, key) => sum + (Array.isArray(connections[key]) ? connections[key].length : 0), 0);
7044
+ console.log("GTM Kernel context");
7045
+ console.log(` Workspace: ${workspace.name || workspace.id || "unknown"}`);
7046
+ console.log(` Campaigns: ${Array.isArray(result.campaigns) ? result.campaigns.length : 0}`);
7047
+ console.log(` Memory: ${Array.isArray(result.memory) ? result.memory.length : 0}`);
7048
+ console.log(` Brain rows: ${Array.isArray(result.brain_patterns) ? result.brain_patterns.length : 0}`);
7049
+ console.log(` Connections: ${connectionCount}`);
7050
+ hint("signaliz gtm bootstrap --include-samples");
7051
+ });
7052
+ }
7053
+ if (sub === "bootstrap" || sub === "doctor") {
7054
+ const result = await sdk.gtm.bootstrapStatus({
7055
+ campaignId: flagArg("campaign-id"),
7056
+ days: numberFlag("days"),
7057
+ minSampleSize: numberFlag("min-sample-size"),
7058
+ includeConnections: !hasFlag("no-connections"),
7059
+ includeSamples: hasFlag("include-samples"),
7060
+ limit: numberFlag("limit")
7061
+ });
7062
+ return output(result, () => {
7063
+ const gates = Array.isArray(result.gates) ? result.gates : [];
7064
+ const ready = gates.filter((gate) => gate.ready === true || gate.status === "ready").length;
7065
+ const nextTools = [...new Set(gates.flatMap((gate) => Array.isArray(gate.next_tools) ? gate.next_tools : []))].slice(0, 5);
7066
+ console.log("GTM Kernel bootstrap");
7067
+ console.log(` Status: ${result.status || result.overall_status || (ready === gates.length ? "ready" : "needs_setup")}`);
7068
+ console.log(` Gates: ${ready}/${gates.length || 0} ready`);
7069
+ if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.length}`);
7070
+ if (Array.isArray(result.warnings) && result.warnings.length) console.log(` Warnings: ${result.warnings.length}`);
7071
+ if (nextTools.length) console.log(` Next tools: ${nextTools.join(", ")}`);
7072
+ hint("signaliz gtm campaigns");
7073
+ });
7074
+ }
7075
+ if (sub === "campaigns") {
7076
+ const result = await sdk.gtm.listCampaigns({
7077
+ status: flagArg("status"),
7078
+ provider: flagArg("provider"),
7079
+ search: flagArg("search"),
7080
+ limit: numberFlag("limit"),
7081
+ includeArchived: hasFlag("include-archived")
7082
+ });
7083
+ return output(result, () => {
7084
+ const campaigns = Array.isArray(result.campaigns) ? result.campaigns : Array.isArray(result) ? result : [];
7085
+ console.log(`GTM Kernel campaigns (${campaigns.length})`);
7086
+ for (const campaign2 of campaigns) {
7087
+ const build = campaign2.campaign_build_id ? ` build=${campaign2.campaign_build_id}` : "";
7088
+ console.log(`- ${campaign2.id}: ${campaign2.name || "Untitled"} [${campaign2.status || "unknown"}]${build}`);
7089
+ }
7090
+ if (campaigns[0]?.id) hint(`signaliz gtm campaign ${campaigns[0].id}`);
7091
+ });
7092
+ }
7093
+ if (sub === "campaign") {
7094
+ const campaignId = rest[0] || flagArg("campaign-id");
7095
+ if (!campaignId) die("Usage: signaliz gtm campaign <campaign_id>");
7096
+ const result = await sdk.gtm.getCampaign(campaignId, {
7097
+ logLimit: numberFlag("log-limit"),
7098
+ memoryLimit: numberFlag("memory-limit")
7099
+ });
7100
+ return output(result, () => {
7101
+ const campaign2 = result.campaign || result;
7102
+ console.log("GTM Kernel campaign");
7103
+ console.log(` ID: ${campaign2.id || campaignId}`);
7104
+ console.log(` Name: ${campaign2.name || "Untitled"}`);
7105
+ console.log(` Status: ${campaign2.status || "unknown"}`);
7106
+ console.log(` Source: ${campaign2.source || "unknown"}`);
7107
+ if (campaign2.campaign_build_id) console.log(` Build: ${campaign2.campaign_build_id}`);
7108
+ const links = Array.isArray(result.provider_links) ? result.provider_links.length : 0;
7109
+ const memory = Array.isArray(result.memory) ? result.memory.length : 0;
7110
+ const logs = Array.isArray(result.logs) ? result.logs.length : 0;
7111
+ console.log(` Provider links: ${links}`);
7112
+ console.log(` Memory: ${memory}`);
7113
+ console.log(` Logs: ${logs}`);
7114
+ hint(`signaliz gtm learning ${campaign2.id || campaignId}`);
7115
+ });
7116
+ }
7117
+ if (sub === "existing-campaigns" || sub === "discover-existing" || sub === "campaign-discover") {
7118
+ const provider = (flagArg("provider") || rest[0] || "instantly").toLowerCase();
7119
+ const result = await sdk.gtm.discoverExistingCampaigns({
7120
+ provider,
7121
+ integrationId: flagArg("integration-id"),
7122
+ search: flagArg("search"),
7123
+ limit: numberFlag("limit"),
7124
+ includeKernelLinked: !hasFlag("no-kernel-linked"),
7125
+ includeProviderLive: !hasFlag("no-provider-live")
7126
+ });
7127
+ return output(result, () => {
7128
+ const campaigns = Array.isArray(result.campaigns) ? result.campaigns : [];
7129
+ const counts = result.counts || {};
7130
+ console.log(`Existing ${provider} campaigns (${campaigns.length})`);
7131
+ if (counts.total_returned !== void 0) console.log(` Returned: ${counts.total_returned}`);
7132
+ if (counts.kernel_linked !== void 0) console.log(` Kernel linked: ${counts.kernel_linked}`);
7133
+ if (counts.provider_live !== void 0) console.log(` Provider live: ${counts.provider_live}`);
7134
+ for (const campaign2 of campaigns.slice(0, 10)) {
7135
+ const providerId = campaign2.provider_campaign_id ? ` provider=${campaign2.provider_campaign_id}` : "";
7136
+ const linked = campaign2.linked_kernel_campaign_id ? ` kernel=${campaign2.linked_kernel_campaign_id}` : "";
7137
+ console.log(`- ${campaign2.name || campaign2.provider_campaign_id || "Untitled"} [${campaign2.status || "unknown"}]${providerId}${linked}`);
7138
+ }
7139
+ const first = campaigns[0];
7140
+ if (first?.provider_campaign_id || first?.linked_kernel_campaign_id) {
7141
+ hint(`signaliz gtm audit-existing --provider ${provider}${first.provider_campaign_id ? ` --provider-campaign-id ${first.provider_campaign_id}` : ""}${first.linked_kernel_campaign_id ? ` --campaign-id ${first.linked_kernel_campaign_id}` : ""}`);
7142
+ }
7143
+ });
7144
+ }
7145
+ if (sub === "audit-existing" || sub === "existing-audit" || sub === "campaign-audit") {
7146
+ let campaignId = flagArg("campaign-id");
7147
+ let providerCampaignId = flagArg("provider-campaign-id") || flagArg("instantly-campaign-id") || positionalAfter(sub);
7148
+ const provider = (flagArg("provider") || "instantly").toLowerCase();
7149
+ let campaignName = flagArg("campaign-name") || flagArg("name");
7150
+ const search = flagArg("search");
7151
+ if (!campaignId && !providerCampaignId && search) {
7152
+ const discovery = await sdk.gtm.discoverExistingCampaigns({
7153
+ provider,
7154
+ search,
7155
+ limit: 1,
7156
+ includeKernelLinked: !hasFlag("no-kernel-linked"),
7157
+ includeProviderLive: !hasFlag("no-provider-live")
7158
+ });
7159
+ const match = Array.isArray(discovery.campaigns) ? discovery.campaigns[0] : null;
7160
+ campaignId = match?.linked_kernel_campaign_id || void 0;
7161
+ providerCampaignId = match?.provider_campaign_id || void 0;
7162
+ campaignName = campaignName || match?.name || match?.linked_kernel_campaign_name;
7163
+ if (!campaignId && !providerCampaignId) {
7164
+ die(`No existing ${provider} campaign matched "${search}". Try signaliz gtm existing-campaigns --provider ${provider} --search "${search}".`);
7165
+ }
7166
+ }
7167
+ if (!campaignId && !providerCampaignId) die("Usage: signaliz gtm audit-existing --provider-campaign-id <id> [--campaign-id ID] or --search <campaign name>");
7168
+ const result = await sdk.gtm.auditExistingCampaign({
7169
+ campaignId,
7170
+ provider,
7171
+ providerCampaignId,
7172
+ campaignName,
7173
+ days: numberFlag("days"),
7174
+ includeRoutePreview: !hasFlag("no-route-preview"),
7175
+ includeMemory: !hasFlag("no-memory"),
7176
+ includeBrain: !hasFlag("no-brain")
7177
+ });
7178
+ return output(result, () => {
7179
+ const completeness = Array.isArray(result.completeness) ? result.completeness : [];
7180
+ const ready = completeness.filter((step) => step.ready === true).length;
7181
+ const recommendations = Array.isArray(result.recommendations) ? result.recommendations : [];
7182
+ const surfaces = Array.isArray(result.analysis_surfaces) ? result.analysis_surfaces : [];
7183
+ const packet = result.improvement_packet || result.audit_packet?.improvement_packet || {};
7184
+ const keepCount = arrayCount(packet.keep);
7185
+ const fixCount = arrayCount(packet.fix_before_scale || packet.fixBeforeScale);
7186
+ const improveCount = arrayCount(packet.improve_next || packet.improveNext);
7187
+ const approveCount = arrayCount(packet.approve_only_after_review || packet.approveOnlyAfterReview);
7188
+ const verifyCount = arrayCount(packet.verify);
7189
+ const nextSafeAction = firstExistingCampaignSafeAction(result);
7190
+ const nextSafeTool = nextSafeAction?.tool || nextSafeAction?.suggested_tool || nextSafeAction?.next_safe_request?.tool;
7191
+ const nextSafeBoundary = nextSafeAction?.approval_boundary || nextSafeAction?.approvalBoundary;
7192
+ const nextSafeTitle = nextSafeAction?.title || nextSafeAction?.id || nextSafeTool;
7193
+ console.log("Existing campaign audit");
7194
+ console.log(` Provider: ${result.provider || provider}`);
7195
+ if (result.provider_campaign_id || providerCampaignId) console.log(` Provider ID: ${result.provider_campaign_id || providerCampaignId}`);
7196
+ if (result.campaign?.id || campaignId) console.log(` Kernel campaign: ${result.campaign?.id || campaignId}`);
7197
+ if (result.audit_score !== void 0) console.log(` Audit score: ${result.audit_score}`);
7198
+ console.log(` Completeness: ${ready}/${completeness.length} ready`);
7199
+ console.log(` Recommendations: ${recommendations.length}`);
7200
+ if (surfaces.length) console.log(` Proof surfaces: ${surfaces.length}`);
7201
+ if (keepCount || fixCount || improveCount || approveCount || verifyCount) {
7202
+ console.log(` Packet: keep ${keepCount} | fix ${fixCount} | improve ${improveCount} | approve ${approveCount} | verify ${verifyCount}`);
7203
+ }
7204
+ if (nextSafeAction) {
7205
+ console.log(` Next safe: ${nextSafeTitle || "Review next action"}${nextSafeBoundary ? ` [${labelize(nextSafeBoundary)}]` : ""}`);
7206
+ if (nextSafeTool) console.log(` Next tool: ${nextSafeTool}`);
7207
+ }
7208
+ if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
7209
+ hint(`Use --json to inspect exact MCP requests before running any gated action.`);
7210
+ });
7211
+ }
7212
+ if (sub === "memory") {
7213
+ const query = promptArg(rest) || flagArg("query");
7214
+ const result = await sdk.gtm.searchMemory({
7215
+ query,
7216
+ campaignId: flagArg("campaign-id"),
7217
+ memoryType: flagArg("memory-type"),
7218
+ outcomeType: flagArg("outcome-type"),
7219
+ days: numberFlag("days"),
7220
+ limit: numberFlag("limit")
7221
+ });
7222
+ return output(result, () => {
7223
+ const memories = Array.isArray(result.memories) ? result.memories : [];
7224
+ console.log(`GTM Kernel memory (${memories.length})`);
7225
+ for (const memory of memories) {
7226
+ const score = typeof memory.rank_score === "number" ? ` score=${memory.rank_score.toFixed(2)}` : "";
7227
+ console.log(`- ${memory.title || memory.id || "Untitled"} [${memory.memory_type || "memory"}]${score}`);
7228
+ }
7229
+ if (!memories.length) console.log("No matching memory rows returned.");
7230
+ });
7231
+ }
7232
+ if (sub === "learning") {
7233
+ const campaignId = rest[0] || flagArg("campaign-id");
7234
+ if (!campaignId) die("Usage: signaliz gtm learning <campaign_id>");
7235
+ const result = await sdk.gtm.learningCyclePlan({
7236
+ campaignId,
7237
+ includeNetwork: hasFlag("include-network"),
7238
+ writeMode: flagArg("write-mode") || "dry_run",
7239
+ days: numberFlag("days"),
7240
+ networkDays: numberFlag("network-days"),
7241
+ minSampleSize: numberFlag("min-sample-size"),
7242
+ minWorkspaceCount: numberFlag("min-workspace-count"),
7243
+ limit: numberFlag("limit")
7244
+ });
7245
+ return output(result, () => {
7246
+ const lanes = Array.isArray(result.learning_lanes) ? result.learning_lanes : [];
7247
+ const calls = Array.isArray(result.recommended_tool_calls) ? result.recommended_tool_calls : [];
7248
+ const ready = lanes.filter((lane) => lane.state === "ready").length;
7249
+ console.log("GTM Brain learning plan");
7250
+ console.log(` Campaign: ${campaignId}`);
7251
+ console.log(` Lanes: ${ready}/${lanes.length} ready`);
7252
+ console.log(` Calls: ${calls.length}`);
7253
+ for (const call of calls.slice(0, 5)) {
7254
+ const state = call.ready === false ? "blocked" : "ready";
7255
+ console.log(`- ${call.tool || call.name || "unknown_tool"} [${state}]`);
7256
+ }
7257
+ hint(`signaliz gtm bootstrap --campaign-id ${campaignId}`);
7258
+ });
7259
+ }
7260
+ if (sub === "learning-run" || sub === "run-learning") {
7261
+ const campaignId = rest[0] || flagArg("campaign-id");
7262
+ if (!campaignId) die("Usage: signaliz gtm learning-run <campaign_id>");
7263
+ const result = await sdk.gtm.learningCycleRun({
7264
+ campaignId,
7265
+ includeMemory: !hasFlag("no-memory"),
7266
+ includeNetwork: hasFlag("include-network"),
7267
+ writeMode: flagArg("write-mode") || "dry_run",
7268
+ phases: csvFlag("phases"),
7269
+ continueOnError: !hasFlag("fail-fast"),
7270
+ days: numberFlag("days"),
7271
+ networkDays: numberFlag("network-days"),
7272
+ minSampleSize: numberFlag("min-sample-size"),
7273
+ minWorkspaceCount: numberFlag("min-workspace-count"),
7274
+ minPrivacyK: numberFlag("min-privacy-k"),
7275
+ limit: numberFlag("limit")
7276
+ });
7277
+ return output(result, () => {
7278
+ console.log("GTM Brain learning run");
7279
+ console.log(` Campaign: ${campaignId}`);
7280
+ console.log(` Mode: ${flagArg("write-mode") || "dry_run"}`);
7281
+ if (result.run_id) console.log(` Run ID: ${result.run_id}`);
7282
+ if (result.status) console.log(` Status: ${result.status}`);
7283
+ const blocked = Array.isArray(result.blocked_phases) ? result.blocked_phases : [];
7284
+ const queued = Array.isArray(result.queued_phases) ? result.queued_phases : Array.isArray(result.phases) ? result.phases : [];
7285
+ if (queued.length) console.log(` Queued: ${queued.join(", ")}`);
7286
+ if (blocked.length) console.log(` Blocked: ${blocked.join(", ")}`);
7287
+ hint(`signaliz gtm learning ${campaignId}`);
7288
+ });
7289
+ }
7290
+ if (sub === "calibrate" || sub === "calibration") {
7291
+ const campaignId = rest[0] || flagArg("campaign-id");
7292
+ if (!campaignId) die("Usage: signaliz gtm calibrate <campaign_id>");
7293
+ const write = hasFlag("write");
7294
+ const result = await sdk.gtm.calibrateDeliverability({
7295
+ campaignId,
7296
+ days: numberFlag("days"),
7297
+ dimensionTypes: csvFlag("dimension-types"),
7298
+ minSampleSize: numberFlag("min-sample-size"),
7299
+ dryRun: !write,
7300
+ writeCalibrations: write,
7301
+ writePatterns: write && !hasFlag("no-patterns"),
7302
+ replaceExisting: !hasFlag("keep-existing"),
7303
+ limit: numberFlag("limit")
7304
+ });
7305
+ return output(result, () => {
7306
+ console.log("GTM deliverability calibration");
7307
+ console.log(` Campaign: ${campaignId}`);
7308
+ console.log(` Mode: ${write ? "write" : "dry_run"}`);
7309
+ const calibrations = Array.isArray(result.calibrations) ? result.calibrations.length : Array.isArray(result.written_calibrations) ? result.written_calibrations.length : 0;
7310
+ if (calibrations) console.log(` Rows: ${calibrations}`);
7311
+ if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
7312
+ if (Array.isArray(result.warnings) && result.warnings.length) console.log(` Warnings: ${result.warnings.join("; ")}`);
7313
+ if (!write) hint("Review dry-run results. To write calibration rows: add --write.");
7314
+ });
7315
+ }
7316
+ if (sub === "execution" || sub === "campaign-status" || sub === "readiness") {
7317
+ const campaignId = rest[0] || flagArg("campaign-id");
7318
+ const campaignBuildId = flagArg("campaign-build-id") || flagArg("build-id");
7319
+ if (!campaignId && !campaignBuildId) die("Usage: signaliz gtm execution <campaign_id> [--campaign-build-id ID]");
7320
+ const result = await sdk.gtm.campaignExecutionStatus({
7321
+ campaignId,
7322
+ campaignBuildId,
7323
+ includeProviderReadiness: !hasFlag("no-provider-readiness"),
7324
+ includeFeedback: !hasFlag("no-feedback"),
7325
+ includeMemory: !hasFlag("no-memory"),
7326
+ includeRecentLog: !hasFlag("no-log"),
7327
+ logLimit: numberFlag("log-limit"),
7328
+ memoryLimit: numberFlag("memory-limit")
7329
+ });
7330
+ return output(result, () => {
7331
+ const summary = result.provider_readiness?.summary || {};
7332
+ console.log("GTM campaign execution");
7333
+ console.log(` Campaign: ${result.campaign?.id || campaignId || "unknown"}`);
7334
+ console.log(` Stage: ${result.execution_stage || "unknown"}`);
7335
+ console.log(` Ready: ${result.ready === true ? "yes" : "no"}`);
7336
+ if (summary.total_layers !== void 0) console.log(` Routes: ${summary.ready_layers || 0}/${summary.total_layers} ready`);
7337
+ if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
7338
+ if (Array.isArray(result.next_actions) && result.next_actions[0]?.tool) console.log(` Next: ${result.next_actions[0].tool}`);
7339
+ hint(`signaliz gtm integrations --campaign-id ${result.campaign?.id || campaignId || "<campaign_id>"} --include-planned`);
7340
+ });
7341
+ }
7342
+ if (sub === "integrations" || sub === "activation") {
7343
+ const result = await sdk.gtm.integrationsActivationStatus({
7344
+ campaignId: flagArg("campaign-id"),
7345
+ layer: flagArg("layer"),
7346
+ includePlanned: hasFlag("include-planned"),
7347
+ includeConnections: !hasFlag("no-connections")
7348
+ });
7349
+ return output(result, () => {
7350
+ const summary = result.summary || {};
7351
+ console.log("GTM provider activation");
7352
+ console.log(` Layers: ${summary.ready_layers || 0}/${summary.total_layers || 0} ready`);
7353
+ console.log(` Blocked: ${summary.blocked_layers || 0}`);
7354
+ for (const layer of (Array.isArray(result.layers) ? result.layers : []).slice(0, 8)) {
7355
+ console.log(`- ${layer.layer}: ${layer.status || "unknown"} via ${layer.selected_provider_id || "none"}`);
7356
+ }
7357
+ hint("signaliz gtm route-preview --layer sender --campaign-id <campaign_id>");
7358
+ });
7359
+ }
7360
+ if (sub === "route-preview" || sub === "preview-route") {
7361
+ const layer = flagArg("layer") || rest[0];
7362
+ if (!layer) die("Usage: signaliz gtm route-preview --layer <layer> [--campaign-id ID]");
7363
+ const result = await sdk.gtm.previewLayerRoute({
7364
+ campaignId: flagArg("campaign-id"),
7365
+ layer,
7366
+ sampleRecords: flagArg("records-file") ? readJsonValue(flagArg("records-file")) : readJsonFlag("records-json"),
7367
+ context: readJsonFlag("context-json")
7368
+ });
7369
+ return output(result, () => {
7370
+ const readiness = result.readiness || {};
7371
+ console.log("GTM route preview");
7372
+ console.log(` Layer: ${result.layer || layer}`);
7373
+ console.log(` Provider: ${result.selected_route?.provider_id || result.selected_recipe?.provider_id || "none"}`);
7374
+ console.log(` Ready: ${readiness.ready === true ? "yes" : "no"}`);
7375
+ if (Array.isArray(readiness.blockers) && readiness.blockers.length) console.log(` Blockers: ${readiness.blockers.join("; ")}`);
7376
+ if (Array.isArray(result.next_actions) && result.next_actions[0]?.action) console.log(` Next: ${result.next_actions[0].action}`);
7377
+ hint("signaliz gtm activate-route --provider-id <provider> --layer <layer> --campaign-id <campaign_id>");
7378
+ });
7379
+ }
7380
+ if (sub === "activate-route" || sub === "route-activate") {
7381
+ const providerId = flagArg("provider-id") || rest[0];
7382
+ if (!providerId) die("Usage: signaliz gtm activate-route --provider-id <provider_id> --layer <layer> [--write --confirm]");
7383
+ const layers = csvFlag("layers");
7384
+ const layer = flagArg("layer");
7385
+ if (!layer && !layers?.length) die("--layer or --layers is required");
7386
+ const write = hasFlag("write");
7387
+ const confirm = hasFlag("confirm");
7388
+ const result = await sdk.gtm.activateProviderRoute({
7389
+ providerId,
7390
+ providerName: flagArg("provider-name"),
7391
+ campaignId: flagArg("campaign-id"),
7392
+ layer,
7393
+ layers,
7394
+ invocationType: flagArg("invocation-type"),
7395
+ authStrategy: flagArg("auth-strategy"),
7396
+ endpointUrl: flagArg("endpoint-url"),
7397
+ secretRef: flagArg("secret-ref"),
7398
+ workspaceIntegrationId: flagArg("workspace-integration-id"),
7399
+ workspaceMcpServerId: flagArg("workspace-mcp-server-id"),
7400
+ workspaceConnectionId: flagArg("workspace-connection-id"),
7401
+ useSignalizFallback: !hasFlag("no-signaliz-fallback"),
7402
+ priority: numberFlag("priority"),
7403
+ routeConfig: readJsonFlag("route-config-json"),
7404
+ readiness: readJsonFlag("readiness-json"),
7405
+ status: flagArg("status"),
7406
+ routeStatus: flagArg("route-status"),
7407
+ replaceExistingRoutes: !hasFlag("keep-existing-routes"),
7408
+ dryRun: !(write && confirm),
7409
+ confirm: write && confirm,
7410
+ sampleRecords: flagArg("records-file") ? readJsonValue(flagArg("records-file")) : readJsonFlag("records-json"),
7411
+ context: readJsonFlag("context-json")
7412
+ });
7413
+ return output(result, () => {
7414
+ const plan = result.activation_plan || {};
7415
+ console.log("GTM provider route activation");
7416
+ console.log(` Provider: ${providerId}`);
7417
+ console.log(` Mode: ${write && confirm ? "write" : "dry_run"}`);
7418
+ if (plan.execution_ready !== void 0) console.log(` Execute: ${plan.execution_ready ? "ready" : "not ready"}`);
7419
+ if (plan.ready_to_write !== void 0) console.log(` Write: ${plan.ready_to_write ? "ready" : "blocked"}`);
7420
+ const routes = Array.isArray(result.routes) ? result.routes.length : Array.isArray(result.route_candidates) ? result.route_candidates.length : 0;
7421
+ if (routes) console.log(` Routes: ${routes}`);
7422
+ const blockers = Array.isArray(result.blockers) ? result.blockers : Array.isArray(plan.blockers) ? plan.blockers : [];
7423
+ const warnings = Array.isArray(result.warnings) ? result.warnings : Array.isArray(plan.warnings) ? plan.warnings : [];
7424
+ if (blockers.length) console.log(` Blockers: ${blockers.join("; ")}`);
7425
+ if (warnings.length) console.log(` Warnings: ${warnings.join("; ")}`);
7426
+ if (!(write && confirm)) hint("Review the dry-run. To write: add --write --confirm.");
7427
+ });
7428
+ }
7429
+ if (sub === "feedback-webhook" || sub === "prepare-feedback") {
7430
+ const provider = (flagArg("provider") || rest[0] || "custom_webhook").toLowerCase();
7431
+ const common = {
7432
+ campaignId: flagArg("campaign-id"),
7433
+ campaignBuildId: flagArg("campaign-build-id") || flagArg("build-id"),
7434
+ providerLinkId: flagArg("provider-link-id"),
7435
+ providerCampaignId: flagArg("provider-campaign-id"),
7436
+ integrationId: flagArg("integration-id"),
7437
+ providerWorkspaceId: flagArg("provider-workspace-id"),
7438
+ providerAccountId: flagArg("provider-account-id"),
7439
+ rotateSecret: hasFlag("rotate-secret"),
7440
+ runBrainCycle: !hasFlag("no-brain-cycle"),
7441
+ brainCycleWriteMode: flagArg("write-mode") || "dry_run",
7442
+ brainCyclePhases: csvFlag("brain-cycle-phases"),
7443
+ brainCycleMinIngested: numberFlag("brain-cycle-min-ingested"),
7444
+ brainCycleMinIntervalMinutes: numberFlag("brain-cycle-min-interval-minutes")
7445
+ };
7446
+ const result = provider === "instantly" ? await sdk.gtm.prepareInstantlyFeedbackWebhook({
7447
+ ...common,
7448
+ instantlyCampaignId: flagArg("instantly-campaign-id")
7449
+ }) : await sdk.gtm.prepareFeedbackWebhook({ provider, ...common });
7450
+ return output(result, () => {
7451
+ console.log("GTM feedback webhook");
7452
+ console.log(` Provider: ${provider}`);
7453
+ console.log(` Brain cycle: ${common.runBrainCycle ? "enabled" : "disabled"} (${common.brainCycleWriteMode})`);
7454
+ if (result.webhook_url_redacted) {
7455
+ console.log(` Webhook: ${result.webhook_url_redacted}`);
7456
+ console.log(" Private URL: available in --json output as webhook_url");
7457
+ } else if (result.webhook_url) {
7458
+ console.log(" Webhook: ready");
7459
+ console.log(" Private URL: available in --json output as webhook_url");
7460
+ }
7461
+ if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
7462
+ hint(`signaliz gtm bootstrap${common.campaignId ? ` --campaign-id ${common.campaignId}` : ""} --include-samples`);
7463
+ });
7464
+ }
7465
+ if (sub === "nango") return gtmNango(rest[0], rest.slice(1));
5808
7466
  if (!sub || sub === "list" || sub === "sources") {
5809
7467
  const result = await sdk.leads.listNativeGtmCapabilities(flagArg("category"));
5810
7468
  return output(result, () => {
@@ -5864,7 +7522,81 @@ ${i + 1}. ${m.capability_id} (score ${m.score}) \u2014 ${m.label}`);
5864
7522
  const result = await sdk.leads.checkStatus(jobId);
5865
7523
  return output(result);
5866
7524
  }
5867
- die("Usage: signaliz gtm <list|find|run|status>");
7525
+ 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>");
7526
+ }
7527
+ function nangoActionInput() {
7528
+ const fromFile = readJsonFlag("input-file");
7529
+ const fromInline = readInlineJsonFlag("input-json");
7530
+ if (fromFile && fromInline) die("Use --input-file or --input-json, not both");
7531
+ return fromFile || fromInline;
7532
+ }
7533
+ function nangoBaseOptions() {
7534
+ return {
7535
+ workspaceConnectionId: flagArg("workspace-connection-id"),
7536
+ connectionId: flagArg("connection-id"),
7537
+ providerConfigKey: flagArg("provider-config-key"),
7538
+ integrationId: flagArg("integration-id"),
7539
+ nangoConnectionId: flagArg("nango-connection-id")
7540
+ };
7541
+ }
7542
+ function nangoStatusUrl(result) {
7543
+ return result?.status_url || result?.statusUrl || result?.nango_result?.status_url || result?.nango_result?.statusUrl;
7544
+ }
7545
+ async function gtmNango(sub, rest) {
7546
+ const sdk = getSdk();
7547
+ if (!sub || sub === "tools" || sub === "list") {
7548
+ const result = await sdk.gtm.listNangoTools({
7549
+ ...nangoBaseOptions(),
7550
+ format: flagArg("format"),
7551
+ includeRaw: hasFlag("include-raw")
7552
+ });
7553
+ return output(result, () => {
7554
+ const tools2 = Array.isArray(result?.tools) ? result.tools : [];
7555
+ console.log(`Nango tools: ${result?.tools_count ?? tools2.length}`);
7556
+ for (const tool of tools2.slice(0, 10)) {
7557
+ console.log(`- ${tool.name || tool.action_name || tool.id}: ${tool.description || tool.type || "action"}`);
7558
+ }
7559
+ hint(`signaliz gtm nango call <action_name> --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --dry-run`);
7560
+ });
7561
+ }
7562
+ if (sub === "call" || sub === "run") {
7563
+ const actionName = rest[0] || flagArg("action-name");
7564
+ const toolName = flagArg("tool-name");
7565
+ if (!actionName && !toolName) {
7566
+ die(`Usage: signaliz gtm nango call <action_name> --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' [--execute --confirm]`);
7567
+ }
7568
+ const result = await sdk.gtm.callNangoTool({
7569
+ ...nangoBaseOptions(),
7570
+ actionName,
7571
+ toolName,
7572
+ input: nangoActionInput(),
7573
+ async: hasFlag("async") || void 0,
7574
+ maxRetries: numberFlag("max-retries"),
7575
+ dryRun: hasFlag("execute") ? false : hasFlag("dry-run") ? true : void 0,
7576
+ confirm: hasFlag("confirm") || void 0,
7577
+ confirmWrite: hasFlag("confirm-write") || void 0
7578
+ });
7579
+ return output(result, () => {
7580
+ console.log(`Nango action ${result?.status || "submitted"}: ${actionName || toolName}`);
7581
+ const statusUrl = nangoStatusUrl(result);
7582
+ if (statusUrl) console.log(` Status URL: ${statusUrl}`);
7583
+ if (result?.next_action) console.log(` Next: ${result.next_action}`);
7584
+ if (statusUrl) hint(`signaliz gtm nango result --status-url ${statusUrl}`);
7585
+ });
7586
+ }
7587
+ if (sub === "result" || sub === "status") {
7588
+ const actionId = rest[0] || flagArg("action-id");
7589
+ const statusUrl = flagArg("status-url");
7590
+ if (!actionId && !statusUrl) die("Usage: signaliz gtm nango result --action-id <id> OR --status-url /action/<id>");
7591
+ const result = await sdk.gtm.getNangoActionResult({ actionId, statusUrl });
7592
+ return output(result, () => {
7593
+ console.log(`Nango action result: ${result?.status || "unknown"}`);
7594
+ if (result?.action_id || actionId) console.log(` Action ID: ${result?.action_id || actionId}`);
7595
+ const nextStatusUrl = nangoStatusUrl(result);
7596
+ if (nextStatusUrl) console.log(` Status URL: ${nextStatusUrl}`);
7597
+ });
7598
+ }
7599
+ die("Usage: signaliz gtm nango <tools|call|result>");
5868
7600
  }
5869
7601
  async function email(sub, rest) {
5870
7602
  const sdk = getSdk();
@@ -6200,6 +7932,7 @@ Available: ${result.available_types.join(", ")}`);
6200
7932
  }
6201
7933
  console.log(`Apps: ${result.summary.connectedDestinations} connected, ${result.summary.failingDestinations} failing`);
6202
7934
  console.log(`Receipts: ${result.summary.delivered30d} delivered, ${result.summary.externalDelivered30d} external`);
7935
+ console.log(`Nango API: ${result.summary.nangoProofs30d ?? 0} receipts, ${result.summary.nangoFailures30d ?? 0} failures`);
6203
7936
  console.log(`CRM proof: ${result.summary.airbyteProofs30d} receipts, ${result.summary.airbyteFailures30d} failures`);
6204
7937
  if (result.destinations.length) {
6205
7938
  console.log("\nDestinations");
@@ -6637,6 +8370,109 @@ var OPS_SHORTCUTS = {
6637
8370
  "attach-sink": "attach-sink",
6638
8371
  saved: "saved"
6639
8372
  };
8373
+ async function withSyntheticArgs(args, fn) {
8374
+ if (!args.length) return fn();
8375
+ const originalArgv = process.argv;
8376
+ process.argv = [...process.argv, ...args];
8377
+ try {
8378
+ return await fn();
8379
+ } finally {
8380
+ process.argv = originalArgv;
8381
+ }
8382
+ }
8383
+ async function simpleJob(cmd, rest) {
8384
+ if (cmd === "build") {
8385
+ if (isHelpRequest(rest) || !promptArg(rest) && !flagArg("prompt") && !flagArg("brief") && !flagArg("campaign-brief")) {
8386
+ process.stdout.write(`signaliz build "campaign brief" [options]
8387
+
8388
+ Plan a campaign without spending credits or writing to providers.
8389
+
8390
+ Examples:
8391
+ signaliz build "Build a campaign for industrial maintenance buyers" --target-count 50
8392
+ signaliz build "Audit prior Instantly performance and build the next campaign" --preferred-providers instantly
8393
+
8394
+ Equivalent:
8395
+ signaliz gtm plan "campaign brief"
8396
+ `);
8397
+ return;
8398
+ }
8399
+ return gtm("plan", rest);
8400
+ }
8401
+ if (cmd === "connect") {
8402
+ if (isHelpRequest(rest)) {
8403
+ process.stdout.write(`signaliz connect [options]
8404
+
8405
+ Inspect provider/tool route readiness across the GTM stack.
8406
+
8407
+ Examples:
8408
+ signaliz connect
8409
+ signaliz connect --campaign-id <campaign_id>
8410
+ signaliz connect --layer sender
8411
+
8412
+ Equivalent:
8413
+ signaliz gtm integrations --include-planned
8414
+ `);
8415
+ return;
8416
+ }
8417
+ const defaults = rest.includes("--include-planned") ? [] : ["--include-planned"];
8418
+ return withSyntheticArgs(defaults, () => gtm("integrations", rest));
8419
+ }
8420
+ if (cmd === "audit") {
8421
+ if (isHelpRequest(rest)) {
8422
+ process.stdout.write(`signaliz audit [options]
8423
+
8424
+ Find previous campaigns to audit before building the next motion.
8425
+
8426
+ Examples:
8427
+ signaliz audit
8428
+ signaliz audit --provider instantly --limit 10
8429
+ signaliz gtm audit-existing --search "industrial maintenance"
8430
+
8431
+ Equivalent:
8432
+ signaliz gtm existing-campaigns --provider instantly --limit 5
8433
+ `);
8434
+ return;
8435
+ }
8436
+ const defaults = [];
8437
+ if (!rest.includes("--provider") && !rest.some((arg2) => arg2.startsWith("--provider="))) defaults.push("--provider", "instantly");
8438
+ if (!rest.includes("--limit") && !rest.some((arg2) => arg2.startsWith("--limit="))) defaults.push("--limit", "5");
8439
+ return withSyntheticArgs(defaults, () => gtm("existing-campaigns", rest));
8440
+ }
8441
+ if (cmd === "improve") {
8442
+ if (isHelpRequest(rest) || !rest[0] && !flagArg("campaign-id")) {
8443
+ process.stdout.write(`signaliz improve <campaign_id> [options]
8444
+
8445
+ Plan Brain learning and improvement lanes for an existing campaign.
8446
+
8447
+ Examples:
8448
+ signaliz improve <campaign_id>
8449
+ signaliz improve <campaign_id> --include-network --write-mode dry_run
8450
+
8451
+ Equivalent:
8452
+ signaliz gtm learning <campaign_id>
8453
+ `);
8454
+ return;
8455
+ }
8456
+ return gtm("learning", rest);
8457
+ }
8458
+ if (cmd === "prove") {
8459
+ if (isHelpRequest(rest)) {
8460
+ process.stdout.write(`signaliz prove [options]
8461
+
8462
+ Prove Ops delivery readiness before scaling a GTM motion.
8463
+
8464
+ Examples:
8465
+ signaliz prove
8466
+ signaliz prove --json
8467
+
8468
+ Equivalent:
8469
+ signaliz ops proof
8470
+ `);
8471
+ return;
8472
+ }
8473
+ return ops("proof", rest);
8474
+ }
8475
+ }
6640
8476
  async function main() {
6641
8477
  const [, , cmd, ...rest] = process.argv;
6642
8478
  if (!cmd || cmd === "--help" || cmd === "-h") {
@@ -6645,6 +8481,9 @@ async function main() {
6645
8481
  }
6646
8482
  const opsShortcut = OPS_SHORTCUTS[cmd];
6647
8483
  if (opsShortcut) return ops(opsShortcut, rest);
8484
+ if (["build", "connect", "audit", "improve", "prove"].includes(cmd)) {
8485
+ return simpleJob(cmd, rest);
8486
+ }
6648
8487
  switch (cmd) {
6649
8488
  case "auth": {
6650
8489
  const sub = rest[0];
@@ -6662,6 +8501,9 @@ async function main() {
6662
8501
  return whoami();
6663
8502
  case "health":
6664
8503
  return health();
8504
+ case "start":
8505
+ case "where-do-i-start":
8506
+ return start();
6665
8507
  case "tools":
6666
8508
  return tools();
6667
8509
  case "discover":
@@ -6672,7 +8514,17 @@ async function main() {
6672
8514
  case "leads":
6673
8515
  return lead(rest[0], rest.slice(1));
6674
8516
  case "gtm":
8517
+ if (!rest[0] || rest[0] === "--help" || rest[0] === "-h") {
8518
+ process.stdout.write(GTM_HELP);
8519
+ return;
8520
+ }
8521
+ if (rest[0] === "help") {
8522
+ process.stdout.write(gtmHelpFor(rest[1]));
8523
+ return;
8524
+ }
6675
8525
  return gtm(rest[0], rest.slice(1));
8526
+ case "nango":
8527
+ return gtm("nango", rest);
6676
8528
  case "email":
6677
8529
  case "emails":
6678
8530
  return email(rest[0], rest.slice(1));