@sellable/mcp 0.1.556 → 0.1.557

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 +13 -2
  2. package/agents/registry.json +2 -2
  3. package/dist/api.js +3 -6
  4. package/dist/auth.d.ts +0 -6
  5. package/dist/auth.js +2 -44
  6. package/dist/refill-run-client.d.ts +0 -5
  7. package/dist/refill-run-client.js +0 -15
  8. package/dist/refill-run-loop.d.ts +1 -12
  9. package/dist/refill-run-loop.js +13 -158
  10. package/dist/server.js +23 -0
  11. package/dist/tools/auth.d.ts +0 -5
  12. package/dist/tools/auth.js +12 -49
  13. package/dist/tools/campaign-message-preparation.d.ts +0 -62
  14. package/dist/tools/campaign-message-preparation.js +0 -41
  15. package/dist/tools/campaigns.js +2 -2
  16. package/dist/tools/csv-dnc.js +2 -2
  17. package/dist/tools/evergreen-refill-plan.d.ts +0 -3
  18. package/dist/tools/evergreen-refill-plan.js +7 -29
  19. package/dist/tools/find-leads-runs.d.ts +151 -0
  20. package/dist/tools/find-leads-runs.js +98 -0
  21. package/dist/tools/leads.d.ts +317 -32
  22. package/dist/tools/leads.js +171 -10
  23. package/dist/tools/model-quality.js +4 -6
  24. package/dist/tools/prompts.d.ts +3 -3
  25. package/dist/tools/prompts.js +7 -15
  26. package/dist/tools/provider-preflight.d.ts +65 -2
  27. package/dist/tools/provider-preflight.js +97 -10
  28. package/dist/tools/readiness.d.ts +89 -5
  29. package/dist/tools/readiness.js +66 -0
  30. package/dist/tools/refill-executors.d.ts +0 -38
  31. package/dist/tools/refill-executors.js +3 -222
  32. package/dist/tools/refill-sends-v2.d.ts +1 -118
  33. package/dist/tools/refill-sends-v2.js +2 -310
  34. package/dist/tools/refill-sends.d.ts +32 -678
  35. package/dist/tools/refill-sends.js +13 -274
  36. package/dist/tools/refill-target-plan.js +14 -486
  37. package/dist/tools/registry.d.ts +330 -115
  38. package/dist/tools/registry.js +7 -1
  39. package/dist/tools/scheduler-fill-capacity.js +1 -1
  40. package/dist/tools/scheduler-run.d.ts +0 -71
  41. package/dist/tools/scheduler-run.js +1 -203
  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 +3 -8
  45. package/dist/tools/workspace-export.js +2 -2
  46. package/dist/tools/workspaces.d.ts +2 -48
  47. package/dist/tools/workspaces.js +5 -48
  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 +48 -630
  53. package/skills/find-leads-v2/SKILL.md +70 -0
  54. package/skills/find-leads-v2/core/flow.v1.json +31 -0
  55. package/skills/refill-sends/SKILL.md +353 -91
  56. package/skills/refill-sends-v2/SKILL.md +6 -6
  57. package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
  58. package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
  59. package/skills/refill-sends-workflow/SKILL.md +743 -100
  60. package/skills/refill-sends-workflow/core/flow.v1.json +1 -185
  61. package/dist/refill-contract.d.ts +0 -157
  62. package/dist/refill-contract.js +0 -487
  63. package/skills/refill-sends-workflow/core/contract.v2.json +0 -543
@@ -1,34 +1,11 @@
1
- import { createHash } from "node:crypto";
2
- import { REFILL_CONTRACT_CACHE_VERSION, REFILL_CONTRACT_HASH, REFILL_CONTRACT_VERSION, renderRefillSafetyGuidance, } from "../refill-contract.js";
3
1
  import { appendIndexLine, appendJournalEvent, createRunJournal, renderBootstrapSection, renderCrashedAbandonedSection, renderExecutionEventSection, renderPlanSection, renderTerminalSection, } from "../refill-journal.js";
4
2
  import { writeRefillWorkspaceState } from "../refill-local-state.js";
5
3
  import { advanceRefillRunGateRemote, completeRefillRun, heartbeatRefillRun, recordRunOutcome, recordRunPlanned, refillRunStatus, startRefillRunRemote, } from "../refill-run-client.js";
