@sellable/mcp 0.1.557 → 0.1.558

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 (63) hide show
  1. package/README.md +2 -13
  2. package/agents/registry.json +2 -2
  3. package/dist/api.js +6 -3
  4. package/dist/auth.d.ts +6 -0
  5. package/dist/auth.js +44 -2
  6. package/dist/refill-contract.d.ts +157 -0
  7. package/dist/refill-contract.js +487 -0
  8. package/dist/refill-run-client.d.ts +10 -0
  9. package/dist/refill-run-client.js +22 -0
  10. package/dist/refill-run-loop.d.ts +14 -2
  11. package/dist/refill-run-loop.js +160 -15
  12. package/dist/server.js +0 -23
  13. package/dist/tools/auth.d.ts +5 -0
  14. package/dist/tools/auth.js +49 -12
  15. package/dist/tools/campaign-message-preparation.d.ts +62 -0
  16. package/dist/tools/campaign-message-preparation.js +41 -0
  17. package/dist/tools/campaigns.js +2 -2
  18. package/dist/tools/csv-dnc.js +2 -2
  19. package/dist/tools/evergreen-refill-plan.d.ts +3 -0
  20. package/dist/tools/evergreen-refill-plan.js +29 -7
  21. package/dist/tools/leads.d.ts +32 -317
  22. package/dist/tools/leads.js +10 -171
  23. package/dist/tools/model-quality.js +6 -4
  24. package/dist/tools/prompts.d.ts +3 -3
  25. package/dist/tools/prompts.js +15 -7
  26. package/dist/tools/provider-preflight.d.ts +2 -65
  27. package/dist/tools/provider-preflight.js +10 -97
  28. package/dist/tools/readiness.d.ts +5 -89
  29. package/dist/tools/readiness.js +0 -66
  30. package/dist/tools/refill-executors.d.ts +38 -0
  31. package/dist/tools/refill-executors.js +222 -3
  32. package/dist/tools/refill-sends-v2.d.ts +118 -1
  33. package/dist/tools/refill-sends-v2.js +312 -3
  34. package/dist/tools/refill-sends.d.ts +678 -32
  35. package/dist/tools/refill-sends.js +274 -13
  36. package/dist/tools/refill-target-plan.js +486 -14
  37. package/dist/tools/registry.d.ts +115 -330
  38. package/dist/tools/registry.js +1 -7
  39. package/dist/tools/scheduler-fill-capacity.js +1 -1
  40. package/dist/tools/scheduler-run.d.ts +71 -0
  41. package/dist/tools/scheduler-run.js +203 -1
  42. package/dist/tools/setup-evergreen-campaigns.js +1 -1
  43. package/dist/tools/workspace-context.d.ts +1 -1
  44. package/dist/tools/workspace-context.js +8 -3
  45. package/dist/tools/workspace-export.js +2 -2
  46. package/dist/tools/workspaces.d.ts +48 -2
  47. package/dist/tools/workspaces.js +48 -5
  48. package/package.json +1 -1
  49. package/skills/create-campaign/SKILL.md +3 -3
  50. package/skills/create-campaign-v2/SKILL.md +1 -1
  51. package/skills/create-evergreen-campaigns/SKILL.md +16 -16
  52. package/skills/find-leads/SKILL.md +630 -48
  53. package/skills/refill-sends/SKILL.md +91 -353
  54. package/skills/refill-sends-v2/SKILL.md +6 -6
  55. package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
  56. package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
  57. package/skills/refill-sends-workflow/SKILL.md +100 -743
  58. package/skills/refill-sends-workflow/core/contract.v2.json +543 -0
  59. package/skills/refill-sends-workflow/core/flow.v1.json +185 -1
  60. package/dist/tools/find-leads-runs.d.ts +0 -151
  61. package/dist/tools/find-leads-runs.js +0 -98
  62. package/skills/find-leads-v2/SKILL.md +0 -70
  63. package/skills/find-leads-v2/core/flow.v1.json +0 -31
