@vibekiln/cutline-mcp-cli 0.6.0 → 0.7.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.
@@ -7395,6 +7395,18 @@ function mcpAudit(entry) {
7395
7395
  }));
7396
7396
  }
7397
7397
  var DEFAULT_MODEL = process.env.MODEL_ID || "gemini-2.5-pro";
7398
+ var GOVERNANCE_ENFORCEMENT = (process.env.CUTLINE_GOVERNANCE_ENFORCEMENT || "advisory").toLowerCase() === "enforced";
7399
+ function buildGovernanceEnvelope(input) {
7400
+ return {
7401
+ decision: input.decision,
7402
+ decisionReasons: input.reasons ?? [],
7403
+ requiredActions: input.requiredActions ?? [],
7404
+ executionPermission: input.executionPermission ?? "conditional",
7405
+ ...input.closePermission ? { closePermission: input.closePermission } : {},
7406
+ ...input.requiredBranches?.length ? { requiredBranches: input.requiredBranches } : {},
7407
+ ...input.mode ? { mode: input.mode } : {}
7408
+ };
7409
+ }
7398
7410
  var generateStructuredContent = (options) => withLlmMonitor(options.modelId || DEFAULT_MODEL, () => cfGenerateStructuredContent(options));
7399
7411
  var explorationSessions = /* @__PURE__ */ new Map();
7400
7412
  function generateId(prefix = "id") {
@@ -8003,6 +8015,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8003
8015
  max_constraints: { type: "number", description: "Max constraints to return (default: 5)" },
8004
8016
  use_semantic: { type: "boolean", description: "Use semantic search if embeddings available (default: true)" },
8005
8017
  phase: { type: "string", enum: ["test_spec", "functional", "security", "performance", "economics", "full", "auto"], description: "RGR phase filter. 'auto' uses complexity heuristic. Default: 'full'" },
8018
+ requestedOutcome: {
8019
+ type: "string",
8020
+ enum: ["approve", "revise", "execute", "close"],
8021
+ description: "Governance intent for this transition (default: approve)"
8022
+ },
8006
8023
  auto_scope_expand: { type: "boolean", description: "If true, auto-seed a new graph entity when scope expansion intent is confidently detected and entity fields are provided." },
8007
8024
  scope_entity_name: { type: "string", description: "Optional explicit entity name to seed during scope expansion (for example 'Vibe Check Extension')." },
8008
8025
  scope_entity_type: { type: "string", enum: ["feature", "component", "data_type"], description: "Entity type for auto scope expansion." },
@@ -8223,7 +8240,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8223
8240
  properties: {
8224
8241
  product_id: { type: "string", description: "Product ID" },
8225
8242
  file_path: { type: "string", description: "File path to assess (e.g., 'src/api/upload.ts')" },
8226
- depth: { type: "number", description: "BFS traversal depth for subgraph extraction (default: 2)" }
8243
+ depth: { type: "number", description: "BFS traversal depth for subgraph extraction (default: 2)" },
8244
+ requestedOutcome: {
8245
+ type: "string",
8246
+ enum: ["approve", "revise", "execute", "close"],
8247
+ description: "Governance intent for this transition (default: approve)"
8248
+ }
8227
8249
  },
8228
8250
  required: ["product_id", "file_path"]
8229
8251
  }
@@ -8240,6 +8262,39 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8240
8262
  required: ["product_id", "phase"]
8241
8263
  }
8242
8264
  },
