@kylewadegrove/cutline-mcp-cli-staging 0.3.0 → 0.4.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.
- package/README.md +12 -0
- package/dist/commands/init.js +12 -0
- package/dist/commands/setup.js +15 -0
- package/dist/servers/cutline-server.js +104 -7
- package/dist/utils/agent-funnel.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,6 +35,16 @@ cutline-mcp setup
|
|
|
35
35
|
|
|
36
36
|
Then ask your AI agent: **"use cutline"**
|
|
37
37
|
|
|
38
|
+
For test-heavy flows, use the explicit bootstrap + route:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx -y @vibekiln/cutline-mcp-cli@latest setup
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then ask:
|
|
45
|
+
- `Write tests for this PR`
|
|
46
|
+
- `use cutline to generate and run constraint-grounded tests for this scope increase`
|
|
47
|
+
|
|
38
48
|
Cutline interprets intent and tier:
|
|
39
49
|
- Natural variants also work: `use cutline to ...`, `using cutline, ...`, `with cutline ...`
|
|
40
50
|
- Free/default: runs `code_audit` (generic codebase scan)
|
|
@@ -185,6 +195,8 @@ The `init` command creates rules that make your AI coding agent follow the Red-G
|
|
|
185
195
|
3. **Verify** — Run a code audit to check coverage
|
|
186
196
|
4. **Complete** — Mark the phase done to update readiness scores
|
|
187
197
|
|
|
198
|
+
When the agent detects testing intent (write/generate/validate tests), it should route through Cutline first and, if not configured, prompt the install bootstrap command above before continuing.
|
|
199
|
+
|
|
188
200
|
### Compliance Frameworks
|
|
189
201
|
|
|
190
202
|
Cutline auto-detects your stack and loads the appropriate compliance constraints:
|
package/dist/commands/init.js
CHANGED
|
@@ -129,6 +129,12 @@ If the user invokes Cutline naturally (for example: **"use cutline"**, **"use cu
|
|
|
129
129
|
- Free/default intent: run \`code_audit(project_root)\` (aka "security vibe check")
|
|
130
130
|
- Premium product-linked intent: run \`engineering_audit(product_id, project_root)\`
|
|
131
131
|
- Feature implementation intent: run \`rgr_plan(...)\` then \`constraints_auto(...)\`
|
|
132
|
+
|
|
133
|
+
## Testing Intent Auto-Route
|
|
134
|
+
|
|
135
|
+
If asked to write, generate, validate, or improve tests, route to Cutline first:
|
|
136
|
+
- If Cutline MCP is missing, provide install bootstrap: \`npx -y @vibekiln/cutline-mcp-cli@latest setup\`
|
|
137
|
+
- Then run: \`use cutline to generate and run constraint-grounded tests for this scope increase\`
|
|
132
138
|
`;
|
|
133
139
|
}
|
|
134
140
|
function cursorConstraintsRule(config, tier) {
|
|
@@ -219,6 +225,12 @@ If the user invokes Cutline naturally (for example: **"use cutline"**, **"use cu
|
|
|
219
225
|
- Free/default intent: \`code_audit(project_root)\` (aka "security vibe check")
|
|
220
226
|
- Premium product-linked intent: \`engineering_audit(product_id, project_root)\`
|
|
221
227
|
- Feature implementation intent: \`rgr_plan(...)\` then \`constraints_auto(...)\`
|
|
228
|
+
|
|
229
|
+
## Testing Intent Auto-Route
|
|
230
|
+
|
|
231
|
+
If asked to write, generate, validate, or improve tests, route to Cutline first:
|
|
232
|
+
- If Cutline MCP is missing, provide install bootstrap: \`npx -y @vibekiln/cutline-mcp-cli@latest setup\`
|
|
233
|
+
- Then run: \`use cutline to generate and run constraint-grounded tests for this scope increase\`
|
|
222
234
|
`;
|
|
223
235
|
}
|
|
224
236
|
function ensureGitignore(projectRoot, patterns) {
|
package/dist/commands/setup.js
CHANGED
|
@@ -403,6 +403,16 @@ export async function setupCommand(options) {
|
|
|
403
403
|
flow: 'onboarding',
|
|
404
404
|
},
|
|
405
405
|
});
|
|
406
|
+
await trackAgentEvent({
|
|
407
|
+
idToken,
|
|
408
|
+
installId,
|
|
409
|
+
eventName: 'agent_cutline_install_completed',
|
|
410
|
+
staging: options.staging,
|
|
411
|
+
eventProperties: {
|
|
412
|
+
command: 'setup',
|
|
413
|
+
route: 'testing_rgr',
|
|
414
|
+
},
|
|
415
|
+
});
|
|
406
416
|
}
|
|
407
417
|
}
|
|
408
418
|
// ── 5. Claude Code one-liners ────────────────────────────────────────────
|
|
@@ -424,9 +434,11 @@ export async function setupCommand(options) {
|
|
|
424
434
|
const items = [
|
|
425
435
|
{ 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' },
|
|
426
436
|
{ cmd: 'Run a deep dive on my product idea', desc: 'Pre-mortem analysis — risks, assumptions, experiments' },
|
|
437
|
+
{ cmd: 'Write tests for this PR', desc: 'Testing intent shortcut — Cutline should route to graph-grounded test generation + RGR verification loop' },
|
|
427
438
|
{ cmd: 'Plan this feature with constraints from my product', desc: 'RGR plan — constraint-aware implementation roadmap' },
|
|
428
439
|
{ cmd: 'Run a security vibe check on this codebase', desc: 'Free security vibe check (`code_audit`) — security, reliability, and scalability (generic, not product-linked)' },
|
|
429
440
|
{ cmd: 'Run an engineering vibe check for my product', desc: 'Premium deep vibe check (`engineering_audit`) — product-linked analysis + RGR remediation plan' },
|
|
441
|
+
{ cmd: 'use cutline to generate and run tests for this scope increase', desc: 'Preferred prompt for pervasive red/green loop execution' },
|
|
430
442
|
{ cmd: 'Check constraints for src/api/upload.ts', desc: 'Get NFR boundaries for a specific file' },
|
|
431
443
|
{ cmd: 'Generate .cutline.md for my product', desc: 'Write the constraint routing engine' },
|
|
432
444
|
{ cmd: 'What does my persona think about X?', desc: 'AI persona feedback on features' },
|
|
@@ -441,6 +453,8 @@ export async function setupCommand(options) {
|
|
|
441
453
|
const items = [
|
|
442
454
|
{ 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' },
|
|
443
455
|
{ cmd: 'Run a security vibe check on this codebase', desc: 'Free security vibe check (`code_audit`) — security, reliability, and scalability scan (3/month free)' },
|
|
456
|
+
{ cmd: 'Write tests for this PR', desc: 'Testing intent shortcut — prompts install/setup guidance if Cutline MCP is missing' },
|
|
457
|
+
{ cmd: 'use cutline to generate tests for this scope increase', desc: 'Runs free-tier test-oriented routing and verification guidance where available' },
|
|
444
458
|
{ cmd: 'Explore a product idea', desc: 'Free 6-act discovery flow to identify pain points and opportunities' },
|
|
445
459
|
{ cmd: 'Continue my exploration session', desc: 'Resume and refine an existing free exploration conversation' },
|
|
446
460
|
];
|
|
@@ -454,6 +468,7 @@ export async function setupCommand(options) {
|
|
|
454
468
|
}
|
|
455
469
|
console.log();
|
|
456
470
|
console.log(chalk.dim(` cutline-mcp v${version} · docs: https://thecutline.ai/docs/setup`));
|
|
471
|
+
console.log(chalk.dim(' Testing bootstrap:'), chalk.cyan('npx -y @vibekiln/cutline-mcp-cli@latest setup'));
|
|
457
472
|
console.log(chalk.dim(' Optional repo policy contract:'), chalk.cyan('cutline-mcp policy-init'));
|
|
458
473
|
console.log();
|
|
459
474
|
}
|
|
@@ -6596,6 +6596,11 @@ async function handleCodeAudit(args, deps) {
|
|
|
6596
6596
|
},
|
|
6597
6597
|
sensitiveDataCount: scanResult.sensitive_data.fields.length,
|
|
6598
6598
|
rgrPlan,
|
|
6599
|
+
rgrAutoTrigger: {
|
|
6600
|
+
enabled: true,
|
|
6601
|
+
onScopeIncrease: true,
|
|
6602
|
+
executionMode: "local_vitest"
|
|
6603
|
+
},
|
|
6599
6604
|
securityGaps: graphAnalysis.securityGaps
|
|
6600
6605
|
}
|
|
6601
6606
|
};
|
|
@@ -7649,6 +7654,43 @@ async function emitPolicyGateEvent(input) {
|
|
|
7649
7654
|
} catch {
|
|
7650
7655
|
}
|
|
7651
7656
|
}
|
|
7657
|
+
async function emitAgentEvent(input) {
|
|
7658
|
+
if (!input.authToken || !input.installId)
|
|
7659
|
+
return;
|
|
7660
|
+
const siteUrl = (process.env.NEXT_PUBLIC_SITE_URL || "https://thecutline.ai").replace(/\/$/, "");
|
|
7661
|
+
try {
|
|
7662
|
+
await fetch(`${siteUrl}/api/agent/event`, {
|
|
7663
|
+
method: "POST",
|
|
7664
|
+
headers: {
|
|
7665
|
+
"Content-Type": "application/json",
|
|
7666
|
+
Authorization: `Bearer ${input.authToken}`
|
|
7667
|
+
},
|
|
7668
|
+
body: JSON.stringify({
|
|
7669
|
+
install_id: input.installId,
|
|
7670
|
+
event_name: input.eventName,
|
|
7671
|
+
event_properties: input.eventProperties || {}
|
|
7672
|
+
})
|
|
7673
|
+
});
|
|
7674
|
+
} catch {
|
|
7675
|
+
}
|
|
7676
|
+
}
|
|
7677
|
+
function isTestingIntentPrompt(prompt) {
|
|
7678
|
+
return /\b(test|tests|testing|vitest|jest|coverage|unit test|integration test|e2e|spec file|assertion)\b/i.test(prompt);
|
|
7679
|
+
}
|
|
7680
|
+
function buildTestingIntentHintResponse(prompt) {
|
|
7681
|
+
return {
|
|
7682
|
+
detected: true,
|
|
7683
|
+
intent: "testing",
|
|
7684
|
+
route: "cutline_testing_rgr",
|
|
7685
|
+
prompts: [
|
|
7686
|
+
"use cutline to generate tests for this scope increase",
|
|
7687
|
+
"use cutline to run the RGR loop for this change",
|
|
7688
|
+
"use cutline to evaluate merge gates for this test run"
|
|
7689
|
+
],
|
|
7690
|
+
bootstrap_if_missing: "npx -y @vibekiln/cutline-mcp-cli@latest setup",
|
|
7691
|
+
source_prompt_excerpt: prompt.slice(0, 180)
|
|
7692
|
+
};
|
|
7693
|
+
}
|
|
7652
7694
|
var DEFAULT_MODEL = process.env.MODEL_ID || "gemini-2.5-pro";
|
|
7653
7695
|
var GOVERNANCE_ENFORCEMENT = (process.env.CUTLINE_GOVERNANCE_ENFORCEMENT || "advisory").toLowerCase() === "enforced";
|
|
7654
7696
|
function buildGovernanceEnvelope(input) {
|
|
@@ -8156,7 +8198,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
8156
8198
|
type: "object",
|
|
8157
8199
|
properties: {
|
|
8158
8200
|
prompt: { type: "string" },
|
|
8159
|
-
wikiMarkdown: { type: "string" }
|
|
8201
|
+
wikiMarkdown: { type: "string" },
|
|
8202
|
+
auth_token: { type: "string", description: "Optional auth token for telemetry attribution" },
|
|
8203
|
+
install_id: { type: "string", description: "Optional install ID for telemetry attribution" }
|
|
8160
8204
|
},
|
|
8161
8205
|
required: ["prompt"]
|
|
8162
8206
|
}
|
|
@@ -8185,7 +8229,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
8185
8229
|
inputSchema: {
|
|
8186
8230
|
type: "object",
|
|
8187
8231
|
properties: {
|
|
8188
|
-
prompt: { type: "string" }
|
|
8232
|
+
prompt: { type: "string" },
|
|
8233
|
+
auth_token: { type: "string", description: "Optional auth token for telemetry attribution" },
|
|
8234
|
+
install_id: { type: "string", description: "Optional install ID for telemetry attribution" }
|
|
8189
8235
|
},
|
|
8190
8236
|
required: ["prompt"]
|
|
8191
8237
|
}
|
|
@@ -8962,9 +9008,32 @@ Why AI: ${idea.whyAI}`
|
|
|
8962
9008
|
};
|
|
8963
9009
|
}
|
|
8964
9010
|
if (name2 === "trial_generate") {
|
|
8965
|
-
const
|
|
9011
|
+
const trialArgs = args;
|
|
9012
|
+
const { prompt } = trialArgs;
|
|
8966
9013
|
const text = await cfGenerateTrialRun(prompt);
|
|
8967
|
-
|
|
9014
|
+
const isTestingIntent = isTestingIntentPrompt(prompt);
|
|
9015
|
+
const env = process.env.CUTLINE_ENV === "staging" ? "staging" : "production";
|
|
9016
|
+
const resolvedInstallId = trialArgs.install_id || getStoredInstallId({ environment: env });
|
|
9017
|
+
if (isTestingIntent) {
|
|
9018
|
+
await emitAgentEvent({
|
|
9019
|
+
authToken: trialArgs.auth_token,
|
|
9020
|
+
installId: resolvedInstallId || void 0,
|
|
9021
|
+
eventName: "agent_test_intent_detected",
|
|
9022
|
+
eventProperties: {
|
|
9023
|
+
tool_name: "trial_generate",
|
|
9024
|
+
route: "cutline_testing_rgr"
|
|
9025
|
+
}
|
|
9026
|
+
});
|
|
9027
|
+
}
|
|
9028
|
+
return {
|
|
9029
|
+
content: [{
|
|
9030
|
+
type: "text",
|
|
9031
|
+
text: JSON.stringify({
|
|
9032
|
+
text,
|
|
9033
|
+
...isTestingIntent ? { cutline_testing_route: buildTestingIntentHintResponse(prompt) } : {}
|
|
9034
|
+
})
|
|
9035
|
+
}]
|
|
9036
|
+
};
|
|
8968
9037
|
}
|
|
8969
9038
|
if (name2 === "get_assurance_manifest") {
|
|
8970
9039
|
const { url } = args;
|
|
@@ -9358,9 +9427,32 @@ Competitive threats: ${competitors}` : ""
|
|
|
9358
9427
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
9359
9428
|
}
|
|
9360
9429
|
case "agent_chat": {
|
|
9361
|
-
const
|
|
9430
|
+
const chatArgs = args;
|
|
9431
|
+
const { prompt, wikiMarkdown } = chatArgs;
|
|
9362
9432
|
const text = await cfGenerateChatSuggestion(prompt, wikiMarkdown);
|
|
9363
|
-
|
|
9433
|
+
const isTestingIntent = isTestingIntentPrompt(prompt);
|
|
9434
|
+
const env = process.env.CUTLINE_ENV === "staging" ? "staging" : "production";
|
|
9435
|
+
const resolvedInstallId = chatArgs.install_id || getStoredInstallId({ environment: env });
|
|
9436
|
+
if (isTestingIntent) {
|
|
9437
|
+
await emitAgentEvent({
|
|
9438
|
+
authToken: chatArgs.auth_token,
|
|
9439
|
+
installId: resolvedInstallId || void 0,
|
|
9440
|
+
eventName: "agent_test_intent_detected",
|
|
9441
|
+
eventProperties: {
|
|
9442
|
+
tool_name: "agent_chat",
|
|
9443
|
+
route: "cutline_testing_rgr"
|
|
9444
|
+
}
|
|
9445
|
+
});
|
|
9446
|
+
}
|
|
9447
|
+
return {
|
|
9448
|
+
content: [{
|
|
9449
|
+
type: "text",
|
|
9450
|
+
text: JSON.stringify({
|
|
9451
|
+
text,
|
|
9452
|
+
...isTestingIntent ? { cutline_testing_route: buildTestingIntentHintResponse(prompt) } : {}
|
|
9453
|
+
})
|
|
9454
|
+
}]
|
|
9455
|
+
};
|
|
9364
9456
|
}
|
|
9365
9457
|
// Integrations
|
|
9366
9458
|
case "integrations_create_issues": {
|
|
@@ -10929,6 +11021,11 @@ ${JSON.stringify(metrics, null, 2)}` }
|
|
|
10929
11021
|
...plan,
|
|
10930
11022
|
entity: rgrMatched[0].name,
|
|
10931
11023
|
complexity,
|
|
11024
|
+
auto_execution: {
|
|
11025
|
+
scope_increase_triggers_rgr: true,
|
|
11026
|
+
mode: "pervasive",
|
|
11027
|
+
expected_runner: "local_vitest"
|
|
11028
|
+
},
|
|
10932
11029
|
governance
|
|
10933
11030
|
}, null, 2)
|
|
10934
11031
|
}]
|
|
@@ -11455,7 +11552,7 @@ Meta: ${JSON.stringify({
|
|
|
11455
11552
|
mode: "product",
|
|
11456
11553
|
codeContext: payload.codeContext || null
|
|
11457
11554
|
});
|
|
11458
|
-
runInput.productId = newJobId;
|
|
11555
|
+
runInput.productId = String(auditArgs.product_id || newJobId);
|
|
11459
11556
|
await updatePremortem(newJobId, { payload: runInput });
|
|
11460
11557
|
return { jobId: newJobId };
|
|
11461
11558
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type AgentEventName = 'install_completed' | 'first_tool_call_success' | 'tool_call_failed' | 'heartbeat' | 'policy_gate_passed' | 'policy_gate_blocked' | 'upgrade_clicked' | 'upgrade_completed';
|
|
1
|
+
type AgentEventName = 'install_completed' | 'first_tool_call_success' | 'tool_call_failed' | 'heartbeat' | 'policy_gate_passed' | 'policy_gate_blocked' | 'upgrade_clicked' | 'upgrade_completed' | 'agent_test_intent_detected' | 'agent_cutline_install_prompted' | 'agent_cutline_install_completed' | 'agent_first_rgr_test_call_success';
|
|
2
2
|
export declare function registerAgentInstall(input: {
|
|
3
3
|
idToken: string;
|
|
4
4
|
staging?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kylewadegrove/cutline-mcp-cli-staging",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|