@unerr-ai/unerr 0.0.0-beta.8 → 0.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -750,7 +750,7 @@ async function getParser(language) {
750
750
  const langFile = `tree-sitter-${language}.wasm`;
751
751
  try {
752
752
  const { join: join68 } = await import("path");
753
- const { existsSync: existsSync63 } = await import("fs");
753
+ const { existsSync: existsSync64 } = await import("fs");
754
754
  const possiblePaths = [
755
755
  join68(
756
756
  process.cwd(),
@@ -762,7 +762,7 @@ async function getParser(language) {
762
762
  ];
763
763
  let wasmPath = null;
764
764
  for (const p of possiblePaths) {
765
- if (existsSync63(p)) {
765
+ if (existsSync64(p)) {
766
766
  wasmPath = p;
767
767
  break;
768
768
  }
@@ -7227,9 +7227,9 @@ function extractTSEntities(node, lines, entities) {
7227
7227
  const nameNode = child.childForFieldName("name");
7228
7228
  const valueNode = child.childForFieldName("value");
7229
7229
  if (!nameNode || !valueNode) continue;
7230
+ const startLine = n.startPosition.row + 1;
7231
+ const endLine = n.endPosition.row + 1;
7230
7232
  if (valueNode.type === "arrow_function" || valueNode.type === "function_expression" || valueNode.type === "function") {
7231
- const startLine = n.startPosition.row + 1;
7232
- const endLine = n.endPosition.row + 1;
7233
7233
  entities.push({
7234
7234
  name: nameNode.text,
7235
7235
  kind: "function",
@@ -7238,11 +7238,53 @@ function extractTSEntities(node, lines, entities) {
7238
7238
  line_end: endLine,
7239
7239
  content_hash: hashLines(lines, startLine, endLine)
7240
7240
  });
7241
+ } else if (valueNode.type === "object" || valueNode.type === "array" || valueNode.type === "as_expression" || valueNode.type === "satisfies_expression" || valueNode.type === "new_expression" || valueNode.type === "call_expression" || valueNode.type === "template_string" || valueNode.type === "string" || valueNode.type === "number" || valueNode.type === "true" || valueNode.type === "false" || valueNode.type === "regex") {
7242
+ const isTopLevel = !n.parent || n.parent.type === "program" || n.parent.type === "export_statement";
7243
+ if (isTopLevel) {
7244
+ entities.push({
7245
+ name: nameNode.text,
7246
+ kind: "variable",
7247
+ signature: "",
7248
+ line_start: startLine,
7249
+ line_end: endLine,
7250
+ content_hash: hashLines(lines, startLine, endLine)
7251
+ });
7252
+ }
7241
7253
  }
7242
7254
  }
7243
7255
  }
7244
7256
  break;
7245
7257
  }
7258
+ case "type_alias_declaration": {
7259
+ const name = n.childForFieldName("name");
7260
+ if (!name) return;
7261
+ const startLine = n.startPosition.row + 1;
7262
+ const endLine = n.endPosition.row + 1;
7263
+ entities.push({
7264
+ name: name.text,
7265
+ kind: "interface",
7266
+ signature: "",
7267
+ line_start: startLine,
7268
+ line_end: endLine,
7269
+ content_hash: hashLines(lines, startLine, endLine)
7270
+ });
7271
+ break;
7272
+ }
7273
+ case "enum_declaration": {
7274
+ const name = n.childForFieldName("name");
7275
+ if (!name) return;
7276
+ const startLine = n.startPosition.row + 1;
7277
+ const endLine = n.endPosition.row + 1;
7278
+ entities.push({
7279
+ name: name.text,
7280
+ kind: "class",
7281
+ signature: "",
7282
+ line_start: startLine,
7283
+ line_end: endLine,
7284
+ content_hash: hashLines(lines, startLine, endLine)
7285
+ });
7286
+ break;
7287
+ }
7246
7288
  }
7247
7289
  });
7248
7290
  }
@@ -9370,6 +9412,42 @@ var init_downloader = __esm({
9370
9412
  archiveType: "gz",
9371
9413
  archiveBinaryPath: null,
9372
9414
  manualInstall: "rustup component add rust-analyzer"
9415
+ },
9416
+ ruby: {
9417
+ language: "ruby",
9418
+ binaryName: "scip-ruby",
9419
+ repo: "sourcegraph/scip-ruby",
9420
+ tag: "latest",
9421
+ // Verified assets: scip-ruby-arm64-darwin, scip-ruby-x86_64-linux (raw binaries)
9422
+ // No darwin-x86_64 or linux-arm64 builds available
9423
+ resolveAssetName: (p) => {
9424
+ if (p.os === "windows") return null;
9425
+ if (p.os === "darwin" && p.nodeArch !== "arm64") return null;
9426
+ if (p.os === "linux" && p.nodeArch !== "x64") return null;
9427
+ const arch2 = p.os === "darwin" ? "arm64" : "x86_64";
9428
+ return `scip-ruby-${arch2}-${p.os}`;
9429
+ },
9430
+ archiveType: "raw",
9431
+ archiveBinaryPath: null,
9432
+ manualInstall: "Download from https://github.com/sourcegraph/scip-ruby/releases"
9433
+ },
9434
+ cpp: {
9435
+ language: "cpp",
9436
+ binaryName: "scip-clang",
9437
+ repo: "sourcegraph/scip-clang",
9438
+ tag: "latest",
9439
+ // Verified assets: scip-clang-arm64-darwin, scip-clang-x86_64-linux (raw binaries)
9440
+ // No darwin-x86_64 or linux-arm64 builds available
9441
+ resolveAssetName: (p) => {
9442
+ if (p.os === "windows") return null;
9443
+ if (p.os === "darwin" && p.nodeArch !== "arm64") return null;
9444
+ if (p.os === "linux" && p.nodeArch !== "x64") return null;
9445
+ const arch2 = p.os === "darwin" ? "arm64" : "x86_64";
9446
+ return `scip-clang-${arch2}-${p.os}`;
9447
+ },
9448
+ archiveType: "raw",
9449
+ archiveBinaryPath: null,
9450
+ manualInstall: "Download from https://github.com/sourcegraph/scip-clang/releases (requires compile_commands.json)"
9373
9451
  }
9374
9452
  };
9375
9453
  }
