@signaliz/sdk 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,6 +7,20 @@ Nango-managed customer API connections, MCP/Ops control-plane methods, and
7
7
  enrichment primitives. Available data is returned before fresh enrichment;
8
8
  live email verification is 0.02 fresh enrichment credits when a new verification is needed.
9
9
 
10
+ ## Which Surface Should I Use?
11
+
12
+ Signaliz is the GTM brain over any stack. The SDK is for application code,
13
+ scripts, and agent runtimes that need typed access to the same GTM Kernel, Ops,
14
+ integration, and approval primitives exposed through MCP and CLI.
15
+
16
+ - Use MCP or Codex when an agent should reason, choose tools, and build or audit
17
+ a campaign from a plain-English goal.
18
+ - Use the CLI when a human operator or local agent needs a repeatable command,
19
+ JSON receipt, readiness check, or debug trail. Start with `signaliz start`.
20
+ - Use the SDK when product code or automation needs typed methods.
21
+ - Use the UI as the human cockpit to inspect state, connect tools, approve gated
22
+ actions, and monitor results.
23
+
10
24
  ## Installation
11
25
 
12
26
  ```bash
@@ -74,6 +88,12 @@ const seed = await signaliz.gtm.seedBrainDefaults({
74
88
  layers: ['icp', 'lead_generation', 'copy_enrichment'],
75
89
  includeGlobal: true,
76
90
  });
91
+ console.log({
92
+ workspacePatterns: seed.seed?.evidence?.workspace_pattern_count,
93
+ networkPatterns: seed.seed?.evidence?.global_pattern_count,
94
+ activeRoutes: seed.seed?.recommended_defaults?.provider_strategy?.active_layer_routes?.length ?? 0,
95
+ privacyPolicy: seed.privacy_policy,
96
+ });
77
97
 
78
98
  const failures = await signaliz.gtm.failurePatterns({
79
99
  campaignId: campaign.campaign?.id,
@@ -111,6 +131,21 @@ const campaignLearning = await signaliz.gtm.campaignLearningStatus({
111
131
  const readyLanes = campaignLearning.learning_lanes?.filter((lane) => lane.state === 'ready') ?? [];
112
132
  const networkLane = campaignLearning.learning_lanes?.find((lane) => lane.id === 'network_patterns');
113
133
 
134
+ const memory = await signaliz.gtm.searchMemory({
135
+ query: 'subject lines that worked for SaaS engineering leaders',
136
+ outcomeType: 'meeting_booked',
137
+ targetIcp: { persona: 'Head of Engineering', segment: 'Series B SaaS' },
138
+ layers: ['copy_enrichment', 'sender'],
139
+ limit: 5,
140
+ });
141
+ const topMemory = memory.memories?.[0];
142
+ console.log({
143
+ title: topMemory?.title,
144
+ outcomeClass: Array.isArray(topMemory?.match_reasons) ? undefined : topMemory?.match_reasons?.outcome_class,
145
+ requestedOutcomeMatch: Array.isArray(topMemory?.match_reasons) ? false : topMemory?.match_reasons?.requested_outcome_match,
146
+ outcomeScore: Array.isArray(topMemory?.match_reasons) ? undefined : topMemory?.match_reasons?.outcome_score,
147
+ });
148
+
114
149
  await signaliz.gtm.createIntegrationRecipe({
115
150
  providerId: 'clay_webhook',
116
151
  providerName: 'Clay Webhook',
@@ -139,6 +174,47 @@ Smartlead, custom APIs, custom MCP servers, or manual review gates. Nango routes
139
174
  keep customer credentials in Nango while Signaliz stores only the workspace
140
175
  connection reference and approval/audit context.
141
176
 
177
+ ### Nango-Managed API Tools
178
+
179
+ Use Nango when a workspace brings its own provider account and the action should
180
+ run through Nango-managed auth. Start by listing available tools for the saved
181
+ workspace connection, dry-run the action, then confirm the write only after the
182
+ preview is approved.
183
+
184
+ ```typescript
185
+ const tools = await signaliz.gtm.listNangoTools({
186
+ workspaceConnectionId: 'workspace_conn_nango_hubspot',
187
+ providerConfigKey: 'hubspot',
188
+ includeRaw: false,
189
+ });
190
+
191
+ const preview = await signaliz.gtm.callNangoTool({
192
+ workspaceConnectionId: 'workspace_conn_nango_hubspot',
193
+ actionName: 'upsert-contact',
194
+ input: { email: 'buyer@example.com', company: 'Acme' },
195
+ dryRun: true,
196
+ confirm: false,
197
+ });
198
+
199
+ if (preview.ready_for_confirmation) {
200
+ const confirmed = await signaliz.gtm.callNangoTool({
201
+ workspaceConnectionId: 'workspace_conn_nango_hubspot',
202
+ actionName: 'upsert-contact',
203
+ input: { email: 'buyer@example.com', company: 'Acme' },
204
+ dryRun: false,
205
+ confirm: true,
206
+ async: true,
207
+ });
208
+
209
+ if (confirmed.action_id || confirmed.status_url) {
210
+ await signaliz.gtm.getNangoActionResult({
211
+ actionId: confirmed.action_id,
212
+ statusUrl: confirmed.status_url,
213
+ });
214
+ }
215
+ }
216
+ ```
217
+
142
218
  ### GTM Kernel Smoke Test
143
219
 
144
220
  After CMM imports or Campaign Builder backfills, run the read-only/dry-run
@@ -150,8 +226,9 @@ SIGNALIZ_API_KEY=sk_... node scripts/cmm-kernel-smoke.mjs \
150
226
  ```
