@sellable/mcp 0.1.0

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.
Files changed (200) hide show
  1. package/.claude-plugin/plugin.json +12 -0
  2. package/.mcp.json +9 -0
  3. package/README.md +355 -0
  4. package/dist/api.d.ts +21 -0
  5. package/dist/api.js +73 -0
  6. package/dist/auth.d.ts +60 -0
  7. package/dist/auth.js +246 -0
  8. package/dist/engage-memory.d.ts +63 -0
  9. package/dist/engage-memory.js +354 -0
  10. package/dist/index-dev.d.ts +2 -0
  11. package/dist/index-dev.js +17 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.js +8 -0
  14. package/dist/server.d.ts +1 -0
  15. package/dist/server.js +499 -0
  16. package/dist/skills.d.ts +11 -0
  17. package/dist/skills.js +97 -0
  18. package/dist/tools/auth.d.ts +30 -0
  19. package/dist/tools/auth.js +124 -0
  20. package/dist/tools/blueprint-commit.d.ts +174 -0
  21. package/dist/tools/blueprint-commit.js +286 -0
  22. package/dist/tools/bootstrap.d.ts +64 -0
  23. package/dist/tools/bootstrap.js +246 -0
  24. package/dist/tools/campaigns.d.ts +589 -0
  25. package/dist/tools/campaigns.js +892 -0
  26. package/dist/tools/cells.d.ts +58 -0
  27. package/dist/tools/cells.js +48 -0
  28. package/dist/tools/context.d.ts +88 -0
  29. package/dist/tools/context.js +271 -0
  30. package/dist/tools/csv-domains.d.ts +73 -0
  31. package/dist/tools/csv-domains.js +464 -0
  32. package/dist/tools/csv-linkedin.d.ts +102 -0
  33. package/dist/tools/csv-linkedin.js +712 -0
  34. package/dist/tools/direct-campaigns.d.ts +240 -0
  35. package/dist/tools/direct-campaigns.js +250 -0
  36. package/dist/tools/engage-bootstrap.d.ts +94 -0
  37. package/dist/tools/engage-bootstrap.js +205 -0
  38. package/dist/tools/engage-discovery.d.ts +78 -0
  39. package/dist/tools/engage-discovery.js +150 -0
  40. package/dist/tools/engage-memory.d.ts +181 -0
  41. package/dist/tools/engage-memory.js +143 -0
  42. package/dist/tools/engage-state.d.ts +72 -0
  43. package/dist/tools/engage-state.js +62 -0
  44. package/dist/tools/enrichment.d.ts +167 -0
  45. package/dist/tools/enrichment.js +174 -0
  46. package/dist/tools/flow-preflight.d.ts +68 -0
  47. package/dist/tools/flow-preflight.js +138 -0
  48. package/dist/tools/framework.d.ts +44 -0
  49. package/dist/tools/framework.js +153 -0
  50. package/dist/tools/interaction-mode.d.ts +27 -0
  51. package/dist/tools/interaction-mode.js +102 -0
  52. package/dist/tools/leads.d.ts +2417 -0
  53. package/dist/tools/leads.js +2307 -0
  54. package/dist/tools/linkedin.d.ts +210 -0
  55. package/dist/tools/linkedin.js +229 -0
  56. package/dist/tools/navigation.d.ts +91 -0
  57. package/dist/tools/navigation.js +381 -0
  58. package/dist/tools/one-off.d.ts +229 -0
  59. package/dist/tools/one-off.js +273 -0
  60. package/dist/tools/processing.d.ts +70 -0
  61. package/dist/tools/processing.js +56 -0
  62. package/dist/tools/prompts.d.ts +211 -0
  63. package/dist/tools/prompts.js +210 -0
  64. package/dist/tools/provider-preflight.d.ts +21 -0
  65. package/dist/tools/provider-preflight.js +59 -0
  66. package/dist/tools/readiness.d.ts +261 -0
  67. package/dist/tools/readiness.js +510 -0
  68. package/dist/tools/rows.d.ts +126 -0
  69. package/dist/tools/rows.js +105 -0
  70. package/dist/tools/rubrics.d.ts +497 -0
  71. package/dist/tools/rubrics.js +681 -0
  72. package/dist/tools/senders.d.ts +44 -0
  73. package/dist/tools/senders.js +69 -0
  74. package/dist/tools/sequencer.d.ts +127 -0
  75. package/dist/tools/sequencer.js +194 -0
  76. package/dist/tools/tables.d.ts +35 -0
  77. package/dist/tools/tables.js +36 -0
  78. package/dist/tools/verify-row.d.ts +36 -0
  79. package/dist/tools/verify-row.js +38 -0
  80. package/dist/tools/workspaces.d.ts +140 -0
  81. package/dist/tools/workspaces.js +139 -0
  82. package/dist/utils/workspace-root.d.ts +1 -0
  83. package/dist/utils/workspace-root.js +39 -0
  84. package/package.json +46 -0
  85. package/skills/building-gtm-tables/SKILL.md +216 -0
  86. package/skills/building-gtm-tables/core/auto-execute.yaml +19 -0
  87. package/skills/building-gtm-tables/core/blueprint-schema.json +72 -0
  88. package/skills/building-gtm-tables/references/brief-to-blueprint.md +334 -0
  89. package/skills/building-gtm-tables/references/column-type-catalog.md +318 -0
  90. package/skills/building-gtm-tables/references/common-blueprints.fixtures.ts +199 -0
  91. package/skills/building-gtm-tables/references/common-blueprints.md +44 -0
  92. package/skills/building-gtm-tables/references/failure-taxonomy.md +197 -0
  93. package/skills/building-gtm-tables/references/uat-seed-prompts.md +37 -0
  94. package/skills/building-gtm-tables/references/verify-loop.md +74 -0
  95. package/skills/campaign-messages/SKILL.md +173 -0
  96. package/skills/campaign-messages/flow.v1.json +75 -0
  97. package/skills/craft-message/SKILL.md +401 -0
  98. package/skills/create-campaign/ARCHITECTURE.md +232 -0
  99. package/skills/create-campaign/DISCUSS.md +296 -0
  100. package/skills/create-campaign/FLOW_ASCII.md +240 -0
  101. package/skills/create-campaign/HOST-PARITY-CHECKLIST.md +49 -0
  102. package/skills/create-campaign/README.md +142 -0
  103. package/skills/create-campaign/SKILL.md +286 -0
  104. package/skills/create-campaign/context/README.md +67 -0
  105. package/skills/create-campaign/context/_TEMPLATE.md +12 -0
  106. package/skills/create-campaign/context/context.md +35 -0
  107. package/skills/create-campaign/context/learnings.md +16 -0
  108. package/skills/create-campaign/context/registry.json +19 -0
  109. package/skills/create-campaign/core/flow.v1.json +217 -0
  110. package/skills/create-campaign/core/policy.md +191 -0
  111. package/skills/create-campaign/core/providers/apollo.json +35 -0
  112. package/skills/create-campaign/core/providers/prospeo.json +34 -0
  113. package/skills/create-campaign/core/providers/registry.json +31 -0
  114. package/skills/create-campaign/core/providers/sales-nav.json +37 -0
  115. package/skills/create-campaign/core/providers/signal-discovery.json +42 -0
  116. package/skills/create-campaign/references/brief-template.md +64 -0
  117. package/skills/create-campaign/references/campaign-quality.md +84 -0
  118. package/skills/create-campaign/references/copy-calibration-examples.md +120 -0
  119. package/skills/create-campaign/references/offer-patterns.md +108 -0
  120. package/skills/create-campaign/references/provider-selection-strategy.md +212 -0
  121. package/skills/create-campaign/references/question-examples.md +167 -0
  122. package/skills/create-campaign/references/token-fill-examples.md +81 -0
  123. package/skills/create-campaign-brief/ARCHITECTURE.md +72 -0
  124. package/skills/create-campaign-brief/DISCUSS.md +64 -0
  125. package/skills/create-campaign-brief/README.md +176 -0
  126. package/skills/create-campaign-brief/SKILL.md +537 -0
  127. package/skills/create-campaign-brief/references/brief-synthesis-rules.md +100 -0
  128. package/skills/create-campaign-brief/references/brief-template.md +220 -0
  129. package/skills/create-campaign-brief/references/campaign-idea-options.md +30 -0
  130. package/skills/create-campaign-brief/references/copy-appendix-template.md +62 -0
  131. package/skills/create-campaign-brief/references/draft-lifecycle.md +23 -0
  132. package/skills/create-campaign-brief/references/examples/MANIFEST.json +89 -0
  133. package/skills/create-campaign-brief/references/examples/briefs/clover.md +223 -0
  134. package/skills/create-campaign-brief/references/examples/briefs/galley.md +222 -0
  135. package/skills/create-campaign-brief/references/examples/briefs/gelee.md +220 -0
  136. package/skills/create-campaign-brief/references/examples/briefs/hey-digital.md +234 -0
  137. package/skills/create-campaign-brief/references/examples/briefs/persona.md +231 -0
  138. package/skills/create-campaign-brief/references/examples/briefs/revvix.md +220 -0
  139. package/skills/create-campaign-brief/references/examples/briefs/sellable-dev.md +220 -0
  140. package/skills/create-campaign-brief/references/examples/briefs/superposition.md +233 -0
  141. package/skills/create-campaign-brief/references/examples/briefs/superpower.md +219 -0
  142. package/skills/create-campaign-brief/references/examples/briefs/westpark-villas.md +220 -0
  143. package/skills/create-campaign-brief/references/icp-lock-question-bank.md +43 -0
  144. package/skills/create-campaign-brief/references/messaging-inputs.md +58 -0
  145. package/skills/create-campaign-brief/references/output-acceptance-rubric.md +62 -0
  146. package/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md +248 -0
  147. package/skills/create-campaign-brief/references/phase75-canonical-brief-template.md +319 -0
  148. package/skills/create-campaign-brief/references/phase75-good-brief-and-messaging-examples.md +445 -0
  149. package/skills/create-campaign-brief/references/quick-research-protocol.md +39 -0
  150. package/skills/create-campaign-brief/references/reference-sheet-protocol.md +60 -0
  151. package/skills/create-campaign-brief/references/zero-shot-iteration-rules.md +66 -0
  152. package/skills/create-campaign-v2/SKILL.md +1619 -0
  153. package/skills/create-campaign-v2/core/auto-execute.README.md +219 -0
  154. package/skills/create-campaign-v2/core/auto-execute.yaml +121 -0
  155. package/skills/create-campaign-v2/core/flow.v2.json +1643 -0
  156. package/skills/create-campaign-v2/core/policy.md +82 -0
  157. package/skills/create-campaign-v2/references/ai-tells.md +253 -0
  158. package/skills/create-campaign-v2/references/approval-gate-framing.md +346 -0
  159. package/skills/create-campaign-v2/references/draft-lifecycle.md +110 -0
  160. package/skills/create-campaign-v2/references/escalation-ladder.md +119 -0
  161. package/skills/create-campaign-v2/references/filter-leads.md +495 -0
  162. package/skills/create-campaign-v2/references/final-handoff-contract.md +176 -0
  163. package/skills/create-campaign-v2/references/gold-standard-message-examples.md +394 -0
  164. package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +314 -0
  165. package/skills/create-campaign-v2/references/gold-standard-message-validation-example.md +212 -0
  166. package/skills/create-campaign-v2/references/lead-validation-preview.md +172 -0
  167. package/skills/create-campaign-v2/references/parallel-critique-protocol.md +368 -0
  168. package/skills/create-campaign-v2/references/sample-validation-loop.md +289 -0
  169. package/skills/create-campaign-v2/references/step-13-import-leads.md +151 -0
  170. package/skills/create-campaign-v2/references/step-15-re-cascade.md +90 -0
  171. package/skills/create-campaign-v2/references/thomas-revision-filters.md +521 -0
  172. package/skills/create-campaign-v2/references/thomas-variant-selection.md +202 -0
  173. package/skills/create-campaign-v2/references/tier-routing-matrix.md +66 -0
  174. package/skills/create-campaign-v2/references/validation-criteria.md +367 -0
  175. package/skills/create-campaign-v2/references/watch-link-handoff.md +106 -0
  176. package/skills/create-campaign-v2-validation/SKILL.md +296 -0
  177. package/skills/create-post/SKILL.md +1308 -0
  178. package/skills/create-rubric/SKILL.md +251 -0
  179. package/skills/engage/SKILL.md +549 -0
  180. package/skills/engage/core/README.md +23 -0
  181. package/skills/engage/core/proven-searches.json +11 -0
  182. package/skills/engage/core/style-guide.template.md +47 -0
  183. package/skills/engage/core/tracked-people.json +10 -0
  184. package/skills/enrich-prospects/SKILL.md +97 -0
  185. package/skills/find-leads/SKILL.md +467 -0
  186. package/skills/generate-messages/SKILL.md +2361 -0
  187. package/skills/interview/SKILL.md +132 -0
  188. package/skills/interview/core/ENGAGE_STYLE_GUIDE.template.md +54 -0
  189. package/skills/interview/core/ICP.template.md +54 -0
  190. package/skills/interview/core/VOICE_PROFILE.template.md +101 -0
  191. package/skills/providers/apollo.md +520 -0
  192. package/skills/providers/prospeo.md +398 -0
  193. package/skills/providers/sales-nav.md +372 -0
  194. package/skills/providers/signal-discovery.md +495 -0
  195. package/skills/research/SKILL.md +258 -0
  196. package/skills/research/config.json +9 -0
  197. package/skills/research/override.md +13 -0
  198. package/skills/research-prospect/SKILL.md +99 -0
  199. package/skills/research-sender/SKILL.md +158 -0
  200. package/skills/workflow-sequences/SKILL.md +85 -0
