@sellable/mcp 0.1.503 → 0.1.505

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.
@@ -10,6 +10,13 @@ const SAFE_PACKET_ACTION_TYPES = new Set([
10
10
  "approve_messages",
11
11
  "start_paused_campaign",
12
12
  "wait_for_scheduler",
13
+ "wait_for_active_work",
14
+ "wait_for_source_import",
15
+ "copy_selected_source_rows",
16
+ "continue_signal_discovery_source",
17
+ "continue_sales_nav_source",
18
+ "continue_prospeo_source",
19
+ "manual_source_replenishment",
13
20
  "refresh_paid_inmail_credits",
14
21
  "lower_paid_inmail_threshold",
15
22
  "switch_to_connection_lane",
@@ -19,6 +26,14 @@ const MANUAL_ONLY_PACKET_ACTION_TYPES = new Set([
19
26
  "lower_paid_inmail_threshold",
20
27
  "switch_to_connection_lane",
21
28
  "create_connection_campaign",
29
+ "continue_sales_nav_source",
30
+ "continue_prospeo_source",
31
+ "manual_source_replenishment",
32
+ ]);
33
+ const TERMINAL_NO_ACTION_BLOCKER_CODES = new Set([
34
+ "paid_inmail_below_threshold",
35
+ "paid_inmail_credit_missing",
36
+ "paid_inmail_credit_stale",
22
37
  ]);
23
38
  const SOURCE_PLAN_STATES = new Set([
24
39
  "not_needed",
@@ -27,6 +42,8 @@ const SOURCE_PLAN_STATES = new Set([
27
42
  "needs_signal_import",
28
43
  "waiting_for_import",
29
44
  "needs_confirm",
45
+ "needs_same_source_copy",
46
+ "needs_provider_continuation",
30
47
  "source_shortfall",
31
48
  "provider_exhausted",
32
49
  "provider_missing",
@@ -156,6 +173,16 @@ function sanitizeActionCandidate(candidate) {
156
173
  tableId: stringValue(candidate.tableId),
157
174
  tableName: stringValue(candidate.tableName) ?? null,
158
175
  columnId: stringValue(candidate.columnId) ?? null,
176
+ sourceLeadListId: stringValue(candidate.sourceLeadListId) ?? null,
177
+ leadSourceProvider: stringValue(candidate.leadSourceProvider) ?? null,
178
+ sourceFingerprint: stringValue(candidate.sourceFingerprint) ?? null,
179
+ sourceInventoryStatus: stringValue(candidate.sourceInventoryStatus) ?? null,
180
+ sourceRowIds: stringArray(candidate.sourceRowIds),
181
+ sourceRowLimit: typeof candidate.sourceRowLimit === "number"
182
+ ? candidate.sourceRowLimit
183
+ : undefined,
184
+ activeJobId: stringValue(candidate.activeJobId) ?? null,
185
+ activeImportStatus: stringValue(candidate.activeImportStatus) ?? null,
159
186
  targetRows: typeof candidate.targetRows === "number" ? candidate.targetRows : undefined,
160
187
  columnRole: stringValue(candidate.columnRole),
161
188
  rowSelector: sanitizeRowSelector(candidate.rowSelector),
@@ -190,9 +217,25 @@ function sanitizeToolInput(value) {
190
217
  return {};
191
218
  return {
192
219
  senderId: stringValue(value.senderId),
220
+ actionType: allowedActionType(value.actionType),
193
221
  campaignId: stringValue(value.campaignId),
194
222
  tableId: stringValue(value.tableId),
195
223
  columnId: stringValue(value.columnId) ?? null,
224
+ sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
225
+ leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
226
+ sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
227
+ activeJobId: stringValue(value.activeJobId) ?? null,
228
+ activeImportStatus: stringValue(value.activeImportStatus) ?? null,
229
+ sourceInventoryStatus: stringValue(value.sourceInventoryStatus) ?? null,
230
+ sourceRowIds: stringArray(value.sourceRowIds),
231
+ sourceRowLimit: typeof value.sourceRowLimit === "number"
232
+ ? value.sourceRowLimit
233
+ : undefined,
234
+ campaignOfferId: stringValue(value.campaignOfferId),
235
+ provider: stringValue(value.provider),
236
+ allowDifferentSourceLeadList: typeof value.allowDifferentSourceLeadList === "boolean"
237
+ ? value.allowDifferentSourceLeadList
238
+ : undefined,
196
239
  targetPreparedMessages: typeof value.targetPreparedMessages === "number"
197
240
  ? value.targetPreparedMessages
198
241
  : undefined,
@@ -219,6 +262,10 @@ function sanitizePacketIds(value) {
219
262
  campaignId: stringValue(value.campaignId),
220
263
  tableId: stringValue(value.tableId),
221
264
  columnId: stringValue(value.columnId) ?? null,
265
+ sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
266
+ leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
267
+ sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
268
+ activeJobId: stringValue(value.activeJobId) ?? null,
222
269
  };
223
270
  }
224
271
  function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
@@ -241,6 +288,7 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
241
288
  return {
242
289
  rank,
243
290
  type: action.type,
291
+ actionType: allowedActionType(action.actionType),
244
292
  toolName: stringValue(action.toolName) ?? null,
245
293
  sideEffectClass: stringValue(action.sideEffectClass),
246
294
  ids,
@@ -338,6 +386,9 @@ function sanitizeSourcePlan(value) {
338
386
  reason: stringValue(value.reason),
339
387
  campaignId: stringValue(value.campaignId),
340
388
  tableId: stringValue(value.tableId),
389
+ sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
390
+ leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
391
+ sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
341
392
  remainingRowsNeeded: typeof value.remainingRowsNeeded === "number"
342
393
  ? value.remainingRowsNeeded
343
394
  : undefined,
@@ -586,14 +637,16 @@ function sanitizeRefillTargetPlanResult(result) {
586
637
  const eligibleSenderLedger = sanitizeEligibleSenderLedger(target.eligibleSenderLedger, selectedBySender);
587
638
  const senderRefillPlans = sanitizeStructuredSenderPlans(target.senderRefillPlans, selectedBySender);
588
639
  const globalActionQueue = buildSanitizedGlobalActionQueue(senderRefillPlans);
589
- const status = blockers.some((blocker) => ["sender_disconnected", "sender_sales_nav_disconnected"].includes(String(blocker.code)))
590
- ? "blocked"
591
- : remainingProjectedGap === 0
592
- ? "complete"
593
- : grossTarget <= 0
594
- ? "blocked"
595
- : remainingReadyOrProjectedGap === 0
596
- ? "awaiting_scheduler_after_ready_buffer"
640
+ const hasTerminalNoActionBlocker = globalActionQueue.length === 0 &&
641
+ blockers.some((blocker) => TERMINAL_NO_ACTION_BLOCKER_CODES.has(String(blocker.code)));
642
+ const status = remainingProjectedGap === 0
643
+ ? "complete"
644
+ : grossTarget <= 0
645
+ ? "blocked"
646
+ : remainingReadyOrProjectedGap === 0
647
+ ? "awaiting_scheduler_after_ready_buffer"
648
+ : hasTerminalNoActionBlocker
649
+ ? "blocked"
597
650
  : "needs_refill";
598
651
  return {
599
652
  ...result,
@@ -584,63 +584,6 @@ export declare const allTools: ({
584
584
  required: string[];
585
585
  additionalProperties: boolean;
586
586
  };
587
- } | {
588
- name: string;
589
- description: string;
590
- inputSchema: {
591
- type: string;
592
- properties: {
593
- campaignId: {
594
- type: string;
595
- description: string;
596
- };
597
- tableId: {
598
- type: string;
599
- };
600
- targetPreparedMessages: {
601
- type: string;
602
- minimum: number;
603
- maximum: number;
604
- };
605
- maxRowsToCheck: {
606
- type: string;
607
- minimum: number;
608
- maximum: number;
609
- description: string;
610
- };
611
- batchSize: {
612
- type: string;
613
- minimum: number;
614
- maximum: number;
615
- description: string;
616
- };
617
- maxBatchRows: {
618
- type: string;
619
- minimum: number;
620
- maximum: number;
621
- description: string;
622
- };
623
- approvalMode: {
624
- type: string;
625
- enum: string[];
626
- description: string;
627
- };
628
- autoContinue: {
629
- type: string;
630
- };
631
- disableLowPassRateStop: {
632
- type: string;
633
- description: string;
634
- };
635
- workspaceId: {
636
- type: string;
637
- description: string;
638
- };
639
- jobId?: undefined;
640
- };
641
- required: string[];
642
- additionalProperties: boolean;
643
- };
644
587
  } | {
645
588
  name: string;
646
589
  description: string;
@@ -666,7 +609,10 @@ export declare const allTools: ({
666
609
  batchSize?: undefined;
667
610
  maxBatchRows?: undefined;
668
611
  approvalMode?: undefined;
612
+ rowSelector?: undefined;
669
613
  autoContinue?: undefined;
614
+ senderId?: undefined;
615
+ actionType?: undefined;
670
616
  disableLowPassRateStop?: undefined;
671
617
  };
672
618
  additionalProperties: boolean;
@@ -3104,6 +3050,8 @@ export declare const allTools: ({
3104
3050
  keepInSync?: undefined;
3105
3051
  jobId?: undefined;
3106
3052
  reviewBatchLimit?: undefined;
3053
+ sourceRowIds?: undefined;
3054
+ sourceRowLimit?: undefined;
3107
3055
  allowPartialSourceList?: undefined;
3108
3056
  includeRawImportResult?: undefined;
3109
3057
  selections?: undefined;
@@ -3298,6 +3246,8 @@ export declare const allTools: ({
3298
3246
  keepInSync?: undefined;
3299
3247
  jobId?: undefined;
3300
3248
  reviewBatchLimit?: undefined;
3249
+ sourceRowIds?: undefined;
3250
+ sourceRowLimit?: undefined;
3301
3251
  allowPartialSourceList?: undefined;
3302
3252
  includeRawImportResult?: undefined;
3303
3253
  selections?: undefined;
@@ -3391,6 +3341,8 @@ export declare const allTools: ({
3391
3341
  keepInSync?: undefined;
3392
3342
  jobId?: undefined;
3393
3343
  reviewBatchLimit?: undefined;
3344
+ sourceRowIds?: undefined;
3345
+ sourceRowLimit?: undefined;
3394
3346
  allowPartialSourceList?: undefined;
3395
3347
  includeRawImportResult?: undefined;
3396
3348
  selections?: undefined;
@@ -3556,6 +3508,8 @@ export declare const allTools: ({
3556
3508
  keepInSync?: undefined;
3557
3509
  jobId?: undefined;
3558
3510
  reviewBatchLimit?: undefined;
3511
+ sourceRowIds?: undefined;
3512
+ sourceRowLimit?: undefined;
3559
3513
  allowPartialSourceList?: undefined;
3560
3514
  includeRawImportResult?: undefined;
3561
3515
  selections?: undefined;
@@ -3663,6 +3617,8 @@ export declare const allTools: ({
3663
3617
  keepInSync?: undefined;
3664
3618
  jobId?: undefined;
3665
3619
  reviewBatchLimit?: undefined;
3620
+ sourceRowIds?: undefined;
3621
+ sourceRowLimit?: undefined;
3666
3622
  allowPartialSourceList?: undefined;
3667
3623
  includeRawImportResult?: undefined;
3668
3624
  selections?: undefined;
@@ -3779,6 +3735,8 @@ export declare const allTools: ({
3779
3735
  keepInSync?: undefined;
3780
3736
  jobId?: undefined;
3781
3737
  reviewBatchLimit?: undefined;
3738
+ sourceRowIds?: undefined;
3739
+ sourceRowLimit?: undefined;
3782
3740
  allowPartialSourceList?: undefined;
3783
3741
  includeRawImportResult?: undefined;
3784
3742
  selections?: undefined;
@@ -3884,6 +3842,8 @@ export declare const allTools: ({
3884
3842
  keepInSync?: undefined;
3885
3843
  jobId?: undefined;
3886
3844
  reviewBatchLimit?: undefined;
3845
+ sourceRowIds?: undefined;
3846
+ sourceRowLimit?: undefined;
3887
3847
  allowPartialSourceList?: undefined;
3888
3848
  includeRawImportResult?: undefined;
3889
3849
  selections?: undefined;
@@ -3994,6 +3954,8 @@ export declare const allTools: ({
3994
3954
  keepInSync?: undefined;
3995
3955
  jobId?: undefined;
3996
3956
  reviewBatchLimit?: undefined;
3957
+ sourceRowIds?: undefined;
3958
+ sourceRowLimit?: undefined;
3997
3959
  allowPartialSourceList?: undefined;
3998
3960
  includeRawImportResult?: undefined;
3999
3961
  selections?: undefined;
@@ -4092,6 +4054,8 @@ export declare const allTools: ({
4092
4054
  keepInSync?: undefined;
4093
4055
  jobId?: undefined;
4094
4056
  reviewBatchLimit?: undefined;
4057
+ sourceRowIds?: undefined;
4058
+ sourceRowLimit?: undefined;
4095
4059
  allowPartialSourceList?: undefined;
4096
4060
  includeRawImportResult?: undefined;
4097
4061
  selections?: undefined;
@@ -4982,6 +4946,8 @@ export declare const allTools: ({
4982
4946
  keepInSync?: undefined;
4983
4947
  jobId?: undefined;
4984
4948
  reviewBatchLimit?: undefined;
4949
+ sourceRowIds?: undefined;
4950
+ sourceRowLimit?: undefined;
4985
4951
  allowPartialSourceList?: undefined;
4986
4952
  includeRawImportResult?: undefined;
4987
4953
  selections?: undefined;
@@ -5089,6 +5055,8 @@ export declare const allTools: ({
5089
5055
  keepInSync?: undefined;
5090
5056
  jobId?: undefined;
5091
5057
  reviewBatchLimit?: undefined;
5058
+ sourceRowIds?: undefined;
5059
+ sourceRowLimit?: undefined;
5092
5060
  allowPartialSourceList?: undefined;
5093
5061
  includeRawImportResult?: undefined;
5094
5062
  selections?: undefined;
@@ -6134,6 +6102,8 @@ export declare const allTools: ({
6134
6102
  keepInSync?: undefined;
6135
6103
  jobId?: undefined;
6136
6104
  reviewBatchLimit?: undefined;
6105
+ sourceRowIds?: undefined;
6106
+ sourceRowLimit?: undefined;
6137
6107
  allowPartialSourceList?: undefined;
6138
6108
  includeRawImportResult?: undefined;
6139
6109
  selections?: undefined;
@@ -6288,6 +6258,8 @@ export declare const allTools: ({
6288
6258
  keepInSync?: undefined;
6289
6259
  jobId?: undefined;
6290
6260
  reviewBatchLimit?: undefined;
6261
+ sourceRowIds?: undefined;
6262
+ sourceRowLimit?: undefined;
6291
6263
  allowPartialSourceList?: undefined;
6292
6264
  includeRawImportResult?: undefined;
6293
6265
  selections?: undefined;
@@ -6429,6 +6401,8 @@ export declare const allTools: ({
6429
6401
  keepInSync?: undefined;
6430
6402
  jobId?: undefined;
6431
6403
  reviewBatchLimit?: undefined;
6404
+ sourceRowIds?: undefined;
6405
+ sourceRowLimit?: undefined;
6432
6406
  allowPartialSourceList?: undefined;
6433
6407
  includeRawImportResult?: undefined;
6434
6408
  selections?: undefined;
@@ -6525,6 +6499,8 @@ export declare const allTools: ({
6525
6499
  keepInSync?: undefined;
6526
6500
  jobId?: undefined;
6527
6501
  reviewBatchLimit?: undefined;
6502
+ sourceRowIds?: undefined;
6503
+ sourceRowLimit?: undefined;
6528
6504
  allowPartialSourceList?: undefined;
6529
6505
  includeRawImportResult?: undefined;
6530
6506
  selections?: undefined;
@@ -6571,6 +6547,17 @@ export declare const allTools: ({
6571
6547
  type: string;
6572
6548
  description: string;
6573
6549
  };
6550
+ sourceRowIds: {
6551
+ type: string;
6552
+ items: {
6553
+ type: string;
6554
+ };
6555
+ description: string;
6556
+ };
6557
+ sourceRowLimit: {
6558
+ type: string;
6559
+ description: string;
6560
+ };
6574
6561
  allowPartialSourceList: {
6575
6562
  type: string;
6576
6563
  description: string;
@@ -6780,6 +6767,8 @@ export declare const allTools: ({
6780
6767
  keepInSync?: undefined;
6781
6768
  jobId?: undefined;
6782
6769
  reviewBatchLimit?: undefined;
6770
+ sourceRowIds?: undefined;
6771
+ sourceRowLimit?: undefined;
6783
6772
  allowPartialSourceList?: undefined;
6784
6773
  includeRawImportResult?: undefined;
6785
6774
  };
@@ -6877,6 +6866,8 @@ export declare const allTools: ({
6877
6866
  keepInSync?: undefined;
6878
6867
  jobId?: undefined;
6879
6868
  reviewBatchLimit?: undefined;
6869
+ sourceRowIds?: undefined;
6870
+ sourceRowLimit?: undefined;
6880
6871
  allowPartialSourceList?: undefined;
6881
6872
  includeRawImportResult?: undefined;
6882
6873
  selections?: undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.503",
3
+ "version": "0.1.505",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -92,10 +92,16 @@ When the host can call typed MCP tools, start with:
92
92
  refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
93
93
  ```
94
94
 
95
- That command helper only normalizes arguments and returns the execution
96
- contract. It does not mutate. Continue with the workflow below for route
97
- selection, state rereads, approval gating, source import, preparation, and
98
- bounded approval.
95
+ That command helper normalizes arguments and returns the execution contract. In
96
+ non-yolo mode it does not mutate. In `--yolo`, it may execute exactly one safe
97
+ bounded primitive from the fresh `target.globalActionQueue[0]`, then reread and
98
+ return the new target plan; currently safe primitives are paid-credit refresh,
99
+ existing-row message preparation, same-source row copy, and read-only wait
100
+ rereads. It does not run unbounded approval, lower
101
+ paid-InMail thresholds, switch source families, create campaigns, launch, send,
102
+ or write scheduler rows. Continue with the workflow below for route selection,
103
+ state rereads, approval gating, source import, preparation, and bounded
104
+ approval.
99
105
 
100
106
  ## Workspace Contract
101
107
 
@@ -199,12 +205,20 @@ Structured planner packet:
199
205
  - `manualAlternates` are not yolo actions. Threshold lowering and campaign
200
206
  creation are manual continuations only.
201
207
 
208
+ Refill action ladder: approve generated rows only when an explicit bounded
209
+ approval gate exists, process all existing same-campaign unenriched/unprepared
210
+ rows in bounded batches before any source work, then copy bounded net-new rows
211
+ from the selected source (`selectedLeadListId`, provider, and source
212
+ fingerprint preserved), then use provider-aligned source-more. A new source or
213
+ provider switch changes the reply-rate baseline and is a manual alternate, not a
214
+ `--yolo` side effect.
215
+
202
216
  Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
203
217
  automatically maintains a `refreshedPaidInmailSenderIds` set for the current
204
218
  command call. If its first target plan has stale/missing paid-InMail credit
205
219
  facts, it refreshes each selected sender at most once, reruns
206
220
  `get_refill_target_plan`, and returns the post-refresh `targetPlan` before
207
- choosing the next prep/approval/start action. If fresh facts are still below
221
+ choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
208
222
  threshold, below-threshold paid-InMail facts fall back to an existing connection
209
223
  lane, the same Sales Nav cascade campaign's connection branch, or a manual
210
224
  continuation.
@@ -293,7 +307,7 @@ they change `stateRevision`, not `targetShapeRevision`, and do not require a
293
307
  second approval.
294
308
 
295
309
  In `--yolo`, continue as far as the rendered packet safely allows. After each
296
- apply/prep/start result, reread state, settle processing when needed, and move to
310
+ apply/prep/source-copy/bounded-approval/read-only wait result, reread state, settle processing when needed, and move to
297
311
  the next selected sender or start-eligible same-packet campaign instead of
298
312
  stopping after the first partial result. If no in-packet safe action remains,
299
313
  return concrete continuation options with campaign names, exact ids, which option
@@ -307,7 +321,7 @@ selected sender: selected send days, gross capacity, actual sent cells, future
307
321
  scheduler-owned scheduled cells with non-null `scheduledFor`, projected count,
308
322
  ready-to-schedule buffer, remaining projected gap, paid-InMail feasibility,
309
323
  `targetShapeRevision`, `stateRevision`, and the next MCP primitive that can
310
- reduce the gap. After every apply/prep/start result, wait for processing, reread
324
+ reduce the gap. After every apply/prep/source-copy/bounded-approval/read-only wait result, wait for processing, reread
311
325
  the target plan/refill state, recompute the ledger, then keep applying safe
312
326
  bounded actions until projected coverage fills the target window or a concrete
313
327
  non-scheduler blocker is proven.
@@ -120,12 +120,19 @@ in-progress wait state, not a reason to mark the goal complete or blocked.
120
120
  - `nextActions[0]` is the current sender's smallest safe primitive.
121
121
  - `manualAlternates` are not yolo actions. Threshold lowering and campaign
122
122
  creation are manual continuations only.
123
+ Refill action ladder: approve generated rows only when an explicit bounded
124
+ approval gate exists, process all existing same-campaign
125
+ unenriched/unprepared rows in bounded batches before any source work, then
126
+ copy bounded net-new rows from the selected source (`selectedLeadListId`,
127
+ provider, and source fingerprint preserved), then use provider-aligned
128
+ source-more. A new source or provider switch changes the reply-rate baseline
129
+ and is a manual alternate, not a `--yolo` side effect.
123
130
  Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
124
131
  automatically maintains a `refreshedPaidInmailSenderIds` set for the current
125
132
  command call. If its first target plan has stale/missing paid-InMail credit
126
133
  facts, it refreshes each selected sender at most once, reruns
127
134
  `get_refill_target_plan`, and returns the post-refresh `targetPlan` before
128
- choosing the next prep/approval/start action. If fresh facts are still below
135
+ choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
129
136
  threshold, below-threshold paid-InMail facts fall back to an existing
130
137
  connection lane, the same Sales Nav cascade campaign's connection branch, or
131
138
  a manual continuation.
@@ -564,7 +571,7 @@ same refill request, do not ask the `Accept` / `Decline` question. Instead:
564
571
  caps/dates, approval mode, blockers, and side-effect class still match the
565
572
  packet;
566
573
  4. execute only the exact packet;
567
- 5. after each terminal credit-refresh/apply/prep/start result, rerun
574
+ 5. after each terminal credit-refresh/apply/prep/source-copy/bounded-approval/read-only wait result, rerun
568
575
  `get_refill_target_plan`, reread state, settle processing when needed,
569
576
  recompute the target-window saturation ledger, and continue with the next smallest
570
577
  safe action inside the same bounded packet until every selected sender is