ctxloom-pro 1.5.5 → 1.5.6

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.
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  VectorStore
3
- } from "./chunk-R56D54Y7.js";
3
+ } from "./chunk-JULFFD7O.js";
4
4
  import {
5
5
  collectFiles,
6
6
  generateEmbedding
7
- } from "./chunk-COH5WYZS.js";
7
+ } from "./chunk-WDX4PJGL.js";
8
8
  import {
9
9
  diskSink,
10
10
  readEvents
@@ -2757,12 +2757,12 @@ var DependencyGraph = class {
2757
2757
  symbolIndex: Object.fromEntries(this.symbolIndex.entries())
2758
2758
  };
2759
2759
  const snapshotPath = this.getSnapshotPath();
2760
- const tmpPath = snapshotPath + ".tmp";
2760
+ const tmpPath = `${snapshotPath}.${process.pid}.tmp`;
2761
2761
  fs6.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
2762
2762
  fs6.renameSync(tmpPath, snapshotPath);
2763
2763
  const callData = this.callGraphIndex.toJSON();
2764
2764
  const callPath = path6.join(this.snapshotDir, "call-graph-snapshot.json");
2765
- const callTmp = callPath + ".tmp";
2765
+ const callTmp = `${callPath}.${process.pid}.tmp`;
2766
2766
  fs6.writeFileSync(callTmp, JSON.stringify(callData));
2767
2767
  fs6.renameSync(callTmp, callPath);
2768
2768
  }
