@vibekiln/cutline-mcp-cli 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 (43) hide show
  1. package/Dockerfile +11 -0
  2. package/README.md +248 -0
  3. package/dist/auth/callback.d.ts +6 -0
  4. package/dist/auth/callback.js +97 -0
  5. package/dist/auth/keychain.d.ts +3 -0
  6. package/dist/auth/keychain.js +16 -0
  7. package/dist/commands/init.d.ts +4 -0
  8. package/dist/commands/init.js +309 -0
  9. package/dist/commands/login.d.ts +7 -0
  10. package/dist/commands/login.js +166 -0
  11. package/dist/commands/logout.d.ts +1 -0
  12. package/dist/commands/logout.js +25 -0
  13. package/dist/commands/serve.d.ts +1 -0
  14. package/dist/commands/serve.js +38 -0
  15. package/dist/commands/setup.d.ts +5 -0
  16. package/dist/commands/setup.js +278 -0
  17. package/dist/commands/status.d.ts +3 -0
  18. package/dist/commands/status.js +127 -0
  19. package/dist/commands/upgrade.d.ts +3 -0
  20. package/dist/commands/upgrade.js +112 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +64 -0
  23. package/dist/servers/chunk-DE7R7WKY.js +331 -0
  24. package/dist/servers/chunk-KMUSQOTJ.js +47 -0
  25. package/dist/servers/chunk-OP4EO6FV.js +454 -0
  26. package/dist/servers/chunk-UBBAYTW3.js +946 -0
  27. package/dist/servers/chunk-ZVWDXO6M.js +1063 -0
  28. package/dist/servers/cutline-server.js +10448 -0
  29. package/dist/servers/data-client-FPUZBUO3.js +160 -0
  30. package/dist/servers/exploration-server.js +930 -0
  31. package/dist/servers/graph-metrics-DCNR7JZN.js +12 -0
  32. package/dist/servers/integrations-server.js +107 -0
  33. package/dist/servers/output-server.js +107 -0
  34. package/dist/servers/premortem-server.js +971 -0
  35. package/dist/servers/tools-server.js +287 -0
  36. package/dist/utils/config-store.d.ts +8 -0
  37. package/dist/utils/config-store.js +35 -0
  38. package/dist/utils/config.d.ts +22 -0
  39. package/dist/utils/config.js +48 -0
  40. package/mcpb/manifest.json +77 -0
  41. package/package.json +76 -0
  42. package/server.json +42 -0
  43. package/smithery.yaml +10 -0