8265
+ {
8266
+ name: "request_execution_gate",
8267
+ description: "\u{1F512} PREMIUM - Governance checkpoint before downstream actions (code generation, file edits, migrations, deploy). Uses RGR completion, audit signals, and constraint acknowledgments to return approved/conditional/blocked.",
8268
+ inputSchema: {
8269
+ type: "object",
8270
+ properties: {
8271
+ product_id: { type: "string", description: "Product ID" },
8272
+ target_action: { type: "string", enum: ["generate_code", "modify_files", "run_migration", "deploy"], description: "Planned downstream action" },
8273
+ target_artifacts: { type: "array", items: { type: "string" }, description: "Files/modules the action will touch" },
8274
+ based_on_step_ids: { type: "array", items: { type: "string" }, description: "Optional planning step IDs this execution is based on" },
8275
+ open_critical_findings: { type: "number", description: "Count of unresolved critical/high findings from latest audit context" },
8276
+ touched_sensitive_paths: { type: "array", items: { type: "string" }, description: "Sensitive files touched in this action (auth, billing, security, AI, integrations, user flows)" },
8277
+ constraints_acknowledged: { type: "boolean", description: "Whether relevant constraints have been reviewed and acknowledged for touched sensitive paths" }
8278
+ },
8279
+ required: ["product_id", "target_action", "target_artifacts"]
8280
+ }
8281
+ },
8282
+ {
8283
+ name: "submit_done_claim",
8284
+ description: "\u{1F512} PREMIUM - Governance close gate. Evaluates completion claims against RGR state, unresolved critical findings, and provided evidence references.",
8285
+ inputSchema: {
8286
+ type: "object",
8287
+ properties: {
8288
+ product_id: { type: "string", description: "Product ID" },
8289
+ completion_summary: { type: "string", description: "What was completed" },
8290
+ claimed_criteria_satisfied: { type: "array", items: { type: "string" }, description: "Success criteria the agent claims are satisfied" },
8291
+ known_limitations: { type: "array", items: { type: "string" }, description: "Known limitations or intentional exclusions" },
8292
+ evidence_refs: { type: "array", items: { type: "string" }, description: "Evidence links/refs (tests, reports, docs, PRs)" },
8293
+ open_critical_findings: { type: "number", description: "Count of unresolved critical/high findings from latest audit context" }
8294
+ },
8295
+ required: ["product_id", "completion_summary", "claimed_criteria_satisfied"]
8296
+ }
8297
+ },
8243
8298
  {
8244
8299
  name: "export_readiness_badge",
8245
8300
  description: "\u{1F512} PREMIUM - Export a public readiness badge and verification page for this product. Computes an architecture readiness grade from the constraint graph, stores a public snapshot, and returns embeddable badge snippets (Markdown for GitHub README, HTML for website footer) plus a full CUTLINE-REPORT.md. The verification page at thecutline.ai/verify/{id} provides SEO backlinks.",
@@ -9182,7 +9237,7 @@ Meta: ${JSON.stringify(output.meta)}` }
9182
9237
  return void 0;
9183
9238
  };
9184
9239
  var detectFramework = detectFramework2;
9185
- const { product_id, file_paths, code_snippet, task_description, mode = "auto", max_constraints = 5, use_semantic = true, phase: autoPhase = "full", auto_scope_expand = false, scope_entity_name, scope_entity_type, scope_entity_description, scope_entity_tags, scope_parent_id, scope_similarity_threshold } = args;
9240
+ const { product_id, file_paths, code_snippet, task_description, mode = "auto", max_constraints = 5, use_semantic = true, phase: autoPhase = "full", requestedOutcome = "approve", auto_scope_expand = false, scope_entity_name, scope_entity_type, scope_entity_description, scope_entity_tags, scope_parent_id, scope_similarity_threshold } = args;
9186
9241
  if (!product_id) {
9187
9242
  throw new McpError(ErrorCode.InvalidParams, "product_id is required");
9188
9243
  }
@@ -9192,6 +9247,19 @@ Meta: ${JSON.stringify(output.meta)}` }
9192
9247
  task_description
9193
9248
  };
