@vibekiln/cutline-mcp-cli 0.4.2 → 0.4.4

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.
@@ -94,7 +94,7 @@ Skip: Pure styling, docs, formatting, non-security dep bumps.
94
94
  ## Magic Phrase
95
95
 
96
96
  If the user invokes Cutline naturally (for example: **"use cutline"**, **"use cutline to..."**, **"using cutline..."**, **"with cutline..."**), route automatically based on tier and intent:
97
- - Free/default intent: run \`code_audit(project_root)\`
97
+ - Free/default intent: run \`code_audit(project_root)\` (aka "security vibe check")
98
98
  - Premium product-linked intent: run \`engineering_audit(product_id, project_root)\`
99
99
  - Feature implementation intent: run \`rgr_plan(...)\` then \`constraints_auto(...)\`
100
100
  `;
@@ -109,7 +109,7 @@ alwaysApply: true
109
109
 
110
110
  # Cutline Constraints
111
111
 
112
- Run \`code_audit(project_root)\` before major implementations to check constraint coverage.
112
+ Run \`code_audit(project_root)\` before major implementations to run a security vibe check on constraint coverage.
113
113
 
114
114
  Severity levels:
115
115
  - **CRITICAL**: Must address before proceeding
@@ -184,7 +184,7 @@ Skip for: pure styling, docs, formatting, non-security dep bumps.
184
184
  ## Magic Phrase
185
185
 
186
186
  If the user invokes Cutline naturally (for example: **"use cutline"**, **"use cutline to..."**, **"using cutline..."**, **"with cutline..."**), route automatically based on tier and intent:
187
- - Free/default intent: \`code_audit(project_root)\`
187
+ - Free/default intent: \`code_audit(project_root)\` (aka "security vibe check")
188
188
  - Premium product-linked intent: \`engineering_audit(product_id, project_root)\`
189
189
  - Feature implementation intent: \`rgr_plan(...)\` then \`constraints_auto(...)\`
190
190
  `;