151
227
 
152
228
  The receipt includes campaign/build/workspace IDs, execution stage, feedback and
153
- memory counts, Brain phase readiness, blockers/warnings, the next safe MCP
154
- action, and explicit no-spend/no-write/no-sender/no-delivery confirmation.
229
+ memory counts, workspace bootstrap gate readiness, Brain phase readiness,
230
+ blockers/warnings, the next safe MCP action, and explicit
231
+ no-spend/no-write/no-sender/no-delivery confirmation.
155
232
 
156
233
  ## MCP/Ops Control Plane
157
234
 
@@ -171,13 +171,14 @@ var HttpClient = class {
171
171
  details: { responseText: text.slice(0, 500) }
172
172
  });
173
173
  }
174
- if (data.error) {
174
+ const responseError = isRecord(data) && isRecord(data.error) ? data.error : null;
175
+ if (responseError) {
175
176
  const err = new SignalizError({
176
- code: data.error.code?.toString() || data.error.data?.error_code || "MCP_ERROR",
177
- message: data.error.message || "MCP request failed",
178
- errorType: mapMcpErrorType(data.error),
179
- retryAfter: data.error.data?.retry_after,
180
- details: data.error.data
177
+ code: firstString(responseError.code, isRecord(responseError.data) ? responseError.data.error_code : void 0) || "MCP_ERROR",
178
+ message: firstString(responseError.message) || "MCP request failed",
179
+ errorType: mapMcpErrorType(responseError),
180
+ retryAfter: isRecord(responseError.data) && typeof responseError.data.retry_after === "number" ? responseError.data.retry_after : void 0,
181
+ details: isRecord(responseError.data) ? responseError.data : void 0
181
182
  });
182
183
  if (err.isRetryable && attempt < this.maxRetries) {
183
184
  lastError = err;
@@ -254,35 +255,63 @@ function normalizeMcpParams(method, params) {
254
255
  }
255
256
  };
256
257
  }
258
+ function isRecord(value) {
259
+ return typeof value === "object" && value !== null;
260
+ }
261
+ function firstString(...values) {
262
+ const value = values.find((item) => typeof item === "string" && item.length > 0);
263
+ return typeof value === "string" ? value : void 0;
264
+ }
265
+ function firstPayloadError(payload) {
266
+ const errors = payload.errors;
267
+ const first = Array.isArray(errors) ? errors[0] : void 0;
268
+ return isRecord(first) ? first : {};
269
+ }
257
270
  function unwrapMcpResponse(data) {
258
- if (data?.result?.structuredContent !== void 0) {
259
- return unwrapMcpPayload(data.result.structuredContent);
271
+ const result = isRecord(data) ? data.result : void 0;
272
+ if (isRecord(result) && result.structuredContent !== void 0) {
273
+ return unwrapMcpPayload(result.structuredContent);
260
274
  }
261
- const text = data?.result?.content?.[0]?.text;
275
+ const content = isRecord(result) ? result.content : void 0;
276
+ const firstContent = Array.isArray(content) ? content[0] : void 0;
277
+ const text = isRecord(firstContent) ? firstContent.text : void 0;
262
278
  if (typeof text === "string") {
263
279
  const parsed = safeJson(text);
264
280
  return unwrapMcpPayload(parsed ?? text);
265
281
  }
266
- return unwrapMcpPayload(data?.result);
282
+ return unwrapMcpPayload(result);
267
283
  }
268
284
  function unwrapMcpPayload(payload) {
269
- if (payload && typeof payload === "object") {
285
+ if (isRecord(payload)) {
270
286
  if (payload.ok === true && Object.prototype.hasOwnProperty.call(payload, "result")) {
271
287
  return payload.result;
272
288
  }
289
+ if (payload.ok === false) {
290
+ const first = firstPayloadError(payload);
291
+ const code = firstString(first.code, payload.error_code, payload.code) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
292
+ throw new SignalizError({
293
+ code,
294
+ message: firstString(first.message, payload.message, payload.summary, payload.error) || "MCP request failed",
295
+ errorType: mapErrorTypeFromCode(code),
296
+ details: {
297
+ ...payload,
298
+ ...isRecord(first.details) ? first.details : {}
299
+ }
300
+ });
301
+ }
273
302
  if (payload.success === true && Object.prototype.hasOwnProperty.call(payload, "data")) {
274
303
  return payload.data;
275
304
  }
276
305
  if (payload.success === false) {
277
- const first = Array.isArray(payload.errors) ? payload.errors[0] ?? {} : {};
278
- const code = first.code || payload.error_code || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
306
+ const first = firstPayloadError(payload);
307
+ const code = firstString(first.code, payload.error_code) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
279
308
  throw new SignalizError({
280
309
  code,
281
- message: first.message || payload.message || payload.summary || "MCP request failed",
310
+ message: firstString(first.message, payload.message, payload.summary) || "MCP request failed",
282
311
  errorType: mapErrorTypeFromCode(code),
283
312
  details: {
284
313
  ...payload,
285
- ...first.details && typeof first.details === "object" ? first.details : {}
314
+ ...isRecord(first.details) ? first.details : {}
286
315
  }
287
316
  });
288
317
  }
@@ -290,8 +319,10 @@ function unwrapMcpPayload(payload) {
290
319
  return payload;
291
320
  }
292
321
  function mapMcpErrorType(error) {
293
- const code = String(error?.data?.error_code || error?.code || "");
294
- const message = String(error?.message || "").toLowerCase();
322
+ const errorRecord = isRecord(error) ? error : {};
323
+ const data = isRecord(errorRecord.data) ? errorRecord.data : {};
324
+ const code = String(data.error_code || errorRecord.code || "");
325
+ const message = String(errorRecord.message || "").toLowerCase();
295
326
  if (code === "429" || message.includes("rate limit")) return "rate_limited";
296
327
  if (code === "401" || code === "AUTH_001" || message.includes("auth")) return "auth_expired";
297
328
  if (code === "400" || code === "-32602" || message.includes("invalid")) return "validation";
@@ -2922,6 +2953,10 @@ function normalizeOpsProofResult(data) {
2922
2953
  failed30d: numberValue(summary.failed_30d ?? summary.failed30d),
2923
2954
  external_delivered_30d: numberValue(summary.external_delivered_30d ?? summary.externalDelivered30d),
2924
2955
  externalDelivered30d: numberValue(summary.external_delivered_30d ?? summary.externalDelivered30d),
2956
+ nango_proofs_30d: numberValue(summary.nango_proofs_30d ?? summary.nangoProofs30d),
2957
+ nangoProofs30d: numberValue(summary.nango_proofs_30d ?? summary.nangoProofs30d),
2958
+ nango_failures_30d: numberValue(summary.nango_failures_30d ?? summary.nangoFailures30d),
2959
+ nangoFailures30d: numberValue(summary.nango_failures_30d ?? summary.nangoFailures30d),
2925
2960
  airbyte_configured: numberValue(summary.airbyte_configured ?? summary.airbyteConfigured),
2926
2961
  airbyteConfigured: numberValue(summary.airbyte_configured ?? summary.airbyteConfigured),
2927
2962
  airbyte_proofs_30d: numberValue(summary.airbyte_proofs_30d ?? summary.airbyteProofs30d),
@@ -3336,9 +3371,10 @@ function buildOpsDebugOptions(params) {
3336
3371
  }
3337
3372
  function buildCreateRoutineBody(params) {
3338
3373
  const { outputSinks, wakeOnEvents, ...rest } = params;
3374
+ const sinks = rest.output_sinks ?? outputSinks;
3339
3375
  return {
3340
3376
  ...rest,
3341
- output_sinks: rest.output_sinks ?? outputSinks,
3377
+ output_sinks: Array.isArray(sinks) ? sinks.map(normalizeOpsSinkRequest) : sinks,
3342
3378
  wake_on_events: rest.wake_on_events ?? wakeOnEvents
3343
3379
  };
3344
3380
  }
@@ -3372,6 +3408,97 @@ function buildCreateOutputSinkBody(params) {
3372
3408
  webhook_url: rest.webhook_url ?? webhookUrl
3373
3409
  };
3374
3410
  }
3411
+ function normalizeOpsSinkRequest(sink) {
3412
+ const {
3413
+ sinkId,
3414
+ connectionId,
3415
+ connectorId,
3416
+ connectorName,
3417
+ deliveryMode,
3418
+ providerConfigKey,
3419
+ integrationId,
3420
+ nangoConnectionId,
3421
+ actionName,
3422
+ nangoAction,
3423
+ proxyPath,
3424
+ nangoProxyPath,
3425
+ fieldMap,
3426
+ requiredFields,
3427
+ writeConfirmed,
3428
+ agentWriteConfirmed,
3429
+ config,
3430
+ ...rest
3431
+ } = sink;
3432
+ const normalizedConfig = normalizeOpsSinkConfigRequest(config);
3433
+ const connection_id = rest.connection_id ?? connectionId;
3434
+ const connector_id = rest.connector_id ?? connectorId;
3435
+ const delivery_mode = rest.delivery_mode ?? deliveryMode;
3436
+ const provider_config_key = rest.provider_config_key ?? providerConfigKey;
3437
+ const integration_id = rest.integration_id ?? integrationId;
3438
+ const nango_connection_id = rest.nango_connection_id ?? nangoConnectionId;
3439
+ const action_name = rest.action_name ?? actionName;
3440
+ const nango_action = rest.nango_action ?? nangoAction;
3441
+ const proxy_path = rest.proxy_path ?? proxyPath;
3442
+ const nango_proxy_path = rest.nango_proxy_path ?? nangoProxyPath;
3443
+ const field_map = rest.field_map ?? fieldMap;
3444
+ const required_fields = rest.required_fields ?? requiredFields;
3445
+ const write_confirmed = rest.write_confirmed ?? writeConfirmed;
3446
+ const agent_write_confirmed = rest.agent_write_confirmed ?? agentWriteConfirmed;
3447
+ if (connection_id !== void 0 && normalizedConfig.connection_id === void 0) normalizedConfig.connection_id = connection_id;
3448
+ if (connector_id !== void 0 && normalizedConfig.connector_id === void 0) normalizedConfig.connector_id = connector_id;
3449
+ if (delivery_mode !== void 0 && normalizedConfig.delivery_mode === void 0) normalizedConfig.delivery_mode = delivery_mode;
3450
+ if (provider_config_key !== void 0 && normalizedConfig.provider_config_key === void 0) normalizedConfig.provider_config_key = provider_config_key;
3451
+ if (integration_id !== void 0 && normalizedConfig.integration_id === void 0) normalizedConfig.integration_id = integration_id;
3452
+ if (nango_connection_id !== void 0 && normalizedConfig.nango_connection_id === void 0) normalizedConfig.nango_connection_id = nango_connection_id;
3453
+ if (action_name !== void 0 && normalizedConfig.action_name === void 0) normalizedConfig.action_name = action_name;
3454
+ if (nango_action !== void 0 && normalizedConfig.nango_action === void 0) normalizedConfig.nango_action = nango_action;
3455
+ if (proxy_path !== void 0 && normalizedConfig.proxy_path === void 0) normalizedConfig.proxy_path = proxy_path;
3456
+ if (nango_proxy_path !== void 0 && normalizedConfig.nango_proxy_path === void 0) normalizedConfig.nango_proxy_path = nango_proxy_path;
3457
+ if (field_map !== void 0 && normalizedConfig.field_map === void 0) normalizedConfig.field_map = field_map;
3458
+ if (required_fields !== void 0 && normalizedConfig.required_fields === void 0) normalizedConfig.required_fields = required_fields;
3459
+ if (write_confirmed !== void 0 && normalizedConfig.write_confirmed === void 0) normalizedConfig.write_confirmed = write_confirmed;
3460
+ if (agent_write_confirmed !== void 0 && normalizedConfig.agent_write_confirmed === void 0) normalizedConfig.agent_write_confirmed = agent_write_confirmed;
3461
+ if (sink.type === "nango" && normalizedConfig.integration_platform === void 0) normalizedConfig.integration_platform = "nango";
3462
+ return {
3463
+ ...rest,
3464
+ sink_id: rest.sink_id ?? sinkId,
3465
+ connection_id,
3466
+ connector_id,
3467
+ connector_name: rest.connector_name ?? connectorName,
3468
+ delivery_mode,
3469
+ provider_config_key,
3470
+ integration_id,
3471
+ nango_connection_id,
3472
+ action_name,
3473
+ nango_action,
3474
+ proxy_path,
3475
+ nango_proxy_path,
3476
+ field_map,
3477
+ required_fields,
3478
+ write_confirmed,
3479
+ agent_write_confirmed,
3480
+ config: normalizedConfig
3481
+ };
3482
+ }
3483
+ function normalizeOpsSinkConfigRequest(config) {
3484
+ const out = { ...config ?? {} };
3485
+ if (out.connection_id === void 0 && out.connectionId !== void 0) out.connection_id = out.connectionId;
3486
+ if (out.connector_id === void 0 && out.connectorId !== void 0) out.connector_id = out.connectorId;
3487
+ if (out.connector_name === void 0 && out.connectorName !== void 0) out.connector_name = out.connectorName;
3488
+ if (out.delivery_mode === void 0 && out.deliveryMode !== void 0) out.delivery_mode = out.deliveryMode;
3489
+ if (out.provider_config_key === void 0 && out.providerConfigKey !== void 0) out.provider_config_key = out.providerConfigKey;
3490
+ if (out.integration_id === void 0 && out.integrationId !== void 0) out.integration_id = out.integrationId;
3491
+ if (out.nango_connection_id === void 0 && out.nangoConnectionId !== void 0) out.nango_connection_id = out.nangoConnectionId;
3492
+ if (out.action_name === void 0 && out.actionName !== void 0) out.action_name = out.actionName;
3493
+ if (out.nango_action === void 0 && out.nangoAction !== void 0) out.nango_action = out.nangoAction;
3494
+ if (out.proxy_path === void 0 && out.proxyPath !== void 0) out.proxy_path = out.proxyPath;
3495
+ if (out.nango_proxy_path === void 0 && out.nangoProxyPath !== void 0) out.nango_proxy_path = out.nangoProxyPath;
3496
+ if (out.field_map === void 0 && out.fieldMap !== void 0) out.field_map = out.fieldMap;
3497
+ if (out.required_fields === void 0 && out.requiredFields !== void 0) out.required_fields = out.requiredFields;
3498
+ if (out.write_confirmed === void 0 && out.writeConfirmed !== void 0) out.write_confirmed = out.writeConfirmed;
3499
+ if (out.agent_write_confirmed === void 0 && out.agentWriteConfirmed !== void 0) out.agent_write_confirmed = out.agentWriteConfirmed;
3500
+ return out;
3501
+ }
3375
3502
  function buildApproveBody(params) {
3376
3503
  const { tokenId, tokenIds, reviewerNotes, ...rest } = params;
3377
3504
  return {
@@ -3520,6 +3647,57 @@ var GtmKernel = class {
3520
3647
  limit: options.limit
3521
3648
  });
3522
3649
  }
3650
+ /** Discover existing provider campaigns, starting with live/Kernel-linked Instantly campaigns, before audit or import preview. */
3651
+ async discoverExistingCampaigns(options = {}) {
3652
+ return this.callMcp("gtm_existing_campaign_discover", {
3653
+ provider: options.provider,
3654
+ integration_id: options.integrationId,
3655
+ search: options.search,
3656
+ limit: options.limit,
3657
+ include_kernel_linked: options.includeKernelLinked,
3658
+ include_provider_live: options.includeProviderLive
3659
+ });
3660
+ }
3661
+ /** Run a read-only existing campaign audit with completeness, recommendations, safe next MCP JSON, and approval boundaries. */
3662
+ async auditExistingCampaign(options) {
3663
+ return this.callMcp("gtm_existing_campaign_audit", {
3664
+ campaign_id: options.campaignId,
3665
+ provider: options.provider,
3666
+ provider_campaign_id: options.providerCampaignId,
3667
+ campaign_name: options.campaignName,
3668
+ days: options.days,
3669
+ include_route_preview: options.includeRoutePreview,
3670
+ include_memory: options.includeMemory,
3671
+ include_brain: options.includeBrain
3672
+ });
3673
+ }
3674
+ /** Discover the first matching existing provider campaign, then run the same read-only audit against that match. */
3675
+ async auditExistingCampaignBySearch(options) {
3676
+ const discovery = await this.discoverExistingCampaigns({
3677
+ provider: options.provider,
3678
+ integrationId: options.integrationId,
3679
+ search: options.search,
3680
+ limit: 1,
3681
+ includeKernelLinked: options.includeKernelLinked,
3682
+ includeProviderLive: options.includeProviderLive
3683
+ });
3684
+ const match = discovery.campaigns?.[0];
3685
+ const campaignId = match?.linked_kernel_campaign_id || void 0;
3686
+ const providerCampaignId = match?.provider_campaign_id || void 0;
3687
+ if (!campaignId && !providerCampaignId) {
3688
+ throw new Error(`No existing ${options.provider || discovery.provider || "provider"} campaign matched "${options.search}"`);
3689
+ }
3690
+ return this.auditExistingCampaign({
3691
+ provider: options.provider || discovery.provider || match?.provider,
3692
+ campaignId,
3693
+ providerCampaignId,
3694
+ campaignName: match?.name || match?.linked_kernel_campaign_name || void 0,
3695
+ days: options.days,
3696
+ includeRoutePreview: options.includeRoutePreview,
3697
+ includeMemory: options.includeMemory,
3698
+ includeBrain: options.includeBrain
3699
+ });
3700
+ }
3523
3701
  /** Create a first-class GTM campaign object in the current workspace. */
3524
3702
  async createCampaign(input) {
3525
3703
  return this.callMcp("gtm_campaign_create", campaignCreateArgs(input));
@@ -3725,6 +3903,47 @@ var GtmKernel = class {
3725
3903
  brain_cycle_min_interval_minutes: input.brainCycleMinIntervalMinutes
3726
3904
  });
3727
3905
  }
3906
+ /** Preview anonymized Instantly workspace sources registered for Kernel import. */
3907
+ async previewKernelImport(input = {}) {
3908
+ return this.callMcp("gtm_kernel_import_preview", {
3909
+ source_ids: input.sourceIds,
3910
+ include_leads: input.includeLeads,
3911
+ include_replies: input.includeReplies,
3912
+ include_private_copy: input.includePrivateCopy,
3913
+ max_pages: input.maxPages,
3914
+ limit: input.limit
3915
+ });
3916
+ }
3917
+ /** Queue the read-only Instantly-to-GTM Kernel import. Live writes require writeApproved. */
3918
+ async runKernelImport(input = {}) {
3919
+ return this.callMcp("gtm_kernel_import_run", {
3920
+ source_ids: input.sourceIds,
3921
+ dry_run: input.dryRun,
3922
+ write_approved: input.writeApproved,
3923
+ include_leads: input.includeLeads,
3924
+ include_replies: input.includeReplies,
3925
+ include_private_copy: input.includePrivateCopy,
3926
+ private_copy_approved: input.privateCopyApproved,
3927
+ promote_global_patterns: input.promoteGlobalPatterns,
3928
+ min_global_privacy_k: input.minGlobalPrivacyK,
3929
+ max_pages: input.maxPages,
3930
+ limit: input.limit
3931
+ });
3932
+ }
3933
+ /** Queue Brain distillation over imported Instantly memory with abstracted-only outputs. */
3934
+ async runBrainDistillation(input = {}) {
3935
+ return this.callMcp("gtm_brain_distill_run", {
3936
+ source_ids: input.sourceIds,
3937
+ write_mode: input.writeMode,
3938
+ write_approved: input.writeApproved,
3939
+ brain_cycle_phases: input.brainCyclePhases,
3940
+ days: input.days,
3941
+ network_days: input.networkDays,
3942
+ min_sample_size: input.minSampleSize,
3943
+ min_workspace_count: input.minWorkspaceCount,
3944
+ min_privacy_k: input.minPrivacyK
3945
+ });
3946
+ }
3728
3947
  /** Prepare a provider-agnostic feedback webhook URL for Smartlead, HeyReach, Airbyte, or custom sender events. */
3729
3948
  async prepareFeedbackWebhook(input) {
3730
3949
  return this.callMcp("gtm_feedback_webhook_prepare", {
@@ -4152,6 +4371,43 @@ var GtmKernel = class {
4152
4371
  context: input.context
4153
4372
  });
4154
4373
  }
4374
+ /** List Nango-backed action tools for a workspace connection without executing them. */
4375
+ async listNangoTools(options = {}) {
4376
+ return this.callMcp("nango_mcp_tools_list", {
4377
+ workspace_connection_id: options.workspaceConnectionId,
4378
+ connection_id: options.connectionId,
4379
+ provider_config_key: options.providerConfigKey,
4380
+ integration_id: options.integrationId,
4381
+ nango_connection_id: options.nangoConnectionId,
4382
+ format: options.format,
4383
+ include_raw: options.includeRaw
4384
+ });
4385
+ }
4386
+ /** Dry-run or execute a Nango-backed action tool through the approval-aware MCP bridge. */
4387
+ async callNangoTool(input) {
4388
+ return this.callMcp("nango_mcp_tool_call", {
4389
+ workspace_connection_id: input.workspaceConnectionId,
4390
+ connection_id: input.connectionId,
4391
+ provider_config_key: input.providerConfigKey,
4392
+ integration_id: input.integrationId,
4393
+ nango_connection_id: input.nangoConnectionId,
4394
+ action_name: input.actionName,
4395
+ tool_name: input.toolName,
4396
+ input: input.input,
4397
+ async: input.async,
4398
+ max_retries: input.maxRetries,
4399
+ dry_run: input.dryRun,
4400
+ confirm: input.confirm,
4401
+ confirm_write: input.confirmWrite
4402
+ });
4403
+ }
4404
+ /** Poll an async Nango action result by action id or status URL. */
4405
+ async getNangoActionResult(input) {
4406
+ return this.callMcp("nango_mcp_action_result_get", {
4407
+ action_id: input.actionId,
4408
+ status_url: input.statusUrl
4409
+ });
4410
+ }
4155
4411
  /** Deliver approved campaign-layer records to a webhook recipe, starting with Clay-style webhooks. */
4156
4412
  async deliverWebhook(input) {
4157
4413
  return this.callMcp("gtm_webhook_deliver", {
@@ -4286,6 +4542,59 @@ function compact2(value) {
4286
4542
  }
4287
4543
 
4288
4544
  // src/index.ts
4545
+ function inferMcpToolCategory(toolName) {
4546
+ if (typeof toolName !== "string" || !toolName) return void 0;
4547
+ if (toolName.startsWith("ops_") || toolName === "get_ops_readiness" || toolName === "get_gtm_ops_readiness" || toolName.startsWith("gtm_") || [
4548
+ "list_routines",
4549
+ "create_routine",
4550
+ "update_routine",
4551
+ "run_routine_now",
4552
+ "get_routine",
4553
+ "get_routine_ticks",
4554
+ "get_tick_items",
4555
+ "get_last_tick_items",
4556
+ "chain_routines",
4557
+ "get_chain_status",
4558
+ "launch_campaign",
4559
+ "quickstart_gtm_book",
4560
+ "list_campaigns",
4561
+ "campaign_performance",
4562
+ "tune_campaign",
4563
+ "emit_event",
4564
+ "approvals_list",
4565
+ "list_output_sinks",
4566
+ "create_output_sink",
4567
+ "update_output_sink",
4568
+ "delete_output_sink",
4569
+ "attach_sink_to_routine"
4570
+ ].includes(toolName)) {
4571
+ return "ops";
4572
+ }
4573
+ if ([
4574
+ "find_emails_with_verification",
4575
+ "verify_email",
4576
+ "enrich_company_signals",
4577
+ "company_intelligence",
4578
+ "find_contacts_with_email",
4579
+ "execute_primitive"
4580
+ ].includes(toolName)) {
4581
+ return "enrichment";
4582
+ }
4583
+ if (toolName.includes("icp")) return "icp";
4584
+ if (toolName.startsWith("ai_clean_")) return "data_cleaning";
4585
+ if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
4586
+ if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
4587
+ return void 0;
4588
+ }
4589
+ function asRecord3(value) {
4590
+ return value && typeof value === "object" ? value : void 0;
4591
+ }
4592
+ function asStringArray(value) {
4593
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : void 0;
4594
+ }
4595
+ function asObjectSchema(value) {
4596
+ return asRecord3(value);
4597
+ }
4289
4598
  var Signaliz = class {
4290
4599
  constructor(config) {
4291
4600
  this.client = new HttpClient(config);
@@ -4344,21 +4653,21 @@ var Signaliz = class {
4344
4653
  const data = await this.client.mcp("tools/list", {});
4345
4654
  const tools = data?.tools ?? data ?? [];
4346
4655
  return tools.map((t) => ({
4347
- name: t.name,
4348
- description: (t.description ?? "").slice(0, 120),
4349
- category: t.annotations?.category,
4350
- costCredits: t.annotations?.cost_credits,
4351
- contractVersion: t.annotations?.contract_version ?? t.annotations?.contract?.contract_version,
4352
- permissionLevel: t.annotations?.permission_level ?? t.annotations?.contract?.permission_level,
4353
- authScopes: t.annotations?.auth_scopes ?? t.annotations?.contract?.auth_scopes,
4354
- idempotent: t.annotations?.idempotentHint ?? t.annotations?.idempotent ?? t.annotations?.contract?.idempotent,
4355
- destructive: t.annotations?.destructiveHint ?? t.annotations?.destructive ?? t.annotations?.contract?.destructive,
4356
- retryable: t.annotations?.retryable ?? t.annotations?.contract?.retryable,
4357
- rateLimitKey: t.annotations?.rate_limit_key ?? t.annotations?.contract?.rate_limit_key,
4358
- observability: t.annotations?.observability ?? t.annotations?.contract?.observability,
4359
- inputSchema: t.inputSchema ?? t.input_schema ?? t.annotations?.contract?.input_schema,
4360
- outputSchema: t.outputSchema ?? t.output_schema ?? t.annotations?.contract?.output_schema,
4361
- annotations: t.annotations
4656
+ name: typeof t.name === "string" ? t.name : "",
4657
+ description: String(t.description ?? "").slice(0, 120),
4658
+ category: typeof t.annotations?.category === "string" ? t.annotations.category : inferMcpToolCategory(t.name),
4659
+ costCredits: typeof t.annotations?.cost_credits === "number" ? t.annotations.cost_credits : void 0,
4660
+ contractVersion: typeof (t.annotations?.contract_version ?? t.annotations?.contract?.contract_version) === "string" ? t.annotations?.contract_version ?? t.annotations?.contract?.contract_version : void 0,
4661
+ permissionLevel: typeof (t.annotations?.permission_level ?? t.annotations?.contract?.permission_level) === "string" ? t.annotations?.permission_level ?? t.annotations?.contract?.permission_level : void 0,
4662
+ authScopes: asStringArray(t.annotations?.auth_scopes ?? t.annotations?.contract?.auth_scopes),
4663
+ 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,
4664
+ 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,
4665
+ retryable: typeof (t.annotations?.retryable ?? t.annotations?.contract?.retryable) === "boolean" ? t.annotations?.retryable ?? t.annotations?.contract?.retryable : void 0,
4666
+ 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,
4667
+ observability: asRecord3(t.annotations?.observability ?? t.annotations?.contract?.observability),
4668
+ inputSchema: asObjectSchema(t.inputSchema ?? t.input_schema ?? t.annotations?.contract?.input_schema),
4669
+ outputSchema: asObjectSchema(t.outputSchema ?? t.output_schema ?? t.annotations?.contract?.output_schema),
4670
+ annotations: asRecord3(t.annotations)
4362
4671
  }));
4363
4672
  }
4364
4673
  /** Discover tools by natural language query */