@@ -0,0 +1,58 @@
1
+ export interface UpdateCellResult {
2
+ success: boolean;
3
+ cellId: string;
4
+ isOverridden: boolean;
5
+ }
6
+ export declare const cellToolDefinitions: ({
7
+ name: string;
8
+ description: string;
9
+ inputSchema: {
10
+ type: string;
11
+ properties: {
12
+ cellId: {
13
+ type: string;
14
+ description: string;
15
+ };
16
+ value: {
17
+ oneOf: {
18
+ type: string;
19
+ }[];
20
+ description: string;
21
+ };
22
+ tableId?: undefined;
23
+ cellIds?: undefined;
24
+ };
25
+ required: string[];
26
+ };
27
+ } | {
28
+ name: string;
29
+ description: string;
30
+ inputSchema: {
31
+ type: string;
32
+ properties: {
33
+ tableId: {
34
+ type: string;
35
+ description: string;
36
+ };
37
+ cellIds: {
38
+ type: string;
39
+ items: {
40
+ type: string;
41
+ };
42
+ description: string;
43
+ };
44
+ cellId?: undefined;
45
+ value?: undefined;
46
+ };
47
+ required: string[];
48
+ };
49
+ })[];
50
+ export declare function updateCell(cellId: string, value: string | boolean | object): Promise<UpdateCellResult>;
51
+ export interface QueueCellsResult {
52
+ queued: number;
53
+ dispatched?: number;
54
+ failed?: number;
55
+ skipped?: number;
56
+ message?: string;
57
+ }
58
+ export declare function queueCells(tableId: string, cellIds: string[]): Promise<QueueCellsResult>;
@@ -0,0 +1,48 @@
1
+ import { getApi } from "../api.js";
2
+ export const cellToolDefinitions = [
3
+ {
4
+ name: "update_cell",
5
+ description: "Update a cell's value. Use for saving crafted messages (messageCellId/subjectCellId), marking examples (exampleCellId with value: true/false), or approving for send (approveCellId with value: true).",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ cellId: {
10
+ type: "string",
11
+ description: "Cell ID (messageCellId/subjectCellId, exampleCellId, or approveCellId from row)",
12
+ },
13
+ value: {
14
+ oneOf: [{ type: "string" }, { type: "boolean" }, { type: "object" }],
15
+ description: "Value to set. String for messages, true for approval.",
16
+ },
17
+ },
18
+ required: ["cellId", "value"],
19
+ },
20
+ },
21
+ {
22
+ name: "queue_cells",
23
+ description: "Queue cells for processing (enrichment, ICP scoring, etc). Use with cell IDs from get_rows_minimal (enrichCellId, icpCellId).",
24
+ inputSchema: {
25
+ type: "object",
26
+ properties: {
27
+ tableId: {
28
+ type: "string",
29
+ description: "Workflow table ID",
30
+ },
31
+ cellIds: {
32
+ type: "array",
33
+ items: { type: "string" },
34
+ description: "Cell IDs to queue for processing",
35
+ },
36
+ },
37
+ required: ["tableId", "cellIds"],
38
+ },
39
+ },
40
+ ];
41
+ export async function updateCell(cellId, value) {
42
+ const api = getApi();
43
+ return api.patch(`/api/v3/workflow-tables/cells/${cellId}/update-result`, { value });
44
+ }
45
+ export async function queueCells(tableId, cellIds) {
46
+ const api = getApi();
47
+ return api.post(`/api/v3/workflow-tables/cells/queue-batch`, { tableId, cellIds });
48
+ }
@@ -0,0 +1,88 @@
1
+ import { getCampaignNavigationState, type CampaignOfferNavigation } from "./navigation.js";
2
+ type GetCampaignContextInput = {
3
+ campaignId: string;
4
+ flowVersion?: "v1" | "v2";
5
+ refresh?: boolean;
6
+ includeTableCheck?: boolean;
7
+ };
8
+ type FrameworkSnapshot = {
9
+ flowVersion: string;
10
+ providerRegistry: unknown;
11
+ providers: Record<string, unknown>;
12
+ overrides: Record<string, unknown>;
13
+ warnings: string[];
14
+ };
15
+ type CampaignContextEntry = {
16
+ campaignId: string;
17
+ flowVersion: "v1" | "v2";
18
+ framework: FrameworkSnapshot;
19
+ navState: Awaited<ReturnType<typeof getCampaignNavigationState>>;
20
+ providerConfig: unknown | null;
21
+ cachedAt: string;
22
+ dirty: boolean;
23
+ dirtyReasons: string[];
24
+ };
25
+ export declare function hydrateCampaignContextFromCampaign(campaign: CampaignOfferNavigation, reason: string): CampaignContextEntry;
26
+ export declare function hydrateCampaignContextFromNavigation(navState: Awaited<ReturnType<typeof getCampaignNavigationState>>, reason: string): CampaignContextEntry;
27
+ export declare function markCampaignContextDirty(campaignId: string, reason: string): void;
28
+ export declare const contextToolDefinitions: {
29
+ name: string;
30
+ description: string;
31
+ inputSchema: {
32
+ type: string;
33
+ properties: {
34
+ campaignId: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ flowVersion: {
39
+ type: string;
40
+ enum: string[];
41
+ description: string;
42
+ };
43
+ refresh: {
44
+ type: string;
45
+ description: string;
46
+ };
47
+ includeTableCheck: {
48
+ type: string;
49
+ description: string;
50
+ };
51
+ };
52
+ required: string[];
53
+ additionalProperties: boolean;
54
+ };
55
+ }[];
56
+ export declare function getCampaignContext(input: GetCampaignContextInput): Promise<{
57
+ campaignId: string;
58
+ flowVersion: "v1" | "v2";
59
+ cachedAt: string;
60
+ refreshed: boolean;
61
+ dirty: boolean;
62
+ dirtyReasons: string[];
63
+ navigation: {
64
+ campaignId: string;
65
+ computedStep: "campaign-created" | "pick-provider" | "provider-search" | "confirm-lead-list";
66
+ blockedAt: ("campaign-created" | "pick-provider" | "provider-search" | "confirm-lead-list") | null;
67
+ missing: string[];
68
+ expectedHeadlessStep: string | null;
69
+ headlessCurrentStep: string | null;
70
+ uiStep: string | null;
71
+ table: {
72
+ workflowTableId: string | null;
73
+ checked: boolean;
74
+ rowCount: number | null;
75
+ hasRows: boolean | null;
76
+ };
77
+ context: {
78
+ leadSourceType: string | null;
79
+ leadSourceProvider: string | null;
80
+ selectedLeadListId: string | null;
81
+ providerCurrentStep: string | null;
82
+ };
83
+ warnings: string[];
84
+ };
85
+ providerConfig: unknown;
86
+ framework: FrameworkSnapshot;
87
+ }>;
88
+ export {};
@@ -0,0 +1,271 @@
1
+ import { getCampaignFramework } from "./framework.js";
2
+ import { computeCampaignNavigationStateFromCampaign, getCampaignNavigationState, logNavigationDebug, } from "./navigation.js";
3
+ const frameworkCache = new Map();
4
+ const campaignContextCache = new Map();
5
+ function frameworkCacheKey(flowVersion) {
6
+ return `flow:${flowVersion}`;
7
+ }
8
+ function getFrameworkSnapshot(flowVersion, force = false) {
9
+ const key = frameworkCacheKey(flowVersion);
10
+ if (!force) {
11
+ const cached = frameworkCache.get(key);
12
+ if (cached)
13
+ return cached;
14
+ }
15
+ const framework = getCampaignFramework({
16
+ flowVersion,
17
+ includePlugins: true,
18
+ });
19
+ const snapshot = {
20
+ flowVersion: framework.flowVersion,
21
+ providerRegistry: framework.providerRegistry,
22
+ providers: framework.providers,
23
+ overrides: framework.overrides,
24
+ warnings: framework.warnings,
25
+ };
26
+ frameworkCache.set(key, snapshot);
27
+ return snapshot;
28
+ }
29
+ function deriveProviderConfig(framework, navState) {
30
+ const providerId = navState.context.leadSourceProvider;
31
+ if (!providerId)
32
+ return null;
33
+ return framework.providers[providerId] ?? null;
34
+ }
35
+ export function hydrateCampaignContextFromCampaign(campaign, reason) {
36
+ logNavigationDebug("context.hydrate_from_campaign.start", {
37
+ campaignId: campaign.id,
38
+ reason,
39
+ currentStep: campaign.currentStep ?? null,
40
+ workflowTableId: campaign.workflowTableId ?? null,
41
+ leadSourceProvider: campaign.leadSourceProvider ?? null,
42
+ }, campaign.id);
43
+ const flowVersion = "v1";
44
+ const framework = getFrameworkSnapshot(flowVersion);
45
+ const navState = computeCampaignNavigationStateFromCampaign(campaign, {
46
+ includeTableCheck: false,
47
+ tableChecked: false,
48
+ rowCount: null,
49
+ hasWorkflowRows: null,
50
+ });
51
+ const providerConfig = deriveProviderConfig(framework, navState);
52
+ const entry = {
53
+ campaignId: campaign.id,
54
+ flowVersion,
55
+ framework,
56
+ navState,
57
+ providerConfig,
58
+ cachedAt: new Date().toISOString(),
59
+ dirty: false,
60
+ dirtyReasons: [],
61
+ };
62
+ campaignContextCache.set(campaign.id, entry);
63
+ logNavigationDebug("context.hydrate_from_campaign.complete", {
64
+ campaignId: campaign.id,
65
+ reason,
66
+ computedStep: navState.computedStep,
67
+ blockedAt: navState.blockedAt,
68
+ missing: navState.missing,
69
+ providerConfigResolved: Boolean(providerConfig),
70
+ }, campaign.id);
71
+ return entry;
72
+ }
73
+ export function hydrateCampaignContextFromNavigation(navState, reason) {
74
+ logNavigationDebug("context.hydrate_from_navigation.start", {
75
+ campaignId: navState.campaignId,
76
+ reason,
77
+ computedStep: navState.computedStep,
78
+ blockedAt: navState.blockedAt,
79
+ missing: navState.missing,
80
+ }, navState.campaignId);
81
+ const flowVersion = "v1";
82
+ const framework = getFrameworkSnapshot(flowVersion);
83
+ const providerConfig = deriveProviderConfig(framework, navState);
84
+ const entry = {
85
+ campaignId: navState.campaignId,
86
+ flowVersion,
87
+ framework,
88
+ navState,
89
+ providerConfig,
90
+ cachedAt: new Date().toISOString(),
91
+ dirty: false,
92
+ dirtyReasons: [],
93
+ };
94
+ campaignContextCache.set(navState.campaignId, entry);
95
+ logNavigationDebug("context.hydrate_from_navigation.complete", {
96
+ campaignId: navState.campaignId,
97
+ reason,
98
+ providerConfigResolved: Boolean(providerConfig),
99
+ warnings: navState.warnings,
100
+ }, navState.campaignId);
101
+ return entry;
102
+ }
103
+ async function refreshCampaignContext(campaignId, flowVersion, options) {
104
+ logNavigationDebug("context.refresh.start", {
105
+ campaignId,
106
+ flowVersion,
107
+ forceFramework: options.forceFramework === true,
108
+ includeTableCheck: options.includeTableCheck,
109
+ }, campaignId);
110
+ const framework = getFrameworkSnapshot(flowVersion, options.forceFramework);
111
+ const navState = await getCampaignNavigationState({
112
+ campaignId,
113
+ includeTableCheck: options.includeTableCheck,
114
+ });
115
+ const providerConfig = deriveProviderConfig(framework, navState);
116
+ const entry = {
117
+ campaignId,
118
+ flowVersion,
119
+ framework,
120
+ navState,
121
+ providerConfig,
122
+ cachedAt: new Date().toISOString(),
123
+ dirty: false,
124
+ dirtyReasons: [],
125
+ };
126
+ campaignContextCache.set(campaignId, entry);
127
+ logNavigationDebug("context.refresh.complete", {
128
+ campaignId,
129
+ flowVersion,
130
+ computedStep: navState.computedStep,
131
+ blockedAt: navState.blockedAt,
132
+ missing: navState.missing,
133
+ providerConfigResolved: Boolean(providerConfig),
134
+ }, campaignId);
135
+ return entry;
136
+ }
137
+ export function markCampaignContextDirty(campaignId, reason) {
138
+ const existing = campaignContextCache.get(campaignId);
139
+ if (existing) {
140
+ existing.dirty = true;
141
+ if (!existing.dirtyReasons.includes(reason)) {
142
+ existing.dirtyReasons.push(reason);
143
+ }
144
+ logNavigationDebug("context.mark_dirty.updated", {
145
+ campaignId,
146
+ reason,
147
+ dirtyReasons: existing.dirtyReasons,
148
+ }, campaignId);
149
+ return;
150
+ }
151
+ // No cached entry yet; record that we should refresh on first request.
152
+ campaignContextCache.set(campaignId, {
153
+ campaignId,
154
+ flowVersion: "v1",
155
+ framework: {
156
+ flowVersion: "v1",
157
+ providerRegistry: null,
158
+ providers: {},
159
+ overrides: {},
160
+ warnings: ["frameworkNotLoaded"],
161
+ },
162
+ navState: {
163
+ campaignId,
164
+ computedStep: "campaign-created",
165
+ blockedAt: "campaign-created",
166
+ missing: ["campaignContextNotLoaded"],
167
+ expectedHeadlessStep: "create-offer",
168
+ headlessCurrentStep: null,
169
+ uiStep: "plan",
170
+ table: {
171
+ workflowTableId: null,
172
+ checked: false,
173
+ rowCount: null,
174
+ hasRows: null,
175
+ },
176
+ context: {
177
+ leadSourceType: null,
178
+ leadSourceProvider: null,
179
+ selectedLeadListId: null,
180
+ providerCurrentStep: null,
181
+ },
182
+ warnings: [],
183
+ },
184
+ providerConfig: null,
185
+ cachedAt: new Date().toISOString(),
186
+ dirty: true,
187
+ dirtyReasons: [reason],
188
+ });
189
+ logNavigationDebug("context.mark_dirty.seeded", {
190
+ campaignId,
191
+ reason,
192
+ }, campaignId);
193
+ }
194
+ export const contextToolDefinitions = [
195
+ {
196
+ name: "get_campaign_context",
197
+ description: "Return cached create-campaign context (framework snapshot + navigation diagnostics). Refreshes automatically when state is marked dirty.",
198
+ inputSchema: {
199
+ type: "object",
200
+ properties: {
201
+ campaignId: {
202
+ type: "string",
203
+ description: "Campaign offer ID",
204
+ },
205
+ flowVersion: {
206
+ type: "string",
207
+ enum: ["v1", "v2"],
208
+ description: "Framework flow version (default: v1)",
209
+ },
210
+ refresh: {
211
+ type: "boolean",
212
+ description: "Force a refresh of campaign state and framework snapshot before returning context.",
213
+ },
214
+ includeTableCheck: {
215
+ type: "boolean",
216
+ description: "When true (default), check workflow table row count using a minimal query.",
217
+ },
218
+ },
219
+ required: ["campaignId"],
220
+ additionalProperties: false,
221
+ },
222
+ },
223
+ ];
224
+ export async function getCampaignContext(input) {
225
+ const flowVersion = input.flowVersion || "v1";
226
+ const includeTableCheck = input.includeTableCheck !== false;
227
+ const refreshRequested = input.refresh === true;
228
+ const cached = campaignContextCache.get(input.campaignId);
229
+ const shouldRefresh = refreshRequested ||
230
+ !cached ||
231
+ cached.flowVersion !== flowVersion ||
232
+ cached.dirty;
233
+ logNavigationDebug("context.get.start", {
234
+ campaignId: input.campaignId,
235
+ flowVersion,
236
+ includeTableCheck,
237
+ refreshRequested,
238
+ hasCachedEntry: Boolean(cached),
239
+ cachedFlowVersion: cached?.flowVersion ?? null,
240
+ cachedDirty: cached?.dirty ?? null,
241
+ cachedDirtyReasons: cached?.dirtyReasons ?? [],
242
+ shouldRefresh,
243
+ }, input.campaignId);
244
+ const entry = shouldRefresh
245
+ ? await refreshCampaignContext(input.campaignId, flowVersion, {
246
+ forceFramework: refreshRequested,
247
+ includeTableCheck,
248
+ })
249
+ : cached;
250
+ logNavigationDebug("context.get.complete", {
251
+ campaignId: entry.campaignId,
252
+ refreshed: shouldRefresh,
253
+ cachedAt: entry.cachedAt,
254
+ dirty: entry.dirty,
255
+ dirtyReasons: entry.dirtyReasons,
256
+ computedStep: entry.navState.computedStep,
257
+ blockedAt: entry.navState.blockedAt,
258
+ missing: entry.navState.missing,
259
+ }, entry.campaignId);
260
+ return {
261
+ campaignId: entry.campaignId,
262
+ flowVersion: entry.flowVersion,
263
+ cachedAt: entry.cachedAt,
264
+ refreshed: shouldRefresh,
265
+ dirty: entry.dirty,
266
+ dirtyReasons: entry.dirtyReasons,
267
+ navigation: entry.navState,
268
+ providerConfig: entry.providerConfig,
269
+ framework: entry.framework,
270
+ };
271
+ }
@@ -0,0 +1,73 @@
1
+ export declare const MAX_CSV_DOMAIN_UPLOAD_BYTES: number;
2
+ export declare const MAX_CSV_DOMAIN_UPLOAD_ROWS = 7500;
3
+ export declare const MAX_CSV_DOMAIN_UPLOAD_UNIQUE_DOMAINS = 1000;
4
+ export declare const MAX_CSV_DOMAIN_CARRY_COLUMNS = 20;
5
+ declare const CONFIRMATION_TOKEN_VERSION = "csv-domain-preview-v1";
6
+ export type CsvDomainLimits = {
7
+ maxBytes: number;
8
+ maxRows: number;
9
+ maxUniqueDomains: number;
10
+ maxCarryColumns: number;
11
+ };
12
+ export type CsvDomainPreview = {
13
+ resolvedFilePath: string;
14
+ headers: string[];
15
+ detectedDomainColumn: string | null;
16
+ candidateDomainColumns: string[];
17
+ needsDomainColumnSelection: boolean;
18
+ suggestedCarryoverColumns: string[];
19
+ selectedColumns: string[];
20
+ totalRows: number;
21
+ rowsWithChosenDomainValue: number;
22
+ uniqueCandidateDomains: number;
23
+ duplicateDomainCount: number;
24
+ invalidDomainCount: number;
25
+ truncatedDomainCount: number;
26
+ emptySelectedDomainRowCount: number;
27
+ duplicatePolicy: "last_wins";
28
+ limits: CsvDomainLimits;
29
+ warnings: string[];
30
+ blockingErrors: string[];
31
+ confirmationToken: string | null;
32
+ };
33
+ export type CsvDomainConfirmationPayload = {
34
+ version: typeof CONFIRMATION_TOKEN_VERSION;
35
+ filePath: string;
36
+ fileSizeBytes: number;
37
+ fileMtimeMs: number;
38
+ domainColumn: string;
39
+ selectedColumns: string[];
40
+ };
41
+ export type CsvDomainPreviewBuild = {
42
+ preview: CsvDomainPreview;
43
+ fileSizeBytes: number;
44
+ fileMtimeMs: number;
45
+ resolvedDomainColumn: string | null;
46
+ parsedRows: Array<Record<string, string>>;
47
+ keptCandidateDomains: string[];
48
+ };
49
+ type ParseCsvDomainFileInput = {
50
+ filePath: string;
51
+ workspaceRoot?: string;
52
+ };
53
+ type BuildCsvDomainPreviewInput = ParseCsvDomainFileInput & {
54
+ domainColumn?: string;
55
+ selectedColumns?: string[];
56
+ };
57
+ type ParsedCsvDomainFile = {
58
+ resolvedFilePath: string;
59
+ fileSizeBytes: number;
60
+ fileMtimeMs: number;
61
+ headers: string[];
62
+ rows: Array<Record<string, string>>;
63
+ totalRows: number;
64
+ blockingErrors: string[];
65
+ warnings: string[];
66
+ };
67
+ export declare function makeConfirmationToken(payload: CsvDomainConfirmationPayload): string;
68
+ export declare function parseConfirmationToken(token: string): CsvDomainConfirmationPayload;
69
+ export declare function matchesConfirmationToken(token: string, payload: CsvDomainConfirmationPayload): boolean;
70
+ export declare function parseCsvDomainFile(input: ParseCsvDomainFileInput): ParsedCsvDomainFile;
71
+ export declare function buildCsvDomainPreview(input: BuildCsvDomainPreviewInput): CsvDomainPreviewBuild;
72
+ export declare function projectCsvCarryRows(previewBuild: CsvDomainPreviewBuild): Array<Record<string, string>>;
73
+ export {};