@kylewadegrove/cutline-mcp-cli 0.6.1 → 0.6.2

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.
@@ -2,29 +2,23 @@
2
2
  import {
3
3
  isWriteTool
4
4
  } from "./chunk-KMUSQOTJ.js";
5
- import {
6
- createLinearIssues,
7
- processStripeEvent
8
- } from "./chunk-M37M2UA4.js";
9
- import "./chunk-JBJYSV4P.js";
10
5
  import {
11
6
  guardBoundary,
12
7
  guardOutput,
13
8
  withPerfTracking
14
9
  } from "./chunk-OP4EO6FV.js";
15
10
  import {
11
+ cfCreateLinearIssues,
16
12
  mapErrorToMcp,
17
13
  requirePremiumWithAutoAuth,
18
14
  validateAuth,
19
15
  validateRequestSize
20
- } from "./chunk-NUBIEJTU.js";
21
- import "./chunk-7FHM2GD3.js";
16
+ } from "./chunk-7N4HJ3KR.js";
22
17
 
23
18
  // ../mcp/dist/mcp/src/integrations-server.js
24
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
25
20
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
26
21
  import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
27
- import Stripe from "stripe";
28
22
  var server = new Server({
29
23
  name: "cutline-integrations",
30
24
  version: "0.1.0"
@@ -85,21 +79,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
85
79
  case "integrations_create_issues": {
86
80
  const { schema_json, limit, auth_token } = args;
87
81
  await requirePremiumWithAutoAuth(auth_token);
88
- const result = await createLinearIssues(schema_json, limit);
82
+ const result = await cfCreateLinearIssues(schema_json, limit);
89
83
  return {
90
84
  content: [{ type: "text", text: JSON.stringify(result) }]
91
85
  };
92
86
  }
93
87
  case "stripe_webhook_dispatch": {
94
- const { event, auth_token } = args;
95
- await requirePremiumWithAutoAuth(auth_token);
96
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
97
- apiVersion: "2023-10-16"
98
- });
99
- await processStripeEvent(event, stripe);
100
- return {
101
- content: [{ type: "text", text: JSON.stringify({ dispatched: true }) }]
102
- };
88
+ throw new McpError(ErrorCode.InvalidRequest, "Stripe webhook dispatch is not available from local MCP. Webhooks are handled server-side.");
103
89
  }
104
90
  default:
105
91
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
@@ -1,23 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- buildPdfBuffer,
4
- generateAnswer,
5
- uploadAndSign
6
- } from "./chunk-M37M2UA4.js";
7
- import "./chunk-JBJYSV4P.js";
3
+ PMJsonSchema
4
+ } from "./chunk-DE7R7WKY.js";
8
5
  import {
9
6
  guardBoundary,
10
7
  guardOutput,
11
8
  withPerfTracking
12
9
  } from "./chunk-OP4EO6FV.js";
13
10
  import {
11
+ cfBuildAndUploadPdf,
12
+ cfGenerateAnswer,
14
13
  mapErrorToMcp,
15
14
  requirePremiumWithAutoAuth,
16
15
  validateRequestSize
17
- } from "./chunk-NUBIEJTU.js";
18
- import {
19
- PMJsonSchema
20
- } from "./chunk-7FHM2GD3.js";
16
+ } from "./chunk-7N4HJ3KR.js";
21
17
 
22
18
  // ../mcp/dist/mcp/src/output-server.js
23
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -75,18 +71,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
75
71
  const { doc, auth_token, store = true } = args;
76
72
  await requirePremiumWithAutoAuth(auth_token);
77
73
  const parsedDoc = PMJsonSchema.parse(doc);
78
- const bytes = await buildPdfBuffer(parsedDoc);
79
- if (store) {
80
- const uploaded = await uploadAndSign(bytes, parsedDoc?.project?.name || "premortem");
81
- if (uploaded?.url) {
82
- return {
83
- content: [{ type: "text", text: JSON.stringify({ ok: true, url: uploaded.url }) }]
84
- };
85
- }
86
- }
87
- const base64 = Buffer.from(bytes).toString("base64");
74
+ const result = await cfBuildAndUploadPdf(parsedDoc);
88
75
  return {
89
- content: [{ type: "text", text: JSON.stringify({ ok: true, dataUrl: `data:application/pdf;base64,${base64}` }) }]
76
+ content: [{ type: "text", text: JSON.stringify({ ok: true, ...result }) }]
90
77
  };
91
78
  }