9194
9249
  if (!hasEnoughSignal(fileContext)) {
9250
+ const governance2 = buildGovernanceEnvelope({
9251
+ decision: "revise",
9252
+ reasons: [{
9253
+ constraintId: "context.signal.missing",
9254
+ severity: "warning",
9255
+ message: "Insufficient context to match constraints deterministically."
9256
+ }],
9257
+ requiredActions: [
9258
+ "Provide file_paths, code_snippet, or task_description.",
9259
+ "Re-run constraints_auto with richer context."
9260
+ ],
9261
+ executionPermission: "denied"
9262
+ });
9195
9263
  return {
9196
9264
  content: [{
9197
9265
  type: "text",
@@ -9202,7 +9270,8 @@ Meta: ${JSON.stringify(output.meta)}` }
9202
9270
  meta: {
9203
9271
  mode: "silent",
9204
9272
  signal_strength: 0
9205
- }
9273
+ },
9274
+ governance: governance2
9206
9275
  })
9207
9276
  }]
9208
9277
  };
@@ -9238,6 +9307,16 @@ Meta: ${JSON.stringify(output.meta)}` }
9238
9307
  }
9239
9308
  const actualMode = mode === "auto" ? analysis.suggested_mode : mode;
9240
9309
  if (actualMode === "silent") {
9310
+ const governance2 = buildGovernanceEnvelope({
9311
+ decision: "approved",
9312
+ reasons: [{
9313
+ constraintId: "constraints.mode.silent",
9314
+ severity: "info",
9315
+ message: "Silent mode selected; constraints were analyzed but not injected into output."
9316
+ }],
9317
+ requiredActions: requestedOutcome === "execute" ? ["If execution is next, run request_execution_gate before downstream write/deploy actions."] : [],
9318
+ executionPermission: requestedOutcome === "execute" ? "conditional" : "denied"
9319
+ });
9241
9320
  return {
9242
9321
  content: [{
9243
9322
  type: "text",
@@ -9252,7 +9331,8 @@ Meta: ${JSON.stringify(output.meta)}` }
9252
9331
  keywords_detected: analysis.signal.keywords?.slice(0, 5),
9253
9332
  scope_expansion: scopeExpansion,
9254
9333
  scope_seeded: scopeSeedResult || void 0
9255
- }
9334
+ },
9335
+ governance: governance2
9256
9336
  })
9257
9337
  }]
9258
9338
  };
@@ -9264,6 +9344,19 @@ Meta: ${JSON.stringify(output.meta)}` }
9264
9344
  lightNodes = await getAllNodesLight(product_id);
9265
9345
  }
9266
9346
  if (lightNodes.length === 0) {
9347
+ const governance2 = buildGovernanceEnvelope({
9348
+ decision: "blocked",
9349
+ reasons: [{
9350
+ constraintId: "constraints.graph.empty",
9351
+ severity: "high",
9352
+ message: "No ingested constraints are available for this product."
9353
+ }],
9354
+ requiredActions: [
9355
+ "Run constraints_ingest_* or graph_ingest_requirements first.",
9356
+ "Re-run constraints_auto after ingestion."
9357
+ ],
9358
+ executionPermission: "denied"
9359
+ });
9267
9360
  return {
9268
9361
  content: [{
9269
9362
  type: "text",
@@ -9275,7 +9368,8 @@ Meta: ${JSON.stringify(output.meta)}` }
9275
9368
  mode: actualMode,
9276
9369
  detected_domains: analysis.detected_domains,
9277
9370
  signal_strength: Math.round(analysis.confidence * 100) / 100
9278
- }
9371
+ },
9372
+ governance: governance2
9279
9373
  })
9280
9374
  }]
9281
9375
  };
@@ -9413,6 +9507,36 @@ Meta: ${JSON.stringify(output.meta)}` }
9413
9507
  ${recommendation}`;
9414
9508
  }
9415
9509
  }
9510
+ const criticalCount = topConstraints.filter((c) => c.severity === "critical").length;
9511
+ const warningCount = topConstraints.filter((c) => c.severity === "warning").length;
9512
+ const branchRequired = detectedConflicts.length > 0;
9513
+ const shouldBlock = actualMode === "blocking" && criticalCount > 0;
9514
+ const governanceDecision = shouldBlock ? "blocked" : branchRequired ? "branch" : criticalCount > 0 || warningCount > 0 ? "revise" : "approved";
9515
+ const governance = buildGovernanceEnvelope({
9516
+ decision: governanceDecision,
9517
+ reasons: [
9518
+ ...criticalCount > 0 ? [{
9519
+ constraintId: "constraints.severity.critical",
9520
+ severity: "critical",
9521
+ message: `${criticalCount} critical constraint(s) detected for the proposed transition.`
9522
+ }] : [],
9523
+ ...branchRequired ? [{
9524
+ constraintId: "constraints.conflict.detected",
9525
+ severity: "high",
9526
+ message: `${detectedConflicts.length} constraint conflict(s) detected; compare alternatives before execution.`
9527
+ }] : []
9528
+ ],
9529
+ requiredActions: [
9530
+ ...criticalCount > 0 ? ["Address critical constraints before implementation handoff."] : [],
9531
+ ...branchRequired ? ["Compare at least two implementation alternatives and resolve conflicts explicitly."] : [],
9532
+ ...requestedOutcome === "execute" ? ["Run request_execution_gate before invoking code-write or deploy actions."] : []
9533
+ ],
9534
+ executionPermission: shouldBlock ? "denied" : requestedOutcome === "execute" ? "conditional" : "denied",
9535
+ requiredBranches: branchRequired ? [
9536
+ { branchId: "A", instruction: "Propose the lowest-risk compliant implementation path." },
9537
+ { branchId: "B", instruction: "Propose an alternative path and document trade-offs." }
9538
+ ] : void 0
9539
+ });
9416
9540
  return {
9417
9541
  content: [{
9418
9542
  type: "text",
@@ -9433,9 +9557,12 @@ ${recommendation}`;
9433
9557
  used_category_prefilter: usePreFilter,
9434
9558
  phase: autoPhase,
9435
9559
  rgr_plan: autoRgrPlan || void 0,
9560
+ requested_outcome: requestedOutcome,
9436
9561
  scope_expansion: scopeExpansion,
9437
- scope_seeded: scopeSeedResult || void 0
9438
- }
9562
+ scope_seeded: scopeSeedResult || void 0,
9563
+ requested_outcome: requestedOutcome
9564
+ },
9565
+ governance
9439
9566
  })
9440
9567
  }]
9441
9568
  };