@@ -204,6 +204,9 @@ function ensureGitignore(projectRoot, patterns) {
204
204
  export async function initCommand(options) {
205
205
  const projectRoot = resolve(options.projectRoot ?? process.cwd());
206
206
  const config = readCutlineConfig(projectRoot);
207
+ const scanUrl = options.staging
208
+ ? 'https://cutline-staging.web.app/scan'
209
+ : 'https://thecutline.ai/scan';
207
210
  console.log(chalk.bold('\n🔧 Cutline Init\n'));
208
211
  // Authenticate and determine tier
209
212
  const spinner = ora('Checking authentication...').start();
@@ -212,6 +215,8 @@ export async function initCommand(options) {
212
215
  if (!auth) {
213
216
  spinner.warn(chalk.yellow('Not authenticated — generating free-tier rules'));
214
217
  console.log(chalk.dim(' Run `cutline-mcp login` to authenticate for richer config.\n'));
218
+ console.log(chalk.dim(' Or run a quick scan in the web app:'), chalk.cyan(scanUrl));
219
+ console.log();
215
220
  }
216
221
  else {
217
222
  tier = auth.tier;
@@ -292,6 +297,7 @@ export async function initCommand(options) {
292
297
  else if (tier === 'free') {
293
298
  console.log(chalk.dim('\n Upgrade to Premium for product-specific constraint graphs and .cutline.md'));
294
299
  console.log(chalk.dim(' →'), chalk.cyan('cutline-mcp upgrade'), chalk.dim('or https://thecutline.ai/upgrade'));
300
+ console.log(chalk.dim(' Free scan in browser:'), chalk.cyan(scanUrl));
295
301
  }
296
302
  if (generatedApiKey) {
297
303
  console.log();
@@ -392,8 +392,8 @@ export async function setupCommand(options) {
392
392
  { cmd: 'use cutline', desc: 'Magic phrase (also works with "use cutline to...", "using cutline...", "with cutline...") — Cutline infers intent and routes to the right flow' },
393
393
  { cmd: 'Run a deep dive on my product idea', desc: 'Pre-mortem analysis — risks, assumptions, experiments' },
394
394
  { cmd: 'Plan this feature with constraints from my product', desc: 'RGR plan — constraint-aware implementation roadmap' },
395
- { cmd: 'Run a code audit on this codebase', desc: 'Free code audit — security, reliability, and scalability (generic, not product-linked)' },
396
- { cmd: 'Run an engineering audit for my product', desc: 'Premium deep audit — product-linked analysis + RGR remediation plan' },
395
+ { cmd: 'Run a security vibe check on this codebase', desc: 'Free security vibe check (`code_audit`) — security, reliability, and scalability (generic, not product-linked)' },
396
+ { cmd: 'Run an engineering vibe check for my product', desc: 'Premium deep vibe check (`engineering_audit`) — product-linked analysis + RGR remediation plan' },
397
397
  { cmd: 'Check constraints for src/api/upload.ts', desc: 'Get NFR boundaries for a specific file' },
398
398
  { cmd: 'Generate .cutline.md for my product', desc: 'Write the constraint routing engine' },
399
399
  { cmd: 'What does my persona think about X?', desc: 'AI persona feedback on features' },
@@ -407,7 +407,7 @@ export async function setupCommand(options) {
407
407
  else {
408
408
  const items = [
409
409
  { cmd: 'use cutline', desc: 'Magic phrase (also works with "use cutline to...", "using cutline...", "with cutline...") — Cutline routes to the highest-value free flow for your intent' },
410
- { cmd: 'Run a code audit on this codebase', desc: 'Free code audit — security, reliability, and scalability scan (3/month free)' },
410
+ { cmd: 'Run a security vibe check on this codebase', desc: 'Free security vibe check (`code_audit`) — security, reliability, and scalability scan (3/month free)' },
411
411
  { cmd: 'Explore a product idea', desc: 'Free 6-act discovery flow to identify pain points and opportunities' },
412
412
  { cmd: 'Continue my exploration session', desc: 'Resume and refine an existing free exploration conversation' },
413
413
  ];
@@ -305,13 +305,17 @@ function getHiddenAuditDimensions() {
305
305
  const normalized = [...new Set(hidden.map((d) => String(d).trim().toLowerCase()).filter((d) => allowed.has(d)))];
306
306
  return normalized;
307
307
  }
308
- function getStoredApiKey() {
308
+ function getStoredApiKey(options) {
309
+ const includeConfig = options?.includeConfig ?? true;
309
310
  if (process.env.CUTLINE_API_KEY) {
310
311
  return {
311
312
  apiKey: process.env.CUTLINE_API_KEY,
312
313
  environment: process.env.CUTLINE_ENV === "staging" ? "staging" : "production"
313
314
  };
314
315
  }
316
+ if (!includeConfig) {
317
+ return null;
318
+ }
315
319
  const config = readLocalCutlineConfig();
316
320
  if (config?.apiKey) {
317
321
  return { apiKey: config.apiKey, environment: config.environment };
@@ -406,12 +410,15 @@ function getSiteUrl(environment) {
406
410
  return environment === "staging" ? "https://cutline-staging.web.app" : "https://thecutline.ai";
407
411
  }
408
412
  async function getPublicSiteUrlForCurrentAuth() {
413
+ const stored = await getStoredToken();
414
+ if (stored?.environment) {
415
+ return getSiteUrl(stored.environment);
416
+ }
409
417
  const apiKeyInfo = getStoredApiKey();
410
418
  if (apiKeyInfo?.environment) {
411
419
  return getSiteUrl(apiKeyInfo.environment);
412
420
  }
413
- const stored = await getStoredToken();
414
- return getSiteUrl(stored?.environment);
421
+ return getSiteUrl();
415
422
  }
416
423
  var cachedBaseUrl;
417
424
  var cachedIdToken;
@@ -455,27 +462,34 @@ async function exchangeRefreshForId(refreshToken, environment) {
455
462
  return data.id_token;
456
463
  }
457
464
  async function resolveAuth() {
458
- const apiKeyInfo = getStoredApiKey();
459
- if (apiKeyInfo) {
465
+ const envApiKeyInfo = getStoredApiKey({ includeConfig: false });
466
+ if (envApiKeyInfo) {
460
467
  return {
461
- baseUrl: getBaseUrl(apiKeyInfo.environment),
462
- idToken: apiKeyInfo.apiKey
468
+ baseUrl: getBaseUrl(envApiKeyInfo.environment),
469
+ idToken: envApiKeyInfo.apiKey
463
470
  };
464
471
  }
465
472
  if (cachedIdToken && Date.now() < tokenExpiresAt && cachedBaseUrl) {
466
473
  return { baseUrl: cachedBaseUrl, idToken: cachedIdToken };
467
474
  }
468
475
  const stored = await getStoredToken();
469
- if (!stored) {
470
- throw new Error("Not authenticated. Run 'cutline-mcp login' or set CUTLINE_API_KEY.");
476
+ if (stored) {
477
+ const env = stored.environment || "production";
478
+ const baseUrl = getBaseUrl(env);
479
+ const idToken = await exchangeRefreshForId(stored.refreshToken, env);
480
+ cachedBaseUrl = baseUrl;
481
+ cachedIdToken = idToken;
482
+ tokenExpiresAt = Date.now() + 50 * 60 * 1e3;
483
+ return { baseUrl, idToken };
484
+ }
485
+ const configApiKeyInfo = getStoredApiKey();
486
+ if (configApiKeyInfo) {
487
+ return {
488
+ baseUrl: getBaseUrl(configApiKeyInfo.environment),
489
+ idToken: configApiKeyInfo.apiKey
490
+ };
471
491
  }
472
- const env = stored.environment || "production";
473
- const baseUrl = getBaseUrl(env);
474
- const idToken = await exchangeRefreshForId(stored.refreshToken, env);
475
- cachedBaseUrl = baseUrl;
476
- cachedIdToken = idToken;
477
- tokenExpiresAt = Date.now() + 50 * 60 * 1e3;
478
- return { baseUrl, idToken };
492
+ throw new Error("Not authenticated. Run 'cutline-mcp login' or set CUTLINE_API_KEY.");
479
493
  }
480
494
  async function proxy(action, params = {}) {
481
495
  const { baseUrl, idToken } = await resolveAuth();
@@ -75,7 +75,7 @@ import {
75
75
  upsertEntities,
76
76
  upsertNodes,
77
77
  validateRequestSize
78
- } from "./chunk-6Y3AEXE3.js";
78
+ } from "./chunk-X2B5QUWO.js";
79
79
  import {
80
80
  GraphTraverser,
81
81
  computeGenericGraphMetrics,
@@ -8106,7 +8106,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8106
8106
  },
8107
8107
  {
8108
8108
  name: "code_audit",
8109
- description: "\u{1F513} FREE - Code audit. Evaluates your codebase against a stack-aware constraint graph covering security, reliability, and scalability. No deep dive or product_id required \u2014 just point at your codebase. Shows aggregate readiness scores and top critical findings; detailed analysis and remediation require Premium. Requires a Cutline account (free). 3 scans/month.",
8109
+ description: "\u{1F513} FREE - Security vibe check (code audit). Evaluates your codebase against a stack-aware constraint graph covering security, reliability, and scalability. No deep dive or product_id required \u2014 just point at your codebase. Shows aggregate readiness scores and top critical findings; detailed analysis and remediation require Premium. Requires a Cutline account (free). 3 scans/month.",
8110
8110
  inputSchema: {
8111
8111
  type: "object",
8112
8112
  properties: {
@@ -8119,7 +8119,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8119
8119
  },
8120
8120
  {
8121
8121
  name: "engineering_audit",
8122
- description: "\u{1F512} PREMIUM - Engineering audit for your product. Security-focused deep audit that scans local code, cross-references the product constraint graph, extracts security gaps, builds an RGR remediation plan, and optionally queues a deep dive job.",
8122
+ description: "\u{1F512} PREMIUM - Engineering vibe check (engineering audit) for your product. Security-focused deep audit that scans local code, cross-references the product constraint graph, extracts security gaps, builds an RGR remediation plan, and optionally queues a deep dive job.",
8123
8123
  inputSchema: {
8124
8124
  type: "object",
8125
8125
  properties: {
@@ -78,7 +78,7 @@ import {
78
78
  upsertEdges,
79
79
  upsertEntities,
80
80
  upsertNodes
81
- } from "./chunk-6Y3AEXE3.js";
81
+ } from "./chunk-X2B5QUWO.js";
82
82
  export {
83
83
  addEdges,
84
84
  addEntity,
@@ -14,7 +14,7 @@ import {
14
14
  requirePremiumWithAutoAuth,
15
15
  updateExplorationSession,
16
16
  validateRequestSize
17
- } from "./chunk-6Y3AEXE3.js";
17
+ } from "./chunk-X2B5QUWO.js";
18
18
 
19
19
  // ../mcp/dist/mcp/src/exploration-server.js
20
20
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -13,7 +13,7 @@ import {
13
13
  requirePremiumWithAutoAuth,
14
14
  validateAuth,
15
15
  validateRequestSize
16
- } from "./chunk-6Y3AEXE3.js";
16
+ } from "./chunk-X2B5QUWO.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-6Y3AEXE3.js";
16
+ } from "./chunk-X2B5QUWO.js";
17
17
 
18
18
  // ../mcp/dist/mcp/src/output-server.js
19
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -27,7 +27,7 @@ import {
27
27
  updatePremortem,
28
28
  validateAuth,
29
29
  validateRequestSize
30
- } from "./chunk-6Y3AEXE3.js";
30
+ } from "./chunk-X2B5QUWO.js";
31
31
 
32
32
  // ../mcp/dist/mcp/src/premortem-server.js
33
33
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -21,7 +21,7 @@ import {
21
21
  requirePremiumWithAutoAuth,
22
22
  validateAuth,
23
23
  validateRequestSize
24
- } from "./chunk-6Y3AEXE3.js";
24
+ } from "./chunk-X2B5QUWO.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": "@vibekiln/cutline-mcp-cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
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",