@sellable/mcp 0.1.614 → 0.1.615-wip.121.2

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.
@@ -1,5 +1,6 @@
1
1
  import { getApi } from "../api.js";
2
2
  import { decodeRefillReadinessAuthority, decodeRefillReadinessCampaignSummary, decodeRefillReadinessIdentity, decodeRefillSchedulerDateGuards, refillReadinessExpectationInput, } from "../refill-readiness.js";
3
+ import { sanitizeProviderSearchReference } from "./refill-executors.js";
3
4
  import { REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT, REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT, REFILL_SCHEDULER_MAX_PLACEMENTS, } from "./scheduler-run.js";
4
5
  import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
5
6
  const REFILL_TARGET_ACTION_TYPES = [
@@ -42,6 +43,11 @@ const SAFE_PACKET_ACTION_TYPES = new Set([
42
43
  "next_campaign",
43
44
  "done",
44
45
  ]);
46
+ const PROVIDER_SAVED_SEARCH_ACTION_TYPES = new Set([
47
+ "continue_sales_nav_source",
48
+ "continue_prospeo_source",
49
+ "broaden_provider_search",
50
+ ]);
45
51
  // Phase 110-05: continue_sales_nav_source and continue_prospeo_source are the
46
52
  // bounded SAME-provider-source continuation rungs for cold-outbound campaigns.
47
53
  // Plain --yolo may execute them once eligible/prepared rows are receipt-proven
@@ -187,6 +193,43 @@ function stringValue(value) {
187
193
  function booleanValue(value) {
188
194
  return typeof value === "boolean" ? value : undefined;
189
195
  }
196
+ function exactProviderSearchReferenceFromValues(values) {
197
+ const present = values.filter((value) => value !== undefined && value !== null);
198
+ if (present.length === 0)
199
+ return null;
200
+ const references = present.map(sanitizeProviderSearchReference);
201
+ if (references.some((reference) => !reference))
202
+ return null;
203
+ const exactReferences = references;
204
+ const [first, ...rest] = exactReferences;
205
+ const fingerprint = JSON.stringify(first);
206
+ return rest.every((reference) => JSON.stringify(reference) === fingerprint)
207
+ ? first
208
+ : null;
209
+ }
210
+ function providerSearchReferenceFromAction(action) {
211
+ const ids = isRecord(action.ids) ? action.ids : {};
212
+ const toolInput = isRecord(action.toolInput) ? action.toolInput : {};
213
+ return exactProviderSearchReferenceFromValues([
214
+ action.providerSearchReference,
215
+ ids.providerSearchReference,
216
+ toolInput.providerSearchReference,
217
+ ]);
218
+ }
219
+ function unusableProviderLineageOutcome(action) {
220
+ return {
221
+ class: "source_terminal",
222
+ code: "provider_search_lineage_unusable",
223
+ detail: "Exact compact workspace/provider/source/search/owner lineage is missing, partial, or contradictory; no provider mutation is authorized.",
224
+ facts: {
225
+ actionType: stringValue(action.type) ?? null,
226
+ actionKey: stringValue(action.actionKey) ?? null,
227
+ effectId: stringValue(action.effectId) ??
228
+ stringValue(isRecord(action.toolInput) ? action.toolInput.effectId : null) ??
229
+ null,
230
+ },
231
+ };
232
+ }
190
233
  function numericRecord(value) {
191
234
  if (!isRecord(value))
192
235
  return {};
@@ -327,6 +370,8 @@ function sanitizeActionCandidate(candidate) {
327
370
  sourceLeadListId: stringValue(candidate.sourceLeadListId) ?? null,
328
371
  leadSourceProvider: stringValue(candidate.leadSourceProvider) ?? null,
329
372
  sourceFingerprint: stringValue(candidate.sourceFingerprint) ?? null,
373
+ providerSearchReference: sanitizeProviderSearchReference(candidate.providerSearchReference) ??
374
+ undefined,
330
375
  sourceInventoryStatus: stringValue(candidate.sourceInventoryStatus) ?? null,
331
376
  sourceRowIds: stringArray(candidate.sourceRowIds),
332
377
  sourceRowLimit: typeof candidate.sourceRowLimit === "number"
@@ -619,10 +664,11 @@ function sanitizeToolInput(value, authority) {
619
664
  : undefined,
620
665
  campaignOfferId: stringValue(value.campaignOfferId),
621
666
  provider: stringValue(value.provider),
622
- // Phase 110-05: reusable SAME-provider-source search reference for bounded
623
- // sales-nav / prospeo yolo continuation (only consumed for same-source
624
- // adds; never authorizes a source-family switch).
667
+ // Legacy searchId remains diagnostic only. Provider mutations require the
668
+ // exact compact providerSearchReference below.
625
669
  searchId: stringValue(value.searchId),
670
+ providerSearchReference: sanitizeProviderSearchReference(value.providerSearchReference) ??
671
+ undefined,
626
672
  targetLeadCount: typeof value.targetLeadCount === "number"
627
673
  ? value.targetLeadCount
628
674
  : undefined,
@@ -671,6 +717,8 @@ function sanitizePacketIds(value) {
671
717
  leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
672
718
  sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
673
719
  activeJobId: stringValue(value.activeJobId) ?? null,
720
+ providerSearchReference: sanitizeProviderSearchReference(value.providerSearchReference) ??
721
+ undefined,
674
722
  };
675
723
  }
676
724
  function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
@@ -681,15 +729,23 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
681
729
  if (mode === "next" && MANUAL_ONLY_PACKET_ACTION_TYPES.has(action.type)) {
682
730
  return null;
683
731
  }
684
- const ids = sanitizePacketIds(action.ids);
732
+ const providerSearchReference = providerSearchReferenceFromAction(action);
733
+ const providerLineageUnusable = PROVIDER_SAVED_SEARCH_ACTION_TYPES.has(action.type) &&
734
+ !providerSearchReference;
735
+ const ids = {
736
+ ...sanitizePacketIds(action.ids),
737
+ ...(providerSearchReference ? { providerSearchReference } : {}),
738
+ };
685
739
  const senderId = stringValue(ids.senderId);
686
740
  if (senderId && !selectedBySender.has(senderId))
687
741
  return null;
688
742
  if (!senderId && action.type !== "wait_for_scheduler")
689
743
  return null;
690
- const yoloEligible = mode === "manual" || MANUAL_ONLY_PACKET_ACTION_TYPES.has(action.type)
691
- ? false
692
- : action.yoloEligible !== false;
744
+ const yoloEligible = providerLineageUnusable && mode === "next"
745
+ ? true
746
+ : mode === "manual" || MANUAL_ONLY_PACKET_ACTION_TYPES.has(action.type)
747
+ ? false
748
+ : action.yoloEligible !== false;
693
749
  const authorityResult = CONSEQUENCE_BOUND_READINESS_ACTIONS.has(action.type)
694
750
  ? decodeRefillReadinessAuthority(action)
695
751
  : null;
@@ -709,7 +765,10 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
709
765
  toolName: stringValue(action.toolName) ?? null,
710
766
  sideEffectClass: stringValue(action.sideEffectClass),
711
767
  ids,
712
- toolInput: sanitizeToolInput(action.toolInput, authority),
768
+ toolInput: {
769
+ ...sanitizeToolInput(action.toolInput, authority),
770
+ ...(providerSearchReference ? { providerSearchReference } : {}),
771
+ },
713
772
  inputSummary: stringValue(action.inputSummary) ?? "",
714
773
  reason: stringValue(action.reason) ?? "",
715
774
  refillReceipt: sanitizeRefillReceipt(action.refillReceipt),
@@ -721,6 +780,12 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
721
780
  stopCondition: stringValue(action.stopCondition) ?? "",
722
781
  yoloEligible,
723
782
  actionKey: stringValue(action.actionKey),
783
+ requestId: stringValue(action.requestId),
784
+ effectId: stringValue(action.effectId) ??
785
+ stringValue(isRecord(action.toolInput) ? action.toolInput.effectId : null),
786
+ ...(providerLineageUnusable
787
+ ? { preExecutorOutcome: unusableProviderLineageOutcome(action) }
788
+ : {}),
724
789
  capSaturated: booleanValue(action.capSaturated) === true ? true : undefined,
725
790
  prepFailureDiagnosis: sanitizePrepFailureDiagnosis(action.prepFailureDiagnosis),
726
791
  ...(authority ? readinessAuthorityFields(authority) : {}),
@@ -812,6 +877,8 @@ function sanitizeSourcePlan(value) {
812
877
  sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
813
878
  leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
814
879
  sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
880
+ providerSearchReference: sanitizeProviderSearchReference(value.providerSearchReference) ??
881
+ undefined,
815
882
  capSaturated: booleanValue(value.capSaturated) === true ? true : undefined,
816
883
  remainingRowsNeeded: typeof value.remainingRowsNeeded === "number"
817
884
  ? value.remainingRowsNeeded
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.614",
3
+ "version": "0.1.615-wip.121.2",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",