@liendev/lien 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +262 -139
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -378,8 +378,8 @@ var init_errors = __esm({
|
|
|
378
378
|
});
|
|
379
379
|
|
|
380
380
|
// src/config/service.ts
|
|
381
|
-
import
|
|
382
|
-
import
|
|
381
|
+
import fs9 from "fs/promises";
|
|
382
|
+
import path9 from "path";
|
|
383
383
|
var ConfigService, configService;
|
|
384
384
|
var init_service = __esm({
|
|
385
385
|
"src/config/service.ts"() {
|
|
@@ -401,13 +401,13 @@ var init_service = __esm({
|
|
|
401
401
|
async load(rootDir = process.cwd()) {
|
|
402
402
|
const configPath = this.getConfigPath(rootDir);
|
|
403
403
|
try {
|
|
404
|
-
const configContent = await
|
|
404
|
+
const configContent = await fs9.readFile(configPath, "utf-8");
|
|
405
405
|
const userConfig = JSON.parse(configContent);
|
|
406
406
|
if (this.needsMigration(userConfig)) {
|
|
407
407
|
console.log("\u{1F504} Migrating config from v0.2.0 to v0.3.0...");
|
|
408
408
|
const result = await this.migrate(rootDir);
|
|
409
409
|
if (result.migrated && result.backupPath) {
|
|
410
|
-
const backupFilename =
|
|
410
|
+
const backupFilename = path9.basename(result.backupPath);
|
|
411
411
|
console.log(`\u2705 Migration complete! Backup saved as ${backupFilename}`);
|
|
412
412
|
console.log("\u{1F4DD} Your config now uses the framework-based structure.");
|
|
413
413
|
}
|
|
@@ -463,7 +463,7 @@ ${validation.errors.join("\n")}`,
|
|
|
463
463
|
}
|
|
464
464
|
try {
|
|
465
465
|
const configJson = JSON.stringify(config, null, 2) + "\n";
|
|
466
|
-
await
|
|
466
|
+
await fs9.writeFile(configPath, configJson, "utf-8");
|
|
467
467
|
} catch (error) {
|
|
468
468
|
throw wrapError(error, "Failed to save configuration", { path: configPath });
|
|
469
469
|
}
|
|
@@ -477,7 +477,7 @@ ${validation.errors.join("\n")}`,
|
|
|
477
477
|
async exists(rootDir = process.cwd()) {
|
|
478
478
|
const configPath = this.getConfigPath(rootDir);
|
|
479
479
|
try {
|
|
480
|
-
await
|
|
480
|
+
await fs9.access(configPath);
|
|
481
481
|
return true;
|
|
482
482
|
} catch {
|
|
483
483
|
return false;
|
|
@@ -494,7 +494,7 @@ ${validation.errors.join("\n")}`,
|
|
|
494
494
|
async migrate(rootDir = process.cwd()) {
|
|
495
495
|
const configPath = this.getConfigPath(rootDir);
|
|
496
496
|
try {
|
|
497
|
-
const configContent = await
|
|
497
|
+
const configContent = await fs9.readFile(configPath, "utf-8");
|
|
498
498
|
const oldConfig = JSON.parse(configContent);
|
|
499
499
|
if (!this.needsMigration(oldConfig)) {
|
|
500
500
|
return {
|
|
@@ -512,7 +512,7 @@ ${validation.errors.join("\n")}`,
|
|
|
512
512
|
);
|
|
513
513
|
}
|
|
514
514
|
const backupPath = `${configPath}.v0.2.0.backup`;
|
|
515
|
-
await
|
|
515
|
+
await fs9.copyFile(configPath, backupPath);
|
|
516
516
|
await this.save(rootDir, newConfig);
|
|
517
517
|
return {
|
|
518
518
|
migrated: true,
|
|
@@ -610,7 +610,7 @@ ${validation.errors.join("\n")}`,
|
|
|
610
610
|
* Get the full path to the config file
|
|
611
611
|
*/
|
|
612
612
|
getConfigPath(rootDir) {
|
|
613
|
-
return
|
|
613
|
+
return path9.join(rootDir, _ConfigService.CONFIG_FILENAME);
|
|
614
614
|
}
|
|
615
615
|
/**
|
|
616
616
|
* Validate modern (v0.3.0+) configuration
|
|
@@ -774,7 +774,7 @@ ${validation.errors.join("\n")}`,
|
|
|
774
774
|
errors.push(`frameworks[${index}] missing required field: path`);
|
|
775
775
|
} else if (typeof fw.path !== "string") {
|
|
776
776
|
errors.push(`frameworks[${index}].path must be a string`);
|
|
777
|
-
} else if (
|
|
777
|
+
} else if (path9.isAbsolute(fw.path)) {
|
|
778
778
|
errors.push(`frameworks[${index}].path must be relative, got: ${fw.path}`);
|
|
779
779
|
}
|
|
780
780
|
if (fw.enabled === void 0) {
|
|
@@ -834,12 +834,12 @@ __export(utils_exports, {
|
|
|
834
834
|
});
|
|
835
835
|
import { exec } from "child_process";
|
|
836
836
|
import { promisify } from "util";
|
|
837
|
-
import
|
|
838
|
-
import
|
|
837
|
+
import fs10 from "fs/promises";
|
|
838
|
+
import path10 from "path";
|
|
839
839
|
async function isGitRepo(rootDir) {
|
|
840
840
|
try {
|
|
841
|
-
const gitDir =
|
|
842
|
-
await
|
|
841
|
+
const gitDir = path10.join(rootDir, ".git");
|
|
842
|
+
await fs10.access(gitDir);
|
|
843
843
|
return true;
|
|
844
844
|
} catch {
|
|
845
845
|
return false;
|
|
@@ -878,7 +878,7 @@ async function getChangedFiles(rootDir, fromRef, toRef) {
|
|
|
878
878
|
// 10 second timeout for diffs
|
|
879
879
|
}
|
|
880
880
|
);
|
|
881
|
-
const files = stdout.trim().split("\n").filter(Boolean).map((file) =>
|
|
881
|
+
const files = stdout.trim().split("\n").filter(Boolean).map((file) => path10.join(rootDir, file));
|
|
882
882
|
return files;
|
|
883
883
|
} catch (error) {
|
|
884
884
|
throw new Error(`Failed to get changed files: ${error}`);
|
|
@@ -893,7 +893,7 @@ async function getChangedFilesInCommit(rootDir, commitSha) {
|
|
|
893
893
|
timeout: 1e4
|
|
894
894
|
}
|
|
895
895
|
);
|
|
896
|
-
const files = stdout.trim().split("\n").filter(Boolean).map((file) =>
|
|
896
|
+
const files = stdout.trim().split("\n").filter(Boolean).map((file) => path10.join(rootDir, file));
|
|
897
897
|
return files;
|
|
898
898
|
} catch (error) {
|
|
899
899
|
throw new Error(`Failed to get changed files in commit: ${error}`);
|
|
@@ -908,7 +908,7 @@ async function getChangedFilesBetweenCommits(rootDir, fromCommit, toCommit) {
|
|
|
908
908
|
timeout: 1e4
|
|
909
909
|
}
|
|
910
910
|
);
|
|
911
|
-
const files = stdout.trim().split("\n").filter(Boolean).map((file) =>
|
|
911
|
+
const files = stdout.trim().split("\n").filter(Boolean).map((file) => path10.join(rootDir, file));
|
|
912
912
|
return files;
|
|
913
913
|
} catch (error) {
|
|
914
914
|
throw new Error(`Failed to get changed files between commits: ${error}`);
|
|
@@ -931,21 +931,21 @@ var init_utils = __esm({
|
|
|
931
931
|
});
|
|
932
932
|
|
|
933
933
|
// src/vectordb/version.ts
|
|
934
|
-
import
|
|
935
|
-
import
|
|
934
|
+
import fs11 from "fs/promises";
|
|
935
|
+
import path11 from "path";
|
|
936
936
|
async function writeVersionFile(indexPath) {
|
|
937
937
|
try {
|
|
938
|
-
const versionFilePath =
|
|
938
|
+
const versionFilePath = path11.join(indexPath, VERSION_FILE);
|
|
939
939
|
const timestamp = Date.now().toString();
|
|
940
|
-
await
|
|
940
|
+
await fs11.writeFile(versionFilePath, timestamp, "utf-8");
|
|
941
941
|
} catch (error) {
|
|
942
942
|
console.error(`Warning: Failed to write version file: ${error}`);
|
|
943
943
|
}
|
|
944
944
|
}
|
|
945
945
|
async function readVersionFile(indexPath) {
|
|
946
946
|
try {
|
|
947
|
-
const versionFilePath =
|
|
948
|
-
const content = await
|
|
947
|
+
const versionFilePath = path11.join(indexPath, VERSION_FILE);
|
|
948
|
+
const content = await fs11.readFile(versionFilePath, "utf-8");
|
|
949
949
|
const timestamp = parseInt(content.trim(), 10);
|
|
950
950
|
return isNaN(timestamp) ? 0 : timestamp;
|
|
951
951
|
} catch (error) {
|
|
@@ -963,8 +963,8 @@ var init_version2 = __esm({
|
|
|
963
963
|
// src/indexer/scanner.ts
|
|
964
964
|
import { glob } from "glob";
|
|
965
965
|
import ignore from "ignore";
|
|
966
|
-
import
|
|
967
|
-
import
|
|
966
|
+
import fs13 from "fs/promises";
|
|
967
|
+
import path13 from "path";
|
|
968
968
|
async function scanCodebaseWithFrameworks(rootDir, config) {
|
|
969
969
|
const allFiles = [];
|
|
970
970
|
for (const framework of config.frameworks) {
|
|
@@ -977,16 +977,16 @@ async function scanCodebaseWithFrameworks(rootDir, config) {
|
|
|
977
977
|
return allFiles;
|
|
978
978
|
}
|
|
979
979
|
async function scanFramework(rootDir, framework) {
|
|
980
|
-
const frameworkPath =
|
|
981
|
-
const gitignorePath =
|
|
980
|
+
const frameworkPath = path13.join(rootDir, framework.path);
|
|
981
|
+
const gitignorePath = path13.join(frameworkPath, ".gitignore");
|
|
982
982
|
let ig = ignore();
|
|
983
983
|
try {
|
|
984
|
-
const gitignoreContent = await
|
|
984
|
+
const gitignoreContent = await fs13.readFile(gitignorePath, "utf-8");
|
|
985
985
|
ig = ignore().add(gitignoreContent);
|
|
986
986
|
} catch (e) {
|
|
987
|
-
const rootGitignorePath =
|
|
987
|
+
const rootGitignorePath = path13.join(rootDir, ".gitignore");
|
|
988
988
|
try {
|
|
989
|
-
const gitignoreContent = await
|
|
989
|
+
const gitignoreContent = await fs13.readFile(rootGitignorePath, "utf-8");
|
|
990
990
|
ig = ignore().add(gitignoreContent);
|
|
991
991
|
} catch (e2) {
|
|
992
992
|
}
|
|
@@ -1008,15 +1008,15 @@ async function scanFramework(rootDir, framework) {
|
|
|
1008
1008
|
}
|
|
1009
1009
|
const uniqueFiles = Array.from(new Set(allFiles));
|
|
1010
1010
|
return uniqueFiles.filter((file) => !ig.ignores(file)).map((file) => {
|
|
1011
|
-
return framework.path === "." ? file :
|
|
1011
|
+
return framework.path === "." ? file : path13.join(framework.path, file);
|
|
1012
1012
|
});
|
|
1013
1013
|
}
|
|
1014
1014
|
async function scanCodebase(options) {
|
|
1015
1015
|
const { rootDir, includePatterns = [], excludePatterns = [] } = options;
|
|
1016
|
-
const gitignorePath =
|
|
1016
|
+
const gitignorePath = path13.join(rootDir, ".gitignore");
|
|
1017
1017
|
let ig = ignore();
|
|
1018
1018
|
try {
|
|
1019
|
-
const gitignoreContent = await
|
|
1019
|
+
const gitignoreContent = await fs13.readFile(gitignorePath, "utf-8");
|
|
1020
1020
|
ig = ignore().add(gitignoreContent);
|
|
1021
1021
|
} catch (e) {
|
|
1022
1022
|
}
|
|
@@ -1043,12 +1043,12 @@ async function scanCodebase(options) {
|
|
|
1043
1043
|
}
|
|
1044
1044
|
const uniqueFiles = Array.from(new Set(allFiles));
|
|
1045
1045
|
return uniqueFiles.filter((file) => {
|
|
1046
|
-
const relativePath =
|
|
1046
|
+
const relativePath = path13.relative(rootDir, file);
|
|
1047
1047
|
return !ig.ignores(relativePath);
|
|
1048
1048
|
});
|
|
1049
1049
|
}
|
|
1050
1050
|
function detectLanguage(filepath) {
|
|
1051
|
-
const ext =
|
|
1051
|
+
const ext = path13.extname(filepath).toLowerCase();
|
|
1052
1052
|
const languageMap = {
|
|
1053
1053
|
".ts": "typescript",
|
|
1054
1054
|
".tsx": "typescript",
|
|
@@ -2591,10 +2591,10 @@ var init_types2 = __esm({
|
|
|
2591
2591
|
});
|
|
2592
2592
|
|
|
2593
2593
|
// src/vectordb/boosting/strategies.ts
|
|
2594
|
-
import
|
|
2594
|
+
import path14 from "path";
|
|
2595
2595
|
function isDocumentationFile(filepath) {
|
|
2596
2596
|
const lower = filepath.toLowerCase();
|
|
2597
|
-
const filename =
|
|
2597
|
+
const filename = path14.basename(filepath).toLowerCase();
|
|
2598
2598
|
if (filename.startsWith("readme")) return true;
|
|
2599
2599
|
if (filename.startsWith("changelog")) return true;
|
|
2600
2600
|
if (filename.endsWith(".md") || filename.endsWith(".mdx") || filename.endsWith(".markdown")) {
|
|
@@ -2651,7 +2651,7 @@ var init_strategies = __esm({
|
|
|
2651
2651
|
FilenameBoostingStrategy = class {
|
|
2652
2652
|
name = "filename-matching";
|
|
2653
2653
|
apply(query, filepath, baseScore) {
|
|
2654
|
-
const filename =
|
|
2654
|
+
const filename = path14.basename(filepath, path14.extname(filepath)).toLowerCase();
|
|
2655
2655
|
const queryTokens = query.toLowerCase().split(/\s+/);
|
|
2656
2656
|
let boostFactor = 1;
|
|
2657
2657
|
for (const token of queryTokens) {
|
|
@@ -3153,7 +3153,7 @@ __export(lancedb_exports, {
|
|
|
3153
3153
|
VectorDB: () => VectorDB
|
|
3154
3154
|
});
|
|
3155
3155
|
import * as lancedb from "vectordb";
|
|
3156
|
-
import
|
|
3156
|
+
import path15 from "path";
|
|
3157
3157
|
import os2 from "os";
|
|
3158
3158
|
import crypto2 from "crypto";
|
|
3159
3159
|
var VectorDB;
|
|
@@ -3174,9 +3174,9 @@ var init_lancedb = __esm({
|
|
|
3174
3174
|
lastVersionCheck = 0;
|
|
3175
3175
|
currentVersion = 0;
|
|
3176
3176
|
constructor(projectRoot) {
|
|
3177
|
-
const projectName =
|
|
3177
|
+
const projectName = path15.basename(projectRoot);
|
|
3178
3178
|
const pathHash = crypto2.createHash("md5").update(projectRoot).digest("hex").substring(0, 8);
|
|
3179
|
-
this.dbPath =
|
|
3179
|
+
this.dbPath = path15.join(
|
|
3180
3180
|
os2.homedir(),
|
|
3181
3181
|
".lien",
|
|
3182
3182
|
"indices",
|
|
@@ -3348,8 +3348,8 @@ var manifest_exports = {};
|
|
|
3348
3348
|
__export(manifest_exports, {
|
|
3349
3349
|
ManifestManager: () => ManifestManager
|
|
3350
3350
|
});
|
|
3351
|
-
import
|
|
3352
|
-
import
|
|
3351
|
+
import fs14 from "fs/promises";
|
|
3352
|
+
import path16 from "path";
|
|
3353
3353
|
var MANIFEST_FILE, ManifestManager;
|
|
3354
3354
|
var init_manifest = __esm({
|
|
3355
3355
|
"src/indexer/manifest.ts"() {
|
|
@@ -3371,7 +3371,7 @@ var init_manifest = __esm({
|
|
|
3371
3371
|
*/
|
|
3372
3372
|
constructor(indexPath) {
|
|
3373
3373
|
this.indexPath = indexPath;
|
|
3374
|
-
this.manifestPath =
|
|
3374
|
+
this.manifestPath = path16.join(indexPath, MANIFEST_FILE);
|
|
3375
3375
|
}
|
|
3376
3376
|
/**
|
|
3377
3377
|
* Loads the manifest from disk.
|
|
@@ -3384,7 +3384,7 @@ var init_manifest = __esm({
|
|
|
3384
3384
|
*/
|
|
3385
3385
|
async load() {
|
|
3386
3386
|
try {
|
|
3387
|
-
const content = await
|
|
3387
|
+
const content = await fs14.readFile(this.manifestPath, "utf-8");
|
|
3388
3388
|
const manifest = JSON.parse(content);
|
|
3389
3389
|
if (manifest.formatVersion !== INDEX_FORMAT_VERSION) {
|
|
3390
3390
|
console.error(
|
|
@@ -3411,7 +3411,7 @@ var init_manifest = __esm({
|
|
|
3411
3411
|
*/
|
|
3412
3412
|
async save(manifest) {
|
|
3413
3413
|
try {
|
|
3414
|
-
await
|
|
3414
|
+
await fs14.mkdir(this.indexPath, { recursive: true });
|
|
3415
3415
|
const manifestToSave = {
|
|
3416
3416
|
...manifest,
|
|
3417
3417
|
formatVersion: INDEX_FORMAT_VERSION,
|
|
@@ -3419,7 +3419,7 @@ var init_manifest = __esm({
|
|
|
3419
3419
|
lastIndexed: Date.now()
|
|
3420
3420
|
};
|
|
3421
3421
|
const content = JSON.stringify(manifestToSave, null, 2);
|
|
3422
|
-
await
|
|
3422
|
+
await fs14.writeFile(this.manifestPath, content, "utf-8");
|
|
3423
3423
|
} catch (error) {
|
|
3424
3424
|
console.error(`[Lien] Warning: Failed to save manifest: ${error}`);
|
|
3425
3425
|
}
|
|
@@ -3556,7 +3556,7 @@ var init_manifest = __esm({
|
|
|
3556
3556
|
*/
|
|
3557
3557
|
async clear() {
|
|
3558
3558
|
try {
|
|
3559
|
-
await
|
|
3559
|
+
await fs14.unlink(this.manifestPath);
|
|
3560
3560
|
} catch (error) {
|
|
3561
3561
|
if (error.code !== "ENOENT") {
|
|
3562
3562
|
console.error(`[Lien] Warning: Failed to clear manifest: ${error}`);
|
|
@@ -3585,8 +3585,8 @@ var tracker_exports = {};
|
|
|
3585
3585
|
__export(tracker_exports, {
|
|
3586
3586
|
GitStateTracker: () => GitStateTracker
|
|
3587
3587
|
});
|
|
3588
|
-
import
|
|
3589
|
-
import
|
|
3588
|
+
import fs15 from "fs/promises";
|
|
3589
|
+
import path17 from "path";
|
|
3590
3590
|
var GitStateTracker;
|
|
3591
3591
|
var init_tracker = __esm({
|
|
3592
3592
|
"src/git/tracker.ts"() {
|
|
@@ -3598,7 +3598,7 @@ var init_tracker = __esm({
|
|
|
3598
3598
|
currentState = null;
|
|
3599
3599
|
constructor(rootDir, indexPath) {
|
|
3600
3600
|
this.rootDir = rootDir;
|
|
3601
|
-
this.stateFile =
|
|
3601
|
+
this.stateFile = path17.join(indexPath, ".git-state.json");
|
|
3602
3602
|
}
|
|
3603
3603
|
/**
|
|
3604
3604
|
* Loads the last known git state from disk.
|
|
@@ -3606,7 +3606,7 @@ var init_tracker = __esm({
|
|
|
3606
3606
|
*/
|
|
3607
3607
|
async loadState() {
|
|
3608
3608
|
try {
|
|
3609
|
-
const content = await
|
|
3609
|
+
const content = await fs15.readFile(this.stateFile, "utf-8");
|
|
3610
3610
|
return JSON.parse(content);
|
|
3611
3611
|
} catch {
|
|
3612
3612
|
return null;
|
|
@@ -3618,7 +3618,7 @@ var init_tracker = __esm({
|
|
|
3618
3618
|
async saveState(state) {
|
|
3619
3619
|
try {
|
|
3620
3620
|
const content = JSON.stringify(state, null, 2);
|
|
3621
|
-
await
|
|
3621
|
+
await fs15.writeFile(this.stateFile, content, "utf-8");
|
|
3622
3622
|
} catch (error) {
|
|
3623
3623
|
console.error(`[Lien] Warning: Failed to save git state: ${error}`);
|
|
3624
3624
|
}
|
|
@@ -3769,7 +3769,7 @@ var init_tracker = __esm({
|
|
|
3769
3769
|
});
|
|
3770
3770
|
|
|
3771
3771
|
// src/indexer/change-detector.ts
|
|
3772
|
-
import
|
|
3772
|
+
import fs16 from "fs/promises";
|
|
3773
3773
|
async function detectChanges(rootDir, vectorDB, config) {
|
|
3774
3774
|
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
3775
3775
|
const savedManifest = await manifest.load();
|
|
@@ -3873,7 +3873,7 @@ async function mtimeBasedDetection(rootDir, savedManifest, config) {
|
|
|
3873
3873
|
const fileStats = /* @__PURE__ */ new Map();
|
|
3874
3874
|
for (const filepath of currentFiles) {
|
|
3875
3875
|
try {
|
|
3876
|
-
const stats = await
|
|
3876
|
+
const stats = await fs16.stat(filepath);
|
|
3877
3877
|
fileStats.set(filepath, stats.mtimeMs);
|
|
3878
3878
|
} catch {
|
|
3879
3879
|
continue;
|
|
@@ -3927,7 +3927,7 @@ var init_result = __esm({
|
|
|
3927
3927
|
});
|
|
3928
3928
|
|
|
3929
3929
|
// src/indexer/incremental.ts
|
|
3930
|
-
import
|
|
3930
|
+
import fs17 from "fs/promises";
|
|
3931
3931
|
async function processFileContent(filepath, content, embeddings, config, verbose) {
|
|
3932
3932
|
const chunkSize = isModernConfig(config) ? config.core.chunkSize : isLegacyConfig(config) ? config.indexing.chunkSize : 75;
|
|
3933
3933
|
const chunkOverlap = isModernConfig(config) ? config.core.chunkOverlap : isLegacyConfig(config) ? config.indexing.chunkOverlap : 10;
|
|
@@ -3966,7 +3966,7 @@ async function indexSingleFile(filepath, vectorDB, embeddings, config, options =
|
|
|
3966
3966
|
const { verbose } = options;
|
|
3967
3967
|
try {
|
|
3968
3968
|
try {
|
|
3969
|
-
await
|
|
3969
|
+
await fs17.access(filepath);
|
|
3970
3970
|
} catch {
|
|
3971
3971
|
if (verbose) {
|
|
3972
3972
|
console.error(`[Lien] File deleted: ${filepath}`);
|
|
@@ -3976,9 +3976,9 @@ async function indexSingleFile(filepath, vectorDB, embeddings, config, options =
|
|
|
3976
3976
|
await manifest2.removeFile(filepath);
|
|
3977
3977
|
return;
|
|
3978
3978
|
}
|
|
3979
|
-
const content = await
|
|
3979
|
+
const content = await fs17.readFile(filepath, "utf-8");
|
|
3980
3980
|
const result = await processFileContent(filepath, content, embeddings, config, verbose || false);
|
|
3981
|
-
const stats = await
|
|
3981
|
+
const stats = await fs17.stat(filepath);
|
|
3982
3982
|
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
3983
3983
|
if (result === null) {
|
|
3984
3984
|
await vectorDB.deleteByFile(filepath);
|
|
@@ -4009,8 +4009,8 @@ async function indexSingleFile(filepath, vectorDB, embeddings, config, options =
|
|
|
4009
4009
|
}
|
|
4010
4010
|
async function processSingleFileForIndexing(filepath, embeddings, config, verbose) {
|
|
4011
4011
|
try {
|
|
4012
|
-
const stats = await
|
|
4013
|
-
const content = await
|
|
4012
|
+
const stats = await fs17.stat(filepath);
|
|
4013
|
+
const content = await fs17.readFile(filepath, "utf-8");
|
|
4014
4014
|
const result = await processFileContent(filepath, content, embeddings, config, verbose);
|
|
4015
4015
|
return Ok({
|
|
4016
4016
|
filepath,
|
|
@@ -4281,7 +4281,7 @@ var indexer_exports = {};
|
|
|
4281
4281
|
__export(indexer_exports, {
|
|
4282
4282
|
indexCodebase: () => indexCodebase
|
|
4283
4283
|
});
|
|
4284
|
-
import
|
|
4284
|
+
import fs18 from "fs/promises";
|
|
4285
4285
|
import ora from "ora";
|
|
4286
4286
|
import chalk5 from "chalk";
|
|
4287
4287
|
import pLimit from "p-limit";
|
|
@@ -4454,8 +4454,8 @@ async function performFullIndex(rootDir, vectorDB, config, options, spinner) {
|
|
|
4454
4454
|
const filePromises = files.map(
|
|
4455
4455
|
(file) => limit(async () => {
|
|
4456
4456
|
try {
|
|
4457
|
-
const stats = await
|
|
4458
|
-
const content = await
|
|
4457
|
+
const stats = await fs18.stat(file);
|
|
4458
|
+
const content = await fs18.readFile(file, "utf-8");
|
|
4459
4459
|
const chunkSize = isModernConfig(config) ? config.core.chunkSize : 75;
|
|
4460
4460
|
const chunkOverlap = isModernConfig(config) ? config.core.chunkOverlap : 10;
|
|
4461
4461
|
const useAST = isModernConfig(config) ? config.chunking.useAST : true;
|
|
@@ -4583,8 +4583,8 @@ import { dirname as dirname4, join as join4 } from "path";
|
|
|
4583
4583
|
|
|
4584
4584
|
// src/cli/init.ts
|
|
4585
4585
|
init_schema();
|
|
4586
|
-
import
|
|
4587
|
-
import
|
|
4586
|
+
import fs8 from "fs/promises";
|
|
4587
|
+
import path8 from "path";
|
|
4588
4588
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4589
4589
|
import chalk3 from "chalk";
|
|
4590
4590
|
import inquirer from "inquirer";
|
|
@@ -4751,8 +4751,8 @@ var MigrationManager = class {
|
|
|
4751
4751
|
};
|
|
4752
4752
|
|
|
4753
4753
|
// src/frameworks/detector-service.ts
|
|
4754
|
-
import
|
|
4755
|
-
import
|
|
4754
|
+
import fs7 from "fs/promises";
|
|
4755
|
+
import path7 from "path";
|
|
4756
4756
|
|
|
4757
4757
|
// src/frameworks/types.ts
|
|
4758
4758
|
var defaultDetectionOptions = {
|
|
@@ -4884,10 +4884,132 @@ var nodejsDetector = {
|
|
|
4884
4884
|
}
|
|
4885
4885
|
};
|
|
4886
4886
|
|
|
4887
|
-
// src/frameworks/
|
|
4887
|
+
// src/frameworks/php/detector.ts
|
|
4888
4888
|
import fs4 from "fs/promises";
|
|
4889
4889
|
import path4 from "path";
|
|
4890
4890
|
|
|
4891
|
+
// src/frameworks/php/config.ts
|
|
4892
|
+
async function generatePhpConfig(_rootDir, _relativePath) {
|
|
4893
|
+
return {
|
|
4894
|
+
include: [
|
|
4895
|
+
// PHP source code
|
|
4896
|
+
"src/**/*.php",
|
|
4897
|
+
"lib/**/*.php",
|
|
4898
|
+
"app/**/*.php",
|
|
4899
|
+
"tests/**/*.php",
|
|
4900
|
+
"*.php",
|
|
4901
|
+
// Common PHP project files
|
|
4902
|
+
"config/**/*.php",
|
|
4903
|
+
"public/**/*.php",
|
|
4904
|
+
// Documentation
|
|
4905
|
+
"**/*.md",
|
|
4906
|
+
"**/*.mdx",
|
|
4907
|
+
"docs/**/*.md",
|
|
4908
|
+
"README.md",
|
|
4909
|
+
"CHANGELOG.md"
|
|
4910
|
+
],
|
|
4911
|
+
exclude: [
|
|
4912
|
+
"vendor/**",
|
|
4913
|
+
"node_modules/**",
|
|
4914
|
+
"dist/**",
|
|
4915
|
+
"build/**",
|
|
4916
|
+
"storage/**",
|
|
4917
|
+
"cache/**",
|
|
4918
|
+
// Test artifacts
|
|
4919
|
+
"coverage/**",
|
|
4920
|
+
"test-results/**",
|
|
4921
|
+
".phpunit.cache/**",
|
|
4922
|
+
// Build outputs
|
|
4923
|
+
"__generated__/**"
|
|
4924
|
+
]
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4928
|
+
// src/frameworks/php/detector.ts
|
|
4929
|
+
var phpDetector = {
|
|
4930
|
+
name: "php",
|
|
4931
|
+
priority: 50,
|
|
4932
|
+
// Generic, yields to specific frameworks like Laravel
|
|
4933
|
+
async detect(rootDir, relativePath) {
|
|
4934
|
+
const fullPath = path4.join(rootDir, relativePath);
|
|
4935
|
+
const result = {
|
|
4936
|
+
detected: false,
|
|
4937
|
+
name: "php",
|
|
4938
|
+
path: relativePath,
|
|
4939
|
+
confidence: "low",
|
|
4940
|
+
evidence: []
|
|
4941
|
+
};
|
|
4942
|
+
const composerJsonPath = path4.join(fullPath, "composer.json");
|
|
4943
|
+
let composerJson = null;
|
|
4944
|
+
try {
|
|
4945
|
+
const content = await fs4.readFile(composerJsonPath, "utf-8");
|
|
4946
|
+
composerJson = JSON.parse(content);
|
|
4947
|
+
result.evidence.push("Found composer.json");
|
|
4948
|
+
} catch {
|
|
4949
|
+
return result;
|
|
4950
|
+
}
|
|
4951
|
+
const hasLaravel = composerJson.require?.["laravel/framework"] || composerJson["require-dev"]?.["laravel/framework"];
|
|
4952
|
+
if (hasLaravel) {
|
|
4953
|
+
return result;
|
|
4954
|
+
}
|
|
4955
|
+
result.detected = true;
|
|
4956
|
+
result.confidence = "high";
|
|
4957
|
+
const phpDirs = ["src", "lib", "app", "tests"];
|
|
4958
|
+
let foundDirs = 0;
|
|
4959
|
+
for (const dir of phpDirs) {
|
|
4960
|
+
try {
|
|
4961
|
+
const dirPath = path4.join(fullPath, dir);
|
|
4962
|
+
const stats = await fs4.stat(dirPath);
|
|
4963
|
+
if (stats.isDirectory()) {
|
|
4964
|
+
foundDirs++;
|
|
4965
|
+
}
|
|
4966
|
+
} catch {
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
if (foundDirs > 0) {
|
|
4970
|
+
result.evidence.push(`Found PHP project structure (${foundDirs} directories)`);
|
|
4971
|
+
}
|
|
4972
|
+
if (composerJson.require?.php) {
|
|
4973
|
+
result.version = composerJson.require.php;
|
|
4974
|
+
result.evidence.push(`PHP ${composerJson.require.php}`);
|
|
4975
|
+
}
|
|
4976
|
+
const testFrameworks = [
|
|
4977
|
+
{ name: "phpunit/phpunit", display: "PHPUnit" },
|
|
4978
|
+
{ name: "pestphp/pest", display: "Pest" },
|
|
4979
|
+
{ name: "codeception/codeception", display: "Codeception" },
|
|
4980
|
+
{ name: "behat/behat", display: "Behat" }
|
|
4981
|
+
];
|
|
4982
|
+
for (const framework of testFrameworks) {
|
|
4983
|
+
if (composerJson.require?.[framework.name] || composerJson["require-dev"]?.[framework.name]) {
|
|
4984
|
+
result.evidence.push(`${framework.display} test framework detected`);
|
|
4985
|
+
break;
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4988
|
+
const tools2 = [
|
|
4989
|
+
{ name: "symfony/framework-bundle", display: "Symfony" },
|
|
4990
|
+
{ name: "symfony/http-kernel", display: "Symfony" },
|
|
4991
|
+
{ name: "symfony/symfony", display: "Symfony (monolithic)" },
|
|
4992
|
+
{ name: "doctrine/orm", display: "Doctrine ORM" },
|
|
4993
|
+
{ name: "guzzlehttp/guzzle", display: "Guzzle HTTP" },
|
|
4994
|
+
{ name: "monolog/monolog", display: "Monolog" }
|
|
4995
|
+
];
|
|
4996
|
+
for (const tool of tools2) {
|
|
4997
|
+
if (composerJson.require?.[tool.name]) {
|
|
4998
|
+
result.evidence.push(`${tool.display} detected`);
|
|
4999
|
+
break;
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
return result;
|
|
5003
|
+
},
|
|
5004
|
+
async generateConfig(rootDir, relativePath) {
|
|
5005
|
+
return generatePhpConfig(rootDir, relativePath);
|
|
5006
|
+
}
|
|
5007
|
+
};
|
|
5008
|
+
|
|
5009
|
+
// src/frameworks/laravel/detector.ts
|
|
5010
|
+
import fs5 from "fs/promises";
|
|
5011
|
+
import path5 from "path";
|
|
5012
|
+
|
|
4891
5013
|
// src/frameworks/laravel/config.ts
|
|
4892
5014
|
async function generateLaravelConfig(_rootDir, _relativePath) {
|
|
4893
5015
|
return {
|
|
@@ -4943,7 +5065,7 @@ var laravelDetector = {
|
|
|
4943
5065
|
priority: 100,
|
|
4944
5066
|
// Laravel takes precedence over Node.js
|
|
4945
5067
|
async detect(rootDir, relativePath) {
|
|
4946
|
-
const fullPath =
|
|
5068
|
+
const fullPath = path5.join(rootDir, relativePath);
|
|
4947
5069
|
const result = {
|
|
4948
5070
|
detected: false,
|
|
4949
5071
|
name: "laravel",
|
|
@@ -4951,10 +5073,10 @@ var laravelDetector = {
|
|
|
4951
5073
|
confidence: "low",
|
|
4952
5074
|
evidence: []
|
|
4953
5075
|
};
|
|
4954
|
-
const composerJsonPath =
|
|
5076
|
+
const composerJsonPath = path5.join(fullPath, "composer.json");
|
|
4955
5077
|
let composerJson = null;
|
|
4956
5078
|
try {
|
|
4957
|
-
const content = await
|
|
5079
|
+
const content = await fs5.readFile(composerJsonPath, "utf-8");
|
|
4958
5080
|
composerJson = JSON.parse(content);
|
|
4959
5081
|
result.evidence.push("Found composer.json");
|
|
4960
5082
|
} catch {
|
|
@@ -4965,9 +5087,9 @@ var laravelDetector = {
|
|
|
4965
5087
|
return result;
|
|
4966
5088
|
}
|
|
4967
5089
|
result.evidence.push("Laravel framework detected in composer.json");
|
|
4968
|
-
const artisanPath =
|
|
5090
|
+
const artisanPath = path5.join(fullPath, "artisan");
|
|
4969
5091
|
try {
|
|
4970
|
-
await
|
|
5092
|
+
await fs5.access(artisanPath);
|
|
4971
5093
|
result.evidence.push("Found artisan file");
|
|
4972
5094
|
result.confidence = "high";
|
|
4973
5095
|
} catch {
|
|
@@ -4977,8 +5099,8 @@ var laravelDetector = {
|
|
|
4977
5099
|
let foundDirs = 0;
|
|
4978
5100
|
for (const dir of laravelDirs) {
|
|
4979
5101
|
try {
|
|
4980
|
-
const dirPath =
|
|
4981
|
-
const stats = await
|
|
5102
|
+
const dirPath = path5.join(fullPath, dir);
|
|
5103
|
+
const stats = await fs5.stat(dirPath);
|
|
4982
5104
|
if (stats.isDirectory()) {
|
|
4983
5105
|
foundDirs++;
|
|
4984
5106
|
}
|
|
@@ -4990,14 +5112,14 @@ var laravelDetector = {
|
|
|
4990
5112
|
result.confidence = "high";
|
|
4991
5113
|
}
|
|
4992
5114
|
const testDirsToCheck = [
|
|
4993
|
-
|
|
4994
|
-
|
|
5115
|
+
path5.join(fullPath, "tests", "Feature"),
|
|
5116
|
+
path5.join(fullPath, "tests", "Unit")
|
|
4995
5117
|
];
|
|
4996
5118
|
for (const testDir of testDirsToCheck) {
|
|
4997
5119
|
try {
|
|
4998
|
-
const stats = await
|
|
5120
|
+
const stats = await fs5.stat(testDir);
|
|
4999
5121
|
if (stats.isDirectory()) {
|
|
5000
|
-
const dirName =
|
|
5122
|
+
const dirName = path5.basename(path5.dirname(testDir)) + "/" + path5.basename(testDir);
|
|
5001
5123
|
result.evidence.push(`Found ${dirName} test directory`);
|
|
5002
5124
|
}
|
|
5003
5125
|
} catch {
|
|
@@ -5015,8 +5137,8 @@ var laravelDetector = {
|
|
|
5015
5137
|
};
|
|
5016
5138
|
|
|
5017
5139
|
// src/frameworks/shopify/detector.ts
|
|
5018
|
-
import
|
|
5019
|
-
import
|
|
5140
|
+
import fs6 from "fs/promises";
|
|
5141
|
+
import path6 from "path";
|
|
5020
5142
|
|
|
5021
5143
|
// src/frameworks/shopify/config.ts
|
|
5022
5144
|
async function generateShopifyConfig(_rootDir, _relativePath) {
|
|
@@ -5074,7 +5196,7 @@ var shopifyDetector = {
|
|
|
5074
5196
|
priority: 100,
|
|
5075
5197
|
// High priority (same as Laravel)
|
|
5076
5198
|
async detect(rootDir, relativePath) {
|
|
5077
|
-
const fullPath =
|
|
5199
|
+
const fullPath = path6.join(rootDir, relativePath);
|
|
5078
5200
|
const result = {
|
|
5079
5201
|
detected: false,
|
|
5080
5202
|
name: "shopify",
|
|
@@ -5082,18 +5204,18 @@ var shopifyDetector = {
|
|
|
5082
5204
|
confidence: "low",
|
|
5083
5205
|
evidence: []
|
|
5084
5206
|
};
|
|
5085
|
-
const settingsSchemaPath =
|
|
5207
|
+
const settingsSchemaPath = path6.join(fullPath, "config", "settings_schema.json");
|
|
5086
5208
|
let hasSettingsSchema = false;
|
|
5087
5209
|
try {
|
|
5088
|
-
await
|
|
5210
|
+
await fs6.access(settingsSchemaPath);
|
|
5089
5211
|
hasSettingsSchema = true;
|
|
5090
5212
|
result.evidence.push("Found config/settings_schema.json");
|
|
5091
5213
|
} catch {
|
|
5092
5214
|
}
|
|
5093
|
-
const themeLayoutPath =
|
|
5215
|
+
const themeLayoutPath = path6.join(fullPath, "layout", "theme.liquid");
|
|
5094
5216
|
let hasThemeLayout = false;
|
|
5095
5217
|
try {
|
|
5096
|
-
await
|
|
5218
|
+
await fs6.access(themeLayoutPath);
|
|
5097
5219
|
hasThemeLayout = true;
|
|
5098
5220
|
result.evidence.push("Found layout/theme.liquid");
|
|
5099
5221
|
} catch {
|
|
@@ -5102,8 +5224,8 @@ var shopifyDetector = {
|
|
|
5102
5224
|
let foundDirs = 0;
|
|
5103
5225
|
for (const dir of shopifyDirs) {
|
|
5104
5226
|
try {
|
|
5105
|
-
const dirPath =
|
|
5106
|
-
const stats = await
|
|
5227
|
+
const dirPath = path6.join(fullPath, dir);
|
|
5228
|
+
const stats = await fs6.stat(dirPath);
|
|
5107
5229
|
if (stats.isDirectory()) {
|
|
5108
5230
|
foundDirs++;
|
|
5109
5231
|
}
|
|
@@ -5114,14 +5236,14 @@ var shopifyDetector = {
|
|
|
5114
5236
|
result.evidence.push(`Shopify directory structure detected (${foundDirs}/${shopifyDirs.length} dirs)`);
|
|
5115
5237
|
}
|
|
5116
5238
|
try {
|
|
5117
|
-
const tomlPath =
|
|
5118
|
-
await
|
|
5239
|
+
const tomlPath = path6.join(fullPath, "shopify.theme.toml");
|
|
5240
|
+
await fs6.access(tomlPath);
|
|
5119
5241
|
result.evidence.push("Found shopify.theme.toml");
|
|
5120
5242
|
} catch {
|
|
5121
5243
|
}
|
|
5122
5244
|
try {
|
|
5123
|
-
const ignorePath =
|
|
5124
|
-
await
|
|
5245
|
+
const ignorePath = path6.join(fullPath, ".shopifyignore");
|
|
5246
|
+
await fs6.access(ignorePath);
|
|
5125
5247
|
result.evidence.push("Found .shopifyignore");
|
|
5126
5248
|
} catch {
|
|
5127
5249
|
}
|
|
@@ -5150,6 +5272,7 @@ var shopifyDetector = {
|
|
|
5150
5272
|
// src/frameworks/registry.ts
|
|
5151
5273
|
var frameworkDetectors = [
|
|
5152
5274
|
nodejsDetector,
|
|
5275
|
+
phpDetector,
|
|
5153
5276
|
laravelDetector,
|
|
5154
5277
|
shopifyDetector
|
|
5155
5278
|
];
|
|
@@ -5167,7 +5290,7 @@ async function detectAllFrameworks(rootDir, options = {}) {
|
|
|
5167
5290
|
return results;
|
|
5168
5291
|
}
|
|
5169
5292
|
async function detectAtPath(rootDir, relativePath, results, visited) {
|
|
5170
|
-
const fullPath =
|
|
5293
|
+
const fullPath = path7.join(rootDir, relativePath);
|
|
5171
5294
|
if (visited.has(fullPath)) {
|
|
5172
5295
|
return;
|
|
5173
5296
|
}
|
|
@@ -5234,9 +5357,9 @@ async function scanSubdirectories(rootDir, relativePath, results, visited, depth
|
|
|
5234
5357
|
if (depth >= options.maxDepth) {
|
|
5235
5358
|
return;
|
|
5236
5359
|
}
|
|
5237
|
-
const fullPath =
|
|
5360
|
+
const fullPath = path7.join(rootDir, relativePath);
|
|
5238
5361
|
try {
|
|
5239
|
-
const entries = await
|
|
5362
|
+
const entries = await fs7.readdir(fullPath, { withFileTypes: true });
|
|
5240
5363
|
const dirs = entries.filter((e) => e.isDirectory());
|
|
5241
5364
|
for (const dir of dirs) {
|
|
5242
5365
|
if (options.skipDirs.includes(dir.name)) {
|
|
@@ -5245,7 +5368,7 @@ async function scanSubdirectories(rootDir, relativePath, results, visited, depth
|
|
|
5245
5368
|
if (dir.name.startsWith(".")) {
|
|
5246
5369
|
continue;
|
|
5247
5370
|
}
|
|
5248
|
-
const subPath = relativePath === "." ? dir.name :
|
|
5371
|
+
const subPath = relativePath === "." ? dir.name : path7.join(relativePath, dir.name);
|
|
5249
5372
|
await detectAtPath(rootDir, subPath, results, visited);
|
|
5250
5373
|
await scanSubdirectories(rootDir, subPath, results, visited, depth + 1, options);
|
|
5251
5374
|
}
|
|
@@ -5256,14 +5379,14 @@ async function scanSubdirectories(rootDir, relativePath, results, visited, depth
|
|
|
5256
5379
|
|
|
5257
5380
|
// src/cli/init.ts
|
|
5258
5381
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
5259
|
-
var __dirname3 =
|
|
5382
|
+
var __dirname3 = path8.dirname(__filename3);
|
|
5260
5383
|
async function initCommand(options = {}) {
|
|
5261
5384
|
const rootDir = options.path || process.cwd();
|
|
5262
|
-
const configPath =
|
|
5385
|
+
const configPath = path8.join(rootDir, ".lien.config.json");
|
|
5263
5386
|
try {
|
|
5264
5387
|
let configExists = false;
|
|
5265
5388
|
try {
|
|
5266
|
-
await
|
|
5389
|
+
await fs8.access(configPath);
|
|
5267
5390
|
configExists = true;
|
|
5268
5391
|
} catch {
|
|
5269
5392
|
}
|
|
@@ -5400,22 +5523,22 @@ async function createNewConfig(rootDir, options) {
|
|
|
5400
5523
|
]);
|
|
5401
5524
|
if (installCursorRules) {
|
|
5402
5525
|
try {
|
|
5403
|
-
const cursorRulesDir =
|
|
5404
|
-
await
|
|
5405
|
-
const templatePath =
|
|
5406
|
-
const rulesPath =
|
|
5526
|
+
const cursorRulesDir = path8.join(rootDir, ".cursor");
|
|
5527
|
+
await fs8.mkdir(cursorRulesDir, { recursive: true });
|
|
5528
|
+
const templatePath = path8.join(__dirname3, "../CURSOR_RULES_TEMPLATE.md");
|
|
5529
|
+
const rulesPath = path8.join(cursorRulesDir, "rules");
|
|
5407
5530
|
let targetPath;
|
|
5408
5531
|
let isDirectory = false;
|
|
5409
5532
|
let isFile = false;
|
|
5410
5533
|
try {
|
|
5411
|
-
const stats = await
|
|
5534
|
+
const stats = await fs8.stat(rulesPath);
|
|
5412
5535
|
isDirectory = stats.isDirectory();
|
|
5413
5536
|
isFile = stats.isFile();
|
|
5414
5537
|
} catch {
|
|
5415
5538
|
}
|
|
5416
5539
|
if (isDirectory) {
|
|
5417
|
-
targetPath =
|
|
5418
|
-
await
|
|
5540
|
+
targetPath = path8.join(rulesPath, "lien.mdc");
|
|
5541
|
+
await fs8.copyFile(templatePath, targetPath);
|
|
5419
5542
|
console.log(chalk3.green("\u2713 Installed Cursor rules as .cursor/rules/lien.mdc"));
|
|
5420
5543
|
} else if (isFile) {
|
|
5421
5544
|
const { convertToDir } = await inquirer.prompt([
|
|
@@ -5427,11 +5550,11 @@ async function createNewConfig(rootDir, options) {
|
|
|
5427
5550
|
}
|
|
5428
5551
|
]);
|
|
5429
5552
|
if (convertToDir) {
|
|
5430
|
-
const existingRules = await
|
|
5431
|
-
await
|
|
5432
|
-
await
|
|
5433
|
-
await
|
|
5434
|
-
await
|
|
5553
|
+
const existingRules = await fs8.readFile(rulesPath, "utf-8");
|
|
5554
|
+
await fs8.unlink(rulesPath);
|
|
5555
|
+
await fs8.mkdir(rulesPath);
|
|
5556
|
+
await fs8.writeFile(path8.join(rulesPath, "project.mdc"), existingRules);
|
|
5557
|
+
await fs8.copyFile(templatePath, path8.join(rulesPath, "lien.mdc"));
|
|
5435
5558
|
console.log(chalk3.green("\u2713 Converted .cursor/rules to directory"));
|
|
5436
5559
|
console.log(chalk3.green(" - Your project rules: .cursor/rules/project.mdc"));
|
|
5437
5560
|
console.log(chalk3.green(" - Lien rules: .cursor/rules/lien.mdc"));
|
|
@@ -5439,9 +5562,9 @@ async function createNewConfig(rootDir, options) {
|
|
|
5439
5562
|
console.log(chalk3.dim("Skipped Cursor rules installation (preserving existing file)"));
|
|
5440
5563
|
}
|
|
5441
5564
|
} else {
|
|
5442
|
-
await
|
|
5443
|
-
targetPath =
|
|
5444
|
-
await
|
|
5565
|
+
await fs8.mkdir(rulesPath, { recursive: true });
|
|
5566
|
+
targetPath = path8.join(rulesPath, "lien.mdc");
|
|
5567
|
+
await fs8.copyFile(templatePath, targetPath);
|
|
5445
5568
|
console.log(chalk3.green("\u2713 Installed Cursor rules as .cursor/rules/lien.mdc"));
|
|
5446
5569
|
}
|
|
5447
5570
|
} catch (error) {
|
|
@@ -5455,8 +5578,8 @@ async function createNewConfig(rootDir, options) {
|
|
|
5455
5578
|
...defaultConfig,
|
|
5456
5579
|
frameworks
|
|
5457
5580
|
};
|
|
5458
|
-
const configPath =
|
|
5459
|
-
await
|
|
5581
|
+
const configPath = path8.join(rootDir, ".lien.config.json");
|
|
5582
|
+
await fs8.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
5460
5583
|
console.log(chalk3.green("\n\u2713 Created .lien.config.json"));
|
|
5461
5584
|
console.log(chalk3.green(`\u2713 Configured ${frameworks.length} framework(s)`));
|
|
5462
5585
|
console.log(chalk3.dim("\nNext steps:"));
|
|
@@ -5494,16 +5617,16 @@ init_service();
|
|
|
5494
5617
|
init_utils();
|
|
5495
5618
|
init_version2();
|
|
5496
5619
|
import chalk4 from "chalk";
|
|
5497
|
-
import
|
|
5498
|
-
import
|
|
5620
|
+
import fs12 from "fs/promises";
|
|
5621
|
+
import path12 from "path";
|
|
5499
5622
|
import os from "os";
|
|
5500
5623
|
import crypto from "crypto";
|
|
5501
5624
|
init_schema();
|
|
5502
5625
|
async function statusCommand() {
|
|
5503
5626
|
const rootDir = process.cwd();
|
|
5504
|
-
const projectName =
|
|
5627
|
+
const projectName = path12.basename(rootDir);
|
|
5505
5628
|
const pathHash = crypto.createHash("md5").update(rootDir).digest("hex").substring(0, 8);
|
|
5506
|
-
const indexPath =
|
|
5629
|
+
const indexPath = path12.join(os.homedir(), ".lien", "indices", `${projectName}-${pathHash}`);
|
|
5507
5630
|
showCompactBanner();
|
|
5508
5631
|
console.log(chalk4.bold("Status\n"));
|
|
5509
5632
|
const hasConfig = await configService.exists(rootDir);
|
|
@@ -5513,11 +5636,11 @@ async function statusCommand() {
|
|
|
5513
5636
|
return;
|
|
5514
5637
|
}
|
|
5515
5638
|
try {
|
|
5516
|
-
const stats = await
|
|
5639
|
+
const stats = await fs12.stat(indexPath);
|
|
5517
5640
|
console.log(chalk4.dim("Index location:"), indexPath);
|
|
5518
5641
|
console.log(chalk4.dim("Index status:"), chalk4.green("\u2713 Exists"));
|
|
5519
5642
|
try {
|
|
5520
|
-
const files = await
|
|
5643
|
+
const files = await fs12.readdir(indexPath, { recursive: true });
|
|
5521
5644
|
console.log(chalk4.dim("Index files:"), files.length);
|
|
5522
5645
|
} catch (e) {
|
|
5523
5646
|
}
|
|
@@ -5546,9 +5669,9 @@ async function statusCommand() {
|
|
|
5546
5669
|
const commit = await getCurrentCommit(rootDir);
|
|
5547
5670
|
console.log(chalk4.dim(" Current branch:"), branch);
|
|
5548
5671
|
console.log(chalk4.dim(" Current commit:"), commit.substring(0, 8));
|
|
5549
|
-
const gitStateFile =
|
|
5672
|
+
const gitStateFile = path12.join(indexPath, ".git-state.json");
|
|
5550
5673
|
try {
|
|
5551
|
-
const gitStateContent = await
|
|
5674
|
+
const gitStateContent = await fs12.readFile(gitStateFile, "utf-8");
|
|
5552
5675
|
const gitState = JSON.parse(gitStateContent);
|
|
5553
5676
|
if (gitState.branch !== branch || gitState.commit !== commit) {
|
|
5554
5677
|
console.log(chalk4.yellow(" \u26A0\uFE0F Git state changed - will reindex on next serve"));
|
|
@@ -5614,8 +5737,8 @@ async function indexCommand(options) {
|
|
|
5614
5737
|
|
|
5615
5738
|
// src/cli/serve.ts
|
|
5616
5739
|
import chalk7 from "chalk";
|
|
5617
|
-
import
|
|
5618
|
-
import
|
|
5740
|
+
import fs19 from "fs/promises";
|
|
5741
|
+
import path18 from "path";
|
|
5619
5742
|
|
|
5620
5743
|
// src/mcp/server.ts
|
|
5621
5744
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -5992,8 +6115,8 @@ function wrapToolHandler(schema, handler) {
|
|
|
5992
6115
|
}
|
|
5993
6116
|
|
|
5994
6117
|
// src/mcp/utils/path-matching.ts
|
|
5995
|
-
function normalizePath(
|
|
5996
|
-
let normalized =
|
|
6118
|
+
function normalizePath(path19, workspaceRoot) {
|
|
6119
|
+
let normalized = path19.replace(/['"]/g, "").trim().replace(/\\/g, "/");
|
|
5997
6120
|
normalized = normalized.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
5998
6121
|
if (normalized.startsWith(workspaceRoot + "/")) {
|
|
5999
6122
|
normalized = normalized.substring(workspaceRoot.length + 1);
|
|
@@ -6210,10 +6333,10 @@ async function startMCPServer(options) {
|
|
|
6210
6333
|
log(`WARNING: Scanned ${SCAN_LIMIT} chunks (limit reached). Test associations may be incomplete for large codebases.`);
|
|
6211
6334
|
}
|
|
6212
6335
|
const pathCache = /* @__PURE__ */ new Map();
|
|
6213
|
-
const normalizePathCached = (
|
|
6214
|
-
if (pathCache.has(
|
|
6215
|
-
const normalized = normalizePath(
|
|
6216
|
-
pathCache.set(
|
|
6336
|
+
const normalizePathCached = (path19) => {
|
|
6337
|
+
if (pathCache.has(path19)) return pathCache.get(path19);
|
|
6338
|
+
const normalized = normalizePath(path19, workspaceRoot);
|
|
6339
|
+
pathCache.set(path19, normalized);
|
|
6217
6340
|
return normalized;
|
|
6218
6341
|
};
|
|
6219
6342
|
const testAssociationsMap = filepaths.map((filepath) => {
|
|
@@ -6321,10 +6444,10 @@ async function startMCPServer(options) {
|
|
|
6321
6444
|
log(`Scanning ${allChunks.length} chunks for imports...`);
|
|
6322
6445
|
const workspaceRoot = process.cwd().replace(/\\/g, "/");
|
|
6323
6446
|
const pathCache = /* @__PURE__ */ new Map();
|
|
6324
|
-
const normalizePathCached = (
|
|
6325
|
-
if (pathCache.has(
|
|
6326
|
-
const normalized = normalizePath(
|
|
6327
|
-
pathCache.set(
|
|
6447
|
+
const normalizePathCached = (path19) => {
|
|
6448
|
+
if (pathCache.has(path19)) return pathCache.get(path19);
|
|
6449
|
+
const normalized = normalizePath(path19, workspaceRoot);
|
|
6450
|
+
pathCache.set(path19, normalized);
|
|
6328
6451
|
return normalized;
|
|
6329
6452
|
};
|
|
6330
6453
|
const importIndex = /* @__PURE__ */ new Map();
|
|
@@ -6618,11 +6741,11 @@ async function startMCPServer(options) {
|
|
|
6618
6741
|
|
|
6619
6742
|
// src/cli/serve.ts
|
|
6620
6743
|
async function serveCommand(options) {
|
|
6621
|
-
const rootDir = options.root ?
|
|
6744
|
+
const rootDir = options.root ? path18.resolve(options.root) : process.cwd();
|
|
6622
6745
|
try {
|
|
6623
6746
|
if (options.root) {
|
|
6624
6747
|
try {
|
|
6625
|
-
const stats = await
|
|
6748
|
+
const stats = await fs19.stat(rootDir);
|
|
6626
6749
|
if (!stats.isDirectory()) {
|
|
6627
6750
|
console.error(chalk7.red(`Error: --root path is not a directory: ${rootDir}`));
|
|
6628
6751
|
process.exit(1);
|