92
79
  case "premortem_qa_answer": {
@@ -95,7 +82,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
95
82
  if (!allowPublic) {
96
83
  await requirePremiumWithAutoAuth(auth_token);
97
84
  }
98
- const result = await generateAnswer(question, doc);
85
+ const result = await cfGenerateAnswer(question, doc);
99
86
  return {
100
87
  content: [{ type: "text", text: JSON.stringify(result) }]
101
88
  };
@@ -1,40 +1,147 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ RunInputSchema
4
+ } from "./chunk-DE7R7WKY.js";
2
5
  import {
3
6
  isWriteTool
4
7
  } from "./chunk-KMUSQOTJ.js";
5
- import "./chunk-M37M2UA4.js";
6
- import "./chunk-JBJYSV4P.js";
7
8
  import {
8
9
  guardBoundary,
9
10
  guardOutput,
10
11
  withPerfTracking
11
12
  } from "./chunk-OP4EO6FV.js";
12
13
  import {
14
+ cfRegenAssumptions,
15
+ cfRegenExperiments,
13
16
  createPremortem,
14
17
  getChat,
15
18
  getPremortem,
16
19
  listPremortems,
17
- saveChat,
18
- updateChat,
19
- updatePremortem
20
- } from "./chunk-PQUAX5YW.js";
21
- import {
22
20
  mapErrorToMcp,
23
21
  requirePremiumWithAutoAuth,
24
22
  resolveAuthContext,
23
+ saveChat,
24
+ updateChat,
25
+ updatePremortem,
25
26
  validateAuth,
26
27
  validateRequestSize
27
- } from "./chunk-NUBIEJTU.js";
28
- import {
29
- RunInputSchema,
30
- regenerateAssumptions,
31
- regenerateExperiments
32
- } from "./chunk-7FHM2GD3.js";
28
+ } from "./chunk-7N4HJ3KR.js";
33
29
 
34
30
  // ../mcp/dist/mcp/src/premortem-server.js
35
31
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
36
32
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
37
33
  import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
