@kylewadegrove/cutline-mcp-cli 0.6.2 → 0.7.1
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.
- package/dist/commands/init.js +49 -0
- package/dist/commands/setup.js +3 -1
- package/dist/commands/upgrade.js +3 -1
- package/dist/servers/{chunk-7N4HJ3KR.js → chunk-TJTE5Q2C.js} +47 -1
- package/dist/servers/cutline-server.js +26 -92
- package/dist/servers/{data-client-PF2AI2MX.js → data-client-FVOG67G6.js} +11 -1
- package/dist/servers/exploration-server.js +5 -26
- package/dist/servers/integrations-server.js +1 -1
- package/dist/servers/output-server.js +1 -1
- package/dist/servers/premortem-server.js +10 -40
- package/dist/servers/tools-server.js +1 -1
- package/dist/utils/config-store.d.ts +1 -0
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
|
4
4
|
import { resolve, join } from 'node:path';
|
|
5
5
|
import { getRefreshToken } from '../auth/keychain.js';
|
|
6
6
|
import { fetchFirebaseApiKey } from '../utils/config.js';
|
|
7
|
+
import { saveConfig, loadConfig } from '../utils/config-store.js';
|
|
7
8
|
const CUTLINE_CONFIG = '.cutline/config.json';
|
|
8
9
|
async function authenticate(options) {
|
|
9
10
|
const refreshToken = await getRefreshToken();
|
|
@@ -33,6 +34,8 @@ async function authenticate(options) {
|
|
|
33
34
|
tier: isPremium ? 'premium' : 'free',
|
|
34
35
|
email: payload.email,
|
|
35
36
|
uid: payload.user_id || payload.sub,
|
|
37
|
+
idToken,
|
|
38
|
+
baseUrl,
|
|
36
39
|
};
|
|
37
40
|
}
|
|
38
41
|
catch {
|
|
@@ -206,6 +209,42 @@ export async function initCommand(options) {
|
|
|
206
209
|
else {
|
|
207
210
|
console.log(chalk.yellow(' No .cutline/config.json found — generating generic rules.'));
|
|
208
211
|
}
|
|
212
|
+
// Generate API key for authenticated users (skips if one already exists)
|
|
213
|
+
let generatedApiKey = null;
|
|
214
|
+
if (auth?.idToken && auth.baseUrl) {
|
|
215
|
+
const existing = loadConfig();
|
|
216
|
+
if (existing.apiKey) {
|
|
217
|
+
console.log(chalk.dim(' API key: already configured'));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const keySpinner = ora('Generating API key...').start();
|
|
221
|
+
try {
|
|
222
|
+
const keyRes = await fetch(`${auth.baseUrl}/mcpDataProxy`, {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
headers: {
|
|
225
|
+
'Content-Type': 'application/json',
|
|
226
|
+
Authorization: `Bearer ${auth.idToken}`,
|
|
227
|
+
},
|
|
228
|
+
body: JSON.stringify({ action: 'apiKey.create', params: { name: 'cursor-ide' } }),
|
|
229
|
+
});
|
|
230
|
+
if (keyRes.ok) {
|
|
231
|
+
const keyData = await keyRes.json();
|
|
232
|
+
generatedApiKey = keyData.key;
|
|
233
|
+
saveConfig({ apiKey: generatedApiKey });
|
|
234
|
+
keySpinner.succeed(chalk.green('API key generated and saved'));
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const errBody = await keyRes.text().catch(() => '');
|
|
238
|
+
keySpinner.warn(chalk.yellow(`API key generation skipped (${keyRes.status})`));
|
|
239
|
+
if (errBody)
|
|
240
|
+
console.log(chalk.dim(` ${errBody.slice(0, 120)}`));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
keySpinner.warn(chalk.yellow('API key generation skipped (network error)'));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
209
248
|
console.log();
|
|
210
249
|
const filesWritten = [];
|
|
211
250
|
// 1. Cursor rules
|
|
@@ -240,6 +279,16 @@ export async function initCommand(options) {
|
|
|
240
279
|
console.log(chalk.dim('\n Upgrade to Premium for product-specific constraint graphs and .cutline.md'));
|
|
241
280
|
console.log(chalk.dim(' →'), chalk.cyan('cutline-mcp upgrade'), chalk.dim('or https://thecutline.ai/upgrade'));
|
|
242
281
|
}
|
|
282
|
+
if (generatedApiKey) {
|
|
283
|
+
console.log();
|
|
284
|
+
console.log(chalk.bold(' API Key (shown once):'));
|
|
285
|
+
console.log(chalk.cyan(` ${generatedApiKey}`));
|
|
286
|
+
console.log();
|
|
287
|
+
console.log(chalk.dim(' Add to your Cursor MCP config for best performance:'));
|
|
288
|
+
console.log(chalk.dim(' "env": { "CUTLINE_API_KEY": "') + chalk.cyan(generatedApiKey) + chalk.dim('" }'));
|
|
289
|
+
console.log();
|
|
290
|
+
console.log(chalk.dim(' Or it will be used automatically from ~/.cutline-mcp/config.json'));
|
|
291
|
+
}
|
|
243
292
|
console.log();
|
|
244
293
|
console.log(chalk.bold(' Next step:'));
|
|
245
294
|
console.log(chalk.dim(' Run'), chalk.cyan('cutline-mcp setup'), chalk.dim('to get the MCP server config for your IDE.\n'));
|
package/dist/commands/setup.js
CHANGED
|
@@ -245,7 +245,9 @@ export async function setupCommand(options) {
|
|
|
245
245
|
}
|
|
246
246
|
const items = [
|
|
247
247
|
{ cmd: 'Run a deep dive on my product idea', desc: 'Pre-mortem analysis — risks, assumptions, experiments' },
|
|
248
|
-
{ cmd: '
|
|
248
|
+
{ cmd: 'Plan this feature with constraints from my product', desc: 'RGR plan — constraint-aware implementation roadmap' },
|
|
249
|
+
{ cmd: 'Run an audit over my code', desc: 'Quick security scan — safe for any codebase' },
|
|
250
|
+
{ cmd: 'Run a code audit for my product', desc: 'Full engineering audit + RGR remediation plan' },
|
|
249
251
|
{ cmd: 'Check constraints for src/api/upload.ts', desc: 'Get NFR boundaries for a specific file' },
|
|
250
252
|
{ cmd: 'Generate .cutline.md for my product', desc: 'Write the constraint routing engine' },
|
|
251
253
|
{ cmd: 'What does my persona think about X?', desc: 'AI persona feedback on features' },
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -88,7 +88,9 @@ export async function upgradeCommand(options) {
|
|
|
88
88
|
console.log(chalk.bold(' Then ask your AI agent:\n'));
|
|
89
89
|
const items = [
|
|
90
90
|
{ cmd: 'Run a deep dive on my product idea', desc: 'Pre-mortem analysis — risks, assumptions, experiments' },
|
|
91
|
-
{ cmd: '
|
|
91
|
+
{ cmd: 'Plan this feature with constraints from my product', desc: 'RGR plan — constraint-aware implementation roadmap' },
|
|
92
|
+
{ cmd: 'Run an audit over my code', desc: 'Quick security scan — safe for any codebase' },
|
|
93
|
+
{ cmd: 'Run a code audit for my product', desc: 'Full engineering audit + RGR remediation plan' },
|
|
92
94
|
{ cmd: 'Generate .cutline.md for my product', desc: 'Write the constraint routing engine' },
|
|
93
95
|
];
|
|
94
96
|
for (const item of items) {
|
|
@@ -287,6 +287,25 @@ async function exchangeRefreshToken(refreshToken, firebaseApiKey, maxRetries = 3
|
|
|
287
287
|
}
|
|
288
288
|
throw lastError || new Error("Token exchange failed after retries");
|
|
289
289
|
}
|
|
290
|
+
function getStoredApiKey() {
|
|
291
|
+
if (process.env.CUTLINE_API_KEY) {
|
|
292
|
+
return {
|
|
293
|
+
apiKey: process.env.CUTLINE_API_KEY,
|
|
294
|
+
environment: process.env.CUTLINE_ENV === "staging" ? "staging" : "production"
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
const configPath = path.join(os.homedir(), ".cutline-mcp", "config.json");
|
|
299
|
+
if (fs.existsSync(configPath)) {
|
|
300
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
301
|
+
if (config.apiKey) {
|
|
302
|
+
return { apiKey: config.apiKey, environment: config.environment };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
290
309
|
async function getStoredToken() {
|
|
291
310
|
if (process.env.CUTLINE_MCP_REFRESH_TOKEN) {
|
|
292
311
|
console.error("[MCP Auth] Using token from CUTLINE_MCP_REFRESH_TOKEN env var");
|
|
@@ -433,12 +452,19 @@ async function exchangeRefreshForId(refreshToken, environment) {
|
|
|
433
452
|
return data.id_token;
|
|
434
453
|
}
|
|
435
454
|
async function resolveAuth() {
|
|
455
|
+
const apiKeyInfo = getStoredApiKey();
|
|
456
|
+
if (apiKeyInfo) {
|
|
457
|
+
return {
|
|
458
|
+
baseUrl: getBaseUrl(apiKeyInfo.environment),
|
|
459
|
+
idToken: apiKeyInfo.apiKey
|
|
460
|
+
};
|
|
461
|
+
}
|
|
436
462
|
if (cachedIdToken && Date.now() < tokenExpiresAt && cachedBaseUrl) {
|
|
437
463
|
return { baseUrl: cachedBaseUrl, idToken: cachedIdToken };
|
|
438
464
|
}
|
|
439
465
|
const stored = await getStoredToken();
|
|
440
466
|
if (!stored) {
|
|
441
|
-
throw new Error("Not authenticated. Run 'cutline-mcp login'
|
|
467
|
+
throw new Error("Not authenticated. Run 'cutline-mcp login' or set CUTLINE_API_KEY.");
|
|
442
468
|
}
|
|
443
469
|
const env = stored.environment || "production";
|
|
444
470
|
const baseUrl = getBaseUrl(env);
|
|
@@ -866,12 +892,27 @@ async function cfPremortemRun(input) {
|
|
|
866
892
|
async function cfPremortemStart(input) {
|
|
867
893
|
return callCF("premortemStart", input, 3e4);
|
|
868
894
|
}
|
|
895
|
+
async function cfPremortemKick(jobId) {
|
|
896
|
+
return callCF("premortemKick", { id: jobId }, 6e5);
|
|
897
|
+
}
|
|
898
|
+
async function cfPremortemChatAgent(message, context) {
|
|
899
|
+
return callCF("premortemChatAgent", { message, context }, 12e4);
|
|
900
|
+
}
|
|
869
901
|
async function cfRegenAssumptions(input, doc) {
|
|
870
902
|
return callCF("regenAssumptions", { input, doc }, 9e4);
|
|
871
903
|
}
|
|
872
904
|
async function cfRegenExperiments(input, doc) {
|
|
873
905
|
return callCF("regenExperiments", { input, doc }, 9e4);
|
|
874
906
|
}
|
|
907
|
+
async function cfGenerateEmbeddings(texts, taskType = "RETRIEVAL_DOCUMENT") {
|
|
908
|
+
return proxy("embeddings.generate", { texts, taskType });
|
|
909
|
+
}
|
|
910
|
+
async function cfExplorationAgent(message, context) {
|
|
911
|
+
return callCF("explorationAgent", { message, context }, 12e4);
|
|
912
|
+
}
|
|
913
|
+
async function cfConsultingDiscoveryAgent(message, context) {
|
|
914
|
+
return callCF("consultingDiscoveryAgent", { message, context }, 12e4);
|
|
915
|
+
}
|
|
875
916
|
async function cfCreateLinearIssues(schema_json, limit) {
|
|
876
917
|
return callCF("integrationsIssues", { schema_json, limit });
|
|
877
918
|
}
|
|
@@ -1017,8 +1058,13 @@ export {
|
|
|
1017
1058
|
cfApplyEdits,
|
|
1018
1059
|
cfPremortemRun,
|
|
1019
1060
|
cfPremortemStart,
|
|
1061
|
+
cfPremortemKick,
|
|
1062
|
+
cfPremortemChatAgent,
|
|
1020
1063
|
cfRegenAssumptions,
|
|
1021
1064
|
cfRegenExperiments,
|
|
1065
|
+
cfGenerateEmbeddings,
|
|
1066
|
+
cfExplorationAgent,
|
|
1067
|
+
cfConsultingDiscoveryAgent,
|
|
1022
1068
|
cfCreateLinearIssues,
|
|
1023
1069
|
getPodcastIntroductions
|
|
1024
1070
|
};
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
cfCreateLinearIssues,
|
|
24
24
|
cfGenerateAnswer,
|
|
25
25
|
cfGenerateChatSuggestion,
|
|
26
|
+
cfGenerateEmbeddings,
|
|
26
27
|
cfGenerateExplorationResponse,
|
|
27
28
|
cfGenerateTemplateResponse,
|
|
28
29
|
cfGenerateTrialRun,
|
|
@@ -71,7 +72,7 @@ import {
|
|
|
71
72
|
upsertEntities,
|
|
72
73
|
upsertNodes,
|
|
73
74
|
validateRequestSize
|
|
74
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
75
76
|
import {
|
|
76
77
|
GraphTraverser,
|
|
77
78
|
computeGenericGraphMetrics,
|
|
@@ -85,10 +86,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
85
86
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
86
87
|
|
|
87
88
|
// ../mcp/dist/mcp/src/context-graph/embeddings.js
|
|
88
|
-
import { GoogleAuth } from "google-auth-library";
|
|
89
|
-
var EMBEDDING_MODEL = "text-embedding-005";
|
|
90
89
|
var EMBEDDING_DIMENSIONS = 768;
|
|
91
|
-
var DEFAULT_LOCATION = process.env.VERTEX_LOCATION || "us-central1";
|
|
92
90
|
var QUERY_EMBED_CACHE_SIZE = 20;
|
|
93
91
|
var QUERY_EMBED_CACHE_TTL = 30 * 60 * 1e3;
|
|
94
92
|
var queryEmbedCache = /* @__PURE__ */ new Map();
|
|
@@ -113,17 +111,6 @@ function setQueryEmbedCached(query, result) {
|
|
|
113
111
|
}
|
|
114
112
|
queryEmbedCache.set(query, { result, fetchedAt: Date.now() });
|
|
115
113
|
}
|
|
116
|
-
async function resolveProjectId() {
|
|
117
|
-
if (process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT) {
|
|
118
|
-
return process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
const auth = new GoogleAuth();
|
|
122
|
-
return await auth.getProjectId();
|
|
123
|
-
} catch (err) {
|
|
124
|
-
throw new Error(`Unable to resolve Google Cloud project id: ${err?.message ?? err}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
114
|
async function generateEmbedding(text) {
|
|
128
115
|
const results = await generateEmbeddings([text]);
|
|
129
116
|
return {
|
|
@@ -133,93 +120,40 @@ async function generateEmbedding(text) {
|
|
|
133
120
|
}
|
|
134
121
|
async function generateEmbeddings(texts) {
|
|
135
122
|
if (texts.length === 0) {
|
|
136
|
-
return { embeddings: [], model:
|
|
123
|
+
return { embeddings: [], model: "text-embedding-005" };
|
|
137
124
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const batchSize = 5;
|
|
146
|
-
const allEmbeddings = [];
|
|
147
|
-
for (let i = 0; i < texts.length; i += batchSize) {
|
|
148
|
-
const batch = texts.slice(i, i + batchSize);
|
|
149
|
-
const requestBody = {
|
|
150
|
-
instances: batch.map((text) => ({
|
|
151
|
-
content: text,
|
|
152
|
-
task_type: "RETRIEVAL_DOCUMENT"
|
|
153
|
-
// Optimized for retrieval
|
|
154
|
-
}))
|
|
125
|
+
try {
|
|
126
|
+
return await cfGenerateEmbeddings(texts, "RETRIEVAL_DOCUMENT");
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("Embedding proxy error:", error);
|
|
129
|
+
return {
|
|
130
|
+
embeddings: texts.map(() => new Array(EMBEDDING_DIMENSIONS).fill(0)),
|
|
131
|
+
model: "text-embedding-005"
|
|
155
132
|
};
|
|
156
|
-
try {
|
|
157
|
-
const response = await client.request({
|
|
158
|
-
url: endpoint,
|
|
159
|
-
method: "POST",
|
|
160
|
-
data: requestBody
|
|
161
|
-
});
|
|
162
|
-
const data = response.data;
|
|
163
|
-
const predictions = data.predictions || [];
|
|
164
|
-
for (const pred of predictions) {
|
|
165
|
-
const embedding = pred.embeddings?.values || [];
|
|
166
|
-
allEmbeddings.push(embedding);
|
|
167
|
-
}
|
|
168
|
-
} catch (error) {
|
|
169
|
-
console.error("Embedding API error:", error);
|
|
170
|
-
for (let j = 0; j < batch.length; j++) {
|
|
171
|
-
allEmbeddings.push(new Array(EMBEDDING_DIMENSIONS).fill(0));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
133
|
}
|
|
175
|
-
return {
|
|
176
|
-
embeddings: allEmbeddings,
|
|
177
|
-
model: EMBEDDING_MODEL
|
|
178
|
-
};
|
|
179
134
|
}
|
|
180
135
|
async function generateQueryEmbedding(query) {
|
|
181
136
|
const cached = getQueryEmbedCached(query);
|
|
182
137
|
if (cached)
|
|
183
138
|
return cached;
|
|
184
|
-
|
|
185
|
-
if (result.embedding.some((v) => v !== 0)) {
|
|
186
|
-
setQueryEmbedCached(query, result);
|
|
187
|
-
}
|
|
188
|
-
return result;
|
|
189
|
-
}
|
|
190
|
-
async function generateQueryEmbeddingUncached(query) {
|
|
191
|
-
const project = await resolveProjectId();
|
|
192
|
-
const location = DEFAULT_LOCATION;
|
|
193
|
-
const endpoint = `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/publishers/google/models/${EMBEDDING_MODEL}:predict`;
|
|
194
|
-
const auth = new GoogleAuth({
|
|
195
|
-
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
|
|
196
|
-
});
|
|
197
|
-
const client = await auth.getClient();
|
|
198
|
-
const requestBody = {
|
|
199
|
-
instances: [{
|
|
200
|
-
content: query,
|
|
201
|
-
task_type: "RETRIEVAL_QUERY"
|
|
202
|
-
}]
|
|
203
|
-
};
|
|
139
|
+
let result;
|
|
204
140
|
try {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
data: requestBody
|
|
209
|
-
});
|
|
210
|
-
const data = response.data;
|
|
211
|
-
const embedding = data.predictions?.[0]?.embeddings?.values || [];
|
|
212
|
-
return {
|
|
213
|
-
embedding,
|
|
141
|
+
const resp = await cfGenerateEmbeddings([query], "RETRIEVAL_QUERY");
|
|
142
|
+
result = {
|
|
143
|
+
embedding: resp.embeddings[0] || new Array(EMBEDDING_DIMENSIONS).fill(0),
|
|
214
144
|
dimensions: EMBEDDING_DIMENSIONS
|
|
215
145
|
};
|
|
216
146
|
} catch (error) {
|
|
217
|
-
console.error("Query embedding error:", error);
|
|
218
|
-
|
|
147
|
+
console.error("Query embedding proxy error:", error);
|
|
148
|
+
result = {
|
|
219
149
|
embedding: new Array(EMBEDDING_DIMENSIONS).fill(0),
|
|
220
150
|
dimensions: EMBEDDING_DIMENSIONS
|
|
221
151
|
};
|
|
222
152
|
}
|
|
153
|
+
if (result.embedding.some((v) => v !== 0)) {
|
|
154
|
+
setQueryEmbedCached(query, result);
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
223
157
|
}
|
|
224
158
|
function cosineSimilarity(a, b) {
|
|
225
159
|
if (a.length !== b.length || a.length === 0)
|
|
@@ -2820,7 +2754,7 @@ async function propagateConstraints(productId, sourceEntityId, targetEntityId, s
|
|
|
2820
2754
|
|
|
2821
2755
|
// ../mcp/dist/src/orchestrator/agents/shared/vertex.js
|
|
2822
2756
|
import { VertexAI } from "@google-cloud/vertexai";
|
|
2823
|
-
import { GoogleAuth
|
|
2757
|
+
import { GoogleAuth } from "google-auth-library";
|
|
2824
2758
|
import { Buffer } from "node:buffer";
|
|
2825
2759
|
|
|
2826
2760
|
// ../mcp/dist/src/shared/circuit-breaker.js
|
|
@@ -2978,7 +2912,7 @@ function estimateCostUsd(model, tokensIn, tokensOut) {
|
|
|
2978
2912
|
return Math.round((tokensIn * price.inputPerM + tokensOut * price.outputPerM) / 1e6 * 1e6) / 1e6;
|
|
2979
2913
|
}
|
|
2980
2914
|
var DEFAULT_MODEL_ID = process.env.MODEL_ID || "gemini-2.5-pro";
|
|
2981
|
-
var
|
|
2915
|
+
var DEFAULT_LOCATION = process.env.VERTEX_LOCATION || "us-central1";
|
|
2982
2916
|
var VERBOSE = (process.env.AGENT_LOG_VERBOSE ?? process.env.PREMORTEM_LOG_VERBOSE) === "true";
|
|
2983
2917
|
var PREVIEW = process.env.AGENT_LOG_PREVIEW === "true";
|
|
2984
2918
|
var PREVIEW_LIMIT = Math.max(0, parseInt(process.env.AGENT_LOG_PREVIEW_LIMIT || "400", 10) || 400);
|
|
@@ -3064,9 +2998,9 @@ async function retryWithBackoff(fn, opts) {
|
|
|
3064
2998
|
throw lastErr;
|
|
3065
2999
|
}
|
|
3066
3000
|
async function generateStructuredContent(options) {
|
|
3067
|
-
const project = await
|
|
3001
|
+
const project = await resolveProjectId();
|
|
3068
3002
|
const modelId = options.modelId || DEFAULT_MODEL_ID;
|
|
3069
|
-
const location = options.location ||
|
|
3003
|
+
const location = options.location || DEFAULT_LOCATION;
|
|
3070
3004
|
const vertex = new VertexAI({ project, location });
|
|
3071
3005
|
const fullSystem = `${GLOBAL_SYSTEM_PROMPT}
|
|
3072
3006
|
|
|
@@ -3312,12 +3246,12 @@ var GLOBAL_SYSTEM_PROMPT = [
|
|
|
3312
3246
|
"- Keep rationales crisp (8\u201330 words), focusing on evidence, base rates, and key assumptions.",
|
|
3313
3247
|
"- No marketing language, no boilerplate, no code fences, no markdown\u2014only the required JSON/plain text."
|
|
3314
3248
|
].join("\n");
|
|
3315
|
-
async function
|
|
3249
|
+
async function resolveProjectId() {
|
|
3316
3250
|
if (process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT) {
|
|
3317
3251
|
return process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
|
|
3318
3252
|
}
|
|
3319
3253
|
try {
|
|
3320
|
-
const auth = new
|
|
3254
|
+
const auth = new GoogleAuth();
|
|
3321
3255
|
return await auth.getProjectId();
|
|
3322
3256
|
} catch (err) {
|
|
3323
3257
|
throw new Error(`Unable to resolve Google Cloud project id: ${err?.message ?? err}`);
|
|
@@ -6,13 +6,18 @@ import {
|
|
|
6
6
|
cfApplyEdits,
|
|
7
7
|
cfBuildAndUploadPdf,
|
|
8
8
|
cfChatWithPersona,
|
|
9
|
+
cfConsultingDiscoveryAgent,
|
|
9
10
|
cfCreateLinearIssues,
|
|
11
|
+
cfExplorationAgent,
|
|
10
12
|
cfGenerateAnswer,
|
|
11
13
|
cfGenerateChatSuggestion,
|
|
14
|
+
cfGenerateEmbeddings,
|
|
12
15
|
cfGenerateExplorationResponse,
|
|
13
16
|
cfGenerateTemplateResponse,
|
|
14
17
|
cfGenerateTrialRun,
|
|
15
18
|
cfGetWikiMarkdown,
|
|
19
|
+
cfPremortemChatAgent,
|
|
20
|
+
cfPremortemKick,
|
|
16
21
|
cfPremortemRun,
|
|
17
22
|
cfPremortemStart,
|
|
18
23
|
cfRegenAssumptions,
|
|
@@ -71,7 +76,7 @@ import {
|
|
|
71
76
|
upsertEdges,
|
|
72
77
|
upsertEntities,
|
|
73
78
|
upsertNodes
|
|
74
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
75
80
|
export {
|
|
76
81
|
addEdges,
|
|
77
82
|
addEntity,
|
|
@@ -80,13 +85,18 @@ export {
|
|
|
80
85
|
cfApplyEdits,
|
|
81
86
|
cfBuildAndUploadPdf,
|
|
82
87
|
cfChatWithPersona,
|
|
88
|
+
cfConsultingDiscoveryAgent,
|
|
83
89
|
cfCreateLinearIssues,
|
|
90
|
+
cfExplorationAgent,
|
|
84
91
|
cfGenerateAnswer,
|
|
85
92
|
cfGenerateChatSuggestion,
|
|
93
|
+
cfGenerateEmbeddings,
|
|
86
94
|
cfGenerateExplorationResponse,
|
|
87
95
|
cfGenerateTemplateResponse,
|
|
88
96
|
cfGenerateTrialRun,
|
|
89
97
|
cfGetWikiMarkdown,
|
|
98
|
+
cfPremortemChatAgent,
|
|
99
|
+
cfPremortemKick,
|
|
90
100
|
cfPremortemRun,
|
|
91
101
|
cfPremortemStart,
|
|
92
102
|
cfRegenAssumptions,
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
withPerfTracking
|
|
6
6
|
} from "./chunk-OP4EO6FV.js";
|
|
7
7
|
import {
|
|
8
|
+
cfConsultingDiscoveryAgent,
|
|
9
|
+
cfExplorationAgent,
|
|
8
10
|
createExplorationSession,
|
|
9
11
|
getExplorationSession,
|
|
10
12
|
listExplorationSessions,
|
|
@@ -12,35 +14,12 @@ import {
|
|
|
12
14
|
requirePremiumWithAutoAuth,
|
|
13
15
|
updateExplorationSession,
|
|
14
16
|
validateRequestSize
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
16
18
|
|
|
17
19
|
// ../mcp/dist/mcp/src/exploration-server.js
|
|
18
20
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
19
21
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
22
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
-
import { GoogleAuth } from "google-auth-library";
|
|
22
|
-
var EXPLORATION_AGENT_FUNCTION_URL = process.env.EXPLORATION_AGENT_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/explorationAgent";
|
|
23
|
-
var CONSULTING_DISCOVERY_AGENT_FUNCTION_URL = process.env.CONSULTING_DISCOVERY_AGENT_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/consultingDiscoveryAgent";
|
|
24
|
-
async function callExplorationAgent(message, context) {
|
|
25
|
-
const auth = new GoogleAuth();
|
|
26
|
-
const client = await auth.getIdTokenClient(EXPLORATION_AGENT_FUNCTION_URL);
|
|
27
|
-
const response = await client.request({
|
|
28
|
-
url: EXPLORATION_AGENT_FUNCTION_URL,
|
|
29
|
-
method: "POST",
|
|
30
|
-
data: { message, context }
|
|
31
|
-
});
|
|
32
|
-
return response.data;
|
|
33
|
-
}
|
|
34
|
-
async function callConsultingDiscoveryAgent(message, context) {
|
|
35
|
-
const auth = new GoogleAuth();
|
|
36
|
-
const client = await auth.getIdTokenClient(CONSULTING_DISCOVERY_AGENT_FUNCTION_URL);
|
|
37
|
-
const response = await client.request({
|
|
38
|
-
url: CONSULTING_DISCOVERY_AGENT_FUNCTION_URL,
|
|
39
|
-
method: "POST",
|
|
40
|
-
data: { message, context }
|
|
41
|
-
});
|
|
42
|
-
return response.data;
|
|
43
|
-
}
|
|
44
23
|
var sessionCache = /* @__PURE__ */ new Map();
|
|
45
24
|
function generateId(mode = "product") {
|
|
46
25
|
const prefix = mode === "consulting" ? "cdisc" : "exp";
|
|
@@ -423,7 +402,7 @@ And what draws you to explore this area?`;
|
|
|
423
402
|
fallbackCount: session.fallbackCount || 0
|
|
424
403
|
};
|
|
425
404
|
console.error("[Discovery] Calling Consulting Discovery Cloud Function...");
|
|
426
|
-
response = await
|
|
405
|
+
response = await cfConsultingDiscoveryAgent(message, context);
|
|
427
406
|
} else {
|
|
428
407
|
const context = {
|
|
429
408
|
currentAct: session.currentAct,
|
|
@@ -435,7 +414,7 @@ And what draws you to explore this area?`;
|
|
|
435
414
|
fallbackCount: session.fallbackCount || 0
|
|
436
415
|
};
|
|
437
416
|
console.error("[Discovery] Calling Exploration Cloud Function...");
|
|
438
|
-
response = await
|
|
417
|
+
response = await cfExplorationAgent(message, context);
|
|
439
418
|
}
|
|
440
419
|
console.error("[Discovery] Cloud Function response received");
|
|
441
420
|
if (response.wasFallback) {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
requirePremiumWithAutoAuth,
|
|
14
14
|
validateAuth,
|
|
15
15
|
validateRequestSize
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
17
17
|
|
|
18
18
|
// ../mcp/dist/mcp/src/integrations-server.js
|
|
19
19
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
mapErrorToMcp,
|
|
14
14
|
requirePremiumWithAutoAuth,
|
|
15
15
|
validateRequestSize
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
17
17
|
|
|
18
18
|
// ../mcp/dist/mcp/src/output-server.js
|
|
19
19
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
withPerfTracking
|
|
12
12
|
} from "./chunk-OP4EO6FV.js";
|
|
13
13
|
import {
|
|
14
|
+
cfPremortemChatAgent,
|
|
15
|
+
cfPremortemKick,
|
|
14
16
|
cfRegenAssumptions,
|
|
15
17
|
cfRegenExperiments,
|
|
16
18
|
createPremortem,
|
|
@@ -25,7 +27,7 @@ import {
|
|
|
25
27
|
updatePremortem,
|
|
26
28
|
validateAuth,
|
|
27
29
|
validateRequestSize
|
|
28
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
29
31
|
|
|
30
32
|
// ../mcp/dist/mcp/src/premortem-server.js
|
|
31
33
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -142,19 +144,6 @@ function buildGraduationMetadata(sessionId, ctx, currentAct) {
|
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
// ../mcp/dist/mcp/src/premortem-server.js
|
|
145
|
-
import { GoogleAuth } from "google-auth-library";
|
|
146
|
-
var PREMORTEM_CHAT_FUNCTION_URL = process.env.PREMORTEM_CHAT_AGENT_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/premortemChatAgent";
|
|
147
|
-
var PREMORTEM_KICK_FUNCTION_URL = process.env.PREMORTEM_KICK_FUNCTION_URL || "https://us-central1-cutline-prod.cloudfunctions.net/premortemKick";
|
|
148
|
-
async function callPremortemChatAgent(message, context) {
|
|
149
|
-
const auth = new GoogleAuth();
|
|
150
|
-
const client = await auth.getIdTokenClient(PREMORTEM_CHAT_FUNCTION_URL);
|
|
151
|
-
const response = await client.request({
|
|
152
|
-
url: PREMORTEM_CHAT_FUNCTION_URL,
|
|
153
|
-
method: "POST",
|
|
154
|
-
data: { message, context }
|
|
155
|
-
});
|
|
156
|
-
return response.data;
|
|
157
|
-
}
|
|
158
147
|
var ACT_NAMES = {
|
|
159
148
|
1: "Product Understanding",
|
|
160
149
|
2: "Assumption Surfacing",
|
|
@@ -517,18 +506,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
517
506
|
if (!kickedFallback && data.status === "queued" && Date.now() - startTime > 1e4) {
|
|
518
507
|
console.error(`[Premortem] Job still queued after 10s, kicking via Cloud Function...`);
|
|
519
508
|
kickedFallback = true;
|
|
520
|
-
|
|
521
|
-
const auth = new GoogleAuth();
|
|
522
|
-
const client = await auth.getIdTokenClient(PREMORTEM_KICK_FUNCTION_URL);
|
|
523
|
-
client.request({
|
|
524
|
-
url: PREMORTEM_KICK_FUNCTION_URL,
|
|
525
|
-
method: "POST",
|
|
526
|
-
data: { id: jobId },
|
|
527
|
-
timeout: 6e5
|
|
528
|
-
}).catch((e) => console.error(`[Premortem] Kick fallback error:`, e?.message));
|
|
529
|
-
} catch (e) {
|
|
530
|
-
console.error(`[Premortem] Kick fallback failed:`, e?.message);
|
|
531
|
-
}
|
|
509
|
+
cfPremortemKick(jobId).catch((e) => console.error(`[Premortem] Kick fallback error:`, e?.message));
|
|
532
510
|
}
|
|
533
511
|
const stage = data.stage_label || data.stage;
|
|
534
512
|
const progress = data.progress;
|
|
@@ -603,22 +581,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
603
581
|
console.error(`[Premortem Kick] Authenticated: UID=${decoded?.uid}`);
|
|
604
582
|
console.error(`[Premortem Kick] Calling Cloud Function for job ${jobId}...`);
|
|
605
583
|
try {
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
const response = await client.request({
|
|
609
|
-
url: PREMORTEM_KICK_FUNCTION_URL,
|
|
610
|
-
method: "POST",
|
|
611
|
-
data: { id: jobId },
|
|
612
|
-
timeout: 6e5
|
|
613
|
-
// 10 minute timeout for full analysis
|
|
614
|
-
});
|
|
615
|
-
console.error(`[Premortem Kick] Cloud Function returned:`, response.data);
|
|
584
|
+
const result = await cfPremortemKick(jobId);
|
|
585
|
+
console.error(`[Premortem Kick] Cloud Function returned:`, result);
|
|
616
586
|
return {
|
|
617
587
|
content: [{ type: "text", text: JSON.stringify({
|
|
618
|
-
kicked:
|
|
619
|
-
status:
|
|
588
|
+
kicked: result.kicked,
|
|
589
|
+
status: result.status,
|
|
620
590
|
jobId,
|
|
621
|
-
message:
|
|
591
|
+
message: result.status === "completed" ? "\u2615 Full analysis complete! Use premortem_status to view results." : "Job processed. Use premortem_status to check results."
|
|
622
592
|
}) }]
|
|
623
593
|
};
|
|
624
594
|
} catch (e) {
|
|
@@ -788,7 +758,7 @@ Let's start with the basics. Tell me more about what you're building:
|
|
|
788
758
|
try {
|
|
789
759
|
const context = sessionToContext(session);
|
|
790
760
|
console.error("[PremortemChat] Calling Cloud Function...");
|
|
791
|
-
response = await
|
|
761
|
+
response = await cfPremortemChatAgent(message, context);
|
|
792
762
|
console.error("[PremortemChat] Cloud Function response received");
|
|
793
763
|
} catch (e) {
|
|
794
764
|
console.error("[PremortemChat] Cloud Function error:", e?.message || e);
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
requirePremiumWithAutoAuth,
|
|
22
22
|
validateAuth,
|
|
23
23
|
validateRequestSize
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TJTE5Q2C.js";
|
|
25
25
|
|
|
26
26
|
// ../mcp/dist/mcp/src/tools-server.js
|
|
27
27
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kylewadegrove/cutline-mcp-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
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",
|