@@ -10253,7 +10380,7 @@ ${JSON.stringify(metrics, null, 2)}` }
10253
10380
  // RGR_PLAN
10254
10381
  // ─────────────────────────────────────────────────────────────────
10255
10382
  case "rgr_plan": {
10256
- const { product_id, file_path, depth: rgrDepth = 2 } = args;
10383
+ const { product_id, file_path, depth: rgrDepth = 2, requestedOutcome = "approve" } = args;
10257
10384
  if (!product_id || !file_path) {
10258
10385
  throw new McpError(ErrorCode.InvalidParams, "product_id and file_path are required");
10259
10386
  }
@@ -10264,10 +10391,26 @@ ${JSON.stringify(metrics, null, 2)}` }
10264
10391
  getAllBindings(product_id)
10265
10392
  ]);
10266
10393
  if (rgrEntities.length === 0) {
10394
+ const governance2 = buildGovernanceEnvelope({
10395
+ decision: "blocked",
10396
+ reasons: [{
10397
+ constraintId: "graph.entities.missing",
10398
+ severity: "high",
10399
+ message: `No graph entities found for product "${product_id}".`
10400
+ }],
10401
+ requiredActions: [
10402
+ "Run graph_ingest_requirements or constraints_ingest_* to seed the graph.",
10403
+ "Re-run rgr_plan after ingestion."
10404
+ ],
10405
+ executionPermission: "denied"
10406
+ });
10267
10407
  return {
10268
10408
  content: [{
10269
10409
  type: "text",
10270
- text: `No graph entities found for product "${product_id}". Run graph_ingest_requirements first.`
10410
+ text: JSON.stringify({
10411
+ message: `No graph entities found for product "${product_id}". Run graph_ingest_requirements first.`,
10412
+ governance: governance2
10413
+ }, null, 2)
10271
10414
  }]
10272
10415
  };
10273
10416
  }
