@vibecheck-ai/mcp 24.5.9 → 24.6.3

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 (3) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.js +1069 -936
  3. package/package.json +15 -23
package/dist/index.js CHANGED
@@ -5752,7 +5752,7 @@ var require_util = __commonJS({
5752
5752
  return path10;
5753
5753
  }
5754
5754
  exports2.normalize = normalize4;
5755
- function join9(aRoot, aPath) {
5755
+ function join10(aRoot, aPath) {
5756
5756
  if (aRoot === "") {
5757
5757
  aRoot = ".";
5758
5758
  }
@@ -5784,7 +5784,7 @@ var require_util = __commonJS({
5784
5784
  }
5785
5785
  return joined;
5786
5786
  }
5787
- exports2.join = join9;
5787
+ exports2.join = join10;
5788
5788
  exports2.isAbsolute = function(aPath) {
5789
5789
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
5790
5790
  };
@@ -5957,7 +5957,7 @@ var require_util = __commonJS({
5957
5957
  parsed.path = parsed.path.substring(0, index2 + 1);
5958
5958
  }
5959
5959
  }
5960
- sourceURL = join9(urlGenerate(parsed), sourceURL);
5960
+ sourceURL = join10(urlGenerate(parsed), sourceURL);
5961
5961
  }
5962
5962
  return normalize4(sourceURL);
5963
5963
  }
@@ -219544,7 +219544,7 @@ var require_bindings = __commonJS({
219544
219544
  var fs7 = __require("fs");
219545
219545
  var path10 = __require("path");
219546
219546
  var fileURLToPath2 = require_file_uri_to_path();
219547
- var join9 = path10.join;
219547
+ var join10 = path10.join;
219548
219548
  var dirname8 = path10.dirname;
219549
219549
  var exists2 = fs7.accessSync && function(path11) {
219550
219550
  try {
@@ -219604,7 +219604,7 @@ var require_bindings = __commonJS({
219604
219604
  var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
219605
219605
  var tries = [], i2 = 0, l = opts.try.length, n, b, err2;
219606
219606
  for (; i2 < l; i2++) {
219607
- n = join9.apply(
219607
+ n = join10.apply(
219608
219608
  null,
219609
219609
  opts.try[i2].map(function(p) {
219610
219610
  return opts[p] || p;
@@ -219665,7 +219665,7 @@ var require_bindings = __commonJS({
219665
219665
  if (dir === ".") {
219666
219666
  dir = process.cwd();
219667
219667
  }
219668
- if (exists2(join9(dir, "package.json")) || exists2(join9(dir, "node_modules"))) {
219668
+ if (exists2(join10(dir, "package.json")) || exists2(join10(dir, "node_modules"))) {
219669
219669
  return dir;
219670
219670
  }
219671
219671
  if (prev === dir) {
@@ -219674,7 +219674,7 @@ var require_bindings = __commonJS({
219674
219674
  );
219675
219675
  }
219676
219676
  prev = dir;
219677
- dir = join9(dir, "..");
219677
+ dir = join10(dir, "..");
219678
219678
  }
219679
219679
  };
219680
219680
  }
@@ -221655,7 +221655,7 @@ ${JSON.stringify(t2, null, 2)}`);
221655
221655
 
221656
221656
  // ../context-engine/dist/chunk-3ZE34DAJ.js
221657
221657
  import { readFile as readFile2 } from "fs/promises";
221658
- import { join as join3, dirname as dirname4 } from "path";
221658
+ import { join as join3, dirname as dirname5 } from "path";
221659
221659
  import { fileURLToPath } from "url";
221660
221660
  async function initParser() {
221661
221661
  if (ParserClass) return ParserClass;
@@ -221795,7 +221795,7 @@ var init_chunk_3ZE34DAJ = __esm({
221795
221795
  SymbolKind2["Export"] = "export";
221796
221796
  return SymbolKind2;
221797
221797
  })(SymbolKind || {});
221798
- GRAMMAR_DIR = join3(dirname4(fileURLToPath(import.meta.url)), "../../../../node_modules/tree-sitter-wasms/out");
221798
+ GRAMMAR_DIR = join3(dirname5(fileURLToPath(import.meta.url)), "../../../../node_modules/tree-sitter-wasms/out");
221799
221799
  EXT_TO_GRAMMAR = {
221800
221800
  ".ts": "typescript",
221801
221801
  ".tsx": "tsx",
@@ -278750,10 +278750,7 @@ import { execFile } from "child_process";
278750
278750
  import { promisify } from "util";
278751
278751
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
278752
278752
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
278753
- import {
278754
- ListToolsRequestSchema,
278755
- CallToolRequestSchema
278756
- } from "@modelcontextprotocol/sdk/types.js";
278753
+ import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
278757
278754
  import { runOnFiles } from "@vibecheck-ai/cli/runner";
278758
278755
  import {
278759
278756
  computeTrustScore,
@@ -289088,6 +289085,845 @@ rules:
289088
289085
  match: "src/repositories/**"
289089
289086
  `;
289090
289087
 
289088
+ // ../context-engine/dist/chunk-INBCP46U.js
289089
+ import * as path5 from "path";
289090
+ var ContextSynthesizer = class {
289091
+ rootPath;
289092
+ data;
289093
+ dna;
289094
+ graph;
289095
+ ruleResult;
289096
+ constructor(rootPath, data, dna, graph, ruleResult) {
289097
+ this.rootPath = rootPath;
289098
+ this.data = data;
289099
+ this.dna = dna;
289100
+ this.graph = graph;
289101
+ this.ruleResult = ruleResult || null;
289102
+ }
289103
+ /**
289104
+ * Synthesize the full context — the complete brain dump for AI agents.
289105
+ */
289106
+ synthesize() {
289107
+ const projectIdentity = this.buildProjectIdentity();
289108
+ const archRules = this.buildArchRuleSummary();
289109
+ const activeViolations = this.ruleResult?.violations || [];
289110
+ const codebaseDNA = this.buildDNASummary();
289111
+ const fileContexts = this.buildFileContexts();
289112
+ const taskPlaybooks = this.buildTaskPlaybooks();
289113
+ const verificationSteps = this.buildVerificationSteps();
289114
+ const riskBriefing = this.buildRiskBriefing();
289115
+ return {
289116
+ version: "2.0.0",
289117
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
289118
+ projectIdentity,
289119
+ architecturalRules: archRules,
289120
+ activeViolations,
289121
+ codebaseDNA,
289122
+ fileContexts,
289123
+ taskPlaybooks,
289124
+ verificationSteps,
289125
+ riskBriefing
289126
+ };
289127
+ }
289128
+ /**
289129
+ * Generate context for a specific file — what an AI agent needs to know
289130
+ * before editing this file.
289131
+ */
289132
+ synthesizeForFile(filePath) {
289133
+ const rel = this.toRelative(filePath);
289134
+ const file = this.data.files.find((f) => f.relativePath === rel || f.path === filePath);
289135
+ if (!file) return null;
289136
+ return this.buildSingleFileContext(file);
289137
+ }
289138
+ /**
289139
+ * Generate a compact markdown context document for IDE rules.
289140
+ * This replaces the old static rule generation with intelligence-driven context.
289141
+ */
289142
+ generateContextDocument() {
289143
+ const ctx = this.synthesize();
289144
+ const lines = [];
289145
+ lines.push(`# ${ctx.projectIdentity.name} \u2014 AI Context`);
289146
+ lines.push(`<!-- Generated by @repo/context-engine at ${ctx.generatedAt} -->`);
289147
+ lines.push("");
289148
+ lines.push("## Project Identity");
289149
+ lines.push(`- **Stack**: ${ctx.projectIdentity.stack}`);
289150
+ lines.push(`- **Architecture**: ${ctx.projectIdentity.architecture}`);
289151
+ if (ctx.projectIdentity.keyPatterns.length > 0) {
289152
+ lines.push(`- **Key Patterns**: ${ctx.projectIdentity.keyPatterns.join(", ")}`);
289153
+ }
289154
+ lines.push("");
289155
+ if (ctx.codebaseDNA.conventions.length > 0) {
289156
+ lines.push("## Conventions (Auto-Discovered)");
289157
+ for (const conv of ctx.codebaseDNA.conventions) {
289158
+ lines.push(`- ${conv}`);
289159
+ }
289160
+ lines.push("");
289161
+ }
289162
+ if (ctx.architecturalRules.length > 0) {
289163
+ lines.push("## Architecture Rules");
289164
+ for (const rule of ctx.architecturalRules) {
289165
+ const icon = rule.severity === "error" ? "MUST" : rule.severity === "warning" ? "SHOULD" : "MAY";
289166
+ lines.push(`- **[${icon}]** ${rule.name}: ${rule.description}`);
289167
+ if (rule.violationCount > 0) {
289168
+ lines.push(` - ${rule.violationCount} active violations`);
289169
+ }
289170
+ }
289171
+ lines.push("");
289172
+ }
289173
+ if (ctx.codebaseDNA.boundaries.length > 0) {
289174
+ lines.push("## Module Boundaries");
289175
+ for (const boundary of ctx.codebaseDNA.boundaries) {
289176
+ lines.push(`- ${boundary}`);
289177
+ }
289178
+ lines.push("");
289179
+ }
289180
+ if (ctx.codebaseDNA.hotFiles.length > 0) {
289181
+ lines.push("## High-Impact Files (Edit With Care)");
289182
+ for (const file of ctx.codebaseDNA.hotFiles.slice(0, 10)) {
289183
+ lines.push(`- \`${file}\``);
289184
+ }
289185
+ lines.push("");
289186
+ }
289187
+ if (ctx.riskBriefing.securityConcerns.length > 0 || ctx.riskBriefing.testGaps.length > 0) {
289188
+ lines.push("## Risk Areas");
289189
+ for (const concern of ctx.riskBriefing.securityConcerns) {
289190
+ lines.push(`- ${concern}`);
289191
+ }
289192
+ for (const gap of ctx.riskBriefing.testGaps.slice(0, 5)) {
289193
+ lines.push(`- ${gap}`);
289194
+ }
289195
+ lines.push("");
289196
+ }
289197
+ if (ctx.projectIdentity.noGoZones.length > 0) {
289198
+ lines.push("## No-Go Zones");
289199
+ for (const zone of ctx.projectIdentity.noGoZones) {
289200
+ lines.push(`- ${zone}`);
289201
+ }
289202
+ lines.push("");
289203
+ }
289204
+ if (ctx.taskPlaybooks.length > 0) {
289205
+ lines.push("## Task Playbooks");
289206
+ for (const playbook of ctx.taskPlaybooks) {
289207
+ lines.push(`### ${playbook.taskType}`);
289208
+ for (const step of playbook.steps) {
289209
+ lines.push(`1. ${step}`);
289210
+ }
289211
+ if (playbook.mustVerify.length > 0) {
289212
+ lines.push(`**Verify**: ${playbook.mustVerify.join(", ")}`);
289213
+ }
289214
+ lines.push("");
289215
+ }
289216
+ }
289217
+ if (ctx.verificationSteps.length > 0) {
289218
+ lines.push("## Verification Protocol");
289219
+ for (const step of ctx.verificationSteps) {
289220
+ lines.push(`### On ${step.trigger}`);
289221
+ for (const check of step.checks) {
289222
+ lines.push(`- ${check}`);
289223
+ }
289224
+ if (step.commands.length > 0) {
289225
+ lines.push(`**Run**: \`${step.commands.join(" && ")}\``);
289226
+ }
289227
+ lines.push("");
289228
+ }
289229
+ }
289230
+ lines.push("## Codebase Health");
289231
+ lines.push(`- **Overall**: ${this.dna.healthScore.overall}/100`);
289232
+ const dims = this.dna.healthScore.dimensions;
289233
+ lines.push(`- Architecture: ${dims.architecture} | Tests: ${dims.testCoverage} | Conventions: ${dims.conventions} | Dependencies: ${dims.dependencies}`);
289234
+ lines.push("");
289235
+ lines.push("---");
289236
+ lines.push("<!-- context-engine:v2 -->");
289237
+ return lines.join("\n");
289238
+ }
289239
+ // ═══════════════════════════════════════════════════════════════════════════
289240
+ // IDENTITY
289241
+ // ═══════════════════════════════════════════════════════════════════════════
289242
+ buildProjectIdentity() {
289243
+ const fp = this.dna.fingerprint;
289244
+ const stack = [fp.framework, fp.language, fp.orm, fp.validator, fp.authLib, fp.router].filter(Boolean).join(" | ");
289245
+ const keyPatterns = this.dna.patterns.map((p) => p.name);
289246
+ const criticalPaths = this.dna.hotspots.slice(0, 5).map((h) => h.file);
289247
+ const noGoZones = [];
289248
+ if (this.ruleResult) {
289249
+ const errorRules = this.ruleResult.violations.filter((v) => v.severity === "error");
289250
+ const uniqueMessages = [...new Set(errorRules.map((v) => v.message))];
289251
+ noGoZones.push(...uniqueMessages.slice(0, 5));
289252
+ }
289253
+ for (const cycle of this.graph.cycles) {
289254
+ noGoZones.push(`Circular dependency: ${cycle.nodes.slice(0, 3).join(" \u2192 ")}...`);
289255
+ }
289256
+ const architecture = this.dna.conventions.filter((c) => c.area === "structure").map((c) => c.description).join("; ") || fp.framework;
289257
+ return {
289258
+ name: fp.name,
289259
+ stack,
289260
+ architecture,
289261
+ keyPatterns,
289262
+ criticalPaths,
289263
+ noGoZones: noGoZones.slice(0, 10)
289264
+ };
289265
+ }
289266
+ // ═══════════════════════════════════════════════════════════════════════════
289267
+ // RULES SUMMARY
289268
+ // ═══════════════════════════════════════════════════════════════════════════
289269
+ buildArchRuleSummary() {
289270
+ if (!this.ruleResult) return [];
289271
+ const breakdown = this.ruleResult.ruleBreakdown;
289272
+ return Object.entries(breakdown).map(([ruleId, count]) => {
289273
+ const violation = this.ruleResult.violations.find((v) => v.ruleId === ruleId);
289274
+ return {
289275
+ id: ruleId,
289276
+ name: violation?.ruleName || ruleId,
289277
+ type: "import_forbidden",
289278
+ severity: violation?.severity || "warning",
289279
+ scope: violation?.sourceSymbol.filePath || "",
289280
+ description: violation?.message || "",
289281
+ violationCount: count
289282
+ };
289283
+ });
289284
+ }
289285
+ // ═══════════════════════════════════════════════════════════════════════════
289286
+ // DNA SUMMARY
289287
+ // ═══════════════════════════════════════════════════════════════════════════
289288
+ buildDNASummary() {
289289
+ return {
289290
+ conventions: this.dna.conventions.filter((c) => c.confidence > 0.5).map((c) => c.description),
289291
+ patterns: this.dna.patterns.map((p) => `${p.name}: ${p.description}`),
289292
+ boundaries: this.dna.boundaries.filter((b) => b.importCount > 3).map((b) => `${b.from} \u2192 ${b.to} (${b.importCount} imports${b.isCircular ? ", CIRCULAR" : ""})`),
289293
+ hotFiles: this.dna.hotspots.slice(0, 10).map((h) => h.file),
289294
+ riskAreas: this.dna.riskMap.filter((r) => r.riskLevel === "critical" || r.riskLevel === "high").map((r) => `${r.file}: ${r.factors[0]}`)
289295
+ };
289296
+ }
289297
+ // ═══════════════════════════════════════════════════════════════════════════
289298
+ // FILE CONTEXTS
289299
+ // ═══════════════════════════════════════════════════════════════════════════
289300
+ buildFileContexts() {
289301
+ const contexts = /* @__PURE__ */ new Map();
289302
+ for (const file of this.data.files) {
289303
+ contexts.set(file.relativePath, this.buildSingleFileContext(file));
289304
+ }
289305
+ return contexts;
289306
+ }
289307
+ buildSingleFileContext(file) {
289308
+ const rel = file.relativePath;
289309
+ const role = this.classifyRole(file);
289310
+ const graphNode = this.graph.nodes.find((n) => n.relativePath === rel);
289311
+ const layer = graphNode?.layer;
289312
+ const dependsOn = this.graph.edges.filter((e) => e.from === rel).map((e) => e.to);
289313
+ const dependedOnBy = this.graph.edges.filter((e) => e.to === rel).map((e) => e.from);
289314
+ const applicableRules = [];
289315
+ if (this.ruleResult) {
289316
+ for (const v of this.ruleResult.violations) {
289317
+ if (v.sourceSymbol.filePath.includes(rel) || v.targetSymbol && v.targetSymbol.filePath.includes(rel)) {
289318
+ if (!applicableRules.includes(v.ruleId)) applicableRules.push(v.ruleId);
289319
+ }
289320
+ }
289321
+ }
289322
+ const conventions = this.dna.conventions.filter((c) => this.conventionAppliesToFile(c.area, file)).map((c) => c.description);
289323
+ const patterns = this.dna.patterns.filter((p) => p.fileMatches.some((m) => m === rel)).map((p) => p.name);
289324
+ const riskEntry = this.dna.riskMap.find((r) => r.file === rel);
289325
+ const riskLevel = riskEntry?.riskLevel || "low";
289326
+ const relatedFiles = this.findRelatedFiles(file, role).slice(0, 8);
289327
+ const editGuidance = this.generateEditGuidance(file, role, layer, dependedOnBy, conventions);
289328
+ return {
289329
+ filePath: file.path,
289330
+ role,
289331
+ layer,
289332
+ dependsOn,
289333
+ dependedOnBy,
289334
+ applicableRules,
289335
+ conventions,
289336
+ patterns,
289337
+ riskLevel,
289338
+ relatedFiles,
289339
+ editGuidance
289340
+ };
289341
+ }
289342
+ classifyRole(file) {
289343
+ const rel = file.relativePath.toLowerCase();
289344
+ if (rel.includes(".test.") || rel.includes(".spec.") || rel.includes("__tests__")) return "test";
289345
+ if (rel.includes("fixture") || rel.includes("mock")) return "fixture";
289346
+ if (rel.includes("migration")) return "migration";
289347
+ if (rel.match(/\.(css|scss|less|styl)$/)) return "style";
289348
+ if (rel.includes(".config.") || rel.includes("config/") || rel === "tsconfig.json") return "config";
289349
+ if (rel.includes("middleware")) return "middleware";
289350
+ if (rel.includes("/api/") || rel.includes("route")) return "route-handler";
289351
+ if (rel.includes("service") || rel.includes("Service")) return "service";
289352
+ if (rel.includes("repositor") || rel.includes("Repositor")) return "repository";
289353
+ if (rel.endsWith(".tsx") && !rel.includes("page.")) return "component";
289354
+ if (rel.includes("/types") || rel.endsWith(".d.ts")) return "type";
289355
+ if (rel.includes("util") || rel.includes("helper") || rel.includes("lib/")) return "util";
289356
+ if (rel.includes("script") || rel.includes("bin/")) return "script";
289357
+ if (rel.match(/^(src\/)?index\.|^(src\/)?main\.|^(src\/)?app\./)) return "entry";
289358
+ return "unknown";
289359
+ }
289360
+ conventionAppliesToFile(area, file) {
289361
+ switch (area) {
289362
+ case "naming":
289363
+ return true;
289364
+ case "imports":
289365
+ return file.relativePath.endsWith(".ts") || file.relativePath.endsWith(".tsx");
289366
+ case "exports":
289367
+ return file.exports.length > 0;
289368
+ case "testing":
289369
+ return file.relativePath.includes(".test.") || file.relativePath.includes(".spec.");
289370
+ case "error-handling":
289371
+ return !file.relativePath.includes(".test.");
289372
+ case "types":
289373
+ return file.relativePath.endsWith(".ts") || file.relativePath.endsWith(".tsx");
289374
+ default:
289375
+ return true;
289376
+ }
289377
+ }
289378
+ findRelatedFiles(file, role) {
289379
+ const related = [];
289380
+ const dir = path5.dirname(file.relativePath);
289381
+ for (const other of this.data.files) {
289382
+ if (other.path === file.path) continue;
289383
+ if (path5.dirname(other.relativePath) === dir) {
289384
+ related.push(other.relativePath);
289385
+ }
289386
+ }
289387
+ if (related.length < 5) {
289388
+ for (const other of this.data.files) {
289389
+ if (other.path === file.path) continue;
289390
+ if (related.includes(other.relativePath)) continue;
289391
+ if (this.classifyRole(other) === role) {
289392
+ related.push(other.relativePath);
289393
+ if (related.length >= 8) break;
289394
+ }
289395
+ }
289396
+ }
289397
+ return related;
289398
+ }
289399
+ generateEditGuidance(file, role, layer, dependedOnBy, conventions) {
289400
+ const guidance = [];
289401
+ if (dependedOnBy.length > 10) {
289402
+ guidance.push(`HIGH IMPACT: ${dependedOnBy.length} files depend on this. Changes have wide blast radius.`);
289403
+ }
289404
+ switch (role) {
289405
+ case "route-handler":
289406
+ guidance.push("Validate all inputs with schemas before processing.");
289407
+ guidance.push("Return consistent response shapes ({ success, data } or { success, error }).");
289408
+ guidance.push("Ensure authentication middleware is applied to protected endpoints.");
289409
+ break;
289410
+ case "service":
289411
+ guidance.push("Keep business logic here, not in controllers/routes.");
289412
+ guidance.push("Use dependency injection for testability.");
289413
+ if (layer) guidance.push(`This is in the ${layer} layer \u2014 only import from lower layers.`);
289414
+ break;
289415
+ case "repository":
289416
+ guidance.push("Only data access logic belongs here \u2014 no business rules.");
289417
+ guidance.push("Return domain objects, not raw database rows.");
289418
+ break;
289419
+ case "component":
289420
+ guidance.push("Keep components focused and composable.");
289421
+ guidance.push("Extract complex logic to custom hooks.");
289422
+ break;
289423
+ case "middleware":
289424
+ guidance.push("Middleware must call next() or return a response \u2014 never leave the request hanging.");
289425
+ guidance.push("Keep middleware focused on a single concern.");
289426
+ break;
289427
+ case "test":
289428
+ guidance.push("Follow Arrange-Act-Assert pattern.");
289429
+ guidance.push("Test edge cases and error conditions, not just happy path.");
289430
+ break;
289431
+ }
289432
+ for (const conv of conventions.slice(0, 3)) {
289433
+ guidance.push(`Convention: ${conv}`);
289434
+ }
289435
+ return guidance;
289436
+ }
289437
+ // ═══════════════════════════════════════════════════════════════════════════
289438
+ // TASK PLAYBOOKS
289439
+ // ═══════════════════════════════════════════════════════════════════════════
289440
+ buildTaskPlaybooks() {
289441
+ const fp = this.dna.fingerprint;
289442
+ const playbooks = [];
289443
+ playbooks.push({
289444
+ taskType: "Bug Fix",
289445
+ steps: [
289446
+ "Reproduce the bug and understand the expected vs actual behavior",
289447
+ "Identify the root cause file(s) using the dependency graph",
289448
+ "Write a failing test that reproduces the bug",
289449
+ "Apply the minimal fix at the root cause",
289450
+ "Verify the fix passes the test and does not break existing tests",
289451
+ "Check that the fix does not violate any architecture rules"
289452
+ ],
289453
+ mustRead: this.dna.hotspots.slice(0, 3).map((h) => h.file),
289454
+ mustUpdate: ["The buggy file", "Related test file"],
289455
+ mustVerify: ["All existing tests pass", "New regression test passes", "No new arch rule violations"],
289456
+ stopConditions: ["Never modify tests to make them pass \u2014 fix the code", "Do not change public API signatures without discussion"]
289457
+ });
289458
+ if (fp.router) {
289459
+ playbooks.push({
289460
+ taskType: "Add API Endpoint",
289461
+ steps: [
289462
+ "Check existing routes in truthpack to avoid duplicates",
289463
+ "Create the route handler following existing patterns",
289464
+ "Add input validation using the project validator",
289465
+ "Add authentication middleware if the route is protected",
289466
+ "Write tests for success, validation failure, and auth failure",
289467
+ "Update the truthpack (run vibecheck scan)"
289468
+ ],
289469
+ mustRead: ["truthpack/routes.json", ...this.dna.patterns.filter((p) => p.category === "api").map((p) => p.exemplar)],
289470
+ mustUpdate: ["Route file", "Test file", "Truthpack"],
289471
+ mustVerify: ["Route responds correctly", "Input validation works", "Auth is enforced", "Test passes"],
289472
+ stopConditions: ["Do not create duplicate routes", "Do not hardcode mock data in handlers"]
289473
+ });
289474
+ }
289475
+ if (fp.framework.includes("Next") || fp.framework.includes("React")) {
289476
+ playbooks.push({
289477
+ taskType: "Add UI Component",
289478
+ steps: [
289479
+ "Check if a similar component already exists",
289480
+ "Create the component following existing naming and structure patterns",
289481
+ "Add TypeScript props interface",
289482
+ "Add unit test for the component",
289483
+ "If using state, determine if it should be a client component"
289484
+ ],
289485
+ mustRead: this.dna.patterns.filter((p) => p.category === "ui" || p.category === "state").map((p) => p.exemplar),
289486
+ mustUpdate: ["Component file", "Test file", "Parent component that uses it"],
289487
+ mustVerify: ["Component renders correctly", "Props are typed", "Test passes"],
289488
+ stopConditions: ['Do not use "any" type for props', 'Do not add useState in server components without "use client"']
289489
+ });
289490
+ }
289491
+ playbooks.push({
289492
+ taskType: "Refactor",
289493
+ steps: [
289494
+ "Identify all callers/dependents of the code being refactored",
289495
+ "Ensure comprehensive tests exist before refactoring",
289496
+ "Apply changes incrementally, testing after each step",
289497
+ "Update all dependents to use the new API",
289498
+ "Remove old code only after all dependents are migrated",
289499
+ "Verify no architecture rules are violated"
289500
+ ],
289501
+ mustRead: ["Dependency graph for affected files"],
289502
+ mustUpdate: ["Refactored file", "All dependent files", "Tests"],
289503
+ mustVerify: ["All tests pass", "No new violations", "No regressions"],
289504
+ stopConditions: ["Never break existing public APIs without migration path", "Do not refactor and add features in the same change"]
289505
+ });
289506
+ return playbooks;
289507
+ }
289508
+ // ═══════════════════════════════════════════════════════════════════════════
289509
+ // VERIFICATION STEPS
289510
+ // ═══════════════════════════════════════════════════════════════════════════
289511
+ buildVerificationSteps() {
289512
+ const fp = this.dna.fingerprint;
289513
+ const steps = [];
289514
+ if (fp.language === "TypeScript") {
289515
+ steps.push({
289516
+ trigger: "Any TypeScript file change",
289517
+ checks: ["TypeScript compilation succeeds", "No new type errors introduced"],
289518
+ commands: [fp.packageManager === "pnpm" ? "pnpm run check-types" : "npm run check-types"],
289519
+ artifacts: []
289520
+ });
289521
+ }
289522
+ if (fp.testRunner) {
289523
+ steps.push({
289524
+ trigger: "Any source file change",
289525
+ checks: ["Related tests pass", "No test regressions"],
289526
+ commands: [`${fp.packageManager} run test`],
289527
+ artifacts: ["test-results.json"]
289528
+ });
289529
+ }
289530
+ if (fp.router) {
289531
+ steps.push({
289532
+ trigger: "Route handler added or modified",
289533
+ checks: ["Route responds with correct status", "Auth middleware is applied", "Input validation works"],
289534
+ commands: ["vibecheck scan"],
289535
+ artifacts: ["truthpack/routes.json"]
289536
+ });
289537
+ }
289538
+ steps.push({
289539
+ trigger: "Any source file change",
289540
+ checks: ["No new architecture rule violations", "No new circular dependencies"],
289541
+ commands: ["vibecheck arch-rules"],
289542
+ artifacts: []
289543
+ });
289544
+ return steps;
289545
+ }
289546
+ // ═══════════════════════════════════════════════════════════════════════════
289547
+ // RISK BRIEFING
289548
+ // ═══════════════════════════════════════════════════════════════════════════
289549
+ buildRiskBriefing() {
289550
+ const criticalFiles = this.dna.hotspots.filter((h) => h.score > 30).slice(0, 10).map((h) => h.file);
289551
+ const recentViolations = this.ruleResult?.violations.filter((v) => v.severity === "error").slice(0, 10) || [];
289552
+ const securityConcerns = [];
289553
+ for (const risk of this.dna.riskMap) {
289554
+ if (risk.riskLevel === "critical") {
289555
+ securityConcerns.push(`${risk.file}: ${risk.factors.join(", ")}`);
289556
+ }
289557
+ }
289558
+ const testGaps = [];
289559
+ const sourceFiles = this.data.files.filter(
289560
+ (f) => !f.relativePath.includes(".test.") && !f.relativePath.includes(".spec.") && (f.relativePath.endsWith(".ts") || f.relativePath.endsWith(".tsx")) && !f.relativePath.includes("config") && !f.relativePath.includes(".d.ts")
289561
+ );
289562
+ const testFiles = this.data.files.filter(
289563
+ (f) => f.relativePath.includes(".test.") || f.relativePath.includes(".spec.")
289564
+ );
289565
+ const testedBases = new Set(testFiles.map(
289566
+ (f) => path5.basename(f.relativePath).replace(/\.(test|spec)\.(ts|tsx|js|jsx)$/, "")
289567
+ ));
289568
+ for (const file of sourceFiles) {
289569
+ const baseName = path5.basename(file.relativePath).replace(/\.(ts|tsx|js|jsx)$/, "");
289570
+ if (!testedBases.has(baseName) && file.exports.length > 0) {
289571
+ testGaps.push(`${file.relativePath} has exports but no test file`);
289572
+ }
289573
+ }
289574
+ const driftWarnings = [];
289575
+ for (const cycle of this.graph.cycles) {
289576
+ driftWarnings.push(`Circular dependency: ${cycle.nodes.slice(0, 3).join(" \u2192 ")}${cycle.nodes.length > 3 ? "..." : ""}`);
289577
+ }
289578
+ return {
289579
+ criticalFiles,
289580
+ recentViolations,
289581
+ securityConcerns: securityConcerns.slice(0, 5),
289582
+ testGaps: testGaps.slice(0, 10),
289583
+ driftWarnings: driftWarnings.slice(0, 5)
289584
+ };
289585
+ }
289586
+ // ═══════════════════════════════════════════════════════════════════════════
289587
+ // HELPERS
289588
+ // ═══════════════════════════════════════════════════════════════════════════
289589
+ toRelative(filePath) {
289590
+ if (filePath.startsWith(this.rootPath)) {
289591
+ return filePath.slice(this.rootPath.length + 1).replace(/\\/g, "/");
289592
+ }
289593
+ return filePath.replace(/\\/g, "/");
289594
+ }
289595
+ };
289596
+ var ContextExplainer = class {
289597
+ /**
289598
+ * Generate a rich explanation for a file.
289599
+ */
289600
+ explain(filePath, ctx) {
289601
+ const fc = ctx.fileContext;
289602
+ const paragraphs = [];
289603
+ const quickFacts = [];
289604
+ const warnings = [];
289605
+ const relatedFiles = [];
289606
+ const overlays = [];
289607
+ const role = fc?.role ?? "unknown";
289608
+ const roleSummary = this.buildRoleSummary(filePath, role, ctx);
289609
+ if (fc) {
289610
+ const depCount = fc.dependedOnBy.length;
289611
+ const depsOnCount = fc.dependsOn.length;
289612
+ if (depCount > 0 || depsOnCount > 0) {
289613
+ const parts2 = [];
289614
+ if (depCount > 0) {
289615
+ const critical = depCount > 10 ? " \u2014 changes here have wide blast radius" : "";
289616
+ parts2.push(`${depCount} file${depCount > 1 ? "s" : ""} depend on this${critical}`);
289617
+ }
289618
+ if (depsOnCount > 0) {
289619
+ parts2.push(`it imports from ${depsOnCount} file${depsOnCount > 1 ? "s" : ""}`);
289620
+ }
289621
+ paragraphs.push({
289622
+ heading: "Dependencies",
289623
+ text: parts2.join(". ") + ".",
289624
+ importance: depCount > 10 ? "critical" : depCount > 5 ? "high" : "medium"
289625
+ });
289626
+ }
289627
+ quickFacts.push({ label: "Role", value: role, icon: "layer" });
289628
+ if (fc.layer) quickFacts.push({ label: "Layer", value: fc.layer, icon: "layer" });
289629
+ quickFacts.push({ label: "Dependents", value: String(depCount), icon: "dependency" });
289630
+ quickFacts.push({ label: "Dependencies", value: String(depsOnCount), icon: "dependency" });
289631
+ if (fc.riskLevel === "critical" || fc.riskLevel === "high") {
289632
+ quickFacts.push({ label: "Risk", value: fc.riskLevel.toUpperCase(), icon: "warning" });
289633
+ warnings.push({
289634
+ message: `This file is classified as ${fc.riskLevel} risk`,
289635
+ severity: fc.riskLevel === "critical" ? "error" : "warning",
289636
+ action: "Add comprehensive tests and review carefully before merging changes"
289637
+ });
289638
+ }
289639
+ for (const dep of fc.dependedOnBy.slice(0, 5)) {
289640
+ relatedFiles.push({
289641
+ filePath: dep,
289642
+ reason: `Imports from this file`,
289643
+ relationship: "depended-by",
289644
+ confidence: 0.9
289645
+ });
289646
+ }
289647
+ overlays.push({
289648
+ type: "code-lens",
289649
+ line: 1,
289650
+ text: `${depCount} dependent${depCount !== 1 ? "s" : ""} \xB7 ${depsOnCount} import${depsOnCount !== 1 ? "s" : ""} \xB7 ${role}`,
289651
+ tooltip: `This ${role} file has ${depCount} files that depend on it and imports from ${depsOnCount} files`
289652
+ });
289653
+ }
289654
+ if (fc && fc.conventions.length > 0) {
289655
+ paragraphs.push({
289656
+ heading: "Conventions",
289657
+ text: `Follow these discovered conventions: ${fc.conventions.slice(0, 3).join("; ")}.`,
289658
+ importance: "medium"
289659
+ });
289660
+ }
289661
+ if (ctx.rules) {
289662
+ const fileViolations = ctx.rules.violations.filter(
289663
+ (v) => v.sourceSymbol.filePath.includes(shortName(filePath)) || v.targetSymbol && v.targetSymbol.filePath.includes(shortName(filePath))
289664
+ );
289665
+ if (fileViolations.length > 0) {
289666
+ const errors = fileViolations.filter((v) => v.severity === "error");
289667
+ const warns = fileViolations.filter((v) => v.severity === "warning");
289668
+ paragraphs.push({
289669
+ heading: "Architecture Violations",
289670
+ text: `${errors.length} error${errors.length !== 1 ? "s" : ""} and ${warns.length} warning${warns.length !== 1 ? "s" : ""} from architecture rules.`,
289671
+ importance: errors.length > 0 ? "critical" : "high"
289672
+ });
289673
+ for (const v of fileViolations.slice(0, 5)) {
289674
+ warnings.push({
289675
+ message: v.message,
289676
+ severity: v.severity === "error" ? "error" : "warning",
289677
+ action: v.suggestedFix ?? "Review and fix the violation",
289678
+ ruleId: v.ruleId
289679
+ });
289680
+ overlays.push({
289681
+ type: "diagnostic",
289682
+ line: v.sourceSymbol.line,
289683
+ text: v.message,
289684
+ severity: v.severity === "error" ? "error" : "warning",
289685
+ tooltip: v.suggestedFix
289686
+ });
289687
+ }
289688
+ }
289689
+ }
289690
+ if (ctx.callGraph) {
289691
+ const fileNodes = ctx.callGraph.nodes.filter((n) => n.filePath.includes(shortName(filePath)));
289692
+ const hotFunctions = fileNodes.filter((n) => n.callerCount > 5);
289693
+ if (hotFunctions.length > 0) {
289694
+ paragraphs.push({
289695
+ heading: "Hot Functions",
289696
+ text: hotFunctions.map(
289697
+ (f) => `\`${f.name}\` is called by ${f.callerCount} function${f.callerCount !== 1 ? "s" : ""}${f.calleeCount > 0 ? ` and calls ${f.calleeCount}` : ""}`
289698
+ ).join(". ") + ".",
289699
+ importance: "high"
289700
+ });
289701
+ for (const fn of hotFunctions) {
289702
+ overlays.push({
289703
+ type: "code-lens",
289704
+ line: 0,
289705
+ // Would need symbol line mapping
289706
+ text: `${fn.callerCount} callers \xB7 ${fn.calleeCount} callees`,
289707
+ tooltip: `Function ${fn.name} has ${fn.callerCount} callers and ${fn.calleeCount} callees`
289708
+ });
289709
+ }
289710
+ }
289711
+ const deadInFile = ctx.callGraph.stats.deadFunctions.filter(
289712
+ (d) => d.filePath.includes(shortName(filePath))
289713
+ );
289714
+ if (deadInFile.length > 0) {
289715
+ for (const dead of deadInFile) {
289716
+ warnings.push({
289717
+ message: `\`${dead.name}\` appears to be dead code (exported but never called)`,
289718
+ severity: "info",
289719
+ action: "Verify this function is not called via dynamic dispatch or external consumers, then consider removing it"
289720
+ });
289721
+ }
289722
+ }
289723
+ }
289724
+ if (ctx.temporal) {
289725
+ const hotspot = ctx.temporal.changeHotspots.find((h) => filePath.includes(h.file) || h.file.includes(shortName(filePath)));
289726
+ if (hotspot) {
289727
+ const daysSince = Math.round((Date.now() - new Date(hotspot.lastChanged).getTime()) / 864e5);
289728
+ paragraphs.push({
289729
+ heading: "Recent Activity",
289730
+ text: `Changed ${hotspot.commits} times in the last ${ctx.temporal.stats.analysisWindowDays} days by ${hotspot.authors} author${hotspot.authors !== 1 ? "s" : ""}. Last modified ${daysSince} day${daysSince !== 1 ? "s" : ""} ago.`,
289731
+ importance: hotspot.commits > 10 ? "high" : "medium"
289732
+ });
289733
+ quickFacts.push({ label: "Recent commits", value: String(hotspot.commits), icon: "git" });
289734
+ quickFacts.push({ label: "Last changed", value: `${daysSince}d ago`, icon: "git" });
289735
+ quickFacts.push({ label: "Authors", value: String(hotspot.authors), icon: "git" });
289736
+ }
289737
+ const churn = ctx.temporal.churnFiles.find((c) => filePath.includes(c.file) || c.file.includes(shortName(filePath)));
289738
+ if (churn && churn.severity !== "low") {
289739
+ warnings.push({
289740
+ message: churn.reason,
289741
+ severity: churn.severity === "high" ? "warning" : "info",
289742
+ action: "Consider whether this file needs refactoring to reduce change frequency"
289743
+ });
289744
+ }
289745
+ const expertise = ctx.temporal.authorExpertise.find(
289746
+ (e) => filePath.startsWith(e.area) || filePath.includes(e.area)
289747
+ );
289748
+ if (expertise && expertise.busFactor === 1) {
289749
+ warnings.push({
289750
+ message: `Bus factor of 1 \u2014 ${expertise.primaryAuthor} has made ${expertise.authors[0]?.percentage}% of changes to this area`,
289751
+ severity: "info",
289752
+ action: "Consider knowledge sharing or pair programming for this area"
289753
+ });
289754
+ }
289755
+ }
289756
+ if (ctx.learned) {
289757
+ const coEdits = ctx.learned.coEdits.filter((p) => p.files[0].includes(shortName(filePath)) || p.files[1].includes(shortName(filePath))).slice(0, 3);
289758
+ if (coEdits.length > 0) {
289759
+ for (const pair of coEdits) {
289760
+ const other = pair.files[0].includes(shortName(filePath)) ? pair.files[1] : pair.files[0];
289761
+ relatedFiles.push({
289762
+ filePath: other,
289763
+ reason: `Often edited together (${pair.count} times)`,
289764
+ relationship: "co-edited",
289765
+ confidence: pair.weight
289766
+ });
289767
+ }
289768
+ }
289769
+ }
289770
+ if (fc && fc.editGuidance.length > 0) {
289771
+ paragraphs.push({
289772
+ heading: "Edit Guidance",
289773
+ text: fc.editGuidance.join(" "),
289774
+ importance: "medium"
289775
+ });
289776
+ }
289777
+ return {
289778
+ filePath,
289779
+ roleSummary,
289780
+ paragraphs,
289781
+ quickFacts,
289782
+ warnings,
289783
+ relatedFiles,
289784
+ overlays
289785
+ };
289786
+ }
289787
+ /**
289788
+ * Generate a compact markdown explanation for AI agent consumption.
289789
+ */
289790
+ explainForAgent(filePath, ctx) {
289791
+ const explanation = this.explain(filePath, ctx);
289792
+ const lines = [];
289793
+ lines.push(`## ${shortName(filePath)}: ${explanation.roleSummary}`);
289794
+ lines.push("");
289795
+ if (explanation.quickFacts.length > 0) {
289796
+ lines.push(explanation.quickFacts.map((f) => `**${f.label}**: ${f.value}`).join(" \xB7 "));
289797
+ lines.push("");
289798
+ }
289799
+ for (const p of explanation.paragraphs.filter((p2) => p2.importance === "critical" || p2.importance === "high")) {
289800
+ lines.push(`### ${p.heading}`);
289801
+ lines.push(p.text);
289802
+ lines.push("");
289803
+ }
289804
+ if (explanation.warnings.length > 0) {
289805
+ lines.push("### Warnings");
289806
+ for (const w of explanation.warnings) {
289807
+ const icon = w.severity === "error" ? "MUST FIX" : w.severity === "warning" ? "SHOULD FIX" : "NOTE";
289808
+ lines.push(`- **[${icon}]** ${w.message} \u2014 ${w.action}`);
289809
+ }
289810
+ lines.push("");
289811
+ }
289812
+ if (explanation.relatedFiles.length > 0) {
289813
+ lines.push("### Related Files");
289814
+ for (const rf of explanation.relatedFiles.slice(0, 5)) {
289815
+ lines.push(`- \`${rf.filePath}\` \u2014 ${rf.reason}`);
289816
+ }
289817
+ lines.push("");
289818
+ }
289819
+ return lines.join("\n");
289820
+ }
289821
+ /**
289822
+ * Generate IDE overlay data for the VS Code extension to consume.
289823
+ */
289824
+ getIDEOverlays(filePath, ctx) {
289825
+ const explanation = this.explain(filePath, ctx);
289826
+ return explanation.overlays;
289827
+ }
289828
+ /**
289829
+ * Generate a health report explanation.
289830
+ */
289831
+ explainHealth(health, dna) {
289832
+ const lines = [];
289833
+ const dims = health.dimensions;
289834
+ lines.push(`## Codebase Health: ${health.overall}/100`);
289835
+ lines.push("");
289836
+ const entries = [
289837
+ { name: "Architecture", score: dims.architecture, explain: this.explainArchScore(dims.architecture, dna) },
289838
+ { name: "Test Coverage", score: dims.testCoverage, explain: this.explainTestScore(dims.testCoverage) },
289839
+ { name: "Conventions", score: dims.conventions, explain: this.explainConventionScore(dims.conventions, dna) },
289840
+ { name: "Dependencies", score: dims.dependencies, explain: this.explainDependencyScore(dims.dependencies, dna) },
289841
+ { name: "Security", score: dims.security, explain: dims.security >= 80 ? "No critical security concerns detected" : "Critical risk areas identified" },
289842
+ { name: "Complexity", score: dims.complexity, explain: dims.complexity >= 80 ? "Complexity is well-managed" : "High-complexity hotspots detected" }
289843
+ ];
289844
+ for (const entry of entries) {
289845
+ const bar = this.renderBar(entry.score);
289846
+ lines.push(`${bar} **${entry.name}**: ${entry.score}/100 \u2014 ${entry.explain}`);
289847
+ }
289848
+ return lines.join("\n");
289849
+ }
289850
+ // ═══════════════════════════════════════════════════════════════════════════
289851
+ // PRIVATE
289852
+ // ═══════════════════════════════════════════════════════════════════════════
289853
+ buildRoleSummary(filePath, role, ctx) {
289854
+ const parts2 = [];
289855
+ switch (role) {
289856
+ case "service":
289857
+ parts2.push("Business logic service");
289858
+ break;
289859
+ case "route-handler":
289860
+ parts2.push("API route handler");
289861
+ break;
289862
+ case "component":
289863
+ parts2.push("UI component");
289864
+ break;
289865
+ case "repository":
289866
+ parts2.push("Data access layer");
289867
+ break;
289868
+ case "middleware":
289869
+ parts2.push("Request middleware");
289870
+ break;
289871
+ case "test":
289872
+ parts2.push("Test file");
289873
+ break;
289874
+ case "config":
289875
+ parts2.push("Configuration");
289876
+ break;
289877
+ case "type":
289878
+ parts2.push("Type definitions");
289879
+ break;
289880
+ case "util":
289881
+ parts2.push("Utility module");
289882
+ break;
289883
+ case "entry":
289884
+ parts2.push("Entry point");
289885
+ break;
289886
+ default:
289887
+ parts2.push("Source file");
289888
+ }
289889
+ if (ctx.fileContext) {
289890
+ if (ctx.fileContext.layer) parts2.push(`in ${ctx.fileContext.layer} layer`);
289891
+ if (ctx.fileContext.dependedOnBy.length > 10) parts2.push("(high-impact)");
289892
+ }
289893
+ return parts2.join(" ");
289894
+ }
289895
+ explainArchScore(score, dna) {
289896
+ if (score >= 80) return `Strong architecture with ${dna.patterns.length} recognized patterns`;
289897
+ if (score >= 50) return `Moderate architecture \u2014 ${dna.patterns.length} patterns detected, room to strengthen boundaries`;
289898
+ return "Architecture needs attention \u2014 few recognized patterns or boundaries";
289899
+ }
289900
+ explainTestScore(score) {
289901
+ if (score >= 80) return "Good test coverage across source files";
289902
+ if (score >= 50) return "Moderate coverage \u2014 some source files lack tests";
289903
+ return "Low test coverage \u2014 many exported modules have no test files";
289904
+ }
289905
+ explainConventionScore(score, dna) {
289906
+ const strong = dna.conventions.filter((c) => c.confidence > 0.6).length;
289907
+ if (score >= 80) return `${strong} strong conventions enforced consistently`;
289908
+ if (score >= 50) return `${strong} conventions detected but inconsistently applied`;
289909
+ return "Few consistent conventions \u2014 codebase style varies across files";
289910
+ }
289911
+ explainDependencyScore(score, dna) {
289912
+ const circular = dna.boundaries.filter((b) => b.isCircular).length;
289913
+ if (score >= 80) return "Clean dependency graph with no circular dependencies";
289914
+ if (circular > 0) return `${circular} circular dependency${circular > 1 ? "ies" : "y"} detected \u2014 these increase coupling and make code harder to reason about`;
289915
+ return "Dependency health needs improvement";
289916
+ }
289917
+ renderBar(score) {
289918
+ const filled = Math.round(score / 10);
289919
+ return "\u2588".repeat(filled) + "\u2591".repeat(10 - filled);
289920
+ }
289921
+ };
289922
+ function shortName(filePath) {
289923
+ const parts2 = filePath.split("/");
289924
+ return parts2[parts2.length - 1] ?? filePath;
289925
+ }
289926
+
289091
289927
  // ../context-engine/dist/chunk-HMKLYBWJ.js
289092
289928
  var import_better_sqlite3 = __toESM(require_lib(), 1);
289093
289929
  var import_fast_glob2 = __toESM(require_out4(), 1);
@@ -289097,7 +289933,7 @@ import { mkdirSync } from "fs";
289097
289933
  import { join as join4 } from "path";
289098
289934
  import { readFile as readFile22 } from "fs/promises";
289099
289935
  import { accessSync } from "fs";
289100
- import { extname as extname2, resolve as resolve2, dirname as dirname5 } from "path";
289936
+ import { extname as extname2, resolve as resolve2, dirname as dirname6 } from "path";
289101
289937
  import { createHash as createHash22 } from "crypto";
289102
289938
  var SCHEMA_VERSION = 1;
289103
289939
  var PersistentIndex = class {
@@ -289995,7 +290831,7 @@ var DefaultFileParser = class {
289995
290831
  }
289996
290832
  resolveImportPath(sourcePath, fromFile) {
289997
290833
  if (!sourcePath.startsWith(".")) return sourcePath;
289998
- const dir = dirname5(fromFile);
290834
+ const dir = dirname6(fromFile);
289999
290835
  const resolved = resolve2(dir, sourcePath);
290000
290836
  const extensions = [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx", "/index.js"];
290001
290837
  for (const ext2 of extensions) {
@@ -290105,845 +290941,6 @@ function flattenCodeSymbols(symbols) {
290105
290941
  return flat;
290106
290942
  }
290107
290943
 
290108
- // ../context-engine/dist/chunk-INBCP46U.js
290109
- import * as path5 from "path";
290110
- var ContextSynthesizer = class {
290111
- rootPath;
290112
- data;
290113
- dna;
290114
- graph;
290115
- ruleResult;
290116
- constructor(rootPath, data, dna, graph, ruleResult) {
290117
- this.rootPath = rootPath;
290118
- this.data = data;
290119
- this.dna = dna;
290120
- this.graph = graph;
290121
- this.ruleResult = ruleResult || null;
290122
- }
290123
- /**
290124
- * Synthesize the full context — the complete brain dump for AI agents.
290125
- */
290126
- synthesize() {
290127
- const projectIdentity = this.buildProjectIdentity();
290128
- const archRules = this.buildArchRuleSummary();
290129
- const activeViolations = this.ruleResult?.violations || [];
290130
- const codebaseDNA = this.buildDNASummary();
290131
- const fileContexts = this.buildFileContexts();
290132
- const taskPlaybooks = this.buildTaskPlaybooks();
290133
- const verificationSteps = this.buildVerificationSteps();
290134
- const riskBriefing = this.buildRiskBriefing();
290135
- return {
290136
- version: "2.0.0",
290137
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
290138
- projectIdentity,
290139
- architecturalRules: archRules,
290140
- activeViolations,
290141
- codebaseDNA,
290142
- fileContexts,
290143
- taskPlaybooks,
290144
- verificationSteps,
290145
- riskBriefing
290146
- };
290147
- }
290148
- /**
290149
- * Generate context for a specific file — what an AI agent needs to know
290150
- * before editing this file.
290151
- */
290152
- synthesizeForFile(filePath) {
290153
- const rel = this.toRelative(filePath);
290154
- const file = this.data.files.find((f) => f.relativePath === rel || f.path === filePath);
290155
- if (!file) return null;
290156
- return this.buildSingleFileContext(file);
290157
- }
290158
- /**
290159
- * Generate a compact markdown context document for IDE rules.
290160
- * This replaces the old static rule generation with intelligence-driven context.
290161
- */
290162
- generateContextDocument() {
290163
- const ctx = this.synthesize();
290164
- const lines = [];
290165
- lines.push(`# ${ctx.projectIdentity.name} \u2014 AI Context`);
290166
- lines.push(`<!-- Generated by @repo/context-engine at ${ctx.generatedAt} -->`);
290167
- lines.push("");
290168
- lines.push("## Project Identity");
290169
- lines.push(`- **Stack**: ${ctx.projectIdentity.stack}`);
290170
- lines.push(`- **Architecture**: ${ctx.projectIdentity.architecture}`);
290171
- if (ctx.projectIdentity.keyPatterns.length > 0) {
290172
- lines.push(`- **Key Patterns**: ${ctx.projectIdentity.keyPatterns.join(", ")}`);
290173
- }
290174
- lines.push("");
290175
- if (ctx.codebaseDNA.conventions.length > 0) {
290176
- lines.push("## Conventions (Auto-Discovered)");
290177
- for (const conv of ctx.codebaseDNA.conventions) {
290178
- lines.push(`- ${conv}`);
290179
- }
290180
- lines.push("");
290181
- }
290182
- if (ctx.architecturalRules.length > 0) {
290183
- lines.push("## Architecture Rules");
290184
- for (const rule of ctx.architecturalRules) {
290185
- const icon = rule.severity === "error" ? "MUST" : rule.severity === "warning" ? "SHOULD" : "MAY";
290186
- lines.push(`- **[${icon}]** ${rule.name}: ${rule.description}`);
290187
- if (rule.violationCount > 0) {
290188
- lines.push(` - ${rule.violationCount} active violations`);
290189
- }
290190
- }
290191
- lines.push("");
290192
- }
290193
- if (ctx.codebaseDNA.boundaries.length > 0) {
290194
- lines.push("## Module Boundaries");
290195
- for (const boundary of ctx.codebaseDNA.boundaries) {
290196
- lines.push(`- ${boundary}`);
290197
- }
290198
- lines.push("");
290199
- }
290200
- if (ctx.codebaseDNA.hotFiles.length > 0) {
290201
- lines.push("## High-Impact Files (Edit With Care)");
290202
- for (const file of ctx.codebaseDNA.hotFiles.slice(0, 10)) {
290203
- lines.push(`- \`${file}\``);
290204
- }
290205
- lines.push("");
290206
- }
290207
- if (ctx.riskBriefing.securityConcerns.length > 0 || ctx.riskBriefing.testGaps.length > 0) {
290208
- lines.push("## Risk Areas");
290209
- for (const concern of ctx.riskBriefing.securityConcerns) {
290210
- lines.push(`- ${concern}`);
290211
- }
290212
- for (const gap of ctx.riskBriefing.testGaps.slice(0, 5)) {
290213
- lines.push(`- ${gap}`);
290214
- }
290215
- lines.push("");
290216
- }
290217
- if (ctx.projectIdentity.noGoZones.length > 0) {
290218
- lines.push("## No-Go Zones");
290219
- for (const zone of ctx.projectIdentity.noGoZones) {
290220
- lines.push(`- ${zone}`);
290221
- }
290222
- lines.push("");
290223
- }
290224
- if (ctx.taskPlaybooks.length > 0) {
290225
- lines.push("## Task Playbooks");
290226
- for (const playbook of ctx.taskPlaybooks) {
290227
- lines.push(`### ${playbook.taskType}`);
290228
- for (const step of playbook.steps) {
290229
- lines.push(`1. ${step}`);
290230
- }
290231
- if (playbook.mustVerify.length > 0) {
290232
- lines.push(`**Verify**: ${playbook.mustVerify.join(", ")}`);
290233
- }
290234
- lines.push("");
290235
- }
290236
- }
290237
- if (ctx.verificationSteps.length > 0) {
290238
- lines.push("## Verification Protocol");
290239
- for (const step of ctx.verificationSteps) {
290240
- lines.push(`### On ${step.trigger}`);
290241
- for (const check of step.checks) {
290242
- lines.push(`- ${check}`);
290243
- }
290244
- if (step.commands.length > 0) {
290245
- lines.push(`**Run**: \`${step.commands.join(" && ")}\``);
290246
- }
290247
- lines.push("");
290248
- }
290249
- }
290250
- lines.push("## Codebase Health");
290251
- lines.push(`- **Overall**: ${this.dna.healthScore.overall}/100`);
290252
- const dims = this.dna.healthScore.dimensions;
290253
- lines.push(`- Architecture: ${dims.architecture} | Tests: ${dims.testCoverage} | Conventions: ${dims.conventions} | Dependencies: ${dims.dependencies}`);
290254
- lines.push("");
290255
- lines.push("---");
290256
- lines.push("<!-- context-engine:v2 -->");
290257
- return lines.join("\n");
290258
- }
290259
- // ═══════════════════════════════════════════════════════════════════════════
290260
- // IDENTITY
290261
- // ═══════════════════════════════════════════════════════════════════════════
290262
- buildProjectIdentity() {
290263
- const fp = this.dna.fingerprint;
290264
- const stack = [fp.framework, fp.language, fp.orm, fp.validator, fp.authLib, fp.router].filter(Boolean).join(" | ");
290265
- const keyPatterns = this.dna.patterns.map((p) => p.name);
290266
- const criticalPaths = this.dna.hotspots.slice(0, 5).map((h) => h.file);
290267
- const noGoZones = [];
290268
- if (this.ruleResult) {
290269
- const errorRules = this.ruleResult.violations.filter((v) => v.severity === "error");
290270
- const uniqueMessages = [...new Set(errorRules.map((v) => v.message))];
290271
- noGoZones.push(...uniqueMessages.slice(0, 5));
290272
- }
290273
- for (const cycle of this.graph.cycles) {
290274
- noGoZones.push(`Circular dependency: ${cycle.nodes.slice(0, 3).join(" \u2192 ")}...`);
290275
- }
290276
- const architecture = this.dna.conventions.filter((c) => c.area === "structure").map((c) => c.description).join("; ") || fp.framework;
290277
- return {
290278
- name: fp.name,
290279
- stack,
290280
- architecture,
290281
- keyPatterns,
290282
- criticalPaths,
290283
- noGoZones: noGoZones.slice(0, 10)
290284
- };
290285
- }
290286
- // ═══════════════════════════════════════════════════════════════════════════
290287
- // RULES SUMMARY
290288
- // ═══════════════════════════════════════════════════════════════════════════
290289
- buildArchRuleSummary() {
290290
- if (!this.ruleResult) return [];
290291
- const breakdown = this.ruleResult.ruleBreakdown;
290292
- return Object.entries(breakdown).map(([ruleId, count]) => {
290293
- const violation = this.ruleResult.violations.find((v) => v.ruleId === ruleId);
290294
- return {
290295
- id: ruleId,
290296
- name: violation?.ruleName || ruleId,
290297
- type: "import_forbidden",
290298
- severity: violation?.severity || "warning",
290299
- scope: violation?.sourceSymbol.filePath || "",
290300
- description: violation?.message || "",
290301
- violationCount: count
290302
- };
290303
- });
290304
- }
290305
- // ═══════════════════════════════════════════════════════════════════════════
290306
- // DNA SUMMARY
290307
- // ═══════════════════════════════════════════════════════════════════════════
290308
- buildDNASummary() {
290309
- return {
290310
- conventions: this.dna.conventions.filter((c) => c.confidence > 0.5).map((c) => c.description),
290311
- patterns: this.dna.patterns.map((p) => `${p.name}: ${p.description}`),
290312
- boundaries: this.dna.boundaries.filter((b) => b.importCount > 3).map((b) => `${b.from} \u2192 ${b.to} (${b.importCount} imports${b.isCircular ? ", CIRCULAR" : ""})`),
290313
- hotFiles: this.dna.hotspots.slice(0, 10).map((h) => h.file),
290314
- riskAreas: this.dna.riskMap.filter((r) => r.riskLevel === "critical" || r.riskLevel === "high").map((r) => `${r.file}: ${r.factors[0]}`)
290315
- };
290316
- }
290317
- // ═══════════════════════════════════════════════════════════════════════════
290318
- // FILE CONTEXTS
290319
- // ═══════════════════════════════════════════════════════════════════════════
290320
- buildFileContexts() {
290321
- const contexts = /* @__PURE__ */ new Map();
290322
- for (const file of this.data.files) {
290323
- contexts.set(file.relativePath, this.buildSingleFileContext(file));
290324
- }
290325
- return contexts;
290326
- }
290327
- buildSingleFileContext(file) {
290328
- const rel = file.relativePath;
290329
- const role = this.classifyRole(file);
290330
- const graphNode = this.graph.nodes.find((n) => n.relativePath === rel);
290331
- const layer = graphNode?.layer;
290332
- const dependsOn = this.graph.edges.filter((e) => e.from === rel).map((e) => e.to);
290333
- const dependedOnBy = this.graph.edges.filter((e) => e.to === rel).map((e) => e.from);
290334
- const applicableRules = [];
290335
- if (this.ruleResult) {
290336
- for (const v of this.ruleResult.violations) {
290337
- if (v.sourceSymbol.filePath.includes(rel) || v.targetSymbol && v.targetSymbol.filePath.includes(rel)) {
290338
- if (!applicableRules.includes(v.ruleId)) applicableRules.push(v.ruleId);
290339
- }
290340
- }
290341
- }
290342
- const conventions = this.dna.conventions.filter((c) => this.conventionAppliesToFile(c.area, file)).map((c) => c.description);
290343
- const patterns = this.dna.patterns.filter((p) => p.fileMatches.some((m) => m === rel)).map((p) => p.name);
290344
- const riskEntry = this.dna.riskMap.find((r) => r.file === rel);
290345
- const riskLevel = riskEntry?.riskLevel || "low";
290346
- const relatedFiles = this.findRelatedFiles(file, role).slice(0, 8);
290347
- const editGuidance = this.generateEditGuidance(file, role, layer, dependedOnBy, conventions);
290348
- return {
290349
- filePath: file.path,
290350
- role,
290351
- layer,
290352
- dependsOn,
290353
- dependedOnBy,
290354
- applicableRules,
290355
- conventions,
290356
- patterns,
290357
- riskLevel,
290358
- relatedFiles,
290359
- editGuidance
290360
- };
290361
- }
290362
- classifyRole(file) {
290363
- const rel = file.relativePath.toLowerCase();
290364
- if (rel.includes(".test.") || rel.includes(".spec.") || rel.includes("__tests__")) return "test";
290365
- if (rel.includes("fixture") || rel.includes("mock")) return "fixture";
290366
- if (rel.includes("migration")) return "migration";
290367
- if (rel.match(/\.(css|scss|less|styl)$/)) return "style";
290368
- if (rel.includes(".config.") || rel.includes("config/") || rel === "tsconfig.json") return "config";
290369
- if (rel.includes("middleware")) return "middleware";
290370
- if (rel.includes("/api/") || rel.includes("route")) return "route-handler";
290371
- if (rel.includes("service") || rel.includes("Service")) return "service";
290372
- if (rel.includes("repositor") || rel.includes("Repositor")) return "repository";
290373
- if (rel.endsWith(".tsx") && !rel.includes("page.")) return "component";
290374
- if (rel.includes("/types") || rel.endsWith(".d.ts")) return "type";
290375
- if (rel.includes("util") || rel.includes("helper") || rel.includes("lib/")) return "util";
290376
- if (rel.includes("script") || rel.includes("bin/")) return "script";
290377
- if (rel.match(/^(src\/)?index\.|^(src\/)?main\.|^(src\/)?app\./)) return "entry";
290378
- return "unknown";
290379
- }
290380
- conventionAppliesToFile(area, file) {
290381
- switch (area) {
290382
- case "naming":
290383
- return true;
290384
- case "imports":
290385
- return file.relativePath.endsWith(".ts") || file.relativePath.endsWith(".tsx");
290386
- case "exports":
290387
- return file.exports.length > 0;
290388
- case "testing":
290389
- return file.relativePath.includes(".test.") || file.relativePath.includes(".spec.");
290390
- case "error-handling":
290391
- return !file.relativePath.includes(".test.");
290392
- case "types":
290393
- return file.relativePath.endsWith(".ts") || file.relativePath.endsWith(".tsx");
290394
- default:
290395
- return true;
290396
- }
290397
- }
290398
- findRelatedFiles(file, role) {
290399
- const related = [];
290400
- const dir = path5.dirname(file.relativePath);
290401
- for (const other of this.data.files) {
290402
- if (other.path === file.path) continue;
290403
- if (path5.dirname(other.relativePath) === dir) {
290404
- related.push(other.relativePath);
290405
- }
290406
- }
290407
- if (related.length < 5) {
290408
- for (const other of this.data.files) {
290409
- if (other.path === file.path) continue;
290410
- if (related.includes(other.relativePath)) continue;
290411
- if (this.classifyRole(other) === role) {
290412
- related.push(other.relativePath);
290413
- if (related.length >= 8) break;
290414
- }
290415
- }
290416
- }
290417
- return related;
290418
- }
290419
- generateEditGuidance(file, role, layer, dependedOnBy, conventions) {
290420
- const guidance = [];
290421
- if (dependedOnBy.length > 10) {
290422
- guidance.push(`HIGH IMPACT: ${dependedOnBy.length} files depend on this. Changes have wide blast radius.`);
290423
- }
290424
- switch (role) {
290425
- case "route-handler":
290426
- guidance.push("Validate all inputs with schemas before processing.");
290427
- guidance.push("Return consistent response shapes ({ success, data } or { success, error }).");
290428
- guidance.push("Ensure authentication middleware is applied to protected endpoints.");
290429
- break;
290430
- case "service":
290431
- guidance.push("Keep business logic here, not in controllers/routes.");
290432
- guidance.push("Use dependency injection for testability.");
290433
- if (layer) guidance.push(`This is in the ${layer} layer \u2014 only import from lower layers.`);
290434
- break;
290435
- case "repository":
290436
- guidance.push("Only data access logic belongs here \u2014 no business rules.");
290437
- guidance.push("Return domain objects, not raw database rows.");
290438
- break;
290439
- case "component":
290440
- guidance.push("Keep components focused and composable.");
290441
- guidance.push("Extract complex logic to custom hooks.");
290442
- break;
290443
- case "middleware":
290444
- guidance.push("Middleware must call next() or return a response \u2014 never leave the request hanging.");
290445
- guidance.push("Keep middleware focused on a single concern.");
290446
- break;
290447
- case "test":
290448
- guidance.push("Follow Arrange-Act-Assert pattern.");
290449
- guidance.push("Test edge cases and error conditions, not just happy path.");
290450
- break;
290451
- }
290452
- for (const conv of conventions.slice(0, 3)) {
290453
- guidance.push(`Convention: ${conv}`);
290454
- }
290455
- return guidance;
290456
- }
290457
- // ═══════════════════════════════════════════════════════════════════════════
290458
- // TASK PLAYBOOKS
290459
- // ═══════════════════════════════════════════════════════════════════════════
290460
- buildTaskPlaybooks() {
290461
- const fp = this.dna.fingerprint;
290462
- const playbooks = [];
290463
- playbooks.push({
290464
- taskType: "Bug Fix",
290465
- steps: [
290466
- "Reproduce the bug and understand the expected vs actual behavior",
290467
- "Identify the root cause file(s) using the dependency graph",
290468
- "Write a failing test that reproduces the bug",
290469
- "Apply the minimal fix at the root cause",
290470
- "Verify the fix passes the test and does not break existing tests",
290471
- "Check that the fix does not violate any architecture rules"
290472
- ],
290473
- mustRead: this.dna.hotspots.slice(0, 3).map((h) => h.file),
290474
- mustUpdate: ["The buggy file", "Related test file"],
290475
- mustVerify: ["All existing tests pass", "New regression test passes", "No new arch rule violations"],
290476
- stopConditions: ["Never modify tests to make them pass \u2014 fix the code", "Do not change public API signatures without discussion"]
290477
- });
290478
- if (fp.router) {
290479
- playbooks.push({
290480
- taskType: "Add API Endpoint",
290481
- steps: [
290482
- "Check existing routes in truthpack to avoid duplicates",
290483
- "Create the route handler following existing patterns",
290484
- "Add input validation using the project validator",
290485
- "Add authentication middleware if the route is protected",
290486
- "Write tests for success, validation failure, and auth failure",
290487
- "Update the truthpack (run vibecheck scan)"
290488
- ],
290489
- mustRead: ["truthpack/routes.json", ...this.dna.patterns.filter((p) => p.category === "api").map((p) => p.exemplar)],
290490
- mustUpdate: ["Route file", "Test file", "Truthpack"],
290491
- mustVerify: ["Route responds correctly", "Input validation works", "Auth is enforced", "Test passes"],
290492
- stopConditions: ["Do not create duplicate routes", "Do not hardcode mock data in handlers"]
290493
- });
290494
- }
290495
- if (fp.framework.includes("Next") || fp.framework.includes("React")) {
290496
- playbooks.push({
290497
- taskType: "Add UI Component",
290498
- steps: [
290499
- "Check if a similar component already exists",
290500
- "Create the component following existing naming and structure patterns",
290501
- "Add TypeScript props interface",
290502
- "Add unit test for the component",
290503
- "If using state, determine if it should be a client component"
290504
- ],
290505
- mustRead: this.dna.patterns.filter((p) => p.category === "ui" || p.category === "state").map((p) => p.exemplar),
290506
- mustUpdate: ["Component file", "Test file", "Parent component that uses it"],
290507
- mustVerify: ["Component renders correctly", "Props are typed", "Test passes"],
290508
- stopConditions: ['Do not use "any" type for props', 'Do not add useState in server components without "use client"']
290509
- });
290510
- }
290511
- playbooks.push({
290512
- taskType: "Refactor",
290513
- steps: [
290514
- "Identify all callers/dependents of the code being refactored",
290515
- "Ensure comprehensive tests exist before refactoring",
290516
- "Apply changes incrementally, testing after each step",
290517
- "Update all dependents to use the new API",
290518
- "Remove old code only after all dependents are migrated",
290519
- "Verify no architecture rules are violated"
290520
- ],
290521
- mustRead: ["Dependency graph for affected files"],
290522
- mustUpdate: ["Refactored file", "All dependent files", "Tests"],
290523
- mustVerify: ["All tests pass", "No new violations", "No regressions"],
290524
- stopConditions: ["Never break existing public APIs without migration path", "Do not refactor and add features in the same change"]
290525
- });
290526
- return playbooks;
290527
- }
290528
- // ═══════════════════════════════════════════════════════════════════════════
290529
- // VERIFICATION STEPS
290530
- // ═══════════════════════════════════════════════════════════════════════════
290531
- buildVerificationSteps() {
290532
- const fp = this.dna.fingerprint;
290533
- const steps = [];
290534
- if (fp.language === "TypeScript") {
290535
- steps.push({
290536
- trigger: "Any TypeScript file change",
290537
- checks: ["TypeScript compilation succeeds", "No new type errors introduced"],
290538
- commands: [fp.packageManager === "pnpm" ? "pnpm run check-types" : "npm run check-types"],
290539
- artifacts: []
290540
- });
290541
- }
290542
- if (fp.testRunner) {
290543
- steps.push({
290544
- trigger: "Any source file change",
290545
- checks: ["Related tests pass", "No test regressions"],
290546
- commands: [`${fp.packageManager} run test`],
290547
- artifacts: ["test-results.json"]
290548
- });
290549
- }
290550
- if (fp.router) {
290551
- steps.push({
290552
- trigger: "Route handler added or modified",
290553
- checks: ["Route responds with correct status", "Auth middleware is applied", "Input validation works"],
290554
- commands: ["vibecheck scan"],
290555
- artifacts: ["truthpack/routes.json"]
290556
- });
290557
- }
290558
- steps.push({
290559
- trigger: "Any source file change",
290560
- checks: ["No new architecture rule violations", "No new circular dependencies"],
290561
- commands: ["vibecheck arch-rules"],
290562
- artifacts: []
290563
- });
290564
- return steps;
290565
- }
290566
- // ═══════════════════════════════════════════════════════════════════════════
290567
- // RISK BRIEFING
290568
- // ═══════════════════════════════════════════════════════════════════════════
290569
- buildRiskBriefing() {
290570
- const criticalFiles = this.dna.hotspots.filter((h) => h.score > 30).slice(0, 10).map((h) => h.file);
290571
- const recentViolations = this.ruleResult?.violations.filter((v) => v.severity === "error").slice(0, 10) || [];
290572
- const securityConcerns = [];
290573
- for (const risk of this.dna.riskMap) {
290574
- if (risk.riskLevel === "critical") {
290575
- securityConcerns.push(`${risk.file}: ${risk.factors.join(", ")}`);
290576
- }
290577
- }
290578
- const testGaps = [];
290579
- const sourceFiles = this.data.files.filter(
290580
- (f) => !f.relativePath.includes(".test.") && !f.relativePath.includes(".spec.") && (f.relativePath.endsWith(".ts") || f.relativePath.endsWith(".tsx")) && !f.relativePath.includes("config") && !f.relativePath.includes(".d.ts")
290581
- );
290582
- const testFiles = this.data.files.filter(
290583
- (f) => f.relativePath.includes(".test.") || f.relativePath.includes(".spec.")
290584
- );
290585
- const testedBases = new Set(testFiles.map(
290586
- (f) => path5.basename(f.relativePath).replace(/\.(test|spec)\.(ts|tsx|js|jsx)$/, "")
290587
- ));
290588
- for (const file of sourceFiles) {
290589
- const baseName = path5.basename(file.relativePath).replace(/\.(ts|tsx|js|jsx)$/, "");
290590
- if (!testedBases.has(baseName) && file.exports.length > 0) {
290591
- testGaps.push(`${file.relativePath} has exports but no test file`);
290592
- }
290593
- }
290594
- const driftWarnings = [];
290595
- for (const cycle of this.graph.cycles) {
290596
- driftWarnings.push(`Circular dependency: ${cycle.nodes.slice(0, 3).join(" \u2192 ")}${cycle.nodes.length > 3 ? "..." : ""}`);
290597
- }
290598
- return {
290599
- criticalFiles,
290600
- recentViolations,
290601
- securityConcerns: securityConcerns.slice(0, 5),
290602
- testGaps: testGaps.slice(0, 10),
290603
- driftWarnings: driftWarnings.slice(0, 5)
290604
- };
290605
- }
290606
- // ═══════════════════════════════════════════════════════════════════════════
290607
- // HELPERS
290608
- // ═══════════════════════════════════════════════════════════════════════════
290609
- toRelative(filePath) {
290610
- if (filePath.startsWith(this.rootPath)) {
290611
- return filePath.slice(this.rootPath.length + 1).replace(/\\/g, "/");
290612
- }
290613
- return filePath.replace(/\\/g, "/");
290614
- }
290615
- };
290616
- var ContextExplainer = class {
290617
- /**
290618
- * Generate a rich explanation for a file.
290619
- */
290620
- explain(filePath, ctx) {
290621
- const fc = ctx.fileContext;
290622
- const paragraphs = [];
290623
- const quickFacts = [];
290624
- const warnings = [];
290625
- const relatedFiles = [];
290626
- const overlays = [];
290627
- const role = fc?.role ?? "unknown";
290628
- const roleSummary = this.buildRoleSummary(filePath, role, ctx);
290629
- if (fc) {
290630
- const depCount = fc.dependedOnBy.length;
290631
- const depsOnCount = fc.dependsOn.length;
290632
- if (depCount > 0 || depsOnCount > 0) {
290633
- const parts2 = [];
290634
- if (depCount > 0) {
290635
- const critical = depCount > 10 ? " \u2014 changes here have wide blast radius" : "";
290636
- parts2.push(`${depCount} file${depCount > 1 ? "s" : ""} depend on this${critical}`);
290637
- }
290638
- if (depsOnCount > 0) {
290639
- parts2.push(`it imports from ${depsOnCount} file${depsOnCount > 1 ? "s" : ""}`);
290640
- }
290641
- paragraphs.push({
290642
- heading: "Dependencies",
290643
- text: parts2.join(". ") + ".",
290644
- importance: depCount > 10 ? "critical" : depCount > 5 ? "high" : "medium"
290645
- });
290646
- }
290647
- quickFacts.push({ label: "Role", value: role, icon: "layer" });
290648
- if (fc.layer) quickFacts.push({ label: "Layer", value: fc.layer, icon: "layer" });
290649
- quickFacts.push({ label: "Dependents", value: String(depCount), icon: "dependency" });
290650
- quickFacts.push({ label: "Dependencies", value: String(depsOnCount), icon: "dependency" });
290651
- if (fc.riskLevel === "critical" || fc.riskLevel === "high") {
290652
- quickFacts.push({ label: "Risk", value: fc.riskLevel.toUpperCase(), icon: "warning" });
290653
- warnings.push({
290654
- message: `This file is classified as ${fc.riskLevel} risk`,
290655
- severity: fc.riskLevel === "critical" ? "error" : "warning",
290656
- action: "Add comprehensive tests and review carefully before merging changes"
290657
- });
290658
- }
290659
- for (const dep of fc.dependedOnBy.slice(0, 5)) {
290660
- relatedFiles.push({
290661
- filePath: dep,
290662
- reason: `Imports from this file`,
290663
- relationship: "depended-by",
290664
- confidence: 0.9
290665
- });
290666
- }
290667
- overlays.push({
290668
- type: "code-lens",
290669
- line: 1,
290670
- text: `${depCount} dependent${depCount !== 1 ? "s" : ""} \xB7 ${depsOnCount} import${depsOnCount !== 1 ? "s" : ""} \xB7 ${role}`,
290671
- tooltip: `This ${role} file has ${depCount} files that depend on it and imports from ${depsOnCount} files`
290672
- });
290673
- }
290674
- if (fc && fc.conventions.length > 0) {
290675
- paragraphs.push({
290676
- heading: "Conventions",
290677
- text: `Follow these discovered conventions: ${fc.conventions.slice(0, 3).join("; ")}.`,
290678
- importance: "medium"
290679
- });
290680
- }
290681
- if (ctx.rules) {
290682
- const fileViolations = ctx.rules.violations.filter(
290683
- (v) => v.sourceSymbol.filePath.includes(shortName(filePath)) || v.targetSymbol && v.targetSymbol.filePath.includes(shortName(filePath))
290684
- );
290685
- if (fileViolations.length > 0) {
290686
- const errors = fileViolations.filter((v) => v.severity === "error");
290687
- const warns = fileViolations.filter((v) => v.severity === "warning");
290688
- paragraphs.push({
290689
- heading: "Architecture Violations",
290690
- text: `${errors.length} error${errors.length !== 1 ? "s" : ""} and ${warns.length} warning${warns.length !== 1 ? "s" : ""} from architecture rules.`,
290691
- importance: errors.length > 0 ? "critical" : "high"
290692
- });
290693
- for (const v of fileViolations.slice(0, 5)) {
290694
- warnings.push({
290695
- message: v.message,
290696
- severity: v.severity === "error" ? "error" : "warning",
290697
- action: v.suggestedFix ?? "Review and fix the violation",
290698
- ruleId: v.ruleId
290699
- });
290700
- overlays.push({
290701
- type: "diagnostic",
290702
- line: v.sourceSymbol.line,
290703
- text: v.message,
290704
- severity: v.severity === "error" ? "error" : "warning",
290705
- tooltip: v.suggestedFix
290706
- });
290707
- }
290708
- }
290709
- }
290710
- if (ctx.callGraph) {
290711
- const fileNodes = ctx.callGraph.nodes.filter((n) => n.filePath.includes(shortName(filePath)));
290712
- const hotFunctions = fileNodes.filter((n) => n.callerCount > 5);
290713
- if (hotFunctions.length > 0) {
290714
- paragraphs.push({
290715
- heading: "Hot Functions",
290716
- text: hotFunctions.map(
290717
- (f) => `\`${f.name}\` is called by ${f.callerCount} function${f.callerCount !== 1 ? "s" : ""}${f.calleeCount > 0 ? ` and calls ${f.calleeCount}` : ""}`
290718
- ).join(". ") + ".",
290719
- importance: "high"
290720
- });
290721
- for (const fn of hotFunctions) {
290722
- overlays.push({
290723
- type: "code-lens",
290724
- line: 0,
290725
- // Would need symbol line mapping
290726
- text: `${fn.callerCount} callers \xB7 ${fn.calleeCount} callees`,
290727
- tooltip: `Function ${fn.name} has ${fn.callerCount} callers and ${fn.calleeCount} callees`
290728
- });
290729
- }
290730
- }
290731
- const deadInFile = ctx.callGraph.stats.deadFunctions.filter(
290732
- (d) => d.filePath.includes(shortName(filePath))
290733
- );
290734
- if (deadInFile.length > 0) {
290735
- for (const dead of deadInFile) {
290736
- warnings.push({
290737
- message: `\`${dead.name}\` appears to be dead code (exported but never called)`,
290738
- severity: "info",
290739
- action: "Verify this function is not called via dynamic dispatch or external consumers, then consider removing it"
290740
- });
290741
- }
290742
- }
290743
- }
290744
- if (ctx.temporal) {
290745
- const hotspot = ctx.temporal.changeHotspots.find((h) => filePath.includes(h.file) || h.file.includes(shortName(filePath)));
290746
- if (hotspot) {
290747
- const daysSince = Math.round((Date.now() - new Date(hotspot.lastChanged).getTime()) / 864e5);
290748
- paragraphs.push({
290749
- heading: "Recent Activity",
290750
- text: `Changed ${hotspot.commits} times in the last ${ctx.temporal.stats.analysisWindowDays} days by ${hotspot.authors} author${hotspot.authors !== 1 ? "s" : ""}. Last modified ${daysSince} day${daysSince !== 1 ? "s" : ""} ago.`,
290751
- importance: hotspot.commits > 10 ? "high" : "medium"
290752
- });
290753
- quickFacts.push({ label: "Recent commits", value: String(hotspot.commits), icon: "git" });
290754
- quickFacts.push({ label: "Last changed", value: `${daysSince}d ago`, icon: "git" });
290755
- quickFacts.push({ label: "Authors", value: String(hotspot.authors), icon: "git" });
290756
- }
290757
- const churn = ctx.temporal.churnFiles.find((c) => filePath.includes(c.file) || c.file.includes(shortName(filePath)));
290758
- if (churn && churn.severity !== "low") {
290759
- warnings.push({
290760
- message: churn.reason,
290761
- severity: churn.severity === "high" ? "warning" : "info",
290762
- action: "Consider whether this file needs refactoring to reduce change frequency"
290763
- });
290764
- }
290765
- const expertise = ctx.temporal.authorExpertise.find(
290766
- (e) => filePath.startsWith(e.area) || filePath.includes(e.area)
290767
- );
290768
- if (expertise && expertise.busFactor === 1) {
290769
- warnings.push({
290770
- message: `Bus factor of 1 \u2014 ${expertise.primaryAuthor} has made ${expertise.authors[0]?.percentage}% of changes to this area`,
290771
- severity: "info",
290772
- action: "Consider knowledge sharing or pair programming for this area"
290773
- });
290774
- }
290775
- }
290776
- if (ctx.learned) {
290777
- const coEdits = ctx.learned.coEdits.filter((p) => p.files[0].includes(shortName(filePath)) || p.files[1].includes(shortName(filePath))).slice(0, 3);
290778
- if (coEdits.length > 0) {
290779
- for (const pair of coEdits) {
290780
- const other = pair.files[0].includes(shortName(filePath)) ? pair.files[1] : pair.files[0];
290781
- relatedFiles.push({
290782
- filePath: other,
290783
- reason: `Often edited together (${pair.count} times)`,
290784
- relationship: "co-edited",
290785
- confidence: pair.weight
290786
- });
290787
- }
290788
- }
290789
- }
290790
- if (fc && fc.editGuidance.length > 0) {
290791
- paragraphs.push({
290792
- heading: "Edit Guidance",
290793
- text: fc.editGuidance.join(" "),
290794
- importance: "medium"
290795
- });
290796
- }
290797
- return {
290798
- filePath,
290799
- roleSummary,
290800
- paragraphs,
290801
- quickFacts,
290802
- warnings,
290803
- relatedFiles,
290804
- overlays
290805
- };
290806
- }
290807
- /**
290808
- * Generate a compact markdown explanation for AI agent consumption.
290809
- */
290810
- explainForAgent(filePath, ctx) {
290811
- const explanation = this.explain(filePath, ctx);
290812
- const lines = [];
290813
- lines.push(`## ${shortName(filePath)}: ${explanation.roleSummary}`);
290814
- lines.push("");
290815
- if (explanation.quickFacts.length > 0) {
290816
- lines.push(explanation.quickFacts.map((f) => `**${f.label}**: ${f.value}`).join(" \xB7 "));
290817
- lines.push("");
290818
- }
290819
- for (const p of explanation.paragraphs.filter((p2) => p2.importance === "critical" || p2.importance === "high")) {
290820
- lines.push(`### ${p.heading}`);
290821
- lines.push(p.text);
290822
- lines.push("");
290823
- }
290824
- if (explanation.warnings.length > 0) {
290825
- lines.push("### Warnings");
290826
- for (const w of explanation.warnings) {
290827
- const icon = w.severity === "error" ? "MUST FIX" : w.severity === "warning" ? "SHOULD FIX" : "NOTE";
290828
- lines.push(`- **[${icon}]** ${w.message} \u2014 ${w.action}`);
290829
- }
290830
- lines.push("");
290831
- }
290832
- if (explanation.relatedFiles.length > 0) {
290833
- lines.push("### Related Files");
290834
- for (const rf of explanation.relatedFiles.slice(0, 5)) {
290835
- lines.push(`- \`${rf.filePath}\` \u2014 ${rf.reason}`);
290836
- }
290837
- lines.push("");
290838
- }
290839
- return lines.join("\n");
290840
- }
290841
- /**
290842
- * Generate IDE overlay data for the VS Code extension to consume.
290843
- */
290844
- getIDEOverlays(filePath, ctx) {
290845
- const explanation = this.explain(filePath, ctx);
290846
- return explanation.overlays;
290847
- }
290848
- /**
290849
- * Generate a health report explanation.
290850
- */
290851
- explainHealth(health, dna) {
290852
- const lines = [];
290853
- const dims = health.dimensions;
290854
- lines.push(`## Codebase Health: ${health.overall}/100`);
290855
- lines.push("");
290856
- const entries = [
290857
- { name: "Architecture", score: dims.architecture, explain: this.explainArchScore(dims.architecture, dna) },
290858
- { name: "Test Coverage", score: dims.testCoverage, explain: this.explainTestScore(dims.testCoverage) },
290859
- { name: "Conventions", score: dims.conventions, explain: this.explainConventionScore(dims.conventions, dna) },
290860
- { name: "Dependencies", score: dims.dependencies, explain: this.explainDependencyScore(dims.dependencies, dna) },
290861
- { name: "Security", score: dims.security, explain: dims.security >= 80 ? "No critical security concerns detected" : "Critical risk areas identified" },
290862
- { name: "Complexity", score: dims.complexity, explain: dims.complexity >= 80 ? "Complexity is well-managed" : "High-complexity hotspots detected" }
290863
- ];
290864
- for (const entry of entries) {
290865
- const bar = this.renderBar(entry.score);
290866
- lines.push(`${bar} **${entry.name}**: ${entry.score}/100 \u2014 ${entry.explain}`);
290867
- }
290868
- return lines.join("\n");
290869
- }
290870
- // ═══════════════════════════════════════════════════════════════════════════
290871
- // PRIVATE
290872
- // ═══════════════════════════════════════════════════════════════════════════
290873
- buildRoleSummary(filePath, role, ctx) {
290874
- const parts2 = [];
290875
- switch (role) {
290876
- case "service":
290877
- parts2.push("Business logic service");
290878
- break;
290879
- case "route-handler":
290880
- parts2.push("API route handler");
290881
- break;
290882
- case "component":
290883
- parts2.push("UI component");
290884
- break;
290885
- case "repository":
290886
- parts2.push("Data access layer");
290887
- break;
290888
- case "middleware":
290889
- parts2.push("Request middleware");
290890
- break;
290891
- case "test":
290892
- parts2.push("Test file");
290893
- break;
290894
- case "config":
290895
- parts2.push("Configuration");
290896
- break;
290897
- case "type":
290898
- parts2.push("Type definitions");
290899
- break;
290900
- case "util":
290901
- parts2.push("Utility module");
290902
- break;
290903
- case "entry":
290904
- parts2.push("Entry point");
290905
- break;
290906
- default:
290907
- parts2.push("Source file");
290908
- }
290909
- if (ctx.fileContext) {
290910
- if (ctx.fileContext.layer) parts2.push(`in ${ctx.fileContext.layer} layer`);
290911
- if (ctx.fileContext.dependedOnBy.length > 10) parts2.push("(high-impact)");
290912
- }
290913
- return parts2.join(" ");
290914
- }
290915
- explainArchScore(score, dna) {
290916
- if (score >= 80) return `Strong architecture with ${dna.patterns.length} recognized patterns`;
290917
- if (score >= 50) return `Moderate architecture \u2014 ${dna.patterns.length} patterns detected, room to strengthen boundaries`;
290918
- return "Architecture needs attention \u2014 few recognized patterns or boundaries";
290919
- }
290920
- explainTestScore(score) {
290921
- if (score >= 80) return "Good test coverage across source files";
290922
- if (score >= 50) return "Moderate coverage \u2014 some source files lack tests";
290923
- return "Low test coverage \u2014 many exported modules have no test files";
290924
- }
290925
- explainConventionScore(score, dna) {
290926
- const strong = dna.conventions.filter((c) => c.confidence > 0.6).length;
290927
- if (score >= 80) return `${strong} strong conventions enforced consistently`;
290928
- if (score >= 50) return `${strong} conventions detected but inconsistently applied`;
290929
- return "Few consistent conventions \u2014 codebase style varies across files";
290930
- }
290931
- explainDependencyScore(score, dna) {
290932
- const circular = dna.boundaries.filter((b) => b.isCircular).length;
290933
- if (score >= 80) return "Clean dependency graph with no circular dependencies";
290934
- if (circular > 0) return `${circular} circular dependency${circular > 1 ? "ies" : "y"} detected \u2014 these increase coupling and make code harder to reason about`;
290935
- return "Dependency health needs improvement";
290936
- }
290937
- renderBar(score) {
290938
- const filled = Math.round(score / 10);
290939
- return "\u2588".repeat(filled) + "\u2591".repeat(10 - filled);
290940
- }
290941
- };
290942
- function shortName(filePath) {
290943
- const parts2 = filePath.split("/");
290944
- return parts2[parts2.length - 1] ?? filePath;
290945
- }
290946
-
290947
290944
  // ../context-engine/dist/index.js
290948
290945
  import * as fs5 from "fs";
290949
290946
  import * as path6 from "path";
@@ -293677,13 +293674,7 @@ var InputValidator = class {
293677
293674
  errors.push("Null byte detected in path");
293678
293675
  logger.warn("Null byte injection attempt blocked", { input });
293679
293676
  }
293680
- const suspiciousPatterns = [
293681
- /\.\.\//,
293682
- /\.\.\\/,
293683
- /%2e%2e/i,
293684
- /%252e/i,
293685
- /\.\./
293686
- ];
293677
+ const suspiciousPatterns = [/\.\.\//, /\.\.\\/, /%2e%2e/i, /%252e/i, /\.\./];
293687
293678
  for (const pattern of suspiciousPatterns) {
293688
293679
  if (pattern.test(input)) {
293689
293680
  errors.push(`Suspicious pattern detected: ${pattern}`);
@@ -293732,12 +293723,7 @@ var InputValidator = class {
293732
293723
  break;
293733
293724
  }
293734
293725
  }
293735
- const scriptPatterns = [
293736
- /<script/i,
293737
- /javascript:/i,
293738
- /on\w+\s*=/i,
293739
- /<iframe/i
293740
- ];
293726
+ const scriptPatterns = [/<script/i, /javascript:/i, /on\w+\s*=/i, /<iframe/i];
293741
293727
  for (const pattern of scriptPatterns) {
293742
293728
  if (pattern.test(input)) {
293743
293729
  logger.warn("Potential script injection attempt blocked", { input });
@@ -293885,10 +293871,7 @@ var InputValidator = class {
293885
293871
  }
293886
293872
  }
293887
293873
  if (args2.outcome !== void 0) {
293888
- const outcomeResult = this.validateEnum(args2.outcome, [
293889
- "helpful",
293890
- "not_helpful"
293891
- ]);
293874
+ const outcomeResult = this.validateEnum(args2.outcome, ["helpful", "not_helpful"]);
293892
293875
  if (!outcomeResult.valid) {
293893
293876
  errors.push(...outcomeResult.errors.map((e) => `outcome: ${e}`));
293894
293877
  }
@@ -293910,7 +293893,9 @@ var InputValidator = class {
293910
293893
  }
293911
293894
  }
293912
293895
  if (args2.enginePreset !== void 0) {
293913
- const presetResult = this.validateEnum(args2.enginePreset, [...VIBECHECK_SCAN_ENGINE_PRESETS]);
293896
+ const presetResult = this.validateEnum(args2.enginePreset, [
293897
+ ...VIBECHECK_SCAN_ENGINE_PRESETS
293898
+ ]);
293914
293899
  if (!presetResult.valid) {
293915
293900
  errors.push(...presetResult.errors.map((e) => `enginePreset: ${e}`));
293916
293901
  }
@@ -293928,6 +293913,21 @@ var InputValidator = class {
293928
293913
  }
293929
293914
  }
293930
293915
  break;
293916
+ case "vibecheck_ghost": {
293917
+ if (args2.file !== void 0) {
293918
+ const fileResult = this.validatePath(args2.file);
293919
+ if (!fileResult.valid) {
293920
+ errors.push(...fileResult.errors.map((e) => `file: ${e}`));
293921
+ }
293922
+ }
293923
+ if (args2.path !== void 0) {
293924
+ const pathResult = this.validatePath(args2.path);
293925
+ if (!pathResult.valid) {
293926
+ errors.push(...pathResult.errors.map((e) => `path: ${e}`));
293927
+ }
293928
+ }
293929
+ break;
293930
+ }
293931
293931
  }
293932
293932
  if (errors.length > 0) {
293933
293933
  logger.warn("Tool argument validation failed", {
@@ -294001,7 +294001,10 @@ var MCP_TOOLS = [
294001
294001
  path: { type: "string", description: "Workspace root. Defaults to cwd." },
294002
294002
  query: { type: "string", description: "Natural language query." },
294003
294003
  limit: { type: "number", description: "Max results. Default 10." },
294004
- useSemantic: { type: "boolean", description: "Use semantic search (embeddings) when available. Slower but finds conceptually related code." }
294004
+ useSemantic: {
294005
+ type: "boolean",
294006
+ description: "Use semantic search (embeddings) when available. Slower but finds conceptually related code."
294007
+ }
294005
294008
  },
294006
294009
  required: ["query"]
294007
294010
  }
@@ -294024,7 +294027,11 @@ var MCP_TOOLS = [
294024
294027
  properties: {
294025
294028
  path: { type: "string", description: "Workspace root. Defaults to cwd." },
294026
294029
  file: { type: "string", description: "File path that was (or was not) helpful." },
294027
- outcome: { type: "string", enum: ["helpful", "not_helpful"], description: "User feedback." }
294030
+ outcome: {
294031
+ type: "string",
294032
+ enum: ["helpful", "not_helpful"],
294033
+ description: "User feedback."
294034
+ }
294028
294035
  },
294029
294036
  required: ["file", "outcome"]
294030
294037
  }
@@ -294098,7 +294105,11 @@ var MCP_TOOLS = [
294098
294105
  type: "object",
294099
294106
  properties: {
294100
294107
  path: { type: "string", description: "Destination path." },
294101
- type: { type: "string", enum: ["component", "api", "hook", "test"], description: "Type of code to forge." },
294108
+ type: {
294109
+ type: "string",
294110
+ enum: ["component", "api", "hook", "test"],
294111
+ description: "Type of code to forge."
294112
+ },
294102
294113
  name: { type: "string", description: "Name of the component/api/hook." }
294103
294114
  },
294104
294115
  required: ["type", "name"]
@@ -294110,7 +294121,10 @@ var MCP_TOOLS = [
294110
294121
  inputSchema: {
294111
294122
  type: "object",
294112
294123
  properties: {
294113
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." },
294124
+ path: {
294125
+ type: "string",
294126
+ description: "Workspace or project root path. Defaults to current directory."
294127
+ },
294114
294128
  targetUrl: { type: "string", description: "Base URL to test." }
294115
294129
  }
294116
294130
  }
@@ -294121,7 +294135,10 @@ var MCP_TOOLS = [
294121
294135
  inputSchema: {
294122
294136
  type: "object",
294123
294137
  properties: {
294124
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294138
+ path: {
294139
+ type: "string",
294140
+ description: "Workspace or project root path. Defaults to current directory."
294141
+ }
294125
294142
  }
294126
294143
  }
294127
294144
  },
@@ -294131,8 +294148,15 @@ var MCP_TOOLS = [
294131
294148
  inputSchema: {
294132
294149
  type: "object",
294133
294150
  properties: {
294134
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." },
294135
- mode: { type: "string", enum: ["enforce", "observe", "off"], description: "Firewall mode to set." }
294151
+ path: {
294152
+ type: "string",
294153
+ description: "Workspace or project root path. Defaults to current directory."
294154
+ },
294155
+ mode: {
294156
+ type: "string",
294157
+ enum: ["enforce", "observe", "off"],
294158
+ description: "Firewall mode to set."
294159
+ }
294136
294160
  },
294137
294161
  required: ["mode"]
294138
294162
  }
@@ -294149,13 +294173,30 @@ var MCP_TOOLS = [
294149
294173
  required: ["action"]
294150
294174
  }
294151
294175
  },
294176
+ {
294177
+ name: "vibecheck_ghost",
294178
+ description: "Ghost Mode \u2014 symbolic execution trace showing how AI-generated code will break at runtime without running it. Returns a line-by-line trace with verdicts.",
294179
+ inputSchema: {
294180
+ type: "object",
294181
+ properties: {
294182
+ file: {
294183
+ type: "string",
294184
+ description: "File path to trace (relative to workspace or absolute)."
294185
+ }
294186
+ },
294187
+ required: ["file"]
294188
+ }
294189
+ },
294152
294190
  {
294153
294191
  name: "vibecheck_docguard",
294154
294192
  description: "Documentation quality analysis (orphaned, stale, or duplicate docs).",
294155
294193
  inputSchema: {
294156
294194
  type: "object",
294157
294195
  properties: {
294158
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294196
+ path: {
294197
+ type: "string",
294198
+ description: "Workspace or project root path. Defaults to current directory."
294199
+ }
294159
294200
  }
294160
294201
  }
294161
294202
  },
@@ -294165,7 +294206,10 @@ var MCP_TOOLS = [
294165
294206
  inputSchema: {
294166
294207
  type: "object",
294167
294208
  properties: {
294168
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294209
+ path: {
294210
+ type: "string",
294211
+ description: "Workspace or project root path. Defaults to current directory."
294212
+ }
294169
294213
  }
294170
294214
  }
294171
294215
  },
@@ -294175,7 +294219,10 @@ var MCP_TOOLS = [
294175
294219
  inputSchema: {
294176
294220
  type: "object",
294177
294221
  properties: {
294178
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294222
+ path: {
294223
+ type: "string",
294224
+ description: "Workspace or project root path. Defaults to current directory."
294225
+ }
294179
294226
  }
294180
294227
  }
294181
294228
  },
@@ -294185,7 +294232,10 @@ var MCP_TOOLS = [
294185
294232
  inputSchema: {
294186
294233
  type: "object",
294187
294234
  properties: {
294188
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." },
294235
+ path: {
294236
+ type: "string",
294237
+ description: "Workspace or project root path. Defaults to current directory."
294238
+ },
294189
294239
  out: { type: "string", description: "Output path for the truthpack." }
294190
294240
  }
294191
294241
  }
@@ -294196,7 +294246,10 @@ var MCP_TOOLS = [
294196
294246
  inputSchema: {
294197
294247
  type: "object",
294198
294248
  properties: {
294199
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." },
294249
+ path: {
294250
+ type: "string",
294251
+ description: "Workspace or project root path. Defaults to current directory."
294252
+ },
294200
294253
  branch: { type: "string", description: "Branch to compare against." }
294201
294254
  }
294202
294255
  }
@@ -294207,7 +294260,10 @@ var MCP_TOOLS = [
294207
294260
  inputSchema: {
294208
294261
  type: "object",
294209
294262
  properties: {
294210
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294263
+ path: {
294264
+ type: "string",
294265
+ description: "Workspace or project root path. Defaults to current directory."
294266
+ }
294211
294267
  }
294212
294268
  }
294213
294269
  },
@@ -294218,7 +294274,10 @@ var MCP_TOOLS = [
294218
294274
  type: "object",
294219
294275
  properties: {
294220
294276
  intent: { type: "string", description: "Description of the feature to build." },
294221
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294277
+ path: {
294278
+ type: "string",
294279
+ description: "Workspace or project root path. Defaults to current directory."
294280
+ }
294222
294281
  },
294223
294282
  required: ["intent"]
294224
294283
  }
@@ -294229,7 +294288,10 @@ var MCP_TOOLS = [
294229
294288
  inputSchema: {
294230
294289
  type: "object",
294231
294290
  properties: {
294232
- path: { type: "string", description: "Workspace or project root path. Defaults to current directory." }
294291
+ path: {
294292
+ type: "string",
294293
+ description: "Workspace or project root path. Defaults to current directory."
294294
+ }
294233
294295
  }
294234
294296
  }
294235
294297
  },
@@ -294263,9 +294325,19 @@ var MCP_TOOLS = [
294263
294325
  type: "object",
294264
294326
  properties: {
294265
294327
  path: { type: "string", description: "Project path. Defaults to current directory." },
294266
- severity: { type: "string", enum: ["critical", "high", "medium", "low", "info"], description: "Filter by severity." },
294267
- engine: { type: "string", description: 'Filter by engine ID (e.g. "phantom_dep", "ghost_route").' },
294268
- file: { type: "string", description: "Filter findings to a specific file or directory path." }
294328
+ severity: {
294329
+ type: "string",
294330
+ enum: ["critical", "high", "medium", "low", "info"],
294331
+ description: "Filter by severity."
294332
+ },
294333
+ engine: {
294334
+ type: "string",
294335
+ description: 'Filter by engine ID (e.g. "phantom_dep", "ghost_route").'
294336
+ },
294337
+ file: {
294338
+ type: "string",
294339
+ description: "Filter findings to a specific file or directory path."
294340
+ }
294269
294341
  }
294270
294342
  }
294271
294343
  },
@@ -294319,7 +294391,10 @@ var MCP_TOOLS = [
294319
294391
  inputSchema: {
294320
294392
  type: "object",
294321
294393
  properties: {
294322
- path: { type: "string", description: "Workspace root path. Defaults to current directory." }
294394
+ path: {
294395
+ type: "string",
294396
+ description: "Workspace root path. Defaults to current directory."
294397
+ }
294323
294398
  }
294324
294399
  }
294325
294400
  }
@@ -294470,7 +294545,7 @@ function createScanIdempotencyKey(prefix) {
294470
294545
  // src/mcp-scan-meter-client.ts
294471
294546
  var MCP_SCAN_METER_CLIENT = {
294472
294547
  type: "mcp",
294473
- version: "24.5.9"
294548
+ version: "24.6.3"
294474
294549
  };
294475
294550
 
294476
294551
  // src/server.ts
@@ -294626,10 +294701,7 @@ async function runGuard(targetPath) {
294626
294701
  var MCP_TOOL_TIMEOUT_MS = 18e4;
294627
294702
  function withTimeout(promise, ms, label) {
294628
294703
  return new Promise((resolve6, reject) => {
294629
- const timer = setTimeout(
294630
- () => reject(new Error(`${label} timed out after ${ms / 1e3}s`)),
294631
- ms
294632
- );
294704
+ const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms / 1e3}s`)), ms);
294633
294705
  promise.then(
294634
294706
  (value) => {
294635
294707
  clearTimeout(timer);
@@ -294758,10 +294830,8 @@ async function handleCallToolRequest(request, runtimeOverrides = {}) {
294758
294830
  }
294759
294831
  const validation = InputValidator.validateToolArgs(name2, args2);
294760
294832
  if (!validation.valid) {
294761
- return buildErrorResponse(
294762
- `Invalid arguments for ${name2}:
294763
- ${validation.errors.join("\n")}`
294764
- );
294833
+ return buildErrorResponse(`Invalid arguments for ${name2}:
294834
+ ${validation.errors.join("\n")}`);
294765
294835
  }
294766
294836
  const BILLABLE_ENGINE_TOOLS = /* @__PURE__ */ new Set(["vibecheck_scan", "vibecheck_score"]);
294767
294837
  if (BILLABLE_ENGINE_TOOLS.has(name2)) {
@@ -294804,9 +294874,14 @@ ${validation.errors.join("\n")}`
294804
294874
  const recordMcpBillableUsage = async (toolKey) => {
294805
294875
  const tok = process.env.VIBECHECK_TOKEN?.trim();
294806
294876
  if (!tok || shouldSkipServerScanMetering()) return { ok: true };
294807
- const r = await postServerScanRecord(tok, MCP_SCAN_METER_CLIENT, createScanIdempotencyKey(toolKey), {
294808
- scanType: toolKey.replace(/^mcp-/, "")
294809
- });
294877
+ const r = await postServerScanRecord(
294878
+ tok,
294879
+ MCP_SCAN_METER_CLIENT,
294880
+ createScanIdempotencyKey(toolKey),
294881
+ {
294882
+ scanType: toolKey.replace(/^mcp-/, "")
294883
+ }
294884
+ );
294810
294885
  if (!r.ok) {
294811
294886
  return { ok: false, message: r.error };
294812
294887
  }
@@ -294828,9 +294903,18 @@ ${validation.errors.join("\n")}`
294828
294903
  await engine.initialize(data);
294829
294904
  return engine.getProactiveContext({ focusedFile });
294830
294905
  };
294831
- const context = await withTimeout(run2(), MCP_TOOL_TIMEOUT_MS, "vibecheck_context_proactive");
294906
+ const context = await withTimeout(
294907
+ run2(),
294908
+ MCP_TOOL_TIMEOUT_MS,
294909
+ "vibecheck_context_proactive"
294910
+ );
294832
294911
  return {
294833
- content: [{ type: "text", text: typeof context === "string" ? context : JSON.stringify(context, null, 2) }]
294912
+ content: [
294913
+ {
294914
+ type: "text",
294915
+ text: typeof context === "string" ? context : JSON.stringify(context, null, 2)
294916
+ }
294917
+ ]
294834
294918
  };
294835
294919
  }
294836
294920
  case "vibecheck_context_intent": {
@@ -294877,12 +294961,16 @@ ${validation.errors.join("\n")}`
294877
294961
  const file = args2?.file;
294878
294962
  const outcome = args2?.outcome;
294879
294963
  if (!file || !outcome) {
294880
- return buildErrorResponse('vibecheck_context_feedback requires "file" and "outcome" (helpful|not_helpful)');
294964
+ return buildErrorResponse(
294965
+ 'vibecheck_context_feedback requires "file" and "outcome" (helpful|not_helpful)'
294966
+ );
294881
294967
  }
294882
294968
  const feedbackFile = normalizeRelativeWorkspaceFilePath(file, "file");
294883
294969
  await runtime.recordFeedback(targetPath, feedbackFile, outcome);
294884
294970
  return {
294885
- content: [{ type: "text", text: JSON.stringify({ ok: true, file: feedbackFile, outcome }) }]
294971
+ content: [
294972
+ { type: "text", text: JSON.stringify({ ok: true, file: feedbackFile, outcome }) }
294973
+ ]
294886
294974
  };
294887
294975
  }
294888
294976
  case "vibecheck_roast": {
@@ -295002,6 +295090,31 @@ ${validation.errors.join("\n")}`
295002
295090
  ]
295003
295091
  };
295004
295092
  }
295093
+ case "vibecheck_ghost": {
295094
+ const fileArg = args2.file;
295095
+ if (!fileArg || typeof fileArg !== "string") {
295096
+ return buildErrorResponse('vibecheck_ghost requires "file"');
295097
+ }
295098
+ let relFile;
295099
+ try {
295100
+ relFile = normalizeRelativeWorkspaceFilePath(fileArg, "file");
295101
+ } catch (e) {
295102
+ return buildErrorResponse(e instanceof Error ? e.message : "Invalid file path");
295103
+ }
295104
+ const absFile = path9.join(targetPath, relFile);
295105
+ if (!fs6.existsSync(absFile) || !fs6.statSync(absFile).isFile()) {
295106
+ return buildErrorResponse(`Not a file: ${relFile}`);
295107
+ }
295108
+ const { runGhostTrace } = await import("@vibecheck/engines");
295109
+ const trace = await withTimeout(
295110
+ runGhostTrace({ workspaceRoot: targetPath, filePath: absFile }),
295111
+ MCP_TOOL_TIMEOUT_MS,
295112
+ "vibecheck_ghost"
295113
+ );
295114
+ return {
295115
+ content: [{ type: "text", text: JSON.stringify(trace, null, 2) }]
295116
+ };
295117
+ }
295005
295118
  // ── Platform Unification Tool Handlers ──────────────────────────────
295006
295119
  case "vibecheck_trust_score": {
295007
295120
  const result = await withTimeout(
@@ -295040,10 +295153,7 @@ ${validation.errors.join("\n")}`
295040
295153
  const fileFilter = args2.file;
295041
295154
  filtered = filtered.filter((f) => f.file?.includes(fileFilter));
295042
295155
  }
295043
- const lines = [
295044
- `## Findings (${filtered.length} of ${gatedReport.summary.total})`,
295045
- ""
295046
- ];
295156
+ const lines = [`## Findings (${filtered.length} of ${gatedReport.summary.total})`, ""];
295047
295157
  for (const f of filtered.slice(0, 50)) {
295048
295158
  const loc = f.file ? `${f.file}${f.line ? `:${f.line}` : ""}` : "unknown";
295049
295159
  lines.push(`- **[${f.severity.toUpperCase()}]** ${f.message}`);
@@ -295095,16 +295205,22 @@ ${validation.errors.join("\n")}`
295095
295205
  const token = process.env.VIBECHECK_TOKEN?.trim();
295096
295206
  if (!token) {
295097
295207
  return {
295098
- content: [{
295099
- type: "text",
295100
- text: JSON.stringify({
295101
- ok: false,
295102
- message: "Authentication required to dismiss findings across surfaces. Set VIBECHECK_TOKEN or run `vibecheck auth login`.",
295103
- localOnly: true,
295104
- findingId,
295105
- reason
295106
- }, null, 2)
295107
- }]
295208
+ content: [
295209
+ {
295210
+ type: "text",
295211
+ text: JSON.stringify(
295212
+ {
295213
+ ok: false,
295214
+ message: "Authentication required to dismiss findings across surfaces. Set VIBECHECK_TOKEN or run `vibecheck auth login`.",
295215
+ localOnly: true,
295216
+ findingId,
295217
+ reason
295218
+ },
295219
+ null,
295220
+ 2
295221
+ )
295222
+ }
295223
+ ]
295108
295224
  };
295109
295225
  }
295110
295226
  try {
@@ -295112,7 +295228,7 @@ ${validation.errors.join("\n")}`
295112
295228
  const resp = await fetch(`${apiBase}/api/v1/findings/${findingId}`, {
295113
295229
  method: "PATCH",
295114
295230
  headers: {
295115
- "Authorization": `Bearer ${token}`,
295231
+ Authorization: `Bearer ${token}`,
295116
295232
  "Content-Type": "application/json"
295117
295233
  },
295118
295234
  body: JSON.stringify({ resolved: true })
@@ -295121,31 +295237,37 @@ ${validation.errors.join("\n")}`
295121
295237
  return buildErrorResponse(`Failed to dismiss finding: HTTP ${resp.status}`);
295122
295238
  }
295123
295239
  return {
295124
- content: [{
295125
- type: "text",
295126
- text: `Finding \`${findingId}\` dismissed. Reason: ${reason}
295240
+ content: [
295241
+ {
295242
+ type: "text",
295243
+ text: `Finding \`${findingId}\` dismissed. Reason: ${reason}
295127
295244
  This change is synced across all surfaces.`
295128
- }]
295245
+ }
295246
+ ]
295129
295247
  };
295130
295248
  } catch (err2) {
295131
- return buildErrorResponse(`Failed to dismiss finding: ${err2 instanceof Error ? err2.message : String(err2)}`);
295249
+ return buildErrorResponse(
295250
+ `Failed to dismiss finding: ${err2 instanceof Error ? err2.message : String(err2)}`
295251
+ );
295132
295252
  }
295133
295253
  }
295134
295254
  case "vibecheck_history": {
295135
295255
  const token = process.env.VIBECHECK_TOKEN?.trim();
295136
295256
  if (!token) {
295137
295257
  return {
295138
- content: [{
295139
- type: "text",
295140
- text: "Scan history requires authentication. Set VIBECHECK_TOKEN or run `vibecheck auth login`."
295141
- }]
295258
+ content: [
295259
+ {
295260
+ type: "text",
295261
+ text: "Scan history requires authentication. Set VIBECHECK_TOKEN or run `vibecheck auth login`."
295262
+ }
295263
+ ]
295142
295264
  };
295143
295265
  }
295144
295266
  try {
295145
295267
  const apiBase = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
295146
295268
  const limit = args2.limit ?? 10;
295147
295269
  const resp = await fetch(`${apiBase}/api/v1/scans/recent?limit=${limit}`, {
295148
- headers: { "Authorization": `Bearer ${token}` }
295270
+ headers: { Authorization: `Bearer ${token}` }
295149
295271
  });
295150
295272
  if (!resp.ok) {
295151
295273
  return buildErrorResponse(`Failed to fetch scan history: HTTP ${resp.status}`);
@@ -295153,7 +295275,14 @@ This change is synced across all surfaces.`
295153
295275
  const body2 = await resp.json();
295154
295276
  const scans = body2.data ?? [];
295155
295277
  if (scans.length === 0) {
295156
- return { content: [{ type: "text", text: "No scan history found. Run `vibecheck scan .` to create your first scan." }] };
295278
+ return {
295279
+ content: [
295280
+ {
295281
+ type: "text",
295282
+ text: "No scan history found. Run `vibecheck scan .` to create your first scan."
295283
+ }
295284
+ ]
295285
+ };
295157
295286
  }
295158
295287
  const lines = [`## Scan History (${scans.length} most recent)`, ""];
295159
295288
  for (const s of scans) {
@@ -295164,7 +295293,9 @@ This change is synced across all surfaces.`
295164
295293
  }
295165
295294
  return { content: [{ type: "text", text: lines.join("\n") }] };
295166
295295
  } catch (err2) {
295167
- return buildErrorResponse(`Failed to fetch history: ${err2 instanceof Error ? err2.message : String(err2)}`);
295296
+ return buildErrorResponse(
295297
+ `Failed to fetch history: ${err2 instanceof Error ? err2.message : String(err2)}`
295298
+ );
295168
295299
  }
295169
295300
  }
295170
295301
  case "vibecheck_engines": {
@@ -295247,7 +295378,9 @@ This change is synced across all surfaces.`
295247
295378
  };
295248
295379
  } catch (error) {
295249
295380
  const err2 = error;
295250
- return buildErrorResponse(`CLI Execution Error: ${err2.message ?? err2.stdout ?? err2.stderr ?? String(error)}`);
295381
+ return buildErrorResponse(
295382
+ `CLI Execution Error: ${err2.message ?? err2.stdout ?? err2.stderr ?? String(error)}`
295383
+ );
295251
295384
  }
295252
295385
  }
295253
295386
  default:
@@ -295263,7 +295396,7 @@ function createMcpServer(runtimeOverrides = {}) {
295263
295396
  const server2 = new Server(
295264
295397
  {
295265
295398
  name: "vibecheck-mcp",
295266
- version: "24.5.9"
295399
+ version: "24.6.3"
295267
295400
  },
295268
295401
  {
295269
295402
  capabilities: {