@a-company/paradigm 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/mcp.js +286 -43
  2. package/package.json +1 -1
package/dist/mcp.js CHANGED
@@ -15940,6 +15940,7 @@ var import_sql2 = __toESM(require_sql_wasm(), 1);
15940
15940
  import * as fs24 from "fs";
15941
15941
  import * as path27 from "path";
15942
15942
  import * as crypto5 from "crypto";
15943
+ import { execSync as execSync2 } from "child_process";
15943
15944
  var cachedSQL = null;
15944
15945
  async function getSqlJs() {
15945
15946
  if (!cachedSQL) {
@@ -15967,6 +15968,8 @@ var SCHEMA_STATEMENTS = [
15967
15968
  start_line INTEGER NOT NULL,
15968
15969
  end_line INTEGER NOT NULL,
15969
15970
  content_hash TEXT,
15971
+ normalized_hash TEXT,
15972
+ materialized_at_commit TEXT,
15970
15973
  last_verified TEXT,
15971
15974
  drifted INTEGER DEFAULT 0
15972
15975
  )`,
@@ -16072,9 +16075,14 @@ function closeAspectGraph(db, rootDir) {
16072
16075
  }
16073
16076
  db.close();
16074
16077
  }
16075
- function materializeAspects(db, symbols) {
16078
+ function materializeAspects(db, symbols, rootDir) {
16076
16079
  const aspects = symbols.filter((s) => s.type === "aspect");
16077
16080
  const now = (/* @__PURE__ */ new Date()).toISOString();
16081
+ let headCommit = null;
16082
+ try {
16083
+ headCommit = execSync2("git rev-parse HEAD", { cwd: rootDir, encoding: "utf8" }).trim();
16084
+ } catch {
16085
+ }
16078
16086
  db.run("DELETE FROM anchors");
16079
16087
  db.run("DELETE FROM edges");
16080
16088
  db.run("DELETE FROM aspects");
@@ -16108,11 +16116,11 @@ function materializeAspects(db, symbols) {
16108
16116
  if (entry.anchors) {
16109
16117
  for (const anchor of entry.anchors) {
16110
16118
  const { startLine, endLine } = resolveAnchorLines(anchor);
16111
- const contentHash = computeAnchorHash(anchor, null);
16119
+ const hashes = computeAnchorHash(anchor, null);
16112
16120
  db.run(
16113
- `INSERT INTO anchors (aspect_id, file_path, start_line, end_line, content_hash, last_verified)
16114
- VALUES (?, ?, ?, ?, ?, ?)`,
16115
- [entry.symbol, anchor.path, startLine, endLine, contentHash, now]
16121
+ `INSERT INTO anchors (aspect_id, file_path, start_line, end_line, content_hash, normalized_hash, materialized_at_commit, last_verified)
16122
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
16123
+ [entry.symbol, anchor.path, startLine, endLine, hashes.exact, hashes.normalized, headCommit, now]
16116
16124
  );
16117
16125
  }
16118
16126
  }
@@ -16195,7 +16203,7 @@ function getHeatmap(db, limit = 20, accessType) {
16195
16203
  [limit]
16196
16204
  );
16197
16205
  }
