@sellable/mcp 0.1.199 → 0.1.200

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.
@@ -99,6 +99,9 @@ export declare function getCampaignContext(input: GetCampaignContextInput): Prom
99
99
  enableICPFilters: boolean | null;
100
100
  activeRubricCount: number;
101
101
  hasApprovedMessageTemplate: boolean;
102
+ generatedMessageCount: number | null;
103
+ approvedGeneratedMessageCount: number | null;
104
+ needsApprovalCount: number | null;
102
105
  senderCount: number;
103
106
  hasSequenceTemplate: boolean;
104
107
  campaignStatus: string | null;
@@ -196,6 +196,9 @@ export function markCampaignContextDirty(campaignId, reason) {
196
196
  enableICPFilters: null,
197
197
  activeRubricCount: 0,
198
198
  hasApprovedMessageTemplate: false,
199
+ generatedMessageCount: null,
200
+ approvedGeneratedMessageCount: null,
201
+ needsApprovalCount: null,
199
202
  senderCount: 0,
200
203
  hasSequenceTemplate: false,
201
204
  campaignStatus: null,
@@ -27,6 +27,14 @@ export type CampaignOfferNavigation = {
27
27
  currentStep?: string | null;
28
28
  watchUrl?: string | null;
29
29
  };
30
+ type WorkflowTableMessageStats = {
31
+ totalRows?: number;
32
+ messagesCount?: number;
33
+ generatedMessagesCount?: number;
34
+ currentRevisionGeneratedMessagesCount?: number;
35
+ approvedCount?: number;
36
+ needsApprovalCount?: number;
37
+ };
30
38
  type NavigationDebugPayload = Record<string, unknown>;
31
39
  export declare function logNavigationDebug(event: string, payload?: NavigationDebugPayload, campaignId?: string | null): void;
32
40
  type CreateCampaignStepId = "campaign-created" | "pick-provider" | "provider-search" | "confirm-lead-list" | "filter-rules" | "messages" | "settings" | "sequence" | "send" | "running";
@@ -54,6 +62,8 @@ type NavigationComputeOptions = {
54
62
  tableChecked: boolean;
55
63
  rowCount: number | null;
56
64
  hasWorkflowRows: boolean | null;
65
+ messageStatsChecked?: boolean;
66
+ messageStats?: WorkflowTableMessageStats | null;
57
67
  selectedLeadListChecked?: boolean;
58
68
  selectedLeadListAccessible?: boolean | null;
59
69
  selectedLeadListRowCount?: number | null;
@@ -99,6 +109,9 @@ export declare function computeCampaignNavigationStateFromCampaign(campaign: Cam
99
109
  enableICPFilters: boolean | null;
100
110
  activeRubricCount: number;
101
111
  hasApprovedMessageTemplate: boolean;
112
+ generatedMessageCount: number | null;
113
+ approvedGeneratedMessageCount: number | null;
114
+ needsApprovalCount: number | null;
102
115
  senderCount: number;
103
116
  hasSequenceTemplate: boolean;
104
117
  campaignStatus: string | null;
@@ -144,6 +157,9 @@ export declare function getCampaignNavigationState(input: GetCampaignNavigationS
144
157
  enableICPFilters: boolean | null;
145
158
  activeRubricCount: number;
146
159
  hasApprovedMessageTemplate: boolean;
160
+ generatedMessageCount: number | null;
161
+ approvedGeneratedMessageCount: number | null;
162
+ needsApprovalCount: number | null;
147
163
  senderCount: number;
148
164
  hasSequenceTemplate: boolean;
149
165
  campaignStatus: string | null;
@@ -238,11 +238,34 @@ function checkRubrics(campaign) {
238
238
  }
239
239
  return { stepId: "filter-rules", missing };
240
240
  }
241
- function checkMessages(campaign) {
241
+ function getGeneratedMessageCount(stats) {
242
+ if (!stats)
243
+ return null;
244
+ return (stats.currentRevisionGeneratedMessagesCount ??
245
+ stats.generatedMessagesCount ??
246
+ stats.messagesCount ??
247
+ null);
248
+ }
249
+ function getApprovedGeneratedMessageCount(stats) {
250
+ if (!stats)
251
+ return null;
252
+ return stats.approvedCount ?? null;
253
+ }
254
+ function checkMessages(campaign, stats, statsChecked = false) {
242
255
  const missing = [];
243
256
  if (!hasApprovedMessageTemplate(campaign)) {
244
257
  missing.push("approvedMessageTemplate");
245
258
  }
259
+ if (statsChecked && hasApprovedMessageTemplate(campaign)) {
260
+ const generatedCount = getGeneratedMessageCount(stats) ?? 0;
261
+ const approvedCount = getApprovedGeneratedMessageCount(stats) ?? 0;
262
+ if (generatedCount <= 0) {
263
+ missing.push("generatedMessages");
264
+ }
265
+ else if (approvedCount <= 0) {
266
+ missing.push("approvedGeneratedMessage");
267
+ }
268
+ }
246
269
  return { stepId: "messages", missing };
247
270
  }
248
271
  function checkSettings(campaign) {
@@ -482,6 +505,10 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
482
505
  tableChecked: options.tableChecked,
483
506
  rowCount: options.rowCount,
484
507
  hasWorkflowRows: options.hasWorkflowRows,
508
+ messageStatsChecked: options.messageStatsChecked ?? false,
509
+ generatedMessageCount: getGeneratedMessageCount(options.messageStats),
510
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(options.messageStats),
511
+ needsApprovalCount: options.messageStats?.needsApprovalCount ?? null,
485
512
  selectedLeadListChecked: options.selectedLeadListChecked ?? false,
486
513
  selectedLeadListAccessible: options.selectedLeadListAccessible ?? null,
487
514
  workflowTableAccessible: options.workflowTableAccessible ?? null,
@@ -514,7 +541,7 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
514
541
  }
515
542
  const evaluateTailState = shouldEvaluateTailState(campaign);
516
543
  if (evaluateTailState) {
517
- checks.push(checkMessages(campaign), checkSettings(campaign), checkSequence(campaign));
544
+ checks.push(checkMessages(campaign, options.messageStats ?? null, options.messageStatsChecked === true), checkSettings(campaign), checkSequence(campaign));
518
545
  }
519
546
  let computedStep = "campaign-created";
520
547
  let blockedAt = null;
@@ -539,7 +566,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
539
566
  const stepForHeadless = blockedAt ?? computedStep;
540
567
  const waitingOnMessageTemplateAfterFilters = blockedAt === "messages" &&
541
568
  campaign.enableICPFilters === true &&
542
- hasActiveRubrics(campaign);
569
+ hasActiveRubrics(campaign) &&
570
+ !hasApprovedMessageTemplate(campaign);
571
+ const waitingOnGeneratedMessageApproval = blockedAt === "messages" && hasApprovedMessageTemplate(campaign);
543
572
  const expectedHeadlessStep = stepForHeadless === "campaign-created"
544
573
  ? "create-offer"
545
574
  : stepForHeadless === "provider-search"
@@ -549,7 +578,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
549
578
  : stepForHeadless === "messages"
550
579
  ? waitingOnMessageTemplateAfterFilters
551
580
  ? "apply-icp-rubric"
552
- : "messages"
581
+ : waitingOnGeneratedMessageApproval
582
+ ? "auto-execute-messaging"
583
+ : "messages"
553
584
  : stepForHeadless === "settings"
554
585
  ? "settings"
555
586
  : stepForHeadless === "sequence"
@@ -623,6 +654,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
623
654
  enableICPFilters: campaign.enableICPFilters ?? null,
624
655
  activeRubricCount: campaign.leadScoringRubrics?.filter((rubric) => rubric.useCheckForScoring !== false).length ?? 0,
625
656
  hasApprovedMessageTemplate: hasApprovedMessageTemplate(campaign),
657
+ generatedMessageCount: getGeneratedMessageCount(options.messageStats),
658
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(options.messageStats),
659
+ needsApprovalCount: options.messageStats?.needsApprovalCount ?? null,
626
660
  senderCount: campaign.senderIds?.length ?? 0,
627
661
  hasSequenceTemplate: hasSequenceTemplate(campaign),
628
662
  campaignStatus: campaign.campaignStatus ?? campaign.status ?? null,
@@ -696,6 +730,8 @@ export async function getCampaignNavigationState(input) {
696
730
  let selectedLeadListRowCount = null;
697
731
  const warnings = [];
698
732
  let tableChecked = false;
733
+ let messageStatsChecked = false;
734
+ let messageStats = null;
699
735
  if (includeTableCheck &&
700
736
  campaign.selectedLeadListId &&
701
737
  campaign.selectedLeadListId !== campaign.workflowTableId) {
@@ -752,12 +788,37 @@ export async function getCampaignNavigationState(input) {
752
788
  error: error instanceof Error ? error.message : String(error),
753
789
  }, input.campaignId);
754
790
  }
791
+ if (workflowTableAccessible !== false) {
792
+ try {
793
+ messageStats = await api.get(`/api/v3/workflow-tables/${campaign.workflowTableId}/stats`);
794
+ messageStatsChecked = true;
795
+ logNavigationDebug("state.message_stats.success", {
796
+ campaignId: input.campaignId,
797
+ workflowTableId: campaign.workflowTableId,
798
+ generatedMessageCount: getGeneratedMessageCount(messageStats),
799
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(messageStats),
800
+ needsApprovalCount: messageStats.needsApprovalCount ?? null,
801
+ }, input.campaignId);
802
+ }
803
+ catch (error) {
804
+ messageStatsChecked = false;
805
+ messageStats = null;
806
+ warnings.push(`Workflow table message stats could not be checked. Detail: ${error instanceof Error ? error.message : String(error)}`);
807
+ logNavigationDebug("state.message_stats.error", {
808
+ campaignId: input.campaignId,
809
+ workflowTableId: campaign.workflowTableId,
810
+ error: error instanceof Error ? error.message : String(error),
811
+ }, input.campaignId);
812
+ }
813
+ }
755
814
  }
756
815
  const result = computeCampaignNavigationStateFromCampaign(campaign, {
757
816
  includeTableCheck,
758
817
  tableChecked,
759
818
  rowCount: tableRowCount,
760
819
  hasWorkflowRows,
820
+ messageStatsChecked,
821
+ messageStats,
761
822
  selectedLeadListChecked,
762
823
  selectedLeadListAccessible,
763
824
  selectedLeadListRowCount,
@@ -152,6 +152,9 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
152
152
  enableICPFilters: boolean | null;
153
153
  activeRubricCount: number;
154
154
  hasApprovedMessageTemplate: boolean;
155
+ generatedMessageCount: number | null;
156
+ approvedGeneratedMessageCount: number | null;
157
+ needsApprovalCount: number | null;
155
158
  senderCount: number;
156
159
  hasSequenceTemplate: boolean;
157
160
  campaignStatus: string | null;
@@ -202,6 +205,9 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
202
205
  enableICPFilters: boolean | null;
203
206
  activeRubricCount: number;
204
207
  hasApprovedMessageTemplate: boolean;
208
+ generatedMessageCount: number | null;
209
+ approvedGeneratedMessageCount: number | null;
210
+ needsApprovalCount: number | null;
205
211
  senderCount: number;
206
212
  hasSequenceTemplate: boolean;
207
213
  campaignStatus: string | null;
@@ -254,6 +260,9 @@ export declare function waitForCampaignTableReady(input: WaitForCampaignTableRea
254
260
  enableICPFilters: boolean | null;
255
261
  activeRubricCount: number;
256
262
  hasApprovedMessageTemplate: boolean;
263
+ generatedMessageCount: number | null;
264
+ approvedGeneratedMessageCount: number | null;
265
+ needsApprovalCount: number | null;
257
266
  senderCount: number;
258
267
  hasSequenceTemplate: boolean;
259
268
  campaignStatus: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.199",
3
+ "version": "0.1.200",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",