@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,124 @@
1
+ import { getApi, SellableApiError } from "../api.js";
2
+ import { getConfig, getConfigPath } from "../auth.js";
3
+ function maskToken(token) {
4
+ if (token.length <= 10)
5
+ return `${token.slice(0, 4)}...`;
6
+ return `${token.slice(0, 8)}...${token.slice(-2)}`;
7
+ }
8
+ export const authToolDefinitions = [
9
+ {
10
+ name: "get_auth_status",
11
+ description: "Verify Sellable authentication early. Call this before any campaign work. Returns ok=false with clear guidance when the token is missing, revoked, or the active workspace is not set. IMPORTANT: When auth succeeds, ALWAYS tell the user the _userNotice message so they know which workspace is active.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {},
15
+ required: [],
16
+ additionalProperties: false,
17
+ },
18
+ },
19
+ ];
20
+ export async function getAuthStatus() {
21
+ const configPath = getConfigPath();
22
+ const checkedAt = new Date().toISOString();
23
+ const base = {
24
+ ok: false,
25
+ configPath,
26
+ activeEnvName: null,
27
+ apiUrl: null,
28
+ activeWorkspaceId: null,
29
+ activeWorkspaceName: null,
30
+ tokenPrefix: null,
31
+ workspacesCount: null,
32
+ _userNotice: null,
33
+ checkedAt,
34
+ };
35
+ try {
36
+ const config = getConfig();
37
+ base.activeEnvName = config.activeEnvName || null;
38
+ const api = getApi();
39
+ const { workspaces } = await api.get("/api/v3/workspaces");
40
+ const activeWorkspaceId = config.activeWorkspaceId || config.workspaceId || null;
41
+ const activeWorkspace = activeWorkspaceId
42
+ ? workspaces.find((ws) => ws.id === activeWorkspaceId)
43
+ : null;
44
+ if (!activeWorkspaceId) {
45
+ return {
46
+ ...base,
47
+ apiUrl: config.apiUrl || null,
48
+ tokenPrefix: maskToken(config.token),
49
+ workspacesCount: workspaces.length,
50
+ error: {
51
+ type: "workspace",
52
+ message: "No active workspace selected.",
53
+ guidance: "Run list_workspaces then set_active_workspace to choose a workspace.",
54
+ },
55
+ };
56
+ }
57
+ if (!activeWorkspace) {
58
+ const available = workspaces
59
+ .map((ws) => `${ws.name} (${ws.id})`)
60
+ .join(", ");
61
+ return {
62
+ ...base,
63
+ apiUrl: config.apiUrl || null,
64
+ tokenPrefix: maskToken(config.token),
65
+ workspacesCount: workspaces.length,
66
+ error: {
67
+ type: "workspace",
68
+ message: `Active workspace ${activeWorkspaceId} not found in access list.`,
69
+ guidance: available
70
+ ? `Available: ${available}. Run set_active_workspace with a valid ID.`
71
+ : "Run list_workspaces to view available workspaces, then set_active_workspace.",
72
+ },
73
+ };
74
+ }
75
+ const workspaceName = activeWorkspace.name || config.activeWorkspaceName || null;
76
+ const envLabel = config.activeEnvName || null;
77
+ const wsLabel = workspaceName || activeWorkspaceId;
78
+ const notice = envLabel
79
+ ? `Workspace: ${wsLabel} (${envLabel})`
80
+ : `Workspace: ${wsLabel}`;
81
+ return {
82
+ ok: true,
83
+ configPath,
84
+ activeEnvName: envLabel,
85
+ apiUrl: config.apiUrl || null,
86
+ activeWorkspaceId,
87
+ activeWorkspaceName: workspaceName,
88
+ tokenPrefix: maskToken(config.token),
89
+ workspacesCount: workspaces.length,
90
+ _userNotice: notice,
91
+ checkedAt,
92
+ error: null,
93
+ };
94
+ }
95
+ catch (error) {
96
+ if (error instanceof SellableApiError && error.isAuthError) {
97
+ return {
98
+ ...base,
99
+ error: {
100
+ type: "auth",
101
+ status: error.status,
102
+ message: error.body || error.message,
103
+ guidance: error.guidance ||
104
+ `Update ${configPath} with a valid token, then retry get_auth_status.`,
105
+ },
106
+ };
107
+ }
108
+ const message = error instanceof Error ? error.message : String(error);
109
+ const isConfigError = message.includes("Sellable not configured") ||
110
+ message.includes("Invalid JSON") ||
111
+ message.includes("Missing 'token'");
112
+ const guidance = isConfigError
113
+ ? `Create ${configPath} with your token, then run list_workspaces + set_active_workspace.`
114
+ : `Fix the configuration in ${configPath}, then retry get_auth_status.`;
115
+ return {
116
+ ...base,
117
+ error: {
118
+ type: isConfigError ? "config" : "api",
119
+ message,
120
+ guidance,
121
+ },
122
+ };
123
+ }
124
+ }
@@ -0,0 +1,174 @@
1
+ type BlueprintColumn = {
2
+ id: string;
3
+ type: string;
4
+ name: string;
5
+ config: Record<string, unknown>;
6
+ inputMapping?: Record<string, string>;
7
+ runCondition?: string;
8
+ };
9
+ type Blueprint = {
10
+ columns: BlueprintColumn[];
11
+ edges: Array<{
12
+ from: string;
13
+ to: string;
14
+ via: string;
15
+ }>;
16
+ };
17
+ export type CommitBlueprintInput = {
18
+ tableId: string;
19
+ blueprint: Blueprint | string;
20
+ };
21
+ export type AddColumnInput = {
22
+ tableId: string;
23
+ column: BlueprintColumn | string;
24
+ validateOnly?: boolean;
25
+ };
26
+ /**
27
+ * Phase 98 MCP surface (3 new tools — prompt-level tool allowlist must stay ≤ 15):
28
+ *
29
+ * 1. sellable:commit_blueprint
30
+ * validateBlueprint -> commitBlueprint(topo walk) -> TableManagementService.addColumn per node.
31
+ * Input: { tableId: string, blueprint: Blueprint }
32
+ * Output:
33
+ * { ok: true, columnIds: string[] }
34
+ * | { ok: false, errors: BlueprintError[] }
35
+ * | { ok: false, createdColumnIds: string[], failedAt: { columnId, reason }, rolledBack: string[], rollbackFailures: { columnId, reason }[] }
36
+ * | { ok: false, error: "concurrent_commit" }
37
+ *
38
+ * 2. sellable:add_column
39
+ * Validate and optionally add one column outside the blueprint flow.
40
+ *
41
+ * 3. sellable:verify_table_row
42
+ * Run one row end-to-end. Per-column status: success | error | skipped | deferred_to_sweeper | condition_not_met.
43
+ * Skips honor caller-supplied skipColumnIds[]; never heuristics.
44
+ * Forces re-execution via forceRerun:true executor param (does not mutate isOverridden).
45
+ * Honors AbortSignal from the request; aborted mid-run rows are reset to prior terminal state in try/finally.
46
+ *
47
+ * Not included (intentionally):
48
+ * - configure_column: merged into add_column/commit_blueprint.
49
+ * - update_column_run_condition: verify supplies skipColumnIds directly (no runtime runCondition override).
50
+ */
51
+ export declare const blueprintCommitToolDefinitions: ({
52
+ name: string;
53
+ description: string;
54
+ inputSchema: {
55
+ type: string;
56
+ properties: {
57
+ tableId: {
58
+ type: string;
59
+ description: string;
60
+ };
61
+ blueprint: {
62
+ description: string;
63
+ type: string;
64
+ properties: {
65
+ columns: {
66
+ type: string;
67
+ items: {
68
+ type: string;
69
+ properties: {
70
+ id: {
71
+ type: string;
72
+ };
73
+ type: {
74
+ type: string;
75
+ };
76
+ name: {
77
+ type: string;
78
+ };
79
+ config: {
80
+ type: string;
81
+ };
82
+ inputMapping: {
83
+ type: string;
84
+ additionalProperties: {
85
+ type: string;
86
+ };
87
+ };
88
+ runCondition: {
89
+ type: string;
90
+ };
91
+ };
92
+ required: string[];
93
+ additionalProperties: boolean;
94
+ };
95
+ };
96
+ edges: {
97
+ type: string;
98
+ items: {
99
+ type: string;
100
+ properties: {
101
+ from: {
102
+ type: string;
103
+ };
104
+ to: {
105
+ type: string;
106
+ };
107
+ via: {
108
+ type: string;
109
+ };
110
+ };
111
+ required: string[];
112
+ additionalProperties: boolean;
113
+ };
114
+ };
115
+ };
116
+ required: string[];
117
+ additionalProperties: boolean;
118
+ };
119
+ column?: undefined;
120
+ validateOnly?: undefined;
121
+ };
122
+ required: string[];
123
+ };
124
+ } | {
125
+ name: string;
126
+ description: string;
127
+ inputSchema: {
128
+ type: string;
129
+ properties: {
130
+ tableId: {
131
+ type: string;
132
+ description: string;
133
+ };
134
+ column: {
135
+ description: string;
136
+ type: string;
137
+ properties: {
138
+ id: {
139
+ type: string;
140
+ };
141
+ type: {
142
+ type: string;
143
+ };
144
+ name: {
145
+ type: string;
146
+ };
147
+ config: {
148
+ type: string;
149
+ };
150
+ inputMapping: {
151
+ type: string;
152
+ additionalProperties: {
153
+ type: string;
154
+ };
155
+ };
156
+ runCondition: {
157
+ type: string;
158
+ };
159
+ };
160
+ required: string[];
161
+ additionalProperties: boolean;
162
+ };
163
+ validateOnly: {
164
+ type: string;
165
+ description: string;
166
+ };
167
+ blueprint?: undefined;
168
+ };
169
+ required: string[];
170
+ };
171
+ })[];
172
+ export declare function handleCommitBlueprint(input: CommitBlueprintInput): Promise<unknown>;
173
+ export declare function handleAddColumn(input: AddColumnInput): Promise<unknown>;
174
+ export {};
@@ -0,0 +1,286 @@
1
+ import { getApi } from "../api.js";
2
+ const knownBlueprintColumnTypes = new Set([
3
+ "ai_column",
4
+ "checkbox",
5
+ "formula",
6
+ "generate_message",
7
+ "http_request",
8
+ "inbound_webhook",
9
+ "score_icp_mcp",
10
+ "send_dm",
11
+ "send_inmail_closed",
12
+ "send_inmail_open",
13
+ "send_invite",
14
+ "text",
15
+ "view_profile",
16
+ "wait",
17
+ "is_open_profile",
18
+ ]);
19
+ const blueprintColumnInputSchema = {
20
+ type: "object",
21
+ properties: {
22
+ id: { type: "string" },
23
+ type: { type: "string" },
24
+ name: { type: "string" },
25
+ config: { type: "object" },
26
+ inputMapping: {
27
+ type: "object",
28
+ additionalProperties: { type: "string" },
29
+ },
30
+ runCondition: { type: "string" },
31
+ },
32
+ required: ["id", "type", "name", "config"],
33
+ additionalProperties: true,
34
+ };
35
+ const blueprintInputSchema = {
36
+ type: "object",
37
+ properties: {
38
+ columns: {
39
+ type: "array",
40
+ items: blueprintColumnInputSchema,
41
+ },
42
+ edges: {
43
+ type: "array",
44
+ items: {
45
+ type: "object",
46
+ properties: {
47
+ from: { type: "string" },
48
+ to: { type: "string" },
49
+ via: { type: "string" },
50
+ },
51
+ required: ["from", "to", "via"],
52
+ additionalProperties: false,
53
+ },
54
+ },
55
+ },
56
+ required: ["columns", "edges"],
57
+ additionalProperties: false,
58
+ };
59
+ /**
60
+ * Phase 98 MCP surface (3 new tools — prompt-level tool allowlist must stay ≤ 15):
61
+ *
62
+ * 1. sellable:commit_blueprint
63
+ * validateBlueprint -> commitBlueprint(topo walk) -> TableManagementService.addColumn per node.
64
+ * Input: { tableId: string, blueprint: Blueprint }
65
+ * Output:
66
+ * { ok: true, columnIds: string[] }
67
+ * | { ok: false, errors: BlueprintError[] }
68
+ * | { ok: false, createdColumnIds: string[], failedAt: { columnId, reason }, rolledBack: string[], rollbackFailures: { columnId, reason }[] }
69
+ * | { ok: false, error: "concurrent_commit" }
70
+ *
71
+ * 2. sellable:add_column
72
+ * Validate and optionally add one column outside the blueprint flow.
73
+ *
74
+ * 3. sellable:verify_table_row
75
+ * Run one row end-to-end. Per-column status: success | error | skipped | deferred_to_sweeper | condition_not_met.
76
+ * Skips honor caller-supplied skipColumnIds[]; never heuristics.
77
+ * Forces re-execution via forceRerun:true executor param (does not mutate isOverridden).
78
+ * Honors AbortSignal from the request; aborted mid-run rows are reset to prior terminal state in try/finally.
79
+ *
80
+ * Not included (intentionally):
81
+ * - configure_column: merged into add_column/commit_blueprint.
82
+ * - update_column_run_condition: verify supplies skipColumnIds directly (no runtime runCondition override).
83
+ */
84
+ export const blueprintCommitToolDefinitions = [
85
+ {
86
+ name: "commit_blueprint",
87
+ description: "Validate and commit a full workflow-table blueprint (multiple columns + wiring) in one call. Use when you have designed every column up-front. NOT for incremental additions — use add_column for that.",
88
+ inputSchema: {
89
+ type: "object",
90
+ properties: {
91
+ tableId: {
92
+ type: "string",
93
+ description: "Workflow table ID",
94
+ },
95
+ blueprint: {
96
+ ...blueprintInputSchema,
97
+ description: "Blueprint with columns [{id,type,name,config,inputMapping?,runCondition?}] and edges [{from,to,via}]",
98
+ },
99
+ },
100
+ required: ["tableId", "blueprint"],
101
+ },
102
+ },
103
+ {
104
+ name: "add_column",
105
+ description: 'Validate and add a single column to an existing workflow table. Use validateOnly:true to dry-run. Use http_request named "Enrich Prospect" for enrichment, score_icp_mcp for ICP scoring, and generate_message for Sellable message generation. NOT for batch additions — use commit_blueprint.',
106
+ inputSchema: {
107
+ type: "object",
108
+ properties: {
109
+ tableId: {
110
+ type: "string",
111
+ description: "Workflow table ID",
112
+ },
113
+ column: {
114
+ ...blueprintColumnInputSchema,
115
+ description: "Column draft {id,type,name,config,inputMapping?,runCondition?}",
116
+ },
117
+ validateOnly: {
118
+ type: "boolean",
119
+ description: "When true, validate and normalize the column without creating it.",
120
+ },
121
+ },
122
+ required: ["tableId", "column"],
123
+ },
124
+ },
125
+ ];
126
+ function parseJsonObject(value, label) {
127
+ try {
128
+ const parsed = JSON.parse(value);
129
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
130
+ return {
131
+ ok: false,
132
+ error: `${label} JSON must parse to an object`,
133
+ };
134
+ }
135
+ return { ok: true, value: parsed };
136
+ }
137
+ catch (error) {
138
+ return {
139
+ ok: false,
140
+ error: `${label} must be an object or valid JSON object string: ${error instanceof Error ? error.message : "invalid JSON"}`,
141
+ };
142
+ }
143
+ }
144
+ function coerceBlueprint(value) {
145
+ if (typeof value === "string") {
146
+ const parsed = parseJsonObject(value, "blueprint");
147
+ if (!parsed.ok) {
148
+ return {
149
+ ok: false,
150
+ errors: [
151
+ {
152
+ kind: "shape",
153
+ message: parsed.error,
154
+ zodIssues: [],
155
+ },
156
+ ],
157
+ };
158
+ }
159
+ return { ok: true, blueprint: parsed.value };
160
+ }
161
+ return { ok: true, blueprint: value };
162
+ }
163
+ function coerceColumn(value) {
164
+ if (typeof value === "string") {
165
+ const parsed = parseJsonObject(value, "column");
166
+ if (!parsed.ok) {
167
+ return {
168
+ ok: false,
169
+ errors: [
170
+ {
171
+ kind: "shape",
172
+ message: parsed.error,
173
+ zodIssues: [],
174
+ },
175
+ ],
176
+ };
177
+ }
178
+ return { ok: true, column: parsed.value };
179
+ }
180
+ return { ok: true, column: value };
181
+ }
182
+ function validateLocalBlueprint(blueprint) {
183
+ const errors = [];
184
+ if (!blueprint || !Array.isArray(blueprint.columns)) {
185
+ return {
186
+ ok: false,
187
+ errors: [
188
+ {
189
+ kind: "shape",
190
+ message: "Blueprint must include a columns array",
191
+ zodIssues: [],
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ for (const column of blueprint.columns) {
197
+ if (!knownBlueprintColumnTypes.has(column.type)) {
198
+ errors.push({
199
+ kind: "phantom_type",
200
+ columnId: column.id,
201
+ attemptedType: column.type,
202
+ availableTypes: Array.from(knownBlueprintColumnTypes).sort(),
203
+ });
204
+ }
205
+ }
206
+ return errors.length > 0
207
+ ? { ok: false, errors }
208
+ : { ok: true };
209
+ }
210
+ function topoSortBlueprint(blueprint) {
211
+ const columnsById = new Map(blueprint.columns.map((column) => [column.id, column]));
212
+ const depsById = new Map();
213
+ for (const column of blueprint.columns) {
214
+ depsById.set(column.id, new Set());
215
+ }
216
+ for (const edge of blueprint.edges || []) {
217
+ if (depsById.has(edge.to) && columnsById.has(edge.from)) {
218
+ depsById.get(edge.to)?.add(edge.from);
219
+ }
220
+ }
221
+ for (const column of blueprint.columns) {
222
+ for (const producerId of Object.values(column.inputMapping || {})) {
223
+ if (columnsById.has(producerId)) {
224
+ depsById.get(column.id)?.add(producerId);
225
+ }
226
+ }
227
+ }
228
+ const sorted = [];
229
+ const visiting = new Set();
230
+ const visited = new Set();
231
+ function visit(columnId) {
232
+ if (visited.has(columnId))
233
+ return;
234
+ if (visiting.has(columnId))
235
+ return;
236
+ visiting.add(columnId);
237
+ for (const depId of depsById.get(columnId) || []) {
238
+ visit(depId);
239
+ }
240
+ visiting.delete(columnId);
241
+ visited.add(columnId);
242
+ const column = columnsById.get(columnId);
243
+ if (column)
244
+ sorted.push(column);
245
+ }
246
+ for (const column of blueprint.columns) {
247
+ visit(column.id);
248
+ }
249
+ return { ...blueprint, columns: sorted };
250
+ }
251
+ export async function handleCommitBlueprint(input) {
252
+ const api = getApi();
253
+ const coerced = coerceBlueprint(input.blueprint);
254
+ if (!coerced.ok) {
255
+ return { ok: false, errors: coerced.errors };
256
+ }
257
+ const validation = validateLocalBlueprint(coerced.blueprint);
258
+ if (!validation.ok) {
259
+ return validation;
260
+ }
261
+ const blueprint = topoSortBlueprint(coerced.blueprint);
262
+ return api.post(`/api/v3/workflow-tables/${input.tableId}/columns/bulk`, {
263
+ blueprint,
264
+ });
265
+ }
266
+ export async function handleAddColumn(input) {
267
+ const api = getApi();
268
+ const coerced = coerceColumn(input.column);
269
+ if (!coerced.ok) {
270
+ return { ok: false, errors: coerced.errors };
271
+ }
272
+ const blueprint = { columns: [coerced.column], edges: [] };
273
+ const validation = validateLocalBlueprint(blueprint);
274
+ if (!validation.ok) {
275
+ return validation;
276
+ }
277
+ return api.post(`/api/v3/workflow-tables/${input.tableId}/columns`, {
278
+ id: coerced.column.id,
279
+ name: coerced.column.name,
280
+ columnType: coerced.column.type,
281
+ config: coerced.column.config,
282
+ inputMapping: coerced.column.inputMapping,
283
+ runCondition: coerced.column.runCondition,
284
+ validateOnly: input.validateOnly ?? false,
285
+ });
286
+ }
@@ -0,0 +1,64 @@
1
+ import { type AuthStatus } from "./auth.js";
2
+ import { getCampaignContext } from "./context.js";
3
+ import { getCampaignFramework } from "./framework.js";
4
+ import { type ListSubskillPromptsResponse, type SubskillPromptResponse } from "./prompts.js";
5
+ type BootstrapCreateCampaignInput = {
6
+ campaignId?: string;
7
+ flowVersion?: "v1" | "v2";
8
+ includeTableCheck?: boolean;
9
+ refreshContext?: boolean;
10
+ };
11
+ type BootstrapCheck = {
12
+ key: "auth" | "framework" | "resume_context" | "subskill_catalog" | "create_campaign_subskill";
13
+ ok: boolean;
14
+ blocking: boolean;
15
+ detail: string;
16
+ };
17
+ type BootstrapBlockingError = {
18
+ check: BootstrapCheck["key"];
19
+ message: string;
20
+ guidance: string;
21
+ };
22
+ type BootstrapCreateCampaignResult = {
23
+ requiredChecks: BootstrapCheck[];
24
+ blockingErrors: BootstrapBlockingError[];
25
+ resumeDetected: boolean;
26
+ nextStep: string;
27
+ safeToProceed: boolean;
28
+ flowVersion: "v1" | "v2";
29
+ campaignId: string | null;
30
+ auth: AuthStatus | null;
31
+ framework: ReturnType<typeof getCampaignFramework> | null;
32
+ campaignContext: Awaited<ReturnType<typeof getCampaignContext>> | null;
33
+ subskillCatalog: ListSubskillPromptsResponse | null;
34
+ createCampaignSubskill: Omit<SubskillPromptResponse, "prompt"> | null;
35
+ };
36
+ export declare const bootstrapToolDefinitions: {
37
+ name: string;
38
+ description: string;
39
+ inputSchema: {
40
+ type: string;
41
+ properties: {
42
+ campaignId: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ flowVersion: {
47
+ type: string;
48
+ enum: string[];
49
+ description: string;
50
+ };
51
+ includeTableCheck: {
52
+ type: string;
53
+ description: string;
54
+ };
55
+ refreshContext: {
56
+ type: string;
57
+ description: string;
58
+ };
59
+ };
60
+ additionalProperties: boolean;
61
+ };
62
+ }[];
63
+ export declare function bootstrapCreateCampaign(input?: BootstrapCreateCampaignInput): Promise<BootstrapCreateCampaignResult>;
64
+ export {};