16198
- function checkDrift(db, rootDir, aspectId) {
16206
+ function checkDrift(db, rootDir, aspectId, autoHeal = true) {
16199
16207
  const anchorRows = aspectId ? queryRows(db, "SELECT * FROM anchors WHERE aspect_id = ?", [aspectId]) : queryRows(db, "SELECT * FROM anchors");
16200
16208
  const results = [];
16201
16209
  for (const anchor of anchorRows) {
@@ -16206,8 +16214,10 @@ function checkDrift(db, rootDir, aspectId) {
16206
16214
  path: anchor.file_path,
16207
16215
  startLine: anchor.start_line,
16208
16216
  endLine: anchor.end_line,
16209
- drifted: true,
16210
- exists: false
16217
+ status: "missing",
16218
+ resolvedBy: "none",
16219
+ exists: false,
16220
+ drifted: true
16211
16221
  });
16212
16222
  continue;
16213
16223
  }
@@ -16217,30 +16227,174 @@ function checkDrift(db, rootDir, aspectId) {
16217
16227
  const startIdx = Math.max(0, anchor.start_line - 1);
16218
16228
  const endIdx = Math.min(lines.length, anchor.end_line);
16219
16229
  const sliceContent = lines.slice(startIdx, endIdx).join("\n");
16220
- const currentHash = crypto5.createHash("sha256").update(sliceContent).digest("hex");
16221
- const drifted = anchor.content_hash != null && currentHash !== anchor.content_hash;
16230
+ const currentExactHash = crypto5.createHash("sha256").update(sliceContent).digest("hex");
16231
+ if (anchor.content_hash != null && currentExactHash === anchor.content_hash) {
16232
+ results.push({
16233
+ aspectId: anchor.aspect_id,
16234
+ path: anchor.file_path,
16235
+ startLine: anchor.start_line,
16236
+ endLine: anchor.end_line,
16237
+ status: "clean",
16238
+ resolvedBy: "exact-hash",
16239
+ exists: true,
16240
+ drifted: false
16241
+ });
16242
+ if (anchor.drifted === 1) {
16243
+ db.run("UPDATE anchors SET drifted = 0 WHERE id = ?", [anchor.id]);
16244
+ }
16245
+ continue;
16246
+ }
16247
+ const currentNormalizedHash = crypto5.createHash("sha256").update(normalizeForHash(sliceContent)).digest("hex");
16248
+ if (anchor.normalized_hash != null && currentNormalizedHash === anchor.normalized_hash) {
16249
+ db.run("UPDATE anchors SET content_hash = ?, drifted = 0 WHERE id = ?", [currentExactHash, anchor.id]);
16250
+ results.push({
16251
+ aspectId: anchor.aspect_id,
16252
+ path: anchor.file_path,
16253
+ startLine: anchor.start_line,
16254
+ endLine: anchor.end_line,
16255
+ status: "cosmetic",
16256
+ resolvedBy: "normalized-hash",
16257
+ exists: true,
16258
+ drifted: false
16259
+ });
16260
+ continue;
16261
+ }
16262
+ if (anchor.content_hash == null && anchor.normalized_hash == null) {
16263
+ db.run(
16264
+ "UPDATE anchors SET content_hash = ?, normalized_hash = ?, drifted = 0 WHERE id = ?",
16265
+ [currentExactHash, currentNormalizedHash, anchor.id]
16266
+ );
16267
+ results.push({
16268
+ aspectId: anchor.aspect_id,
16269
+ path: anchor.file_path,
16270
+ startLine: anchor.start_line,
16271
+ endLine: anchor.end_line,
16272
+ status: "clean",
16273
+ resolvedBy: "exact-hash",
16274
+ exists: true,
16275
+ drifted: false
16276
+ });
16277
+ continue;
16278
+ }
16279
+ let resolvedByGit = false;
16280
+ if (anchor.materialized_at_commit) {
16281
+ const mapping = computeLineShift(
16282
+ rootDir,
16283
+ anchor.file_path,
16284
+ anchor.materialized_at_commit,
16285
+ anchor.start_line,
16286
+ anchor.end_line
16287
+ );
16288
+ if (mapping) {
16289
+ const shiftedStartIdx = Math.max(0, mapping.currentStart - 1);
16290
+ const shiftedEndIdx = Math.min(lines.length, mapping.currentEnd);
16291
+ const shiftedContent = lines.slice(shiftedStartIdx, shiftedEndIdx).join("\n");
16292
+ const shiftedExactHash = crypto5.createHash("sha256").update(shiftedContent).digest("hex");
16293
+ if (anchor.content_hash != null && shiftedExactHash === anchor.content_hash) {
16294
+ const healed = autoHeal;
16295
+ if (healed) {
16296
+ db.run(
16297
+ "UPDATE anchors SET start_line = ?, end_line = ?, drifted = 0 WHERE id = ?",
16298
+ [mapping.currentStart, mapping.currentEnd, anchor.id]
16299
+ );
16300
+ const aspectRow = queryRows(
16301
+ db,
16302
+ "SELECT defined_in FROM aspects WHERE id = ?",
16303
+ [anchor.aspect_id]
16304
+ );
16305
+ if (aspectRow.length > 0) {
16306
+ healAnchorInPurposeFile(
16307
+ rootDir,
16308
+ aspectRow[0].defined_in,
16309
+ anchor.file_path,
16310
+ anchor.start_line,
16311
+ anchor.end_line,
16312
+ mapping.currentStart,
16313
+ mapping.currentEnd
16314
+ );
16315
+ }
16316
+ }
16317
+ results.push({
16318
+ aspectId: anchor.aspect_id,
16319
+ path: anchor.file_path,
16320
+ startLine: healed ? mapping.currentStart : anchor.start_line,
16321
+ endLine: healed ? mapping.currentEnd : anchor.end_line,
16322
+ status: "shifted",
16323
+ resolvedBy: "git-line-mapping",
16324
+ exists: true,
16325
+ drifted: false,
16326
+ suggestedStart: mapping.currentStart,
16327
+ suggestedEnd: mapping.currentEnd,
16328
+ autoHealed: healed
16329
+ });
16330
+ resolvedByGit = true;
16331
+ } else {
16332
+ const shiftedNormalized = crypto5.createHash("sha256").update(normalizeForHash(shiftedContent)).digest("hex");
16333
+ if (anchor.normalized_hash != null && shiftedNormalized === anchor.normalized_hash) {
16334
+ if (autoHeal) {
16335
+ const shiftedNewHash = crypto5.createHash("sha256").update(shiftedContent).digest("hex");
16336
+ db.run(
16337
+ "UPDATE anchors SET start_line = ?, end_line = ?, content_hash = ?, drifted = 0 WHERE id = ?",
16338
+ [mapping.currentStart, mapping.currentEnd, shiftedNewHash, anchor.id]
16339
+ );
16340
+ const aspectRow = queryRows(
16341
+ db,
16342
+ "SELECT defined_in FROM aspects WHERE id = ?",
16343
+ [anchor.aspect_id]
16344
+ );
16345
+ if (aspectRow.length > 0) {
16346
+ healAnchorInPurposeFile(
16347
+ rootDir,
16348
+ aspectRow[0].defined_in,
16349
+ anchor.file_path,
16350
+ anchor.start_line,
16351
+ anchor.end_line,
16352
+ mapping.currentStart,
16353
+ mapping.currentEnd
16354
+ );
16355
+ }
16356
+ }
16357
+ results.push({
16358
+ aspectId: anchor.aspect_id,
16359
+ path: anchor.file_path,
16360
+ startLine: autoHeal ? mapping.currentStart : anchor.start_line,
16361
+ endLine: autoHeal ? mapping.currentEnd : anchor.end_line,
16362
+ status: "shifted",
16363
+ resolvedBy: "git-line-mapping",
16364
+ exists: true,
16365
+ drifted: false,
16366
+ suggestedStart: mapping.currentStart,
16367
+ suggestedEnd: mapping.currentEnd,
16368
+ autoHealed: autoHeal
16369
+ });
16370
+ resolvedByGit = true;
16371
+ }
16372
+ }
16373
+ }
16374
+ }
16375
+ if (resolvedByGit) continue;
16376
+ db.run("UPDATE anchors SET drifted = 1 WHERE id = ?", [anchor.id]);
16222
16377
  results.push({
16223
16378
  aspectId: anchor.aspect_id,
16224
16379
  path: anchor.file_path,
16225
16380
  startLine: anchor.start_line,
16226
16381
  endLine: anchor.end_line,
16227
- drifted,
16382
+ status: "modified",
16383
+ resolvedBy: "none",
16228
16384
  exists: true,
16229
- currentContent: drifted ? sliceContent : void 0
16385
+ currentContent: sliceContent,
16386
+ drifted: true
16230
16387
  });
16231
- if (drifted) {
16232
- db.run("UPDATE anchors SET drifted = 1 WHERE id = ?", [anchor.id]);
16233
- } else if (anchor.drifted === 1) {
16234
- db.run("UPDATE anchors SET drifted = 0 WHERE id = ?", [anchor.id]);
16235
- }
16236
16388
  } catch {
16237
16389
  results.push({
16238
16390
  aspectId: anchor.aspect_id,
16239
16391
  path: anchor.file_path,
16240
16392
  startLine: anchor.start_line,
16241
16393
  endLine: anchor.end_line,
16242
- drifted: true,
16243
- exists: true
16394
+ status: "modified",
16395
+ resolvedBy: "none",
16396
+ exists: true,
16397
+ drifted: true
16244
16398
  });
16245
16399
  }
16246
16400
  }