@@ -1,84 +1,10 @@
1
- import { getApi } from "../api.js";
2
- import { getConfig } from "../auth.js";
3
- export const FIND_LEADS_WORKFLOW_VERSION = "find-leads-v1";
4
- function diagnostic(code, message, nextAction) {
5
- return { ok: false, code, message, nextAction, resumable: true };
6
- }
7
- export async function preflightFindLeadsProvider(input) {
8
- if (input.workflowVersion !== FIND_LEADS_WORKFLOW_VERSION) {
9
- return diagnostic("find_leads_mcp_runtime_outdated", `Find Leads requires ${FIND_LEADS_WORKFLOW_VERSION}; received ${input.workflowVersion}.`, "update the Sellable MCP/plugin, restart the MCP server, and retry Find Leads.");
10
- }
11
- let workspaceId = null;
12
- try {
13
- const config = getConfig();
14
- workspaceId = config.activeWorkspaceId || config.workspaceId || null;
15
- }
16
- catch {
17
- return diagnostic("find_leads_auth_required", "Sellable authentication is required before Find Leads can start.", "Run the Sellable first-run login flow, then retry bootstrap_find_leads.");
18
- }
19
- if (!workspaceId) {
20
- return diagnostic("find_leads_workspace_required", "Find Leads needs an active request-scoped workspace.", "Run list_workspaces, set_active_workspace, and retry.");
21
- }
22
- if (input.providerFacts && !input.providerFacts.configured) {
23
- const code = input.provider === "sales-nav"
24
- ? "find_leads_sales_nav_unavailable"
25
- : input.provider === "prospeo"
26
- ? "find_leads_prospeo_unavailable"
27
- : "find_leads_signal_capacity_unavailable";
28
- const nextAction = input.provider === "sales-nav"
29
- ? "Connect a LinkedIn account with an active Sales Navigator search session, then retry preflight."
30
- : input.provider === "prospeo"
31
- ? "Configure Prospeo and ensure enough credits are available, then retry preflight."
32
- : "Wait for Signal Discovery capacity or choose another provider, then retry preflight.";
33
- return diagnostic(code, input.providerFacts.reason || `${input.provider} is not ready`, nextAction);
34
- }
35
- if (!Number.isInteger(input.runVersion) || (input.runVersion ?? -1) < 0) {
36
- return diagnostic("find_leads_run_version_required", "A current durable run version is required to persist provider preflight.", "Call get_find_leads_run, then retry preflight with the returned version.");
37
- }
38
- const receipt = {
39
- workflowVersion: FIND_LEADS_WORKFLOW_VERSION,
40
- promptHash: input.promptHash || `builtin:${FIND_LEADS_WORKFLOW_VERSION}:${input.provider}`,
41
- provider: input.provider,
42
- checkedAt: new Date().toISOString(),
43
- };
44
- const response = await getApi().patch(`/api/v3/find-leads/runs/${encodeURIComponent(input.runId)}`, {
45
- action: "record_receipt",
46
- version: input.runVersion,
47
- kind: "provider_prompt",
48
- provider: input.provider.replace(/-/g, "_"),
49
- receipt,
50
- }, { workspaceId });
51
- markProviderPromptLoaded({
52
- provider: input.provider,
53
- findLeadsRunId: input.runId,
54
- });
55
- return { ok: true, provider: input.provider, receipt, run: response };
56
- }
57
- export const findLeadsProviderPreflightToolDefinitions = [
58
- {
59
- name: "preflight_find_leads_provider",
60
- description: "Persist the selected provider prompt/version receipt and return actionable setup diagnostics before any provider call.",
61
- inputSchema: {
62
- type: "object",
63
- properties: {
64
- runId: { type: "string" },
65
- runVersion: { type: "number" },
66
- provider: { type: "string", enum: ["sales-nav", "prospeo", "signal-discovery"] },
67
- workflowVersion: { type: "string" },
68
- promptHash: { type: "string" },
69
- },
70
- required: ["runId", "runVersion", "provider", "workflowVersion"],
71
- additionalProperties: false,
72
- },
73
- },
74
- ];
75
1
  const providerPromptLoadedState = new Map();
