@sellable/mcp 0.1.945 → 0.1.946

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.
@@ -63,7 +63,10 @@ type StartPrepareMessagesInput = PrepareMessagesBaseInput & PrepareMessagesReadi
63
63
  senderId?: string;
64
64
  actionType?: string;
65
65
  };
66
- type StatusPrepareMessagesInput = PrepareMessagesBaseInput;
66
+ type StatusPrepareMessagesInput = PrepareMessagesBaseInput & {
67
+ /** With no jobId: the latest job started by this source, not the latest job. */
68
+ requestSource?: string;
69
+ };
67
70
  type CancelPrepareMessagesInput = PrepareMessagesBaseInput;
68
71
  export declare const campaignMessagePreparationToolDefinitions: ({
69
72
  name: string;
@@ -269,6 +269,7 @@ export async function startPrepareCampaignMessages(input) {
269
269
  effectId: input.effectId,
270
270
  ...(reportingContext ? { reportingContext } : {}),
271
271
  ...(input.history ? { history: input.history } : {}),
272
+ ...(input.requestSource ? { requestSource: input.requestSource } : {}),
272
273
  ...(workspaceId ? { workspaceId } : {}),
273
274
  }, workspaceId ?? undefined);
274
275
  return sanitizePreparationResponse(result);
@@ -226,6 +226,10 @@ export declare const REFILL_V3_CONTINUE_OUTPUT_SCHEMA: Readonly<{
226
226
  readonly type: "integer";
227
227
  readonly minimum: 1;
228
228
  };
229
+ readonly runningForSeconds: {
230
+ readonly type: "integer";
231
+ readonly minimum: 0;
232
+ };
229
233
  readonly advanceResult: {
230
234
  readonly type: "object";
231
235
  };
@@ -122,6 +122,7 @@ export const REFILL_V3_CONTINUE_OUTPUT_SCHEMA = Object.freeze({
122
122
  properties: {
123
123
  kind: { type: "string", enum: [...REFILL_V3_CONTINUE_RESULT_KINDS] },
124
124
  retryAfterMs: { type: "integer", minimum: 1 },
125
+ runningForSeconds: { type: "integer", minimum: 0 },
125
126
  advanceResult: { type: "object" },
126
127
  packet: { type: "object" },
127
128
  correction: { type: "object" },
@@ -221,6 +221,10 @@ export declare const refillV3ContinueToolDefinitions: {
221
221
  readonly type: "integer";
222
222
  readonly minimum: 1;
223
223
  };
224
+ readonly runningForSeconds: {
225
+ readonly type: "integer";
226
+ readonly minimum: 0;
227
+ };
224
228
  readonly advanceResult: {
225
229
  readonly type: "object";
226
230
  };
@@ -389,6 +393,7 @@ export type RefillV3ContinueInput = {
389
393
  export type RefillV3ContinueResult = {
390
394
  kind: "continuation_pending";
391
395
  retryAfterMs: number;
396
+ runningForSeconds?: number;
392
397
  } | {
393
398
  kind: "world_advanced";
394
399
  advanceResult: Extract<RefillV3AdvanceResult, {
@@ -458,10 +458,15 @@ export async function runRefillV3CampaignWorkWithProductionOwners(input, owners
458
458
  const exactDiagnosticRowIds = request.rowIds ?? [];
459
459
  let lastStatus = null;
460
460
  try {
461
+ // Read the ladder's OWN last cohort. Other owners (refill_sends exact
462
+ // fills) start one- and two-row jobs on the same table; taking the
463
+ // latest job of any source made every cohort look thin and pinned
464
+ // the ladder to ten-row probes for the whole run.
461
465
  lastStatus = await owners.getPrepareCampaignMessagesStatus({
462
466
  workspaceId: request.scope.workspaceId,
463
467
  campaignId: request.scope.campaignId,
464
468
  tableId: request.scope.tableId,
469
+ requestSource: "refill_v3_continue",
465
470
  });
466
471
  }
467
472
  catch {
@@ -130,7 +130,11 @@ export function startRefillV3Continuation(input, execute) {
130
130
  if (continuationFlights.size >= MAX_RETAINED_REFILL_RUNS) {
131
131
  throw new Error("Collect pending refill continuations before starting another scope.");
132
132
  }
133
- const entry = { scope: input, promise: Promise.resolve().then(execute) };
133
+ const entry = {
134
+ scope: input,
135
+ promise: Promise.resolve().then(execute),
136
+ startedAt: Date.now(),
137
+ };
134
138
  continuationFlights.set(runKey(input), entry);
135
139
  return collectContinuation(entry);
136
140
  }
@@ -144,8 +148,15 @@ async function collectContinuation(entry) {
144
148
  timer = setTimeout(() => resolve(pending), 20_000);
145
149
  }),
146
150
  ]);
151
+ // Each pending answer says how long the operation has run. Byte-identical
152
+ // answers to identical polls trip host loop guards (Hermes halts a tool
153
+ // after five), which stopped an unattended refill before its work settled.
147
154
  if (result === pending)
148
- return { kind: "continuation_pending", retryAfterMs: 1000 };
155
+ return {
156
+ kind: "continuation_pending",
157
+ retryAfterMs: 1000,
158
+ runningForSeconds: Math.max(0, Math.round((Date.now() - entry.startedAt) / 1000)),
159
+ };
149
160
  if (continuationFlights.get(runKey(entry.scope)) === entry)
150
161
  continuationFlights.delete(runKey(entry.scope));
151
162
  return result;
@@ -11448,6 +11448,10 @@ export declare const allTools: ({
11448
11448
  readonly type: "integer";
11449
11449
  readonly minimum: 1;
11450
11450
  };
11451
+ readonly runningForSeconds: {
11452
+ readonly type: "integer";
11453
+ readonly minimum: 0;
11454
+ };
11451
11455
  readonly advanceResult: {
11452
11456
  readonly type: "object";
11453
11457
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.945",
3
+ "version": "0.1.946",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",
@@ -67,6 +67,21 @@ Scheduled results use five product meanings:
67
67
  customer action. Make the result available to the daily review; do not post a
68
68
  second routine message.
69
69
 
70
+ Customer fixes. A blocked row's `reason.codes` names what only the customer can
71
+ fix. Say it once per sender in plain words, with the next step, and keep filling
72
+ every other sender and lane:
73
+
74
+ - `sender_disconnected`: that sender's LinkedIn account is disconnected. Next
75
+ step: reconnect it in Sellable (LinkedIn accounts), or remove the sender if it
76
+ is no longer used.
77
+ - `sales_nav_disconnected` or `paid_inmail_connection_health_recheck_required`:
78
+ Sellable cannot read that sender's Sales Navigator InMail credits. Next step:
79
+ reconnect Sales Navigator for that sender (or renew it if it lapsed).
80
+ Connection requests continue meanwhile.
81
+
82
+ Retryable provider codes (`paid_inmail_credit_refresh_failed`, timeouts) are not
83
+ customer tasks; never ask the customer to retry them.
84
+
70
85
  Interactive `refill-sends --yolo` always receives its actual result immediately.
71
86
  State connection invitations and paid InMail separately: invitation capacity is
72
87
  not paid InMail credit, and paid InMail coverage is never proof of invitation