@@ -9483,7 +9561,10 @@ var init_detector = __esm({
9483
9561
  EXTERNAL_SCIP = {
9484
9562
  go: ["scip-go"],
9485
9563
  java: ["scip-java"],
9486
- rust: ["rust-analyzer"]
9564
+ rust: ["rust-analyzer"],
9565
+ ruby: ["scip-ruby"],
9566
+ cpp: ["scip-clang"],
9567
+ csharp: ["scip-dotnet"]
9487
9568
  };
9488
9569
  EXT_TO_SCIP_LANG = {
9489
9570
  // TypeScript / JavaScript (scip-typescript handles all)
@@ -9508,7 +9589,19 @@ var init_detector = __esm({
9508
9589
  ".scala": "java",
9509
9590
  ".sc": "java",
9510
9591
  // Rust
9511
- ".rs": "rust"
9592
+ ".rs": "rust",
9593
+ // Ruby
9594
+ ".rb": "ruby",
9595
+ // C / C++ (scip-clang handles both)
9596
+ ".c": "cpp",
9597
+ ".cpp": "cpp",
9598
+ ".cc": "cpp",
9599
+ ".cxx": "cpp",
9600
+ ".h": "cpp",
9601
+ ".hpp": "cpp",
9602
+ ".hxx": "cpp",
9603
+ // C#
9604
+ ".cs": "csharp"
9512
9605
  };
9513
9606
  }
9514
9607
  });
@@ -9615,6 +9708,9 @@ async function runScipIndexer(options) {
9615
9708
  }
9616
9709
  const outputPath = join22(outputDir, "index.scip");
9617
9710
  const args = buildScipArgs(language, binaryPath, projectRoot, outputPath);
9711
+ if (options.extraArgs?.length) {
9712
+ args.push(...options.extraArgs);
9713
+ }
9618
9714
  try {
9619
9715
  log4.info(`Running SCIP indexer: ${args[0]} for ${language}`);
9620
9716
  const result = await exec(args[0], args.slice(1), {
@@ -9623,6 +9719,12 @@ async function runScipIndexer(options) {
9623
9719
  });
9624
9720
  const durationMs = performance.now() - start;
9625
9721
  if (result.exitCode !== 0) {
9722
+ if (existsSync17(outputPath)) {
9723
+ log4.warn(
9724
+ `SCIP indexer exited with code ${result.exitCode} but output file was created \u2014 treating as success`
9725
+ );
9726
+ return { success: true, outputPath, durationMs, error: null };
9727
+ }
9626
9728
  log4.warn(
9627
9729
  `SCIP indexer failed (exit ${result.exitCode}): ${result.stderr.slice(0, 500)}`
9628
9730
  );
@@ -9669,6 +9771,12 @@ function buildScipArgs(language, binaryPath, projectRoot, outputPath) {
9669
9771
  return [binaryPath, "index", "--output", outputPath];
9670
9772
  case "rust":
9671
9773
  return [binaryPath, "scip", projectRoot, "--output", outputPath];
9774
+ case "ruby":
9775
+ return [binaryPath, "--output", outputPath];
9776
+ case "cpp":
9777
+ return [binaryPath, "--output", outputPath];
9778
+ case "csharp":
9779
+ return [binaryPath, "index", "--output", outputPath];
9672
9780
  default:
9673
9781
  return [binaryPath, "--output", outputPath];
9674
9782
  }
@@ -9684,8 +9792,9 @@ var init_runner = __esm({
9684
9792
  });
9685
9793
 
9686
9794
  // src/intelligence/indexer/scip/orchestrator.ts
9795
+ import { existsSync as existsSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
9687
9796
  import { join as join23 } from "path";
9688
- async function enrichWithScip(files, projectRoot, existingEdges, entities) {
9797
+ async function enrichWithScip(files, projectRoot, existingEdges, entities, options) {
9689
9798
  const languages = detectProjectLanguages(files);
9690
9799
  if (languages.length === 0) {
9691
9800
  return skipResult(existingEdges, "No supported language detected");
@@ -9699,20 +9808,29 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities) {
9699
9808
  for (const { language, fileCount } of languages) {
9700
9809
  log5.info(`SCIP: processing ${language} (${fileCount} files)`);
9701
9810
  let binaryInfo = await detectScipBinary(language);
9702
- if (!binaryInfo.available && isAutoDownloadSupported(language)) {
9703
- log5.info(`SCIP binary not found for ${language}, downloading...`);
9704
- const downloadResult = await downloadScipBinary(language, (msg) => {
9705
- log5.info(msg);
9706
- });
9707
- if (downloadResult.success && downloadResult.binaryPath) {
9708
- binaryInfo = await detectScipBinary(language);
9709
- } else {
9710
- const manualInstr = getManualInstallInstructions(language);
9711
- log5.warn(
9712
- `SCIP auto-download failed for ${language}: ${downloadResult.error}${manualInstr ? `
9811
+ if (!binaryInfo.available) {
9812
+ if (language === "csharp") {
9813
+ const installed = await installScipDotnet();
9814
+ if (installed) {
9815
+ binaryInfo = await detectScipBinary(language);
9816
+ } else {
9817
+ continue;
9818
+ }
9819
+ } else if (isAutoDownloadSupported(language)) {
9820
+ log5.info(`SCIP binary not found for ${language}, downloading...`);
9821
+ const downloadResult = await downloadScipBinary(language, (msg) => {
9822
+ log5.info(msg);
9823
+ });
9824
+ if (downloadResult.success && downloadResult.binaryPath) {
9825
+ binaryInfo = await detectScipBinary(language);
9826
+ } else {
9827
+ const manualInstr = getManualInstallInstructions(language);
9828
+ log5.warn(
9829
+ `SCIP auto-download failed for ${language}: ${downloadResult.error}${manualInstr ? `
9713
9830
  Manual install: ${manualInstr}` : ""}`
9714
- );
9715
- continue;
9831
+ );
9832
+ continue;
9833
+ }
9716
9834
  }
9717
9835
  }
9718
9836
  if (!binaryInfo.available) {
@@ -9726,12 +9844,38 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities) {
9726
9844
  );
9727
9845
  const outputDir = join23(projectRoot, ".unerr", "scip");
9728
9846
  const binaryPath = binaryInfo.path ?? binaryInfo.binaryName;
9847
+ let extraArgs;
9848
+ if (language === "typescript") {
9849
+ if (!existsSync18(join23(projectRoot, "tsconfig.json")) && !existsSync18(join23(projectRoot, "jsconfig.json"))) {
9850
+ log5.info(
9851
+ `SCIP skipping TypeScript: no tsconfig.json or jsconfig.json found in project root. Create one to enable SCIP indexing.`
9852
+ );
9853
+ continue;
9854
+ }
9855
+ }
9856
+ if (language === "java") {
9857
+ const buildToolResult = await resolveJavaBuildTool(projectRoot, options);
9858
+ if (buildToolResult) {
9859
+ extraArgs = buildToolResult.extraArgs;
9860
+ }
9861
+ }
9862
+ if (language === "cpp") {
9863
+ const compdbPath = resolveCompileCommandsJson(projectRoot);
9864
+ if (!compdbPath) {
9865
+ log5.info(
9866
+ `SCIP skipping C/C++: no compile_commands.json found. Generate one with CMake (-DCMAKE_EXPORT_COMPILE_COMMANDS=ON), Bear, or your build system.`
9867
+ );
9868
+ continue;
9869
+ }
9870
+ extraArgs = [`--compdb-path=${compdbPath}`];
9871
+ }
9729
9872
  const runResult = await runScipIndexer({
9730
9873
  language,
9731
9874
  binaryPath,
9732
9875
  projectRoot,
9733
9876
  outputDir,
9734
- timeoutMs: 3e4
9877
+ timeoutMs: 3e4,
9878
+ extraArgs
9735
9879
  });
9736
9880
  lastRunResult = runResult;
9737
9881
  if (!runResult.success || !runResult.outputPath) {
@@ -9778,6 +9922,136 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities) {
9778
9922
  skipReason: null
9779
9923
  };
9780
9924
  }
9925
+ function detectJavaBuildTools(projectRoot) {
9926
+ const detected = [];
9927
+ for (const [tool, files] of Object.entries(BUILD_TOOL_FILES)) {
9928
+ if (files.some((f) => existsSync18(join23(projectRoot, f)))) {
9929
+ detected.push(tool);
9930
+ }
9931
+ }
9932
+ return detected;
9933
+ }
9934
+ function getStoredBuildTool(projectRoot) {
9935
+ try {
9936
+ const configPath = join23(projectRoot, ".unerr", "config.json");
9937
+ const config = JSON.parse(readFileSync18(configPath, "utf-8"));
9938
+ return config.javaBuildTool ?? null;
9939
+ } catch {
9940
+ return null;
9941
+ }
9942
+ }
9943
+ function storeBuildTool(projectRoot, tool) {
9944
+ try {
9945
+ const configPath = join23(projectRoot, ".unerr", "config.json");
9946
+ let config = {};
9947
+ try {
9948
+ config = JSON.parse(readFileSync18(configPath, "utf-8"));
9949
+ } catch {
9950
+ }
9951
+ config.javaBuildTool = tool;
9952
+ writeFileSync9(configPath, `${JSON.stringify(config, null, 2)}
9953
+ `);
9954
+ } catch {
9955
+ }
9956
+ }
9957
+ async function promptBuildTool(tools, options) {
9958
+ if (!process.stdin.isTTY) {
9959
+ return null;
9960
+ }
9961
+ try {
9962
+ options?.onPromptStart?.();
9963
+ const clack2 = await import("@clack/prompts");
9964
+ const result = await clack2.select({
9965
+ message: "Multiple Java build tools detected. Which one should SCIP use?",
9966
+ options: tools.map((t) => ({
9967
+ value: t,
9968
+ label: t.charAt(0).toUpperCase() + t.slice(1)
9969
+ }))
9970
+ });
9971
+ options?.onPromptEnd?.();
9972
+ if (clack2.isCancel(result)) return null;
9973
+ return result;
9974
+ } catch {
9975
+ options?.onPromptEnd?.();
9976
+ return null;
9977
+ }
9978
+ }
9979
+ async function resolveJavaBuildTool(projectRoot, options) {
9980
+ const detected = detectJavaBuildTools(projectRoot);
9981
+ if (detected.length === 0) {
9982
+ return null;
9983
+ }
9984
+ if (detected.length === 1) {
9985
+ log5.info(`Java build tool: ${detected[0]} (auto-detected)`);
9986
+ return { tool: detected[0], extraArgs: [`--build-tool=${detected[0]}`] };
9987
+ }
9988
+ const stored = getStoredBuildTool(projectRoot);
9989
+ if (stored && detected.includes(stored)) {
9990
+ log5.info(`Java build tool: ${stored} (from config)`);
9991
+ return { tool: stored, extraArgs: [`--build-tool=${stored}`] };
9992
+ }
9993
+ const chosen = await promptBuildTool(detected, options);
9994
+ if (chosen) {
9995
+ storeBuildTool(projectRoot, chosen);
9996
+ log5.info(`Java build tool: ${chosen} (user selected, saved to config)`);
9997
+ return { tool: chosen, extraArgs: [`--build-tool=${chosen}`] };
9998
+ }
9999
+ const fallback = detected[0];
10000
+ log5.warn(
10001
+ `Multiple Java build tools detected (${detected.join(", ")}), using ${fallback}. Set "javaBuildTool" in .unerr/config.json to change.`
10002
+ );
10003
+ return { tool: fallback, extraArgs: [`--build-tool=${fallback}`] };
10004
+ }
10005
+ function resolveCompileCommandsJson(projectRoot) {
10006
+ for (const relPath of COMPDB_SEARCH_PATHS) {
10007
+ const absPath = join23(projectRoot, relPath);
10008
+ if (existsSync18(absPath)) {
10009
+ log5.info(`Found compile_commands.json at ${relPath}`);
10010
+ return absPath;
10011
+ }
10012
+ }
10013
+ return null;
10014
+ }
10015
+ async function installScipDotnet() {
10016
+ try {
10017
+ const dotnetCheck = await exec("which", ["dotnet"]);
10018
+ if (dotnetCheck.exitCode !== 0) {
10019
+ log5.warn(
10020
+ `SCIP skipping C#: dotnet CLI not found on PATH. Install the .NET SDK to enable SCIP indexing for C#.`
10021
+ );
10022
+ return false;
10023
+ }
10024
+ } catch {
10025
+ log5.warn(
10026
+ `SCIP skipping C#: dotnet CLI not found on PATH. Install the .NET SDK to enable SCIP indexing for C#.`
10027
+ );
10028
+ return false;
10029
+ }
10030
+ log5.info("Installing scip-dotnet via dotnet tool install...");
10031
+ try {
10032
+ const result = await exec("dotnet", [
10033
+ "tool",
10034
+ "install",
10035
+ "--global",
10036
+ "scip-dotnet"
10037
+ ]);
10038
+ if (result.exitCode === 0) {
10039
+ log5.info("scip-dotnet installed successfully");
10040
+ return true;
10041
+ }
10042
+ if (result.stderr.includes("already installed")) {
10043
+ log5.info("scip-dotnet already installed");
10044
+ return true;
10045
+ }
10046
+ log5.warn(`scip-dotnet install failed: ${result.stderr.slice(0, 300)}`);
10047
+ return false;
10048
+ } catch (err) {
10049
+ log5.warn(
10050
+ `scip-dotnet install failed: ${err instanceof Error ? err.message : String(err)}`
10051
+ );
10052
+ return false;
10053
+ }
10054
+ }
9781
10055
  function skipResult(existingEdges, reason) {
9782
10056
  log5.info(`SCIP skipped: ${reason}`);
9783
10057
  return {
@@ -9799,10 +10073,11 @@ function markAsStructural(edges) {
9799
10073
  scipVerified: false
9800
10074
  }));
9801
10075
  }
9802
- var log5;
10076
+ var log5, BUILD_TOOL_FILES, COMPDB_SEARCH_PATHS;
9803
10077
  var init_orchestrator = __esm({
9804
10078
  "src/intelligence/indexer/scip/orchestrator.ts"() {
9805
10079
  "use strict";
10080
+ init_exec();
9806
10081
  init_logger();
9807
10082
  init_decoder();
9808
10083
  init_detector();
@@ -9810,6 +10085,19 @@ var init_orchestrator = __esm({
9810
10085
  init_merger();
9811
10086
  init_runner();
9812
10087
  log5 = createModuleLogger("scip-orchestrator");
10088
+ BUILD_TOOL_FILES = {
10089
+ Maven: ["pom.xml"],
10090
+ Gradle: ["build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts"],
10091
+ Bazel: ["BUILD", "BUILD.bazel", "WORKSPACE", "WORKSPACE.bazel"],
10092
+ Sbt: ["build.sbt"]
10093
+ };
10094
+ COMPDB_SEARCH_PATHS = [
10095
+ "compile_commands.json",
10096
+ "build/compile_commands.json",
10097
+ "cmake-build-debug/compile_commands.json",
10098
+ "cmake-build-release/compile_commands.json",
10099
+ "out/compile_commands.json"
10100
+ ];
9813
10101
  }
9814
10102
  });
9815
10103
 
@@ -10329,7 +10617,7 @@ __export(local_indexer_exports, {
10329
10617
  runCommunityDetection: () => runCommunityDetection,
10330
10618
  runConventionDetection: () => runConventionDetection
10331
10619
  });
10332
- import { readFileSync as readFileSync18, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
10620
+ import { readFileSync as readFileSync19, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
10333
10621
  import { basename as basename2, extname as extname2, join as join24, relative } from "path";
10334
10622
  async function indexLocalProject(projectRoot, graphStore, repoId, opts) {
10335
10623
  const startTime = Date.now();
@@ -10357,7 +10645,7 @@ async function indexLocalProject(projectRoot, graphStore, repoId, opts) {
10357
10645
  });
10358
10646
  let content;
10359
10647
  try {
10360
- content = readFileSync18(absPath, "utf-8");
10648
+ content = readFileSync19(absPath, "utf-8");
10361
10649
  } catch {
10362
10650
  filesProcessed++;
10363
10651
  continue;
@@ -10468,10 +10756,18 @@ async function indexLocalProject(projectRoot, graphStore, repoId, opts) {
10468
10756
  ...coChangeCompactEdges
10469
10757
  ];
10470
10758
  await populateCozoDB(graphStore, allEntities, allEdges);
10759
+ progress?.({
10760
+ processed: filesProcessed,
10761
+ total: files.length,
10762
+ phase: "documents",
10763
+ currentFile: null
10764
+ });
10765
+ const docKeys = await indexDocumentFiles(projectRoot, graphStore);
10471
10766
  for (const e of allEntities) indexedEntityKeys.add(e.key);
10472
10767
  for (const e of allEntities) {
10473
10768
  if (e.file_path) indexedEntityKeys.add(`file:${e.file_path}`);
10474
10769
  }
10770
+ for (const dk of docKeys) indexedEntityKeys.add(dk);
10475
10771
  await removeOrphanedEntities(graphStore, indexedEntityKeys);
10476
10772
  await materializeL1Edges(graphStore);
10477
10773
  progress?.({
@@ -10507,7 +10803,7 @@ async function indexLocalProject(projectRoot, graphStore, repoId, opts) {
10507
10803
  await persistLocalSnapshot(projectRoot, repoId, allEntities, resolvedEdges);
10508
10804
  const elapsedMs = Date.now() - startTime;
10509
10805
  log6.info(
10510
- `Indexed ${files.length} files \u2192 ${allEntities.length} entities, ${resolvedEdges.length} edges in ${elapsedMs}ms`
10806
+ `Indexed ${files.length} files \u2192 ${allEntities.length} entities, ${resolvedEdges.length} edges, ${docKeys.length} docs in ${elapsedMs}ms`
10511
10807
  );
10512
10808
  return {
10513
10809
  fileCount: files.length,
@@ -10516,6 +10812,7 @@ async function indexLocalProject(projectRoot, graphStore, repoId, opts) {
10516
10812
  communityCount,
10517
10813
  patternCount,
10518
10814
  ruleCount,
10815
+ docCount: docKeys.length,
10519
10816
  elapsedMs,
10520
10817
  scip: scipResult.mergeResult ? {
10521
10818
  language: scipResult.language,
@@ -10531,7 +10828,7 @@ async function reindexFile(projectRoot, filePath, graphStore, repoId) {
10531
10828
  await removeFileEntities(graphStore, relPath);
10532
10829
  let content;
10533
10830
  try {
10534
- content = readFileSync18(absPath, "utf-8");
10831
+ content = readFileSync19(absPath, "utf-8");
10535
10832
  } catch {
10536
10833
  return { entities: 0, edges: 0 };
10537
10834
  }
@@ -11338,7 +11635,113 @@ async function resolveEntityNameGlobal(name, graphStore) {
11338
11635
  }
11339
11636
  return null;
11340
11637
  }
11341
- var INDEXABLE_EXTENSIONS, EXCLUDED_DIRS2, MAX_FILE_SIZE, log6;
11638
+ function walkDirForDocs(dir, files, projectRoot) {
11639
+ let entries;
11640
+ try {
11641
+ entries = readdirSync6(dir);
11642
+ } catch {
11643
+ return;
11644
+ }
11645
+ for (const entry of entries) {
11646
+ const absPath = join24(dir, entry);
11647
+ let stats;
11648
+ try {
11649
+ stats = statSync6(absPath);
11650
+ } catch {
11651
+ continue;
11652
+ }
11653
+ if (stats.isDirectory()) {
11654
+ if (EXCLUDED_DIRS2.has(entry)) continue;
11655
+ if (entry.startsWith(".") && !CI_CD_DIRS.has(entry)) continue;
11656
+ walkDirForDocs(absPath, files, projectRoot);
11657
+ continue;
11658
+ }
11659
+ if (!stats.isFile()) continue;
11660
+ if (stats.size > MAX_FILE_SIZE) continue;
11661
+ const ext = extname2(entry).toLowerCase();
11662
+ const name = basename2(entry);
11663
+ if (INDEXABLE_EXTENSIONS.has(ext)) continue;
11664
+ if (DOCUMENT_EXTENSIONS.has(ext) || DOCUMENT_NAMES.has(name)) {
11665
+ files.push(absPath);
11666
+ }
11667
+ }
11668
+ }
11669
+ function discoverDocumentFiles(projectRoot) {
11670
+ const files = [];
11671
+ walkDirForDocs(projectRoot, files, projectRoot);
11672
+ return files;
11673
+ }
11674
+ function extractDocTokens(absPath, relPath) {
11675
+ const tokens = new Set(tokenize(basename2(relPath)));
11676
+ for (const segment of relPath.split("/").slice(0, -1)) {
11677
+ if (segment && !EXCLUDED_DIRS2.has(segment)) {
11678
+ for (const t of tokenize(segment)) tokens.add(t);
11679
+ }
11680
+ }
11681
+ const ext = extname2(absPath).toLowerCase();
11682
+ try {
11683
+ const content = readFileSync19(absPath, "utf-8").slice(0, DOC_READ_LIMIT);
11684
+ const pattern = DOC_TOKEN_PATTERNS[ext];
11685
+ if (pattern) {
11686
+ pattern.lastIndex = 0;
11687
+ let match;
11688
+ while ((match = pattern.exec(content)) !== null) {
11689
+ if (match[1]) for (const t of tokenize(match[1])) tokens.add(t);
11690
+ if (match[2]) for (const t of tokenize(match[2])) tokens.add(t);
11691
+ }
11692
+ }
11693
+ if (ext === ".yaml" || ext === ".yml") {
11694
+ const yamlKeyRegex = /^([a-zA-Z_][\w-]*)\s*:/gm;
11695
+ let match;
11696
+ while ((match = yamlKeyRegex.exec(content)) !== null) {
11697
+ if (match[1]) for (const t of tokenize(match[1])) tokens.add(t);
11698
+ }
11699
+ }
11700
+ } catch {
11701
+ }
11702
+ return [...tokens];
11703
+ }
11704
+ async function indexDocumentFiles(projectRoot, graphStore) {
11705
+ const docFiles = discoverDocumentFiles(projectRoot);
11706
+ if (docFiles.length === 0) return [];
11707
+ const docKeys = [];
11708
+ for (const absPath of docFiles) {
11709
+ const relPath = relative(projectRoot, absPath);
11710
+ const name = basename2(relPath);
11711
+ const key = `doc:${relPath}`;
11712
+ docKeys.push(key);
11713
+ try {
11714
+ await graphStore.db.run(
11715
+ '?[key, kind, name, file_path, fan_in, fan_out, risk_level] <- [[$key, "document", $name, $fp, 0, 0, "low"]] :put entities { key => kind, name, file_path, fan_in, fan_out, risk_level }',
11716
+ { key, name, fp: relPath }
11717
+ );
11718
+ } catch {
11719
+ continue;
11720
+ }
11721
+ const docTokens = extractDocTokens(absPath, relPath);
11722
+ for (const token of docTokens) {
11723
+ try {
11724
+ await graphStore.db.run(
11725
+ "?[token, entity_key] <- [[$token, $key]] :put search_tokens { token, entity_key }",
11726
+ { token, key }
11727
+ );
11728
+ } catch {
11729
+ }
11730
+ }
11731
+ try {
11732
+ await graphStore.db.run(
11733
+ "?[file_path, entity_key] <- [[$fp, $key]] :put file_index { file_path, entity_key }",
11734
+ { fp: relPath, key }
11735
+ );
11736
+ } catch {
11737
+ }
11738
+ }
11739
+ if (docKeys.length > 0) {
11740
+ log6.info(`Documents: ${docKeys.length} doc/config files indexed for search`);
11741
+ }
11742
+ return docKeys;
11743
+ }
11744
+ var INDEXABLE_EXTENSIONS, EXCLUDED_DIRS2, MAX_FILE_SIZE, DOCUMENT_EXTENSIONS, DOCUMENT_NAMES, CI_CD_DIRS, DOC_READ_LIMIT, log6, DOC_TOKEN_PATTERNS;
11342
11745
  var init_local_indexer = __esm({
11343
11746
  "src/intelligence/local-indexer.ts"() {
11344
11747
  "use strict";
@@ -11392,6 +11795,87 @@ var init_local_indexer = __esm({
11392
11795
  ".parcel-cache"
11393
11796
  ]);
11394
11797
  MAX_FILE_SIZE = 1048576;
11798
+ DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
11799
+ ".md",
11800
+ ".mdx",
11801
+ ".txt",
11802
+ ".rst",
11803
+ ".adoc",
11804
+ ".org",
11805
+ ".yaml",
11806
+ ".yml",
11807
+ ".toml",
11808
+ ".json",
11809
+ ".xml",
11810
+ ".tf",
11811
+ ".tfvars",
11812
+ ".hcl",
11813
+ ".proto",
11814
+ ".graphql",
11815
+ ".gql",
11816
+ ".sql",
11817
+ ".sh",
11818
+ ".bash",
11819
+ ".zsh",
11820
+ ".html",
11821
+ ".css",
11822
+ ".scss",
11823
+ ".sass",
11824
+ ".less",
11825
+ ".vue",
11826
+ ".svelte",
11827
+ ".astro",
11828
+ ".j2",
11829
+ ".jinja2",
11830
+ ".tmpl",
11831
+ ".hbs",
11832
+ ".ejs",
11833
+ ".pug",
11834
+ ".prisma",
11835
+ ".avsc",
11836
+ ".thrift",
11837
+ ".smithy",
11838
+ ".cmake",
11839
+ ".bazel",
11840
+ ".bzl",
11841
+ ".mk",
11842
+ ".csv",
11843
+ ".tsv",
11844
+ ".ini",
11845
+ ".cfg",
11846
+ ".conf",
11847
+ ".properties",
11848
+ ".env.example",
11849
+ ".editorconfig",
11850
+ ".dockerfile",
11851
+ ".tex",
11852
+ ".latex",
11853
+ ".eslintrc",
11854
+ ".prettierrc",
11855
+ ".stylelintrc",
11856
+ ".pylintrc",
11857
+ ".flake8"
11858
+ ]);
11859
+ DOCUMENT_NAMES = /* @__PURE__ */ new Set([
11860
+ "Dockerfile",
11861
+ "Makefile",
11862
+ "Procfile",
11863
+ "Vagrantfile",
11864
+ "Jenkinsfile",
11865
+ "Gemfile",
11866
+ "Rakefile",
11867
+ ".gitignore",
11868
+ ".dockerignore",
11869
+ ".prettierrc",
11870
+ ".editorconfig",
11871
+ ".eslintrc",
11872
+ ".stylelintrc",
11873
+ "biome.json",
11874
+ "tslint.json",
11875
+ ".gitlab-ci.yml"
11876
+ ]);
11877
+ CI_CD_DIRS = /* @__PURE__ */ new Set([".github", ".circleci"]);
11878
+ DOC_READ_LIMIT = 8192;
11395
11879
  log6 = {
11396
11880
  info: (msg) => process.stderr.write(`[unerr] ${msg}
11397
11881
  `),
@@ -11400,6 +11884,31 @@ var init_local_indexer = __esm({
11400
11884
  `);
11401
11885
  }
11402
11886
  };
11887
+ DOC_TOKEN_PATTERNS = {
11888
+ ".md": /^#{1,6}\s+(.+)$/gm,
11889
+ ".mdx": /^#{1,6}\s+(.+)$/gm,
11890
+ ".tf": /^(?:resource|module|variable|data|output)\s+"([^"]+)"(?:\s+"([^"]+)")?/gm,
11891
+ ".hcl": /^(?:resource|module|variable|data|output)\s+"([^"]+)"(?:\s+"([^"]+)")?/gm,
11892
+ ".sql": /CREATE\s+(?:TABLE|VIEW|FUNCTION|PROCEDURE|INDEX)\s+(?:IF\s+NOT\s+EXISTS\s+)?["'`]?(\w+)/gim,
11893
+ ".graphql": /^(?:type|query|mutation|subscription|input|enum|interface)\s+(\w+)/gm,
11894
+ ".gql": /^(?:type|query|mutation|subscription|input|enum|interface)\s+(\w+)/gm,
11895
+ ".sh": /^(?:function\s+)?(\w+)\s*\(\)/gm,
11896
+ ".bash": /^(?:function\s+)?(\w+)\s*\(\)/gm,
11897
+ ".zsh": /^(?:function\s+)?(\w+)\s*\(\)/gm,
11898
+ ".proto": /^(?:message|service|enum|rpc)\s+(\w+)/gm,
11899
+ ".prisma": /^(?:model|enum|type|datasource|generator)\s+(\w+)/gm,
11900
+ ".smithy": /^(?:service|resource|operation|structure|union|enum)\s+(\w+)/gm,
11901
+ ".cmake": /^(?:project|add_library|add_executable|find_package)\s*\(\s*(\w+)/gm,
11902
+ ".bazel": /^(?:cc_library|cc_binary|java_library|py_library|go_library)\s*\(\s*name\s*=\s*"([^"]+)"/gm,
11903
+ ".bzl": /^def\s+(\w+)\s*\(/gm,
11904
+ ".tex": /\\(?:section|subsection|chapter|title)\{([^}]+)\}/gm,
11905
+ ".latex": /\\(?:section|subsection|chapter|title)\{([^}]+)\}/gm,
11906
+ ".html": /<(?:h[1-6]|title)[^>]*>([^<]+)</gim,
11907
+ ".vue": /<(?:h[1-6]|title)[^>]*>([^<]+)</gim,
11908
+ ".svelte": /<(?:h[1-6]|title)[^>]*>([^<]+)</gim,
11909
+ ".thrift": /^(?:service|struct|enum|exception|typedef)\s+(\w+)/gm,
11910
+ ".avsc": /"name"\s*:\s*"([^"]+)"/gm
11911
+ };
11403
11912
  }
11404
11913
  });
11405
11914
 
@@ -11412,23 +11921,23 @@ __export(hook_installer_exports, {
11412
11921
  });
11413
11922
  import {
11414
11923
  chmodSync as chmodSync3,
11415
- existsSync as existsSync18,
11924
+ existsSync as existsSync19,
11416
11925
  mkdirSync as mkdirSync13,
11417
11926
  unlinkSync as unlinkSync2,
11418
- writeFileSync as writeFileSync9
11927
+ writeFileSync as writeFileSync10
11419
11928
  } from "fs";
11420
11929
  import { join as join25 } from "path";
11421
11930
  function installClaudeHook(cwd) {
11422
11931
  const hooksDir = join25(cwd, ".claude", "hooks");
11423
11932
  const hookPath = join25(hooksDir, "PostToolUse.sh");
11424
- if (existsSync18(hookPath)) {
11933
+ if (existsSync19(hookPath)) {
11425
11934
  return { path: hookPath, action: "already_exists" };
11426
11935
  }
11427
11936
  try {
11428
- if (!existsSync18(hooksDir)) {
11937
+ if (!existsSync19(hooksDir)) {
11429
11938
  mkdirSync13(hooksDir, { recursive: true });
11430
11939
  }
11431
- writeFileSync9(hookPath, HOOK_CONTENT, "utf-8");
11940
+ writeFileSync10(hookPath, HOOK_CONTENT, "utf-8");
11432
11941
  chmodSync3(hookPath, 493);
11433
11942
  return { path: hookPath, action: "installed" };
11434
11943
  } catch {
@@ -11437,7 +11946,7 @@ function installClaudeHook(cwd) {
11437
11946
  }
11438
11947
  function removeClaudeHook(cwd) {
11439
11948
  const hookPath = join25(cwd, ".claude", "hooks", "PostToolUse.sh");
11440
- if (!existsSync18(hookPath)) return false;
11949
+ if (!existsSync19(hookPath)) return false;
11441
11950
  try {
11442
11951
  unlinkSync2(hookPath);
11443
11952
  return true;
@@ -11446,7 +11955,7 @@ function removeClaudeHook(cwd) {
11446
11955
  }
11447
11956
  }
11448
11957
  function isClaudeHookInstalled(cwd) {
11449
- return existsSync18(join25(cwd, ".claude", "hooks", "PostToolUse.sh"));
11958
+ return existsSync19(join25(cwd, ".claude", "hooks", "PostToolUse.sh"));
11450
11959
  }
11451
11960
  var HOOK_CONTENT;
11452
11961
  var init_hook_installer = __esm({
@@ -11473,13 +11982,13 @@ __export(tool_detector_exports, {
11473
11982
  detectTools: () => detectTools,
11474
11983
  formatDetectedTools: () => formatDetectedTools
11475
11984
  });
11476
- import { existsSync as existsSync19 } from "fs";
11985
+ import { existsSync as existsSync20 } from "fs";
11477
11986
  import { join as join26 } from "path";
11478
11987
  function detectTools(cwd) {
11479
11988
  const detected = [];
11480
11989
  for (const agent of AGENT_REGISTRY) {
11481
11990
  const hasDirMarker = agent.dirMarkers.some(
11482
- (dir) => existsSync19(join26(cwd, dir))
11991
+ (dir) => existsSync20(join26(cwd, dir))
11483
11992
  );
11484
11993
  const hasEnvVar = agent.envVars.some((envVar) => !!process.env[envVar]);
11485
11994
  if (hasDirMarker || hasEnvVar) {
@@ -11487,7 +11996,7 @@ function detectTools(cwd) {
11487
11996
  detected.push({
11488
11997
  ide: agent.id,
11489
11998
  configDir: join26(cwd, agent.dirMarkers[0] ?? ""),
11490
- hasExistingConfig: existsSync19(configPath),
11999
+ hasExistingConfig: existsSync20(configPath),
11491
12000
  agent
11492
12001
  });
11493
12002
  }
@@ -11831,13 +12340,13 @@ __export(resolver_exports, {
11831
12340
  scanSkillDirectory: () => scanSkillDirectory
11832
12341
  });
11833
12342
  import {
11834
- existsSync as existsSync22,
12343
+ existsSync as existsSync23,
11835
12344
  mkdirSync as mkdirSync16,
11836
- readFileSync as readFileSync21,
12345
+ readFileSync as readFileSync22,
11837
12346
  readdirSync as readdirSync7,
11838
12347
  rmSync,
11839
12348
  unlinkSync as unlinkSync4,
11840
- writeFileSync as writeFileSync12
12349
+ writeFileSync as writeFileSync13
11841
12350
  } from "fs";
11842
12351
  import { homedir as homedir6 } from "os";
11843
12352
  import { dirname as dirname6, join as join29 } from "path";
@@ -11937,7 +12446,7 @@ function writeSkillFile(skill, ide, skillDir, ext, dirPerSkill) {
11937
12446
  filePath = join29(skillDir, `${skillName}${ext}`);
11938
12447
  content = formatMarkdownSkill(skill);
11939
12448
  }
11940
- writeFileSync12(filePath, content);
12449
+ writeFileSync13(filePath, content);
11941
12450
  return filePath;
11942
12451
  }
11943
12452
  function formatClaudeCodeSkill(skill) {
@@ -12114,13 +12623,13 @@ function parseFrontmatter(raw) {
12114
12623
  return { meta, content };
12115
12624
  }
12116
12625
  function scanSkillDirectory(dir) {
12117
- if (!existsSync22(dir)) return [];
12626
+ if (!existsSync23(dir)) return [];
12118
12627
  const skills = [];
12119
12628
  try {
12120
12629
  const files = readdirSync7(dir).filter((f) => f.endsWith(".md"));
12121
12630
  for (const file of files) {
12122
12631
  try {
12123
- const raw = readFileSync21(join29(dir, file), "utf-8");
12632
+ const raw = readFileSync22(join29(dir, file), "utf-8");
12124
12633
  const { meta, content } = parseFrontmatter(raw);
12125
12634
  const name = meta.name ?? file.replace(/\.md$/, "");
12126
12635
  skills.push({
@@ -12167,13 +12676,13 @@ async function resolveAndInstallSkills(opts) {
12167
12676
  }
12168
12677
  async function ensureSkillsPresent(opts) {
12169
12678
  const { dir, ext, dirPerSkill } = getSkillDir(opts.ide, opts.cwd);
12170
- if (existsSync22(dir)) {
12679
+ if (existsSync23(dir)) {
12171
12680
  try {
12172
12681
  const entries = readdirSync7(dir);
12173
12682
  let hasSkills;
12174
12683
  if (dirPerSkill) {
12175
12684
  hasSkills = entries.some(
12176
- (f) => f.startsWith("unerr-") && existsSync22(join29(dir, f, "SKILL.md"))
12685
+ (f) => f.startsWith("unerr-") && existsSync23(join29(dir, f, "SKILL.md"))
12177
12686
  );
12178
12687
  } else {
12179
12688
  hasSkills = entries.some(
@@ -12189,11 +12698,11 @@ async function ensureSkillsPresent(opts) {
12189
12698
  }
12190
12699
  function listInstalledSkills(ide, cwd) {
12191
12700
  const { dir, ext, dirPerSkill } = getSkillDir(ide, cwd);
12192
- if (!existsSync22(dir)) return [];
12701
+ if (!existsSync23(dir)) return [];
12193
12702
  try {
12194
12703
  if (dirPerSkill) {
12195
12704
  return readdirSync7(dir).filter(
12196
- (f) => f.startsWith("unerr-") && existsSync22(join29(dir, f, "SKILL.md"))
12705
+ (f) => f.startsWith("unerr-") && existsSync23(join29(dir, f, "SKILL.md"))
12197
12706
  ).map((f) => ({
12198
12707
  name: f.replace("unerr-", ""),
12199
12708
  path: join29(dir, f, "SKILL.md")
@@ -12236,7 +12745,7 @@ var correction_detector_exports = {};
12236
12745
  __export(correction_detector_exports, {
12237
12746
  detectCorrections: () => detectCorrections
12238
12747
  });
12239
- import { existsSync as existsSync24, readFileSync as readFileSync23 } from "fs";
12748
+ import { existsSync as existsSync25, readFileSync as readFileSync24 } from "fs";
12240
12749
  function detectCorrections(ledgerPath, options) {
12241
12750
  const MIN_CONFIDENCE = options?.min_confidence ?? 0.6;
12242
12751
  const CORRECTION_WINDOW = options?.correction_window_ms ?? 6e4;
@@ -12259,11 +12768,11 @@ function detectCorrections(ledgerPath, options) {
12259
12768
  return deduplicatePatterns(scored);
12260
12769
  }
12261
12770
  function readLedgerEntries(ledgerPath, sinceDays) {
12262
- if (!existsSync24(ledgerPath)) return [];
12771
+ if (!existsSync25(ledgerPath)) return [];
12263
12772
  const cutoff = Date.now() - sinceDays * 24 * 60 * 60 * 1e3;
12264
12773
  const entries = [];
12265
12774
  try {
12266
- const content = readFileSync23(ledgerPath, "utf-8");
12775
+ const content = readFileSync24(ledgerPath, "utf-8");
12267
12776
  const lines = content.split("\n");
12268
12777
  for (const line of lines) {
12269
12778
  if (line.trim().length === 0) continue;
@@ -12468,10 +12977,10 @@ __export(offline_rewind_exports, {
12468
12977
  import { randomBytes } from "crypto";
12469
12978
  import {
12470
12979
  appendFileSync as appendFileSync6,
12471
- existsSync as existsSync27,
12980
+ existsSync as existsSync28,
12472
12981
  mkdirSync as mkdirSync18,
12473
- readFileSync as readFileSync25,
12474
- writeFileSync as writeFileSync14
12982
+ readFileSync as readFileSync26,
12983
+ writeFileSync as writeFileSync15
12475
12984
  } from "fs";
12476
12985
  import { join as join33 } from "path";
12477
12986
  async function offlineRewind(input) {
@@ -12609,9 +13118,9 @@ async function computeLocalBlastRadius(graph, revertFiles, targetFiles, startTim
12609
13118
  }
12610
13119
  function readBranchCounter(unerrDir) {
12611
13120
  const contextPath = join33(unerrDir, "ledger", "branch_context.json");
12612
- if (!existsSync27(contextPath)) return 1;
13121
+ if (!existsSync28(contextPath)) return 1;
12613
13122
  try {
12614
- const data = JSON.parse(readFileSync25(contextPath, "utf-8"));
13123
+ const data = JSON.parse(readFileSync26(contextPath, "utf-8"));
12615
13124
  return data.timeline_branch ?? 1;
12616
13125
  } catch {
12617
13126
  return 1;
@@ -12620,13 +13129,13 @@ function readBranchCounter(unerrDir) {
12620
13129
  function incrementBranchCounter(unerrDir) {
12621
13130
  const contextPath = join33(unerrDir, "ledger", "branch_context.json");
12622
13131
  const ledgerDir = join33(unerrDir, "ledger");
12623
- if (!existsSync27(ledgerDir)) {
13132
+ if (!existsSync28(ledgerDir)) {
12624
13133
  mkdirSync18(ledgerDir, { recursive: true });
12625
13134
  }
12626
13135
  let data = {};
12627
- if (existsSync27(contextPath)) {
13136
+ if (existsSync28(contextPath)) {
12628
13137
  try {
12629
- data = JSON.parse(readFileSync25(contextPath, "utf-8"));
13138
+ data = JSON.parse(readFileSync26(contextPath, "utf-8"));
12630
13139
  } catch {
12631
13140
  }
12632
13141
  }
@@ -12634,25 +13143,25 @@ function incrementBranchCounter(unerrDir) {
12634
13143
  const next = current + 1;
12635
13144
  data.timeline_branch = next;
12636
13145
  data.last_rewind_at = (/* @__PURE__ */ new Date()).toISOString();
12637
- writeFileSync14(contextPath, JSON.stringify(data, null, 2), "utf-8");
13146
+ writeFileSync15(contextPath, JSON.stringify(data, null, 2), "utf-8");
12638
13147
  return next;
12639
13148
  }
12640
13149
  function markEntriesReverted(unerrDir, entryIds) {
12641
13150
  if (entryIds.length === 0) return;
12642
13151
  const revertedPath = join33(unerrDir, "ledger", "reverted_entries.json");
12643
13152
  const ledgerDir = join33(unerrDir, "ledger");
12644
- if (!existsSync27(ledgerDir)) {
13153
+ if (!existsSync28(ledgerDir)) {
12645
13154
  mkdirSync18(ledgerDir, { recursive: true });
12646
13155
  }
12647
13156
  let existing = [];
12648
- if (existsSync27(revertedPath)) {
13157
+ if (existsSync28(revertedPath)) {
12649
13158
  try {
12650
- existing = JSON.parse(readFileSync25(revertedPath, "utf-8"));
13159
+ existing = JSON.parse(readFileSync26(revertedPath, "utf-8"));
12651
13160
  } catch {
12652
13161
  }
12653
13162
  }
12654
13163
  const merged = Array.from(/* @__PURE__ */ new Set([...existing, ...entryIds]));
12655
- writeFileSync14(revertedPath, JSON.stringify(merged, null, 2), "utf-8");
13164
+ writeFileSync15(revertedPath, JSON.stringify(merged, null, 2), "utf-8");
12656
13165
  }
12657
13166
  function extractFilesFromEntry(entry) {
12658
13167
  const files = [];
@@ -12712,10 +13221,10 @@ __export(shadow_ledger_exports, {
12712
13221
  import { randomBytes as randomBytes2 } from "crypto";
12713
13222
  import {
12714
13223
  appendFileSync as appendFileSync7,
12715
- existsSync as existsSync28,
13224
+ existsSync as existsSync29,
12716
13225
  mkdirSync as mkdirSync19,
12717
- readFileSync as readFileSync26,
12718
- writeFileSync as writeFileSync15
13226
+ readFileSync as readFileSync27,
13227
+ writeFileSync as writeFileSync16
12719
13228
  } from "fs";
12720
13229
  import { join as join34 } from "path";
12721
13230
  function generateId2() {
@@ -12750,7 +13259,7 @@ var init_shadow_ledger = __esm({
12750
13259
  this.ledgerDir = join34(unerrDir, "ledger");
12751
13260
  this.filePath = join34(this.ledgerDir, "shadow.jsonl");
12752
13261
  this.sessionId = generateId2();
12753
- if (!existsSync28(this.ledgerDir)) {
13262
+ if (!existsSync29(this.ledgerDir)) {
12754
13263
  mkdirSync19(this.ledgerDir, { recursive: true });
12755
13264
  }
12756
13265
  this.recoverFile();
@@ -12857,9 +13366,9 @@ var init_shadow_ledger = __esm({
12857
13366
  * Get all entries (read from file). Used sparingly — prefer buffer.
12858
13367
  */
12859
13368
  readAllEntries() {
12860
- if (!existsSync28(this.filePath)) return [];
13369
+ if (!existsSync29(this.filePath)) return [];
12861
13370
  try {
12862
- const content = readFileSync26(this.filePath, "utf-8");
13371
+ const content = readFileSync27(this.filePath, "utf-8");
12863
13372
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
12864
13373
  return lines.map((line) => JSON.parse(line));
12865
13374
  } catch {
@@ -12896,9 +13405,9 @@ var init_shadow_ledger = __esm({
12896
13405
  * Recover from file corruption: truncate to last valid JSONL line.
12897
13406
  */
12898
13407
  recoverFile() {
12899
- if (!existsSync28(this.filePath)) return;
13408
+ if (!existsSync29(this.filePath)) return;
12900
13409
  try {
12901
- const content = readFileSync26(this.filePath, "utf-8");
13410
+ const content = readFileSync27(this.filePath, "utf-8");
12902
13411
  const lines = content.split("\n");
12903
13412
  const validLines = [];
12904
13413
  for (const line of lines) {
@@ -12915,23 +13424,23 @@ var init_shadow_ledger = __esm({
12915
13424
  }
12916
13425
  }
12917
13426
  if (validLines.length < lines.filter((l) => l.trim().length > 0).length) {
12918
- writeFileSync15(
13427
+ writeFileSync16(
12919
13428
  this.filePath,
12920
13429
  validLines.join("\n") + (validLines.length > 0 ? "\n" : ""),
12921
13430
  "utf-8"
12922
13431
  );
12923
13432
  }
12924
13433
  } catch {
12925
- writeFileSync15(this.filePath, "", "utf-8");
13434
+ writeFileSync16(this.filePath, "", "utf-8");
12926
13435
  }
12927
13436
  }
12928
13437
  /**
12929
13438
  * Load the most recent entries from the file into the buffer.
12930
13439
  */
12931
13440
  loadRecentEntries() {
12932
- if (!existsSync28(this.filePath)) return;
13441
+ if (!existsSync29(this.filePath)) return;
12933
13442
  try {
12934
- const content = readFileSync26(this.filePath, "utf-8");
13443
+ const content = readFileSync27(this.filePath, "utf-8");
12935
13444
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
12936
13445
  const start = Math.max(0, lines.length - MAX_BUFFER_SIZE);
12937
13446
  for (let i = start; i < lines.length; i++) {
@@ -12959,9 +13468,9 @@ var init_shadow_ledger = __esm({
12959
13468
  * Count total entries in the file.
12960
13469
  */
12961
13470
  countEntries() {
12962
- if (!existsSync28(this.filePath)) return 0;
13471
+ if (!existsSync29(this.filePath)) return 0;
12963
13472
  try {
12964
- const content = readFileSync26(this.filePath, "utf-8");
13473
+ const content = readFileSync27(this.filePath, "utf-8");
12965
13474
  return content.split("\n").filter((l) => l.trim().length > 0).length;
12966
13475
  } catch {
12967
13476
  return 0;
@@ -12986,7 +13495,7 @@ __export(timeline_fork_exports, {
12986
13495
  resetTimelineForks: () => resetTimelineForks,
12987
13496
  wasForkPoint: () => wasForkPoint
12988
13497
  });
12989
- import { existsSync as existsSync29, mkdirSync as mkdirSync20, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "fs";
13498
+ import { existsSync as existsSync30, mkdirSync as mkdirSync20, readFileSync as readFileSync28, writeFileSync as writeFileSync17 } from "fs";
12990
13499
  import { join as join35 } from "path";
12991
13500
  function createTimelineFork(snapshotId, abandonedEntities, prompts, reason, unerrDir) {
12992
13501
  const state = unerrDir ? loadState(unerrDir) : { activeTimeline: inMemoryTimeline, forks: [] };
@@ -13117,17 +13626,17 @@ function getStatePath(unerrDir) {
13117
13626
  }
13118
13627
  function ensureStateDir(unerrDir) {
13119
13628
  const stateDir = join35(unerrDir, "state");
13120
- if (!existsSync29(stateDir)) {
13629
+ if (!existsSync30(stateDir)) {
13121
13630
  mkdirSync20(stateDir, { recursive: true });
13122
13631
  }
13123
13632
  }
13124
13633
  function loadState(unerrDir) {
13125
13634
  const path7 = getStatePath(unerrDir);
13126
- if (!existsSync29(path7)) {
13635
+ if (!existsSync30(path7)) {
13127
13636
  return { activeTimeline: 0, forks: [] };
13128
13637
  }
13129
13638
  try {
13130
- const raw = readFileSync27(path7, "utf-8");
13639
+ const raw = readFileSync28(path7, "utf-8");
13131
13640
  const parsed = JSON.parse(raw);
13132
13641
  return {
13133
13642
  activeTimeline: typeof parsed.activeTimeline === "number" ? parsed.activeTimeline : 0,
@@ -13141,7 +13650,7 @@ function loadState(unerrDir) {
13141
13650
  function saveState(unerrDir, state) {
13142
13651
  ensureStateDir(unerrDir);
13143
13652
  const path7 = getStatePath(unerrDir);
13144
- writeFileSync16(path7, JSON.stringify(state, null, 2), "utf-8");
13653
+ writeFileSync17(path7, JSON.stringify(state, null, 2), "utf-8");
13145
13654
  }
13146
13655
  function deduplicateStrings(arr) {
13147
13656
  return Array.from(new Set(arr));
@@ -13203,9 +13712,9 @@ function createEmptyAllTime() {
13203
13712
  function loadStats() {
13204
13713
  const currentWeek = getWeekStart();
13205
13714
  try {
13206
- const { readFileSync: readFileSync57 } = __require("fs");
13715
+ const { readFileSync: readFileSync58 } = __require("fs");
13207
13716
  const raw = JSON.parse(
13208
- readFileSync57(getStatsPath(), "utf-8")
13717
+ readFileSync58(getStatsPath(), "utf-8")
13209
13718
  );
13210
13719
  if (raw.version !== 1) {
13211
13720
  return {
@@ -13328,7 +13837,7 @@ __export(branch_context_exports, {
13328
13837
  getHeadSha: () => getHeadSha2,
13329
13838
  startBranchPoller: () => startBranchPoller
13330
13839
  });
13331
- import { existsSync as existsSync30, readFileSync as readFileSync28 } from "fs";
13840
+ import { existsSync as existsSync31, readFileSync as readFileSync29 } from "fs";
13332
13841
  import { join as join37 } from "path";
13333
13842
  async function computeBranchContext(cwd) {
13334
13843
  const dir = cwd ?? process.cwd();
@@ -13393,9 +13902,9 @@ function detectBranchSwitch(previousBranch, cwd) {
13393
13902
  function getCurrentBranch2(cwd) {
13394
13903
  const gitDir = cwd ? join37(cwd, ".git") : join37(process.cwd(), ".git");
13395
13904
  const headPath = join37(gitDir, "HEAD");
13396
- if (!existsSync30(headPath)) return null;
13905
+ if (!existsSync31(headPath)) return null;
13397
13906
  try {
13398
- const content = readFileSync28(headPath, "utf-8").trim();
13907
+ const content = readFileSync29(headPath, "utf-8").trim();
13399
13908
  if (content.startsWith("ref: refs/heads/")) {
13400
13909
  return content.slice("ref: refs/heads/".length);
13401
13910
  }
@@ -13918,9 +14427,9 @@ function getCumulativePath() {
13918
14427
  function loadCumulativeStats() {
13919
14428
  const currentWeek = getWeekStart2();
13920
14429
  try {
13921
- const { readFileSync: readFileSync57 } = __require("fs");
14430
+ const { readFileSync: readFileSync58 } = __require("fs");
13922
14431
  const raw = JSON.parse(
13923
- readFileSync57(getCumulativePath(), "utf-8")
14432
+ readFileSync58(getCumulativePath(), "utf-8")
13924
14433
  );
13925
14434
  if (raw.weekStart !== currentWeek) {
13926
14435
  return {
@@ -13981,9 +14490,9 @@ function createEmptyCumulativeLocal(weekStart) {
13981
14490
  function loadCumulativeLocalStats() {
13982
14491
  const currentWeek = getWeekStart2();
13983
14492
  try {
13984
- const { readFileSync: readFileSync57 } = __require("fs");
14493
+ const { readFileSync: readFileSync58 } = __require("fs");
13985
14494
  const raw = JSON.parse(
13986
- readFileSync57(getCumulativeLocalPath(), "utf-8")
14495
+ readFileSync58(getCumulativeLocalPath(), "utf-8")
13987
14496
  );
13988
14497
  if (raw.weekStartDate !== currentWeek) {
13989
14498
  return createEmptyCumulativeLocal(currentWeek);
@@ -14587,11 +15096,11 @@ __export(pid_lock_exports, {
14587
15096
  PidLock: () => PidLock
14588
15097
  });
14589
15098
  import {
14590
- existsSync as existsSync34,
15099
+ existsSync as existsSync35,
14591
15100
  mkdirSync as mkdirSync21,
14592
- readFileSync as readFileSync32,
15101
+ readFileSync as readFileSync33,
14593
15102
  unlinkSync as unlinkSync6,
14594
- writeFileSync as writeFileSync18
15103
+ writeFileSync as writeFileSync19
14595
15104
  } from "fs";
14596
15105
  import { createServer } from "http";
14597
15106
  import { join as join41 } from "path";
@@ -14671,12 +15180,12 @@ var init_pid_lock = __esm({
14671
15180
  */
14672
15181
  async acquire() {
14673
15182
  const stateDir = join41(this.pidPath, "..");
14674
- if (!existsSync34(stateDir)) {
15183
+ if (!existsSync35(stateDir)) {
14675
15184
  mkdirSync21(stateDir, { recursive: true });
14676
15185
  }
14677
- if (existsSync34(this.pidPath)) {
15186
+ if (existsSync35(this.pidPath)) {
14678
15187
  try {
14679
- const raw = readFileSync32(this.pidPath, "utf-8").trim();
15188
+ const raw = readFileSync33(this.pidPath, "utf-8").trim();
14680
15189
  const pidData = parsePidFile(raw);
14681
15190
  if (pidData && isProcessAlive(pidData.pid)) {
14682
15191
  if (pidData.healthPort) {
@@ -14736,7 +15245,7 @@ var init_pid_lock = __esm({
14736
15245
  startedAt: this.startedAt,
14737
15246
  healthPort: this.healthPort
14738
15247
  };
14739
- writeFileSync18(this.pidPath, JSON.stringify(data), "utf-8");
15248
+ writeFileSync19(this.pidPath, JSON.stringify(data), "utf-8");
14740
15249
  }
14741
15250
  async startHealthServer() {
14742
15251
  return new Promise((resolve3) => {
@@ -14781,8 +15290,8 @@ var init_pid_lock = __esm({
14781
15290
  this.healthServer = null;
14782
15291
  }
14783
15292
  try {
14784
- if (existsSync34(this.pidPath)) {
14785
- const raw = readFileSync32(this.pidPath, "utf-8").trim();
15293
+ if (existsSync35(this.pidPath)) {
15294
+ const raw = readFileSync33(this.pidPath, "utf-8").trim();
14786
15295
  const data = parsePidFile(raw);
14787
15296
  if (data && data.pid === process.pid) {
14788
15297
  unlinkSync6(this.pidPath);
@@ -14795,9 +15304,9 @@ var init_pid_lock = __esm({
14795
15304
  * Check if a proxy is currently running (for external callers).
14796
15305
  */
14797
15306
  isLocked() {
14798
- if (!existsSync34(this.pidPath)) return { locked: false };
15307
+ if (!existsSync35(this.pidPath)) return { locked: false };
14799
15308
  try {
14800
- const raw = readFileSync32(this.pidPath, "utf-8").trim();
15309
+ const raw = readFileSync33(this.pidPath, "utf-8").trim();
14801
15310
  const data = parsePidFile(raw);
14802
15311
  if (data && isProcessAlive(data.pid)) {
14803
15312
  return { locked: true, pid: data.pid, healthPort: data.healthPort };
@@ -14812,9 +15321,9 @@ var init_pid_lock = __esm({
14812
15321
  * Uses health check for full verification (unlike isLocked() which is sync-only).
14813
15322
  */
14814
15323
  async probe() {
14815
- if (!existsSync34(this.pidPath)) return { alive: false };
15324
+ if (!existsSync35(this.pidPath)) return { alive: false };
14816
15325
  try {
14817
- const raw = readFileSync32(this.pidPath, "utf-8").trim();
15326
+ const raw = readFileSync33(this.pidPath, "utf-8").trim();
14818
15327
  const pidData = parsePidFile(raw);
14819
15328
  if (!pidData || !isProcessAlive(pidData.pid)) return { alive: false };
14820
15329
  if (pidData.healthPort) {
@@ -14831,9 +15340,9 @@ var init_pid_lock = __esm({
14831
15340
  */
14832
15341
  static readPidFile(stateDir) {
14833
15342
  const pidPath = join41(stateDir, PID_FILENAME);
14834
- if (!existsSync34(pidPath)) return null;
15343
+ if (!existsSync35(pidPath)) return null;
14835
15344
  try {
14836
- const raw = readFileSync32(pidPath, "utf-8").trim();
15345
+ const raw = readFileSync33(pidPath, "utf-8").trim();
14837
15346
  const data = parsePidFile(raw);
14838
15347
  if (data && isProcessAlive(data.pid)) return data;
14839
15348
  return null;
@@ -15124,6 +15633,11 @@ var init_tool_definitions = __esm({
15124
15633
  description: "Direction of references: 'callers' (who calls this entity, default) or 'callees' (what this entity calls)",
15125
15634
  default: "callers"
15126
15635
  },
15636
+ limit: {
15637
+ type: "number",
15638
+ description: "Max number of references to return (default 25). Use higher values only when you need the full list.",
15639
+ default: 25
15640
+ },
15127
15641
  token_budget: TOKEN_BUDGET_PROP
15128
15642
  },
15129
15643
  required: ["key"]
@@ -15282,12 +15796,8 @@ var init_tool_definitions = __esm({
15282
15796
  },
15283
15797
  purpose: {
15284
15798
  type: "string",
15285
- enum: ["explore", "edit", "reference"],
15286
- description: "Read intent: 'explore' (default, budget-capped for browsing), 'edit' (full file, no gating \u2014 use when you plan to modify), 'reference' (entity/offset only, tight budget)"
15287
- },
15288
- force_full: {
15289
- type: "boolean",
15290
- description: "Force full file read even for large files (alias for purpose:'edit')"
15799
+ enum: ["explore", "reference"],
15800
+ description: "Read intent: 'explore' (default, budget-capped for browsing/understanding), 'reference' (entity/offset only, tight budget). To edit a file, use file_read(explore) to understand it, then built-in Read with offset/limit on the target lines, then Edit."
15291
15801
  },
15292
15802
  token_budget: TOKEN_BUDGET_PROP
15293
15803
  },
@@ -15640,7 +16150,7 @@ var init_deep_link = __esm({
15640
16150
  });
15641
16151
 
15642
16152
  // src/proxy/startup-renderer.ts
15643
- import { existsSync as existsSync35, readFileSync as readFileSync33, writeFileSync as writeFileSync19 } from "fs";
16153
+ import { existsSync as existsSync36, readFileSync as readFileSync34, writeFileSync as writeFileSync20 } from "fs";
15644
16154
  import { join as join42 } from "path";
15645
16155
  import React2 from "react";
15646
16156
  var StartupRenderer;
@@ -15753,9 +16263,9 @@ var init_startup_renderer = __esm({
15753
16263
  "state",
15754
16264
  "graph_version.json"
15755
16265
  );
15756
- if (!existsSync35(versionPath)) return true;
16266
+ if (!existsSync36(versionPath)) return true;
15757
16267
  try {
15758
- const data = JSON.parse(readFileSync33(versionPath, "utf-8"));
16268
+ const data = JSON.parse(readFileSync34(versionPath, "utf-8"));
15759
16269
  return !data.first_boot_shown;
15760
16270
  } catch {
15761
16271
  return true;
@@ -15766,11 +16276,11 @@ var init_startup_renderer = __esm({
15766
16276
  const versionPath = join42(stateDir, "graph_version.json");
15767
16277
  try {
15768
16278
  let data = {};
15769
- if (existsSync35(versionPath)) {
15770
- data = JSON.parse(readFileSync33(versionPath, "utf-8"));
16279
+ if (existsSync36(versionPath)) {
16280
+ data = JSON.parse(readFileSync34(versionPath, "utf-8"));
15771
16281
  }
15772
16282
  data.first_boot_shown = true;
15773
- writeFileSync19(versionPath, JSON.stringify(data, null, 2));
16283
+ writeFileSync20(versionPath, JSON.stringify(data, null, 2));
15774
16284
  } catch {
15775
16285
  }
15776
16286
  }
@@ -16041,13 +16551,13 @@ var init_lifecycle_actor = __esm({
16041
16551
  });
16042
16552
 
16043
16553
  // src/intelligence/facts-schema.ts
16044
- import { existsSync as existsSync36, mkdirSync as mkdirSync22 } from "fs";
16554
+ import { existsSync as existsSync37, mkdirSync as mkdirSync22 } from "fs";
16045
16555
  import { join as join43 } from "path";
16046
16556
  async function openFactsDb(projectRoot) {
16047
16557
  const unerrDir = join43(projectRoot, ".unerr");
16048
16558
  mkdirSync22(unerrDir, { recursive: true });
16049
16559
  const dbPath = join43(unerrDir, FACTS_DB_FILENAME);
16050
- const isNew = !existsSync36(dbPath);
16560
+ const isNew = !existsSync37(dbPath);
16051
16561
  const cozoModule = await import("cozo-node");
16052
16562
  const CozoDbConstructor = cozoModule.default ? cozoModule.default.CozoDb : cozoModule.CozoDb;
16053
16563
  const db = new CozoDbConstructor("sqlite", dbPath);
@@ -16648,7 +17158,7 @@ __export(fact_generator_exports, {
16648
17158
  generateFromSessionAnalysis: () => generateFromSessionAnalysis,
16649
17159
  runFactGenerationPipeline: () => runFactGenerationPipeline
16650
17160
  });
16651
- import { existsSync as existsSync37, readdirSync as readdirSync9, readFileSync as readFileSync34 } from "fs";
17161
+ import { existsSync as existsSync38, readdirSync as readdirSync9, readFileSync as readFileSync35 } from "fs";
16652
17162
  import { join as join44 } from "path";
16653
17163
  async function runFactGenerationPipeline(factStore2, unerrDir) {
16654
17164
  const results = [];
@@ -16801,13 +17311,13 @@ async function generateFromSessionAnalysis(factStore2, unerrDir) {
16801
17311
  }
16802
17312
  function loadRecentSessions(unerrDir, limit) {
16803
17313
  const sessionsDir = join44(unerrDir, "sessions");
16804
- if (!existsSync37(sessionsDir)) return [];
17314
+ if (!existsSync38(sessionsDir)) return [];
16805
17315
  try {
16806
17316
  const files = readdirSync9(sessionsDir).filter((f) => f.endsWith(".jsonl")).sort().slice(-limit);
16807
17317
  const summaries = [];
16808
17318
  for (const file of files) {
16809
17319
  try {
16810
- const content = readFileSync34(join44(sessionsDir, file), "utf-8");
17320
+ const content = readFileSync35(join44(sessionsDir, file), "utf-8");
16811
17321
  const lines = content.trim().split("\n").filter(Boolean);
16812
17322
  const lastLine = lines[lines.length - 1];
16813
17323
  if (lastLine) {
@@ -17331,7 +17841,7 @@ var init_model_pricing = __esm({
17331
17841
  });
17332
17842
 
17333
17843
  // src/tracking/entity-rewind.ts
17334
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync20 } from "fs";
17844
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync21 } from "fs";
17335
17845
  import { join as join45 } from "path";
17336
17846
  async function revertEntity(entityName, localGraph, projectRoot, filePath) {
17337
17847
  const driftEntity = await findDriftEntity(localGraph, entityName, filePath);
@@ -17409,12 +17919,12 @@ async function findDriftEntity(localGraph, entityName, filePath) {
17409
17919
  }
17410
17920
  async function removeAddedEntity(absPath, entity, localGraph) {
17411
17921
  try {
17412
- const content = readFileSync35(absPath, "utf-8");
17922
+ const content = readFileSync36(absPath, "utf-8");
17413
17923
  const lines = content.split("\n");
17414
17924
  const startIdx = entity.line_start - 1;
17415
17925
  const endIdx = entity.line_end;
17416
17926
  lines.splice(startIdx, endIdx - startIdx);
17417
- writeFileSync20(absPath, lines.join("\n"), "utf-8");
17927
+ writeFileSync21(absPath, lines.join("\n"), "utf-8");
17418
17928
  await localGraph.removeDriftEntity(entity.key);
17419
17929
  return {
17420
17930
  reverted: true,
@@ -17444,12 +17954,12 @@ async function restoreDeletedEntity(absPath, entity, localGraph) {
17444
17954
  };
17445
17955
  }
17446
17956
  try {
17447
- const content = readFileSync35(absPath, "utf-8");
17957
+ const content = readFileSync36(absPath, "utf-8");
17448
17958
  const lines = content.split("\n");
17449
17959
  const previousLines = entity.previous_body.split("\n");
17450
17960
  const insertIdx = Math.min(entity.line_start - 1, lines.length);
17451
17961
  lines.splice(insertIdx, 0, ...previousLines);
17452
- writeFileSync20(absPath, lines.join("\n"), "utf-8");
17962
+ writeFileSync21(absPath, lines.join("\n"), "utf-8");
17453
17963
  await localGraph.removeDriftEntity(entity.key);
17454
17964
  const endLine = insertIdx + previousLines.length;
17455
17965
  return {
@@ -17480,13 +17990,13 @@ async function restoreModifiedEntity(absPath, entity, localGraph) {
17480
17990
  };
17481
17991
  }
17482
17992
  try {
17483
- const content = readFileSync35(absPath, "utf-8");
17993
+ const content = readFileSync36(absPath, "utf-8");
17484
17994
  const lines = content.split("\n");
17485
17995
  const previousLines = entity.previous_body.split("\n");
17486
17996
  const startIdx = entity.line_start - 1;
17487
17997
  const deleteCount = entity.line_end - entity.line_start + 1;
17488
17998
  lines.splice(startIdx, deleteCount, ...previousLines);
17489
- writeFileSync20(absPath, lines.join("\n"), "utf-8");
17999
+ writeFileSync21(absPath, lines.join("\n"), "utf-8");
17490
18000
  await localGraph.removeDriftEntity(entity.key);
17491
18001
  const endLine = startIdx + previousLines.length;
17492
18002
  return {
@@ -17892,7 +18402,7 @@ __export(file_outline_exports, {
17892
18402
  buildFileOutline: () => buildFileOutline,
17893
18403
  fileOutlineTool: () => fileOutlineTool
17894
18404
  });
17895
- import { existsSync as existsSync38, readFileSync as readFileSync36 } from "fs";
18405
+ import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
17896
18406
  import { relative as relative2, resolve } from "path";
17897
18407
  function normRisk(rl) {
17898
18408
  const x2 = (rl ?? "low").toLowerCase();
@@ -17951,10 +18461,10 @@ function detectExportedNames(lines, scanLimit) {
17951
18461
  async function buildFileOutline(params) {
17952
18462
  const abs = resolve(params.cwd, params.filePathArg);
17953
18463
  const rel = relative2(params.cwd, abs).replace(/\\/g, "/") || params.filePathArg;
17954
- if (!existsSync38(abs)) {
18464
+ if (!existsSync39(abs)) {
17955
18465
  throw new Error(`File not found: ${abs}`);
17956
18466
  }
17957
- const raw = readFileSync36(abs);
18467
+ const raw = readFileSync37(abs);
17958
18468
  const sampleEnd = Math.min(raw.length, 8192);
17959
18469
  for (let i = 0; i < sampleEnd; i++) {
17960
18470
  if (raw[i] === 0) {
@@ -18102,7 +18612,7 @@ __export(file_read_protocol_exports, {
18102
18612
  runFileReadForRouter: () => runFileReadForRouter,
18103
18613
  runFileReadTool: () => runFileReadTool
18104
18614
  });
18105
- import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
18615
+ import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
18106
18616
  import { relative as relative3, resolve as resolve2 } from "path";
18107
18617
  function isGeneratedPath(rel) {
18108
18618
  return /(?:^|\/)node_modules\/|(?:^|\/)dist\/|\/\.next\/|\.generated\./.test(
@@ -18163,9 +18673,8 @@ function logFileRead(cwd, file, mode, totalLines, returnedLines, entity, tokenEs
18163
18673
  async function runFileReadForRouter(args, ctx) {
18164
18674
  const filePathArg = args.file_path;
18165
18675
  if (!filePathArg) throw new Error("file_read requires file_path");
18166
- const forceFull = args.force_full === true;
18167
- const purpose = args.purpose?.trim() || "explore";
18168
- const isFullRead = forceFull || purpose === "edit";
18676
+ const rawPurpose = args.purpose?.trim() || "explore";
18677
+ const purpose = rawPurpose === "edit" ? "explore" : rawPurpose;
18169
18678
  const entityName = args.entity?.trim();
18170
18679
  let entityWindowApplied = false;
18171
18680
  let entityMatchInfo;
@@ -18173,14 +18682,14 @@ async function runFileReadForRouter(args, ctx) {
18173
18682
  let limit = args.limit != null ? Math.min(MAX_READ_LINES, Math.max(1, Number(args.limit))) : void 0;
18174
18683
  const defaultBudget = purpose === "reference" ? 1e3 : 2e3;
18175
18684
  const tokenBudget = typeof args.token_budget === "number" && args.token_budget >= 100 ? args.token_budget : defaultBudget;
18176
- const budgetLines = isFullRead ? MAX_READ_LINES : Math.floor(tokenBudget * CHARS_PER_TOKEN4 / AVG_CHARS_PER_LINE);
18685
+ const budgetLines = Math.floor(tokenBudget * CHARS_PER_TOKEN4 / AVG_CHARS_PER_LINE);
18177
18686
  const abs = resolve2(ctx.cwd, filePathArg);
18178
18687
  const rel = relative3(ctx.cwd, abs).replace(/\\/g, "/") || filePathArg;
18179
18688
  const isOutOfProject = rel.startsWith("..");
18180
- if (!existsSync39(abs)) {
18689
+ if (!existsSync40(abs)) {
18181
18690
  return { content: { error: `File not found: ${abs}` } };
18182
18691
  }
18183
- const raw = readFileSync37(abs);
18692
+ const raw = readFileSync38(abs);
18184
18693
  const sampleEnd = Math.min(raw.length, 8192);
18185
18694
  for (let i = 0; i < sampleEnd; i++) {
18186
18695
  if (raw[i] === 0) {
@@ -18196,7 +18705,7 @@ async function runFileReadForRouter(args, ctx) {
18196
18705
  const lines = text2.split("\n");
18197
18706
  const totalLines = lines.length;
18198
18707
  const effectiveGate = Math.max(LINE_GATE, Math.min(HARD_GATE_CEILING, budgetLines));
18199
- if (totalLines > effectiveGate && totalLines > LINE_GATE && offset === void 0 && !entityName && !isFullRead) {
18708
+ if (totalLines > effectiveGate && totalLines > LINE_GATE && offset === void 0 && !entityName && !entityName) {
18200
18709
  const outline = await buildFileOutline({
18201
18710
  cwd: ctx.cwd,
18202
18711
  filePathArg,
@@ -18207,7 +18716,7 @@ async function runFileReadForRouter(args, ctx) {
18207
18716
  content: {
18208
18717
  ...outline,
18209
18718
  gated: true,
18210
- _gate_reason: `File has ${totalLines} lines (> ${effectiveGate}). Structure shown \u2014 call file_read again with entity or offset/limit, or force_full:true. NOTE: If you plan to Edit this file, you MUST call built-in Read (not file_read) on the target lines first.`
18719
+ _gate_reason: `File has ${totalLines} lines (> ${effectiveGate}). Structure shown \u2014 call file_read again with entity or offset/limit for targeted access.`
18211
18720
  },
18212
18721
  _layer6_meta: {
18213
18722
  format: "outline",
@@ -18345,7 +18854,7 @@ async function runFileReadForRouter(args, ctx) {
18345
18854
  limit = LOG_TAIL_LINES;
18346
18855
  }
18347
18856
  const effOffset = offset ?? 1;
18348
- const effLimit = limit ?? (isFullRead ? totalLines : Math.min(budgetLines, totalLines));
18857
+ const effLimit = limit ?? Math.min(budgetLines, totalLines);
18349
18858
  const sliced = lines.slice(effOffset - 1, effOffset - 1 + effLimit);
18350
18859
  const numbered = sliced.map((line, i) => `${effOffset + i} ${line}`).join("\n");
18351
18860
  let body = effOffset > 1 || sliced.length < totalLines || entityWindowApplied ? `${numbered}
@@ -18375,10 +18884,7 @@ ${body}`;
18375
18884
  total_lines: totalLines,
18376
18885
  total_chars: text2.length
18377
18886
  };
18378
- if (isFullRead && sliced.length === totalLines) {
18379
- meta.optimization = `file_read full (purpose:${purpose})`;
18380
- meta._edit_note = "file_read does NOT satisfy Edit's Read prerequisite. You must still call built-in Read before using Edit on this file.";
18381
- } else if (effOffset > 1 || sliced.length < totalLines || entityWindowApplied) {
18887
+ if (effOffset > 1 || sliced.length < totalLines || entityWindowApplied) {
18382
18888
  meta.optimization = `file_read window lines ${effOffset}-${effOffset + sliced.length - 1}`;
18383
18889
  }
18384
18890
  if (entityWindowApplied) {
@@ -18390,6 +18896,10 @@ ${body}`;
18390
18896
  if (isProbableLogPath(rel) && offset !== void 0 && totalLines > LINE_GATE) {
18391
18897
  meta.optimization = `${meta.optimization ?? "file_read"} \xB7 log_tail`;
18392
18898
  }
18899
+ if (isOutOfProject) {
18900
+ meta.out_of_project = true;
18901
+ meta._hint = "File is outside the indexed project. Graph features (references, callers) unavailable.";
18902
+ }
18393
18903
  const returnedLineCount = sliced.length;
18394
18904
  const readMode = entityWindowApplied ? "entity" : isProbableLogPath(rel) && offset !== void 0 && totalLines > LINE_GATE ? "log_tail" : effOffset > 1 || returnedLineCount < totalLines ? "slice" : "full";
18395
18905
  logFileRead(
@@ -19943,11 +20453,11 @@ var init_query_router = __esm({
19943
20453
  const entity = await this.resolveEntityWithOverlay(key);
19944
20454
  if (entity && entity.file_path && entity.start_line > 0) {
19945
20455
  try {
19946
- const { readFileSync: readFileSync57 } = await import("fs");
20456
+ const { readFileSync: readFileSync58 } = await import("fs");
19947
20457
  const { resolve: resolve3 } = await import("path");
19948
20458
  const cwd = this.projectRoot ?? process.cwd();
19949
20459
  const abs = resolve3(cwd, entity.file_path);
19950
- const lines = readFileSync57(abs, "utf-8").split("\n");
20460
+ const lines = readFileSync58(abs, "utf-8").split("\n");
19951
20461
  const start = entity.start_line - 1;
19952
20462
  const end = entity.end_line ?? lines.length;
19953
20463
  entity.body = lines.slice(start, end).join("\n");
@@ -19959,15 +20469,29 @@ var init_query_router = __esm({
19959
20469
  case "get_references": {
19960
20470
  const key = await this.resolveKeyArg(args.key);
19961
20471
  const direction = args.direction ?? "callers";
19962
- return direction === "callees" ? await this.localGraph.getCalleesOf(key) : await this.localGraph.getCallersOf(key);
20472
+ const limit = typeof args.limit === "number" && args.limit > 0 ? args.limit : 25;
20473
+ const raw = direction === "callees" ? await this.localGraph.getCalleesOf(key) : await this.localGraph.getCallersOf(key);
20474
+ const totalCount = raw.length;
20475
+ const capped = raw.slice(0, limit);
20476
+ const results = capped.map(({ body: _body, ...rest }) => rest);
20477
+ return {
20478
+ references: results,
20479
+ direction,
20480
+ total: totalCount,
20481
+ returned: results.length,
20482
+ truncated: totalCount > limit,
20483
+ ...totalCount > limit ? { _hint: `Showing ${limit} of ${totalCount}. Pass limit: ${totalCount} to see all.` } : {}
20484
+ };
19963
20485
  }
19964
20486
  case "get_callers": {
19965
20487
  const key = await this.resolveKeyArg(args.key);
19966
- return await this.localGraph.getCallersOf(key);
20488
+ const rawCallers = await this.localGraph.getCallersOf(key);
20489
+ return rawCallers.slice(0, 25).map(({ body: _body, ...rest }) => rest);
19967
20490
  }
19968
20491
  case "get_callees": {
19969
20492
  const key = await this.resolveKeyArg(args.key);
19970
- return await this.localGraph.getCalleesOf(key);
20493
+ const rawCallees = await this.localGraph.getCalleesOf(key);
20494
+ return rawCallees.slice(0, 25).map(({ body: _body, ...rest }) => rest);
19971
20495
  }
19972
20496
  case "get_imports": {
19973
20497
  const filePath = args.file_path;
@@ -20000,6 +20524,14 @@ var init_query_router = __esm({
20000
20524
  { entityKey: entityKey2, exceptions }
20001
20525
  );
20002
20526
  }
20527
+ if (filePath && (filePath.endsWith("/") || !/\.\w+$/.test(filePath))) {
20528
+ const dirPrefix = filePath.endsWith("/") ? filePath : `${filePath}/`;
20529
+ const allRules = await this.localGraph.getRules();
20530
+ return allRules.filter((rule) => {
20531
+ if (!rule.file_glob) return true;
20532
+ return rule.file_glob.includes(dirPrefix) || rule.file_glob.startsWith(dirPrefix) || dirPrefix.startsWith(rule.file_glob.replace(/\*.*$/, ""));
20533
+ });
20534
+ }
20003
20535
  return await this.localGraph.getRules(filePath);
20004
20536
  }
20005
20537
  case "check_rules": {
@@ -20035,7 +20567,37 @@ var init_query_router = __esm({
20035
20567
  if (!raw)
20036
20568
  throw new Error("get_business_context requires key or entity_key");
20037
20569
  const key = await this.resolveKeyArg(raw);
20038
- return await this.localGraph.getBusinessContext(key);
20570
+ const stored = await this.localGraph.getBusinessContext(key);
20571
+ if (stored) return stored;
20572
+ const entity = await this.localGraph.getEntity(key);
20573
+ if (!entity) return { error: `Entity not found: ${raw}` };
20574
+ const callers = await this.localGraph.getCallersOf(key);
20575
+ const callees = await this.localGraph.getCalleesOf(key);
20576
+ const pathParts = entity.file_path.split("/");
20577
+ const dirHint = pathParts.slice(-3, -1).join("/");
20578
+ const featureArea = dirHint || "root";
20579
+ let purpose;
20580
+ if (callers.length === 0 && callees.length > 0)
20581
+ purpose = "Entry point / top-level orchestrator";
20582
+ else if (callers.length > 5)
20583
+ purpose = `Widely-used utility (${callers.length} callers)`;
20584
+ else if (callees.length === 0 && callers.length > 0)
20585
+ purpose = "Leaf function (no outgoing calls)";
20586
+ else if (callers.length > 0 && callees.length > 0)
20587
+ purpose = `Internal function (${callers.length} callers, ${callees.length} callees)`;
20588
+ else
20589
+ purpose = "Standalone / unused function";
20590
+ return {
20591
+ purpose,
20592
+ taxonomy: `${entity.kind}/${featureArea}`,
20593
+ feature_area: featureArea,
20594
+ confidence: 0.3,
20595
+ entity,
20596
+ _source: "inferred",
20597
+ _hint: "This context was inferred from graph structure. Use record_fact to store explicit business context.",
20598
+ callers_count: callers.length,
20599
+ callees_count: callees.length
20600
+ };
20039
20601
  }
20040
20602
  case "get_conventions": {
20041
20603
  return await this.localGraph.getConventions();
@@ -20164,6 +20726,18 @@ var init_query_router = __esm({
20164
20726
  throw new Error(`Unknown local tool: ${toolName}`);
20165
20727
  }
20166
20728
  }
20729
+ /**
20730
+ * Get entity keys for a file path (from file_index).
20731
+ * Used by fact injection to call recallForFile with entity-scoped facts.
20732
+ */
20733
+ async getEntityKeysForFile(filePath) {
20734
+ try {
20735
+ const results = await this.localGraph.getEntitiesByFile(filePath);
20736
+ return results.map((e) => e.key);
20737
+ } catch {
20738
+ return [];
20739
+ }
20740
+ }
20167
20741
  /**
20168
20742
  * Resolve a key argument: if it looks like a hex hash (entity key), use as-is.
20169
20743
  * Otherwise, search by name and return the best match's key.
@@ -21473,7 +22047,7 @@ __export(causal_bridge_exports, {
21473
22047
  assembleCausalChain: () => assembleCausalChain,
21474
22048
  computeDurability: () => computeDurability
21475
22049
  });
21476
- import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
22050
+ import { existsSync as existsSync41, readFileSync as readFileSync39 } from "fs";
21477
22051
  import { join as join46 } from "path";
21478
22052
  function computeAggregateDurability(interactions) {
21479
22053
  if (interactions.length === 0) return 1;
@@ -21632,8 +22206,8 @@ var init_causal_bridge = __esm({
21632
22206
  }
21633
22207
  loadEntityLedgerEntries(entityKey2) {
21634
22208
  const ledgerPath = join46(this.unerrDir, "ledger", "shadow.jsonl");
21635
- if (!existsSync40(ledgerPath)) return [];
21636
- const content = readFileSync38(ledgerPath, "utf-8");
22209
+ if (!existsSync41(ledgerPath)) return [];
22210
+ const content = readFileSync39(ledgerPath, "utf-8");
21637
22211
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
21638
22212
  const entries = [];
21639
22213
  for (const line of lines) {
@@ -22119,7 +22693,7 @@ var context_ledger_exports = {};
22119
22693
  __export(context_ledger_exports, {
22120
22694
  createContextLedger: () => createContextLedger
22121
22695
  });
22122
- import { existsSync as existsSync41, mkdirSync as mkdirSync23, readFileSync as readFileSync39, writeFileSync as writeFileSync21 } from "fs";
22696
+ import { existsSync as existsSync42, mkdirSync as mkdirSync23, readFileSync as readFileSync40, writeFileSync as writeFileSync22 } from "fs";
22123
22697
  import { join as join47 } from "path";
22124
22698
  function createContextLedger(unerrDir) {
22125
22699
  const stateDir = join47(unerrDir, "state");
@@ -22127,7 +22701,7 @@ function createContextLedger(unerrDir) {
22127
22701
  let records = [];
22128
22702
  let index = /* @__PURE__ */ new Map();
22129
22703
  function ensureDir() {
22130
- if (!existsSync41(stateDir)) {
22704
+ if (!existsSync42(stateDir)) {
22131
22705
  mkdirSync23(stateDir, { recursive: true });
22132
22706
  }
22133
22707
  }
@@ -22136,13 +22710,13 @@ function createContextLedger(unerrDir) {
22136
22710
  }
22137
22711
  function load() {
22138
22712
  ensureDir();
22139
- if (!existsSync41(filePath)) {
22713
+ if (!existsSync42(filePath)) {
22140
22714
  records = [];
22141
22715
  index = /* @__PURE__ */ new Map();
22142
22716
  return /* @__PURE__ */ new Map();
22143
22717
  }
22144
22718
  try {
22145
- const raw = readFileSync39(filePath, "utf-8");
22719
+ const raw = readFileSync40(filePath, "utf-8");
22146
22720
  const parsed = JSON.parse(raw);
22147
22721
  records = Array.isArray(parsed) ? parsed : [];
22148
22722
  } catch {
@@ -22178,7 +22752,7 @@ function createContextLedger(unerrDir) {
22178
22752
  records = newRecords;
22179
22753
  index = delivered;
22180
22754
  try {
22181
- writeFileSync21(filePath, JSON.stringify(records, null, 2), "utf-8");
22755
+ writeFileSync22(filePath, JSON.stringify(records, null, 2), "utf-8");
22182
22756
  } catch {
22183
22757
  }
22184
22758
  }
@@ -23049,11 +23623,11 @@ __export(intent_correlator_exports, {
23049
23623
  IntentCorrelator: () => IntentCorrelator
23050
23624
  });
23051
23625
  import {
23052
- existsSync as existsSync42,
23626
+ existsSync as existsSync43,
23053
23627
  mkdirSync as mkdirSync24,
23054
- readFileSync as readFileSync40,
23628
+ readFileSync as readFileSync41,
23055
23629
  renameSync,
23056
- writeFileSync as writeFileSync22
23630
+ writeFileSync as writeFileSync23
23057
23631
  } from "fs";
23058
23632
  import { join as join48 } from "path";
23059
23633
  function extractFiles4(args) {
@@ -23105,7 +23679,7 @@ var init_intent_correlator = __esm({
23105
23679
  constructor(unerrDir) {
23106
23680
  this.ledgerDir = join48(unerrDir, "ledger");
23107
23681
  this.pendingPath = join48(this.ledgerDir, "pending_correlations.json");
23108
- if (!existsSync42(this.ledgerDir)) {
23682
+ if (!existsSync43(this.ledgerDir)) {
23109
23683
  mkdirSync24(this.ledgerDir, { recursive: true });
23110
23684
  }
23111
23685
  this.load();
@@ -23197,9 +23771,9 @@ var init_intent_correlator = __esm({
23197
23771
  }
23198
23772
  // ── Persistence ─────────────────────────────────────────────────
23199
23773
  load() {
23200
- if (!existsSync42(this.pendingPath)) return;
23774
+ if (!existsSync43(this.pendingPath)) return;
23201
23775
  try {
23202
- const raw = readFileSync40(this.pendingPath, "utf-8");
23776
+ const raw = readFileSync41(this.pendingPath, "utf-8");
23203
23777
  const parsed = JSON.parse(raw);
23204
23778
  if (Array.isArray(parsed)) {
23205
23779
  this.pending = parsed;
@@ -23211,7 +23785,7 @@ var init_intent_correlator = __esm({
23211
23785
  save() {
23212
23786
  try {
23213
23787
  const tmpPath = `${this.pendingPath}.tmp`;
23214
- writeFileSync22(tmpPath, JSON.stringify(this.pending, null, 2), "utf-8");
23788
+ writeFileSync23(tmpPath, JSON.stringify(this.pending, null, 2), "utf-8");
23215
23789
  renameSync(tmpPath, this.pendingPath);
23216
23790
  } catch (err) {
23217
23791
  process.stderr.write(
@@ -23231,12 +23805,12 @@ __export(working_snapshots_exports, {
23231
23805
  });
23232
23806
  import { randomBytes as randomBytes3 } from "crypto";
23233
23807
  import {
23234
- existsSync as existsSync43,
23808
+ existsSync as existsSync44,
23235
23809
  mkdirSync as mkdirSync25,
23236
- readFileSync as readFileSync41,
23810
+ readFileSync as readFileSync42,
23237
23811
  readdirSync as readdirSync10,
23238
23812
  rmSync as rmSync2,
23239
- writeFileSync as writeFileSync23
23813
+ writeFileSync as writeFileSync24
23240
23814
  } from "fs";
23241
23815
  import { join as join49 } from "path";
23242
23816
  var _log2, MAX_SNAPSHOTS, AUTO_SNAPSHOT_COOLDOWN_MS, WorkingSnapshotStore;
@@ -23257,7 +23831,7 @@ var init_working_snapshots = __esm({
23257
23831
  constructor(unerrDir) {
23258
23832
  this.unerrDir = unerrDir;
23259
23833
  this.snapshotDir = join49(unerrDir, "snapshots");
23260
- if (!existsSync43(this.snapshotDir)) {
23834
+ if (!existsSync44(this.snapshotDir)) {
23261
23835
  mkdirSync25(this.snapshotDir, { recursive: true });
23262
23836
  }
23263
23837
  }
@@ -23276,7 +23850,7 @@ var init_working_snapshots = __esm({
23276
23850
  sessionId: opts.sessionId,
23277
23851
  processed: false
23278
23852
  };
23279
- writeFileSync23(
23853
+ writeFileSync24(
23280
23854
  join49(this.snapshotDir, `${id}.json`),
23281
23855
  JSON.stringify(snapshot, null, 2),
23282
23856
  "utf-8"
@@ -23292,9 +23866,9 @@ var init_working_snapshots = __esm({
23292
23866
  */
23293
23867
  get(snapshotId) {
23294
23868
  const filePath = join49(this.snapshotDir, `${snapshotId}.json`);
23295
- if (!existsSync43(filePath)) return null;
23869
+ if (!existsSync44(filePath)) return null;
23296
23870
  try {
23297
- return JSON.parse(readFileSync41(filePath, "utf-8"));
23871
+ return JSON.parse(readFileSync42(filePath, "utf-8"));
23298
23872
  } catch {
23299
23873
  return null;
23300
23874
  }
@@ -23303,14 +23877,14 @@ var init_working_snapshots = __esm({
23303
23877
  * List all snapshots, most recent first.
23304
23878
  */
23305
23879
  list() {
23306
- if (!existsSync43(this.snapshotDir)) return [];
23880
+ if (!existsSync44(this.snapshotDir)) return [];
23307
23881
  const files = readdirSync10(this.snapshotDir).filter(
23308
23882
  (f) => f.endsWith(".json")
23309
23883
  );
23310
23884
  const snapshots = [];
23311
23885
  for (const file of files) {
23312
23886
  try {
23313
- const raw = readFileSync41(join49(this.snapshotDir, file), "utf-8");
23887
+ const raw = readFileSync42(join49(this.snapshotDir, file), "utf-8");
23314
23888
  snapshots.push(JSON.parse(raw));
23315
23889
  } catch {
23316
23890
  }
@@ -23350,7 +23924,7 @@ var init_working_snapshots = __esm({
23350
23924
  const snapshot = this.get(snapshotId);
23351
23925
  if (!snapshot) return;
23352
23926
  snapshot.processed = true;
23353
- writeFileSync23(
23927
+ writeFileSync24(
23354
23928
  join49(this.snapshotDir, `${snapshotId}.json`),
23355
23929
  JSON.stringify(snapshot, null, 2),
23356
23930
  "utf-8"
@@ -23367,7 +23941,7 @@ var init_working_snapshots = __esm({
23367
23941
  */
23368
23942
  delete(snapshotId) {
23369
23943
  const filePath = join49(this.snapshotDir, `${snapshotId}.json`);
23370
- if (!existsSync43(filePath)) return false;
23944
+ if (!existsSync44(filePath)) return false;
23371
23945
  rmSync2(filePath);
23372
23946
  return true;
23373
23947
  }
@@ -23376,9 +23950,9 @@ var init_working_snapshots = __esm({
23376
23950
  */
23377
23951
  getTimelineBranch() {
23378
23952
  const contextPath = join49(this.unerrDir, "branch_context.json");
23379
- if (!existsSync43(contextPath)) return 0;
23953
+ if (!existsSync44(contextPath)) return 0;
23380
23954
  try {
23381
- const ctx = JSON.parse(readFileSync41(contextPath, "utf-8"));
23955
+ const ctx = JSON.parse(readFileSync42(contextPath, "utf-8"));
23382
23956
  return ctx.timelineBranch ?? 0;
23383
23957
  } catch {
23384
23958
  return 0;
@@ -23390,16 +23964,16 @@ var init_working_snapshots = __esm({
23390
23964
  incrementTimelineBranch() {
23391
23965
  const contextPath = join49(this.unerrDir, "branch_context.json");
23392
23966
  let ctx = {};
23393
- if (existsSync43(contextPath)) {
23967
+ if (existsSync44(contextPath)) {
23394
23968
  try {
23395
- ctx = JSON.parse(readFileSync41(contextPath, "utf-8"));
23969
+ ctx = JSON.parse(readFileSync42(contextPath, "utf-8"));
23396
23970
  } catch {
23397
23971
  ctx = {};
23398
23972
  }
23399
23973
  }
23400
23974
  const current = ctx.timelineBranch ?? 0;
23401
23975
  ctx.timelineBranch = current + 1;
23402
- writeFileSync23(contextPath, JSON.stringify(ctx, null, 2), "utf-8");
23976
+ writeFileSync24(contextPath, JSON.stringify(ctx, null, 2), "utf-8");
23403
23977
  return current + 1;
23404
23978
  }
23405
23979
  /**
@@ -23565,7 +24139,7 @@ var quality_signals_exports = {};
23565
24139
  __export(quality_signals_exports, {
23566
24140
  QualitySignalTracker: () => QualitySignalTracker
23567
24141
  });
23568
- import { existsSync as existsSync44, readFileSync as readFileSync42, writeFileSync as writeFileSync24 } from "fs";
24142
+ import { existsSync as existsSync45, readFileSync as readFileSync43, writeFileSync as writeFileSync25 } from "fs";
23569
24143
  import { join as join50 } from "path";
23570
24144
  function computeDurabilityFromAge(survivalMs) {
23571
24145
  if (survivalMs < FRAGILE_THRESHOLD_MS) {
@@ -23686,11 +24260,11 @@ var init_quality_signals = __esm({
23686
24260
  save() {
23687
24261
  try {
23688
24262
  const dir = join50(this.signalsPath, "..");
23689
- if (!existsSync44(dir)) {
24263
+ if (!existsSync45(dir)) {
23690
24264
  const { mkdirSync: mkdirSync39 } = __require("fs");
23691
24265
  mkdirSync39(dir, { recursive: true });
23692
24266
  }
23693
- writeFileSync24(
24267
+ writeFileSync25(
23694
24268
  this.signalsPath,
23695
24269
  JSON.stringify(this.signals, null, 2),
23696
24270
  "utf-8"
@@ -23732,7 +24306,7 @@ var init_quality_signals = __esm({
23732
24306
  * Load signals from disk.
23733
24307
  */
23734
24308
  load() {
23735
- if (!existsSync44(this.signalsPath)) {
24309
+ if (!existsSync45(this.signalsPath)) {
23736
24310
  return {
23737
24311
  durabilityScores: {},
23738
24312
  corrections: [],
@@ -23741,7 +24315,7 @@ var init_quality_signals = __esm({
23741
24315
  }
23742
24316
  try {
23743
24317
  return JSON.parse(
23744
- readFileSync42(this.signalsPath, "utf-8")
24318
+ readFileSync43(this.signalsPath, "utf-8")
23745
24319
  );
23746
24320
  } catch {
23747
24321
  return {
@@ -24758,7 +25332,7 @@ var incomplete_work_exports = {};
24758
25332
  __export(incomplete_work_exports, {
24759
25333
  IncompleteWorkDetector: () => IncompleteWorkDetector
24760
25334
  });
24761
- import { existsSync as existsSync45, mkdirSync as mkdirSync26, readFileSync as readFileSync43, writeFileSync as writeFileSync25 } from "fs";
25335
+ import { existsSync as existsSync46, mkdirSync as mkdirSync26, readFileSync as readFileSync44, writeFileSync as writeFileSync26 } from "fs";
24762
25336
  import { join as join51 } from "path";
24763
25337
  function severityRank(severity) {
24764
25338
  switch (severity) {
@@ -24953,9 +25527,9 @@ var init_incomplete_work = __esm({
24953
25527
  if (!this.unerrDir) return false;
24954
25528
  try {
24955
25529
  const stateDir = join51(this.unerrDir, "state");
24956
- if (!existsSync45(stateDir)) mkdirSync26(stateDir, { recursive: true });
25530
+ if (!existsSync46(stateDir)) mkdirSync26(stateDir, { recursive: true });
24957
25531
  const filePath = join51(stateDir, PERSISTENCE_FILE);
24958
- writeFileSync25(
25532
+ writeFileSync26(
24959
25533
  filePath,
24960
25534
  JSON.stringify({
24961
25535
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -24975,8 +25549,8 @@ var init_incomplete_work = __esm({
24975
25549
  static readPersistedItems(unerrDir) {
24976
25550
  try {
24977
25551
  const filePath = join51(unerrDir, "state", PERSISTENCE_FILE);
24978
- if (!existsSync45(filePath)) return [];
24979
- const data = JSON.parse(readFileSync43(filePath, "utf-8"));
25552
+ if (!existsSync46(filePath)) return [];
25553
+ const data = JSON.parse(readFileSync44(filePath, "utf-8"));
24980
25554
  return data.items ?? [];
24981
25555
  } catch {
24982
25556
  return [];
@@ -26447,7 +27021,7 @@ var transport_mux_exports = {};
26447
27021
  __export(transport_mux_exports, {
26448
27022
  TransportMux: () => TransportMux
26449
27023
  });
26450
- import { existsSync as existsSync46, unlinkSync as unlinkSync7 } from "fs";
27024
+ import { existsSync as existsSync47, unlinkSync as unlinkSync7 } from "fs";
26451
27025
  import { createServer as createServer2 } from "net";
26452
27026
  var _log4, TransportMux;
26453
27027
  var init_transport_mux = __esm({
@@ -26487,7 +27061,7 @@ var init_transport_mux = __esm({
26487
27061
  * Start listening for secondary clients on the Unix domain socket.
26488
27062
  */
26489
27063
  start() {
26490
- if (existsSync46(this.sockPath)) {
27064
+ if (existsSync47(this.sockPath)) {
26491
27065
  try {
26492
27066
  unlinkSync7(this.sockPath);
26493
27067
  } catch {
@@ -26520,7 +27094,7 @@ var init_transport_mux = __esm({
26520
27094
  this.server.close();
26521
27095
  this.server = null;
26522
27096
  }
26523
- if (existsSync46(this.sockPath)) {
27097
+ if (existsSync47(this.sockPath)) {
26524
27098
  try {
26525
27099
  unlinkSync7(this.sockPath);
26526
27100
  } catch {
@@ -26668,7 +27242,7 @@ __export(git_trailers_exports, {
26668
27242
  parseTrailersFromMessage: () => parseTrailersFromMessage,
26669
27243
  uninstallPrepareCommitMsgHook: () => uninstallPrepareCommitMsgHook
26670
27244
  });
26671
- import { existsSync as existsSync47, readFileSync as readFileSync44, writeFileSync as writeFileSync26 } from "fs";
27245
+ import { existsSync as existsSync48, readFileSync as readFileSync45, writeFileSync as writeFileSync27 } from "fs";
26672
27246
  import { join as join52 } from "path";
26673
27247
  function getCommitTrailers(ledger, timelineBranch, branch) {
26674
27248
  const recent = ledger.getRecentEntries(1);
@@ -26690,14 +27264,14 @@ function formatTrailers(trailers) {
26690
27264
  }
26691
27265
  function installPrepareCommitMsgHook(projectRoot) {
26692
27266
  const hooksDir = join52(projectRoot, ".git", "hooks");
26693
- if (!existsSync47(hooksDir)) {
27267
+ if (!existsSync48(hooksDir)) {
26694
27268
  return false;
26695
27269
  }
26696
27270
  const hookPath = join52(hooksDir, "prepare-commit-msg");
26697
27271
  const marker = "# unerr-trailer-injection";
26698
- if (existsSync47(hookPath)) {
27272
+ if (existsSync48(hookPath)) {
26699
27273
  try {
26700
- const existing = readFileSync44(hookPath, "utf-8");
27274
+ const existing = readFileSync45(hookPath, "utf-8");
26701
27275
  if (existing.includes(marker)) {
26702
27276
  return true;
26703
27277
  }
@@ -26705,7 +27279,7 @@ function installPrepareCommitMsgHook(projectRoot) {
26705
27279
 
26706
27280
  ${marker}
26707
27281
  ${generateHookScript()}`;
26708
- writeFileSync26(hookPath, existing + appendSection, { mode: 493 });
27282
+ writeFileSync27(hookPath, existing + appendSection, { mode: 493 });
26709
27283
  _log5.info(
26710
27284
  "Appended trailer injection to existing prepare-commit-msg hook"
26711
27285
  );
@@ -26718,7 +27292,7 @@ ${generateHookScript()}`;
26718
27292
  ${marker}
26719
27293
  ${generateHookScript()}`;
26720
27294
  try {
26721
- writeFileSync26(hookPath, hookContent, { mode: 493 });
27295
+ writeFileSync27(hookPath, hookContent, { mode: 493 });
26722
27296
  _log5.info("Installed prepare-commit-msg hook for trailer injection");
26723
27297
  return true;
26724
27298
  } catch {
@@ -26727,9 +27301,9 @@ ${generateHookScript()}`;
26727
27301
  }
26728
27302
  function uninstallPrepareCommitMsgHook(projectRoot) {
26729
27303
  const hookPath = join52(projectRoot, ".git", "hooks", "prepare-commit-msg");
26730
- if (!existsSync47(hookPath)) return true;
27304
+ if (!existsSync48(hookPath)) return true;
26731
27305
  try {
26732
- const content = readFileSync44(hookPath, "utf-8");
27306
+ const content = readFileSync45(hookPath, "utf-8");
26733
27307
  const marker = "# unerr-trailer-injection";
26734
27308
  if (!content.includes(marker)) return true;
26735
27309
  const lines = content.split("\n");
@@ -26742,7 +27316,7 @@ function uninstallPrepareCommitMsgHook(projectRoot) {
26742
27316
  } else {
26743
27317
  const markerIdx = content.indexOf(marker);
26744
27318
  if (markerIdx > 0) {
26745
- writeFileSync26(hookPath, `${content.slice(0, markerIdx).trimEnd()}
27319
+ writeFileSync27(hookPath, `${content.slice(0, markerIdx).trimEnd()}
26746
27320
  `, {
26747
27321
  mode: 493
26748
27322
  });
@@ -26894,13 +27468,13 @@ var init_http_transport = __esm({
26894
27468
 
26895
27469
  // src/tracking/branch-snapshot.ts
26896
27470
  import {
26897
- existsSync as existsSync48,
27471
+ existsSync as existsSync49,
26898
27472
  mkdirSync as mkdirSync28,
26899
- readFileSync as readFileSync45,
27473
+ readFileSync as readFileSync46,
26900
27474
  readdirSync as readdirSync11,
26901
27475
  rmSync as rmSync3,
26902
27476
  statSync as statSync7,
26903
- writeFileSync as writeFileSync27
27477
+ writeFileSync as writeFileSync28
26904
27478
  } from "fs";
26905
27479
  import { join as join53 } from "path";
26906
27480
  function sanitizeBranchName(branch) {
@@ -26935,7 +27509,7 @@ var init_branch_snapshot = __esm({
26935
27509
  }
26936
27510
  const dirName = sanitizeBranchName(branch);
26937
27511
  const snapshotDir = join53(this.branchDir, dirName);
26938
- if (!existsSync48(snapshotDir)) {
27512
+ if (!existsSync49(snapshotDir)) {
26939
27513
  mkdirSync28(snapshotDir, { recursive: true });
26940
27514
  }
26941
27515
  const snapshot = {
@@ -26945,12 +27519,12 @@ var init_branch_snapshot = __esm({
26945
27519
  fileHashes: fileHashState,
26946
27520
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
26947
27521
  };
26948
- writeFileSync27(
27522
+ writeFileSync28(
26949
27523
  join53(snapshotDir, OVERLAY_FILE),
26950
27524
  JSON.stringify(snapshot, null, 2),
26951
27525
  "utf-8"
26952
27526
  );
26953
- writeFileSync27(
27527
+ writeFileSync28(
26954
27528
  join53(snapshotDir, HASHES_FILE),
26955
27529
  JSON.stringify(fileHashState, null, 2),
26956
27530
  "utf-8"
@@ -26969,12 +27543,12 @@ var init_branch_snapshot = __esm({
26969
27543
  const dirName = sanitizeBranchName(branch);
26970
27544
  const snapshotDir = join53(this.branchDir, dirName);
26971
27545
  const overlayPath = join53(snapshotDir, OVERLAY_FILE);
26972
- if (!existsSync48(overlayPath)) {
27546
+ if (!existsSync49(overlayPath)) {
26973
27547
  log16.info(`No snapshot for branch ${branch} \u2014 first visit`);
26974
27548
  return null;
26975
27549
  }
26976
27550
  try {
26977
- const raw = readFileSync45(overlayPath, "utf-8");
27551
+ const raw = readFileSync46(overlayPath, "utf-8");
26978
27552
  const snapshot = JSON.parse(raw);
26979
27553
  for (const entity of snapshot.entities) {
26980
27554
  await localGraph.upsertDriftEntity(entity);
@@ -26985,7 +27559,7 @@ var init_branch_snapshot = __esm({
26985
27559
  }
26986
27560
  }
26987
27561
  const now = /* @__PURE__ */ new Date();
26988
- writeFileSync27(
27562
+ writeFileSync28(
26989
27563
  join53(snapshotDir, ".last_access"),
26990
27564
  now.toISOString(),
26991
27565
  "utf-8"
@@ -27006,7 +27580,7 @@ var init_branch_snapshot = __esm({
27006
27580
  */
27007
27581
  hasSnapshot(branch) {
27008
27582
  const dirName = sanitizeBranchName(branch);
27009
- return existsSync48(join53(this.branchDir, dirName, OVERLAY_FILE));
27583
+ return existsSync49(join53(this.branchDir, dirName, OVERLAY_FILE));
27010
27584
  }
27011
27585
  /**
27012
27586
  * Get the file hash state from a branch snapshot.
@@ -27014,9 +27588,9 @@ var init_branch_snapshot = __esm({
27014
27588
  getSnapshotFileHashes(branch) {
27015
27589
  const dirName = sanitizeBranchName(branch);
27016
27590
  const hashesPath = join53(this.branchDir, dirName, HASHES_FILE);
27017
- if (!existsSync48(hashesPath)) return null;
27591
+ if (!existsSync49(hashesPath)) return null;
27018
27592
  try {
27019
- const raw = readFileSync45(hashesPath, "utf-8");
27593
+ const raw = readFileSync46(hashesPath, "utf-8");
27020
27594
  return JSON.parse(raw);
27021
27595
  } catch {
27022
27596
  return null;
@@ -27028,7 +27602,7 @@ var init_branch_snapshot = __esm({
27028
27602
  deleteSnapshot(branch) {
27029
27603
  const dirName = sanitizeBranchName(branch);
27030
27604
  const snapshotDir = join53(this.branchDir, dirName);
27031
- if (!existsSync48(snapshotDir)) return false;
27605
+ if (!existsSync49(snapshotDir)) return false;
27032
27606
  rmSync3(snapshotDir, { recursive: true, force: true });
27033
27607
  log16.info(`Deleted branch snapshot: ${branch}`);
27034
27608
  return true;
@@ -27037,7 +27611,7 @@ var init_branch_snapshot = __esm({
27037
27611
  * Garbage-collect snapshots for branches that no longer exist in git.
27038
27612
  */
27039
27613
  async garbageCollect() {
27040
- if (!existsSync48(this.branchDir)) return 0;
27614
+ if (!existsSync49(this.branchDir)) return 0;
27041
27615
  const gitBranches = new Set(await listBranches(this.projectRoot));
27042
27616
  if (gitBranches.size === 0) return 0;
27043
27617
  const snapshots = this.listSnapshots();
@@ -27056,20 +27630,20 @@ var init_branch_snapshot = __esm({
27056
27630
  * List all branch snapshots, sorted by most recently accessed first.
27057
27631
  */
27058
27632
  listSnapshots() {
27059
- if (!existsSync48(this.branchDir)) return [];
27633
+ if (!existsSync49(this.branchDir)) return [];
27060
27634
  try {
27061
27635
  const entries = readdirSync11(this.branchDir, { withFileTypes: true });
27062
27636
  const snapshots = [];
27063
27637
  for (const entry of entries) {
27064
27638
  if (!entry.isDirectory()) continue;
27065
27639
  const overlayPath = join53(this.branchDir, entry.name, OVERLAY_FILE);
27066
- if (!existsSync48(overlayPath)) continue;
27640
+ if (!existsSync49(overlayPath)) continue;
27067
27641
  try {
27068
- const raw = readFileSync45(overlayPath, "utf-8");
27642
+ const raw = readFileSync46(overlayPath, "utf-8");
27069
27643
  const snapshot = JSON.parse(raw);
27070
27644
  const accessPath = join53(this.branchDir, entry.name, ".last_access");
27071
27645
  let accessedAt;
27072
- if (existsSync48(accessPath)) {
27646
+ if (existsSync49(accessPath)) {
27073
27647
  accessedAt = statSync7(accessPath).mtime;
27074
27648
  } else {
27075
27649
  accessedAt = statSync7(overlayPath).mtime;
@@ -27113,11 +27687,11 @@ __export(file_hash_state_exports, {
27113
27687
  });
27114
27688
  import { createHash as createHash3 } from "crypto";
27115
27689
  import {
27116
- existsSync as existsSync49,
27690
+ existsSync as existsSync50,
27117
27691
  mkdirSync as mkdirSync29,
27118
- readFileSync as readFileSync46,
27692
+ readFileSync as readFileSync47,
27119
27693
  renameSync as renameSync2,
27120
- writeFileSync as writeFileSync28
27694
+ writeFileSync as writeFileSync29
27121
27695
  } from "fs";
27122
27696
  import { join as join54 } from "path";
27123
27697
  function contentSha256(content) {
@@ -27179,11 +27753,11 @@ var init_file_hash_state = __esm({
27179
27753
  * Persist state to disk atomically (write .tmp → rename).
27180
27754
  */
27181
27755
  save() {
27182
- if (!existsSync49(this.stateDir)) {
27756
+ if (!existsSync50(this.stateDir)) {
27183
27757
  mkdirSync29(this.stateDir, { recursive: true });
27184
27758
  }
27185
27759
  const tmpPath = `${this.statePath}.tmp`;
27186
- writeFileSync28(tmpPath, JSON.stringify(this.state, null, 2), "utf-8");
27760
+ writeFileSync29(tmpPath, JSON.stringify(this.state, null, 2), "utf-8");
27187
27761
  renameSync2(tmpPath, this.statePath);
27188
27762
  }
27189
27763
  /**
@@ -27206,11 +27780,11 @@ var init_file_hash_state = __esm({
27206
27780
  this.state = { files: { ...snapshot.files } };
27207
27781
  }
27208
27782
  load() {
27209
- if (!existsSync49(this.statePath)) {
27783
+ if (!existsSync50(this.statePath)) {
27210
27784
  return { files: {} };
27211
27785
  }
27212
27786
  try {
27213
- const raw = readFileSync46(this.statePath, "utf-8");
27787
+ const raw = readFileSync47(this.statePath, "utf-8");
27214
27788
  return JSON.parse(raw);
27215
27789
  } catch {
27216
27790
  return { files: {} };
@@ -27222,13 +27796,13 @@ var init_file_hash_state = __esm({
27222
27796
 
27223
27797
  // src/tracking/stash-manager.ts
27224
27798
  import {
27225
- existsSync as existsSync50,
27799
+ existsSync as existsSync51,
27226
27800
  mkdirSync as mkdirSync30,
27227
- readFileSync as readFileSync47,
27801
+ readFileSync as readFileSync48,
27228
27802
  readdirSync as readdirSync12,
27229
27803
  rmSync as rmSync4,
27230
27804
  statSync as statSync8,
27231
- writeFileSync as writeFileSync29
27805
+ writeFileSync as writeFileSync30
27232
27806
  } from "fs";
27233
27807
  import { join as join55 } from "path";
27234
27808
  var MAX_STASH_SNAPSHOTS, OVERLAY_FILE2, HASHES_FILE2, _log6, StashManager;
@@ -27295,7 +27869,7 @@ var init_stash_manager = __esm({
27295
27869
  }
27296
27870
  const snapshotId = stashRef.slice(0, 12);
27297
27871
  const snapshotDir = join55(this.stashDir, snapshotId);
27298
- if (!existsSync50(snapshotDir)) {
27872
+ if (!existsSync51(snapshotDir)) {
27299
27873
  mkdirSync30(snapshotDir, { recursive: true });
27300
27874
  }
27301
27875
  const snapshot = {
@@ -27305,12 +27879,12 @@ var init_stash_manager = __esm({
27305
27879
  fileHashes: fileHashState,
27306
27880
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
27307
27881
  };
27308
- writeFileSync29(
27882
+ writeFileSync30(
27309
27883
  join55(snapshotDir, OVERLAY_FILE2),
27310
27884
  JSON.stringify(snapshot, null, 2),
27311
27885
  "utf-8"
27312
27886
  );
27313
- writeFileSync29(
27887
+ writeFileSync30(
27314
27888
  join55(snapshotDir, HASHES_FILE2),
27315
27889
  JSON.stringify(fileHashState, null, 2),
27316
27890
  "utf-8"
@@ -27334,12 +27908,12 @@ var init_stash_manager = __esm({
27334
27908
  const latest = snapshots[0];
27335
27909
  const snapshotDir = join55(this.stashDir, latest.id);
27336
27910
  const overlayPath = join55(snapshotDir, OVERLAY_FILE2);
27337
- if (!existsSync50(overlayPath)) {
27911
+ if (!existsSync51(overlayPath)) {
27338
27912
  _log6.warn(`Snapshot ${latest.id} missing overlay file`);
27339
27913
  return 0;
27340
27914
  }
27341
27915
  try {
27342
- const raw = readFileSync47(overlayPath, "utf-8");
27916
+ const raw = readFileSync48(overlayPath, "utf-8");
27343
27917
  const snapshot = JSON.parse(raw);
27344
27918
  for (const entity of snapshot.entities) {
27345
27919
  await localGraph.upsertDriftEntity(entity);
@@ -27370,9 +27944,9 @@ var init_stash_manager = __esm({
27370
27944
  if (snapshots.length === 0) return null;
27371
27945
  const latest = snapshots[0];
27372
27946
  const hashesPath = join55(this.stashDir, latest.id, HASHES_FILE2);
27373
- if (!existsSync50(hashesPath)) return null;
27947
+ if (!existsSync51(hashesPath)) return null;
27374
27948
  try {
27375
- const raw = readFileSync47(hashesPath, "utf-8");
27949
+ const raw = readFileSync48(hashesPath, "utf-8");
27376
27950
  return JSON.parse(raw);
27377
27951
  } catch {
27378
27952
  return null;
@@ -27384,7 +27958,7 @@ var init_stash_manager = __esm({
27384
27958
  dropSnapshot(stashRef) {
27385
27959
  const snapshotId = stashRef.slice(0, 12);
27386
27960
  const snapshotDir = join55(this.stashDir, snapshotId);
27387
- if (!existsSync50(snapshotDir)) return false;
27961
+ if (!existsSync51(snapshotDir)) return false;
27388
27962
  rmSync4(snapshotDir, { recursive: true, force: true });
27389
27963
  _log6.info(`Dropped stash snapshot: ${snapshotId}`);
27390
27964
  return true;
@@ -27393,14 +27967,14 @@ var init_stash_manager = __esm({
27393
27967
  * List all stash snapshots, sorted by most recent first.
27394
27968
  */
27395
27969
  listSnapshots() {
27396
- if (!existsSync50(this.stashDir)) return [];
27970
+ if (!existsSync51(this.stashDir)) return [];
27397
27971
  try {
27398
27972
  const entries = readdirSync12(this.stashDir, { withFileTypes: true });
27399
27973
  const snapshots = [];
27400
27974
  for (const entry of entries) {
27401
27975
  if (!entry.isDirectory()) continue;
27402
27976
  const overlayPath = join55(this.stashDir, entry.name, OVERLAY_FILE2);
27403
- if (!existsSync50(overlayPath)) continue;
27977
+ if (!existsSync51(overlayPath)) continue;
27404
27978
  try {
27405
27979
  const stat2 = statSync8(overlayPath);
27406
27980
  snapshots.push({ id: entry.name, savedAt: stat2.mtime });
@@ -27418,9 +27992,9 @@ var init_stash_manager = __esm({
27418
27992
  */
27419
27993
  readStashRef() {
27420
27994
  const stashPath = join55(this.gitDir, "refs", "stash");
27421
- if (!existsSync50(stashPath)) return null;
27995
+ if (!existsSync51(stashPath)) return null;
27422
27996
  try {
27423
- return readFileSync47(stashPath, "utf-8").trim() || null;
27997
+ return readFileSync48(stashPath, "utf-8").trim() || null;
27424
27998
  } catch {
27425
27999
  return null;
27426
28000
  }
@@ -27430,9 +28004,9 @@ var init_stash_manager = __esm({
27430
28004
  */
27431
28005
  getStashCount() {
27432
28006
  const logPath = join55(this.gitDir, "logs", "refs", "stash");
27433
- if (!existsSync50(logPath)) return 0;
28007
+ if (!existsSync51(logPath)) return 0;
27434
28008
  try {
27435
- const content = readFileSync47(logPath, "utf-8");
28009
+ const content = readFileSync48(logPath, "utf-8");
27436
28010
  return content.split("\n").filter((line) => line.trim().length > 0).length;
27437
28011
  } catch {
27438
28012
  return 0;
@@ -27464,11 +28038,11 @@ __export(drift_tracker_exports, {
27464
28038
  determineOrigin: () => determineOrigin
27465
28039
  });
27466
28040
  import {
27467
- existsSync as existsSync51,
28041
+ existsSync as existsSync52,
27468
28042
  mkdirSync as mkdirSync31,
27469
- readFileSync as readFileSync48,
28043
+ readFileSync as readFileSync49,
27470
28044
  statSync as statSync9,
27471
- writeFileSync as writeFileSync30
28045
+ writeFileSync as writeFileSync31
27472
28046
  } from "fs";
27473
28047
  import { join as join56 } from "path";
27474
28048
  function determineOrigin(lastSyncTimestamp) {
@@ -27685,11 +28259,11 @@ var init_drift_tracker = __esm({
27685
28259
  const relPath = filePath.startsWith("/") ? filePath.slice(this.config.projectRoot.length + 1) : filePath;
27686
28260
  const language = detectLanguage2(relPath);
27687
28261
  if (!language) return result;
27688
- if (existsSync51(absPath) && !this.mtimeCache.check(absPath)) {
28262
+ if (existsSync52(absPath) && !this.mtimeCache.check(absPath)) {
27689
28263
  result.filesSkipped = 1;
27690
28264
  return result;
27691
28265
  }
27692
- if (!existsSync51(absPath)) {
28266
+ if (!existsSync52(absPath)) {
27693
28267
  const baseEntities2 = await this.localGraph.getEntitiesByFile(relPath);
27694
28268
  this.markFileDeleted(relPath, intentId);
27695
28269
  result.filesProcessed = 1;
@@ -27727,7 +28301,7 @@ var init_drift_tracker = __esm({
27727
28301
  this.maybeEmitDrift(relPath, result);
27728
28302
  return result;
27729
28303
  }
27730
- const content = readFileSync48(absPath, "utf-8");
28304
+ const content = readFileSync49(absPath, "utf-8");
27731
28305
  const sha = contentSha256(content);
27732
28306
  const decision = this.fileHashManager.shouldProcess(relPath, sha, headSha);
27733
28307
  if (decision === "skip") {
@@ -28047,11 +28621,11 @@ var init_drift_tracker = __esm({
28047
28621
  }
28048
28622
  async saveDriftSummary() {
28049
28623
  const driftDir = join56(this.config.unerrDir, "drift");
28050
- if (!existsSync51(driftDir)) {
28624
+ if (!existsSync52(driftDir)) {
28051
28625
  mkdirSync31(driftDir, { recursive: true });
28052
28626
  }
28053
28627
  const summary = await this.getDriftSummary();
28054
- writeFileSync30(
28628
+ writeFileSync31(
28055
28629
  join56(driftDir, "drift_summary.json"),
28056
28630
  JSON.stringify(summary, null, 2),
28057
28631
  "utf-8"
@@ -28461,7 +29035,7 @@ var incremental_indexer_exports = {};
28461
29035
  __export(incremental_indexer_exports, {
28462
29036
  indexFilesIncremental: () => indexFilesIncremental
28463
29037
  });
28464
- import { existsSync as existsSync52, readFileSync as readFileSync49 } from "fs";
29038
+ import { existsSync as existsSync53, readFileSync as readFileSync50 } from "fs";
28465
29039
  import { join as join57, relative as relative4 } from "path";
28466
29040
  async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repoId) {
28467
29041
  const startMs = Date.now();
@@ -28479,7 +29053,7 @@ async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repo
28479
29053
  for (const filePath of changedFiles) {
28480
29054
  const absPath = filePath.startsWith("/") ? filePath : join57(projectRoot, filePath);
28481
29055
  const relPath = filePath.startsWith("/") ? relative4(projectRoot, filePath) : filePath;
28482
- if (!existsSync52(absPath)) {
29056
+ if (!existsSync53(absPath)) {
28483
29057
  const deleted2 = await deleteFileFromGraph(db, relPath);
28484
29058
  filesDeleted++;
28485
29059
  totalEntitiesDeleted += deleted2.entitiesDeleted;
@@ -28492,7 +29066,7 @@ async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repo
28492
29066
  }
28493
29067
  let content;
28494
29068
  try {
28495
- content = readFileSync49(absPath, "utf-8");
29069
+ content = readFileSync50(absPath, "utf-8");
28496
29070
  } catch {
28497
29071
  continue;
28498
29072
  }
@@ -29659,7 +30233,7 @@ var workspace_manifest_exports = {};
29659
30233
  __export(workspace_manifest_exports, {
29660
30234
  WorkspaceManifest: () => WorkspaceManifest
29661
30235
  });
29662
- import { existsSync as existsSync53, mkdirSync as mkdirSync32, readFileSync as readFileSync50, writeFileSync as writeFileSync31 } from "fs";
30236
+ import { existsSync as existsSync54, mkdirSync as mkdirSync32, readFileSync as readFileSync51, writeFileSync as writeFileSync32 } from "fs";
29663
30237
  import { join as join58 } from "path";
29664
30238
  var WorkspaceManifest;
29665
30239
  var init_workspace_manifest = __esm({
@@ -29765,7 +30339,7 @@ var init_workspace_manifest = __esm({
29765
30339
  }
29766
30340
  // ── Internal ─────────────────────────────────────────────────────
29767
30341
  load() {
29768
- if (!existsSync53(this.manifestPath)) {
30342
+ if (!existsSync54(this.manifestPath)) {
29769
30343
  return {
29770
30344
  version: 1,
29771
30345
  repoId: this.repoId,
@@ -29775,7 +30349,7 @@ var init_workspace_manifest = __esm({
29775
30349
  };
29776
30350
  }
29777
30351
  try {
29778
- const raw = readFileSync50(this.manifestPath, "utf-8");
30352
+ const raw = readFileSync51(this.manifestPath, "utf-8");
29779
30353
  const parsed = JSON.parse(raw);
29780
30354
  if (parsed.repoId !== this.repoId) {
29781
30355
  return {
@@ -29798,10 +30372,10 @@ var init_workspace_manifest = __esm({
29798
30372
  }
29799
30373
  }
29800
30374
  save() {
29801
- if (!existsSync53(this.unerrDir)) {
30375
+ if (!existsSync54(this.unerrDir)) {
29802
30376
  mkdirSync32(this.unerrDir, { recursive: true });
29803
30377
  }
29804
- writeFileSync31(
30378
+ writeFileSync32(
29805
30379
  this.manifestPath,
29806
30380
  JSON.stringify(this.data, null, 2),
29807
30381
  "utf-8"
@@ -29992,7 +30566,7 @@ var log_tailer_exports = {};
29992
30566
  __export(log_tailer_exports, {
29993
30567
  startLogTailer: () => startLogTailer
29994
30568
  });
29995
- import { existsSync as existsSync54, statSync as statSync10, openSync, readSync, closeSync, watch } from "fs";
30569
+ import { existsSync as existsSync55, statSync as statSync10, openSync, readSync, closeSync, watch } from "fs";
29996
30570
  import { join as join59 } from "path";
29997
30571
  function formatSize2(bytes) {
29998
30572
  if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
@@ -30107,22 +30681,22 @@ function startLogTailer(cwd, options) {
30107
30681
  const fileReadsPath = join59(logsDir, "file-reads.jsonl");
30108
30682
  const compressionState = {
30109
30683
  path: compressionPath,
30110
- offset: existsSync54(compressionPath) ? statSync10(compressionPath).size : 0,
30684
+ offset: existsSync55(compressionPath) ? statSync10(compressionPath).size : 0,
30111
30685
  watcher: null
30112
30686
  };
30113
30687
  const generalState = {
30114
30688
  path: generalPath,
30115
- offset: existsSync54(generalPath) ? statSync10(generalPath).size : 0,
30689
+ offset: existsSync55(generalPath) ? statSync10(generalPath).size : 0,
30116
30690
  watcher: null
30117
30691
  };
30118
30692
  const tokenFlowState = {
30119
30693
  path: tokenFlowPath,
30120
- offset: existsSync54(tokenFlowPath) ? statSync10(tokenFlowPath).size : 0,
30694
+ offset: existsSync55(tokenFlowPath) ? statSync10(tokenFlowPath).size : 0,
30121
30695
  watcher: null
30122
30696
  };
30123
30697
  const fileReadsState = {
30124
30698
  path: fileReadsPath,
30125
- offset: existsSync54(fileReadsPath) ? statSync10(fileReadsPath).size : 0,
30699
+ offset: existsSync55(fileReadsPath) ? statSync10(fileReadsPath).size : 0,
30126
30700
  watcher: null
30127
30701
  };
30128
30702
  function setupWatcher(state, handler) {
@@ -30150,7 +30724,7 @@ function startLogTailer(cwd, options) {
30150
30724
  ];
30151
30725
  const pollInterval = setInterval(() => {
30152
30726
  for (const { state, handler } of allStates) {
30153
- if (!state.watcher && existsSync54(state.path)) {
30727
+ if (!state.watcher && existsSync55(state.path)) {
30154
30728
  try {
30155
30729
  state.offset = 0;
30156
30730
  state.watcher = watch(state.path, () => {
@@ -31484,13 +32058,13 @@ function createSystemRoutes(deps) {
31484
32058
  });
31485
32059
  app.get("/config", async (c) => {
31486
32060
  const start = performance.now();
31487
- const { existsSync: existsSync63, readFileSync: readFileSync57 } = await import("fs");
32061
+ const { existsSync: existsSync64, readFileSync: readFileSync58 } = await import("fs");
31488
32062
  const { join: join68 } = await import("path");
31489
32063
  let config = {};
31490
32064
  const configPath = join68(deps.cwd, ".unerr", "config.json");
31491
- if (existsSync63(configPath)) {
32065
+ if (existsSync64(configPath)) {
31492
32066
  try {
31493
- config = JSON.parse(readFileSync57(configPath, "utf-8"));
32067
+ config = JSON.parse(readFileSync58(configPath, "utf-8"));
31494
32068
  } catch {
31495
32069
  config = { error: "unreadable" };
31496
32070
  }
@@ -31691,20 +32265,20 @@ __export(session_history_exports, {
31691
32265
  getWeeklyStats: () => getWeeklyStats,
31692
32266
  readSessionHistory: () => readSessionHistory
31693
32267
  });
31694
- import { appendFileSync as appendFileSync8, existsSync as existsSync55, mkdirSync as mkdirSync33, readFileSync as readFileSync51 } from "fs";
32268
+ import { appendFileSync as appendFileSync8, existsSync as existsSync56, mkdirSync as mkdirSync33, readFileSync as readFileSync52 } from "fs";
31695
32269
  import { join as join60 } from "path";
31696
32270
  function appendSessionHistory(unerrDir, entry) {
31697
32271
  const stateDir = join60(unerrDir, "state");
31698
- if (!existsSync55(stateDir)) mkdirSync33(stateDir, { recursive: true });
32272
+ if (!existsSync56(stateDir)) mkdirSync33(stateDir, { recursive: true });
31699
32273
  const historyPath = join60(stateDir, "session-history.jsonl");
31700
32274
  appendFileSync8(historyPath, `${JSON.stringify(entry)}
31701
32275
  `, "utf-8");
31702
32276
  }
31703
32277
  function readSessionHistory(unerrDir) {
31704
32278
  const historyPath = join60(unerrDir, "state", "session-history.jsonl");
31705
- if (!existsSync55(historyPath)) return [];
32279
+ if (!existsSync56(historyPath)) return [];
31706
32280
  try {
31707
- const content = readFileSync51(historyPath, "utf-8");
32281
+ const content = readFileSync52(historyPath, "utf-8");
31708
32282
  return content.split("\n").filter(Boolean).map((line) => {
31709
32283
  try {
31710
32284
  return JSON.parse(line);
@@ -32365,7 +32939,7 @@ var http_exports = {};
32365
32939
  __export(http_exports, {
32366
32940
  startDashboardServer: () => startDashboardServer
32367
32941
  });
32368
- import { existsSync as existsSync56, readFileSync as readFileSync52, unlinkSync as unlinkSync8, writeFileSync as writeFileSync32 } from "fs";
32942
+ import { existsSync as existsSync57, readFileSync as readFileSync53, unlinkSync as unlinkSync8, writeFileSync as writeFileSync33 } from "fs";
32369
32943
  import { createServer as createServer3 } from "net";
32370
32944
  import { dirname as dirname7, join as join61 } from "path";
32371
32945
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -32415,8 +32989,8 @@ async function startDashboardServer(opts) {
32415
32989
  }
32416
32990
  const distDir = join61(dirname7(fileURLToPath2(import.meta.url)), "ui");
32417
32991
  const spaIndex = join61(distDir, "index.html");
32418
- if (existsSync56(spaIndex)) {
32419
- const spaHtml = readFileSync52(spaIndex, "utf-8");
32992
+ if (existsSync57(spaIndex)) {
32993
+ const spaHtml = readFileSync53(spaIndex, "utf-8");
32420
32994
  app.use("*", serveStatic({ root: distDir }));
32421
32995
  app.get("*", (c) => {
32422
32996
  const path7 = c.req.path;
@@ -32453,7 +33027,7 @@ async function startDashboardServer(opts) {
32453
33027
  url: `http://localhost:${port}`
32454
33028
  };
32455
33029
  const tmpPath = `${serverJsonPath}.tmp.${process.pid}`;
32456
- writeFileSync32(tmpPath, JSON.stringify(serverInfo, null, 2));
33030
+ writeFileSync33(tmpPath, JSON.stringify(serverInfo, null, 2));
32457
33031
  const { renameSync: renameSync3 } = await import("fs");
32458
33032
  renameSync3(tmpPath, serverJsonPath);
32459
33033
  const close = () => {
@@ -32847,7 +33421,7 @@ var proxy_exports = {};
32847
33421
  __export(proxy_exports, {
32848
33422
  startProxy: () => startProxy
32849
33423
  });
32850
- import { existsSync as existsSync57, mkdirSync as mkdirSync34, readFileSync as readFileSync53, readdirSync as readdirSync13, writeFileSync as fsWriteFileSync } from "fs";
33424
+ import { existsSync as existsSync58, mkdirSync as mkdirSync34, readFileSync as readFileSync54, readdirSync as readdirSync13, writeFileSync as fsWriteFileSync } from "fs";
32851
33425
  import { join as join62 } from "path";
32852
33426
  async function getProxyFactStore(unerrDir) {
32853
33427
  if (proxyFactStore !== void 0) return proxyFactStore;
@@ -32934,8 +33508,8 @@ async function handleRecallFactsProxy(args, unerrDir) {
32934
33508
  function migrateAgentPermissions(cwd) {
32935
33509
  try {
32936
33510
  const settingsPath = join62(cwd, ".claude", "settings.json");
32937
- if (!existsSync57(settingsPath)) return;
32938
- const raw = readFileSync53(settingsPath, "utf-8");
33511
+ if (!existsSync58(settingsPath)) return;
33512
+ const raw = readFileSync54(settingsPath, "utf-8");
32939
33513
  const settings = JSON.parse(raw);
32940
33514
  const deny = settings?.permissions?.deny;
32941
33515
  if (!Array.isArray(deny)) return;
@@ -32956,7 +33530,7 @@ async function startProxy(opts = {}) {
32956
33530
  lifecycle.send({ type: "START_DETECT" });
32957
33531
  startup.setLocalMode(true);
32958
33532
  const stateDir = join62(process.cwd(), ".unerr", "state");
32959
- if (!existsSync57(stateDir)) {
33533
+ if (!existsSync58(stateDir)) {
32960
33534
  mkdirSync34(stateDir, { recursive: true });
32961
33535
  }
32962
33536
  const pidLock = new PidLock(stateDir);
@@ -32990,15 +33564,15 @@ async function startProxy(opts = {}) {
32990
33564
  repoIds = [opts.repoId];
32991
33565
  } else {
32992
33566
  const configPath = join62(process.cwd(), ".unerr", "config.json");
32993
- if (existsSync57(configPath)) {
33567
+ if (existsSync58(configPath)) {
32994
33568
  try {
32995
- const config = JSON.parse(readFileSync53(configPath, "utf-8"));
33569
+ const config = JSON.parse(readFileSync54(configPath, "utf-8"));
32996
33570
  if (config.repoId) repoIds = [config.repoId];
32997
33571
  } catch {
32998
33572
  }
32999
33573
  }
33000
33574
  const manifestsDir = join62(process.cwd(), ".unerr", "manifests");
33001
- if (repoIds.length === 0 && existsSync57(manifestsDir)) {
33575
+ if (repoIds.length === 0 && existsSync58(manifestsDir)) {
33002
33576
  repoIds = readdirSync13(manifestsDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
33003
33577
  }
33004
33578
  }
@@ -33432,8 +34006,8 @@ async function startProxy(opts = {}) {
33432
34006
  );
33433
34007
  process.env.UNERR_SESSION_ID = shadowLedger2.getSessionId();
33434
34008
  try {
33435
- const { writeFileSync: writeFileSync36 } = await import("fs");
33436
- writeFileSync36(join62(unerrDirForLedger, "state", "session.id"), shadowLedger2.getSessionId(), "utf-8");
34009
+ const { writeFileSync: writeFileSync37 } = await import("fs");
34010
+ writeFileSync37(join62(unerrDirForLedger, "state", "session.id"), shadowLedger2.getSessionId(), "utf-8");
33437
34011
  } catch {
33438
34012
  }
33439
34013
  router2.setTokenFlow(tokenFlowWriter2);
@@ -34263,7 +34837,7 @@ async function startProxy(opts = {}) {
34263
34837
  });
34264
34838
  for (const file of sourceFiles.slice(0, 500)) {
34265
34839
  try {
34266
- const content = readFileSync53(join62(process.cwd(), file), "utf-8");
34840
+ const content = readFileSync54(join62(process.cwd(), file), "utf-8");
34267
34841
  const entities = extractEntitiesFromSource2(file, content);
34268
34842
  parseIndex.addEntities(entities);
34269
34843
  } catch {
@@ -34425,7 +34999,7 @@ async function startProxy(opts = {}) {
34425
34999
  temporal: await (async () => {
34426
35000
  try {
34427
35001
  const { TemporalFactStore: TemporalFactStore2 } = await Promise.resolve().then(() => (init_temporal_facts(), temporal_facts_exports));
34428
- const { readdirSync: readdirSync15, readFileSync: readFileSync57 } = await import("fs");
35002
+ const { readdirSync: readdirSync15, readFileSync: readFileSync58 } = await import("fs");
34429
35003
  const factStore2 = await TemporalFactStore2.create(
34430
35004
  process.cwd()
34431
35005
  );
@@ -34436,7 +35010,7 @@ async function startProxy(opts = {}) {
34436
35010
  const sessDir = join62(unerrDirForApi, "sessions");
34437
35011
  const files = readdirSync15(sessDir).filter((f) => f.endsWith(".jsonl")).sort().slice(-limit);
34438
35012
  return files.map((f) => {
34439
- const content = readFileSync57(join62(sessDir, f), "utf-8").trim().split("\n").pop();
35013
+ const content = readFileSync58(join62(sessDir, f), "utf-8").trim().split("\n").pop();
34440
35014
  return JSON.parse(content);
34441
35015
  });
34442
35016
  } catch {
@@ -34858,7 +35432,7 @@ __export(session_logger_exports, {
34858
35432
  import { randomUUID as randomUUID2 } from "crypto";
34859
35433
  import {
34860
35434
  appendFileSync as appendFileSync9,
34861
- existsSync as existsSync58,
35435
+ existsSync as existsSync59,
34862
35436
  mkdirSync as mkdirSync35,
34863
35437
  readdirSync as readdirSync14,
34864
35438
  statSync as statSync11,
@@ -34872,7 +35446,7 @@ function formatTimestamp() {
34872
35446
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
34873
35447
  }
34874
35448
  function cleanupOldLogs(logsDir) {
34875
- if (!existsSync58(logsDir)) return;
35449
+ if (!existsSync59(logsDir)) return;
34876
35450
  try {
34877
35451
  const files = readdirSync14(logsDir).filter((f) => f.startsWith("session-") && f.endsWith(".log")).map((f) => {
34878
35452
  const fullPath = join63(logsDir, f);
@@ -34892,7 +35466,7 @@ function cleanupOldLogs(logsDir) {
34892
35466
  }
34893
35467
  }
34894
35468
  }
34895
- const remaining = files.filter((f) => existsSync58(f.path));
35469
+ const remaining = files.filter((f) => existsSync59(f.path));
34896
35470
  if (remaining.length > MAX_FILES) {
34897
35471
  for (const file of remaining.slice(MAX_FILES)) {
34898
35472
  try {
@@ -34985,7 +35559,7 @@ __export(setup_wizard_exports, {
34985
35559
  runSetup: () => runSetup
34986
35560
  });
34987
35561
  import { createHash as createHash4 } from "crypto";
34988
- import { existsSync as existsSync59, mkdirSync as mkdirSync36, writeFileSync as writeFileSync33 } from "fs";
35562
+ import { existsSync as existsSync60, mkdirSync as mkdirSync36, writeFileSync as writeFileSync34 } from "fs";
34989
35563
  import { join as join64 } from "path";
34990
35564
  import * as clack from "@clack/prompts";
34991
35565
  async function runSetup(cwd) {
@@ -34997,10 +35571,10 @@ async function runSetup(cwd) {
34997
35571
  mkdirSync36(configDir, { recursive: true });
34998
35572
  const configPath = join64(configDir, "config.json");
34999
35573
  const settingsPath = join64(configDir, "settings.json");
35000
- writeFileSync33(configPath, `${JSON.stringify({ repoId }, null, 2)}
35574
+ writeFileSync34(configPath, `${JSON.stringify({ repoId }, null, 2)}
35001
35575
  `);
35002
35576
  let existingSettings = {};
35003
- if (existsSync59(settingsPath)) {
35577
+ if (existsSync60(settingsPath)) {
35004
35578
  try {
35005
35579
  existingSettings = JSON.parse(
35006
35580
  __require("fs").readFileSync(settingsPath, "utf-8")
@@ -35008,7 +35582,7 @@ async function runSetup(cwd) {
35008
35582
  } catch {
35009
35583
  }
35010
35584
  }
35011
- writeFileSync33(
35585
+ writeFileSync34(
35012
35586
  settingsPath,
35013
35587
  `${JSON.stringify({ ...existingSettings }, null, 2)}
35014
35588
  `
@@ -35609,13 +36183,13 @@ __export(session_summary_writer_exports, {
35609
36183
  readLastSession: () => readLastSession,
35610
36184
  writeSessionSummary: () => writeSessionSummary
35611
36185
  });
35612
- import { existsSync as existsSync60, mkdirSync as mkdirSync37, appendFileSync as appendFileSync10, writeFileSync as writeFileSync34, readFileSync as readFileSync54 } from "fs";
36186
+ import { existsSync as existsSync61, mkdirSync as mkdirSync37, appendFileSync as appendFileSync10, writeFileSync as writeFileSync35, readFileSync as readFileSync55 } from "fs";
35613
36187
  import { join as join65 } from "path";
35614
36188
  function writeSessionSummary(unerrDir, ctx) {
35615
36189
  if (ctx.entries.length === 0) return null;
35616
36190
  try {
35617
36191
  const sessionsDir = join65(unerrDir, "sessions");
35618
- if (!existsSync60(sessionsDir)) {
36192
+ if (!existsSync61(sessionsDir)) {
35619
36193
  mkdirSync37(sessionsDir, { recursive: true });
35620
36194
  }
35621
36195
  const sorted = [...ctx.entries].sort(
@@ -35675,8 +36249,8 @@ function writeSessionSummary(unerrDir, ctx) {
35675
36249
  function readLastSession(unerrDir) {
35676
36250
  try {
35677
36251
  const pointerPath = join65(unerrDir, "state", "last_session.json");
35678
- if (!existsSync60(pointerPath)) return null;
35679
- const content = readFileSync54(pointerPath, "utf-8");
36252
+ if (!existsSync61(pointerPath)) return null;
36253
+ const content = readFileSync55(pointerPath, "utf-8");
35680
36254
  return JSON.parse(content);
35681
36255
  } catch {
35682
36256
  return null;
@@ -35685,11 +36259,11 @@ function readLastSession(unerrDir) {
35685
36259
  function writeLastSessionPointer(unerrDir, sessionId, record) {
35686
36260
  try {
35687
36261
  const stateDir = join65(unerrDir, "state");
35688
- if (!existsSync60(stateDir)) {
36262
+ if (!existsSync61(stateDir)) {
35689
36263
  mkdirSync37(stateDir, { recursive: true });
35690
36264
  }
35691
36265
  const pointerPath = join65(stateDir, "last_session.json");
35692
- writeFileSync34(pointerPath, JSON.stringify(record, null, 2), "utf-8");
36266
+ writeFileSync35(pointerPath, JSON.stringify(record, null, 2), "utf-8");
35693
36267
  } catch {
35694
36268
  }
35695
36269
  }
@@ -35886,20 +36460,20 @@ var mcp_server_exports = {};
35886
36460
  __export(mcp_server_exports, {
35887
36461
  startMcpServer: () => startMcpServer
35888
36462
  });
35889
- import { existsSync as existsSync61, mkdirSync as mkdirSync38, readFileSync as readFileSync55, writeFileSync as writeFileSync35 } from "fs";
36463
+ import { existsSync as existsSync62, mkdirSync as mkdirSync38, readFileSync as readFileSync56, writeFileSync as writeFileSync36 } from "fs";
35890
36464
  import { join as join66 } from "path";
35891
36465
  function migrateAgentPermissions2(cwd) {
35892
36466
  try {
35893
36467
  const settingsPath = join66(cwd, ".claude", "settings.json");
35894
- if (!existsSync61(settingsPath)) return;
35895
- const raw = readFileSync55(settingsPath, "utf-8");
36468
+ if (!existsSync62(settingsPath)) return;
36469
+ const raw = readFileSync56(settingsPath, "utf-8");
35896
36470
  const settings = JSON.parse(raw);
35897
36471
  const deny = settings?.permissions?.deny;
35898
36472
  if (!Array.isArray(deny)) return;
35899
36473
  const readIdx = deny.indexOf("Read");
35900
36474
  if (readIdx < 0) return;
35901
36475
  deny.splice(readIdx, 1);
35902
- writeFileSync35(settingsPath, JSON.stringify(settings, null, 2) + "\n");
36476
+ writeFileSync36(settingsPath, JSON.stringify(settings, null, 2) + "\n");
35903
36477
  process.stderr.write("[unerr] Migrated permissions: removed Read from deny list (required for Edit workflow)\n");
35904
36478
  } catch {
35905
36479
  }
@@ -35909,7 +36483,7 @@ async function startMcpServer(cwd) {
35909
36483
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
35910
36484
  const { ListToolsRequestSchema, CallToolRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
35911
36485
  const unerrDir = join66(cwd, ".unerr");
35912
- if (!existsSync61(unerrDir)) {
36486
+ if (!existsSync62(unerrDir)) {
35913
36487
  mkdirSync38(unerrDir, { recursive: true });
35914
36488
  }
35915
36489
  migrateAgentPermissions2(cwd);
@@ -36075,22 +36649,28 @@ async function startMcpServer(cwd) {
36075
36649
  const filePath = args.file_path ?? args.path ?? args.key?.split("::")[0] ?? null;
36076
36650
  if (filePath) {
36077
36651
  try {
36078
- const [fileFacts, negativeFacts] = await Promise.all([
36079
- factStore.recallByScope(filePath),
36080
- factStore.recallNegative(0.2)
36081
- ]);
36082
- const seen = /* @__PURE__ */ new Set();
36083
- const merged = [];
36084
- for (const f of fileFacts) {
36085
- if (!seen.has(f.fact_id)) {
36086
- seen.add(f.fact_id);
36087
- merged.push(f);
36652
+ let merged;
36653
+ if (name === "file_read" && router) {
36654
+ const entityKeys = await router.getEntityKeysForFile(filePath);
36655
+ merged = await factStore.recallForFile(filePath, entityKeys);
36656
+ } else {
36657
+ const [fileFacts, negativeFacts] = await Promise.all([
36658
+ factStore.recallByScope(filePath),
36659
+ factStore.recallNegative(0.2)
36660
+ ]);
36661
+ const seen = /* @__PURE__ */ new Set();
36662
+ merged = [];
36663
+ for (const f of fileFacts) {
36664
+ if (!seen.has(f.fact_id)) {
36665
+ seen.add(f.fact_id);
36666
+ merged.push(f);
36667
+ }
36088
36668
  }
36089
- }
36090
- for (const f of negativeFacts) {
36091
- if (!seen.has(f.fact_id)) {
36092
- seen.add(f.fact_id);
36093
- merged.push(f);
36669
+ for (const f of negativeFacts) {
36670
+ if (!seen.has(f.fact_id)) {
36671
+ seen.add(f.fact_id);
36672
+ merged.push(f);
36673
+ }
36094
36674
  }
36095
36675
  }
36096
36676
  if (merged.length > 0) {
@@ -36317,7 +36897,7 @@ async function initTier2Modules(unerrDir) {
36317
36897
  try {
36318
36898
  const stateDir = join66(unerrDir, "state");
36319
36899
  mkdirSync38(stateDir, { recursive: true });
36320
- writeFileSync35(join66(stateDir, "session.id"), sessionId, "utf-8");
36900
+ writeFileSync36(join66(stateDir, "session.id"), sessionId, "utf-8");
36321
36901
  } catch {
36322
36902
  }
36323
36903
  log24.info(`Token flow active (session ${sessionId.slice(0, 8)})`);
@@ -36459,7 +37039,7 @@ async function loadIntelligence(cwd) {
36459
37039
  const projectRoot = cwd;
36460
37040
  try {
36461
37041
  const unerrDir = join66(projectRoot, ".unerr");
36462
- if (!existsSync61(unerrDir)) {
37042
+ if (!existsSync62(unerrDir)) {
36463
37043
  mkdirSync38(unerrDir, { recursive: true });
36464
37044
  }
36465
37045
  const { openPersistentDb: openPersistentDb2 } = await Promise.resolve().then(() => (init_persistent_db(), persistent_db_exports));
@@ -36480,9 +37060,9 @@ async function loadIntelligence(cwd) {
36480
37060
  await runCommunityDetection2(localGraph);
36481
37061
  const configPath = join66(projectRoot, ".unerr", "config.json");
36482
37062
  let repoId = "unknown";
36483
- if (existsSync61(configPath)) {
37063
+ if (existsSync62(configPath)) {
36484
37064
  try {
36485
- const config = JSON.parse(readFileSync55(configPath, "utf-8"));
37065
+ const config = JSON.parse(readFileSync56(configPath, "utf-8"));
36486
37066
  repoId = config.repoId ?? repoId;
36487
37067
  } catch {
36488
37068
  }
@@ -36511,9 +37091,9 @@ async function loadIntelligence(cwd) {
36511
37091
  try {
36512
37092
  const configPath = join66(projectRoot, ".unerr", "config.json");
36513
37093
  let indexRepoId = "unknown";
36514
- if (existsSync61(configPath)) {
37094
+ if (existsSync62(configPath)) {
36515
37095
  try {
36516
- const cfg = JSON.parse(readFileSync55(configPath, "utf-8"));
37096
+ const cfg = JSON.parse(readFileSync56(configPath, "utf-8"));
36517
37097
  indexRepoId = cfg.repoId ?? indexRepoId;
36518
37098
  } catch {
36519
37099
  }
@@ -36623,7 +37203,7 @@ var init_mcp_server = __esm({
36623
37203
 
36624
37204
  // src/entrypoints/cli.ts
36625
37205
  init_startup_log();
36626
- import { existsSync as existsSync62, readFileSync as readFileSync56 } from "fs";
37206
+ import { existsSync as existsSync63, readFileSync as readFileSync57 } from "fs";
36627
37207
  import { join as join67 } from "path";
36628
37208
  import { Command } from "commander";
36629
37209
 
@@ -38628,19 +39208,19 @@ async function buildShellDiffRiskMap(graph, stdout) {
38628
39208
  }
38629
39209
  async function tryLoadGraphForShellBoost(cwd) {
38630
39210
  try {
38631
- const { existsSync: existsSync63, readFileSync: readFileSync57 } = await import("fs");
39211
+ const { existsSync: existsSync64, readFileSync: readFileSync58 } = await import("fs");
38632
39212
  const { join: join68 } = await import("path");
38633
39213
  const { gunzipSync: gunzipSync3 } = await import("zlib");
38634
39214
  const { unpack } = await import("msgpackr");
38635
39215
  const snapshotsDir = join68(cwd, ".unerr", "snapshots");
38636
39216
  let snapshotPath2 = join68(snapshotsDir, "graph.msgpack.gz");
38637
- if (!existsSync63(snapshotPath2)) {
39217
+ if (!existsSync64(snapshotPath2)) {
38638
39218
  snapshotPath2 = join68(snapshotsDir, "graph.msgpack");
38639
39219
  }
38640
- if (!existsSync63(snapshotPath2)) return null;
39220
+ if (!existsSync64(snapshotPath2)) return null;
38641
39221
  const { default: CozoDbConstructor } = await import("cozo-node");
38642
39222
  const { CozoGraphStore: CozoGraphStore2 } = await Promise.resolve().then(() => (init_local_graph(), local_graph_exports));
38643
- const raw = readFileSync57(snapshotPath2);
39223
+ const raw = readFileSync58(snapshotPath2);
38644
39224
  let buffer;
38645
39225
  try {
38646
39226
  buffer = gunzipSync3(raw);
@@ -41832,6 +42412,7 @@ function runPreToolUseHook(stdinJson, handler) {
41832
42412
  if (!payload) return "{}";
41833
42413
  const adapter = detectAdapter(payload);
41834
42414
  const normalized = adapter.normalize(payload);
42415
+ normalized.agentName = adapter.name;
41835
42416
  const result = handler(normalized);
41836
42417
  return adapter.formatPreToolUse(result);
41837
42418
  }
@@ -41840,6 +42421,7 @@ function runPostToolUseHook(stdinJson, handler) {
41840
42421
  if (!payload) return "{}";
41841
42422
  const adapter = detectAdapter(payload);
41842
42423
  const normalized = adapter.normalize(payload);
42424
+ normalized.agentName = adapter.name;
41843
42425
  const result = handler(normalized);
41844
42426
  return adapter.formatPostToolUse(result);
41845
42427
  }
@@ -41848,6 +42430,7 @@ function runPromptSubmitHook(stdinJson, handler) {
41848
42430
  if (!payload) return "{}";
41849
42431
  const adapter = detectAdapter(payload);
41850
42432
  const normalized = adapter.normalize(payload);
42433
+ normalized.agentName = adapter.name;
41851
42434
  const result = handler(normalized);
41852
42435
  return adapter.formatPromptSubmit(result);
41853
42436
  }
@@ -41876,17 +42459,27 @@ var preReadHandler = (normalized) => {
41876
42459
  const input = normalized.toolInput;
41877
42460
  const filePath = extractFilePath2(input);
41878
42461
  if (!filePath) return passthrough();
42462
+ const isClaudeCode = normalized.agentName === "claude-code";
41879
42463
  const hasOffset = input.offset !== void 0;
41880
42464
  const hasLimit = input.limit !== void 0;
41881
42465
  const isTargeted = hasOffset || hasLimit;
41882
- const targetedReadGuidance = isTargeted ? "" : `
41883
- IMPORTANT: Use offset/limit to read only the lines you plan to edit \u2014 do NOT read the entire file. You already know the target lines from file_read. Example: Read with offset=50, limit=30 to read lines 50-79.`;
41884
- return nudge(
41885
- `READ ROUTING: Built-in Read is ONLY for the Edit workflow (Read \u2192 Edit). For all other reading, use unerr tools instead:
41886
- - Reading to understand: \`file_read({ file_path: "${filePath}", purpose: "explore" })\`
41887
- - Reading before Edit: built-in Read is correct (proceed)
42466
+ if (isClaudeCode && isTargeted) {
42467
+ return passthrough();
42468
+ }
42469
+ if (isClaudeCode) {
42470
+ return nudge(
42471
+ `READ ROUTING: Built-in Read is ONLY for the Edit workflow (Read \u2192 Edit). Use offset/limit to read only the lines you plan to edit \u2014 do NOT read the entire file.
42472
+ For all other reading, use unerr tools instead:
42473
+ - Reading to understand: \`file_read({ file_path: "${filePath}" })\`
41888
42474
  - File structure: \`file_outline("${filePath}")\`
41889
- - Specific function: \`get_entity\` or \`file_read\` with \`entity\` param` + targetedReadGuidance
42475
+ - Specific function: \`get_entity\` or \`file_read\` with \`entity\` param`
42476
+ );
42477
+ }
42478
+ return nudge(
42479
+ `Use unerr tools instead of built-in Read:
42480
+ - \`file_read({ file_path: "${filePath}" })\` \u2014 auto-injects conventions, facts, drift status
42481
+ - \`file_outline("${filePath}")\` \u2014 file structure overview
42482
+ - \`get_entity\` or \`file_read\` with \`entity\` param \u2014 specific function/class`
41890
42483
  );
41891
42484
  };
41892
42485
  var preGrepHandler = (normalized) => {
@@ -41938,9 +42531,10 @@ var preEditHandler = (normalized) => {
41938
42531
  const input = normalized.toolInput;
41939
42532
  const filePath = extractFilePath2(input);
41940
42533
  if (!filePath || !isCodeFile(filePath)) return passthrough();
41941
- const readPrereq = `CRITICAL: Edit REQUIRES built-in Read to have been called on "${filePath}" first. file_read (MCP) does NOT satisfy this \u2014 the Edit tool will fail with "File has not been read yet". If you haven't called built-in Read on this file, do so now before attempting Edit. Use offset/limit to read only the lines you plan to edit \u2014 do NOT read the entire file.
42534
+ const isClaudeCode = normalized.agentName === "claude-code";
42535
+ const readPrereq = isClaudeCode ? `CRITICAL: Edit REQUIRES built-in Read to have been called on "${filePath}" first. file_read (MCP) does NOT satisfy this \u2014 the Edit tool will fail with "File has not been read yet". If you haven't called built-in Read (with offset/limit on the target lines) on this file, do so now before attempting Edit.
41942
42536
 
41943
- `;
42537
+ ` : "";
41944
42538
  const oldStr = input.old_string;
41945
42539
  const hasSignatureChange = oldStr && /^(export\s+)?(async\s+)?function\s+\w+|^(export\s+)?class\s+\w+/.test(oldStr.trim());
41946
42540
  if (hasSignatureChange) {
@@ -41960,9 +42554,16 @@ var postReadHandler = (normalized) => {
41960
42554
  const input = normalized.toolInput;
41961
42555
  const filePath = extractFilePath2(input);
41962
42556
  if (!filePath || !isCodeFile(filePath)) return passthrough();
41963
- return enrich(
41964
- `If you're about to Edit this file, this Read was correct (Edit requires built-in Read first).
42557
+ const isClaudeCode = normalized.agentName === "claude-code";
42558
+ if (isClaudeCode) {
42559
+ return enrich(
42560
+ `If you're about to Edit this file, this Read was correct (Edit requires built-in Read first).
41965
42561
  If you're exploring, use \`file_read\` instead \u2014 it auto-injects conventions, facts, and drift status.
42562
+ Next steps: \`get_references\` to check callers before modifying, \`get_rules\` to validate conventions.`
42563
+ );
42564
+ }
42565
+ return enrich(
42566
+ `Prefer \`file_read\` over built-in Read \u2014 it auto-injects conventions, facts, and drift status.
41966
42567
  Next steps: \`get_references\` to check callers before modifying, \`get_rules\` to validate conventions.`
41967
42568
  );
41968
42569
  };
@@ -42085,56 +42686,32 @@ function runPreBashHook(stdinJson) {
42085
42686
  }
42086
42687
 
42087
42688
  // src/commands/hook.ts
42689
+ function safeHookAction(handler) {
42690
+ return () => {
42691
+ try {
42692
+ const stdin = readFileSync15(0, "utf-8");
42693
+ process.stdout.write(handler(stdin));
42694
+ } catch (e) {
42695
+ process.stderr.write(`[unerr] hook error: ${e}
42696
+ `);
42697
+ process.stdout.write("{}");
42698
+ }
42699
+ };
42700
+ }
42088
42701
  function registerHookCommand(program2) {
42089
42702
  const hook = program2.command("hook").description("IDE hook handlers (stdin/stdout JSON)");
42090
- hook.command("pre-bash").description("Rewrite Bash tool input to pipe through unerr exec").action(() => {
42091
- const stdin = readFileSync15(0, "utf-8");
42092
- process.stdout.write(runPreBashHook(stdin));
42093
- });
42094
- hook.command("pre-read").description("Nudge agent to use file_outline/file_read instead of Read").action(() => {
42095
- const stdin = readFileSync15(0, "utf-8");
42096
- process.stdout.write(runPreReadHook(stdin));
42097
- });
42098
- hook.command("pre-grep").description("Nudge agent to use search_code/get_callers instead of Grep").action(() => {
42099
- const stdin = readFileSync15(0, "utf-8");
42100
- process.stdout.write(runPreGrepHook(stdin));
42101
- });
42102
- hook.command("pre-glob").description("Nudge agent to use search_code instead of Glob").action(() => {
42103
- const stdin = readFileSync15(0, "utf-8");
42104
- process.stdout.write(runPreGlobHook(stdin));
42105
- });
42106
- hook.command("pre-write").description("Blast radius + convention check before Write").action(() => {
42107
- const stdin = readFileSync15(0, "utf-8");
42108
- process.stdout.write(runPreWriteHook(stdin));
42109
- });
42110
- hook.command("pre-edit").description("Blast radius + convention check before Edit").action(() => {
42111
- const stdin = readFileSync15(0, "utf-8");
42112
- process.stdout.write(runPreEditHook(stdin));
42113
- });
42114
- hook.command("post-read").description("Enrich Read output with graph navigation suggestions").action(() => {
42115
- const stdin = readFileSync15(0, "utf-8");
42116
- process.stdout.write(runPostReadHook(stdin));
42117
- });
42118
- hook.command("post-grep").description("Enrich Grep output with graph navigation suggestions").action(() => {
42119
- const stdin = readFileSync15(0, "utf-8");
42120
- process.stdout.write(runPostGrepHook(stdin));
42121
- });
42122
- hook.command("post-glob").description("Enrich Glob output with graph navigation suggestions").action(() => {
42123
- const stdin = readFileSync15(0, "utf-8");
42124
- process.stdout.write(runPostGlobHook(stdin));
42125
- });
42126
- hook.command("post-write").description("Post-write convention check + caller verification reminder").action(() => {
42127
- const stdin = readFileSync15(0, "utf-8");
42128
- process.stdout.write(runPostWriteHook(stdin));
42129
- });
42130
- hook.command("post-edit").description("Post-edit convention check + caller verification reminder").action(() => {
42131
- const stdin = readFileSync15(0, "utf-8");
42132
- process.stdout.write(runPostEditHook(stdin));
42133
- });
42134
- hook.command("prompt-submit").description("Inject unerr tool reminder on each user prompt").action(() => {
42135
- const stdin = readFileSync15(0, "utf-8");
42136
- process.stdout.write(runUserPromptSubmitHook(stdin));
42137
- });
42703
+ hook.command("pre-bash").description("Rewrite Bash tool input to pipe through unerr exec").action(safeHookAction(runPreBashHook));
42704
+ hook.command("pre-read").description("Nudge agent to use file_outline/file_read instead of Read").action(safeHookAction(runPreReadHook));
42705
+ hook.command("pre-grep").description("Nudge agent to use search_code/get_callers instead of Grep").action(safeHookAction(runPreGrepHook));
42706
+ hook.command("pre-glob").description("Nudge agent to use search_code instead of Glob").action(safeHookAction(runPreGlobHook));
42707
+ hook.command("pre-write").description("Blast radius + convention check before Write").action(safeHookAction(runPreWriteHook));
42708
+ hook.command("pre-edit").description("Blast radius + convention check before Edit").action(safeHookAction(runPreEditHook));
42709
+ hook.command("post-read").description("Enrich Read output with graph navigation suggestions").action(safeHookAction(runPostReadHook));
42710
+ hook.command("post-grep").description("Enrich Grep output with graph navigation suggestions").action(safeHookAction(runPostGrepHook));
42711
+ hook.command("post-glob").description("Enrich Glob output with graph navigation suggestions").action(safeHookAction(runPostGlobHook));
42712
+ hook.command("post-write").description("Post-write convention check + caller verification reminder").action(safeHookAction(runPostWriteHook));
42713
+ hook.command("post-edit").description("Post-edit convention check + caller verification reminder").action(safeHookAction(runPostEditHook));
42714
+ hook.command("prompt-submit").description("Inject unerr tool reminder on each user prompt").action(safeHookAction(runUserPromptSubmitHook));
42138
42715
  }
42139
42716
 
42140
42717
  // src/commands/index.ts
@@ -42304,89 +42881,108 @@ function runInit(cwd) {
42304
42881
 
42305
42882
  // src/commands/install.ts
42306
42883
  init_agent_registry();
42307
- import { chmodSync as chmodSync4, existsSync as existsSync23, mkdirSync as mkdirSync17, readFileSync as readFileSync22, writeFileSync as writeFileSync13 } from "fs";
42884
+ import { chmodSync as chmodSync4, existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "fs";
42308
42885
  import { join as join30 } from "path";
42309
42886
 
42310
42887
  // src/config/claude-settings-hooks.ts
42311
- import { existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync19, writeFileSync as writeFileSync10 } from "fs";
42888
+ import { execSync as execSync2 } from "child_process";
42889
+ import { existsSync as existsSync21, mkdirSync as mkdirSync14, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
42312
42890
  import { join as join27 } from "path";
42313
- var UNERR_MATCHER_HOOKS = [
42314
- // PreToolUse advisory nudges + Bash rewrite
42315
- { event: "PreToolUse", matcher: "Bash", command: "unerr hook pre-bash" },
42316
- { event: "PreToolUse", matcher: "Read", command: "unerr hook pre-read" },
42317
- { event: "PreToolUse", matcher: "Grep", command: "unerr hook pre-grep" },
42318
- { event: "PreToolUse", matcher: "Glob", command: "unerr hook pre-glob" },
42319
- // PreToolUse blast radius + convention validation for writes
42320
- { event: "PreToolUse", matcher: "Write", command: "unerr hook pre-write" },
42321
- { event: "PreToolUse", matcher: "Edit", command: "unerr hook pre-edit" },
42322
- // PostToolUse — enrich tool output with graph navigation suggestions
42323
- { event: "PostToolUse", matcher: "Read", command: "unerr hook post-read" },
42324
- { event: "PostToolUse", matcher: "Grep", command: "unerr hook post-grep" },
42325
- { event: "PostToolUse", matcher: "Glob", command: "unerr hook post-glob" },
42326
- { event: "PostToolUse", matcher: "Write", command: "unerr hook post-write" },
42327
- { event: "PostToolUse", matcher: "Edit", command: "unerr hook post-edit" }
42328
- ];
42329
- var UNERR_GLOBAL_HOOKS = [
42330
- { event: "UserPromptSubmit", command: "unerr hook prompt-submit" }
42331
- ];
42332
- function isUnerrHookEntry(entry, hookCmd, matcherName) {
42891
+ function resolveUnerrBinary() {
42892
+ const entryScript = process.argv[1];
42893
+ if (entryScript && existsSync21(entryScript)) {
42894
+ return entryScript;
42895
+ }
42896
+ try {
42897
+ const resolved = execSync2("which unerr", { encoding: "utf-8" }).trim();
42898
+ if (resolved && existsSync21(resolved)) {
42899
+ return resolved;
42900
+ }
42901
+ } catch {
42902
+ }
42903
+ return "unerr";
42904
+ }
42905
+ var _resolvedBinary;
42906
+ function getUnerrBinary() {
42907
+ if (_resolvedBinary === void 0) {
42908
+ _resolvedBinary = resolveUnerrBinary();
42909
+ }
42910
+ return _resolvedBinary;
42911
+ }
42912
+ function buildMatcherHooks() {
42913
+ const bin = getUnerrBinary();
42914
+ return [
42915
+ // PreToolUse — advisory nudges + Bash rewrite
42916
+ { event: "PreToolUse", matcher: "Bash", command: `${bin} hook pre-bash` },
42917
+ { event: "PreToolUse", matcher: "Read", command: `${bin} hook pre-read` },
42918
+ { event: "PreToolUse", matcher: "Grep", command: `${bin} hook pre-grep` },
42919
+ { event: "PreToolUse", matcher: "Glob", command: `${bin} hook pre-glob` },
42920
+ // PreToolUse — blast radius + convention validation for writes
42921
+ { event: "PreToolUse", matcher: "Write", command: `${bin} hook pre-write` },
42922
+ { event: "PreToolUse", matcher: "Edit", command: `${bin} hook pre-edit` },
42923
+ // PostToolUse — enrich tool output with graph navigation suggestions
42924
+ { event: "PostToolUse", matcher: "Read", command: `${bin} hook post-read` },
42925
+ { event: "PostToolUse", matcher: "Grep", command: `${bin} hook post-grep` },
42926
+ { event: "PostToolUse", matcher: "Glob", command: `${bin} hook post-glob` },
42927
+ { event: "PostToolUse", matcher: "Write", command: `${bin} hook post-write` },
42928
+ { event: "PostToolUse", matcher: "Edit", command: `${bin} hook post-edit` }
42929
+ ];
42930
+ }
42931
+ function buildGlobalHooks() {
42932
+ const bin = getUnerrBinary();
42933
+ return [
42934
+ { event: "UserPromptSubmit", command: `${bin} hook prompt-submit` }
42935
+ ];
42936
+ }
42937
+ function isAnyUnerrHook(entry) {
42333
42938
  if (!entry || typeof entry !== "object") return false;
42334
42939
  const e = entry;
42335
- if (matcherName !== void 0 && e.matcher !== matcherName) return false;
42336
42940
  const hs = e.hooks;
42337
42941
  if (!Array.isArray(hs)) return false;
42338
42942
  return hs.some((h) => {
42339
42943
  if (!h || typeof h !== "object") return false;
42340
- const x2 = h;
42341
- return x2.command === hookCmd || x2.command === `npx ${hookCmd}`;
42944
+ const cmd = h.command;
42945
+ return typeof cmd === "string" && /(?:^|\/)unerr\s+hook\s+/.test(cmd);
42342
42946
  });
42343
42947
  }
42344
- function isAnyUnerrHook(entry) {
42345
- for (const hookDef of UNERR_MATCHER_HOOKS) {
42346
- if (isUnerrHookEntry(entry, hookDef.command, hookDef.matcher)) return true;
42347
- }
42348
- for (const hookDef of UNERR_GLOBAL_HOOKS) {
42349
- if (isUnerrHookEntry(entry, hookDef.command)) return true;
42350
- }
42351
- return false;
42352
- }
42353
42948
  function mergePreToolUseBashHook(cwd) {
42354
42949
  const dir = join27(cwd, ".claude");
42355
42950
  const settingsPath = join27(dir, "settings.json");
42356
42951
  try {
42357
- if (!existsSync20(dir)) {
42952
+ if (!existsSync21(dir)) {
42358
42953
  mkdirSync14(dir, { recursive: true });
42359
42954
  }
42360
42955
  let settings = {};
42361
- if (existsSync20(settingsPath)) {
42956
+ if (existsSync21(settingsPath)) {
42362
42957
  try {
42363
- settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
42958
+ settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
42364
42959
  } catch {
42365
42960
  settings = {};
42366
42961
  }
42367
42962
  }
42368
42963
  const hooks = settings.hooks ?? {};
42369
42964
  let added = 0;
42370
- for (const hookDef of UNERR_MATCHER_HOOKS) {
42371
- const eventArray = Array.isArray(hooks[hookDef.event]) ? [...hooks[hookDef.event]] : [];
42372
- const alreadyPresent = eventArray.some(
42373
- (entry) => isUnerrHookEntry(entry, hookDef.command, hookDef.matcher)
42374
- );
42375
- if (!alreadyPresent) {
42376
- eventArray.push({
42377
- matcher: hookDef.matcher,
42378
- hooks: [{ type: "command", command: hookDef.command }]
42379
- });
42380
- hooks[hookDef.event] = eventArray;
42381
- added++;
42965
+ const matcherHooks = buildMatcherHooks();
42966
+ const globalHooks = buildGlobalHooks();
42967
+ for (const eventType of ["PreToolUse", "PostToolUse", "UserPromptSubmit"]) {
42968
+ if (Array.isArray(hooks[eventType])) {
42969
+ hooks[eventType] = hooks[eventType].filter(
42970
+ (entry) => !isAnyUnerrHook(entry)
42971
+ );
42382
42972
  }
42383
42973
  }
42384
- for (const hookDef of UNERR_GLOBAL_HOOKS) {
42974
+ for (const hookDef of matcherHooks) {
42385
42975
  const eventArray = Array.isArray(hooks[hookDef.event]) ? [...hooks[hookDef.event]] : [];
42386
- const alreadyPresent = eventArray.some(
42387
- (entry) => isUnerrHookEntry(entry, hookDef.command)
42388
- );
42389
- if (!alreadyPresent) {
42976
+ eventArray.push({
42977
+ matcher: hookDef.matcher,
42978
+ hooks: [{ type: "command", command: hookDef.command }]
42979
+ });
42980
+ hooks[hookDef.event] = eventArray;
42981
+ added++;
42982
+ }
42983
+ for (const hookDef of globalHooks) {
42984
+ const eventArray = Array.isArray(hooks[hookDef.event]) ? [...hooks[hookDef.event]] : [];
42985
+ if (!eventArray.some((entry) => isAnyUnerrHook(entry))) {
42390
42986
  eventArray.push({
42391
42987
  hooks: [{ type: "command", command: hookDef.command }]
42392
42988
  });
@@ -42398,7 +42994,7 @@ function mergePreToolUseBashHook(cwd) {
42398
42994
  return { ok: true, path: settingsPath, action: "already_present" };
42399
42995
  }
42400
42996
  settings.hooks = hooks;
42401
- writeFileSync10(
42997
+ writeFileSync11(
42402
42998
  settingsPath,
42403
42999
  `${JSON.stringify(settings, null, 2)}
42404
43000
  `,
@@ -42414,13 +43010,13 @@ function addDisallowedTools(cwd) {
42414
43010
  const dir = join27(cwd, ".claude");
42415
43011
  const settingsPath = join27(dir, "settings.json");
42416
43012
  try {
42417
- if (!existsSync20(dir)) {
43013
+ if (!existsSync21(dir)) {
42418
43014
  mkdirSync14(dir, { recursive: true });
42419
43015
  }
42420
43016
  let settings = {};
42421
- if (existsSync20(settingsPath)) {
43017
+ if (existsSync21(settingsPath)) {
42422
43018
  try {
42423
- settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
43019
+ settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
42424
43020
  } catch {
42425
43021
  settings = {};
42426
43022
  }
@@ -42443,7 +43039,7 @@ function addDisallowedTools(cwd) {
42443
43039
  }
42444
43040
  permissions.deny = deny;
42445
43041
  settings.permissions = permissions;
42446
- writeFileSync10(settingsPath, `${JSON.stringify(settings, null, 2)}
43042
+ writeFileSync11(settingsPath, `${JSON.stringify(settings, null, 2)}
42447
43043
  `, "utf-8");
42448
43044
  return { added, path: settingsPath };
42449
43045
  } catch {
@@ -42452,9 +43048,9 @@ function addDisallowedTools(cwd) {
42452
43048
  }
42453
43049
  function removeDisallowedTools(cwd) {
42454
43050
  const settingsPath = join27(cwd, ".claude", "settings.json");
42455
- if (!existsSync20(settingsPath)) return false;
43051
+ if (!existsSync21(settingsPath)) return false;
42456
43052
  try {
42457
- const settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
43053
+ const settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
42458
43054
  const permissions = settings.permissions;
42459
43055
  if (!permissions || !Array.isArray(permissions.deny)) return false;
42460
43056
  const before = permissions.deny.length;
@@ -42465,7 +43061,7 @@ function removeDisallowedTools(cwd) {
42465
43061
  if (removed === 0) return false;
42466
43062
  if (permissions.deny.length === 0) delete permissions.deny;
42467
43063
  if (Object.keys(permissions).length === 0) delete settings.permissions;
42468
- writeFileSync10(settingsPath, `${JSON.stringify(settings, null, 2)}
43064
+ writeFileSync11(settingsPath, `${JSON.stringify(settings, null, 2)}
42469
43065
  `, "utf-8");
42470
43066
  return true;
42471
43067
  } catch {
@@ -42474,9 +43070,9 @@ function removeDisallowedTools(cwd) {
42474
43070
  }
42475
43071
  function removePreToolUseBashHook(cwd) {
42476
43072
  const settingsPath = join27(cwd, ".claude", "settings.json");
42477
- if (!existsSync20(settingsPath)) return false;
43073
+ if (!existsSync21(settingsPath)) return false;
42478
43074
  try {
42479
- const settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
43075
+ const settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
42480
43076
  const hooks = settings.hooks;
42481
43077
  if (!hooks) return false;
42482
43078
  let totalRemoved = 0;
@@ -42493,7 +43089,7 @@ function removePreToolUseBashHook(cwd) {
42493
43089
  }
42494
43090
  if (totalRemoved === 0) return false;
42495
43091
  if (Object.keys(hooks).length === 0) delete settings.hooks;
42496
- writeFileSync10(
43092
+ writeFileSync11(
42497
43093
  settingsPath,
42498
43094
  `${JSON.stringify(settings, null, 2)}
42499
43095
  `,
@@ -42511,11 +43107,31 @@ init_mcp_config_writer();
42511
43107
 
42512
43108
  // src/config/instruction-writer.ts
42513
43109
  init_agent_registry();
42514
- import { existsSync as existsSync21, mkdirSync as mkdirSync15, readFileSync as readFileSync20, unlinkSync as unlinkSync3, writeFileSync as writeFileSync11 } from "fs";
43110
+ import { existsSync as existsSync22, mkdirSync as mkdirSync15, readFileSync as readFileSync21, unlinkSync as unlinkSync3, writeFileSync as writeFileSync12 } from "fs";
42515
43111
  import { dirname as dirname5, join as join28 } from "path";
42516
43112
  var SENTINEL_START = "<!-- unerr:start -->";
42517
43113
  var SENTINEL_END = "<!-- unerr:end -->";
42518
- function getInstructionContent() {
43114
+ function getInstructionContent(ide) {
43115
+ const isClaudeCode = ide === "claude-code";
43116
+ const readForEditRow = isClaudeCode ? `| Understand a file before editing | \`file_read\` with \`purpose:'explore'\` to understand, then built-in \`Read\` (offset/limit) on target lines before Edit | Reading entire file |` : `| Read a file before editing | \`file_read\` with \`entity\` param or offset/limit for targeted access | Reading entire file |`;
43117
+ const twoStepSection = isClaudeCode ? `
43118
+ ### IMPORTANT: Two-step Read Routing (Claude Code specific)
43119
+
43120
+ **Why this matters:** Claude Code's Edit tool requires built-in \`Read\` to have been called on the file first. \`file_read\` (unerr MCP) does NOT satisfy this because it's a separate MCP tool. Meanwhile, built-in Read misses project conventions and facts that \`file_read\` auto-injects.
43121
+
43122
+ **The rule \u2014 two paths, choose by intent:**
43123
+
43124
+ | Intent | Tool | Why |
43125
+ |--------|------|-----|
43126
+ | Reading to understand code | \`file_read\` (unerr MCP) | Auto-injects conventions, facts, drift status |
43127
+ | Reading immediately before Edit | Built-in \`Read\` with offset/limit | Required by Edit tool \u2014 \`file_read\` does NOT satisfy this. Use targeted reads (offset/limit) for only the lines you plan to edit. |
43128
+
43129
+ When your next action is Edit, use built-in Read with offset/limit on the target lines. For everything else, use \`file_read\`.
43130
+
43131
+ **Common failure mode:** Using \`file_read\` to understand a file, then attempting Edit without calling built-in Read first. The Edit tool WILL reject with "File has not been read yet". Always call built-in Read (with offset/limit) immediately before Edit.` : "";
43132
+ const summaryEditNote = isClaudeCode ? `
43133
+ NEVER use built-in Read/Grep/Glob for code navigation. EXCEPTION: built-in Read (with offset/limit) is REQUIRED immediately before Edit (file_read cannot substitute \u2014 Edit will fail without it).` : `
43134
+ NEVER use built-in Read/Grep/Glob for code navigation \u2014 use unerr MCP tools instead.`;
42519
43135
  return `## REQUIRED: Use unerr Graph Intelligence Tools (18 MCP tools)
42520
43136
 
42521
43137
  This project has unerr MCP tools installed. You MUST use these instead of built-in Read/Grep/Glob for code navigation. unerr tools are graph-backed, return results in <5ms, and include project context that built-in tools miss.
@@ -42526,8 +43142,8 @@ This project has unerr MCP tools installed. You MUST use these instead of built-
42526
43142
  |---|---|---|
42527
43143
  | Find a function, class, or type | \`search_code\` | Grep, Glob |
42528
43144
  | Find callers or callees | \`get_references\` (direction: callers/callees) | Grep for function name |
42529
- | Read a file for understanding | \`file_read\` with \`purpose:'explore'\` (default, auto-injects conventions/facts) | Built-in Read (use ONLY before Edit) |
42530
- | Understand a file before editing | \`file_read\` with \`purpose:'edit'\` (returns full file, no gating) | Multiple offset/limit calls |
43145
+ | Read a file for understanding | \`file_read\` with \`purpose:'explore'\` (default, auto-injects conventions/facts) | Built-in Read/Grep/Glob |
43146
+ ${readForEditRow}
42531
43147
  | Get file structure overview | \`file_outline\` | Reading the whole file |
42532
43148
  | Get a specific function or class | \`get_entity\` or \`file_read\` with \`entity\` param | Reading entire file |
42533
43149
  | Trace imports/dependencies | \`get_imports\` or \`get_references\` (direction: callees) | Manual import scanning |
@@ -42535,27 +43151,12 @@ This project has unerr MCP tools installed. You MUST use these instead of built-
42535
43151
 
42536
43152
  ### FORBIDDEN Patterns (these waste tokens and miss context)
42537
43153
 
42538
- - Calling file_read multiple times with offset/limit to read a whole file -> use \`file_read\` with \`purpose:'edit'\` (one call, full content)
42539
43154
  - Reading an entire file to find one function -> use \`get_entity\` or \`file_read\` with \`entity\` param
42540
43155
  - Grep for a function name to find callers -> use \`get_references\` (finds indirect refs too)
42541
43156
  - Glob + Grep to search for code -> use \`search_code\` (indexes ALL entities, <5ms)
42542
43157
  - Reading multiple files to understand conventions -> use \`get_conventions\`
42543
43158
  - Guessing code style for new code -> use \`get_rules\` (with \`content\` param to validate)
42544
-
42545
- ### IMPORTANT: Two-step Read Routing
42546
-
42547
- **Why this matters:** The Edit tool has a hard technical constraint \u2014 it requires built-in \`Read\` to have been called on the file first. \`file_read\` (unerr MCP) does NOT satisfy this requirement because it's a separate MCP tool, not the built-in Read. Meanwhile, built-in Read misses project conventions, facts, and drift status that \`file_read\` auto-injects. Using the wrong one at the wrong time either blocks your edit or loses critical context.
42548
-
42549
- **The rule \u2014 two paths, choose by intent:**
42550
-
42551
- | Intent | Tool | Why |
42552
- |--------|------|-----|
42553
- | Reading to understand code | \`file_read\` (unerr MCP) | Auto-injects conventions, facts, drift status |
42554
- | Reading immediately before Edit | Built-in \`Read\` with offset/limit | Required by Edit tool \u2014 \`file_read\` does NOT satisfy this. Use targeted reads (offset/limit) for only the lines you plan to edit. |
42555
-
42556
- When your next action is Edit, use built-in Read. For everything else, use \`file_read\`.
42557
-
42558
- **Common failure mode:** Using \`file_read\` to understand a file, then attempting Edit without calling built-in Read first. The Edit tool WILL reject with "File has not been read yet" \u2014 \`file_read\` (MCP) cannot satisfy this requirement. Always call built-in Read immediately before Edit.
43159
+ - Reading a full file when you only need a section -> use \`file_read\` with \`entity\` param or offset/limit${twoStepSection}
42559
43160
 
42560
43161
  ### Tool Reference
42561
43162
 
@@ -42581,9 +43182,8 @@ When your next action is Edit, use built-in Read. For everything else, use \`fil
42581
43182
 
42582
43183
  \`file_read\` auto-injects relevant facts and conventions. For files >50 lines, call \`file_outline\` first, then \`file_read\` with \`entity\` param for targeted access.
42583
43184
 
42584
- **\`purpose\` parameter (IMPORTANT):** Controls read behavior \u2014 set it to match your intent:
42585
- - \`purpose:'explore'\` (default) \u2014 budget-capped, returns outline for large files. Use for browsing/understanding.
42586
- - \`purpose:'edit'\` \u2014 returns full file content with NO gating or budget cap. Use when you plan to modify the file. **One call instead of 3-5 offset/limit calls.**
43185
+ **\`purpose\` parameter:** Controls read behavior \u2014 set it to match your intent:
43186
+ - \`purpose:'explore'\` (default) \u2014 budget-capped, returns outline for large files. Use for browsing and pre-edit understanding.
42587
43187
  - \`purpose:'reference'\` \u2014 tight budget, entity/offset reads only. Use for quick lookups.
42588
43188
 
42589
43189
  #### Shell Compression (automatic)
@@ -42622,8 +43222,7 @@ ONLY use built-in Read/Grep/Glob when:
42622
43222
 
42623
43223
  ### Summary (CRITICAL \u2014 read this even if you skimmed above)
42624
43224
 
42625
- ALWAYS use unerr MCP tools: \`search_code\`, \`get_references\`, \`file_read\`, \`file_outline\`, \`get_entity\`.
42626
- NEVER use built-in Read/Grep/Glob for code navigation. EXCEPTION: built-in Read is REQUIRED before Edit (file_read cannot substitute \u2014 Edit will fail without it).
43225
+ ALWAYS use unerr MCP tools: \`search_code\`, \`get_references\`, \`file_read\`, \`file_outline\`, \`get_entity\`.${summaryEditNote}
42627
43226
  unerr skills available: /audit, /blame, /test, /lint, /commit, /review-pr.
42628
43227
  Before writing code: \`get_conventions\`, \`get_rules\`. After writing: \`get_rules\` with content to validate.
42629
43228
  Before risky changes: \`unerr_mark_working\`. If things break: \`unerr_revert_to_working_state\`.`;
@@ -42634,7 +43233,7 @@ description: REQUIRED \u2014 use unerr graph intelligence tools instead of built
42634
43233
  alwaysApply: true
42635
43234
  ---
42636
43235
 
42637
- ${getInstructionContent()}
43236
+ ${getInstructionContent("cursor")}
42638
43237
  `;
42639
43238
  }
42640
43239
  function writeInstructionFile(cwd, ide) {
@@ -42648,7 +43247,7 @@ function writeInstructionFile(cwd, ide) {
42648
43247
  }
42649
43248
  if (agentDef.instructionFormat === "windsurf-rule") {
42650
43249
  mkdirSync15(dirname5(filePath), { recursive: true });
42651
- const content = getInstructionContent();
43250
+ const content = getInstructionContent(ide);
42652
43251
  const truncatedContent = content.length > 5800 ? `${content.slice(0, 5800)}
42653
43252
 
42654
43253
  [Truncated \u2014 full content exceeds Windsurf 6K limit]` : content;
@@ -42659,19 +43258,19 @@ description: "Tool routing instructions for unerr MCP integration"
42659
43258
 
42660
43259
  ${truncatedContent}
42661
43260
  `;
42662
- const existed = existsSync21(filePath);
43261
+ const existed = existsSync22(filePath);
42663
43262
  if (existed) {
42664
- const existing = readFileSync20(filePath, "utf-8");
43263
+ const existing = readFileSync21(filePath, "utf-8");
42665
43264
  if (existing === windsurfContent) {
42666
43265
  return { path: filePath, action: "skipped" };
42667
43266
  }
42668
43267
  }
42669
- writeFileSync11(filePath, windsurfContent, "utf-8");
43268
+ writeFileSync12(filePath, windsurfContent, "utf-8");
42670
43269
  return { path: filePath, action: existed ? "updated" : "created" };
42671
43270
  }
42672
43271
  if (agentDef.instructionFormat === "antigravity-rule") {
42673
43272
  mkdirSync15(dirname5(filePath), { recursive: true });
42674
- const content = getInstructionContent();
43273
+ const content = getInstructionContent(ide);
42675
43274
  const antigravityContent = `---
42676
43275
  name: unerr-instructions
42677
43276
  description: Tool routing instructions for unerr MCP integration
@@ -42680,34 +43279,34 @@ type: manual
42680
43279
 
42681
43280
  ${content}
42682
43281
  `;
42683
- const existed = existsSync21(filePath);
43282
+ const existed = existsSync22(filePath);
42684
43283
  if (existed) {
42685
- const existing = readFileSync20(filePath, "utf-8");
43284
+ const existing = readFileSync21(filePath, "utf-8");
42686
43285
  if (existing === antigravityContent) {
42687
43286
  return { path: filePath, action: "skipped" };
42688
43287
  }
42689
43288
  }
42690
- writeFileSync11(filePath, antigravityContent, "utf-8");
43289
+ writeFileSync12(filePath, antigravityContent, "utf-8");
42691
43290
  return { path: filePath, action: existed ? "updated" : "created" };
42692
43291
  }
42693
- return mergeMarkdownSection(filePath, getInstructionContent());
43292
+ return mergeMarkdownSection(filePath, getInstructionContent(ide));
42694
43293
  }
42695
43294
  function mergeMarkdownSection(filePath, content) {
42696
43295
  const wrappedContent = `${SENTINEL_START}
42697
43296
  ${content}
42698
43297
  ${SENTINEL_END}`;
42699
- if (!existsSync21(filePath)) {
43298
+ if (!existsSync22(filePath)) {
42700
43299
  const dir = dirname5(filePath);
42701
- if (!existsSync21(dir)) mkdirSync15(dir, { recursive: true });
42702
- writeFileSync11(filePath, `${wrappedContent}
43300
+ if (!existsSync22(dir)) mkdirSync15(dir, { recursive: true });
43301
+ writeFileSync12(filePath, `${wrappedContent}
42703
43302
  `);
42704
43303
  return { path: filePath, action: "created" };
42705
43304
  }
42706
- const existing = readFileSync20(filePath, "utf-8");
43305
+ const existing = readFileSync21(filePath, "utf-8");
42707
43306
  const startIdx = existing.indexOf(SENTINEL_START);
42708
43307
  const endIdx = existing.indexOf(SENTINEL_END);
42709
43308
  if (startIdx === -1 || endIdx === -1) {
42710
- writeFileSync11(filePath, `${wrappedContent}
43309
+ writeFileSync12(filePath, `${wrappedContent}
42711
43310
 
42712
43311
  ${existing}`);
42713
43312
  return { path: filePath, action: "updated" };
@@ -42718,21 +43317,21 @@ ${existing}`);
42718
43317
  }
42719
43318
  const before = existing.slice(0, startIdx);
42720
43319
  const after = existing.slice(endIdx + SENTINEL_END.length);
42721
- writeFileSync11(filePath, `${before}${wrappedContent}${after}`);
43320
+ writeFileSync12(filePath, `${before}${wrappedContent}${after}`);
42722
43321
  return { path: filePath, action: "updated" };
42723
43322
  }
42724
43323
  function writeMdcInstructionFile(filePath) {
42725
43324
  const content = getMdcContent();
42726
- const alreadyExists = existsSync21(filePath);
43325
+ const alreadyExists = existsSync22(filePath);
42727
43326
  if (alreadyExists) {
42728
- const existing = readFileSync20(filePath, "utf-8");
43327
+ const existing = readFileSync21(filePath, "utf-8");
42729
43328
  if (existing === content) {
42730
43329
  return { path: filePath, action: "skipped" };
42731
43330
  }
42732
43331
  }
42733
43332
  const dir = dirname5(filePath);
42734
- if (!existsSync21(dir)) mkdirSync15(dir, { recursive: true });
42735
- writeFileSync11(filePath, content);
43333
+ if (!existsSync22(dir)) mkdirSync15(dir, { recursive: true });
43334
+ writeFileSync12(filePath, content);
42736
43335
  return {
42737
43336
  path: filePath,
42738
43337
  action: alreadyExists ? "updated" : "created"
@@ -42742,26 +43341,26 @@ function removeInstructionSection(cwd, ide) {
42742
43341
  const agentDef = getAgent(ide);
42743
43342
  if (!agentDef?.instructionFilePath) return false;
42744
43343
  const filePath = join28(cwd, agentDef.instructionFilePath);
42745
- if (!existsSync21(filePath)) return false;
43344
+ if (!existsSync22(filePath)) return false;
42746
43345
  if (agentDef.instructionFormat === "mdc") {
42747
43346
  unlinkSync3(filePath);
42748
43347
  return true;
42749
43348
  }
42750
43349
  if (agentDef.instructionFormat === "windsurf-rule") {
42751
- if (existsSync21(filePath)) {
43350
+ if (existsSync22(filePath)) {
42752
43351
  unlinkSync3(filePath);
42753
43352
  return true;
42754
43353
  }
42755
43354
  return false;
42756
43355
  }
42757
43356
  if (agentDef.instructionFormat === "antigravity-rule") {
42758
- if (existsSync21(filePath)) {
43357
+ if (existsSync22(filePath)) {
42759
43358
  unlinkSync3(filePath);
42760
43359
  return true;
42761
43360
  }
42762
43361
  return false;
42763
43362
  }
42764
- const content = readFileSync20(filePath, "utf-8");
43363
+ const content = readFileSync21(filePath, "utf-8");
42765
43364
  const startIdx = content.indexOf(SENTINEL_START);
42766
43365
  const endIdx = content.indexOf(SENTINEL_END);
42767
43366
  if (startIdx === -1 || endIdx === -1) return false;
@@ -42772,12 +43371,12 @@ function removeInstructionSection(cwd, ide) {
42772
43371
  if (trimmed.length === 0) {
42773
43372
  unlinkSync3(filePath);
42774
43373
  } else {
42775
- writeFileSync11(filePath, cleaned);
43374
+ writeFileSync12(filePath, cleaned);
42776
43375
  }
42777
43376
  return true;
42778
43377
  }
42779
43378
  function generateCustomInstructions(ide) {
42780
- const content = getInstructionContent();
43379
+ const content = getInstructionContent(ide);
42781
43380
  if (ide && ide !== "other") {
42782
43381
  const agentDef = getAgent(ide);
42783
43382
  if (agentDef?.instructionFilePath) {
@@ -43149,16 +43748,16 @@ function installCursorHooks(cwd) {
43149
43748
  ]
43150
43749
  };
43151
43750
  try {
43152
- if (!existsSync23(hooksDir)) {
43751
+ if (!existsSync24(hooksDir)) {
43153
43752
  mkdirSync17(hooksDir, { recursive: true });
43154
43753
  }
43155
43754
  let config = {
43156
43755
  version: 1,
43157
43756
  hooks: {}
43158
43757
  };
43159
- if (existsSync23(hooksJsonPath)) {
43758
+ if (existsSync24(hooksJsonPath)) {
43160
43759
  try {
43161
- const existing = JSON.parse(readFileSync22(hooksJsonPath, "utf-8"));
43760
+ const existing = JSON.parse(readFileSync23(hooksJsonPath, "utf-8"));
43162
43761
  if (existing.version && existing.hooks) {
43163
43762
  config = existing;
43164
43763
  }
@@ -43175,7 +43774,7 @@ function installCursorHooks(cwd) {
43175
43774
  }
43176
43775
  config.hooks[event] = existing;
43177
43776
  }
43178
- writeFileSync13(hooksJsonPath, `${JSON.stringify(config, null, 2)}
43777
+ writeFileSync14(hooksJsonPath, `${JSON.stringify(config, null, 2)}
43179
43778
  `);
43180
43779
  writeCursorHookScript(hooksDir, "unerr-pre-tool.sh", CURSOR_PRE_TOOL_SCRIPT);
43181
43780
  writeCursorHookScript(hooksDir, "unerr-post-tool.sh", CURSOR_POST_TOOL_SCRIPT);
@@ -43188,15 +43787,15 @@ function installCursorHooks(cwd) {
43188
43787
  }
43189
43788
  function writeCursorHookScript(dir, filename, content) {
43190
43789
  const scriptPath = join30(dir, filename);
43191
- writeFileSync13(scriptPath, content, "utf-8");
43790
+ writeFileSync14(scriptPath, content, "utf-8");
43192
43791
  chmodSync4(scriptPath, 493);
43193
43792
  }
43194
43793
  function installClineHooks(cwd) {
43195
43794
  const hooksDir = join30(cwd, ".clinerules", "hooks");
43196
43795
  const hookPath = join30(hooksDir, "unerr-pre-tool.sh");
43197
- if (existsSync23(hookPath)) return true;
43796
+ if (existsSync24(hookPath)) return true;
43198
43797
  try {
43199
- if (!existsSync23(hooksDir)) {
43798
+ if (!existsSync24(hooksDir)) {
43200
43799
  const { mkdirSync: mkdirSync39 } = __require("fs");
43201
43800
  mkdirSync39(hooksDir, { recursive: true });
43202
43801
  }
@@ -43206,7 +43805,7 @@ function installClineHooks(cwd) {
43206
43805
  # Removed by: unerr uninstall cline
43207
43806
  cat /dev/stdin | unerr hook pre-read
43208
43807
  `;
43209
- writeFileSync13(hookPath, hookContent, "utf-8");
43808
+ writeFileSync14(hookPath, hookContent, "utf-8");
43210
43809
  chmodSync4(hookPath, 493);
43211
43810
  return true;
43212
43811
  } catch {
@@ -43215,15 +43814,15 @@ cat /dev/stdin | unerr hook pre-read
43215
43814
  }
43216
43815
  function ensureGitignore(cwd) {
43217
43816
  const gitignorePath = join30(cwd, ".gitignore");
43218
- if (!existsSync23(gitignorePath)) return false;
43817
+ if (!existsSync24(gitignorePath)) return false;
43219
43818
  try {
43220
- const content = readFileSync22(gitignorePath, "utf-8");
43819
+ const content = readFileSync23(gitignorePath, "utf-8");
43221
43820
  const lines = content.split("\n");
43222
43821
  if (lines.some((l) => l.trim() === ".unerr" || l.trim() === ".unerr/")) {
43223
43822
  return false;
43224
43823
  }
43225
43824
  const newline = content.endsWith("\n") ? "" : "\n";
43226
- writeFileSync13(
43825
+ writeFileSync14(
43227
43826
  gitignorePath,
43228
43827
  `${content}${newline}
43229
43828
  # unerr local artifacts
@@ -43238,7 +43837,7 @@ function ensureGitignore(cwd) {
43238
43837
 
43239
43838
  // src/commands/learn.ts
43240
43839
  init_correction_detector();
43241
- import { existsSync as existsSync25 } from "fs";
43840
+ import { existsSync as existsSync26 } from "fs";
43242
43841
  import { join as join31 } from "path";
43243
43842
  import { gunzipSync as gunzipSync2 } from "zlib";
43244
43843
  import pc3 from "picocolors";
@@ -43255,7 +43854,7 @@ function registerLearnCommand(program2) {
43255
43854
  const cwd = process.cwd();
43256
43855
  const unerrDir = join31(cwd, ".unerr");
43257
43856
  const ledgerPath = join31(unerrDir, "ledger", "shadow.jsonl");
43258
- if (!existsSync25(ledgerPath)) {
43857
+ if (!existsSync26(ledgerPath)) {
43259
43858
  fail("No shadow ledger found at .unerr/ledger/shadow.jsonl");
43260
43859
  info(
43261
43860
  "The shadow ledger is created when the unerr proxy runs. Start the proxy first."
@@ -43312,20 +43911,20 @@ async function persistPatterns(patterns, _unerrDir) {
43312
43911
  try {
43313
43912
  const cwd = process.cwd();
43314
43913
  const configPath = join31(cwd, ".unerr", "config.json");
43315
- if (!existsSync25(configPath)) {
43914
+ if (!existsSync26(configPath)) {
43316
43915
  warn(
43317
43916
  "No repo config found \u2014 cannot persist to CozoDB. Run 'unerr' to configure."
43318
43917
  );
43319
43918
  return;
43320
43919
  }
43321
- const { readFileSync: readFileSync57 } = await import("fs");
43322
- const config = JSON.parse(readFileSync57(configPath, "utf-8"));
43920
+ const { readFileSync: readFileSync58 } = await import("fs");
43921
+ const config = JSON.parse(readFileSync58(configPath, "utf-8"));
43323
43922
  if (!config.repoId || !config.orgId) {
43324
43923
  warn("Repo not configured \u2014 cannot persist to CozoDB.");
43325
43924
  return;
43326
43925
  }
43327
43926
  const snapshotPath2 = join31(cwd, ".unerr", "snapshots", "graph.msgpack.gz");
43328
- if (!existsSync25(snapshotPath2)) {
43927
+ if (!existsSync26(snapshotPath2)) {
43329
43928
  warn("No graph snapshot found \u2014 cannot persist to CozoDB.");
43330
43929
  return;
43331
43930
  }
@@ -43337,7 +43936,7 @@ async function persistPatterns(patterns, _unerrDir) {
43337
43936
  const { CozoGraphStore: CozoGraphStore2 } = await Promise.resolve().then(() => (init_local_graph(), local_graph_exports));
43338
43937
  const store = await CozoGraphStore2.create(db);
43339
43938
  const { unpack } = await import("msgpackr");
43340
- const raw = readFileSync57(snapshotPath2);
43939
+ const raw = readFileSync58(snapshotPath2);
43341
43940
  const buffer = gunzipSync2(raw);
43342
43941
  const envelope = unpack(buffer);
43343
43942
  await store.loadSnapshot(envelope);
@@ -43354,16 +43953,16 @@ async function persistPatterns(patterns, _unerrDir) {
43354
43953
 
43355
43954
  // src/commands/manifest.ts
43356
43955
  init_exec();
43357
- import { existsSync as existsSync26, readFileSync as readFileSync24 } from "fs";
43956
+ import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
43358
43957
  import { join as join32 } from "path";
43359
43958
  async function findRepoRoot() {
43360
43959
  return gitQuery(["rev-parse", "--show-toplevel"]);
43361
43960
  }
43362
43961
  function loadManifest(repoRoot) {
43363
43962
  const manifestPath = join32(repoRoot, ".unerr", "manifest.json");
43364
- if (!existsSync26(manifestPath)) return null;
43963
+ if (!existsSync27(manifestPath)) return null;
43365
43964
  try {
43366
- const raw = readFileSync24(manifestPath, "utf-8");
43965
+ const raw = readFileSync25(manifestPath, "utf-8");
43367
43966
  return JSON.parse(raw);
43368
43967
  } catch {
43369
43968
  return null;
@@ -43684,7 +44283,7 @@ function registerStatsCommand(program2) {
43684
44283
 
43685
44284
  // src/commands/status.ts
43686
44285
  init_git();
43687
- import { existsSync as existsSync31, readFileSync as readFileSync29 } from "fs";
44286
+ import { existsSync as existsSync32, readFileSync as readFileSync30 } from "fs";
43688
44287
  import { join as join38 } from "path";
43689
44288
  import React from "react";
43690
44289
  function buildSuggestions(data) {
@@ -43733,9 +44332,9 @@ function registerStatusCommand(program2) {
43733
44332
  const localDataDir = join38(cwd, ".unerr");
43734
44333
  let repoId = "";
43735
44334
  const configPath = join38(unerrDir, "config.json");
43736
- if (existsSync31(configPath)) {
44335
+ if (existsSync32(configPath)) {
43737
44336
  try {
43738
- const config = JSON.parse(readFileSync29(configPath, "utf-8"));
44337
+ const config = JSON.parse(readFileSync30(configPath, "utf-8"));
43739
44338
  repoId = config.repoId ?? "";
43740
44339
  } catch {
43741
44340
  }
@@ -43764,9 +44363,9 @@ function registerStatusCommand(program2) {
43764
44363
  let proxyStatus = "Not running";
43765
44364
  let proxyRunning = false;
43766
44365
  const pidPath = join38(unerrDir, "state", "proxy.pid");
43767
- if (existsSync31(pidPath)) {
44366
+ if (existsSync32(pidPath)) {
43768
44367
  try {
43769
- const pidStr = readFileSync29(pidPath, "utf-8").trim();
44368
+ const pidStr = readFileSync30(pidPath, "utf-8").trim();
43770
44369
  const pid = Number.parseInt(pidStr, 10);
43771
44370
  process.kill(pid, 0);
43772
44371
  proxyStatus = `Running (PID ${pid})`;
@@ -43777,10 +44376,10 @@ function registerStatusCommand(program2) {
43777
44376
  }
43778
44377
  let graphInfo = "No local graph";
43779
44378
  const manifestsDir = join38(localDataDir, "manifests");
43780
- if (repoId && existsSync31(join38(manifestsDir, `${repoId}.json`))) {
44379
+ if (repoId && existsSync32(join38(manifestsDir, `${repoId}.json`))) {
43781
44380
  try {
43782
44381
  const manifest = JSON.parse(
43783
- readFileSync29(join38(manifestsDir, `${repoId}.json`), "utf-8")
44382
+ readFileSync30(join38(manifestsDir, `${repoId}.json`), "utf-8")
43784
44383
  );
43785
44384
  const entityCount = manifest.entityCount ?? 0;
43786
44385
  const edgeCount = manifest.edgeCount ?? 0;
@@ -43799,10 +44398,10 @@ function registerStatusCommand(program2) {
43799
44398
  }
43800
44399
  let drift;
43801
44400
  const driftSummaryPath = join38(unerrDir, "drift", "drift_summary.json");
43802
- if (existsSync31(driftSummaryPath)) {
44401
+ if (existsSync32(driftSummaryPath)) {
43803
44402
  try {
43804
44403
  const summary = JSON.parse(
43805
- readFileSync29(driftSummaryPath, "utf-8")
44404
+ readFileSync30(driftSummaryPath, "utf-8")
43806
44405
  );
43807
44406
  drift = {
43808
44407
  modified: summary.modified ?? 0,
@@ -43815,9 +44414,9 @@ function registerStatusCommand(program2) {
43815
44414
  let healthGrade;
43816
44415
  let healthScore;
43817
44416
  const graphVersionPath = join38(unerrDir, "state", "graph_version.json");
43818
- if (existsSync31(graphVersionPath)) {
44417
+ if (existsSync32(graphVersionPath)) {
43819
44418
  try {
43820
- const gv = JSON.parse(readFileSync29(graphVersionPath, "utf-8"));
44419
+ const gv = JSON.parse(readFileSync30(graphVersionPath, "utf-8"));
43821
44420
  healthGrade = gv.health_grade;
43822
44421
  healthScore = gv.health_score;
43823
44422
  } catch {
@@ -43828,15 +44427,15 @@ function registerStatusCommand(program2) {
43828
44427
  try {
43829
44428
  const snapshotsDir = join38(localDataDir, "snapshots");
43830
44429
  let snapshotPath2 = join38(snapshotsDir, "graph.msgpack.gz");
43831
- if (!existsSync31(snapshotPath2)) {
44430
+ if (!existsSync32(snapshotPath2)) {
43832
44431
  snapshotPath2 = join38(snapshotsDir, "graph.msgpack");
43833
44432
  }
43834
- if (existsSync31(snapshotPath2)) {
44433
+ if (existsSync32(snapshotPath2)) {
43835
44434
  const { gunzipSync: gunzipSync3 } = await import("zlib");
43836
44435
  const { unpack } = await import("msgpackr");
43837
44436
  const { default: CozoDbConstructor } = await import("cozo-node");
43838
44437
  const { CozoGraphStore: CozoGraphStore2 } = await Promise.resolve().then(() => (init_local_graph(), local_graph_exports));
43839
- const raw = readFileSync29(snapshotPath2);
44438
+ const raw = readFileSync30(snapshotPath2);
43840
44439
  let buffer;
43841
44440
  try {
43842
44441
  buffer = gunzipSync3(raw);
@@ -43855,9 +44454,9 @@ function registerStatusCommand(program2) {
43855
44454
  let liveToolCalls;
43856
44455
  let latency;
43857
44456
  const statsPath = join38(unerrDir, "state", "session_stats.json");
43858
- if (existsSync31(statsPath) && proxyRunning) {
44457
+ if (existsSync32(statsPath) && proxyRunning) {
43859
44458
  try {
43860
- const liveStats = JSON.parse(readFileSync29(statsPath, "utf-8"));
44459
+ const liveStats = JSON.parse(readFileSync30(statsPath, "utf-8"));
43861
44460
  const localCalls = liveStats.toolCallsLocal ?? 0;
43862
44461
  if (localCalls > 0) {
43863
44462
  liveToolCalls = { local: localCalls };
@@ -43884,8 +44483,8 @@ function registerStatusCommand(program2) {
43884
44483
  "state",
43885
44484
  "firewall_stats.json"
43886
44485
  );
43887
- if (existsSync31(firewallStatsPath)) {
43888
- const fs5 = JSON.parse(readFileSync29(firewallStatsPath, "utf-8"));
44486
+ if (existsSync32(firewallStatsPath)) {
44487
+ const fs5 = JSON.parse(readFileSync30(firewallStatsPath, "utf-8"));
43889
44488
  firewallBlocked = fs5.blocked ?? 0;
43890
44489
  }
43891
44490
  } catch {
@@ -43922,9 +44521,9 @@ function registerStatusCommand(program2) {
43922
44521
  }
43923
44522
  let lastIndexed;
43924
44523
  const snapshotMetaPath = join38(unerrDir, "state", "snapshot_meta.json");
43925
- if (existsSync31(snapshotMetaPath)) {
44524
+ if (existsSync32(snapshotMetaPath)) {
43926
44525
  try {
43927
- const meta = JSON.parse(readFileSync29(snapshotMetaPath, "utf-8"));
44526
+ const meta = JSON.parse(readFileSync30(snapshotMetaPath, "utf-8"));
43928
44527
  if (meta.indexedAt) {
43929
44528
  const ageMs = Date.now() - new Date(meta.indexedAt).getTime();
43930
44529
  const ageHours = Math.floor(ageMs / 36e5);
@@ -43941,8 +44540,8 @@ function registerStatusCommand(program2) {
43941
44540
  let corrections;
43942
44541
  try {
43943
44542
  const corrPath = join38(unerrDir, "state", "corrections_count.json");
43944
- if (existsSync31(corrPath)) {
43945
- const cc = JSON.parse(readFileSync29(corrPath, "utf-8"));
44543
+ if (existsSync32(corrPath)) {
44544
+ const cc = JSON.parse(readFileSync30(corrPath, "utf-8"));
43946
44545
  corrections = cc.count;
43947
44546
  }
43948
44547
  } catch {
@@ -43951,8 +44550,8 @@ function registerStatusCommand(program2) {
43951
44550
  let conventionCount;
43952
44551
  let ruleCount;
43953
44552
  try {
43954
- if (existsSync31(graphVersionPath)) {
43955
- const gv = JSON.parse(readFileSync29(graphVersionPath, "utf-8"));
44553
+ if (existsSync32(graphVersionPath)) {
44554
+ const gv = JSON.parse(readFileSync30(graphVersionPath, "utf-8"));
43956
44555
  communityCount = gv.community_count;
43957
44556
  conventionCount = gv.convention_count;
43958
44557
  ruleCount = gv.rule_count;
@@ -43994,8 +44593,8 @@ function registerStatusCommand(program2) {
43994
44593
  let ledgerEntryCount;
43995
44594
  try {
43996
44595
  const ledgerPath = join38(unerrDir, "ledger", "shadow.jsonl");
43997
- if (existsSync31(ledgerPath)) {
43998
- const content = readFileSync29(ledgerPath, "utf-8");
44596
+ if (existsSync32(ledgerPath)) {
44597
+ const content = readFileSync30(ledgerPath, "utf-8");
43999
44598
  ledgerEntryCount = content.split("\n").filter((l) => l.trim().length > 0).length;
44000
44599
  }
44001
44600
  } catch {
@@ -44003,7 +44602,7 @@ function registerStatusCommand(program2) {
44003
44602
  let logPath;
44004
44603
  try {
44005
44604
  const logsDir = join38(unerrDir, "logs");
44006
- if (existsSync31(logsDir)) {
44605
+ if (existsSync32(logsDir)) {
44007
44606
  const { readdirSync: readdirSync15, statSync: statSync12 } = await import("fs");
44008
44607
  const logs = readdirSync15(logsDir).filter((f) => f.startsWith("session-") && f.endsWith(".log")).map((f) => ({
44009
44608
  name: f,
@@ -44034,8 +44633,8 @@ function registerStatusCommand(program2) {
44034
44633
  if (!proxyRunning) {
44035
44634
  try {
44036
44635
  const statsPath2 = join38(unerrDir, "state", "session_stats.json");
44037
- if (existsSync31(statsPath2)) {
44038
- const raw = JSON.parse(readFileSync29(statsPath2, "utf-8"));
44636
+ if (existsSync32(statsPath2)) {
44637
+ const raw = JSON.parse(readFileSync30(statsPath2, "utf-8"));
44039
44638
  const totalCalls = raw.toolCallsLocal ?? 0;
44040
44639
  if (totalCalls > 0) {
44041
44640
  const endTime = raw.updatedAt ? new Date(raw.updatedAt) : /* @__PURE__ */ new Date();
@@ -44070,8 +44669,8 @@ function registerStatusCommand(program2) {
44070
44669
  let preBashHookConfigured = false;
44071
44670
  try {
44072
44671
  const sp = join38(cwd, ".claude", "settings.json");
44073
- if (existsSync31(sp)) {
44074
- const raw = readFileSync29(sp, "utf8");
44672
+ if (existsSync32(sp)) {
44673
+ const raw = readFileSync30(sp, "utf8");
44075
44674
  preBashHookConfigured = raw.includes("unerr hook pre-bash") || raw.includes('"unerr hook pre-bash"');
44076
44675
  }
44077
44676
  } catch {
@@ -44359,7 +44958,7 @@ function registerTimelineCommand(program2) {
44359
44958
 
44360
44959
  // src/commands/uninstall.ts
44361
44960
  init_agent_registry();
44362
- import { existsSync as existsSync33, readFileSync as readFileSync31, unlinkSync as unlinkSync5, writeFileSync as writeFileSync17 } from "fs";
44961
+ import { existsSync as existsSync34, readFileSync as readFileSync32, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "fs";
44363
44962
  import { join as join40 } from "path";
44364
44963
  init_hook_installer();
44365
44964
  init_mcp_config_writer();
@@ -44504,9 +45103,9 @@ function runUninstallAll(cwd) {
44504
45103
  }
44505
45104
  function removeCursorHooks(cwd) {
44506
45105
  const hooksPath = join40(cwd, ".cursor", "hooks.json");
44507
- if (!existsSync33(hooksPath)) return false;
45106
+ if (!existsSync34(hooksPath)) return false;
44508
45107
  try {
44509
- const config = JSON.parse(readFileSync31(hooksPath, "utf-8"));
45108
+ const config = JSON.parse(readFileSync32(hooksPath, "utf-8"));
44510
45109
  if (!Array.isArray(config.hooks)) return false;
44511
45110
  const before = config.hooks.length;
44512
45111
  config.hooks = config.hooks.filter(
@@ -44516,7 +45115,7 @@ function removeCursorHooks(cwd) {
44516
45115
  if (config.hooks.length === 0) {
44517
45116
  unlinkSync5(hooksPath);
44518
45117
  } else {
44519
- writeFileSync17(hooksPath, `${JSON.stringify(config, null, 2)}
45118
+ writeFileSync18(hooksPath, `${JSON.stringify(config, null, 2)}
44520
45119
  `);
44521
45120
  }
44522
45121
  return true;
@@ -44526,7 +45125,7 @@ function removeCursorHooks(cwd) {
44526
45125
  }
44527
45126
  function removeClineHooks(cwd) {
44528
45127
  const hookPath = join40(cwd, ".clinerules", "hooks", "unerr-pre-tool.sh");
44529
- if (!existsSync33(hookPath)) return false;
45128
+ if (!existsSync34(hookPath)) return false;
44530
45129
  try {
44531
45130
  unlinkSync5(hookPath);
44532
45131
  return true;
@@ -45081,9 +45680,9 @@ async function detectProjectRoot(cwd) {
45081
45680
  }
45082
45681
  function readLocalConfig(cwd) {
45083
45682
  const configPath = join67(cwd, ".unerr", "config.json");
45084
- if (!existsSync62(configPath)) return null;
45683
+ if (!existsSync63(configPath)) return null;
45085
45684
  try {
45086
- return JSON.parse(readFileSync56(configPath, "utf-8"));
45685
+ return JSON.parse(readFileSync57(configPath, "utf-8"));
45087
45686
  } catch {
45088
45687
  return null;
45089
45688
  }
@@ -45158,7 +45757,7 @@ async function mcpBoot(cwd) {
45158
45757
  }
45159
45758
  const stateDir = join67(cwd, ".unerr", "state");
45160
45759
  const sockPath = join67(stateDir, "proxy.sock");
45161
- if (existsSync62(sockPath)) {
45760
+ if (existsSync63(sockPath)) {
45162
45761
  const { PidLock: PidLock2 } = await Promise.resolve().then(() => (init_pid_lock(), pid_lock_exports));
45163
45762
  const pidLock = new PidLock2(stateDir);
45164
45763
  const probeResult = await pidLock.probe();
@@ -45179,12 +45778,12 @@ async function mcpBoot(cwd) {
45179
45778
  }
45180
45779
  }
45181
45780
  if (!readLocalConfig(cwd)) {
45182
- const { mkdirSync: mkdirSync39, writeFileSync: writeFileSync36 } = await import("fs");
45781
+ const { mkdirSync: mkdirSync39, writeFileSync: writeFileSync37 } = await import("fs");
45183
45782
  const { createHash: createHash5 } = await import("crypto");
45184
45783
  const repoId = createHash5("sha256").update(cwd).digest("hex").slice(0, 12);
45185
45784
  const unerrDir = join67(cwd, ".unerr");
45186
45785
  mkdirSync39(unerrDir, { recursive: true });
45187
- writeFileSync36(
45786
+ writeFileSync37(
45188
45787
  join67(unerrDir, "config.json"),
45189
45788
  JSON.stringify(
45190
45789
  { repoId, mode: "local", createdAt: (/* @__PURE__ */ new Date()).toISOString() },