34
+
35
+ // ../mcp/dist/mcp/src/premortem-handoff.js
36
+ function buildBrief(ctx) {
37
+ if (!ctx)
38
+ return "";
39
+ const parts = [];
40
+ if (ctx.brief)
41
+ parts.push(ctx.brief);
42
+ if (ctx.problemSolved && !ctx.brief?.toLowerCase().includes(ctx.problemSolved.toLowerCase().slice(0, 20)))
43
+ parts.push(`Problem: ${ctx.problemSolved}`);
44
+ if (ctx.uniqueValue && !ctx.brief?.toLowerCase().includes(ctx.uniqueValue.toLowerCase().slice(0, 20)))
45
+ parts.push(`Unique value: ${ctx.uniqueValue}`);
46
+ if (ctx.targetUser && !ctx.brief?.toLowerCase().includes(ctx.targetUser.toLowerCase().slice(0, 15)))
47
+ parts.push(`Target users: ${ctx.targetUser}`);
48
+ if (ctx.businessModel && !ctx.brief?.toLowerCase().includes(ctx.businessModel.toLowerCase().slice(0, 15)))
49
+ parts.push(`Business model: ${ctx.businessModel}`);
50
+ return parts.join(". ").trim() || "No description provided.";
51
+ }
52
+ function buildReferenceClasses(competitors) {
53
+ if (competitors && competitors.length > 0) {
54
+ return competitors.filter((c) => c.name && c.name.length > 0).map((c) => c.name).slice(0, 5);
55
+ }
56
+ return ["General market alternatives"];
57
+ }
58
+ function buildSeedPersonas(ctx) {
59
+ if (!ctx.productContext?.targetUser)
60
+ return void 0;
61
+ return {
62
+ user_personas: [{ name: "Primary User", description: ctx.productContext.targetUser }]
63
+ };
64
+ }
65
+ function buildRunInput(request) {
66
+ const { projectName, conversationalContext: ctx, mode = "product", clientContext } = request;
67
+ let brief = buildBrief(ctx.productContext);
68
+ if (ctx.risks.length > 0) {
69
+ const topRisks = ctx.risks.filter((r) => r.severity === "critical" || r.severity === "high").slice(0, 2).map((r) => r.title);
70
+ if (topRisks.length > 0)
71
+ brief += ` Key concerns to investigate: ${topRisks.join(", ")}.`;
72
+ }
73
+ if (ctx.verdict?.summary)
74
+ brief += ` Initial assessment: ${ctx.verdict.summary}`;
75
+ const runInput = {
76
+ mode,
77
+ project: { name: projectName, brief, reference_classes: buildReferenceClasses(ctx.competitors) }
78
+ };
79
+ if (mode === "consulting" && clientContext) {
80
+ runInput.client = {
81
+ name: clientContext.name,
82
+ industry: clientContext.industry,
83
+ size: clientContext.size,
84
+ stakeholders: clientContext.stakeholders
85
+ };
86
+ }
87
+ const seedPersonas = buildSeedPersonas(ctx);
88
+ if (seedPersonas)
89
+ runInput.seed_personas = seedPersonas;
90
+ if (ctx.risks.length > 0 || ctx.assumptions.length > 0 || ctx.competitors.length > 0) {
91
+ runInput.conversational_artifacts = {
92
+ risks: ctx.risks.length > 0 ? ctx.risks.map((r) => ({
93
+ title: r.title,
94
+ description: r.description,
95
+ category: r.category,
96
+ severity: r.severity,
97
+ likelihood: r.likelihood,
98
+ impact: r.impact
99
+ })) : void 0,
100
+ assumptions: ctx.assumptions.length > 0 ? ctx.assumptions.map((a) => ({
101
+ statement: a.statement,
102
+ category: a.category,
103
+ confidence: a.confidence,
104
+ importance: a.importance
105
+ })) : void 0,
106
+ competitors: ctx.competitors.length > 0 ? ctx.competitors.map((c) => ({
107
+ name: c.name,
108
+ description: c.description,
109
+ threat_level: c.threatLevel
110
+ })) : void 0,
111
+ conversation_summary: ctx.verdict?.summary
112
+ };
113
+ }
114
+ return runInput;
115
+ }
116
+ function validateForGraduation(ctx) {
117
+ const errors = [];
118
+ const warnings = [];
119
+ if (!ctx.productContext?.brief && !ctx.productContext?.problemSolved)
120
+ errors.push("No product description found. Please describe what you're building first.");
121
+ if (ctx.assumptions.length === 0)
122
+ warnings.push("No assumptions were surfaced. The full analysis will discover them.");
123
+ if (ctx.risks.length === 0)
124
+ warnings.push("No risks were identified. The full analysis will analyze risks in depth.");
125
+ if (ctx.competitors.length === 0)
126
+ warnings.push("No competitors were discussed. Provide reference companies for better analysis.");
127
+ return { valid: errors.length === 0, errors, warnings };
128
+ }
129
+ function buildGraduationMetadata(sessionId, ctx, currentAct) {
130
+ return {
131
+ sourceType: "conversational_premortem",
132
+ sourceSessionId: sessionId,
133
+ graduatedAt: Date.now(),
134
+ conversationSummary: {
135
+ actsCompleted: currentAct,
136
+ assumptionsCount: ctx.assumptions.length,
137
+ risksCount: ctx.risks.length,
138
+ competitorsCount: ctx.competitors.length,
139
+ hasVerdict: !!ctx.verdict
140
+ }
141
+ };
142
+ }
143
+
144
+ // ../mcp/dist/mcp/src/premortem-server.js
38
145
  import { GoogleAuth } from "google-auth-library";
39
146
  var PREMORTEM_CHAT_FUNCTION_URL = process.env.PREMORTEM_CHAT_AGENT_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/premortemChatAgent";
40
147
  var PREMORTEM_KICK_FUNCTION_URL = process.env.PREMORTEM_KICK_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/premortemKick";
