@sellable/mcp 0.1.640 → 0.1.641

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.
@@ -520,49 +520,67 @@ function workspaceCoordinatorInput(input) {
520
520
  delete coordinatorInput.agentKeywords;
521
521
  return coordinatorInput;
522
522
  }
523
- function firstRecordWithExactTarget(value) {
523
+ function recordsWithExactTarget(value) {
524
524
  return Array.isArray(value)
525
525
  ? value
526
526
  .map(recordValue)
527
- .find((candidate) => Boolean(stringValue(candidate?.campaignId)) &&
528
- Boolean(stringValue(candidate?.tableId)))
529
- : undefined;
527
+ .filter((candidate) => Boolean(candidate &&
528
+ stringValue(candidate.campaignId) &&
529
+ stringValue(candidate.tableId)))
530
+ : [];
530
531
  }
531
- function workspaceExactTargetFromAction(action) {
532
+ function workspaceExactTargetsFromAction(action) {
532
533
  const toolInput = recordValue(action.toolInput) ?? {};
533
- const exactEdge = firstRecordWithExactTarget(toolInput.expectedTargets) ??
534
- firstRecordWithExactTarget(toolInput.sourceScopes);
534
+ const expectedTargets = recordsWithExactTarget(toolInput.expectedTargets);
535
+ const sourceScopes = recordsWithExactTarget(toolInput.sourceScopes);
536
+ const exactEdges = expectedTargets.length > 0
537
+ ? expectedTargets
538
+ : sourceScopes.length > 0
539
+ ? sourceScopes
540
+ : [null];
535
541
  const campaignIds = normalizeStrings(toolInput.campaignIds);
536
542
  const tableIds = normalizeStrings(toolInput.tableIds);
537
- const campaignId = actionCampaignId(action) ??
538
- stringValue(exactEdge?.campaignId) ??
539
- campaignIds[0];
540
- const tableId = actionTableId(action) ?? stringValue(exactEdge?.tableId) ?? tableIds[0];
541
- if (!campaignId || !tableId)
542
- return null;
543
- const exactEdgeSenderIds = normalizeStrings(exactEdge?.senderIds);
544
- const senderId = actionSenderId(action) ?? stringValue(exactEdge?.senderId) ?? null;
545
- const senderIds = senderId
546
- ? [senderId]
547
- : exactEdgeSenderIds.length > 0
548
- ? exactEdgeSenderIds
549
- : normalizeStrings(toolInput.senderIds);
550
- const directActionType = stringValue(action.actionType) ??
551
- stringValue(exactEdge?.actionType) ??
552
- stringValue(exactEdge?.refillLaneKey);
553
- const exactEdgeActionTypes = normalizeStrings(exactEdge?.branchActionTypes);
554
- const actionTypes = directActionType && REFILL_SEND_ACTION_TYPE_SET.has(directActionType)
555
- ? [directActionType]
556
- : (exactEdgeActionTypes.length > 0
557
- ? exactEdgeActionTypes
558
- : normalizeStrings(toolInput.actionTypes)).filter((actionType) => REFILL_SEND_ACTION_TYPE_SET.has(actionType));
559
- return {
560
- campaignId,
561
- tableId,
562
- senderIds,
563
- actionTypes,
564
- actionKey: stringValue(action.actionKey) ?? null,
565
- };
543
+ return exactEdges.flatMap((exactEdge) => {
544
+ const campaignId = stringValue(exactEdge?.campaignId) ??
545
+ actionCampaignId(action) ??
546
+ campaignIds[0];
547
+ const tableId = stringValue(exactEdge?.tableId) ?? actionTableId(action) ?? tableIds[0];
548
+ if (!campaignId || !tableId)
549
+ return [];
550
+ const exactEdgeSenderIds = normalizeStrings(exactEdge?.senderIds);
551
+ const senderId = stringValue(exactEdge?.senderId) ?? actionSenderId(action) ?? null;
552
+ const senderIds = senderId
553
+ ? [senderId]
554
+ : exactEdgeSenderIds.length > 0
555
+ ? exactEdgeSenderIds
556
+ : normalizeStrings(toolInput.senderIds);
557
+ const directActionType = stringValue(exactEdge?.actionType) ??
558
+ stringValue(exactEdge?.refillLaneKey) ??
559
+ stringValue(action.actionType);
560
+ const exactEdgeActionTypes = normalizeStrings(exactEdge?.branchActionTypes);
561
+ const actionTypes = directActionType && REFILL_SEND_ACTION_TYPE_SET.has(directActionType)
562
+ ? [directActionType]
563
+ : (exactEdgeActionTypes.length > 0
564
+ ? exactEdgeActionTypes
565
+ : normalizeStrings(toolInput.actionTypes)).filter((actionType) => REFILL_SEND_ACTION_TYPE_SET.has(actionType));
566
+ return [
567
+ {
568
+ campaignId,
569
+ tableId,
570
+ senderIds,
571
+ actionTypes,
572
+ actionKey: stringValue(action.actionKey) ?? null,
573
+ },
574
+ ];
575
+ });
576
+ }
577
+ function workspaceExactTargetKey(target) {
578
+ return JSON.stringify([
579
+ target.campaignId,
580
+ target.tableId,
581
+ [...new Set(target.senderIds)].sort(),
582
+ [...new Set(target.actionTypes)].sort(),
583
+ ]);
566
584
  }
567
585
  function evergreenExactTargetCandidates(workspacePlan, options) {
568
586
  const root = recordValue(workspacePlan) ?? {};
@@ -647,16 +665,22 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
647
665
  .filter((action) => Boolean(action))
648
666
  : [];
649
667
  const workspaceActions = [...globalActions, ...rankedCandidates];
650
- const selectedTarget = [
651
- ...workspaceActions.map(workspaceExactTargetFromAction),
652
- ...evergreenExactTargetCandidates(workspacePlan, {
653
- preferredSenderId: options.preferredSenderId,
654
- actionTypes: input.actionTypes,
655
- }),
656
- ].find((candidate) => Boolean(candidate) &&
657
- !excludedTargets.some((excluded) => excluded.campaignId === candidate?.campaignId &&
658
- excluded.tableId === candidate?.tableId));
659
- if (!selectedTarget) {
668
+ const actionTargets = workspaceActions.flatMap(workspaceExactTargetsFromAction);
669
+ const evergreenTargets = evergreenExactTargetCandidates(workspacePlan, {
670
+ preferredSenderId: options.preferredSenderId,
671
+ actionTypes: input.actionTypes,
672
+ }).filter((candidate) => !actionTargets.some((actionTarget) => actionTarget.campaignId === candidate.campaignId &&
673
+ actionTarget.tableId === candidate.tableId));
674
+ const seenTargetKeys = new Set();
675
+ const targetCandidates = [...actionTargets, ...evergreenTargets].filter((candidate) => {
676
+ const key = workspaceExactTargetKey(candidate);
677
+ if (seenTargetKeys.has(key))
678
+ return false;
679
+ seenTargetKeys.add(key);
680
+ return !excludedTargets.some((excluded) => excluded.campaignId === candidate.campaignId &&
681
+ excluded.tableId === candidate.tableId);
682
+ });
683
+ if (targetCandidates.length === 0) {
660
684
  return {
661
685
  status: "blocked",
662
686
  code: "workspace_exact_target_unavailable",
@@ -666,61 +690,74 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
666
690
  workspacePlan,
667
691
  };
668
692
  }
669
- const exactInput = {
670
- ...workspaceInput,
671
- campaignId: selectedTarget.campaignId,
672
- tableId: selectedTarget.tableId,
673
- ...(selectedTarget.senderIds.length > 0
674
- ? { senderIds: selectedTarget.senderIds, senders: [], senderNames: [] }
675
- : {}),
676
- ...(selectedTarget.actionTypes.length > 0
677
- ? { actionTypes: selectedTarget.actionTypes }
678
- : {}),
679
- };
680
- const exactTargetPlan = await getRefillTargetPlan(targetPlanInputFor(exactInput));
681
- let targetConfig;
682
- try {
683
- targetConfig = normalizeRefillTargetConfig(recordValue(exactTargetPlan)?.targetConfig);
684
- }
685
- catch {
686
- return {
687
- status: "blocked",
688
- code: "exact_target_config_unavailable",
689
- note: "The exact read-only planner did not issue targetConfig. No refill run or mutation was started.",
690
- workspacePlan,
691
- exactTargetPlan,
692
- selectedTarget,
693
- };
694
- }
695
- if (targetConfig.workspaceId !==
696
- normalizeExplicitWorkspaceId(input.workspaceId) ||
697
- targetConfig.campaignId !== selectedTarget.campaignId ||
698
- targetConfig.tableId !== selectedTarget.tableId) {
699
- return {
700
- status: "blocked",
701
- code: "exact_target_config_mismatch",
702
- note: "The server-issued targetConfig did not match the workspace queue's selected campaign/table. No refill run or mutation was started.",
703
- workspacePlan,
704
- exactTargetPlan,
705
- selectedTarget,
693
+ let completedExactTargetCount = 0;
694
+ for (const selectedTarget of targetCandidates) {
695
+ const exactInput = {
696
+ ...workspaceInput,
697
+ campaignId: selectedTarget.campaignId,
698
+ tableId: selectedTarget.tableId,
699
+ ...(selectedTarget.senderIds.length > 0
700
+ ? { senderIds: selectedTarget.senderIds, senders: [], senderNames: [] }
701
+ : {}),
702
+ ...(selectedTarget.actionTypes.length > 0
703
+ ? { actionTypes: selectedTarget.actionTypes }
704
+ : {}),
706
705
  };
707
- }
708
- if (!exactCampaignProjectionMatches(exactTargetPlan, selectedTarget.campaignId, selectedTarget.tableId)) {
706
+ const exactTargetPlan = await getRefillTargetPlan(targetPlanInputFor(exactInput));
707
+ if (yoloPlanIsComplete(exactTargetPlan)) {
708
+ completedExactTargetCount += 1;
709
+ continue;
710
+ }
711
+ let targetConfig;
712
+ try {
713
+ targetConfig = normalizeRefillTargetConfig(recordValue(exactTargetPlan)?.targetConfig);
714
+ }
715
+ catch {
716
+ return {
717
+ status: "blocked",
718
+ code: "exact_target_config_unavailable",
719
+ note: "The exact read-only planner did not issue targetConfig. No refill run or mutation was started.",
720
+ workspacePlan,
721
+ exactTargetPlan,
722
+ selectedTarget,
723
+ };
724
+ }
725
+ if (targetConfig.workspaceId !==
726
+ normalizeExplicitWorkspaceId(input.workspaceId) ||
727
+ targetConfig.campaignId !== selectedTarget.campaignId ||
728
+ targetConfig.tableId !== selectedTarget.tableId) {
729
+ return {
730
+ status: "blocked",
731
+ code: "exact_target_config_mismatch",
732
+ note: "The server-issued targetConfig did not match the workspace queue's selected campaign/table. No refill run or mutation was started.",
733
+ workspacePlan,
734
+ exactTargetPlan,
735
+ selectedTarget,
736
+ };
737
+ }
738
+ if (!exactCampaignProjectionMatches(exactTargetPlan, selectedTarget.campaignId, selectedTarget.tableId)) {
739
+ return {
740
+ status: "blocked",
741
+ code: "exact_target_projection_mismatch",
742
+ note: "The live exact planner projection did not contain only the workspace queue's selected campaign/table. No refill run or mutation was started.",
743
+ workspacePlan,
744
+ exactTargetPlan,
745
+ selectedTarget,
746
+ };
747
+ }
709
748
  return {
710
- status: "blocked",
711
- code: "exact_target_projection_mismatch",
712
- note: "The live exact planner projection did not contain only the workspace queue's selected campaign/table. No refill run or mutation was started.",
749
+ status: "selected",
713
750
  workspacePlan,
714
751
  exactTargetPlan,
715
752
  selectedTarget,
753
+ targetConfig,
716
754
  };
717
755
  }
718
756
  return {
719
- status: "selected",
757
+ status: "blocked",
758
+ code: "workspace_exact_target_unavailable",
759
+ note: `The fresh workspace queue remained incomplete, but all ${completedExactTargetCount} exposed exact targets were already complete. No identical refill fence was reopened.`,
720
760
  workspacePlan,
721
- exactTargetPlan,
722
- selectedTarget,
723
- targetConfig,
724
761
  };
725
762
  }
726
763
  function yoloCoverage(plan) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.640",
3
+ "version": "0.1.641",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",