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.
- package/README.md +2 -2
- package/apps/dashboard/dist/server/index.js +110 -105
- package/dist/{VectorStore-4VWT2ZMW.js → VectorStore-2LVECRTY.js} +2 -2
- package/dist/{chunk-5R4P7VEE.js → chunk-FPMNXF4D.js} +234 -177
- package/dist/{chunk-R56D54Y7.js → chunk-JULFFD7O.js} +10 -2
- package/dist/{chunk-COH5WYZS.js → chunk-WDX4PJGL.js} +2 -2
- package/dist/{embedder-7YOG4DFN.js → embedder-3AE4CSR7.js} +2 -2
- package/dist/index.js +138 -21
- package/dist/{src-QMDQDATD.js → src-DL44T55H.js} +8 -4
- package/dist/workers/indexerWorker.js +2 -2
- package/package.json +1 -1
- package/README.md.bak +0 -832
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VectorStore
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JULFFD7O.js";
|
|
4
4
|
import {
|
|
5
5
|
collectFiles,
|
|
6
6
|
generateEmbedding
|
|
7
|
-
} from "./chunk-
|
|
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
|
|
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
|
|
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
|
|
3551
|
-
this.nodeCounts.set(
|
|
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 [
|
|
3699
|
-
nodes[
|
|
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 [
|
|
3715
|
-
idx.nodes.set(
|
|
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(
|
|
3729
|
-
const existing = this.nodes.get(
|
|
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(
|
|
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 [
|
|
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[
|
|
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 [
|
|
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(
|
|
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(
|
|
3846
|
-
const existing = this.nodes.get(
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
5793
|
+
import path16 from "path";
|
|
5739
5794
|
function escapeXML4(text) {
|
|
5740
5795
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
7167
|
-
import
|
|
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 =
|
|
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 =
|
|
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
|
|
7460
|
-
import
|
|
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 (!
|
|
7503
|
-
return JSON.parse(
|
|
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 =
|
|
7510
|
-
if (!
|
|
7511
|
-
|
|
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 =
|
|
7521
|
-
return this.repos.find((r) =>
|
|
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 &&
|
|
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) =>
|
|
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:
|
|
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) =>
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
7572
7627
|
}
|
|
7573
7628
|
function registerCrossRepoSearchTool(registry, ctx, registryFilePath) {
|
|
7574
|
-
const repoRegistryPath = registryFilePath ??
|
|
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
|
|
7696
|
-
import
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
7917
|
-
import
|
|
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 =
|
|
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-
|
|
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 =
|
|
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-
|
|
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
|
|
8277
|
-
import
|
|
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 =
|
|
8290
|
-
|
|
8291
|
-
const snapshotPath =
|
|
8292
|
-
if (!snapshotPath.startsWith(snapshotsDir +
|
|
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 (
|
|
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
|
|
8311
|
-
|
|
8312
|
-
|
|
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 =
|
|
8316
|
-
if (!
|
|
8317
|
-
return
|
|
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
|
|
8367
|
-
import
|
|
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 =
|
|
8376
|
-
const snapshotPath =
|
|
8377
|
-
if (!snapshotPath.startsWith(snapshotsDir +
|
|
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 (!
|
|
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(
|
|
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
|
|
8779
|
-
import
|
|
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 =
|
|
8849
|
+
const filePath = path24.join(rootDir, ".ctxloom", "rules.yml");
|
|
8795
8850
|
let raw;
|
|
8796
8851
|
try {
|
|
8797
|
-
raw = await
|
|
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
|
|
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:
|
|
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
|
|
9441
|
-
import
|
|
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 =
|
|
9520
|
+
const fullPath = path25.join(this.projectRoot, ruleFile);
|
|
9466
9521
|
try {
|
|
9467
9522
|
this.pathValidator.validate(fullPath);
|
|
9468
|
-
if (
|
|
9469
|
-
const stat =
|
|
9523
|
+
if (fs23.existsSync(fullPath)) {
|
|
9524
|
+
const stat = fs23.statSync(fullPath);
|
|
9470
9525
|
if (stat.isFile()) {
|
|
9471
|
-
const content =
|
|
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 =
|
|
9533
|
+
const dirEntries = fs23.readdirSync(fullPath);
|
|
9479
9534
|
for (const entry of dirEntries) {
|
|
9480
|
-
const entryPath =
|
|
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 =
|
|
9541
|
+
const entryStat = fs23.statSync(entryPath);
|
|
9487
9542
|
if (entryStat.isFile()) {
|
|
9488
|
-
const content =
|
|
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
|
|
9532
|
-
import
|
|
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
|
|
9558
|
-
|
|
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 =
|
|
9622
|
+
const file = path26.join(this.ctxloomDir, "authors.yml");
|
|
9568
9623
|
try {
|
|
9569
|
-
const raw = await
|
|
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 =
|
|
9633
|
+
const file = path26.join(this.ctxloomDir, "authors-cache.json");
|
|
9579
9634
|
try {
|
|
9580
|
-
const raw = await
|
|
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
|
|
9606
|
-
import
|
|
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
|
|
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
|
|
9646
|
-
await
|
|
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
|
|
9832
|
-
import
|
|
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 =
|
|
9898
|
+
const file = path28.join(root, ".ctxloom", "review.yml");
|
|
9844
9899
|
try {
|
|
9845
|
-
const raw = await
|
|
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
|
|
9861
|
-
import
|
|
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 =
|
|
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 =
|
|
9931
|
+
const resolved = path29.resolve(this.canonicalRoot, inputPath);
|
|
9877
9932
|
let canonical;
|
|
9878
9933
|
try {
|
|
9879
|
-
canonical =
|
|
9934
|
+
canonical = fs27.realpathSync(resolved);
|
|
9880
9935
|
} catch {
|
|
9881
9936
|
canonical = resolved;
|
|
9882
9937
|
}
|
|
9883
|
-
if (!canonical.startsWith(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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
10619
|
+
import path33 from "path";
|
|
10565
10620
|
import os6 from "os";
|
|
10566
10621
|
function noticePath(home) {
|
|
10567
|
-
return
|
|
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(
|
|
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
|
|
10636
|
+
import path35 from "path";
|
|
10582
10637
|
|
|
10583
10638
|
// packages/core/src/server/projectId.ts
|
|
10584
10639
|
import crypto5 from "crypto";
|
|
10585
|
-
import
|
|
10640
|
+
import path34 from "path";
|
|
10586
10641
|
function hashProjectRoot(absPath) {
|
|
10587
|
-
const canonical =
|
|
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:
|
|
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
|
|
10748
|
-
import
|
|
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 :
|
|
10828
|
+
expanded = p === "~" ? home : path36.join(home, p.slice(2));
|
|
10774
10829
|
}
|
|
10775
|
-
return
|
|
10830
|
+
return path36.isAbsolute(expanded) ? path36.resolve(expanded) : path36.resolve(cwd, expanded);
|
|
10776
10831
|
}
|
|
10777
10832
|
function realpathOrSame(p) {
|
|
10778
10833
|
try {
|
|
10779
|
-
return
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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) =>
|
|
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
|
|
10920
|
-
import
|
|
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 =
|
|
11546
|
-
const stat =
|
|
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 =
|
|
11595
|
-
const rootResolved =
|
|
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 +
|
|
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 =
|
|
11607
|
-
const existing = existed ?
|
|
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
|
-
|
|
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 =
|
|
11693
|
+
const existed = fs29.existsSync(filePath);
|
|
11639
11694
|
let current = {};
|
|
11640
11695
|
if (existed) {
|
|
11641
11696
|
try {
|
|
11642
|
-
const text =
|
|
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 ${
|
|
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 =
|
|
11718
|
+
const currentText = fs29.readFileSync(filePath, "utf-8");
|
|
11664
11719
|
if (currentText === nextJson) alreadyCorrect = true;
|
|
11665
11720
|
}
|
|
11666
11721
|
if (!opts.dryRun && !alreadyCorrect) {
|
|
11667
|
-
|
|
11668
|
-
|
|
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 =
|
|
11691
|
-
const existed =
|
|
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 =
|
|
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
|
-
|
|
11702
|
-
|
|
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 =
|
|
11770
|
+
const existed = fs29.existsSync(filePath);
|
|
11716
11771
|
let alreadyCorrect = false;
|
|
11717
11772
|
if (existed) {
|
|
11718
|
-
if (
|
|
11773
|
+
if (fs29.readFileSync(filePath, "utf-8") === skill.content) {
|
|
11719
11774
|
alreadyCorrect = true;
|
|
11720
11775
|
}
|
|
11721
11776
|
}
|
|
11722
11777
|
if (!opts.dryRun && !alreadyCorrect) {
|
|
11723
|
-
|
|
11724
|
-
|
|
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 =
|
|
11792
|
+
const existed = fs29.existsSync(filePath);
|
|
11738
11793
|
let alreadyCorrect = false;
|
|
11739
11794
|
if (existed) {
|
|
11740
|
-
const current =
|
|
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
|
-
|
|
11745
|
-
|
|
11799
|
+
fs29.mkdirSync(dir, { recursive: true });
|
|
11800
|
+
fs29.writeFileSync(filePath, SESSION_START_FULL, "utf-8");
|
|
11746
11801
|
try {
|
|
11747
|
-
|
|
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-
|
|
11949
|
+
//# sourceMappingURL=chunk-FPMNXF4D.js.map
|