@liendev/lien 0.38.0 → 0.38.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/README.md +1 -1
- package/dist/index.js +210 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ Lien tracks code complexity with intuitive outputs:
|
|
|
109
109
|
|
|
110
110
|
TypeScript • JavaScript • Vue • Python • PHP • Liquid • Go • Rust • Java • C/C++ • Ruby • Swift • Kotlin • C# • Scala • Markdown
|
|
111
111
|
|
|
112
|
-
**Ecosystem Presets:** Node.js, Laravel,
|
|
112
|
+
**Ecosystem Presets:** 12 ecosystem presets including Node.js, Python, PHP, Laravel, Ruby, Rails, Rust, JVM, Swift, .NET, Django, and Astro (auto-detected)
|
|
113
113
|
|
|
114
114
|
## Contributing
|
|
115
115
|
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,7 @@ function wrapInBox(text, footer, padding = 1) {
|
|
|
58
58
|
return [top, ...paddedLines, separator, paddedFooter, bottom].join("\n");
|
|
59
59
|
}
|
|
60
60
|
function showBanner() {
|
|
61
|
+
if (!process.stderr.isTTY) return;
|
|
61
62
|
const banner = figlet.textSync("LIEN", {
|
|
62
63
|
font: "ANSI Shadow",
|
|
63
64
|
horizontalLayout: "fitted",
|
|
@@ -69,6 +70,7 @@ function showBanner() {
|
|
|
69
70
|
console.error();
|
|
70
71
|
}
|
|
71
72
|
function showCompactBanner() {
|
|
73
|
+
if (!process.stdout.isTTY) return;
|
|
72
74
|
const banner = figlet.textSync("LIEN", {
|
|
73
75
|
font: "ANSI Shadow",
|
|
74
76
|
horizontalLayout: "fitted",
|
|
@@ -3656,9 +3658,9 @@ var require_dist = __commonJS({
|
|
|
3656
3658
|
});
|
|
3657
3659
|
|
|
3658
3660
|
// src/cli/index.ts
|
|
3659
|
-
import { Command } from "commander";
|
|
3660
|
-
import { createRequire as
|
|
3661
|
-
import { fileURLToPath as
|
|
3661
|
+
import { Command, Option } from "commander";
|
|
3662
|
+
import { createRequire as createRequire4 } from "module";
|
|
3663
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3662
3664
|
import { dirname as dirname3, join as join3 } from "path";
|
|
3663
3665
|
|
|
3664
3666
|
// src/cli/init.ts
|
|
@@ -3715,6 +3717,8 @@ import chalk3 from "chalk";
|
|
|
3715
3717
|
import fs2 from "fs/promises";
|
|
3716
3718
|
import path2 from "path";
|
|
3717
3719
|
import os from "os";
|
|
3720
|
+
import { createRequire as createRequire2 } from "module";
|
|
3721
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3718
3722
|
import {
|
|
3719
3723
|
isGitRepo,
|
|
3720
3724
|
getCurrentBranch,
|
|
@@ -3727,75 +3731,179 @@ import {
|
|
|
3727
3731
|
DEFAULT_CHUNK_OVERLAP,
|
|
3728
3732
|
DEFAULT_GIT_POLL_INTERVAL_MS
|
|
3729
3733
|
} from "@liendev/core";
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
const repoId = extractRepoId(rootDir);
|
|
3733
|
-
const indexPath = path2.join(os.homedir(), ".lien", "indices", repoId);
|
|
3734
|
-
showCompactBanner();
|
|
3735
|
-
console.log(chalk3.bold("Status\n"));
|
|
3736
|
-
console.log(
|
|
3737
|
-
chalk3.dim("Configuration:"),
|
|
3738
|
-
chalk3.green("\u2713 Using defaults (no per-project config needed)")
|
|
3739
|
-
);
|
|
3734
|
+
var VALID_FORMATS = ["text", "json"];
|
|
3735
|
+
async function getFileStats(filePath) {
|
|
3740
3736
|
try {
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
}
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3737
|
+
return await fs2.stat(filePath);
|
|
3738
|
+
} catch {
|
|
3739
|
+
return null;
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
async function getFileCount(dirPath) {
|
|
3743
|
+
try {
|
|
3744
|
+
const files = await fs2.readdir(dirPath, { recursive: true });
|
|
3745
|
+
return files.length;
|
|
3746
|
+
} catch {
|
|
3747
|
+
return null;
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
async function getLastReindex(indexPath) {
|
|
3751
|
+
try {
|
|
3752
|
+
const version = await readVersionFile(indexPath);
|
|
3753
|
+
return version > 0 ? version : null;
|
|
3758
3754
|
} catch {
|
|
3755
|
+
return null;
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
function getPackageVersion() {
|
|
3759
|
+
const __filename4 = fileURLToPath2(import.meta.url);
|
|
3760
|
+
const __dirname4 = path2.dirname(__filename4);
|
|
3761
|
+
const require5 = createRequire2(import.meta.url);
|
|
3762
|
+
try {
|
|
3763
|
+
return require5(path2.join(__dirname4, "../package.json")).version;
|
|
3764
|
+
} catch {
|
|
3765
|
+
return require5(path2.join(__dirname4, "../../package.json")).version;
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
async function getGitState(rootDir) {
|
|
3769
|
+
try {
|
|
3770
|
+
const branch = await getCurrentBranch(rootDir);
|
|
3771
|
+
const commit = await getCurrentCommit(rootDir);
|
|
3772
|
+
return { branch, commit };
|
|
3773
|
+
} catch {
|
|
3774
|
+
return null;
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
async function getStoredGitState(indexPath) {
|
|
3778
|
+
try {
|
|
3779
|
+
const content = await fs2.readFile(path2.join(indexPath, ".git-state.json"), "utf-8");
|
|
3780
|
+
return JSON.parse(content);
|
|
3781
|
+
} catch {
|
|
3782
|
+
return null;
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
async function printIndexStatus(indexPath) {
|
|
3786
|
+
const stats = await getFileStats(indexPath);
|
|
3787
|
+
if (!stats) {
|
|
3759
3788
|
console.log(chalk3.dim("Index status:"), chalk3.yellow("\u2717 Not indexed"));
|
|
3760
3789
|
console.log(
|
|
3761
3790
|
chalk3.yellow("\nRun"),
|
|
3762
3791
|
chalk3.bold("lien index"),
|
|
3763
3792
|
chalk3.yellow("to index your codebase")
|
|
3764
3793
|
);
|
|
3794
|
+
return;
|
|
3765
3795
|
}
|
|
3766
|
-
console.log(chalk3.
|
|
3796
|
+
console.log(chalk3.dim("Index location:"), indexPath);
|
|
3797
|
+
console.log(chalk3.dim("Index status:"), chalk3.green("\u2713 Exists"));
|
|
3798
|
+
const fileCount = await getFileCount(indexPath);
|
|
3799
|
+
if (fileCount !== null) {
|
|
3800
|
+
console.log(chalk3.dim("Index files:"), fileCount);
|
|
3801
|
+
}
|
|
3802
|
+
console.log(chalk3.dim("Last modified:"), stats.mtime.toLocaleString());
|
|
3803
|
+
const reindexTs = await getLastReindex(indexPath);
|
|
3804
|
+
if (reindexTs !== null) {
|
|
3805
|
+
console.log(chalk3.dim("Last reindex:"), new Date(reindexTs).toLocaleString());
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
async function printGitStatus(rootDir, indexPath) {
|
|
3767
3809
|
const isRepo = await isGitRepo(rootDir);
|
|
3768
|
-
if (isRepo) {
|
|
3769
|
-
console.log(chalk3.dim("Git detection:"), chalk3.green("\u2713 Enabled"));
|
|
3770
|
-
console.log(chalk3.dim(" Poll interval:"), `${DEFAULT_GIT_POLL_INTERVAL_MS / 1e3}s`);
|
|
3771
|
-
try {
|
|
3772
|
-
const branch = await getCurrentBranch(rootDir);
|
|
3773
|
-
const commit = await getCurrentCommit(rootDir);
|
|
3774
|
-
console.log(chalk3.dim(" Current branch:"), branch);
|
|
3775
|
-
console.log(chalk3.dim(" Current commit:"), commit.substring(0, 8));
|
|
3776
|
-
const gitStateFile = path2.join(indexPath, ".git-state.json");
|
|
3777
|
-
try {
|
|
3778
|
-
const gitStateContent = await fs2.readFile(gitStateFile, "utf-8");
|
|
3779
|
-
const gitState = JSON.parse(gitStateContent);
|
|
3780
|
-
if (gitState.branch !== branch || gitState.commit !== commit) {
|
|
3781
|
-
console.log(chalk3.yellow(" \u26A0\uFE0F Git state changed - will reindex on next serve"));
|
|
3782
|
-
}
|
|
3783
|
-
} catch {
|
|
3784
|
-
}
|
|
3785
|
-
} catch {
|
|
3786
|
-
}
|
|
3787
|
-
} else {
|
|
3810
|
+
if (!isRepo) {
|
|
3788
3811
|
console.log(chalk3.dim("Git detection:"), chalk3.yellow("Not a git repo"));
|
|
3812
|
+
return;
|
|
3789
3813
|
}
|
|
3814
|
+
console.log(chalk3.dim("Git detection:"), chalk3.green("\u2713 Enabled"));
|
|
3815
|
+
console.log(chalk3.dim(" Poll interval:"), `${DEFAULT_GIT_POLL_INTERVAL_MS / 1e3}s`);
|
|
3816
|
+
const gitState = await getGitState(rootDir);
|
|
3817
|
+
if (!gitState) return;
|
|
3818
|
+
console.log(chalk3.dim(" Current branch:"), gitState.branch);
|
|
3819
|
+
console.log(chalk3.dim(" Current commit:"), gitState.commit.substring(0, 8));
|
|
3820
|
+
const storedGit = await getStoredGitState(indexPath);
|
|
3821
|
+
if (storedGit && (storedGit.branch !== gitState.branch || storedGit.commit !== gitState.commit)) {
|
|
3822
|
+
console.log(chalk3.yellow(" \u26A0\uFE0F Git state changed - will reindex on next serve"));
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
function printWatchStatus() {
|
|
3790
3826
|
console.log(chalk3.dim("File watching:"), chalk3.green("\u2713 Enabled (default)"));
|
|
3791
3827
|
console.log(chalk3.dim(" Batch window:"), "500ms (collects rapid changes, force-flush after 5s)");
|
|
3792
3828
|
console.log(chalk3.dim(" Disable with:"), chalk3.bold("lien serve --no-watch"));
|
|
3829
|
+
}
|
|
3830
|
+
function printIndexingSettings() {
|
|
3793
3831
|
console.log(chalk3.bold("\nIndexing Settings (defaults):"));
|
|
3794
3832
|
console.log(chalk3.dim("Concurrency:"), DEFAULT_CONCURRENCY);
|
|
3795
3833
|
console.log(chalk3.dim("Batch size:"), DEFAULT_EMBEDDING_BATCH_SIZE);
|
|
3796
3834
|
console.log(chalk3.dim("Chunk size:"), DEFAULT_CHUNK_SIZE);
|
|
3797
3835
|
console.log(chalk3.dim("Chunk overlap:"), DEFAULT_CHUNK_OVERLAP);
|
|
3798
3836
|
}
|
|
3837
|
+
async function statusCommand(options = {}) {
|
|
3838
|
+
const format = options.format || "text";
|
|
3839
|
+
if (!VALID_FORMATS.includes(format)) {
|
|
3840
|
+
console.error(
|
|
3841
|
+
chalk3.red(`Error: Invalid --format value "${format}". Must be one of: text, json`)
|
|
3842
|
+
);
|
|
3843
|
+
process.exit(1);
|
|
3844
|
+
}
|
|
3845
|
+
const rootDir = process.cwd();
|
|
3846
|
+
const repoId = extractRepoId(rootDir);
|
|
3847
|
+
const indexPath = path2.join(os.homedir(), ".lien", "indices", repoId);
|
|
3848
|
+
if (format === "json") {
|
|
3849
|
+
await outputJson(rootDir, indexPath);
|
|
3850
|
+
return;
|
|
3851
|
+
}
|
|
3852
|
+
showCompactBanner();
|
|
3853
|
+
console.log(chalk3.bold("Status\n"));
|
|
3854
|
+
console.log(
|
|
3855
|
+
chalk3.dim("Configuration:"),
|
|
3856
|
+
chalk3.green("\u2713 Using defaults (no per-project config needed)")
|
|
3857
|
+
);
|
|
3858
|
+
await printIndexStatus(indexPath);
|
|
3859
|
+
console.log(chalk3.bold("\nFeatures:"));
|
|
3860
|
+
await printGitStatus(rootDir, indexPath);
|
|
3861
|
+
printWatchStatus();
|
|
3862
|
+
if (options.verbose) {
|
|
3863
|
+
printIndexingSettings();
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
async function outputJson(rootDir, indexPath) {
|
|
3867
|
+
const data = {
|
|
3868
|
+
version: getPackageVersion(),
|
|
3869
|
+
indexPath,
|
|
3870
|
+
indexStatus: "not_indexed",
|
|
3871
|
+
indexFiles: 0,
|
|
3872
|
+
lastModified: null,
|
|
3873
|
+
lastReindex: null,
|
|
3874
|
+
git: { enabled: false, branch: null, commit: null },
|
|
3875
|
+
features: { fileWatching: true, gitDetection: true },
|
|
3876
|
+
settings: {
|
|
3877
|
+
concurrency: DEFAULT_CONCURRENCY,
|
|
3878
|
+
batchSize: DEFAULT_EMBEDDING_BATCH_SIZE,
|
|
3879
|
+
chunkSize: DEFAULT_CHUNK_SIZE,
|
|
3880
|
+
chunkOverlap: DEFAULT_CHUNK_OVERLAP
|
|
3881
|
+
}
|
|
3882
|
+
};
|
|
3883
|
+
const stats = await getFileStats(indexPath);
|
|
3884
|
+
if (stats) {
|
|
3885
|
+
data.indexStatus = "exists";
|
|
3886
|
+
data.lastModified = stats.mtime.toISOString();
|
|
3887
|
+
const fileCount = await getFileCount(indexPath);
|
|
3888
|
+
if (fileCount !== null) {
|
|
3889
|
+
data.indexFiles = fileCount;
|
|
3890
|
+
}
|
|
3891
|
+
const reindexTs = await getLastReindex(indexPath);
|
|
3892
|
+
if (reindexTs !== null) {
|
|
3893
|
+
data.lastReindex = new Date(reindexTs).toISOString();
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
const isRepo = await isGitRepo(rootDir);
|
|
3897
|
+
if (isRepo) {
|
|
3898
|
+
const gitState = await getGitState(rootDir);
|
|
3899
|
+
data.git = {
|
|
3900
|
+
enabled: true,
|
|
3901
|
+
branch: gitState?.branch ?? null,
|
|
3902
|
+
commit: gitState ? gitState.commit.substring(0, 8) : null
|
|
3903
|
+
};
|
|
3904
|
+
}
|
|
3905
|
+
console.log(JSON.stringify(data, null, 2));
|
|
3906
|
+
}
|
|
3799
3907
|
|
|
3800
3908
|
// src/cli/index-cmd.ts
|
|
3801
3909
|
init_banner();
|
|
@@ -4027,8 +4135,8 @@ import path7 from "path";
|
|
|
4027
4135
|
// src/mcp/server.ts
|
|
4028
4136
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4029
4137
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4030
|
-
import { createRequire as
|
|
4031
|
-
import { fileURLToPath as
|
|
4138
|
+
import { createRequire as createRequire3 } from "module";
|
|
4139
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4032
4140
|
import { dirname as dirname2, join as join2 } from "path";
|
|
4033
4141
|
import { WorkerEmbeddings, VERSION_CHECK_INTERVAL_MS, createVectorDB } from "@liendev/core";
|
|
4034
4142
|
|
|
@@ -10366,9 +10474,8 @@ import {
|
|
|
10366
10474
|
normalizeToRelativePath as normalizeToRelativePath2,
|
|
10367
10475
|
createGitignoreFilter
|
|
10368
10476
|
} from "@liendev/core";
|
|
10369
|
-
async function handleFileDeletion(filepath, vectorDB, log) {
|
|
10477
|
+
async function handleFileDeletion(filepath, vectorDB, manifest, log) {
|
|
10370
10478
|
log(`\u{1F5D1}\uFE0F File deleted: ${filepath}`);
|
|
10371
|
-
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
10372
10479
|
try {
|
|
10373
10480
|
await vectorDB.deleteByFile(filepath);
|
|
10374
10481
|
await manifest.removeFile(filepath);
|
|
@@ -10378,8 +10485,7 @@ async function handleFileDeletion(filepath, vectorDB, log) {
|
|
|
10378
10485
|
throw error;
|
|
10379
10486
|
}
|
|
10380
10487
|
}
|
|
10381
|
-
async function handleBatchDeletions(deletedFiles, vectorDB, log) {
|
|
10382
|
-
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
10488
|
+
async function handleBatchDeletions(deletedFiles, vectorDB, manifest, log) {
|
|
10383
10489
|
const failures = [];
|
|
10384
10490
|
for (const filepath of deletedFiles) {
|
|
10385
10491
|
log(`\u{1F5D1}\uFE0F File deleted: ${filepath}`);
|
|
@@ -10396,8 +10502,7 @@ async function handleBatchDeletions(deletedFiles, vectorDB, log) {
|
|
|
10396
10502
|
throw new Error(`Failed to delete ${failures.length} file(s): ${failures.join(", ")}`);
|
|
10397
10503
|
}
|
|
10398
10504
|
}
|
|
10399
|
-
async function canSkipReindex(filepath, rootDir,
|
|
10400
|
-
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
10505
|
+
async function canSkipReindex(filepath, rootDir, manifest, log) {
|
|
10401
10506
|
const normalizedPath = normalizeToRelativePath2(filepath, rootDir);
|
|
10402
10507
|
const manifestData = await manifest.load();
|
|
10403
10508
|
const existingEntry = manifestData?.files[normalizedPath];
|
|
@@ -10415,11 +10520,11 @@ async function canSkipReindex(filepath, rootDir, vectorDB, log) {
|
|
|
10415
10520
|
}
|
|
10416
10521
|
return false;
|
|
10417
10522
|
}
|
|
10418
|
-
async function handleSingleFileChange(filepath, type, rootDir, vectorDB, embeddings, log, reindexStateManager) {
|
|
10523
|
+
async function handleSingleFileChange(filepath, type, rootDir, vectorDB, embeddings, manifest, log, reindexStateManager) {
|
|
10419
10524
|
const action = type === "add" ? "added" : "changed";
|
|
10420
10525
|
if (type === "change") {
|
|
10421
10526
|
try {
|
|
10422
|
-
if (await canSkipReindex(filepath, rootDir,
|
|
10527
|
+
if (await canSkipReindex(filepath, rootDir, manifest, log)) return;
|
|
10423
10528
|
} catch (error) {
|
|
10424
10529
|
log(`Content hash check failed, will reindex: ${error}`, "warning");
|
|
10425
10530
|
}
|
|
@@ -10477,9 +10582,8 @@ async function updateUnchangedMtimes(manifest, results) {
|
|
|
10477
10582
|
return null;
|
|
10478
10583
|
});
|
|
10479
10584
|
}
|
|
10480
|
-
async function filterModifiedFilesByHash(modifiedFiles, rootDir,
|
|
10585
|
+
async function filterModifiedFilesByHash(modifiedFiles, rootDir, manifest, log) {
|
|
10481
10586
|
if (modifiedFiles.length === 0) return [];
|
|
10482
|
-
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
10483
10587
|
const manifestData = await manifest.load();
|
|
10484
10588
|
if (!manifestData) return modifiedFiles;
|
|
10485
10589
|
const checkResults = await checkFilesAgainstManifest(
|
|
@@ -10491,13 +10595,13 @@ async function filterModifiedFilesByHash(modifiedFiles, rootDir, vectorDB, log)
|
|
|
10491
10595
|
await updateUnchangedMtimes(manifest, checkResults);
|
|
10492
10596
|
return checkResults.filter((r) => r.shouldReindex).map((r) => r.filepath);
|
|
10493
10597
|
}
|
|
10494
|
-
async function prepareFilesForReindexing(event, rootDir,
|
|
10598
|
+
async function prepareFilesForReindexing(event, rootDir, manifest, log) {
|
|
10495
10599
|
const addedFiles = event.added || [];
|
|
10496
10600
|
const modifiedFiles = event.modified || [];
|
|
10497
10601
|
const deletedFiles = event.deleted || [];
|
|
10498
10602
|
let modifiedFilesToReindex = [];
|
|
10499
10603
|
try {
|
|
10500
|
-
modifiedFilesToReindex = await filterModifiedFilesByHash(modifiedFiles, rootDir,
|
|
10604
|
+
modifiedFilesToReindex = await filterModifiedFilesByHash(modifiedFiles, rootDir, manifest, log);
|
|
10501
10605
|
} catch (error) {
|
|
10502
10606
|
log(`Hash-based filtering failed, will reindex all modified files: ${error}`, "warning");
|
|
10503
10607
|
modifiedFilesToReindex = modifiedFiles;
|
|
@@ -10505,24 +10609,20 @@ async function prepareFilesForReindexing(event, rootDir, vectorDB, log) {
|
|
|
10505
10609
|
const filesToIndex = [...addedFiles, ...modifiedFilesToReindex];
|
|
10506
10610
|
return { filesToIndex, deletedFiles };
|
|
10507
10611
|
}
|
|
10508
|
-
async function executeReindexOperations(filesToIndex, deletedFiles, rootDir, vectorDB, embeddings, log) {
|
|
10509
|
-
const operations = [];
|
|
10612
|
+
async function executeReindexOperations(filesToIndex, deletedFiles, rootDir, vectorDB, embeddings, manifest, log) {
|
|
10510
10613
|
if (filesToIndex.length > 0) {
|
|
10511
10614
|
log(`\u{1F4C1} ${filesToIndex.length} file(s) changed, reindexing...`);
|
|
10512
|
-
|
|
10513
|
-
indexMultipleFiles(filesToIndex, vectorDB, embeddings, { verbose: false, rootDir })
|
|
10514
|
-
);
|
|
10615
|
+
await indexMultipleFiles(filesToIndex, vectorDB, embeddings, { verbose: false, rootDir });
|
|
10515
10616
|
}
|
|
10516
10617
|
if (deletedFiles.length > 0) {
|
|
10517
|
-
|
|
10618
|
+
await handleBatchDeletions(deletedFiles, vectorDB, manifest, log);
|
|
10518
10619
|
}
|
|
10519
|
-
await Promise.all(operations);
|
|
10520
10620
|
}
|
|
10521
|
-
async function handleBatchEvent(event, rootDir, vectorDB, embeddings, log, reindexStateManager) {
|
|
10621
|
+
async function handleBatchEvent(event, rootDir, vectorDB, embeddings, manifest, log, reindexStateManager) {
|
|
10522
10622
|
const { filesToIndex, deletedFiles } = await prepareFilesForReindexing(
|
|
10523
10623
|
event,
|
|
10524
10624
|
rootDir,
|
|
10525
|
-
|
|
10625
|
+
manifest,
|
|
10526
10626
|
log
|
|
10527
10627
|
);
|
|
10528
10628
|
const allFiles = [...filesToIndex, ...deletedFiles];
|
|
@@ -10532,7 +10632,15 @@ async function handleBatchEvent(event, rootDir, vectorDB, embeddings, log, reind
|
|
|
10532
10632
|
const startTime = Date.now();
|
|
10533
10633
|
reindexStateManager.startReindex(allFiles);
|
|
10534
10634
|
try {
|
|
10535
|
-
await executeReindexOperations(
|
|
10635
|
+
await executeReindexOperations(
|
|
10636
|
+
filesToIndex,
|
|
10637
|
+
deletedFiles,
|
|
10638
|
+
rootDir,
|
|
10639
|
+
vectorDB,
|
|
10640
|
+
embeddings,
|
|
10641
|
+
manifest,
|
|
10642
|
+
log
|
|
10643
|
+
);
|
|
10536
10644
|
const duration = Date.now() - startTime;
|
|
10537
10645
|
reindexStateManager.completeReindex(duration);
|
|
10538
10646
|
log(
|
|
@@ -10543,11 +10651,11 @@ async function handleBatchEvent(event, rootDir, vectorDB, embeddings, log, reind
|
|
|
10543
10651
|
log(`Batch reindex failed: ${error}`, "warning");
|
|
10544
10652
|
}
|
|
10545
10653
|
}
|
|
10546
|
-
async function handleUnlinkEvent(filepath, vectorDB, log, reindexStateManager) {
|
|
10654
|
+
async function handleUnlinkEvent(filepath, vectorDB, manifest, log, reindexStateManager) {
|
|
10547
10655
|
const startTime = Date.now();
|
|
10548
10656
|
reindexStateManager.startReindex([filepath]);
|
|
10549
10657
|
try {
|
|
10550
|
-
await handleFileDeletion(filepath, vectorDB, log);
|
|
10658
|
+
await handleFileDeletion(filepath, vectorDB, manifest, log);
|
|
10551
10659
|
const duration = Date.now() - startTime;
|
|
10552
10660
|
reindexStateManager.completeReindex(duration);
|
|
10553
10661
|
} catch (error) {
|
|
@@ -10579,6 +10687,7 @@ function hasGitignoreChange(event) {
|
|
|
10579
10687
|
}
|
|
10580
10688
|
function createFileChangeHandler(rootDir, vectorDB, embeddings, log, reindexStateManager, checkAndReconnect) {
|
|
10581
10689
|
let ignoreFilter = null;
|
|
10690
|
+
const manifest = new ManifestManager(vectorDB.dbPath);
|
|
10582
10691
|
return async (event) => {
|
|
10583
10692
|
if (hasGitignoreChange(event)) {
|
|
10584
10693
|
ignoreFilter = null;
|
|
@@ -10592,10 +10701,18 @@ function createFileChangeHandler(rootDir, vectorDB, embeddings, log, reindexStat
|
|
|
10592
10701
|
const totalToProcess = filtered.added.length + filtered.modified.length + filtered.deleted.length;
|
|
10593
10702
|
if (totalToProcess === 0) return;
|
|
10594
10703
|
await checkAndReconnect();
|
|
10595
|
-
await handleBatchEvent(
|
|
10704
|
+
await handleBatchEvent(
|
|
10705
|
+
filtered,
|
|
10706
|
+
rootDir,
|
|
10707
|
+
vectorDB,
|
|
10708
|
+
embeddings,
|
|
10709
|
+
manifest,
|
|
10710
|
+
log,
|
|
10711
|
+
reindexStateManager
|
|
10712
|
+
);
|
|
10596
10713
|
} else if (type === "unlink") {
|
|
10597
10714
|
await checkAndReconnect();
|
|
10598
|
-
await handleUnlinkEvent(event.filepath, vectorDB, log, reindexStateManager);
|
|
10715
|
+
await handleUnlinkEvent(event.filepath, vectorDB, manifest, log, reindexStateManager);
|
|
10599
10716
|
} else {
|
|
10600
10717
|
if (isFileIgnored(event.filepath, rootDir, ignoreFilter)) return;
|
|
10601
10718
|
await checkAndReconnect();
|
|
@@ -10605,6 +10722,7 @@ function createFileChangeHandler(rootDir, vectorDB, embeddings, log, reindexStat
|
|
|
10605
10722
|
rootDir,
|
|
10606
10723
|
vectorDB,
|
|
10607
10724
|
embeddings,
|
|
10725
|
+
manifest,
|
|
10608
10726
|
log,
|
|
10609
10727
|
reindexStateManager
|
|
10610
10728
|
);
|
|
@@ -10867,9 +10985,9 @@ function setupCleanupHandlers(server, versionCheckInterval, gitPollInterval, fil
|
|
|
10867
10985
|
}
|
|
10868
10986
|
|
|
10869
10987
|
// src/mcp/server.ts
|
|
10870
|
-
var __filename2 =
|
|
10988
|
+
var __filename2 = fileURLToPath3(import.meta.url);
|
|
10871
10989
|
var __dirname2 = dirname2(__filename2);
|
|
10872
|
-
var require3 =
|
|
10990
|
+
var require3 = createRequire3(import.meta.url);
|
|
10873
10991
|
var packageJson2;
|
|
10874
10992
|
try {
|
|
10875
10993
|
packageJson2 = require3(join2(__dirname2, "../package.json"));
|
|
@@ -11133,7 +11251,7 @@ import { VectorDB } from "@liendev/core";
|
|
|
11133
11251
|
import { ComplexityAnalyzer as ComplexityAnalyzer2 } from "@liendev/core";
|
|
11134
11252
|
import { formatReport } from "@liendev/core";
|
|
11135
11253
|
var VALID_FAIL_ON = ["error", "warning"];
|
|
11136
|
-
var
|
|
11254
|
+
var VALID_FORMATS2 = ["text", "json", "sarif"];
|
|
11137
11255
|
function validateFailOn(failOn) {
|
|
11138
11256
|
if (failOn && !VALID_FAIL_ON.includes(failOn)) {
|
|
11139
11257
|
console.error(
|
|
@@ -11143,7 +11261,7 @@ function validateFailOn(failOn) {
|
|
|
11143
11261
|
}
|
|
11144
11262
|
}
|
|
11145
11263
|
function validateFormat(format) {
|
|
11146
|
-
if (!
|
|
11264
|
+
if (!VALID_FORMATS2.includes(format)) {
|
|
11147
11265
|
console.error(
|
|
11148
11266
|
chalk7.red(`Error: Invalid --format value "${format}". Must be one of: text, json, sarif`)
|
|
11149
11267
|
);
|
|
@@ -11289,9 +11407,9 @@ async function configListCommand() {
|
|
|
11289
11407
|
}
|
|
11290
11408
|
|
|
11291
11409
|
// src/cli/index.ts
|
|
11292
|
-
var __filename3 =
|
|
11410
|
+
var __filename3 = fileURLToPath4(import.meta.url);
|
|
11293
11411
|
var __dirname3 = dirname3(__filename3);
|
|
11294
|
-
var require4 =
|
|
11412
|
+
var require4 = createRequire4(import.meta.url);
|
|
11295
11413
|
var packageJson3;
|
|
11296
11414
|
try {
|
|
11297
11415
|
packageJson3 = require4(join3(__dirname3, "../package.json"));
|
|
@@ -11304,13 +11422,18 @@ program.command("init").description("Initialize Lien in the current directory").
|
|
|
11304
11422
|
program.command("index").description("Index the codebase for semantic search").option("-f, --force", "Force full reindex (skip incremental)").option("-v, --verbose", "Show detailed logging during indexing").action(indexCommand);
|
|
11305
11423
|
program.command("serve").description(
|
|
11306
11424
|
"Start the MCP server (works with Cursor, Claude Code, Windsurf, and any MCP client)"
|
|
11307
|
-
).option("-p, --port <port>", "Port number (for future use)", "7133").option("--no-watch", "Disable file watching for this session").
|
|
11308
|
-
|
|
11425
|
+
).option("-p, --port <port>", "Port number (for future use)", "7133").option("--no-watch", "Disable file watching for this session").addOption(
|
|
11426
|
+
new Option("-w, --watch", "[DEPRECATED] File watching is now enabled by default").hideHelp()
|
|
11427
|
+
).option("-r, --root <path>", "Root directory to serve (defaults to current directory)").action(serveCommand);
|
|
11428
|
+
program.command("status").description("Show indexing status and statistics").option("-v, --verbose", "Show detailed settings").option("--format <type>", "Output format: text, json", "text").action(statusCommand);
|
|
11309
11429
|
program.command("complexity").description("Analyze code complexity").option("--files <paths...>", "Specific files to analyze").option("--format <type>", "Output format: text, json, sarif", "text").option("--fail-on <severity>", "Exit 1 if violations: error, warning").action(complexityCommand);
|
|
11310
11430
|
var configCmd = program.command("config").description("Manage global configuration (~/.lien/config.json)");
|
|
11311
11431
|
configCmd.command("set <key> <value>").description("Set a global config value").action(configSetCommand);
|
|
11312
11432
|
configCmd.command("get <key>").description("Get a config value").action(configGetCommand);
|
|
11313
11433
|
configCmd.command("list").description("Show all current config").action(configListCommand);
|
|
11434
|
+
program.action(() => {
|
|
11435
|
+
program.help();
|
|
11436
|
+
});
|
|
11314
11437
|
program.addHelpText("beforeAll", `Quick start: run 'lien serve' in your project directory
|
|
11315
11438
|
`);
|
|
11316
11439
|
|