@@ -522,7 +629,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
522
629
  case "premortem_regen_assumptions": {
523
630
  const { input, doc, auth_token } = args;
524
631
  await requirePremiumWithAutoAuth(auth_token);
525
- const out = await regenerateAssumptions(input, doc);
632
+ const out = await cfRegenAssumptions(input, doc);
526
633
  return {
527
634
  content: [{ type: "text", text: JSON.stringify(out) }]
528
635
  };
@@ -530,7 +637,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
530
637
  case "premortem_regen_experiments": {
531
638
  const { input, doc, auth_token } = args;
532
639
  await requirePremiumWithAutoAuth(auth_token);
533
- const out = await regenerateExperiments(input, doc);
640
+ const out = await cfRegenExperiments(input, doc);
534
641
  return {
535
642
  content: [{ type: "text", text: JSON.stringify(out) }]
536
643
  };
@@ -555,7 +662,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
555
662
  throw new McpError(ErrorCode.InvalidParams, "conversational_context is required");
556
663
  }
557
664
  const decoded = await requirePremiumWithAutoAuth(auth_token);
558
- const { buildRunInput, validateForGraduation, buildGraduationMetadata } = await import("./premortem-handoff-XT4K3YDJ.js");
559
665
  const validation = validateForGraduation(conversational_context);
560
666
  if (!validation.valid) {
561
667
  throw new McpError(ErrorCode.InvalidParams, `Cannot graduate: ${validation.errors.join(", ")}`);
@@ -820,7 +926,6 @@ Let's start with the basics. Tell me more about what you're building:
820
926
  competitors: session.competitors,
821
927
  verdict: session.verdict
822
928
  };
823
- const { buildRunInput, validateForGraduation, buildGraduationMetadata } = await import("./premortem-handoff-XT4K3YDJ.js");
824
929
  const validation = validateForGraduation(conversational_context);
825
930
  if (!validation.valid) {
826
931
  throw new McpError(ErrorCode.InvalidParams, `Cannot graduate: ${validation.errors.join(", ")}`);
@@ -837,10 +942,7 @@ Let's start with the basics. Tell me more about what you're building:
837
942
  payload: parsedInput,
838
943
  uid: decoded?.uid || null,
839
944
  source: "mcp_chat_graduate",
840
- metadata: buildGraduationMetadata({
841
- sessionId: session_id,
842
- conversationalContext: conversational_context
843
- })
945
+ metadata: buildGraduationMetadata(session_id, conversational_context, conversational_context.verdict ? 5 : 4)
844
946
  });
