@locusai/cli 0.5.0 → 0.5.1
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/bin/agent/worker.js +132 -14
- package/bin/locus.js +138 -23
- package/package.json +2 -2
package/bin/agent/worker.js
CHANGED
|
@@ -35423,6 +35423,7 @@ class ArtifactSyncer {
|
|
|
35423
35423
|
}
|
|
35424
35424
|
|
|
35425
35425
|
// ../sdk/src/core/indexer.ts
|
|
35426
|
+
import { createHash } from "node:crypto";
|
|
35426
35427
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync } from "node:fs";
|
|
35427
35428
|
import { dirname, join as join4 } from "node:path";
|
|
35428
35429
|
|
|
@@ -35934,16 +35935,64 @@ var generateGlobTasksSync = normalizeArgumentsSync(generateTasksSync);
|
|
|
35934
35935
|
class CodebaseIndexer {
|
|
35935
35936
|
projectPath;
|
|
35936
35937
|
indexPath;
|
|
35938
|
+
fullReindexRatioThreshold = 0.2;
|
|
35937
35939
|
constructor(projectPath) {
|
|
35938
35940
|
this.projectPath = projectPath;
|
|
35939
35941
|
this.indexPath = join4(projectPath, ".locus", "codebase-index.json");
|
|
35940
35942
|
}
|
|
35941
|
-
async index(onProgress, treeSummarizer) {
|
|
35943
|
+
async index(onProgress, treeSummarizer, force = false) {
|
|
35942
35944
|
if (!treeSummarizer) {
|
|
35943
35945
|
throw new Error("A treeSummarizer is required for this indexing method.");
|
|
35944
35946
|
}
|
|
35945
|
-
|
|
35946
|
-
|
|
35947
|
+
onProgress?.("Generating file tree...");
|
|
35948
|
+
const currentFiles = await this.getFileTree();
|
|
35949
|
+
const treeString = currentFiles.join(`
|
|
35950
|
+
`);
|
|
35951
|
+
const newTreeHash = this.hashTree(treeString);
|
|
35952
|
+
const existingIndex = this.loadIndex();
|
|
35953
|
+
if (!force && existingIndex?.treeHash === newTreeHash) {
|
|
35954
|
+
onProgress?.("No file changes detected, skipping reindex");
|
|
35955
|
+
return null;
|
|
35956
|
+
}
|
|
35957
|
+
const currentHashes = this.computeFileHashes(currentFiles);
|
|
35958
|
+
const existingHashes = existingIndex?.fileHashes;
|
|
35959
|
+
const canIncremental = !force && existingIndex && existingHashes;
|
|
35960
|
+
if (canIncremental) {
|
|
35961
|
+
onProgress?.("Performing incremental update");
|
|
35962
|
+
const { added, deleted, modified } = this.diffFiles(currentHashes, existingHashes);
|
|
35963
|
+
const changedFiles = [...added, ...modified];
|
|
35964
|
+
const totalChanges = changedFiles.length + deleted.length;
|
|
35965
|
+
const existingFileCount = Object.keys(existingHashes).length;
|
|
35966
|
+
onProgress?.(`File changes detected: ${changedFiles.length} changed, ${added.length} added, ${deleted.length} deleted`);
|
|
35967
|
+
if (existingFileCount > 0) {
|
|
35968
|
+
const changeRatio = totalChanges / existingFileCount;
|
|
35969
|
+
if (changeRatio <= this.fullReindexRatioThreshold && changedFiles.length > 0) {
|
|
35970
|
+
onProgress?.(`Reindexing ${changedFiles.length} changed files and merging with existing index`);
|
|
35971
|
+
const incrementalIndex = await treeSummarizer(changedFiles.join(`
|
|
35972
|
+
`));
|
|
35973
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
35974
|
+
this.removeFilesFromIndex(updatedIndex, [...deleted, ...modified]);
|
|
35975
|
+
return this.mergeIndex(updatedIndex, incrementalIndex, currentHashes, newTreeHash);
|
|
35976
|
+
}
|
|
35977
|
+
if (changedFiles.length === 0 && deleted.length > 0) {
|
|
35978
|
+
onProgress?.(`Removing ${deleted.length} deleted files from index`);
|
|
35979
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
35980
|
+
this.removeFilesFromIndex(updatedIndex, deleted);
|
|
35981
|
+
return this.applyIndexMetadata(updatedIndex, currentHashes, newTreeHash);
|
|
35982
|
+
}
|
|
35983
|
+
if (changedFiles.length === 0 && deleted.length === 0) {
|
|
35984
|
+
onProgress?.("No actual file changes, updating hashes only");
|
|
35985
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
35986
|
+
return this.applyIndexMetadata(updatedIndex, currentHashes, newTreeHash);
|
|
35987
|
+
}
|
|
35988
|
+
onProgress?.(`Too many changes (${(changeRatio * 100).toFixed(1)}%), performing full reindex`);
|
|
35989
|
+
}
|
|
35990
|
+
}
|
|
35991
|
+
onProgress?.("AI is analyzing codebase structure...");
|
|
35992
|
+
const index = await treeSummarizer(treeString);
|
|
35993
|
+
return this.applyIndexMetadata(index, currentHashes, newTreeHash);
|
|
35994
|
+
}
|
|
35995
|
+
async getFileTree() {
|
|
35947
35996
|
const gitmodulesPath = join4(this.projectPath, ".gitmodules");
|
|
35948
35997
|
const submoduleIgnores = [];
|
|
35949
35998
|
if (existsSync3(gitmodulesPath)) {
|
|
@@ -35961,7 +36010,7 @@ class CodebaseIndexer {
|
|
|
35961
36010
|
}
|
|
35962
36011
|
} catch {}
|
|
35963
36012
|
}
|
|
35964
|
-
|
|
36013
|
+
return globby(["**/*"], {
|
|
35965
36014
|
cwd: this.projectPath,
|
|
35966
36015
|
gitignore: true,
|
|
35967
36016
|
ignore: [
|
|
@@ -36002,13 +36051,6 @@ class CodebaseIndexer {
|
|
|
36002
36051
|
"**/*.{png,jpg,jpeg,gif,svg,ico,mp4,webm,wav,mp3,woff,woff2,eot,ttf,otf,pdf,zip,tar.gz,rar}"
|
|
36003
36052
|
]
|
|
36004
36053
|
});
|
|
36005
|
-
const treeString = files.join(`
|
|
36006
|
-
`);
|
|
36007
|
-
if (onProgress)
|
|
36008
|
-
onProgress("AI is analyzing codebase structure...");
|
|
36009
|
-
const index = await treeSummarizer(treeString);
|
|
36010
|
-
index.lastIndexed = new Date().toISOString();
|
|
36011
|
-
return index;
|
|
36012
36054
|
}
|
|
36013
36055
|
loadIndex() {
|
|
36014
36056
|
if (existsSync3(this.indexPath)) {
|
|
@@ -36027,6 +36069,79 @@ class CodebaseIndexer {
|
|
|
36027
36069
|
}
|
|
36028
36070
|
writeFileSync(this.indexPath, JSON.stringify(index, null, 2));
|
|
36029
36071
|
}
|
|
36072
|
+
cloneIndex(index) {
|
|
36073
|
+
return JSON.parse(JSON.stringify(index));
|
|
36074
|
+
}
|
|
36075
|
+
applyIndexMetadata(index, fileHashes, treeHash) {
|
|
36076
|
+
index.lastIndexed = new Date().toISOString();
|
|
36077
|
+
index.treeHash = treeHash;
|
|
36078
|
+
index.fileHashes = fileHashes;
|
|
36079
|
+
return index;
|
|
36080
|
+
}
|
|
36081
|
+
hashTree(tree) {
|
|
36082
|
+
return createHash("sha256").update(tree).digest("hex");
|
|
36083
|
+
}
|
|
36084
|
+
hashFile(filePath) {
|
|
36085
|
+
try {
|
|
36086
|
+
const content = readFileSync3(join4(this.projectPath, filePath), "utf-8");
|
|
36087
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
36088
|
+
} catch {
|
|
36089
|
+
return null;
|
|
36090
|
+
}
|
|
36091
|
+
}
|
|
36092
|
+
computeFileHashes(files) {
|
|
36093
|
+
const hashes = {};
|
|
36094
|
+
for (const file2 of files) {
|
|
36095
|
+
const hash2 = this.hashFile(file2);
|
|
36096
|
+
if (hash2 !== null) {
|
|
36097
|
+
hashes[file2] = hash2;
|
|
36098
|
+
}
|
|
36099
|
+
}
|
|
36100
|
+
return hashes;
|
|
36101
|
+
}
|
|
36102
|
+
diffFiles(currentHashes, existingHashes) {
|
|
36103
|
+
const currentFiles = Object.keys(currentHashes);
|
|
36104
|
+
const existingFiles = Object.keys(existingHashes);
|
|
36105
|
+
const existingSet = new Set(existingFiles);
|
|
36106
|
+
const currentSet = new Set(currentFiles);
|
|
36107
|
+
const added = currentFiles.filter((f) => !existingSet.has(f));
|
|
36108
|
+
const deleted = existingFiles.filter((f) => !currentSet.has(f));
|
|
36109
|
+
const modified = currentFiles.filter((f) => existingSet.has(f) && currentHashes[f] !== existingHashes[f]);
|
|
36110
|
+
return { added, deleted, modified };
|
|
36111
|
+
}
|
|
36112
|
+
removeFilesFromIndex(index, files) {
|
|
36113
|
+
const fileSet = new Set(files);
|
|
36114
|
+
for (const file2 of files) {
|
|
36115
|
+
delete index.responsibilities[file2];
|
|
36116
|
+
}
|
|
36117
|
+
for (const [symbol2, paths] of Object.entries(index.symbols)) {
|
|
36118
|
+
index.symbols[symbol2] = paths.filter((p) => !fileSet.has(p));
|
|
36119
|
+
if (index.symbols[symbol2].length === 0) {
|
|
36120
|
+
delete index.symbols[symbol2];
|
|
36121
|
+
}
|
|
36122
|
+
}
|
|
36123
|
+
}
|
|
36124
|
+
mergeIndex(existing, incremental, newHashes, newTreeHash) {
|
|
36125
|
+
const mergedSymbols = { ...existing.symbols };
|
|
36126
|
+
for (const [symbol2, paths] of Object.entries(incremental.symbols)) {
|
|
36127
|
+
if (mergedSymbols[symbol2]) {
|
|
36128
|
+
mergedSymbols[symbol2] = [
|
|
36129
|
+
...new Set([...mergedSymbols[symbol2], ...paths])
|
|
36130
|
+
];
|
|
36131
|
+
} else {
|
|
36132
|
+
mergedSymbols[symbol2] = paths;
|
|
36133
|
+
}
|
|
36134
|
+
}
|
|
36135
|
+
const merged = {
|
|
36136
|
+
symbols: mergedSymbols,
|
|
36137
|
+
responsibilities: {
|
|
36138
|
+
...existing.responsibilities,
|
|
36139
|
+
...incremental.responsibilities
|
|
36140
|
+
},
|
|
36141
|
+
lastIndexed: ""
|
|
36142
|
+
};
|
|
36143
|
+
return this.applyIndexMetadata(merged, newHashes, newTreeHash);
|
|
36144
|
+
}
|
|
36030
36145
|
}
|
|
36031
36146
|
|
|
36032
36147
|
// ../sdk/src/agent/codebase-indexer-service.ts
|
|
@@ -36037,9 +36152,8 @@ class CodebaseIndexerService {
|
|
|
36037
36152
|
this.deps = deps;
|
|
36038
36153
|
this.indexer = new CodebaseIndexer(deps.projectPath);
|
|
36039
36154
|
}
|
|
36040
|
-
async reindex() {
|
|
36155
|
+
async reindex(force = false) {
|
|
36041
36156
|
try {
|
|
36042
|
-
this.deps.log("Reindexing codebase...", "info");
|
|
36043
36157
|
const index = await this.indexer.index((msg) => this.deps.log(msg, "info"), async (tree) => {
|
|
36044
36158
|
const prompt = `You are a codebase analysis expert. Analyze the file tree and extract:
|
|
36045
36159
|
1. Key symbols (classes, functions, types) and their locations
|
|
@@ -36060,7 +36174,11 @@ Return ONLY valid JSON, no markdown formatting.`;
|
|
|
36060
36174
|
return JSON.parse(jsonMatch[0]);
|
|
36061
36175
|
}
|
|
36062
36176
|
return { symbols: {}, responsibilities: {}, lastIndexed: "" };
|
|
36063
|
-
});
|
|
36177
|
+
}, force);
|
|
36178
|
+
if (index === null) {
|
|
36179
|
+
this.deps.log("No changes detected, skipping reindex", "info");
|
|
36180
|
+
return;
|
|
36181
|
+
}
|
|
36064
36182
|
this.indexer.saveIndex(index);
|
|
36065
36183
|
this.deps.log("Codebase reindexed successfully", "success");
|
|
36066
36184
|
} catch (error48) {
|
package/bin/locus.js
CHANGED
|
@@ -17129,6 +17129,7 @@ class ArtifactSyncer {
|
|
|
17129
17129
|
}
|
|
17130
17130
|
}
|
|
17131
17131
|
// ../sdk/src/core/indexer.ts
|
|
17132
|
+
import { createHash } from "node:crypto";
|
|
17132
17133
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
17133
17134
|
import { dirname, join as join3 } from "node:path";
|
|
17134
17135
|
|
|
@@ -17640,16 +17641,64 @@ var generateGlobTasksSync = normalizeArgumentsSync(generateTasksSync);
|
|
|
17640
17641
|
class CodebaseIndexer {
|
|
17641
17642
|
projectPath;
|
|
17642
17643
|
indexPath;
|
|
17644
|
+
fullReindexRatioThreshold = 0.2;
|
|
17643
17645
|
constructor(projectPath) {
|
|
17644
17646
|
this.projectPath = projectPath;
|
|
17645
17647
|
this.indexPath = join3(projectPath, ".locus", "codebase-index.json");
|
|
17646
17648
|
}
|
|
17647
|
-
async index(onProgress, treeSummarizer) {
|
|
17649
|
+
async index(onProgress, treeSummarizer, force = false) {
|
|
17648
17650
|
if (!treeSummarizer) {
|
|
17649
17651
|
throw new Error("A treeSummarizer is required for this indexing method.");
|
|
17650
17652
|
}
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
+
onProgress?.("Generating file tree...");
|
|
17654
|
+
const currentFiles = await this.getFileTree();
|
|
17655
|
+
const treeString = currentFiles.join(`
|
|
17656
|
+
`);
|
|
17657
|
+
const newTreeHash = this.hashTree(treeString);
|
|
17658
|
+
const existingIndex = this.loadIndex();
|
|
17659
|
+
if (!force && existingIndex?.treeHash === newTreeHash) {
|
|
17660
|
+
onProgress?.("No file changes detected, skipping reindex");
|
|
17661
|
+
return null;
|
|
17662
|
+
}
|
|
17663
|
+
const currentHashes = this.computeFileHashes(currentFiles);
|
|
17664
|
+
const existingHashes = existingIndex?.fileHashes;
|
|
17665
|
+
const canIncremental = !force && existingIndex && existingHashes;
|
|
17666
|
+
if (canIncremental) {
|
|
17667
|
+
onProgress?.("Performing incremental update");
|
|
17668
|
+
const { added, deleted, modified } = this.diffFiles(currentHashes, existingHashes);
|
|
17669
|
+
const changedFiles = [...added, ...modified];
|
|
17670
|
+
const totalChanges = changedFiles.length + deleted.length;
|
|
17671
|
+
const existingFileCount = Object.keys(existingHashes).length;
|
|
17672
|
+
onProgress?.(`File changes detected: ${changedFiles.length} changed, ${added.length} added, ${deleted.length} deleted`);
|
|
17673
|
+
if (existingFileCount > 0) {
|
|
17674
|
+
const changeRatio = totalChanges / existingFileCount;
|
|
17675
|
+
if (changeRatio <= this.fullReindexRatioThreshold && changedFiles.length > 0) {
|
|
17676
|
+
onProgress?.(`Reindexing ${changedFiles.length} changed files and merging with existing index`);
|
|
17677
|
+
const incrementalIndex = await treeSummarizer(changedFiles.join(`
|
|
17678
|
+
`));
|
|
17679
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
17680
|
+
this.removeFilesFromIndex(updatedIndex, [...deleted, ...modified]);
|
|
17681
|
+
return this.mergeIndex(updatedIndex, incrementalIndex, currentHashes, newTreeHash);
|
|
17682
|
+
}
|
|
17683
|
+
if (changedFiles.length === 0 && deleted.length > 0) {
|
|
17684
|
+
onProgress?.(`Removing ${deleted.length} deleted files from index`);
|
|
17685
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
17686
|
+
this.removeFilesFromIndex(updatedIndex, deleted);
|
|
17687
|
+
return this.applyIndexMetadata(updatedIndex, currentHashes, newTreeHash);
|
|
17688
|
+
}
|
|
17689
|
+
if (changedFiles.length === 0 && deleted.length === 0) {
|
|
17690
|
+
onProgress?.("No actual file changes, updating hashes only");
|
|
17691
|
+
const updatedIndex = this.cloneIndex(existingIndex);
|
|
17692
|
+
return this.applyIndexMetadata(updatedIndex, currentHashes, newTreeHash);
|
|
17693
|
+
}
|
|
17694
|
+
onProgress?.(`Too many changes (${(changeRatio * 100).toFixed(1)}%), performing full reindex`);
|
|
17695
|
+
}
|
|
17696
|
+
}
|
|
17697
|
+
onProgress?.("AI is analyzing codebase structure...");
|
|
17698
|
+
const index = await treeSummarizer(treeString);
|
|
17699
|
+
return this.applyIndexMetadata(index, currentHashes, newTreeHash);
|
|
17700
|
+
}
|
|
17701
|
+
async getFileTree() {
|
|
17653
17702
|
const gitmodulesPath = join3(this.projectPath, ".gitmodules");
|
|
17654
17703
|
const submoduleIgnores = [];
|
|
17655
17704
|
if (existsSync2(gitmodulesPath)) {
|
|
@@ -17667,7 +17716,7 @@ class CodebaseIndexer {
|
|
|
17667
17716
|
}
|
|
17668
17717
|
} catch {}
|
|
17669
17718
|
}
|
|
17670
|
-
|
|
17719
|
+
return globby(["**/*"], {
|
|
17671
17720
|
cwd: this.projectPath,
|
|
17672
17721
|
gitignore: true,
|
|
17673
17722
|
ignore: [
|
|
@@ -17708,13 +17757,6 @@ class CodebaseIndexer {
|
|
|
17708
17757
|
"**/*.{png,jpg,jpeg,gif,svg,ico,mp4,webm,wav,mp3,woff,woff2,eot,ttf,otf,pdf,zip,tar.gz,rar}"
|
|
17709
17758
|
]
|
|
17710
17759
|
});
|
|
17711
|
-
const treeString = files.join(`
|
|
17712
|
-
`);
|
|
17713
|
-
if (onProgress)
|
|
17714
|
-
onProgress("AI is analyzing codebase structure...");
|
|
17715
|
-
const index = await treeSummarizer(treeString);
|
|
17716
|
-
index.lastIndexed = new Date().toISOString();
|
|
17717
|
-
return index;
|
|
17718
17760
|
}
|
|
17719
17761
|
loadIndex() {
|
|
17720
17762
|
if (existsSync2(this.indexPath)) {
|
|
@@ -17733,6 +17775,79 @@ class CodebaseIndexer {
|
|
|
17733
17775
|
}
|
|
17734
17776
|
writeFileSync(this.indexPath, JSON.stringify(index, null, 2));
|
|
17735
17777
|
}
|
|
17778
|
+
cloneIndex(index) {
|
|
17779
|
+
return JSON.parse(JSON.stringify(index));
|
|
17780
|
+
}
|
|
17781
|
+
applyIndexMetadata(index, fileHashes, treeHash) {
|
|
17782
|
+
index.lastIndexed = new Date().toISOString();
|
|
17783
|
+
index.treeHash = treeHash;
|
|
17784
|
+
index.fileHashes = fileHashes;
|
|
17785
|
+
return index;
|
|
17786
|
+
}
|
|
17787
|
+
hashTree(tree) {
|
|
17788
|
+
return createHash("sha256").update(tree).digest("hex");
|
|
17789
|
+
}
|
|
17790
|
+
hashFile(filePath) {
|
|
17791
|
+
try {
|
|
17792
|
+
const content = readFileSync2(join3(this.projectPath, filePath), "utf-8");
|
|
17793
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
17794
|
+
} catch {
|
|
17795
|
+
return null;
|
|
17796
|
+
}
|
|
17797
|
+
}
|
|
17798
|
+
computeFileHashes(files) {
|
|
17799
|
+
const hashes = {};
|
|
17800
|
+
for (const file of files) {
|
|
17801
|
+
const hash = this.hashFile(file);
|
|
17802
|
+
if (hash !== null) {
|
|
17803
|
+
hashes[file] = hash;
|
|
17804
|
+
}
|
|
17805
|
+
}
|
|
17806
|
+
return hashes;
|
|
17807
|
+
}
|
|
17808
|
+
diffFiles(currentHashes, existingHashes) {
|
|
17809
|
+
const currentFiles = Object.keys(currentHashes);
|
|
17810
|
+
const existingFiles = Object.keys(existingHashes);
|
|
17811
|
+
const existingSet = new Set(existingFiles);
|
|
17812
|
+
const currentSet = new Set(currentFiles);
|
|
17813
|
+
const added = currentFiles.filter((f) => !existingSet.has(f));
|
|
17814
|
+
const deleted = existingFiles.filter((f) => !currentSet.has(f));
|
|
17815
|
+
const modified = currentFiles.filter((f) => existingSet.has(f) && currentHashes[f] !== existingHashes[f]);
|
|
17816
|
+
return { added, deleted, modified };
|
|
17817
|
+
}
|
|
17818
|
+
removeFilesFromIndex(index, files) {
|
|
17819
|
+
const fileSet = new Set(files);
|
|
17820
|
+
for (const file of files) {
|
|
17821
|
+
delete index.responsibilities[file];
|
|
17822
|
+
}
|
|
17823
|
+
for (const [symbol, paths] of Object.entries(index.symbols)) {
|
|
17824
|
+
index.symbols[symbol] = paths.filter((p) => !fileSet.has(p));
|
|
17825
|
+
if (index.symbols[symbol].length === 0) {
|
|
17826
|
+
delete index.symbols[symbol];
|
|
17827
|
+
}
|
|
17828
|
+
}
|
|
17829
|
+
}
|
|
17830
|
+
mergeIndex(existing, incremental, newHashes, newTreeHash) {
|
|
17831
|
+
const mergedSymbols = { ...existing.symbols };
|
|
17832
|
+
for (const [symbol, paths] of Object.entries(incremental.symbols)) {
|
|
17833
|
+
if (mergedSymbols[symbol]) {
|
|
17834
|
+
mergedSymbols[symbol] = [
|
|
17835
|
+
...new Set([...mergedSymbols[symbol], ...paths])
|
|
17836
|
+
];
|
|
17837
|
+
} else {
|
|
17838
|
+
mergedSymbols[symbol] = paths;
|
|
17839
|
+
}
|
|
17840
|
+
}
|
|
17841
|
+
const merged = {
|
|
17842
|
+
symbols: mergedSymbols,
|
|
17843
|
+
responsibilities: {
|
|
17844
|
+
...existing.responsibilities,
|
|
17845
|
+
...incremental.responsibilities
|
|
17846
|
+
},
|
|
17847
|
+
lastIndexed: ""
|
|
17848
|
+
};
|
|
17849
|
+
return this.applyIndexMetadata(merged, newHashes, newTreeHash);
|
|
17850
|
+
}
|
|
17736
17851
|
}
|
|
17737
17852
|
|
|
17738
17853
|
// ../sdk/src/agent/codebase-indexer-service.ts
|
|
@@ -17743,9 +17858,8 @@ class CodebaseIndexerService {
|
|
|
17743
17858
|
this.deps = deps;
|
|
17744
17859
|
this.indexer = new CodebaseIndexer(deps.projectPath);
|
|
17745
17860
|
}
|
|
17746
|
-
async reindex() {
|
|
17861
|
+
async reindex(force = false) {
|
|
17747
17862
|
try {
|
|
17748
|
-
this.deps.log("Reindexing codebase...", "info");
|
|
17749
17863
|
const index = await this.indexer.index((msg) => this.deps.log(msg, "info"), async (tree) => {
|
|
17750
17864
|
const prompt = `You are a codebase analysis expert. Analyze the file tree and extract:
|
|
17751
17865
|
1. Key symbols (classes, functions, types) and their locations
|
|
@@ -17766,7 +17880,11 @@ Return ONLY valid JSON, no markdown formatting.`;
|
|
|
17766
17880
|
return JSON.parse(jsonMatch[0]);
|
|
17767
17881
|
}
|
|
17768
17882
|
return { symbols: {}, responsibilities: {}, lastIndexed: "" };
|
|
17769
|
-
});
|
|
17883
|
+
}, force);
|
|
17884
|
+
if (index === null) {
|
|
17885
|
+
this.deps.log("No changes detected, skipping reindex", "info");
|
|
17886
|
+
return;
|
|
17887
|
+
}
|
|
17770
17888
|
this.indexer.saveIndex(index);
|
|
17771
17889
|
this.deps.log("Codebase reindexed successfully", "success");
|
|
17772
17890
|
} catch (error) {
|
|
@@ -36923,9 +37041,9 @@ async function runCommand(args) {
|
|
|
36923
37041
|
const projectPath = values.dir || process.cwd();
|
|
36924
37042
|
requireInitialization(projectPath, "run");
|
|
36925
37043
|
new ConfigManager(projectPath).updateVersion(VERSION2);
|
|
36926
|
-
const apiKey = values["api-key"]
|
|
36927
|
-
const workspaceId = values.workspace
|
|
36928
|
-
const provider = resolveProvider2(values.provider
|
|
37044
|
+
const apiKey = values["api-key"];
|
|
37045
|
+
const workspaceId = values.workspace;
|
|
37046
|
+
const provider = resolveProvider2(values.provider);
|
|
36929
37047
|
const model = values.model || DEFAULT_MODEL[provider];
|
|
36930
37048
|
if (!apiKey || !workspaceId) {
|
|
36931
37049
|
console.error(c.error("Error: --api-key and --workspace are required"));
|
|
@@ -36979,7 +37097,9 @@ async function indexCommand(args) {
|
|
|
36979
37097
|
const indexer = new CodebaseIndexer(projectPath);
|
|
36980
37098
|
console.log(`${c.primary("\uD83D\uDD0D Indexing codebase in")} ${c.bold(projectPath)}...`);
|
|
36981
37099
|
const index = await indexer.index((msg) => console.log(` ${c.dim(msg)}`), (tree) => summarizer.summarize(tree));
|
|
36982
|
-
|
|
37100
|
+
if (index) {
|
|
37101
|
+
indexer.saveIndex(index);
|
|
37102
|
+
}
|
|
36983
37103
|
console.log(c.success("✅ Indexing complete!"));
|
|
36984
37104
|
}
|
|
36985
37105
|
async function initCommand() {
|
|
@@ -37043,11 +37163,6 @@ Examples:
|
|
|
37043
37163
|
locus index
|
|
37044
37164
|
locus run --api-key YOUR_KEY --workspace WORKSPACE_ID
|
|
37045
37165
|
|
|
37046
|
-
Environment Variables:
|
|
37047
|
-
LOCUS_API_KEY API key for authentication
|
|
37048
|
-
LOCUS_WORKSPACE_ID Workspace ID
|
|
37049
|
-
LOCUS_AI_PROVIDER AI provider: claude or codex
|
|
37050
|
-
|
|
37051
37166
|
For more information, visit: https://locusai.dev/docs
|
|
37052
37167
|
`);
|
|
37053
37168
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locusai/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "CLI for Locus - AI-native project management platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"author": "",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@locusai/sdk": "^0.5.
|
|
35
|
+
"@locusai/sdk": "^0.5.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {}
|
|
38
38
|
}
|