@sellable/mcp 0.1.199 → 0.1.201

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,9 +27,19 @@ 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";
41
+ export type GeneratedMessageApprovalGateMissing = "generatedMessages" | "approvedGeneratedMessage";
42
+ export declare function getGeneratedMessageApprovalGateMissing(stats?: WorkflowTableMessageStats | null, statsChecked?: boolean): GeneratedMessageApprovalGateMissing[];
33
43
  export declare const navigationToolDefinitions: {
34
44
  name: string;
35
45
  description: string;
@@ -54,6 +64,8 @@ type NavigationComputeOptions = {
54
64
  tableChecked: boolean;
55
65
  rowCount: number | null;
56
66
  hasWorkflowRows: boolean | null;
67
+ messageStatsChecked?: boolean;
68
+ messageStats?: WorkflowTableMessageStats | null;
57
69
  selectedLeadListChecked?: boolean;
58
70
  selectedLeadListAccessible?: boolean | null;
59
71
  selectedLeadListRowCount?: number | null;
@@ -99,6 +111,9 @@ export declare function computeCampaignNavigationStateFromCampaign(campaign: Cam
99
111
  enableICPFilters: boolean | null;
100
112
  activeRubricCount: number;
101
113
  hasApprovedMessageTemplate: boolean;
114
+ generatedMessageCount: number | null;
115
+ approvedGeneratedMessageCount: number | null;
116
+ needsApprovalCount: number | null;
102
117
  senderCount: number;
103
118
  hasSequenceTemplate: boolean;
104
119
  campaignStatus: string | null;
@@ -144,6 +159,9 @@ export declare function getCampaignNavigationState(input: GetCampaignNavigationS
144
159
  enableICPFilters: boolean | null;
145
160
  activeRubricCount: number;
146
161
  hasApprovedMessageTemplate: boolean;
162
+ generatedMessageCount: number | null;
163
+ approvedGeneratedMessageCount: number | null;
164
+ needsApprovalCount: number | null;
147
165
  senderCount: number;
148
166
  hasSequenceTemplate: boolean;
149
167
  campaignStatus: string | null;
@@ -238,11 +238,35 @@ 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
+ export function getGeneratedMessageApprovalGateMissing(stats, statsChecked = false) {
242
255
  const missing = [];
243
- if (!hasApprovedMessageTemplate(campaign)) {
244
- missing.push("approvedMessageTemplate");
256
+ if (statsChecked) {
257
+ const generatedCount = getGeneratedMessageCount(stats) ?? 0;
258
+ const approvedCount = getApprovedGeneratedMessageCount(stats) ?? 0;
259
+ if (generatedCount <= 0) {
260
+ missing.push("generatedMessages");
261
+ }
262
+ else if (approvedCount <= 0) {
263
+ missing.push("approvedGeneratedMessage");
264
+ }
245
265
  }
266
+ return missing;
267
+ }
268
+ function checkMessages(stats, statsChecked = false) {
269
+ const missing = getGeneratedMessageApprovalGateMissing(stats, statsChecked);
246
270
  return { stepId: "messages", missing };
247
271
  }
248
272
  function checkSettings(campaign) {
@@ -482,6 +506,10 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
482
506
  tableChecked: options.tableChecked,
483
507
  rowCount: options.rowCount,
484
508
  hasWorkflowRows: options.hasWorkflowRows,
509
+ messageStatsChecked: options.messageStatsChecked ?? false,
510
+ generatedMessageCount: getGeneratedMessageCount(options.messageStats),
511
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(options.messageStats),
512
+ needsApprovalCount: options.messageStats?.needsApprovalCount ?? null,
485
513
  selectedLeadListChecked: options.selectedLeadListChecked ?? false,
486
514
  selectedLeadListAccessible: options.selectedLeadListAccessible ?? null,
487
515
  workflowTableAccessible: options.workflowTableAccessible ?? null,
@@ -514,7 +542,7 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
514
542
  }
515
543
  const evaluateTailState = shouldEvaluateTailState(campaign);
516
544
  if (evaluateTailState) {
517
- checks.push(checkMessages(campaign), checkSettings(campaign), checkSequence(campaign));
545
+ checks.push(checkMessages(options.messageStats ?? null, options.messageStatsChecked === true), checkSettings(campaign), checkSequence(campaign));
518
546
  }
519
547
  let computedStep = "campaign-created";
520
548
  let blockedAt = null;
@@ -537,9 +565,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
537
565
  computedStep = isRunningCampaign(campaign) ? "running" : "send";
538
566
  }
539
567
  const stepForHeadless = blockedAt ?? computedStep;
540
- const waitingOnMessageTemplateAfterFilters = blockedAt === "messages" &&
541
- campaign.enableICPFilters === true &&
542
- hasActiveRubrics(campaign);
568
+ const waitingOnGeneratedMessageApproval = blockedAt === "messages" &&
569
+ (missing.includes("generatedMessages") ||
570
+ missing.includes("approvedGeneratedMessage"));
543
571
  const expectedHeadlessStep = stepForHeadless === "campaign-created"
544
572
  ? "create-offer"
545
573
  : stepForHeadless === "provider-search"
@@ -547,8 +575,8 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
547
575
  : stepForHeadless === "filter-rules"
548
576
  ? "create-icp-rubric"
549
577
  : stepForHeadless === "messages"
550
- ? waitingOnMessageTemplateAfterFilters
551
- ? "apply-icp-rubric"
578
+ ? waitingOnGeneratedMessageApproval
579
+ ? "auto-execute-messaging"
552
580
  : "messages"
553
581
  : stepForHeadless === "settings"
554
582
  ? "settings"
@@ -623,6 +651,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
623
651
  enableICPFilters: campaign.enableICPFilters ?? null,
624
652
  activeRubricCount: campaign.leadScoringRubrics?.filter((rubric) => rubric.useCheckForScoring !== false).length ?? 0,
625
653
  hasApprovedMessageTemplate: hasApprovedMessageTemplate(campaign),
654
+ generatedMessageCount: getGeneratedMessageCount(options.messageStats),
655
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(options.messageStats),
656
+ needsApprovalCount: options.messageStats?.needsApprovalCount ?? null,
626
657
  senderCount: campaign.senderIds?.length ?? 0,
627
658
  hasSequenceTemplate: hasSequenceTemplate(campaign),
628
659
  campaignStatus: campaign.campaignStatus ?? campaign.status ?? null,
@@ -696,6 +727,8 @@ export async function getCampaignNavigationState(input) {
696
727
  let selectedLeadListRowCount = null;
697
728
  const warnings = [];
698
729
  let tableChecked = false;
730
+ let messageStatsChecked = false;
731
+ let messageStats = null;
699
732
  if (includeTableCheck &&
700
733
  campaign.selectedLeadListId &&
701
734
  campaign.selectedLeadListId !== campaign.workflowTableId) {
@@ -752,12 +785,37 @@ export async function getCampaignNavigationState(input) {
752
785
  error: error instanceof Error ? error.message : String(error),
753
786
  }, input.campaignId);
754
787
  }
788
+ if (workflowTableAccessible !== false) {
789
+ try {
790
+ messageStats = await api.get(`/api/v3/workflow-tables/${campaign.workflowTableId}/stats`);
791
+ messageStatsChecked = true;
792
+ logNavigationDebug("state.message_stats.success", {
793
+ campaignId: input.campaignId,
794
+ workflowTableId: campaign.workflowTableId,
795
+ generatedMessageCount: getGeneratedMessageCount(messageStats),
796
+ approvedGeneratedMessageCount: getApprovedGeneratedMessageCount(messageStats),
797
+ needsApprovalCount: messageStats.needsApprovalCount ?? null,
798
+ }, input.campaignId);
799
+ }
800
+ catch (error) {
801
+ messageStatsChecked = false;
802
+ messageStats = null;
803
+ warnings.push(`Workflow table message stats could not be checked. Detail: ${error instanceof Error ? error.message : String(error)}`);
804
+ logNavigationDebug("state.message_stats.error", {
805
+ campaignId: input.campaignId,
806
+ workflowTableId: campaign.workflowTableId,
807
+ error: error instanceof Error ? error.message : String(error),
808
+ }, input.campaignId);
809
+ }
810
+ }
755
811
  }
756
812
  const result = computeCampaignNavigationStateFromCampaign(campaign, {
757
813
  includeTableCheck,
758
814
  tableChecked,
759
815
  rowCount: tableRowCount,
760
816
  hasWorkflowRows,
817
+ messageStatsChecked,
818
+ messageStats,
761
819
  selectedLeadListChecked,
762
820
  selectedLeadListAccessible,
763
821
  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.201",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",