@@ -16262,10 +16416,76 @@ function resolveAnchorLines(anchor) {
16262
16416
  }
16263
16417
  return { startLine: 1, endLine: 1 };
16264
16418
  }
16419
+ function parseUnifiedDiffHunks(diffOutput) {
16420
+ const hunks = [];
16421
+ const hunkPattern = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/gm;
16422
+ let match;
16423
+ while ((match = hunkPattern.exec(diffOutput)) !== null) {
16424
+ hunks.push({
16425
+ oldStart: parseInt(match[1], 10),
16426
+ oldCount: match[2] !== void 0 ? parseInt(match[2], 10) : 1,
16427
+ newStart: parseInt(match[3], 10),
16428
+ newCount: match[4] !== void 0 ? parseInt(match[4], 10) : 1
16429
+ });
16430
+ }
16431
+ return hunks;
16432
+ }
16433
+ function computeLineShift(rootDir, filePath, fromCommit, originalStart, originalEnd) {
16434
+ let diff;
16435
+ try {
16436
+ diff = execSync2(
16437
+ `git diff ${fromCommit}..HEAD --unified=0 -- "${filePath}"`,
16438
+ { cwd: rootDir, encoding: "utf8", timeout: 5e3 }
16439
+ );
16440
+ } catch {
16441
+ return null;
16442
+ }
16443
+ if (!diff.trim()) {
16444
+ return { originalStart, originalEnd, currentStart: originalStart, currentEnd: originalEnd };
16445
+ }
16446
+ const hunks = parseUnifiedDiffHunks(diff);
16447
+ let offset = 0;
16448
+ for (const hunk of hunks) {
16449
+ const hunkOldEnd = hunk.oldStart + hunk.oldCount;
16450
+ if (hunkOldEnd <= originalStart) {
16451
+ offset += hunk.newCount - hunk.oldCount;
16452
+ continue;
16453
+ }
16454
+ if (hunk.oldStart < originalEnd) {
16455
+ return null;
16456
+ }
16457
+ break;
16458
+ }
16459
+ if (offset === 0) return null;
16460
+ return {
16461
+ originalStart,
16462
+ originalEnd,
16463
+ currentStart: originalStart + offset,
16464
+ currentEnd: originalEnd + offset
16465
+ };
16466
+ }
16467
+ function healAnchorInPurposeFile(rootDir, purposeFilePath, anchorFilePath, oldStart, oldEnd, newStart, newEnd) {
16468
+ const absolutePurpose = path27.isAbsolute(purposeFilePath) ? purposeFilePath : path27.join(rootDir, purposeFilePath);
16469
+ if (!fs24.existsSync(absolutePurpose)) return false;
16470
+ try {
16471
+ const content = fs24.readFileSync(absolutePurpose, "utf8");
16472
+ const oldAnchor = oldStart === oldEnd ? `${anchorFilePath}:${oldStart}` : `${anchorFilePath}:${oldStart}-${oldEnd}`;
16473
+ const newAnchor = newStart === newEnd ? `${anchorFilePath}:${newStart}` : `${anchorFilePath}:${newStart}-${newEnd}`;
16474
+ if (!content.includes(oldAnchor)) return false;
16475
+ const updated = content.replace(oldAnchor, newAnchor);
16476
+ fs24.writeFileSync(absolutePurpose, updated, "utf8");
16477
+ return true;
16478
+ } catch {
16479
+ return false;
16480
+ }
16481
+ }
16482
+ function normalizeForHash(content) {
16483
+ return content.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim() !== "").map((line) => line.replace(/\s+/g, " ")).join("\n");
16484
+ }
16265
16485
  function computeAnchorHash(anchor, rootDir) {
16266
- if (!rootDir) return null;
16486
+ if (!rootDir) return { exact: null, normalized: null };
16267
16487
  const absolutePath = path27.isAbsolute(anchor.path) ? anchor.path : path27.join(rootDir, anchor.path);
16268
- if (!fs24.existsSync(absolutePath)) return null;
16488
+ if (!fs24.existsSync(absolutePath)) return { exact: null, normalized: null };
16269
16489
  try {
16270
16490
  const fileContent = fs24.readFileSync(absolutePath, "utf8");
16271
16491
  const lines = fileContent.split("\n");
@@ -16273,9 +16493,11 @@ function computeAnchorHash(anchor, rootDir) {
16273
16493
  const startIdx = Math.max(0, startLine - 1);
16274
16494
  const endIdx = Math.min(lines.length, endLine);
16275
16495
  const sliceContent = lines.slice(startIdx, endIdx).join("\n");
16276
- return crypto5.createHash("sha256").update(sliceContent).digest("hex");
16496
+ const exact = crypto5.createHash("sha256").update(sliceContent).digest("hex");
16497
+ const normalized = crypto5.createHash("sha256").update(normalizeForHash(sliceContent)).digest("hex");
16498
+ return { exact, normalized };
16277
16499
  } catch {
16278
- return null;
16500
+ return { exact: null, normalized: null };
16279
16501
  }
16280
16502
  }
16281
16503
  function inferCategory(data, entry) {
@@ -16878,7 +17100,7 @@ async function rebuildStaticFiles(rootDir, ctx) {
16878
17100
  let aspectGraphStats;
16879
17101
  try {
16880
17102
  const db = await openAspectGraph(rootDir);
16881
- materializeAspects(db, aggregation.symbols);
17103
+ materializeAspects(db, aggregation.symbols, rootDir);
16882
17104
  const loreLinks = await materializeLoreLinks(db, rootDir);
16883
17105
  const inferredEdges = await inferLoreEdges(db, rootDir);
16884
17106
  const aspectCount = db.exec("SELECT COUNT(*) FROM aspects")[0]?.values[0]?.[0] ?? 0;
@@ -17593,7 +17815,7 @@ function summarizeEntry(entry) {
17593
17815
  // ../paradigm-mcp/src/tools/habits.ts
17594
17816
  import * as fs27 from "fs";
17595
17817
  import * as path30 from "path";
17596
- import { execSync as execSync2 } from "child_process";
17818
+ import { execSync as execSync3 } from "child_process";
17597
17819
  function getHabitsToolsList() {
17598
17820
  return [
17599
17821
  {
@@ -17797,7 +18019,7 @@ async function handleHabitsCheck(args, ctx) {
17797
18019
  ].some((k) => taskLower.includes(k));
17798
18020
  let gitClean;
17799
18021
  try {
17800
- const status = execSync2("git status --porcelain", {
18022
+ const status = execSync3("git status --porcelain", {
17801
18023
  cwd: ctx.rootDir,
17802
18024
  encoding: "utf8",
17803
18025
  timeout: 5e3
@@ -18493,18 +18715,22 @@ function getAspectGraphToolsList() {
18493
18715
  },
18494
18716
  {
18495
18717
  name: "paradigm_aspect_drift",
18496
- description: "Check if code at aspect anchor locations has changed since last materialization. Detects broken or stale anchors. ~200 tokens.",
18718
+ description: "Smart drift detection for code anchors. Layer 1: normalized hash (ignores formatting). Layer 2: git-aware line mapping (detects shifts, auto-heals .purpose files). ~200 tokens.",
18497
18719
  inputSchema: {
18498
18720
  type: "object",
18499
18721
  properties: {
18500
18722
  aspectId: {
18501
18723
  type: "string",
18502
18724
  description: "Optional: check a specific aspect. If omitted, checks all aspects."
18725
+ },
18726
+ autoHeal: {
18727
+ type: "boolean",
18728
+ description: "Auto-update anchors for high-confidence shifts (default: true)"
18503
18729
  }
18504
18730
  }
18505
18731
  },
18506
18732
  annotations: {
18507
- readOnlyHint: true,
18733
+ readOnlyHint: false,
18508
18734
  destructiveHint: false
18509
18735
  }
18510
18736
  },
@@ -18894,34 +19120,51 @@ async function handleAspectSuggestScan(args, ctx) {
18894
19120
  }
18895
19121
  }
18896
19122
  async function handleAspectDrift(args, ctx) {
18897
- const { aspectId } = args;
19123
+ const { aspectId, autoHeal: autoHealArg } = args;
19124
+ const autoHeal = autoHealArg !== false;
18898
19125
  const normalizedId = aspectId ? aspectId.startsWith("~") ? aspectId.slice(1) : aspectId : void 0;
18899
19126
  let db = null;
18900
19127
  try {
18901
19128
  db = await openAspectGraph(ctx.rootDir);
18902
- const results = checkDrift(db, ctx.rootDir, normalizedId);
18903
- const driftedCount = results.filter((r) => r.drifted).length;
18904
- const missingCount = results.filter((r) => !r.exists).length;
18905
- const healthyCount = results.filter((r) => !r.drifted && r.exists).length;
19129
+ const results = checkDrift(db, ctx.rootDir, normalizedId, autoHeal);
19130
+ const cleanCount = results.filter((r) => r.status === "clean").length;
19131
+ const cosmeticCount = results.filter((r) => r.status === "cosmetic").length;
19132
+ const shiftedCount = results.filter((r) => r.status === "shifted").length;
19133
+ const modifiedCount = results.filter((r) => r.status === "modified").length;
19134
+ const missingCount = results.filter((r) => r.status === "missing").length;
19135
+ const hasIssues = modifiedCount > 0 || missingCount > 0;
19136
+ const hasHeals = cosmeticCount > 0 || shiftedCount > 0;
19137
+ const overallStatus = hasIssues ? "drift-detected" : hasHeals ? "clean-with-heals" : "clean";
18906
19138
  const response = {
18907
19139
  ...normalizedId ? { aspectId: normalizedId } : { scope: "all" },
18908
19140
  totalAnchors: results.length,
18909
- healthy: healthyCount,
18910
- drifted: driftedCount,
19141
+ clean: cleanCount,
19142
+ cosmetic: cosmeticCount,
19143
+ shifted: shiftedCount,
19144
+ modified: modifiedCount,
18911
19145
  missing: missingCount,
18912
- status: driftedCount === 0 && missingCount === 0 ? "clean" : "drift-detected",
19146
+ status: overallStatus,
18913
19147
  results: results.map((r) => ({
18914
19148
  aspectId: r.aspectId,
18915
19149
  path: r.path,
18916
19150
  startLine: r.startLine,
18917
19151
  endLine: r.endLine,
18918
- drifted: r.drifted,
19152
+ status: r.status,
19153
+ resolvedBy: r.resolvedBy,
18919
19154
  exists: r.exists,
18920
- // Include current content only for drifted anchors (truncated)
18921
- ...r.drifted && r.currentContent ? { currentContent: r.currentContent.slice(0, 500) } : {}
19155
+ // Include shift details for shifted anchors
19156
+ ...r.status === "shifted" ? { suggestedStart: r.suggestedStart, suggestedEnd: r.suggestedEnd, autoHealed: r.autoHealed } : {},
19157
+ // Include current content only for modified anchors (truncated)
19158
+ ...r.status === "modified" && r.currentContent ? { currentContent: r.currentContent.slice(0, 500) } : {}
18922
19159
  })),
18923
- ...driftedCount > 0 || missingCount > 0 ? {
18924
- suggestion: "Run `paradigm scan` to re-materialize the aspect graph and update anchor hashes. Review drifted anchors to ensure aspects still apply."
19160
+ ...cosmeticCount > 0 || shiftedCount > 0 ? {
19161
+ healed: [
19162
+ cosmeticCount > 0 ? `${cosmeticCount} cosmetic (whitespace/formatting \u2014 hashes updated)` : "",
19163
+ shiftedCount > 0 ? `${shiftedCount} shifted (line numbers updated via git diff${autoHeal ? " \u2014 .purpose files patched" : ""})` : ""
19164
+ ].filter(Boolean).join(", ")
19165
+ } : {},
19166
+ ...hasIssues ? {
19167
+ suggestion: "Review drifted anchors to ensure aspects still apply. Run `paradigm scan` to re-materialize after fixing."
18925
19168
  } : {}
18926
19169
  };
18927
19170
  const text = JSON.stringify(response, null, 2);
@@ -19371,7 +19614,7 @@ async function handleAssessmentTool(name, args, ctx) {
19371
19614
 
19372
19615
  // ../paradigm-mcp/src/tools/fallback-grep.ts
19373
19616
  import * as path32 from "path";
19374
- import { execSync as execSync3 } from "child_process";
19617
+ import { execSync as execSync4 } from "child_process";
19375
19618
  function grepForReferences(rootDir, symbol, options = {}) {
19376
19619
  const { maxResults = 20 } = options;
19377
19620
  const results = [];
@@ -19385,7 +19628,7 @@ function grepForReferences(rootDir, symbol, options = {}) {
19385
19628
  let output = "";
19386
19629
  for (const cmd of grepCommands) {
19387
19630
  try {
19388
- output = execSync3(cmd, { encoding: "utf8", maxBuffer: 1024 * 1024 });
19631
+ output = execSync4(cmd, { encoding: "utf8", maxBuffer: 1024 * 1024 });
19389
19632
  if (output.trim()) break;
19390
19633
  } catch {
19391
19634
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a-company/paradigm",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "Unified CLI for Paradigm developer tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",