@@ -0,0 +1,454 @@
1
+ // ../mcp/dist/mcp/src/shared/sanitize.js
2
+ var NULL_AND_CONTROL_RE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
3
+ var HTML_TAG_RE = /<\/?[a-z][^>]*>/gi;
4
+ var SCRIPT_RE = /<script[\s>][\s\S]*?<\/script>/gi;
5
+ var EVENT_HANDLER_RE = /\s+on\w+\s*=\s*["'][^"']*["']/gi;
6
+ function stripControlChars(input) {
7
+ return input.replace(NULL_AND_CONTROL_RE, "");
8
+ }
9
+ function stripHtmlTags(input) {
10
+ return input.replace(SCRIPT_RE, "").replace(EVENT_HANDLER_RE, "").replace(HTML_TAG_RE, "");
11
+ }
12
+ var DEFAULT_MAX_LENGTH = 5e4;
13
+ function sanitizeText(input, options = {}) {
14
+ const { maxLength = DEFAULT_MAX_LENGTH, stripHtml = true } = options;
15
+ let result = stripControlChars(input);
16
+ if (stripHtml) {
17
+ result = stripHtmlTags(result);
18
+ }
19
+ result = result.trim();
20
+ if (result.length > maxLength) {
21
+ result = result.slice(0, maxLength);
22
+ }
23
+ return result;
24
+ }
25
+ function sanitizeArgs(value, options = {}) {
26
+ if (typeof value === "string") {
27
+ return sanitizeText(value, options);
28
+ }
29
+ if (Array.isArray(value)) {
30
+ return value.map((item) => sanitizeArgs(item, options));
31
+ }
32
+ if (value !== null && typeof value === "object" && !(value instanceof Date)) {
33
+ const result = {};
34
+ for (const [key, val] of Object.entries(value)) {
35
+ result[key] = sanitizeArgs(val, options);
36
+ }
37
+ return result;
38
+ }
39
+ return value;
40
+ }
41
+
42
+ // ../mcp/dist/mcp/src/shared/pii-scanner.js
43
+ var patterns = [
44
+ // ── Secrets ──────────────────────────────────────────────────────────────
45
+ {
46
+ type: "aws_key",
47
+ pattern: /AKIA[0-9A-Z]{16}/g,
48
+ severity: "critical",
49
+ description: "AWS Access Key ID",
50
+ validate: (m) => m.length === 20
51
+ },
52
+ {
53
+ type: "aws_secret",
54
+ pattern: /(?:aws_secret_access_key|secret_access_key|aws_secret)\s*[=:]\s*[A-Za-z0-9/+=]{40}/g,
55
+ severity: "critical",
56
+ description: "AWS Secret Access Key"
57
+ },
58
+ {
59
+ type: "stripe_key",
60
+ pattern: /[sr]k_(live|test)_[0-9a-zA-Z]{24,}/g,
61
+ severity: "critical",
62
+ description: "Stripe API key"
63
+ },
64
+ {
65
+ type: "stripe_key",
66
+ pattern: /pk_(live|test)_[0-9a-zA-Z]{24,}/g,
67
+ severity: "critical",
68
+ description: "Stripe publishable key"
69
+ },
70
+ {
71
+ type: "github_token",
72
+ pattern: /gh[ps]_[A-Za-z0-9]{36,}/g,
73
+ severity: "critical",
74
+ description: "GitHub personal access token"
75
+ },
76
+ {
77
+ type: "github_token",
78
+ pattern: /github_pat_[A-Za-z0-9_]{20,}/g,
79
+ severity: "critical",
80
+ description: "GitHub fine-grained personal access token"
81
+ },
82
+ {
83
+ type: "bearer_token",
84
+ pattern: /Bearer\s+[A-Za-z0-9\-._~+/]+=*/g,
85
+ severity: "critical",
86
+ description: "Bearer authorization token"
87
+ },
88
+ {
89
+ type: "generic_api_key",
90
+ pattern: /(?:api[_-]?key|apikey|api[_-]?secret|secret[_-]?key)\s*[=:"']\s*["']?([A-Za-z0-9\-._~+/]{20,})["']?/gi,
91
+ severity: "warning",
92
+ description: "Generic API key/secret assignment"
93
+ },
94
+ // ── PII ──────────────────────────────────────────────────────────────────
95
+ {
96
+ type: "credit_card",
97
+ pattern: /\b(?:4[0-9]{3}|5[1-5][0-9]{2}|3[47][0-9]{2}|6(?:011|5[0-9]{2}))[- ]?[0-9]{4}[- ]?[0-9]{4}[- ]?[0-9]{4}\b/g,
98
+ severity: "critical",
99
+ description: "Credit card number (Visa, MC, Amex, Discover)"
100
+ },
101
+ {
102
+ type: "ssn",
103
+ pattern: /(?:ssn|social\s*security(?:\s*number)?|ss#)\s*(?:number\s*)?[:\s]?\s*(\d{3})-?(\d{2})-?(\d{4})/gi,
104
+ severity: "critical",
105
+ description: "US Social Security Number (context-required)",
106
+ validate: (_m, _full, _idx) => true
107
+ },
108
+ {
109
+ type: "phone_number",
110
+ pattern: /(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}/g,
111
+ severity: "warning",
112
+ description: "US phone number"
113
+ },
114
+ {
115
+ type: "email",
116
+ pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
117
+ severity: "info",
118
+ description: "Email address"
119
+ }
120
+ ];
121
+ var DEFAULT_PATTERNS = Object.freeze(patterns.map((p) => ({ ...p })));
122
+ var REDACT_LABELS = {
123
+ aws_key: "[AWS_KEY]",
124
+ aws_secret: "[AWS_SECRET]",
125
+ stripe_key: "[STRIPE_KEY]",
126
+ github_token: "[GITHUB_TOKEN]",
127
+ bearer_token: "[BEARER_TOKEN]",
128
+ generic_api_key: "[API_KEY]",
129
+ credit_card: "[CREDIT_CARD]",
130
+ ssn: "[SSN]",
131
+ phone_number: "[PHONE]",
132
+ email: "[EMAIL]"
133
+ };
134
+ function scanForPii(input) {
135
+ return runScan(input, patterns);
136
+ }
137
+ function runScan(input, defs) {
138
+ if (!input) {
139
+ return { matches: [], flags_by_type: {}, scanned_chars: 0, redacted: "" };
140
+ }
141
+ const allMatches = [];
142
+ for (const def of defs) {
143
+ const re = new RegExp(def.pattern.source, def.pattern.flags);
144
+ let m;
145
+ while ((m = re.exec(input)) !== null) {
146
+ const text = m[0];
147
+ const start = m.index;
148
+ const end = start + text.length;
149
+ if (def.validate && !def.validate(text, input, start)) {
150
+ continue;
151
+ }
152
+ allMatches.push({
153
+ type: def.type,
154
+ text,
155
+ start,
156
+ end,
157
+ severity: def.severity
158
+ });
159
+ }
160
+ }
161
+ allMatches.sort((a, b) => a.start - b.start);
162
+ const deduped = deduplicateOverlaps(allMatches);
163
+ const flags_by_type = {};
164
+ for (const match of deduped) {
165
+ flags_by_type[match.type] = (flags_by_type[match.type] || 0) + 1;
166
+ }
167
+ const redacted = buildRedacted(input, deduped);
168
+ return {
169
+ matches: deduped,
170
+ flags_by_type,
171
+ scanned_chars: input.length,
172
+ redacted
173
+ };
174
+ }
175
+ function deduplicateOverlaps(sorted) {
176
+ if (sorted.length <= 1)
177
+ return sorted;
178
+ const severityRank = {
179
+ critical: 3,
180
+ warning: 2,
181
+ info: 1
182
+ };
183
+ const result = [sorted[0]];
184
+ for (let i = 1; i < sorted.length; i++) {
185
+ const prev = result[result.length - 1];
186
+ const curr = sorted[i];
187
+ if (curr.start < prev.end) {
188
+ const prevRank = severityRank[prev.severity];
189
+ const currRank = severityRank[curr.severity];
190
+ if (currRank > prevRank || currRank === prevRank && curr.end - curr.start > prev.end - prev.start) {
191
+ result[result.length - 1] = curr;
192
+ }
193
+ } else {
194
+ result.push(curr);
195
+ }
196
+ }
197
+ return result;
198
+ }
199
+ function buildRedacted(input, matches) {
200
+ if (matches.length === 0)
201
+ return input;
202
+ const parts = [];
203
+ let cursor = 0;
204
+ for (const match of matches) {
205
+ if (match.start > cursor) {
206
+ parts.push(input.slice(cursor, match.start));
207
+ }
208
+ parts.push(REDACT_LABELS[match.type] || `[${match.type.toUpperCase()}]`);
209
+ cursor = match.end;
210
+ }
211
+ if (cursor < input.length) {
212
+ parts.push(input.slice(cursor));
213
+ }
214
+ return parts.join("");
215
+ }
216
+
217
+ // ../mcp/dist/mcp/src/shared/boundary-guard.js
218
+ var DEFAULT_OPTS = { stripHtml: false, maxLength: 1e5 };
219
+ function guardBoundary(toolName, rawArgs, opts = DEFAULT_OPTS) {
220
+ const args = sanitizeArgs(rawArgs, opts);
221
+ const piiResults = [];
222
+ for (const [key, val] of Object.entries(args)) {
223
+ if (typeof val === "string" && val.length > 0) {
224
+ const scan = scanForPii(val);
225
+ if (scan.matches.length > 0) {
226
+ piiResults.push({ field: key, result: scan });
227
+ auditLog("pii_detected", "tool_call", toolName, {
228
+ field: key,
229
+ flags_by_type: scan.flags_by_type,
230
+ match_count: scan.matches.length,
231
+ scanned_chars: scan.scanned_chars
232
+ });
233
+ }
234
+ }
235
+ }
236
+ return {
237
+ args,
238
+ piiDetected: piiResults.length > 0,
239
+ piiResults
240
+ };
241
+ }
242
+ function guardOutput(toolName, response) {
243
+ let totalRedactions = 0;
244
+ const content = response.content.map((block) => {
245
+ if (block.type !== "text" || !block.text)
246
+ return block;
247
+ const scan = scanForPii(block.text);
248
+ if (scan.matches.length === 0)
249
+ return block;
250
+ totalRedactions += scan.matches.length;
251
+ return { ...block, text: scan.redacted };
252
+ });
253
+ if (totalRedactions > 0) {
254
+ auditLog("secret_in_output", "tool_response", toolName, {
255
+ redaction_count: totalRedactions
256
+ });
257
+ }
258
+ return {
259
+ ...response,
260
+ content,
261
+ _secretsRedacted: totalRedactions > 0,
262
+ _redactionCount: totalRedactions
263
+ };
264
+ }
265
+ function auditLog(eventType, resourceType, resourceId, data) {
266
+ console.error(JSON.stringify({
267
+ audit: true,
268
+ severity: "INFO",
269
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
270
+ eventType,
271
+ resourceType,
272
+ resourceId,
273
+ data
274
+ }));
275
+ }
276
+
277
+ // ../mcp/dist/mcp/src/shared/perf-tracker.js
278
+ var PerfTracker = class {
279
+ entries = /* @__PURE__ */ new Map();
280
+ windowMs;
281
+ failureAlertThreshold;
282
+ onFailureAlert;
283
+ latencyThresholds;
284
+ maxEntriesPerTool;
285
+ startedAt = Date.now();
286
+ alertActive = false;
287
+ constructor(options = {}) {
288
+ this.windowMs = options.windowMs ?? 5 * 60 * 1e3;
289
+ this.failureAlertThreshold = options.failureAlertThreshold ?? 0.05;
290
+ this.onFailureAlert = options.onFailureAlert;
291
+ this.latencyThresholds = options.latencyThresholds ?? [];
292
+ this.maxEntriesPerTool = options.maxEntriesPerTool ?? 1e4;
293
+ }
294
+ record(tool, latencyMs, success) {
295
+ if (!this.entries.has(tool)) {
296
+ this.entries.set(tool, []);
297
+ }
298
+ const bucket = this.entries.get(tool);
299
+ bucket.push({ timestamp: Date.now(), latencyMs, success });
300
+ if (bucket.length > this.maxEntriesPerTool) {
301
+ bucket.splice(0, bucket.length - this.maxEntriesPerTool);
302
+ }
303
+ this.checkFailureAlert();
304
+ }
305
+ getToolMetrics(tool) {
306
+ const active = this.getActiveEntries(tool);
307
+ if (!active || active.length === 0)
308
+ return void 0;
309
+ return this.computeMetrics(active);
310
+ }
311
+ getSnapshot() {
312
+ const tools = {};
313
+ let totalCalls = 0;
314
+ let totalFailures = 0;
315
+ for (const tool of this.entries.keys()) {
316
+ const active = this.getActiveEntries(tool);
317
+ if (active.length === 0)
318
+ continue;
319
+ const metrics = this.computeMetrics(active);
320
+ tools[tool] = metrics;
321
+ totalCalls += metrics.totalCalls;
322
+ totalFailures += metrics.failureCount;
323
+ }
324
+ return {
325
+ tools,
326
+ totalCalls,
327
+ globalFailureRate: totalCalls > 0 ? totalFailures / totalCalls : 0,
328
+ uptimeMs: Date.now() - this.startedAt,
329
+ windowMs: this.windowMs
330
+ };
331
+ }
332
+ getThresholdBreaches() {
333
+ const breaches = [];
334
+ for (const threshold of this.latencyThresholds) {
335
+ const metrics = this.getToolMetrics(threshold.tool);
336
+ if (!metrics)
337
+ continue;
338
+ const actual = metrics[threshold.percentile];
339
+ if (actual > threshold.maxMs) {
340
+ breaches.push({ ...threshold, actual });
341
+ }
342
+ }
343
+ return breaches;
344
+ }
345
+ // ═════════════════════════════════════════════════════════════════════════════
346
+ // INTERNALS
347
+ // ═════════════════════════════════════════════════════════════════════════════
348
+ getActiveEntries(tool) {
349
+ const bucket = this.entries.get(tool);
350
+ if (!bucket)
351
+ return [];
352
+ const cutoff = Date.now() - this.windowMs;
353
+ const active = bucket.filter((e) => e.timestamp >= cutoff);
354
+ this.entries.set(tool, active);
355
+ return active;
356
+ }
357
+ computeMetrics(entries) {
358
+ const latencies = entries.map((e) => e.latencyMs).sort((a, b) => a - b);
359
+ const successCount = entries.filter((e) => e.success).length;
360
+ const failureCount = entries.length - successCount;
361
+ const sum = latencies.reduce((a, b) => a + b, 0);
362
+ return {
363
+ totalCalls: entries.length,
364
+ successCount,
365
+ failureCount,
366
+ failureRate: entries.length > 0 ? failureCount / entries.length : 0,
367
+ p50: percentile(latencies, 0.5),
368
+ p95: percentile(latencies, 0.95),
369
+ p99: percentile(latencies, 0.99),
370
+ avgMs: Math.round(sum / entries.length),
371
+ minMs: latencies[0],
372
+ maxMs: latencies[latencies.length - 1]
373
+ };
374
+ }
375
+ checkFailureAlert() {
376
+ const snap = this.getSnapshot();
377
+ if (snap.totalCalls === 0)
378
+ return;
379
+ if (snap.globalFailureRate > this.failureAlertThreshold) {
380
+ if (!this.alertActive) {
381
+ this.alertActive = true;
382
+ auditLog2("perf_failure_alert", snap);
383
+ this.onFailureAlert?.(snap);
384
+ }
385
+ } else {
386
+ this.alertActive = false;
387
+ }
388
+ }
389
+ };
390
+ function percentile(sorted, p) {
391
+ if (sorted.length === 0)
392
+ return 0;
393
+ if (sorted.length === 1)
394
+ return sorted[0];
395
+ const idx = (sorted.length - 1) * p;
396
+ const lo = Math.floor(idx);
397
+ const hi = Math.ceil(idx);
398
+ if (lo === hi)
399
+ return sorted[lo];
400
+ return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);
401
+ }
402
+ function auditLog2(eventType, snapshot) {
403
+ const toolSummary = {};
404
+ for (const [tool, m] of Object.entries(snapshot.tools)) {
405
+ toolSummary[tool] = { calls: m.totalCalls, failRate: m.failureRate, p95: m.p95 };
406
+ }
407
+ console.error(JSON.stringify({
408
+ audit: true,
409
+ severity: "ERROR",
410
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
411
+ eventType,
412
+ resourceType: "mcp_perf",
413
+ data: {
414
+ globalFailureRate: snapshot.globalFailureRate,
415
+ totalCalls: snapshot.totalCalls,
416
+ tools: toolSummary
417
+ }
418
+ }));
419
+ }
420
+
421
+ // ../mcp/dist/mcp/src/shared/perf-tracker-instance.js
422
+ var LATENCY_THRESHOLDS = [
423
+ { tool: "exploration_start", percentile: "p99", maxMs: 500 },
424
+ { tool: "discovery_start", percentile: "p99", maxMs: 500 },
425
+ { tool: "constraints_query", percentile: "p95", maxMs: 800 },
426
+ { tool: "constraints_semantic_query", percentile: "p95", maxMs: 800 },
427
+ { tool: "template_discover", percentile: "p95", maxMs: 500 },
428
+ { tool: "template_list", percentile: "p95", maxMs: 500 }
429
+ ];
430
+ var perfTracker = new PerfTracker({
431
+ windowMs: 5 * 60 * 1e3,
432
+ failureAlertThreshold: 0.05,
433
+ latencyThresholds: LATENCY_THRESHOLDS,
434
+ maxEntriesPerTool: 5e3
435
+ });
436
+ async function withPerfTracking(toolName, fn) {
437
+ const start = Date.now();
438
+ let success = true;
439
+ try {
440
+ return await fn();
441
+ } catch (err) {
442
+ success = false;
443
+ throw err;
444
+ } finally {
445
+ perfTracker.record(toolName, Date.now() - start, success);
446
+ }
447
+ }
448
+
449
+ export {
450
+ guardBoundary,
451
+ guardOutput,
452
+ perfTracker,
453
+ withPerfTracking
454
+ };