@@ -10286,6 +10429,19 @@ ${JSON.stringify(metrics, null, 2)}` }
10286
10429
  }
10287
10430
  }
10288
10431
  if (rgrMatched.length === 0) {
10432
+ const governance2 = buildGovernanceEnvelope({
10433
+ decision: "revise",
10434
+ reasons: [{
10435
+ constraintId: "graph.binding.missing",
10436
+ severity: "warning",
10437
+ message: `No graph entity is bound to "${file_path}".`
10438
+ }],
10439
+ requiredActions: [
10440
+ "Bind codebase entities using graph_bind_codebase/graph_bind_confirm.",
10441
+ "Proceed with full delivery only if no bound entity is expected."
10442
+ ],
10443
+ executionPermission: requestedOutcome === "execute" ? "conditional" : "denied"
10444
+ });
10289
10445
  return {
10290
10446
  content: [{
10291
10447
  type: "text",
@@ -10293,7 +10449,8 @@ ${JSON.stringify(metrics, null, 2)}` }
10293
10449
  strategy: "full",
10294
10450
  phases: [{ name: "full", label: "Full Delivery", description: "No entity bound to this file. Deliver all constraints.", categories: [], constraint_count: 0 }],
10295
10451
  total_constraints: 0,
10296
- rationale: `No entity bound to "${file_path}". Cannot assess constraint complexity.`
10452
+ rationale: `No entity bound to "${file_path}". Cannot assess constraint complexity.`,
10453
+ governance: governance2
10297
10454
  }, null, 2)
10298
10455
  }]
10299
10456
  };
@@ -10302,13 +10459,36 @@ ${JSON.stringify(metrics, null, 2)}` }
10302
10459
  const fileConstraints = rgrSubgraph?.constraints ?? [];
10303
10460
  const plan = planRgrPhases(fileConstraints);
10304
10461
  const complexity = assessComplexity(fileConstraints);
10462
+ const branchNeeded = plan.strategy === "phased" && (complexity.critical_count > 0 || requestedOutcome === "execute");
10463
+ const governance = buildGovernanceEnvelope({
10464
+ decision: branchNeeded ? "branch" : "approved",
10465
+ reasons: branchNeeded ? [{
10466
+ constraintId: "rgr.phased.required",
10467
+ severity: "high",
10468
+ message: `${complexity.critical_count} critical constraint(s) across ${complexity.category_count} categories require phased comparison.`
10469
+ }] : [{
10470
+ constraintId: "rgr.plan.ready",
10471
+ severity: "info",
10472
+ message: "Plan assessed and ready for implementation sequencing."
10473
+ }],
10474
+ requiredActions: [
10475
+ ...plan.strategy === "phased" ? ["Follow phased RGR execution order from this plan."] : ["Deliver full constraint set in a single pass."],
10476
+ ...requestedOutcome === "execute" ? ["Request execution permission via request_execution_gate before downstream write/deploy actions."] : []
10477
+ ],
10478
+ executionPermission: requestedOutcome === "execute" ? "conditional" : "denied",
10479
+ requiredBranches: branchNeeded ? [
10480
+ { branchId: "A", instruction: "Prioritize functional progress (test_spec/functional) then apply NFR phases." },
10481
+ { branchId: "B", instruction: "Prioritize security/performance constraints before broad implementation." }
10482
+ ] : void 0
10483
+ });
10305
10484
  return {
10306
10485
  content: [{
10307
10486
  type: "text",
10308
10487
  text: JSON.stringify({
10309
10488
  ...plan,
10310
10489
  entity: rgrMatched[0].name,
10311
- complexity
10490
+ complexity,
10491
+ governance
10312
10492
  }, null, 2)
10313
10493
  }]
10314
10494
  };
@@ -10379,6 +10559,157 @@ ${JSON.stringify(metrics, null, 2)}` }
10379
10559
  };
10380
10560
  }
10381
10561
  // ─────────────────────────────────────────────────────────────────