76
- function scopedKey(provider, campaignOfferId, findLeadsRunId) {
77
- return `${campaignOfferId ? `campaign:${campaignOfferId}` : findLeadsRunId ? `run:${findLeadsRunId}` : "provider:*"}::${provider}`;
2
+ function scopedKey(provider, campaignOfferId) {
3
+ return `${campaignOfferId ?? "*"}::${provider}`;
78
4
  }
79
- function resolveLoadedState(provider, campaignOfferId, findLeadsRunId) {
80
- if (campaignOfferId || findLeadsRunId) {
81
- return (providerPromptLoadedState.get(scopedKey(provider, campaignOfferId, findLeadsRunId)) ??
5
+ function resolveLoadedState(provider, campaignOfferId) {
6
+ if (campaignOfferId) {
7
+ return (providerPromptLoadedState.get(scopedKey(provider, campaignOfferId)) ??
82
8
  null);
83
9
  }
84
10
  const providerScoped = providerPromptLoadedState.get(scopedKey(provider));
@@ -88,45 +14,32 @@ export function markProviderPromptLoaded(params) {
88
14
  const entry = {
89
15
  provider: params.provider,
90
16
  campaignOfferId: params.campaignOfferId ?? null,
91
- findLeadsRunId: params.findLeadsRunId ?? null,
92
17
  loadedAt: new Date().toISOString(),
93
18
  };
94
- providerPromptLoadedState.set(scopedKey(params.provider, params.campaignOfferId, params.findLeadsRunId), entry);
19
+ providerPromptLoadedState.set(scopedKey(params.provider, params.campaignOfferId), entry);
95
20
  return {
96
21
  ...entry,
97
- scope: entry.campaignOfferId
98
- ? "campaign"
99
- : entry.findLeadsRunId
100
- ? "find-leads-run"
101
- : "provider",
22
+ scope: entry.campaignOfferId ? "campaign" : "provider",
102
23
  };
103
24
  }
104
25
  export function assertProviderPromptLoaded(params) {
105
- const loadedState = resolveLoadedState(params.provider, params.campaignOfferId, params.findLeadsRunId);
26
+ const loadedState = resolveLoadedState(params.provider, params.campaignOfferId);
106
27
  if (loadedState) {
107
28
  return {
108
29
  ok: true,
109
30
  provider: params.provider,
110
31
  campaignOfferId: params.campaignOfferId ?? null,
111
- findLeadsRunId: params.findLeadsRunId ?? null,
112
32
  loadedAt: loadedState.loadedAt,
113
- scope: loadedState.campaignOfferId
114
- ? "campaign"
115
- : loadedState.findLeadsRunId
116
- ? "find-leads-run"
117
- : "provider",
33
+ scope: loadedState.campaignOfferId ? "campaign" : "provider",
118
34
  };
119
35
  }
120
36
  const scopeText = params.campaignOfferId
121
37
  ? `campaign ${params.campaignOfferId}`
122
- : params.findLeadsRunId
123
- ? `Find Leads run ${params.findLeadsRunId}`
124
- : "this provider session";
38
+ : "this run";
125
39
  const blockingMessage = `Provider prompt preflight missing for ${params.provider} (${scopeText}).`;
126
40
  const diagnostics = {
127
41
  provider: params.provider,
128
42
  campaignOfferId: params.campaignOfferId ?? null,
129
- findLeadsRunId: params.findLeadsRunId ?? null,
130
43
  safeToProceed: false,
131
44
  blockingErrors: [
132
45
  `${blockingMessage} Call get_provider_prompt({ provider: "${params.provider}"${params.campaignOfferId
@@ -8,7 +8,6 @@ type WaitForCampaignTableReadyInput = {
8
8
  type WaitForLeadListReadyInput = {
9
9
  leadListId?: string;
10
10
  campaignOfferId?: string;
11
- findLeadsRunId?: string;
12
11
  workspaceId?: string;
13
12
  provider?: "apollo" | "sales-nav" | "prospeo" | "signal-discovery" | "csv-linkedin";
14
13
  jobId?: string;
@@ -53,7 +52,6 @@ export declare const readinessToolDefinitions: ({
53
52
  };
54
53
  leadListId?: undefined;
55
54
  campaignOfferId?: undefined;
56
- findLeadsRunId?: undefined;
57
55
  workspaceId?: undefined;
58
56
  provider?: undefined;
59
57
  jobId?: undefined;
@@ -77,10 +75,6 @@ export declare const readinessToolDefinitions: ({
77
75
  type: string;
78
76
  description: string;
79
77
  };
80
- findLeadsRunId: {
81
- type: string;
82
- description: string;
83
- };
84
78
  workspaceId: {
85
79
  type: string;
86
80
  description: string;
@@ -284,76 +278,18 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
284
278
  warning: string | undefined;
285
279
  }>;
286
280
  export declare function waitForLeadListReady(input: WaitForLeadListReadyInput): Promise<{
287
- ready: boolean;
288
- reason: string;
289
- runId: string;
290
- leadListId: string;
291
- attempts: number;
292
- elapsedMs: number;
293
- provider?: undefined;
294
- jobId?: undefined;
295
- status?: undefined;
296
- rowCount?: undefined;
297
- counts?: undefined;
298
- retryable?: undefined;
299
- warning?: undefined;
300
- targetLeadCount?: undefined;
301
- error?: undefined;
302
- sourceShortfall?: undefined;
303
- materializing?: undefined;
304
- } | {
305
- ready: boolean;
306
- reason: string | undefined;
307
- runId: any;
308
- leadListId: any;
309
- provider: string | null;
310
- jobId: any;
311
- status: any;
312
- rowCount: number;
313
- counts: any;
314
- retryable: any;
315
- attempts: number;
316
- elapsedMs: number;
317
- warning?: undefined;
318
- targetLeadCount?: undefined;
319
- error?: undefined;
320
- sourceShortfall?: undefined;
321
- materializing?: undefined;
322
- } | {
323
- ready: boolean;
324
- reason: string;
325
- runId: string;
326
- leadListId: any;
327
- provider: string | null;
328
- jobId: any;
329
- status: any;
330
- rowCount: number;
331
- retryable: boolean;
332
- attempts: number;
333
- elapsedMs: number;
334
- warning: string | undefined;
335
- counts?: undefined;
336
- targetLeadCount?: undefined;
337
- error?: undefined;
338
- sourceShortfall?: undefined;
339
- materializing?: undefined;
340
- } | {
341
281
  ready: boolean;
342
282
  reason: string;
343
283
  attempts: number;
344
284
  elapsedMs: number;
345
285
  leadListId: null;
346
- runId?: undefined;
347
286
  provider?: undefined;
348
- jobId?: undefined;
349
- status?: undefined;
350
287
  rowCount?: undefined;
351
- counts?: undefined;
352
- retryable?: undefined;
353
- warning?: undefined;
288
+ status?: undefined;
354
289
  targetLeadCount?: undefined;
355
290
  error?: undefined;
356
291
  sourceShortfall?: undefined;
292
+ warning?: undefined;
357
293
  materializing?: undefined;
358
294
  } | {
359
295
  ready: boolean;
@@ -365,13 +301,9 @@ export declare function waitForLeadListReady(input: WaitForLeadListReadyInput):
365
301
  rowCount: number;
366
302
  status: string;
367
303
  targetLeadCount: number | undefined;
368
- runId?: undefined;
369
- jobId?: undefined;
370
- counts?: undefined;
371
- retryable?: undefined;
372
- warning?: undefined;
373
304
  error?: undefined;
374
305
  sourceShortfall?: undefined;
306
+ warning?: undefined;
375
307
  materializing?: undefined;
376
308
  } | {
377
309
  ready: boolean;
@@ -384,12 +316,8 @@ export declare function waitForLeadListReady(input: WaitForLeadListReadyInput):
384
316
  status: string | null;
385
317
  targetLeadCount: number | undefined;
386
318
  error: string;
387
- runId?: undefined;
388
- jobId?: undefined;
389
- counts?: undefined;
390
- retryable?: undefined;
391
- warning?: undefined;
392
319
  sourceShortfall?: undefined;
320
+ warning?: undefined;
393
321
  materializing?: undefined;
394
322
  } | {
395
323
  ready: boolean;
@@ -402,12 +330,8 @@ export declare function waitForLeadListReady(input: WaitForLeadListReadyInput):
402
330
  status: string;
403
331
  targetLeadCount: number | undefined;
404
332
  error: string | null;
405
- runId?: undefined;
406
- jobId?: undefined;
407
- counts?: undefined;
408
- retryable?: undefined;
409
- warning?: undefined;
410
333
  sourceShortfall?: undefined;
334
+ warning?: undefined;
411
335
  materializing?: undefined;
412
336
  } | {
413
337
  ready: boolean;
@@ -421,10 +345,6 @@ export declare function waitForLeadListReady(input: WaitForLeadListReadyInput):
421
345
  sourceShortfall: boolean;
422
346
  warning: string | undefined;
423
347
  reason?: undefined;
424
- runId?: undefined;
425
- jobId?: undefined;
426
- counts?: undefined;
427
- retryable?: undefined;
428
348
  error?: undefined;
429
349
  materializing?: undefined;
430
350
  } | {
@@ -440,10 +360,6 @@ export declare function waitForLeadListReady(input: WaitForLeadListReadyInput):
440
360
  materializing: boolean | undefined;
441
361
  warning: string | undefined;
442
362
  error: string | undefined;
443
- runId?: undefined;
444
- jobId?: undefined;
445
- counts?: undefined;
446
- retryable?: undefined;
447
363
  sourceShortfall?: undefined;
448
364
  }>;
449
365
  export {};
@@ -109,10 +109,6 @@ export const readinessToolDefinitions = [
109
109
  type: "string",
110
110
  description: "Campaign offer ID (used to resolve selectedLeadListId if leadListId is missing).",
111
111
  },
112
- findLeadsRunId: {
113
- type: "string",
114
- description: "Durable campaignless run/list ID. When present, poll the authoritative run snapshot instead of campaign/table config.",
115
- },
116
112
  workspaceId: {
117
113
  type: "string",
118
114
  description: "Explicit request-scoped workspace id for scheduled/yolo refill automation.",
@@ -208,68 +204,6 @@ export async function waitForLeadListReady(input) {
208
204
  const intervalMs = Math.max(500, input.intervalMs ?? DEFAULT_INTERVAL_MS);
209
205
  const requireRows = input.requireRows !== false;
210
206
  const requireComplete = input.requireComplete !== false;
211
- if (input.findLeadsRunId) {
212
- if (input.campaignOfferId || (input.leadListId && input.leadListId !== input.findLeadsRunId)) {
213
- return {
214
- ready: false,
215
- reason: "find_leads_target_mismatch",
216
- runId: input.findLeadsRunId,
217
- leadListId: input.leadListId ?? input.findLeadsRunId,
218
- attempts: 0,
219
- elapsedMs: 0,
220
- };
221
- }
222
- const startedAt = Date.now();
223
- let attempts = 0;
224
- let snapshot = null;
225
- while (Date.now() - startedAt <= effectiveTimeoutMs) {
226
- attempts += 1;
227
- snapshot = await apiGet(`/api/v3/find-leads/runs/${encodeURIComponent(input.findLeadsRunId)}`);
228
- const status = String(snapshot.status ?? "").toLowerCase();
229
- const terminal = snapshot.terminal === true ||
230
- ["ready", "completed", "empty", "failed", "cancelled"].includes(status);
231
- if (terminal) {
232
- const rowCount = Number(snapshot.counts?.rows ?? snapshot.rowCount ?? snapshot.counts?.materialized ?? 0);
233
- const failed = status === "failed";
234
- const cancelled = status === "cancelled" || snapshot.cancelled === true;
235
- return {
236
- ready: !failed && !cancelled,
237
- reason: failed ? "import_failed" : cancelled ? "cancelled" : undefined,
238
- runId: snapshot.runId ?? input.findLeadsRunId,
239
- leadListId: snapshot.leadListId ?? input.findLeadsRunId,
240
- provider: String(snapshot.provider ?? "").replaceAll("_", "-") || null,
241
- jobId: snapshot.importJobId ?? null,
242
- status: snapshot.status,
243
- rowCount,
244
- counts: snapshot.counts ?? { rows: rowCount },
245
- retryable: snapshot.retryable ?? false,
246
- attempts,
247
- elapsedMs: Date.now() - startedAt,
248
- };
249
- }
250
- if (Date.now() - startedAt >= effectiveTimeoutMs)
251
- break;
252
- await sleep(intervalMs);
253
- }
254
- return {
255
- ready: false,
256
- reason: guardApplied ? "tool_timeout_guard" : "timeout",
257
- runId: input.findLeadsRunId,
258
- leadListId: snapshot?.leadListId ?? input.findLeadsRunId,
259
- provider: snapshot?.provider
260
- ? String(snapshot.provider).replaceAll("_", "-")
261
- : null,
262
- jobId: snapshot?.importJobId ?? null,
263
- status: snapshot?.status,
264
- rowCount: Number(snapshot?.counts?.rows ?? snapshot?.rowCount ?? 0),
265
- retryable: true,
266
- attempts,
267
- elapsedMs: Date.now() - startedAt,
268
- warning: guardApplied
269
- ? `Stopped after ${effectiveTimeoutMs}ms to avoid host tool timeout (requested ${requestedTimeoutMs}ms). Re-run wait_for_lead_list_ready with the same findLeadsRunId.`
270
- : undefined,
271
- };
272
- }
273
207
  let leadListId = input.leadListId;
274
208
  let provider = input.provider;
275
209
  let targetLeadCount = input.targetLeadCount;
@@ -1,4 +1,5 @@
1
1
  import { searchSignals } from "./leads.js";
2
+ import { type SchedulerExpectedTargetInput } from "./scheduler-run.js";
2
3
  export type RefillSendsApprovalMode = "approve" | "mark_ready";
3
4
  export type PaidInmailRefreshAction = {
4
5
  senderId: string;
@@ -134,6 +135,43 @@ export declare function sleep(ms: number): Promise<unknown>;
134
135
  export declare function recordValue(value: unknown): Record<string, unknown> | null;
135
136
  export declare function stringValue(value: unknown): string | null;
136
137
  export declare function numberValue(value: unknown): number | null;
138
+ export type SchedulerChangedCount = {
139
+ campaignId: string;
140
+ tableId: string;
141
+ actionType: string;
142
+ count: number;
143
+ };
144
+ export type SchedulerChangedCounts = {
145
+ complete: true;
146
+ truncated: false;
147
+ total: number;
148
+ byCampaignTableActionType: SchedulerChangedCount[];
149
+ byCampaignTableActionTypeSender: Array<SchedulerChangedCount & {
150
+ senderId: string;
151
+ }>;
152
+ };
153
+ export declare function normalizeSchedulerChangedCounts(value: unknown): SchedulerChangedCounts | null;
154
+ export declare function normalizeSchedulerPrimitiveResult(value: unknown, expected?: {
155
+ expectedTargets: SchedulerExpectedTargetInput[];
156
+ expectedTargetsHash: string;
157
+ maxPlacements: number;
158
+ }): {
159
+ status: "scheduler_receipt_incomplete";
160
+ schedulerStatus: string;
161
+ receipt: {} | null;
162
+ retryAfterMs: number | null;
163
+ changedCounts: null;
164
+ auditComplete: false;
165
+ blocker: "scheduler_receipt_incomplete";
166
+ } | {
167
+ status: string;
168
+ receipt: {} | null;
169
+ retryAfterMs: number | null;
170
+ changedCounts: SchedulerChangedCounts;
171
+ auditComplete: true;
172
+ schedulerStatus?: undefined;
173
+ blocker?: undefined;
174
+ };
137
175
  export declare function stringArray(value: unknown): string[];
138
176
  export declare function prepareRowSelectorValue(value: unknown): PrepareRowSelector | undefined;
139
177
  export declare function uniqueStrings(values: Array<string | null | undefined>): string[];