6
4
  import { runRefillV2Loop } from "../refill-run-loop.js";
7
- import { getPrepareCampaignMessagesStatus, stopSatisfiedPrepareCampaignMessages, } from "./campaign-message-preparation.js";
5
+ import { getPrepareCampaignMessagesStatus } from "./campaign-message-preparation.js";
8
6
  import { getRefillPlanV2 } from "./evergreen-refill-plan.js";
9
7
  import { executeOneYoloPrimitive, executeStartCampaignPrimitive, prepareRowSelectorValue, refillPrepareRequestHash, refreshPaidInmailCreditsWithRetry, } from "./refill-executors.js";
10
8
  import { runSchedulerSweep } from "./scheduler-run.js";
11
- function installedIdentityEnv(env, name, fallback) {
12
- const value = env[name]?.trim();
13
- return value || fallback;
14
- }
15
- export function resolveRefillV2InstalledIdentity(env = process.env) {
16
- const mcpVersion = installedIdentityEnv(env, "SELLABLE_MCP_PACKAGE_VERSION", "unresolved-mcp");
17
- return {
18
- mcpVersion,
19
- installVersion: installedIdentityEnv(env, "SELLABLE_INSTALL_PACKAGE_VERSION", "unresolved-install"),
20
- pluginVersion: installedIdentityEnv(env, "SELLABLE_CODEX_PLUGIN_VERSION", "unresolved-plugin"),
21
- cacheIdentity: installedIdentityEnv(env, "SELLABLE_PLUGIN_CACHE_IDENTITY", `mcp-package:${mcpVersion}`),
22
- };
23
- }
24
- export const REFILL_V2_RUNTIME_IDENTITY = {
25
- contract: {
26
- version: REFILL_CONTRACT_VERSION,
27
- hash: REFILL_CONTRACT_HASH,
28
- cacheKey: REFILL_CONTRACT_CACHE_VERSION,
29
- },
30
- installed: resolveRefillV2InstalledIdentity(),
31
- };
32
9
  const FORBIDDEN_ACTIONS = [
33
10
  "Do not schedule sends.",
34
11
  "Do not send messages.",
@@ -41,11 +18,7 @@ const BOUNDED_AUTHORITY = "Within the refill run, bounded approvals, preparation
41
18
  export const refillSendsV2ToolDefinitions = [
42
19
  {
43
20
  name: "refill_sends_v2",
44
- description: [
45
- "Execute the server-internal refill loop behind public refill_sends; it is retained for dispatch compatibility but is not advertised.",
46
- `contractHash=${REFILL_CONTRACT_HASH}`,
47
- renderRefillSafetyGuidance(),
48
- ].join(" "),
21
+ description: "Execute the refill sends v2 loop with run-record fencing, packet re-planning, shared refill executors, and resumable dry-run/real-run modes.",
49
22
  inputSchema: {
50
23
  type: "object",
51
24
  properties: {
@@ -78,18 +51,6 @@ export const refillSendsV2ToolDefinitions = [
78
51
  type: "string",
79
52
  enum: ["auto", "evergreen", "plain", "active"],
80
53
  },
81
- targetDate: {
82
- type: "string",
83
- description: "Exact sender-local YYYY-MM-DD date.",
84
- },
85
- untilDate: {
86
- type: "string",
87
- description: "Inclusive sender-local YYYY-MM-DD through-date.",
88
- },
89
- horizonSendDays: {
90
- type: "number",
91
- description: "Positive sender-local send-day horizon.",
92
- },
93
54
  },
94
55
  required: ["workspaceId"],
95
56
  additionalProperties: false,
@@ -107,234 +68,6 @@ function resumeHandle(input) {
107
68
  ? { runId: input.runId, fence: input.fence }
108
69
  : undefined;
109
70
  }
110
- function validDate(value, field) {
111
- const trimmed = value.trim();
112
- if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed) ||
113
- new Date(`${trimmed}T00:00:00.000Z`).toISOString().slice(0, 10) !== trimmed) {
114
- throw new Error(`${field} must be a valid YYYY-MM-DD date.`);
115
- }
116
- return trimmed;
117
- }
118
- function normalizeDateSelector(input) {
119
- const selected = [
120
- input.targetDate !== undefined,
121
- input.untilDate !== undefined,
122
- input.horizonSendDays !== undefined,
123
- ].filter(Boolean).length;
124
- if (selected > 1) {
125
- throw new Error("Provide exactly one refill date selector.");
126
- }
127
- if (input.targetDate !== undefined) {
128
- const targetDate = validDate(input.targetDate, "targetDate");
129
- return {
130
- dateSelector: { kind: "target_date", targetDate },
131
- targetDate,
132
- };
133
- }
134
- if (input.untilDate !== undefined) {
135
- const untilDate = validDate(input.untilDate, "untilDate");
136
- return {
137
- dateSelector: { kind: "until_date", untilDate },
138
- untilDate,
139
- };
140
- }
141
- if (input.horizonSendDays !== undefined) {
142
- if (!Number.isInteger(input.horizonSendDays) ||
143
- input.horizonSendDays <= 0) {
144
- throw new Error("horizonSendDays must be a positive integer.");
145
- }
146
- return {
147
- dateSelector: {
148
- kind: "horizon_send_days",
149
- horizonSendDays: input.horizonSendDays,
150
- },
151
- horizonSendDays: input.horizonSendDays,
152
- };
153
- }
154
- return { dateSelector: { kind: "scheduler_default" } };
155
- }
156
- function record(value) {
157
- return value && typeof value === "object" && !Array.isArray(value)
158
- ? value
159
- : null;
160
- }
161
- function text(value) {
162
- return typeof value === "string" && value.trim() ? value.trim() : null;
163
- }
164
- function list(value) {
165
- return Array.isArray(value) ? value : [];
166
- }
167
- function sortedUnique(values) {
168
- return [
169
- ...new Set(values.filter((value) => Boolean(value))),
170
- ].sort((left, right) => left.localeCompare(right));
171
- }
172
- function sha256(value) {
173
- return createHash("sha256").update(JSON.stringify(value)).digest("hex");
174
- }
175
- function targetPlanParts(targetPlan) {
176
- const target = record(targetPlan.target) ?? {};
177
- const plans = list(target.senderRefillPlans)
178
- .map(record)
179
- .filter((value) => value != null);
180
- const actions = list(target.globalActionQueue)
181
- .map(record)
182
- .filter((value) => value != null);
183
- return { target, plans, actions };
184
- }
185
- function stableIdsFromTargetPlan(targetPlan, input) {
186
- const { plans, actions } = targetPlanParts(targetPlan);
187
- const actionRecords = actions.map((action) => ({
188
- action,
189
- ids: record(action.ids) ?? {},
190
- toolInput: record(action.toolInput) ?? {},
191
- }));
192
- const senderIds = sortedUnique([
193
- ...(input.senderIds ?? []),
194
- ...plans.map((plan) => text(plan.senderId)),
195
- ...actionRecords.map(({ ids, toolInput }) => text(ids.senderId) ?? text(toolInput.senderId)),
196
- ]);
197
- const campaignIds = sortedUnique(actionRecords.map(({ ids, toolInput }) => text(ids.campaignId) ?? text(toolInput.campaignId)));
198
- const tableIds = sortedUnique(actionRecords.map(({ ids, toolInput }) => text(ids.tableId) ?? text(toolInput.tableId)));
199
- const actionIds = sortedUnique(actionRecords.map(({ action }) => text(action.actionKey) ?? text(action.type)));
200
- const senderTimezones = Object.fromEntries(plans
201
- .flatMap((plan) => list(plan.selectedDays))
202
- .map(record)
203
- .filter((day) => day != null)
204
- .map((day) => [
205
- text(day.senderId),
206
- text(day.senderTimeZone) ?? text(day.timeZone),
207
- ])
208
- .filter((entry) => entry[0] != null && entry[1] != null)
209
- .sort(([left], [right]) => left.localeCompare(right)));
210
- return {
211
- senderIds,
212
- campaignIds,
213
- tableIds,
214
- actionIds,
215
- senderTimezones,
216
- actions: actionRecords,
217
- };
218
- }
219
- function buildApprovalEnvelope(input) {
220
- const workspaceId = normalizeWorkspaceId(input.workspaceId);
221
- const date = normalizeDateSelector(input);
222
- const stable = stableIdsFromTargetPlan(input.targetPlan, input);
223
- const schedulerAction = stable.actions.find(({ action }) => action.type === "run_scheduler_sweep");
224
- const schedulerInput = schedulerAction?.toolInput ?? {};
225
- const expectedTargets = list(schedulerInput.expectedTargets);
226
- const expectedTargetsHash = text(schedulerInput.expectedTargetsHash) ?? sha256(expectedTargets);
227
- const maxPlacements = typeof schedulerInput.maxPlacements === "number" &&
228
- Number.isInteger(schedulerInput.maxPlacements) &&
229
- schedulerInput.maxPlacements > 0
230
- ? schedulerInput.maxPlacements
231
- : 150;
232
- const scope = {
233
- version: 2,
234
- workspaceId,
235
- intent: input.intent ?? "auto",
236
- senderIds: stable.senderIds,
237
- campaignIds: stable.campaignIds,
238
- tableIds: stable.tableIds,
239
- actionIds: stable.actionIds,
240
- approvalMode: input.approvalMode ?? "approve",
241
- dateSelector: date.dateSelector,
242
- senderTimezones: stable.senderTimezones,
243
- expectedTargetsHash,
244
- maxPlacements,
245
- contract: { ...REFILL_V2_RUNTIME_IDENTITY.contract },
246
- installed: { ...REFILL_V2_RUNTIME_IDENTITY.installed },
247
- };
248
- const scopeHash = sha256(scope);
249
- const targetShapeRevision = text(input.targetPlan.targetShapeRevision) ??
250
- text(record(input.targetPlan.target)?.targetShapeRevision) ??
251
- "missing_target_shape_revision";
252
- const actionFingerprint = text(stable.actions[0]?.action.actionKey) ??
253
- text(stable.actions[0]?.action.type) ??
254
- "no_action";
255
- const sideEffectEnvelope = sortedUnique(stable.actions.map(({ action }) => text(action.type)));
256
- const approvalExpiresAt = input.approvalExpiresAt ??
257
- new Date((input.now ?? new Date()).getTime() + 15 * 60_000).toISOString();
258
- const fingerprintFields = {
259
- scopeHash,
260
- targetShapeRevision,
261
- actionFingerprint,
262
- expectedTargetsHash,
263
- sideEffectEnvelope,
264
- maxPlacements,
265
- approvalExpiresAt,
266
- };
267
- const approval = {
268
- status: "awaiting_approval",
269
- ...fingerprintFields,
270
- approvalFingerprint: sha256(fingerprintFields),
271
- };
272
- return { scope, scopeHash, approval, date };
273
- }
274
- export async function prepareRefillSendsV2Approval(input) {
275
- const envelope = buildApprovalEnvelope(input);
276
- const started = await startRefillRunRemote({
277
- workspaceId: envelope.scope.workspaceId,
278
- config: {
279
- scope: envelope.scope,
280
- scopeHash: envelope.scopeHash,
281
- approval: envelope.approval,
282
- },
283
- runState: {
284
- version: 1,
285
- scope: envelope.scope,
286
- scopeHash: envelope.scopeHash,
287
- approval: envelope.approval,
288
- senderCursors: [],
289
- laneCooldowns: [],
290
- passRates: [],
291
- },
292
- });
293
- const result = record(started) ?? {};
294
- const runId = text(result.runId);
295
- const fence = typeof result.fence === "number" && Number.isFinite(result.fence)
296
- ? result.fence
297
- : null;
298
- if (!runId || fence == null) {
299
- return {
300
- status: "blocked",
301
- blocker: text(result.blocker) ?? "approval_run_unavailable",
302
- response: started,
303
- };
304
- }
305
- const persistedConfig = record(result.config);
306
- const persistedScope = record(persistedConfig?.scope) ?? envelope.scope;
307
- const persistedApproval = record(persistedConfig?.approval) ??
308
- envelope.approval;
309
- return {
310
- ...persistedApproval,
311
- status: "awaiting_approval",
312
- runId,
313
- fence,
314
- scope: persistedScope,
315
- };
316
- }
317
- function validateApprovalEcho(envelope, echo, now = new Date()) {
318
- const fields = [
319
- "scopeHash",
320
- "targetShapeRevision",
321
- "actionFingerprint",
322
- "expectedTargetsHash",
323
- "approvalExpiresAt",
324
- "approvalFingerprint",
325
- ];
326
- const changed = fields.filter((field) => echo[field] !== envelope.approval[field]);
327
- if (Date.parse(envelope.approval.approvalExpiresAt) <= now.getTime()) {
328
- return { ok: false, blocker: "approval_expired", changed };
329
- }
330
- return changed.length === 0
331
- ? { ok: true }
332
- : {
333
- ok: false,
334
- blocker: "approval_fingerprint_mismatch",
335
- changed,
336
- };
337
- }
338
71
  async function maybeAddLostFenceGuidance(result, input) {
339
72
  if (result.status !== "blocked" ||
340
73
  result.blocker !== "lease_lost" ||
@@ -361,45 +94,12 @@ async function maybeAddLostFenceGuidance(result, input) {
361
94
  }
362
95
  export async function refillSendsV2Command(input) {
363
96
  const workspaceId = normalizeWorkspaceId(input.workspaceId);
364
- const date = normalizeDateSelector(input);
365
- let resolvedScope = input.scope;
366
- let resolvedScopeHash = input.scopeHash;
367
- let resolvedApproval = input.approval;
368
- if (input.targetPlan && input.approvalEcho) {
369
- const envelope = buildApprovalEnvelope({
370
- workspaceId,
371
- intent: input.intent,
372
- senderIds: input.senderIds,
373
- approvalMode: input.approvalMode,
374
- targetDate: input.targetDate,
375
- untilDate: input.untilDate,
376
- horizonSendDays: input.horizonSendDays,
377
- targetPlan: input.targetPlan,
378
- approvalExpiresAt: input.approvalEcho.approvalExpiresAt,
379
- });
380
- const validation = validateApprovalEcho(envelope, input.approvalEcho);
381
- if (!validation.ok) {
382
- return {
383
- status: "blocked",
384
- blocker: validation.blocker,
385
- guidance: "The durable refill approval no longer matches fresh scope; render and approve a new packet before mutation.",
386
- report: { changed: validation.changed, fresh: envelope.approval },
387
- readOnly: false,
388
- forbiddenActions: FORBIDDEN_ACTIONS,
389
- boundedAuthority: BOUNDED_AUTHORITY,
390
- };
391
- }
392
- resolvedScope = envelope.scope;
393
- resolvedScopeHash = envelope.scopeHash;
394
- resolvedApproval = envelope.approval;
395
- }
396
97
  if (input.dryRun) {
397
98
  const plan = await getRefillPlanV2({
398
99
  workspaceId,
399
100
  intent: input.intent,
400
101
  senderIds: input.senderIds,
401
102
  journal: true,
402
- ...date,
403
103
  });
404
104
  return {
405
105
  ...plan,
@@ -415,10 +115,6 @@ export async function refillSendsV2Command(input) {
415
115
  senderIds: input.senderIds,
416
116
  approvalMode: input.approvalMode ?? "approve",
417
117
  resume: resumeHandle(input),
418
- ...date,
419
- scope: resolvedScope,
420
- scopeHash: resolvedScopeHash,
421
- approval: resolvedApproval,
422
118
  }, {
423
119
  runClient: {
424
120
  startRefillRunRemote,
@@ -435,16 +131,12 @@ export async function refillSendsV2Command(input) {
435
131
  senderIds: planInput.senderIds,
436
132
  runState: planInput.runState,
437
133
  journal: planInput.journal,
438
- targetDate: planInput.targetDate,
439
- untilDate: planInput.untilDate,
440
- horizonSendDays: planInput.horizonSendDays,
441
134
  }),
442
135
  executors: {
443
136
  executeOneYoloPrimitive,
444
137
  executeStartCampaignPrimitive,
445
138
  refreshPaidInmailCreditsWithRetry,
446
139
  getPrepareCampaignMessagesStatus,
447
- stopSatisfiedPrepareCampaignMessages,
448
140
  refillPrepareRequestHash,
449
141
  prepareRowSelectorValue,
450
142
  },