10562
+ // REQUEST_EXECUTION_GATE
10563
+ // ─────────────────────────────────────────────────────────────────
10564
+ case "request_execution_gate": {
10565
+ const { product_id, target_action, target_artifacts, based_on_step_ids = [], open_critical_findings = 0, touched_sensitive_paths = [], constraints_acknowledged = false } = args;
10566
+ if (!product_id || !target_action || !Array.isArray(target_artifacts) || target_artifacts.length === 0) {
10567
+ throw new McpError(ErrorCode.InvalidParams, "product_id, target_action, and non-empty target_artifacts are required");
10568
+ }
10569
+ const meta = await getGraphMetadata(product_id);
10570
+ const completedPhases = meta?.rgr_completed_phases ?? [];
10571
+ const metrics = meta?.metrics;
10572
+ const unmetCheckpoints = [];
10573
+ const blockingFindings = [];
10574
+ const requiredNextSteps = [];
10575
+ if (!completedPhases.includes("security")) {
10576
+ unmetCheckpoints.push("security_commitment");
10577
+ blockingFindings.push({
10578
+ constraintId: "rgr.phase.security",
10579
+ severity: "high",
10580
+ message: "Security phase is not marked complete."
10581
+ });
10582
+ requiredNextSteps.push('Complete security remediation and call rgr_complete_phase(product_id, phase: "security").');
10583
+ }
10584
+ if (target_action === "deploy" && !completedPhases.includes("performance")) {
10585
+ unmetCheckpoints.push("implementation_readiness");
10586
+ blockingFindings.push({
10587
+ constraintId: "rgr.phase.performance",
10588
+ severity: "warning",
10589
+ message: "Deploy requested before performance phase completion."
10590
+ });
10591
+ requiredNextSteps.push('Complete performance checks and call rgr_complete_phase(product_id, phase: "performance").');
10592
+ }
10593
+ if (open_critical_findings > 0) {
10594
+ unmetCheckpoints.push("verification");
10595
+ blockingFindings.push({
10596
+ constraintId: "audit.findings.open",
10597
+ severity: "critical",
10598
+ message: `${open_critical_findings} unresolved critical/high findings are still open.`
10599
+ });
10600
+ requiredNextSteps.push("Resolve or explicitly accept outstanding critical/high findings before execution.");
10601
+ }
10602
+ if (touched_sensitive_paths.length > 0 && !constraints_acknowledged) {
10603
+ unmetCheckpoints.push("implementation_readiness");
10604
+ blockingFindings.push({
10605
+ constraintId: "constraints.ack.required",
10606
+ severity: "high",
10607
+ message: "Sensitive paths were provided without explicit constraint acknowledgment."
10608
+ });
10609
+ requiredNextSteps.push("Run constraints_auto for touched sensitive paths and acknowledge applicable constraints.");
10610
+ }
10611
+ const hasBlocks = blockingFindings.some((f) => f.severity === "critical" || f.severity === "high");
10612
+ const denied = hasBlocks && GOVERNANCE_ENFORCEMENT;
10613
+ const decision = denied ? "blocked" : blockingFindings.length > 0 ? "conditional" : "approved";
10614
+ const governance = buildGovernanceEnvelope({
10615
+ decision: denied ? "blocked" : blockingFindings.length > 0 ? "revise" : "approved",
10616
+ reasons: blockingFindings,
10617
+ requiredActions: requiredNextSteps,
10618
+ executionPermission: denied ? "denied" : blockingFindings.length > 0 ? "conditional" : "granted",
10619
+ mode: GOVERNANCE_ENFORCEMENT ? "enforced" : "advisory"
10620
+ });
10621
+ return {
10622
+ content: [{
10623
+ type: "text",
10624
+ text: JSON.stringify({
10625
+ decision,
10626
+ unmetCheckpoints: [...new Set(unmetCheckpoints)],
10627
+ blockingFindings,
10628
+ requiredNextSteps,
10629
+ based_on_step_ids,
10630
+ product_id,
10631
+ target_action,
10632
+ target_artifacts,
10633
+ governanceMode: GOVERNANCE_ENFORCEMENT ? "enforced" : "advisory",
10634
+ readiness: {
10635
+ rgr_completed_phases: completedPhases,
10636
+ security_readiness_pct: metrics?.security_readiness_pct ?? null,
10637
+ engineering_readiness_pct: metrics?.engineering_readiness_pct ?? null
10638
+ },
10639
+ governance
10640
+ }, null, 2)
10641
+ }]
10642
+ };
10643
+ }
10644
+ // ─────────────────────────────────────────────────────────────────
10645
+ // SUBMIT_DONE_CLAIM
10646
+ // ─────────────────────────────────────────────────────────────────
10647
+ case "submit_done_claim": {
10648
+ const { product_id, completion_summary, claimed_criteria_satisfied, known_limitations = [], evidence_refs = [], open_critical_findings = 0 } = args;
10649
+ if (!product_id || !completion_summary || !Array.isArray(claimed_criteria_satisfied)) {
10650
+ throw new McpError(ErrorCode.InvalidParams, "product_id, completion_summary, and claimed_criteria_satisfied are required");
10651
+ }
10652
+ const meta = await getGraphMetadata(product_id);
10653
+ const completedPhases = meta?.rgr_completed_phases ?? [];
10654
+ const unsatisfiedCriteria = [];
10655
+ const blockingFindings = [];
10656
+ const requiredNextSteps = [];
10657
+ if (!completedPhases.includes("security")) {
10658
+ unsatisfiedCriteria.push("Security phase completion not recorded.");
10659
+ blockingFindings.push({
10660
+ constraintId: "done.rgr.security_missing",
10661
+ severity: "high",
10662
+ message: "Cannot close work item before security phase completion."
10663
+ });
10664
+ requiredNextSteps.push('Complete and record security phase via rgr_complete_phase(product_id, phase: "security").');
10665
+ }
10666
+ if (evidence_refs.length === 0) {
10667
+ unsatisfiedCriteria.push("No evidence references provided for completion claim.");
10668
+ blockingFindings.push({
10669
+ constraintId: "done.evidence.required",
10670
+ severity: "warning",
10671
+ message: "Done claims require evidence refs (tests, reports, or docs)."
10672
+ });
10673
+ requiredNextSteps.push("Provide evidence_refs for tests, audit reruns, or implementation verification.");
10674
+ }
10675
+ if (open_critical_findings > 0) {
10676
+ unsatisfiedCriteria.push(`${open_critical_findings} unresolved critical/high findings remain.`);
10677
+ blockingFindings.push({
10678
+ constraintId: "done.critical_findings.open",
10679
+ severity: "critical",
10680
+ message: "Outstanding critical/high findings prevent closure."
10681
+ });
10682
+ requiredNextSteps.push("Resolve or explicitly disposition outstanding critical/high findings before closure.");
10683
+ }
10684
+ const hasHardBlock = blockingFindings.some((f) => f.severity === "critical" || f.severity === "high");
10685
+ const decision = hasHardBlock ? "blocked" : unsatisfiedCriteria.length > 0 ? "incomplete" : "complete";
10686
+ const governance = buildGovernanceEnvelope({
10687
+ decision: hasHardBlock ? "blocked" : unsatisfiedCriteria.length > 0 ? "incomplete" : "approved",
10688
+ reasons: blockingFindings,
10689
+ requiredActions: requiredNextSteps,
10690
+ executionPermission: "denied",
10691
+ closePermission: decision === "complete" ? "granted" : "denied",
10692
+ mode: GOVERNANCE_ENFORCEMENT ? "enforced" : "advisory"
10693
+ });
10694
+ return {
10695
+ content: [{
10696
+ type: "text",
10697
+ text: JSON.stringify({
10698
+ decision,
10699
+ closePermission: decision === "complete" ? "granted" : "denied",
10700
+ completionSummary: completion_summary,
10701
+ claimedCriteriaSatisfied: claimed_criteria_satisfied,
10702
+ knownLimitations: known_limitations,
10703
+ evidenceRefs: evidence_refs,
10704
+ unsatisfiedCriteria,
10705
+ blockingFindings,
10706
+ requiredNextSteps,
10707
+ governance
10708
+ }, null, 2)
10709
+ }]
10710
+ };
10711
+ }
10712
+ // ─────────────────────────────────────────────────────────────────
10382
10713
  // GENERATE_CUTLINE_MD
10383
10714
  // ─────────────────────────────────────────────────────────────────
10384
10715
  case "generate_cutline_md": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibekiln/cutline-mcp-cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",