845
947
  session.conversationHistory.push({
846
948
  role: "assistant",
@@ -2,30 +2,26 @@
2
2
  import {
3
3
  isWriteTool
4
4
  } from "./chunk-KMUSQOTJ.js";
5
- import {
6
- applyEditsLogic,
7
- chatWithPersona,
8
- generateChatSuggestion,
9
- generateTrialRun,
10
- getPersona,
11
- getWikiMarkdown,
12
- listPersonas,
13
- saveWikiMarkdown
14
- } from "./chunk-M37M2UA4.js";
15
- import "./chunk-JBJYSV4P.js";
16
5
  import {
17
6
  guardBoundary,
18
7
  guardOutput,
19
8
  withPerfTracking
20
9
  } from "./chunk-OP4EO6FV.js";
21
10
  import {
11
+ cfApplyEdits,
12
+ cfChatWithPersona,
13
+ cfGenerateChatSuggestion,
14
+ cfGenerateTrialRun,
15
+ cfGetWikiMarkdown,
16
+ cfSaveWikiMarkdown,
17
+ getPersona,
18
+ getPodcastIntroductions,
19
+ listPersonas,
22
20
  mapErrorToMcp,
23
21
  requirePremiumWithAutoAuth,
24
- resolveAuthContext,
25
22
  validateAuth,
26
23
  validateRequestSize
27
- } from "./chunk-NUBIEJTU.js";
28
- import "./chunk-7FHM2GD3.js";
24
+ } from "./chunk-7N4HJ3KR.js";
29
25
 
30
26
  // ../mcp/dist/mcp/src/tools-server.js
31
27
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -198,7 +194,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
198
194
  switch (name) {
199
195
  case "trial_generate": {
200
196
  const { prompt } = args;
201
- const text = await generateTrialRun(prompt);
197
+ const text = await cfGenerateTrialRun(prompt);
202
198
  return {
203
199
  content: [{ type: "text", text: JSON.stringify({ ok: true, text }) }]
204
200
  };
@@ -206,7 +202,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
206
202
  case "agent_chat": {
207
203
  const { prompt, wikiMarkdown, auth_token } = args;
208
204
  await requirePremiumWithAutoAuth(auth_token);
209
- const text = await generateChatSuggestion(prompt, wikiMarkdown);
205
+ const text = await cfGenerateChatSuggestion(prompt, wikiMarkdown);
210
206
  return {
211
207
  content: [{ type: "text", text: JSON.stringify({ text }) }]
212
208
  };
@@ -214,7 +210,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
214
210
  case "wiki_load": {
215
211
  const { projectId, auth_token } = args;
216
212
  await requirePremiumWithAutoAuth(auth_token);
217
- const markdown = await getWikiMarkdown(projectId);
213
+ const markdown = await cfGetWikiMarkdown(projectId);
218
214
  return {
219
215
  content: [{ type: "text", text: JSON.stringify({ markdown }) }]
220
216
  };
@@ -222,7 +218,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
222
218
  case "wiki_save": {
223
219
  const { projectId, markdown, auth_token } = args;
224
220
  const decoded = await requirePremiumWithAutoAuth(auth_token);
225
- await saveWikiMarkdown(projectId, markdown, decoded?.uid);
221
+ await cfSaveWikiMarkdown(projectId, markdown);
226
222
  return {
227
223
  content: [{ type: "text", text: JSON.stringify({ ok: true }) }]
228
224
  };
@@ -230,7 +226,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
230
226
  case "wiki_apply_edits": {
231
227
  const { edits, auth_token } = args;
232
228
  await requirePremiumWithAutoAuth(auth_token);
233
- const result = await applyEditsLogic(edits);
229
+ const result = await cfApplyEdits(edits);
234
230
  return {
235
231
  content: [{ type: "text", text: JSON.stringify(result) }]
236
232
  };
@@ -238,8 +234,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
238
234
  case "personas_list": {
239
235
  const { productId, auth_token } = args;
240
236
  const normalizedAuthToken = auth_token && auth_token !== "auto" && auth_token.trim() !== "" ? auth_token : void 0;
241
- const { effectiveUid } = await resolveAuthContext(normalizedAuthToken);
242
- const personas = await listPersonas(effectiveUid, productId);
237
+ await requirePremiumWithAutoAuth(normalizedAuthToken);
238
+ const personas = await listPersonas(productId);
243
239
  return {
244
240
  content: [{ type: "text", text: JSON.stringify({ personas }) }]
245
241
  };
@@ -247,8 +243,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
247
243
  case "personas_get": {
248
244
  const { personaId, auth_token } = args;
249
245
  const normalizedAuthToken = auth_token && auth_token !== "auto" && auth_token.trim() !== "" ? auth_token : void 0;
250
- const { effectiveUid } = await resolveAuthContext(normalizedAuthToken);
251
- const persona = await getPersona(effectiveUid, personaId);
246
+ await requirePremiumWithAutoAuth(normalizedAuthToken);
247
+ const persona = await getPersona(personaId);
252
248
  return {
253
249
  content: [{ type: "text", text: JSON.stringify({ persona }) }]
254
250
  };
@@ -257,7 +253,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
257
253
  const { persona, userMessage, product, conversationHistory, auth_token } = args;
258
254
  const normalizedAuthToken = auth_token && auth_token !== "auto" && auth_token.trim() !== "" ? auth_token : void 0;
259
255
  await requirePremiumWithAutoAuth(normalizedAuthToken);
260
- const result = await chatWithPersona(persona, userMessage, product, conversationHistory);
256
+ const result = await cfChatWithPersona(persona, userMessage, product, conversationHistory);
261
257
  return {
262
258
  content: [{ type: "text", text: JSON.stringify(result) }]
263
259
  };
@@ -265,8 +261,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
265
261
  case "podcast_get_participants": {
266
262
  const { productId, format, auth_token } = args;
267
263
  const normalizedAuthToken = auth_token && auth_token !== "auto" && auth_token.trim() !== "" ? auth_token : void 0;
268
- const { effectiveUid } = await resolveAuthContext(normalizedAuthToken);
269
- const result = await (void 0)(effectiveUid, productId, format || "json");
264
+ await requirePremiumWithAutoAuth(normalizedAuthToken);
265
+ const result = await getPodcastIntroductions(productId, format || "json");
270
266
  return {
271
267
  content: [{ type: "text", text: JSON.stringify(result) }]
272
268
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kylewadegrove/cutline-mcp-cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "CLI and MCP servers for Cutline — authenticate, then run constraint-aware MCP servers in Cursor or any MCP client.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -53,24 +53,15 @@
53
53
  "author": "Cutline",
54
54
  "license": "MIT",
55
55
  "dependencies": {
56
- "@google-cloud/storage": "^7.7.0",
57
56
  "@google-cloud/vertexai": "^1.9.2",
58
57
  "@modelcontextprotocol/sdk": "^1.0.0",
59
- "@pdf-lib/fontkit": "^1.1.1",
60
58
  "chalk": "^4.1.2",
61
59
  "commander": "^11.1.0",
62
- "customerio-node": "^4.0.0",
63
60
  "dotenv": "^16.4.5",
64
- "express": "^4.18.2",
65
- "firebase-admin": "^12.0.0",
66
- "firebase-functions": "^6.3.0",
67
61
  "google-auth-library": "^9.14.2",
68
62
  "keytar": "^7.9.0",
69
- "node-fetch": "^3.3.2",
70
63
  "open": "^9.1.0",
71
64
  "ora": "^5.4.1",
72
- "pdf-lib": "^1.17.1",
73
- "stripe": "^14.20.0",
74
65
  "zod": "^3.23.8"
75
66
  },
76
67
  "devDependencies": {