@@ -3547,8 +3547,8 @@ var CoChangeIndex = class _CoChangeIndex {
3547
3547
  if (event.isBulk || event.isMerge) return;
3548
3548
  const paths = event.files.map((f) => f.path);
3549
3549
  if (paths.length === 0) return;
3550
- for (const path37 of paths) {
3551
- this.nodeCounts.set(path37, (this.nodeCounts.get(path37) ?? 0) + 1);
3550
+ for (const path38 of paths) {
3551
+ this.nodeCounts.set(path38, (this.nodeCounts.get(path38) ?? 0) + 1);
3552
3552
  }
3553
3553
  for (let i = 0; i < paths.length; i++) {
3554
3554
  for (let j = i + 1; j < paths.length; j++) {
@@ -3695,8 +3695,8 @@ var ChurnIndex = class _ChurnIndex {
3695
3695
  */
3696
3696
  snapshot() {
3697
3697
  const nodes = {};
3698
- for (const [path37, raw] of this.nodes) {
3699
- nodes[path37] = {
3698
+ for (const [path38, raw] of this.nodes) {
3699
+ nodes[path38] = {
3700
3700
  commits: raw.commits,
3701
3701
  churnLines: raw.churnLines,
3702
3702
  bugCommits: raw.bugCommits,
@@ -3711,8 +3711,8 @@ var ChurnIndex = class _ChurnIndex {
3711
3711
  */
3712
3712
  static load(s) {
3713
3713
  const idx = new _ChurnIndex();
3714
- for (const [path37, raw] of Object.entries(s.nodes)) {
3715
- idx.nodes.set(path37, {
3714
+ for (const [path38, raw] of Object.entries(s.nodes)) {
3715
+ idx.nodes.set(path38, {
3716
3716
  commits: raw.commits,
3717
3717
  churnLines: raw.churnLines,
3718
3718
  bugCommits: raw.bugCommits,
@@ -3725,8 +3725,8 @@ var ChurnIndex = class _ChurnIndex {
3725
3725
  // -------------------------------------------------------------------------
3726
3726
  // Private helpers
3727
3727
  // -------------------------------------------------------------------------
3728
- getOrCreate(path37) {
3729
- const existing = this.nodes.get(path37);
3728
+ getOrCreate(path38) {
3729
+ const existing = this.nodes.get(path38);
3730
3730
  if (existing !== void 0) return existing;
3731
3731
  const fresh = {
3732
3732
  commits: 0,
@@ -3735,7 +3735,7 @@ var ChurnIndex = class _ChurnIndex {
3735
3735
  authorCounts: {},
3736
3736
  lastTouch: 0
3737
3737
  };
3738
- this.nodes.set(path37, fresh);
3738
+ this.nodes.set(path38, fresh);
3739
3739
  return fresh;
3740
3740
  }
3741
3741
  };
@@ -3816,12 +3816,12 @@ var OwnershipIndex = class _OwnershipIndex {
3816
3816
  */
3817
3817
  snapshot() {
3818
3818
  const nodes = {};
3819
- for (const [path37, raw] of this.nodes) {
3819
+ for (const [path38, raw] of this.nodes) {
3820
3820
  const authorWeights = {};
3821
3821
  for (const [email, entry] of Object.entries(raw.authorWeights)) {
3822
3822
  authorWeights[email] = { ...entry };
3823
3823
  }
3824
- nodes[path37] = { authorWeights, lastTouch: raw.lastTouch };
3824
+ nodes[path38] = { authorWeights, lastTouch: raw.lastTouch };
3825
3825
  }
3826
3826
  return { version: 1, nodes };
3827
3827
  }
@@ -3830,23 +3830,23 @@ var OwnershipIndex = class _OwnershipIndex {
3830
3830
  */
3831
3831
  static load(s) {
3832
3832
  const idx = new _OwnershipIndex();
3833
- for (const [path37, raw] of Object.entries(s.nodes)) {
3833
+ for (const [path38, raw] of Object.entries(s.nodes)) {
3834
3834
  const authorWeights = {};
3835
3835
  for (const [email, entry] of Object.entries(raw.authorWeights)) {
3836
3836
  authorWeights[email] = { ...entry };
3837
3837
  }
3838
- idx.nodes.set(path37, { authorWeights, lastTouch: raw.lastTouch });
3838
+ idx.nodes.set(path38, { authorWeights, lastTouch: raw.lastTouch });
3839
3839
  }
3840
3840
  return idx;
3841
3841
  }
3842
3842
  // -------------------------------------------------------------------------
3843
3843
  // Private helpers
3844
3844
  // -------------------------------------------------------------------------
3845
- getOrCreate(path37) {
3846
- const existing = this.nodes.get(path37);
3845
+ getOrCreate(path38) {
3846
+ const existing = this.nodes.get(path38);
3847
3847
  if (existing !== void 0) return existing;
3848
3848
  const fresh = { authorWeights: {}, lastTouch: 0 };
3849
- this.nodes.set(path37, fresh);
3849
+ this.nodes.set(path38, fresh);
3850
3850
  return fresh;
3851
3851
  }
3852
3852
  };
@@ -4599,6 +4599,61 @@ ${methodLines.join("\n")}
4599
4599
  }
4600
4600
  };
4601
4601
 
4602
+ // packages/core/src/db/vectorsCleanup.ts
4603
+ import fs14 from "fs";
4604
+ import path14 from "path";
4605
+ var VECTOR_DB_REL = path14.join(".ctxloom", "vectors.lancedb");
4606
+ var TABLE_DIR = "code_embeddings.lance";
4607
+ function inspectVectorsDb(rootDir) {
4608
+ const tablePath = path14.join(rootDir, VECTOR_DB_REL, TABLE_DIR);
4609
+ const counts = {
4610
+ txn: 0,
4611
+ manifest: 0,
4612
+ lance: 0,
4613
+ totalBytes: 0
4614
+ };
4615
+ if (!fs14.existsSync(tablePath)) return counts;
4616
+ for (const sub of ["_transactions", "_versions", "data"]) {
4617
+ const dir = path14.join(tablePath, sub);
4618
+ if (!fs14.existsSync(dir)) continue;
4619
+ for (const name of fs14.readdirSync(dir)) {
4620
+ const full = path14.join(dir, name);
4621
+ try {
4622
+ const st = fs14.statSync(full);
4623
+ if (!st.isFile()) continue;
4624
+ counts.totalBytes += st.size;
4625
+ if (name.endsWith(".txn")) counts.txn += 1;
4626
+ else if (name.endsWith(".manifest")) counts.manifest += 1;
4627
+ else if (name.endsWith(".lance")) counts.lance += 1;
4628
+ } catch {
4629
+ }
4630
+ }
4631
+ }
4632
+ return counts;
4633
+ }
4634
+ function cleanupVectors(options = {}, activePids = []) {
4635
+ const rootDir = options.rootDir ?? process.cwd();
4636
+ const dbPath = path14.join(rootDir, VECTOR_DB_REL);
4637
+ if (!fs14.existsSync(dbPath)) {
4638
+ return { cleaned: false, reason: "no-db" };
4639
+ }
4640
+ if (activePids.length > 0) {
4641
+ return {
4642
+ cleaned: false,
4643
+ reason: "in-use",
4644
+ conflictingPids: [...activePids]
4645
+ };
4646
+ }
4647
+ const before = inspectVectorsDb(rootDir);
4648
+ if (options.dryRun) {
4649
+ return { cleaned: true, before };
4650
+ }
4651
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4652
+ const backupPath = `${dbPath}.bak-${stamp}`;
4653
+ fs14.renameSync(dbPath, backupPath);
4654
+ return { cleaned: true, before, backupPath };
4655
+ }
4656
+
4602
4657
  // packages/core/src/tools/status.ts
4603
4658
  import { z as z2 } from "zod";
4604
4659
 
@@ -5624,7 +5679,7 @@ function registerFileTool(registry, ctx) {
5624
5679
 
5625
5680
  // packages/core/src/tools/context-packet.ts
5626
5681
  import { z as z5 } from "zod";
5627
- import path14 from "path";
5682
+ import path15 from "path";
5628
5683
  var DEFAULT_MAX_RESPONSE_TOKENS3 = 6e3;
5629
5684
  var Schema3 = z5.object({
5630
5685
  target_file: z5.string().describe("Relative path to the primary file"),
@@ -5693,7 +5748,7 @@ function registerContextPacketTool(registry, ctx) {
5693
5748
  const skeletons = await Promise.all(
5694
5749
  imports.map(async (dep) => {
5695
5750
  try {
5696
- const absDep = path14.resolve(ctx.projectRoot, dep);
5751
+ const absDep = path15.resolve(ctx.projectRoot, dep);
5697
5752
  const sk = await skeletonizer.skeletonize(absDep);
5698
5753
  return `
5699
5754
  <!-- ${dep} -->
@@ -5735,7 +5790,7 @@ ${sk}`;
5735
5790
  import { z as z6 } from "zod";
5736
5791
 
5737
5792
  // packages/core/src/tools/findCallers.ts
5738
- import path15 from "path";
5793
+ import path16 from "path";
5739
5794
  function escapeXML4(text) {
5740
5795
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5741
5796
  }
@@ -6597,7 +6652,7 @@ function registerArchitectureOverviewTool(registry, ctx) {
6597
6652
 
6598
6653
  // packages/core/src/tools/knowledge-gaps.ts
6599
6654
  import { z as z15 } from "zod";
6600
- import path16 from "path";
6655
+ import path17 from "path";
6601
6656
  var Schema13 = z15.object({
6602
6657
  min_importers: z15.number().min(1).max(50).optional().default(3).describe(
6603
6658
  "Minimum importers to qualify as an untested hub (default: 3)"
@@ -6648,7 +6703,7 @@ function registerKnowledgeGapsTool(registry, ctx) {
6648
6703
  const testFiles = new Set(files.filter((f) => TEST_PATTERN2.test(f)));
6649
6704
  const testedBases = /* @__PURE__ */ new Set();
6650
6705
  for (const tf of testFiles) {
6651
- const base = path16.basename(tf).replace(/\.(test|spec)\.[^.]+$/, "").replace(/\.[^.]+$/, "");
6706
+ const base = path17.basename(tf).replace(/\.(test|spec)\.[^.]+$/, "").replace(/\.[^.]+$/, "");
6652
6707
  if (base) testedBases.add(base);
6653
6708
  }
6654
6709
  const isolated = [];
@@ -6666,7 +6721,7 @@ function registerKnowledgeGapsTool(registry, ctx) {
6666
6721
  deadCode.push(file);
6667
6722
  }
6668
6723
  if (importers >= min_importers) {
6669
- const base = path16.basename(file).replace(/\.[^.]+$/, "");
6724
+ const base = path17.basename(file).replace(/\.[^.]+$/, "");
6670
6725
  if (!testedBases.has(base)) {
6671
6726
  untestedHubs.push({ file, importers });
6672
6727
  }
@@ -6853,7 +6908,7 @@ function registerSurprisingConnectionsTool(registry, ctx) {
6853
6908
 
6854
6909
  // packages/core/src/tools/wiki-generate.ts
6855
6910
  import { z as z17 } from "zod";
6856
- import fs14 from "fs";
6911
+ import fs15 from "fs";
6857
6912
  var DEFAULT_MAX_RESPONSE_TOKENS5 = 12e3;
6858
6913
  var Schema15 = z17.object({
6859
6914
  force: z17.boolean().optional().default(false).describe(
@@ -6873,7 +6928,7 @@ function escapeXML14(text) {
6873
6928
  }
6874
6929
  function safeFileSize(filePath) {
6875
6930
  try {
6876
- return fs14.statSync(filePath).size;
6931
+ return fs15.statSync(filePath).size;
6877
6932
  } catch {
6878
6933
  return 0;
6879
6934
  }
@@ -7163,8 +7218,8 @@ function registerGitDiffReviewTool(registry, ctx) {
7163
7218
 
7164
7219
  // packages/core/src/tools/refactor-preview.ts
7165
7220
  import { z as z20 } from "zod";
7166
- import fs15 from "fs";
7167
- import path17 from "path";
7221
+ import fs16 from "fs";
7222
+ import path18 from "path";
7168
7223
  var DEFAULT_MAX_RESPONSE_TOKENS7 = 4e3;
7169
7224
  var Schema18 = z20.object({
7170
7225
  symbol: z20.string().min(1).describe("Symbol name to rename (exact match, case-sensitive)"),
@@ -7184,7 +7239,7 @@ function escapeXML17(text) {
7184
7239
  function scanFile(filePath, symbol, newName) {
7185
7240
  let content;
7186
7241
  try {
7187
- content = fs15.readFileSync(filePath, "utf-8");
7242
+ content = fs16.readFileSync(filePath, "utf-8");
7188
7243
  } catch {
7189
7244
  return [];
7190
7245
  }
@@ -7251,7 +7306,7 @@ function registerRefactorPreviewTool(registry, ctx) {
7251
7306
  const fileChanges = [];
7252
7307
  let totalOccurrences = 0;
7253
7308
  for (const relPath of candidates) {
7254
- const absPath = path17.join(ctx.projectRoot, relPath);
7309
+ const absPath = path18.join(ctx.projectRoot, relPath);
7255
7310
  const occurrences = scanFile(absPath, symbol, new_name);
7256
7311
  if (occurrences.length > 0) {
7257
7312
  fileChanges.push({ filePath: relPath, occurrences });
@@ -7456,8 +7511,8 @@ function registerExecutionFlowTool(registry, ctx) {
7456
7511
 
7457
7512
  // packages/core/src/tools/cross-repo-search.ts
7458
7513
  import { z as z22 } from "zod";
7459
- import fs16 from "fs";
7460
- import path18 from "path";
7514
+ import fs17 from "fs";
7515
+ import path19 from "path";
7461
7516
  var DEFAULT_MAX_RESPONSE_TOKENS9 = 4e3;
7462
7517
  var ALIAS_REGEX = /^[a-z0-9-]{1,40}$/;
7463
7518
  var RESERVED_ALIASES = /* @__PURE__ */ new Set([
@@ -7499,16 +7554,16 @@ var RepoRegistry = class {
7499
7554
  }
7500
7555
  load() {
7501
7556
  try {
7502
- if (!fs16.existsSync(this.filePath)) return [];
7503
- return JSON.parse(fs16.readFileSync(this.filePath, "utf-8"));
7557
+ if (!fs17.existsSync(this.filePath)) return [];
7558
+ return JSON.parse(fs17.readFileSync(this.filePath, "utf-8"));
7504
7559
  } catch {
7505
7560
  return [];
7506
7561
  }
7507
7562
  }
7508
7563
  save() {
7509
- const dir = path18.dirname(this.filePath);
7510
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
7511
- fs16.writeFileSync(this.filePath, JSON.stringify(this.repos, null, 2), "utf-8");
7564
+ const dir = path19.dirname(this.filePath);
7565
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
7566
+ fs17.writeFileSync(this.filePath, JSON.stringify(this.repos, null, 2), "utf-8");
7512
7567
  }
7513
7568
  list() {
7514
7569
  return [...this.repos];
@@ -7517,15 +7572,15 @@ var RepoRegistry = class {
7517
7572
  return this.repos.find((r) => r.alias === alias) ?? null;
7518
7573
  }
7519
7574
  findByPath(absPath) {
7520
- const canonical = path18.resolve(absPath);
7521
- return this.repos.find((r) => path18.resolve(r.root) === canonical) ?? null;
7575
+ const canonical = path19.resolve(absPath);
7576
+ return this.repos.find((r) => path19.resolve(r.root) === canonical) ?? null;
7522
7577
  }
7523
7578
  register(root, dbPath, opts = {}) {
7524
7579
  if (opts.alias !== void 0) {
7525
7580
  const v = validateAlias(opts.alias);
7526
7581
  if (!v.ok) throw new Error(`Invalid alias: ${v.reason}`);
7527
7582
  const colliding = this.repos.find(
7528
- (r) => r.alias === opts.alias && path18.resolve(r.root) !== path18.resolve(root)
7583
+ (r) => r.alias === opts.alias && path19.resolve(r.root) !== path19.resolve(root)
7529
7584
  );
7530
7585
  if (colliding) {
7531
7586
  throw new Error(
@@ -7533,11 +7588,11 @@ var RepoRegistry = class {
7533
7588
  );
7534
7589
  }
7535
7590
  }
7536
- const existingIdx = this.repos.findIndex((r) => path18.resolve(r.root) === path18.resolve(root));
7591
+ const existingIdx = this.repos.findIndex((r) => path19.resolve(r.root) === path19.resolve(root));
7537
7592
  const entry = {
7538
7593
  root,
7539
7594
  dbPath,
7540
- name: path18.basename(root),
7595
+ name: path19.basename(root),
7541
7596
  alias: opts.alias,
7542
7597
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
7543
7598
  };
@@ -7549,7 +7604,7 @@ var RepoRegistry = class {
7549
7604
  this.save();
7550
7605
  }
7551
7606
  unregister(root) {
7552
- this.repos = this.repos.filter((r) => path18.resolve(r.root) !== path18.resolve(root));
7607
+ this.repos = this.repos.filter((r) => path19.resolve(r.root) !== path19.resolve(root));
7553
7608
  this.save();
7554
7609
  }
7555
7610
  };
@@ -7571,7 +7626,7 @@ function escapeXML19(text) {
7571
7626
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7572
7627
  }
7573
7628
  function registerCrossRepoSearchTool(registry, ctx, registryFilePath) {
7574
- const repoRegistryPath = registryFilePath ?? path18.join(process.env.HOME ?? process.env.USERPROFILE ?? "", ".ctxloom", "repos.json");
7629
+ const repoRegistryPath = registryFilePath ?? path19.join(process.env.HOME ?? process.env.USERPROFILE ?? "", ".ctxloom", "repos.json");
7575
7630
  registry.register(
7576
7631
  "ctx_cross_repo_search",
7577
7632
  {
@@ -7692,8 +7747,8 @@ function registerCrossRepoSearchTool(registry, ctx, registryFilePath) {
7692
7747
 
7693
7748
  // packages/core/src/tools/apply-refactor.ts
7694
7749
  import { z as z23 } from "zod";
7695
- import fs17 from "fs";
7696
- import path19 from "path";
7750
+ import fs18 from "fs";
7751
+ import path20 from "path";
7697
7752
  var DEFAULT_MAX_RESPONSE_TOKENS10 = 2e3;
7698
7753
  var Schema21 = z23.object({
7699
7754
  symbol: z23.string().min(1).describe("Symbol name to rename (exact, case-sensitive)"),
@@ -7716,7 +7771,7 @@ function escapeXML20(text) {
7716
7771
  function applyToFile(absPath, symbol, newName, dryRun) {
7717
7772
  let content;
7718
7773
  try {
7719
- content = fs17.readFileSync(absPath, "utf-8");
7774
+ content = fs18.readFileSync(absPath, "utf-8");
7720
7775
  } catch {
7721
7776
  return 0;
7722
7777
  }
@@ -7725,7 +7780,7 @@ function applyToFile(absPath, symbol, newName, dryRun) {
7725
7780
  const occurrences = (content.match(regex) ?? []).length;
7726
7781
  if (occurrences === 0) return 0;
7727
7782
  if (!dryRun) {
7728
- fs17.writeFileSync(absPath, content.replace(regex, newName), "utf-8");
7783
+ fs18.writeFileSync(absPath, content.replace(regex, newName), "utf-8");
7729
7784
  }
7730
7785
  return occurrences;
7731
7786
  }
@@ -7769,7 +7824,7 @@ function registerApplyRefactorTool(registry, ctx) {
7769
7824
  const results = [];
7770
7825
  let totalOccurrences = 0;
7771
7826
  for (const relPath of candidates) {
7772
- const absPath = path19.join(ctx.projectRoot, relPath);
7827
+ const absPath = path20.join(ctx.projectRoot, relPath);
7773
7828
  const count = applyToFile(absPath, symbol, new_name, dry_run);
7774
7829
  if (count > 0) {
7775
7830
  results.push({ filePath: relPath, occurrences: count, written: !dry_run });
@@ -7913,8 +7968,8 @@ function registerDetectChangesTool(registry, ctx) {
7913
7968
 
7914
7969
  // packages/core/src/tools/full-text-search.ts
7915
7970
  import { z as z25 } from "zod";
7916
- import fs18 from "fs";
7917
- import path20 from "path";
7971
+ import fs19 from "fs";
7972
+ import path21 from "path";
7918
7973
  var DEFAULT_MAX_RESPONSE_TOKENS11 = 4e3;
7919
7974
  var Schema23 = z25.object({
7920
7975
  query: z25.string().min(1).describe("Search term \u2014 literal or /regex/"),
@@ -7945,7 +8000,7 @@ function buildPattern(query, caseSensitive) {
7945
8000
  function scanFile2(absPath, pattern, contextLines) {
7946
8001
  let content;
7947
8002
  try {
7948
- content = fs18.readFileSync(absPath, "utf-8");
8003
+ content = fs19.readFileSync(absPath, "utf-8");
7949
8004
  } catch {
7950
8005
  return null;
7951
8006
  }
@@ -8017,7 +8072,7 @@ function registerFullTextSearchTool(registry, ctx) {
8017
8072
  };
8018
8073
  if (mode === "semantic") {
8019
8074
  try {
8020
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-7YOG4DFN.js");
8075
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-3AE4CSR7.js");
8021
8076
  const store = await ctx.getStore(project_root);
8022
8077
  const embedding = await generateEmbedding2(query);
8023
8078
  const results = await store.search(embedding, limit);
@@ -8039,7 +8094,7 @@ function registerFullTextSearchTool(registry, ctx) {
8039
8094
  const files = graph.allFiles();
8040
8095
  const keywordResults = [];
8041
8096
  for (const relPath of files) {
8042
- const absPath = path20.join(ctx.projectRoot, relPath);
8097
+ const absPath = path21.join(ctx.projectRoot, relPath);
8043
8098
  const hit = scanFile2(absPath, pattern, context_lines);
8044
8099
  if (hit) {
8045
8100
  keywordResults.push({
@@ -8054,7 +8109,7 @@ function registerFullTextSearchTool(registry, ctx) {
8054
8109
  let merged = keywordResults.slice(0, limit);
8055
8110
  if (mode === "hybrid") {
8056
8111
  try {
8057
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-7YOG4DFN.js");
8112
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-3AE4CSR7.js");
8058
8113
  const store = await ctx.getStore(project_root);
8059
8114
  const embedding = await generateEmbedding2(query);
8060
8115
  const vectorResults = await store.search(embedding, Math.ceil(limit / 2));
@@ -8273,8 +8328,8 @@ function registerGetWorkflowTool(registry, _ctx) {
8273
8328
  }
8274
8329
 
8275
8330
  // packages/core/src/tools/graph-snapshot.ts
8276
- import fs19 from "fs";
8277
- import path21 from "path";
8331
+ import fs20 from "fs";
8332
+ import path22 from "path";
8278
8333
  import { z as z28 } from "zod";
8279
8334
  var schema = z28.object({
8280
8335
  name: z28.string().min(1).max(64).regex(/^[\w.-]+$/, "Name may only contain letters, digits, dots, underscores, hyphens").describe(
@@ -8286,13 +8341,13 @@ var schema = z28.object({
8286
8341
  project_root: ProjectRootField
8287
8342
  });
8288
8343
  function saveNamedSnapshot(graph, name, rootDir, overwrite = false) {
8289
- const snapshotsDir = path21.resolve(rootDir, ".ctxloom", "snapshots");
8290
- fs19.mkdirSync(snapshotsDir, { recursive: true });
8291
- const snapshotPath = path21.resolve(snapshotsDir, `${name}.json`);
8292
- if (!snapshotPath.startsWith(snapshotsDir + path21.sep)) {
8344
+ const snapshotsDir = path22.resolve(rootDir, ".ctxloom", "snapshots");
8345
+ fs20.mkdirSync(snapshotsDir, { recursive: true });
8346
+ const snapshotPath = path22.resolve(snapshotsDir, `${name}.json`);
8347
+ if (!snapshotPath.startsWith(snapshotsDir + path22.sep)) {
8293
8348
  throw new Error(`Invalid snapshot name: "${name}"`);
8294
8349
  }
8295
- if (fs19.existsSync(snapshotPath) && !overwrite) {
8350
+ if (fs20.existsSync(snapshotPath) && !overwrite) {
8296
8351
  throw new Error(`Snapshot "${name}" already exists. Pass overwrite: true to replace it.`);
8297
8352
  }
8298
8353
  const files = graph.allFiles();
@@ -8307,14 +8362,14 @@ function saveNamedSnapshot(graph, name, rootDir, overwrite = false) {
8307
8362
  edgeCount: graph.edgeCount(),
8308
8363
  forwardEdges
8309
8364
  };
8310
- const tmp = snapshotPath + ".tmp";
8311
- fs19.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
8312
- fs19.renameSync(tmp, snapshotPath);
8365
+ const tmp = `${snapshotPath}.${process.pid}.tmp`;
8366
+ fs20.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
8367
+ fs20.renameSync(tmp, snapshotPath);
8313
8368
  }
8314
8369
  function listNamedSnapshots(rootDir) {
8315
- const snapshotsDir = path21.join(rootDir, ".ctxloom", "snapshots");
8316
- if (!fs19.existsSync(snapshotsDir)) return [];
8317
- return fs19.readdirSync(snapshotsDir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)).sort();
8370
+ const snapshotsDir = path22.join(rootDir, ".ctxloom", "snapshots");
8371
+ if (!fs20.existsSync(snapshotsDir)) return [];
8372
+ return fs20.readdirSync(snapshotsDir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)).sort();
8318
8373
  }
8319
8374
  function registerGraphSnapshotTool(registry, ctx) {
8320
8375
  registry.register(
@@ -8363,8 +8418,8 @@ function registerGraphSnapshotTool(registry, ctx) {
8363
8418
  }
8364
8419
 
8365
8420
  // packages/core/src/tools/graph-diff.ts
8366
- import fs20 from "fs";
8367
- import path22 from "path";
8421
+ import fs21 from "fs";
8422
+ import path23 from "path";
8368
8423
  import { z as z29 } from "zod";
8369
8424
  var schema2 = z29.object({
8370
8425
  baseline: z29.string().min(1).describe('Name of the baseline snapshot (the "before" state).'),
@@ -8372,16 +8427,16 @@ var schema2 = z29.object({
8372
8427
  project_root: ProjectRootField
8373
8428
  });
8374
8429
  function loadSnapshot(name, rootDir) {
8375
- const snapshotsDir = path22.resolve(rootDir, ".ctxloom", "snapshots");
8376
- const snapshotPath = path22.resolve(snapshotsDir, `${name}.json`);
8377
- if (!snapshotPath.startsWith(snapshotsDir + path22.sep)) {
8430
+ const snapshotsDir = path23.resolve(rootDir, ".ctxloom", "snapshots");
8431
+ const snapshotPath = path23.resolve(snapshotsDir, `${name}.json`);
8432
+ if (!snapshotPath.startsWith(snapshotsDir + path23.sep)) {
8378
8433
  throw new Error(`Invalid snapshot name: "${name}"`);
8379
8434
  }
8380
- if (!fs20.existsSync(snapshotPath)) {
8435
+ if (!fs21.existsSync(snapshotPath)) {
8381
8436
  throw new Error(`Snapshot "${name}" not found. Run ctx_graph_snapshot first.`);
8382
8437
  }
8383
8438
  try {
8384
- return JSON.parse(fs20.readFileSync(snapshotPath, "utf-8"));
8439
+ return JSON.parse(fs21.readFileSync(snapshotPath, "utf-8"));
8385
8440
  } catch (e) {
8386
8441
  throw new Error(`Snapshot "${name}" is corrupted: ${e instanceof Error ? e.message : String(e)}`);
8387
8442
  }
@@ -8775,8 +8830,8 @@ var RulesConfigError = class extends Error {
8775
8830
  };
8776
8831
 
8777
8832
  // packages/core/src/rules/loadConfig.ts
8778
- import fs21 from "fs/promises";
8779
- import path23 from "path";
8833
+ import fs22 from "fs/promises";
8834
+ import path24 from "path";
8780
8835
  import yaml from "js-yaml";
8781
8836
  import { z as z33 } from "zod";
8782
8837
  var RuleSchema = z33.object({
@@ -8791,10 +8846,10 @@ var RulesConfigSchema = z33.object({
8791
8846
  rules: z33.array(RuleSchema).default([])
8792
8847
  });
8793
8848
  async function loadRulesConfig(rootDir) {
8794
- const filePath = path23.join(rootDir, ".ctxloom", "rules.yml");
8849
+ const filePath = path24.join(rootDir, ".ctxloom", "rules.yml");
8795
8850
  let raw;
8796
8851
  try {
8797
- raw = await fs21.readFile(filePath, "utf-8");
8852
+ raw = await fs22.readFile(filePath, "utf-8");
8798
8853
  } catch (err) {
8799
8854
  if (err.code === "ENOENT") return null;
8800
8855
  throw new RulesConfigError(`Failed to read rules config: ${String(err)}`);
@@ -9206,11 +9261,11 @@ function readRecentChanges(projectRoot) {
9206
9261
  return lines.slice(0, 20).map((line) => {
9207
9262
  const x = line[0];
9208
9263
  const y = line[1];
9209
- const path37 = line.slice(3).trim();
9264
+ const path38 = line.slice(3).trim();
9210
9265
  let status = "?";
9211
9266
  const xy = x === " " ? y : x;
9212
9267
  if (xy === "M" || xy === "A" || xy === "D" || xy === "R") status = xy;
9213
- return { file: path37, status };
9268
+ return { file: path38, status };
9214
9269
  });
9215
9270
  } catch {
9216
9271
  return [];
@@ -9437,8 +9492,8 @@ function createToolRegistry(ctx) {
9437
9492
  }
9438
9493
 
9439
9494
  // packages/core/src/tools/ruleManager.ts
9440
- import fs22 from "fs";
9441
- import path24 from "path";
9495
+ import fs23 from "fs";
9496
+ import path25 from "path";
9442
9497
  var RULE_FILES = [
9443
9498
  ".cursorrules",
9444
9499
  "CLAUDE.md",
@@ -9462,30 +9517,30 @@ var RuleManager = class {
9462
9517
  if (this.cachedRules) return this.cachedRules;
9463
9518
  const rules = [];
9464
9519
  for (const ruleFile of RULE_FILES) {
9465
- const fullPath = path24.join(this.projectRoot, ruleFile);
9520
+ const fullPath = path25.join(this.projectRoot, ruleFile);
9466
9521
  try {
9467
9522
  this.pathValidator.validate(fullPath);
9468
- if (fs22.existsSync(fullPath)) {
9469
- const stat = fs22.statSync(fullPath);
9523
+ if (fs23.existsSync(fullPath)) {
9524
+ const stat = fs23.statSync(fullPath);
9470
9525
  if (stat.isFile()) {
9471
- const content = fs22.readFileSync(fullPath, "utf-8");
9526
+ const content = fs23.readFileSync(fullPath, "utf-8");
9472
9527
  rules.push({
9473
9528
  name: ruleFile,
9474
9529
  path: ruleFile,
9475
9530
  content
9476
9531
  });
9477
9532
  } else if (stat.isDirectory()) {
9478
- const dirEntries = fs22.readdirSync(fullPath);
9533
+ const dirEntries = fs23.readdirSync(fullPath);
9479
9534
  for (const entry of dirEntries) {
9480
- const entryPath = path24.join(fullPath, entry);
9535
+ const entryPath = path25.join(fullPath, entry);
9481
9536
  try {
9482
9537
  this.pathValidator.validate(entryPath);
9483
9538
  } catch {
9484
9539
  continue;
9485
9540
  }
9486
- const entryStat = fs22.statSync(entryPath);
9541
+ const entryStat = fs23.statSync(entryPath);
9487
9542
  if (entryStat.isFile()) {
9488
- const content = fs22.readFileSync(entryPath, "utf-8");
9543
+ const content = fs23.readFileSync(entryPath, "utf-8");
9489
9544
  rules.push({
9490
9545
  name: `${ruleFile}/${entry}`,
9491
9546
  path: `${ruleFile}/${entry}`,
@@ -9528,8 +9583,8 @@ var RuleManager = class {
9528
9583
  };
9529
9584
 
9530
9585
  // packages/core/src/review/AuthorResolver.ts
9531
- import fs23 from "fs/promises";
9532
- import path25 from "path";
9586
+ import fs24 from "fs/promises";
9587
+ import path26 from "path";
9533
9588
  import yaml2 from "js-yaml";
9534
9589
  var AuthorResolver = class {
9535
9590
  constructor(ctxloomDir) {
@@ -9554,8 +9609,8 @@ var AuthorResolver = class {
9554
9609
  /** Write a new mapping to the cache file. */
9555
9610
  async writeCache(email, handle) {
9556
9611
  this.cache = { ...this.cache, [email]: handle };
9557
- await fs23.writeFile(
9558
- path25.join(this.ctxloomDir, "authors-cache.json"),
9612
+ await fs24.writeFile(
9613
+ path26.join(this.ctxloomDir, "authors-cache.json"),
9559
9614
  JSON.stringify(this.cache, null, 2)
9560
9615
  );
9561
9616
  }
@@ -9564,9 +9619,9 @@ var AuthorResolver = class {
9564
9619
  return emails.filter((e) => this.resolve(e) === void 0);
9565
9620
  }
9566
9621
  async loadYml() {
9567
- const file = path25.join(this.ctxloomDir, "authors.yml");
9622
+ const file = path26.join(this.ctxloomDir, "authors.yml");
9568
9623
  try {
9569
- const raw = await fs23.readFile(file, "utf8");
9624
+ const raw = await fs24.readFile(file, "utf8");
9570
9625
  const parsed = yaml2.load(raw);
9571
9626
  if (!parsed) return;
9572
9627
  this.mappings = parsed.mappings ?? {};
@@ -9575,9 +9630,9 @@ var AuthorResolver = class {
9575
9630
  }
9576
9631
  }
9577
9632
  async loadCache() {
9578
- const file = path25.join(this.ctxloomDir, "authors-cache.json");
9633
+ const file = path26.join(this.ctxloomDir, "authors-cache.json");
9579
9634
  try {
9580
- const raw = await fs23.readFile(file, "utf8");
9635
+ const raw = await fs24.readFile(file, "utf8");
9581
9636
  this.cache = JSON.parse(raw);
9582
9637
  } catch {
9583
9638
  }
@@ -9602,8 +9657,8 @@ async function resolveViaGitHubApi(email, owner, repo, token) {
9602
9657
  }
9603
9658
 
9604
9659
  // packages/core/src/review/CodeownersWriter.ts
9605
- import fs24 from "fs/promises";
9606
- import path26 from "path";
9660
+ import fs25 from "fs/promises";
9661
+ import path27 from "path";
9607
9662
  var MARKER_START = "# <ctxloom:start> \u2014 managed by ctxloom review-suggest; do not edit between markers";
9608
9663
  var MARKER_START_DETECT = "# <ctxloom:start>";
9609
9664
  var MARKER_END = "# <ctxloom:end>";
@@ -9635,15 +9690,15 @@ ${block}
9635
9690
  async function generateCODEOWNERS(codeownersPath, rules) {
9636
9691
  let existing = "";
9637
9692
  try {
9638
- existing = await fs24.readFile(codeownersPath, "utf8");
9693
+ existing = await fs25.readFile(codeownersPath, "utf8");
9639
9694
  } catch {
9640
9695
  }
9641
9696
  const block = buildCodeownersBlock(rules);
9642
9697
  return mergeIntoFile(existing, block);
9643
9698
  }
9644
9699
  async function writeCODEOWNERS(codeownersPath, content) {
9645
- await fs24.mkdir(path26.dirname(codeownersPath), { recursive: true });
9646
- await fs24.writeFile(codeownersPath, content, "utf8");
9700
+ await fs25.mkdir(path27.dirname(codeownersPath), { recursive: true });
9701
+ await fs25.writeFile(codeownersPath, content, "utf8");
9647
9702
  }
9648
9703
 
9649
9704
  // packages/core/src/review/types.ts
@@ -9828,8 +9883,8 @@ function matchGlob(pattern, value) {
9828
9883
  }
9829
9884
 
9830
9885
  // packages/core/src/review/loadConfig.ts
9831
- import fs25 from "fs/promises";
9832
- import path27 from "path";
9886
+ import fs26 from "fs/promises";
9887
+ import path28 from "path";
9833
9888
  import yaml3 from "js-yaml";
9834
9889
  function freshDefaults() {
9835
9890
  return {
@@ -9840,9 +9895,9 @@ function freshDefaults() {
9840
9895
  };
9841
9896
  }
9842
9897
  async function loadReviewConfig(root) {
9843
- const file = path27.join(root, ".ctxloom", "review.yml");
9898
+ const file = path28.join(root, ".ctxloom", "review.yml");
9844
9899
  try {
9845
- const raw = await fs25.readFile(file, "utf8");
9900
+ const raw = await fs26.readFile(file, "utf8");
9846
9901
  const parsed = yaml3.load(raw);
9847
9902
  if (!parsed) return freshDefaults();
9848
9903
  return {
@@ -9857,13 +9912,13 @@ async function loadReviewConfig(root) {
9857
9912
  }
9858
9913
 
9859
9914
  // packages/core/src/security/PathValidator.ts
9860
- import path28 from "path";
9861
- import fs26 from "fs";
9915
+ import path29 from "path";
9916
+ import fs27 from "fs";
9862
9917
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
9863
9918
  var PathValidator = class {
9864
9919
  canonicalRoot;
9865
9920
  constructor(projectRoot) {
9866
- this.canonicalRoot = fs26.realpathSync(path28.resolve(projectRoot));
9921
+ this.canonicalRoot = fs27.realpathSync(path29.resolve(projectRoot));
9867
9922
  }
9868
9923
  /**
9869
9924
  * Validates that the given input path resolves within the project root.
@@ -9873,14 +9928,14 @@ var PathValidator = class {
9873
9928
  * @throws Error if the path escapes the project root
9874
9929
  */
9875
9930
  validate(inputPath) {
9876
- const resolved = path28.resolve(this.canonicalRoot, inputPath);
9931
+ const resolved = path29.resolve(this.canonicalRoot, inputPath);
9877
9932
  let canonical;
9878
9933
  try {
9879
- canonical = fs26.realpathSync(resolved);
9934
+ canonical = fs27.realpathSync(resolved);
9880
9935
  } catch {
9881
9936
  canonical = resolved;
9882
9937
  }
9883
- if (!canonical.startsWith(this.canonicalRoot + path28.sep) && canonical !== this.canonicalRoot) {
9938
+ if (!canonical.startsWith(this.canonicalRoot + path29.sep) && canonical !== this.canonicalRoot) {
9884
9939
  throw new Error(
9885
9940
  `Path traversal blocked: "${inputPath}" resolves outside of the project root`
9886
9941
  );
@@ -9897,7 +9952,7 @@ var PathValidator = class {
9897
9952
  * Converts an absolute path to a relative path from the project root.
9898
9953
  */
9899
9954
  toRelative(absolutePath) {
9900
- return path28.relative(this.canonicalRoot, absolutePath);
9955
+ return path29.relative(this.canonicalRoot, absolutePath);
9901
9956
  }
9902
9957
  /**
9903
9958
  * Validates and reads a file, returning its content.
@@ -9905,11 +9960,11 @@ var PathValidator = class {
9905
9960
  */
9906
9961
  readFile(inputPath) {
9907
9962
  const absPath = this.validate(inputPath);
9908
- const stat = fs26.statSync(absPath);
9963
+ const stat = fs27.statSync(absPath);
9909
9964
  if (stat.size > MAX_FILE_SIZE) {
9910
9965
  throw new Error(`File too large: ${inputPath} (${Math.round(stat.size / 1024)}KB, max ${MAX_FILE_SIZE / 1024 / 1024}MB)`);
9911
9966
  }
9912
- return fs26.readFileSync(absPath, "utf-8");
9967
+ return fs27.readFileSync(absPath, "utf-8");
9913
9968
  }
9914
9969
  /**
9915
9970
  * Checks if a path exists and is within the project root.
@@ -10062,7 +10117,7 @@ var EmailAlreadyUsedError = class extends Error {
10062
10117
 
10063
10118
  // packages/core/src/license/LicenseStore.ts
10064
10119
  import { readFileSync, writeFileSync, unlinkSync, mkdirSync, chmodSync, existsSync } from "fs";
10065
- import path29 from "path";
10120
+ import path30 from "path";
10066
10121
 
10067
10122
  // packages/core/src/license/types.ts
10068
10123
  import { z as z37 } from "zod";
@@ -10083,7 +10138,7 @@ var LicenseFileSchema = z37.object({
10083
10138
 
10084
10139
  // packages/core/src/license/LicenseStore.ts
10085
10140
  function licenseFilePath(home) {
10086
- return path29.join(home, ".ctxloom", "license.json");
10141
+ return path30.join(home, ".ctxloom", "license.json");
10087
10142
  }
10088
10143
  var LicenseStore = class {
10089
10144
  filePath;
@@ -10106,7 +10161,7 @@ var LicenseStore = class {
10106
10161
  }
10107
10162
  }
10108
10163
  async write(license) {
10109
- mkdirSync(path29.dirname(this.filePath), { recursive: true });
10164
+ mkdirSync(path30.dirname(this.filePath), { recursive: true });
10110
10165
  writeFileSync(this.filePath, JSON.stringify(license, null, 2), {
10111
10166
  encoding: "utf8",
10112
10167
  mode: 384
@@ -10237,11 +10292,11 @@ import os5 from "os";
10237
10292
 
10238
10293
  // packages/core/src/license/DistinctIdStore.ts
10239
10294
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
10240
- import path30 from "path";
10295
+ import path31 from "path";
10241
10296
  import os3 from "os";
10242
10297
  var UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10243
10298
  function distinctIdPath(home) {
10244
- return path30.join(home ?? os3.homedir(), ".ctxloom", "distinct_id");
10299
+ return path31.join(home ?? os3.homedir(), ".ctxloom", "distinct_id");
10245
10300
  }
10246
10301
  function isValidV4(id) {
10247
10302
  return typeof id === "string" && UUID_V4_REGEX.test(id);
@@ -10262,7 +10317,7 @@ function getOrCreateDistinctId(home) {
10262
10317
  id: crypto.randomUUID(),
10263
10318
  alias_pending: os3.hostname()
10264
10319
  };
10265
- mkdirSync2(path30.dirname(filePath), { recursive: true });
10320
+ mkdirSync2(path31.dirname(filePath), { recursive: true });
10266
10321
  writeFileSync2(filePath, JSON.stringify(record), { mode: 384 });
10267
10322
  return record;
10268
10323
  }
@@ -10291,7 +10346,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
10291
10346
  function getTelemetryLevel() {
10292
10347
  return TELEMETRY_LEVEL;
10293
10348
  }
10294
- var CTXLOOM_VERSION = "1.5.5".length > 0 ? "1.5.5" : "dev";
10349
+ var CTXLOOM_VERSION = "1.5.6".length > 0 ? "1.5.6" : "dev";
10295
10350
  var POSTHOG_HOST = "https://eu.i.posthog.com";
10296
10351
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
10297
10352
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528\u2028" : "");
@@ -10424,17 +10479,17 @@ function parseStack(stack) {
10424
10479
 
10425
10480
  // packages/core/src/license/FunnelMilestones.ts
10426
10481
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
10427
- import path31 from "path";
10482
+ import path32 from "path";
10428
10483
  import os4 from "os";
10429
10484
  var INSTALL_MARKER = "installed_at";
10430
10485
  var FIRST_REVIEW_MARKER = "first_review_at";
10431
10486
  function writeMarker(filePath) {
10432
- mkdirSync3(path31.dirname(filePath), { recursive: true });
10487
+ mkdirSync3(path32.dirname(filePath), { recursive: true });
10433
10488
  writeFileSync3(filePath, (/* @__PURE__ */ new Date()).toISOString(), { mode: 384 });
10434
10489
  }
10435
10490
  function shouldEmitInstallCompleted(home) {
10436
10491
  const root = home ?? os4.homedir();
10437
- const marker = path31.join(root, ".ctxloom", INSTALL_MARKER);
10492
+ const marker = path32.join(root, ".ctxloom", INSTALL_MARKER);
10438
10493
  if (existsSync3(marker)) return false;
10439
10494
  try {
10440
10495
  writeMarker(marker);
@@ -10443,7 +10498,7 @@ function shouldEmitInstallCompleted(home) {
10443
10498
  return true;
10444
10499
  }
10445
10500
  function shouldEmitFirstReviewRun(projectRoot) {
10446
- const marker = path31.join(projectRoot, ".ctxloom", FIRST_REVIEW_MARKER);
10501
+ const marker = path32.join(projectRoot, ".ctxloom", FIRST_REVIEW_MARKER);
10447
10502
  if (existsSync3(marker)) return false;
10448
10503
  try {
10449
10504
  writeMarker(marker);
@@ -10561,16 +10616,16 @@ async function startTrial(email, opts = {}) {
10561
10616
 
10562
10617
  // packages/core/src/license/TelemetryNotice.ts
10563
10618
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
10564
- import path32 from "path";
10619
+ import path33 from "path";
10565
10620
  import os6 from "os";
10566
10621
  function noticePath(home) {
10567
- return path32.join(home ?? os6.homedir(), ".ctxloom", "telemetry_notice_shown");
10622
+ return path33.join(home ?? os6.homedir(), ".ctxloom", "telemetry_notice_shown");
10568
10623
  }
10569
10624
  function shouldShowTelemetryNotice(home) {
10570
10625
  const filePath = noticePath(home);
10571
10626
  if (existsSync4(filePath)) return false;
10572
10627
  try {
10573
- mkdirSync4(path32.dirname(filePath), { recursive: true });
10628
+ mkdirSync4(path33.dirname(filePath), { recursive: true });
10574
10629
  writeFileSync4(filePath, (/* @__PURE__ */ new Date()).toISOString(), { mode: 384 });
10575
10630
  } catch {
10576
10631
  }
@@ -10578,13 +10633,13 @@ function shouldShowTelemetryNotice(home) {
10578
10633
  }
10579
10634
 
10580
10635
  // packages/core/src/server/ProjectState.ts
10581
- import path34 from "path";
10636
+ import path35 from "path";
10582
10637
 
10583
10638
  // packages/core/src/server/projectId.ts
10584
10639
  import crypto5 from "crypto";
10585
- import path33 from "path";
10640
+ import path34 from "path";
10586
10641
  function hashProjectRoot(absPath) {
10587
- const canonical = path33.resolve(absPath);
10642
+ const canonical = path34.resolve(absPath);
10588
10643
  return crypto5.createHash("sha256").update(canonical).digest("hex").slice(0, 16);
10589
10644
  }
10590
10645
 
@@ -10592,7 +10647,7 @@ function hashProjectRoot(absPath) {
10592
10647
  function createProjectState(projectRoot, opts = {}) {
10593
10648
  return {
10594
10649
  projectRoot,
10595
- dbPath: path34.join(projectRoot, ".ctxloom", "vectors.lancedb"),
10650
+ dbPath: path35.join(projectRoot, ".ctxloom", "vectors.lancedb"),
10596
10651
  pinned: opts.pinned ?? false,
10597
10652
  lastTouchedAt: Date.now(),
10598
10653
  vectorsInitialized: false,
@@ -10744,8 +10799,8 @@ var ProjectStateManager = class {
10744
10799
  };
10745
10800
 
10746
10801
  // packages/core/src/server/resolveProjectRoot.ts
10747
- import fs27 from "fs";
10748
- import path35 from "path";
10802
+ import fs28 from "fs";
10803
+ import path36 from "path";
10749
10804
  var PATH_SEPARATOR_PATTERN = /[/\\~]|^[A-Za-z]:/;
10750
10805
  function looksLikePath(value) {
10751
10806
  return PATH_SEPARATOR_PATTERN.test(value);
@@ -10770,13 +10825,13 @@ function resolvePathSafely(p, cwd) {
10770
10825
  let expanded = p;
10771
10826
  if (p === "~" || p.startsWith("~/")) {
10772
10827
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
10773
- expanded = p === "~" ? home : path35.join(home, p.slice(2));
10828
+ expanded = p === "~" ? home : path36.join(home, p.slice(2));
10774
10829
  }
10775
- return path35.isAbsolute(expanded) ? path35.resolve(expanded) : path35.resolve(cwd, expanded);
10830
+ return path36.isAbsolute(expanded) ? path36.resolve(expanded) : path36.resolve(cwd, expanded);
10776
10831
  }
10777
10832
  function realpathOrSame(p) {
10778
10833
  try {
10779
- return fs27.realpathSync(p);
10834
+ return fs28.realpathSync(p);
10780
10835
  } catch {
10781
10836
  return p;
10782
10837
  }
@@ -10801,7 +10856,7 @@ function resolveProjectRoot(input) {
10801
10856
  };
10802
10857
  }
10803
10858
  const resolved2 = resolvePathSafely(arg, cwd);
10804
- if (!fs27.existsSync(resolved2)) {
10859
+ if (!fs28.existsSync(resolved2)) {
10805
10860
  return {
10806
10861
  kind: "project_root_not_found",
10807
10862
  attemptedPath: resolved2,
@@ -10812,7 +10867,7 @@ function resolveProjectRoot(input) {
10812
10867
  }
10813
10868
  if (env !== void 0 && env !== "") {
10814
10869
  const resolved2 = resolvePathSafely(env, cwd);
10815
- if (!fs27.existsSync(resolved2)) {
10870
+ if (!fs28.existsSync(resolved2)) {
10816
10871
  return {
10817
10872
  kind: "project_root_not_found",
10818
10873
  attemptedPath: resolved2,
@@ -10839,12 +10894,12 @@ var FILESYSTEM_ROOTS = /* @__PURE__ */ new Set(["/", "C:\\", "D:\\", "E:\\", "F:
10839
10894
  function validateDefaultRoot(candidate) {
10840
10895
  if (FILESYSTEM_ROOTS.has(candidate)) return false;
10841
10896
  try {
10842
- const stat = fs27.statSync(candidate);
10897
+ const stat = fs28.statSync(candidate);
10843
10898
  if (!stat.isDirectory()) return false;
10844
10899
  } catch {
10845
10900
  return false;
10846
10901
  }
10847
- return PROJECT_MARKERS.some((m) => fs27.existsSync(path35.join(candidate, m)));
10902
+ return PROJECT_MARKERS.some((m) => fs28.existsSync(path36.join(candidate, m)));
10848
10903
  }
10849
10904
 
10850
10905
  // packages/core/src/server/structuredErrors.ts
@@ -10916,8 +10971,8 @@ var EmittedOnceTracker = class {
10916
10971
  };
10917
10972
 
10918
10973
  // packages/core/src/install/installer.ts
10919
- import fs28 from "fs";
10920
- import path36 from "path";
10974
+ import fs29 from "fs";
10975
+ import path37 from "path";
10921
10976
 
10922
10977
  // packages/core/src/install/templates.ts
10923
10978
  var RULES_BLOCK_NAME = "CTXLOOM-RULES";
@@ -11542,8 +11597,8 @@ function skillFilePath(name) {
11542
11597
  // packages/core/src/install/installer.ts
11543
11598
  function installHarness(opts = {}) {
11544
11599
  const cwd = opts.cwd ?? process.cwd();
11545
- const projectRoot = path36.resolve(cwd);
11546
- const stat = fs28.statSync(projectRoot);
11600
+ const projectRoot = path37.resolve(cwd);
11601
+ const stat = fs29.statSync(projectRoot);
11547
11602
  if (!stat.isDirectory()) {
11548
11603
  throw new Error(`installHarness: ${projectRoot} is not a directory`);
11549
11604
  }
@@ -11591,20 +11646,20 @@ function resolveExtraHosts(ids, warnings) {
11591
11646
  return HOST_ADAPTERS.filter((a) => requested.has(a.id));
11592
11647
  }
11593
11648
  function safeJoin(root, name) {
11594
- const target = path36.resolve(root, name);
11595
- const rootResolved = path36.resolve(root);
11649
+ const target = path37.resolve(root, name);
11650
+ const rootResolved = path37.resolve(root);
11596
11651
  const caseFold = process.platform === "darwin" || process.platform === "win32";
11597
11652
  const t = caseFold ? target.toLowerCase() : target;
11598
11653
  const r = caseFold ? rootResolved.toLowerCase() : rootResolved;
11599
- if (!t.startsWith(r + path36.sep) && t !== r) {
11654
+ if (!t.startsWith(r + path37.sep) && t !== r) {
11600
11655
  throw new Error(`installHarness: refusing to write outside project root: ${target}`);
11601
11656
  }
11602
11657
  return target;
11603
11658
  }
11604
11659
  function writeRulesBlock(projectRoot, filename, opts) {
11605
11660
  const filePath = safeJoin(projectRoot, filename);
11606
- const existed = fs28.existsSync(filePath);
11607
- const existing = existed ? fs28.readFileSync(filePath, "utf-8") : "";
11661
+ const existed = fs29.existsSync(filePath);
11662
+ const existing = existed ? fs29.readFileSync(filePath, "utf-8") : "";
11608
11663
  if (existed) {
11609
11664
  const block = extractBlock(existing, RULES_BLOCK_NAME);
11610
11665
  if (block) {
@@ -11622,7 +11677,7 @@ function writeRulesBlock(projectRoot, filename, opts) {
11622
11677
  }
11623
11678
  const next = upsertBlock(existing, RULES_BLOCK_NAME, RULES_BLOCK_CONTENT);
11624
11679
  if (!opts.dryRun) {
11625
- fs28.writeFileSync(filePath, next, "utf-8");
11680
+ fs29.writeFileSync(filePath, next, "utf-8");
11626
11681
  }
11627
11682
  return {
11628
11683
  path: filePath,
@@ -11635,15 +11690,15 @@ function writeRulesBlock(projectRoot, filename, opts) {
11635
11690
  function writeHooksJson(projectRoot, opts) {
11636
11691
  const dir = safeJoin(projectRoot, ".claude");
11637
11692
  const filePath = safeJoin(projectRoot, ".claude/hooks.json");
11638
- const existed = fs28.existsSync(filePath);
11693
+ const existed = fs29.existsSync(filePath);
11639
11694
  let current = {};
11640
11695
  if (existed) {
11641
11696
  try {
11642
- const text = fs28.readFileSync(filePath, "utf-8");
11697
+ const text = fs29.readFileSync(filePath, "utf-8");
11643
11698
  current = JSON.parse(text);
11644
11699
  } catch (err) {
11645
11700
  opts.warnings.push(
11646
- `Could not parse existing ${path36.relative(projectRoot, filePath)}; treating as empty. (${err instanceof Error ? err.message : String(err)})`
11701
+ `Could not parse existing ${path37.relative(projectRoot, filePath)}; treating as empty. (${err instanceof Error ? err.message : String(err)})`
11647
11702
  );
11648
11703
  current = {};
11649
11704
  }
@@ -11660,12 +11715,12 @@ function writeHooksJson(projectRoot, opts) {
11660
11715
  const nextJson = JSON.stringify(merged, null, 2) + "\n";
11661
11716
  let alreadyCorrect = false;
11662
11717
  if (existed) {
11663
- const currentText = fs28.readFileSync(filePath, "utf-8");
11718
+ const currentText = fs29.readFileSync(filePath, "utf-8");
11664
11719
  if (currentText === nextJson) alreadyCorrect = true;
11665
11720
  }
11666
11721
  if (!opts.dryRun && !alreadyCorrect) {
11667
- fs28.mkdirSync(dir, { recursive: true });
11668
- fs28.writeFileSync(filePath, nextJson, "utf-8");
11722
+ fs29.mkdirSync(dir, { recursive: true });
11723
+ fs29.writeFileSync(filePath, nextJson, "utf-8");
11669
11724
  }
11670
11725
  return {
11671
11726
  path: filePath,
@@ -11687,19 +11742,19 @@ function isCtxloomEntry(entry, expectedMatcher) {
11687
11742
  }
11688
11743
  function writeHostAdapter(projectRoot, adapter, opts) {
11689
11744
  const filePath = safeJoin(projectRoot, adapter.path);
11690
- const dir = path36.dirname(filePath);
11691
- const existed = fs28.existsSync(filePath);
11745
+ const dir = path37.dirname(filePath);
11746
+ const existed = fs29.existsSync(filePath);
11692
11747
  const rendered = adapter.render();
11693
11748
  let alreadyCorrect = false;
11694
11749
  if (existed) {
11695
- const current = fs28.readFileSync(filePath, "utf-8");
11750
+ const current = fs29.readFileSync(filePath, "utf-8");
11696
11751
  if (adapter.isCanonical(current)) {
11697
11752
  alreadyCorrect = true;
11698
11753
  }
11699
11754
  }
11700
11755
  if (!opts.dryRun && !alreadyCorrect) {
11701
- fs28.mkdirSync(dir, { recursive: true });
11702
- fs28.writeFileSync(filePath, rendered, "utf-8");
11756
+ fs29.mkdirSync(dir, { recursive: true });
11757
+ fs29.writeFileSync(filePath, rendered, "utf-8");
11703
11758
  }
11704
11759
  return {
11705
11760
  path: filePath,
@@ -11712,16 +11767,16 @@ function writeHostAdapter(projectRoot, adapter, opts) {
11712
11767
  function writeSkill(projectRoot, skill, opts) {
11713
11768
  const dir = safeJoin(projectRoot, `.claude/skills/${skill.name}`);
11714
11769
  const filePath = safeJoin(projectRoot, skillFilePath(skill.name));
11715
- const existed = fs28.existsSync(filePath);
11770
+ const existed = fs29.existsSync(filePath);
11716
11771
  let alreadyCorrect = false;
11717
11772
  if (existed) {
11718
- if (fs28.readFileSync(filePath, "utf-8") === skill.content) {
11773
+ if (fs29.readFileSync(filePath, "utf-8") === skill.content) {
11719
11774
  alreadyCorrect = true;
11720
11775
  }
11721
11776
  }
11722
11777
  if (!opts.dryRun && !alreadyCorrect) {
11723
- fs28.mkdirSync(dir, { recursive: true });
11724
- fs28.writeFileSync(filePath, skill.content, "utf-8");
11778
+ fs29.mkdirSync(dir, { recursive: true });
11779
+ fs29.writeFileSync(filePath, skill.content, "utf-8");
11725
11780
  }
11726
11781
  return {
11727
11782
  path: filePath,
@@ -11734,17 +11789,17 @@ function writeSkill(projectRoot, skill, opts) {
11734
11789
  function writeSessionStartScript(projectRoot, opts) {
11735
11790
  const dir = safeJoin(projectRoot, ".claude/hooks");
11736
11791
  const filePath = safeJoin(projectRoot, ".claude/hooks/session-start.sh");
11737
- const existed = fs28.existsSync(filePath);
11792
+ const existed = fs29.existsSync(filePath);
11738
11793
  let alreadyCorrect = false;
11739
11794
  if (existed) {
11740
- const current = fs28.readFileSync(filePath, "utf-8");
11795
+ const current = fs29.readFileSync(filePath, "utf-8");
11741
11796
  if (current === SESSION_START_FULL) alreadyCorrect = true;
11742
11797
  }
11743
11798
  if (!opts.dryRun && !alreadyCorrect) {
11744
- fs28.mkdirSync(dir, { recursive: true });
11745
- fs28.writeFileSync(filePath, SESSION_START_FULL, "utf-8");
11799
+ fs29.mkdirSync(dir, { recursive: true });
11800
+ fs29.writeFileSync(filePath, SESSION_START_FULL, "utf-8");
11746
11801
  try {
11747
- fs28.chmodSync(filePath, 493);
11802
+ fs29.chmodSync(filePath, 493);
11748
11803
  } catch {
11749
11804
  }
11750
11805
  }
@@ -11793,6 +11848,8 @@ export {
11793
11848
  loadTrendSeries,
11794
11849
  loadFileRiskHistory,
11795
11850
  Skeletonizer,
11851
+ inspectVectorsDb,
11852
+ cleanupVectors,
11796
11853
  renderStatusXml,
11797
11854
  __resetLearnedSuggestionsCacheForTests,
11798
11855
  learnSuggestionsFromTelemetry,
@@ -11889,4 +11946,4 @@ export {
11889
11946
  skillFilePath,
11890
11947
  installHarness
11891
11948
  };
11892
- //# sourceMappingURL=chunk-5R4P7VEE.js.map
11949
+ //# sourceMappingURL=chunk-FPMNXF4D.js.map