project-librarian 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +36 -0
- package/README.ko.md +57 -360
- package/README.md +56 -359
- package/dist/args.js +6 -1
- package/dist/code-index/extractors/light-languages.js +285 -0
- package/dist/code-index/extractors/registry.js +12 -0
- package/dist/code-index/extractors/shared.js +18 -1
- package/dist/code-index/extractors/typescript.js +30 -16
- package/dist/code-index/modes.js +136 -32
- package/dist/code-index/native-helper-matrix.js +99 -0
- package/dist/code-index/native-helper.js +292 -0
- package/dist/code-index/ownership.js +8 -6
- package/dist/code-index/schema.js +72 -13
- package/dist/code-index/search.js +1 -1
- package/dist/code-index-db.js +20 -12
- package/dist/code-index-file-policy.js +17 -11
- package/dist/code-index.js +365 -13
- package/dist/hooks.js +5 -5
- package/dist/init-project-wiki.js +7 -1
- package/dist/install-skill.js +99 -6
- package/dist/mcp-server.js +4 -4
- package/dist/migration.js +27 -2
- package/dist/native/darwin-arm64/project-librarian-indexer +0 -0
- package/dist/native/darwin-x64/project-librarian-indexer +0 -0
- package/dist/native/linux-arm64/project-librarian-indexer +0 -0
- package/dist/native/linux-arm64-musl/project-librarian-indexer +0 -0
- package/dist/native/linux-x64/project-librarian-indexer +0 -0
- package/dist/native/linux-x64-musl/project-librarian-indexer +0 -0
- package/dist/native/project-librarian-indexer-manifest.json +70 -0
- package/dist/native/win32-arm64/project-librarian-indexer.exe +0 -0
- package/dist/native/win32-x64/project-librarian-indexer.exe +0 -0
- package/dist/templates.js +4 -3
- package/dist/workspace.js +137 -10
- package/docs/README.md +11 -0
- package/docs/benchmarks.md +64 -0
- package/docs/cli-reference.md +60 -0
- package/docs/code-evidence.md +87 -0
- package/docs/ko/README.md +13 -0
- package/docs/ko/benchmarks.md +64 -0
- package/docs/ko/cli-reference.md +60 -0
- package/docs/ko/code-evidence.md +87 -0
- package/docs/ko/maintainer.md +76 -0
- package/docs/ko/usage.md +167 -0
- package/docs/maintainer.md +76 -0
- package/docs/usage.md +175 -0
- package/package.json +13 -2
|
@@ -52,8 +52,10 @@ function pathOwnerKey(filePath) {
|
|
|
52
52
|
return parts[0] ?? ".";
|
|
53
53
|
}
|
|
54
54
|
function readJsonObject(relativePath) {
|
|
55
|
+
if (!(0, workspace_1.containedProjectFileStat)(relativePath))
|
|
56
|
+
return null;
|
|
55
57
|
try {
|
|
56
|
-
const parsed = JSON.parse(
|
|
58
|
+
const parsed = JSON.parse((0, workspace_1.read)(relativePath));
|
|
57
59
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
58
60
|
}
|
|
59
61
|
catch {
|
|
@@ -83,19 +85,19 @@ function workspacePatternCandidates(pattern) {
|
|
|
83
85
|
const suffix = normalized.slice(starIndex + 1).replace(/^\/+/, "");
|
|
84
86
|
const base = prefix || ".";
|
|
85
87
|
const basePath = (0, workspace_1.abs)(base);
|
|
86
|
-
if (!
|
|
88
|
+
if (!(0, workspace_1.containedProjectDirectoryStat)(base))
|
|
87
89
|
return [];
|
|
88
90
|
return fs.readdirSync(basePath, { withFileTypes: true })
|
|
89
91
|
.filter((entry) => entry.isDirectory())
|
|
90
92
|
.map((entry) => (0, workspace_1.normalizePath)(path.join(base, entry.name, suffix)))
|
|
91
|
-
.filter((candidate) =>
|
|
93
|
+
.filter((candidate) => (0, workspace_1.containedProjectDirectoryStat)(candidate));
|
|
92
94
|
}
|
|
93
95
|
function workspacePackages() {
|
|
94
96
|
const packages = new Map();
|
|
95
97
|
for (const pattern of workspacePatternsFromRootPackage()) {
|
|
96
98
|
for (const candidate of workspacePatternCandidates(pattern)) {
|
|
97
99
|
const packageJsonPath = (0, workspace_1.normalizePath)(path.join(candidate, "package.json"));
|
|
98
|
-
if (!
|
|
100
|
+
if (!(0, workspace_1.containedProjectFileStat)(packageJsonPath))
|
|
99
101
|
continue;
|
|
100
102
|
const packageJson = readJsonObject(packageJsonPath);
|
|
101
103
|
const packageName = typeof packageJson?.name === "string" ? packageJson.name : candidate;
|
|
@@ -119,9 +121,9 @@ function codeownerRules() {
|
|
|
119
121
|
const files = [".github/CODEOWNERS", "CODEOWNERS", "docs/CODEOWNERS"];
|
|
120
122
|
const rules = [];
|
|
121
123
|
for (const filePath of files) {
|
|
122
|
-
if (!
|
|
124
|
+
if (!(0, workspace_1.containedProjectFileStat)(filePath))
|
|
123
125
|
continue;
|
|
124
|
-
const lines =
|
|
126
|
+
const lines = (0, workspace_1.read)(filePath).split(/\r?\n/);
|
|
125
127
|
lines.forEach((lineText, index) => {
|
|
126
128
|
const trimmed = lineText.trim();
|
|
127
129
|
if (!trimmed || trimmed.startsWith("#"))
|
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.codeIndexSchemaVersion = void 0;
|
|
37
|
+
exports.fileFtsRowid = fileFtsRowid;
|
|
38
|
+
exports.createSecondaryIndexes = createSecondaryIndexes;
|
|
4
39
|
exports.setupDatabase = setupDatabase;
|
|
5
40
|
exports.createIndexStatements = createIndexStatements;
|
|
6
41
|
exports.removeIndexedFile = removeIndexedFile;
|
|
@@ -10,14 +45,44 @@ exports.indexedScopes = indexedScopes;
|
|
|
10
45
|
exports.indexedParserMode = indexedParserMode;
|
|
11
46
|
exports.incrementalCompatibility = incrementalCompatibility;
|
|
12
47
|
exports.codeIndexSnapshot = codeIndexSnapshot;
|
|
48
|
+
const crypto = __importStar(require("node:crypto"));
|
|
13
49
|
const workspace_1 = require("../workspace");
|
|
14
|
-
exports.codeIndexSchemaVersion = "
|
|
15
|
-
function
|
|
50
|
+
exports.codeIndexSchemaVersion = "5";
|
|
51
|
+
function stableFtsRowid(parts) {
|
|
52
|
+
const hash = crypto.createHash("sha256");
|
|
53
|
+
for (const part of parts) {
|
|
54
|
+
hash.update(part);
|
|
55
|
+
hash.update("\0");
|
|
56
|
+
}
|
|
57
|
+
const digest = hash.digest();
|
|
58
|
+
let value = 0;
|
|
59
|
+
for (let index = 0; index < 6; index += 1)
|
|
60
|
+
value = value * 256 + digest[index];
|
|
61
|
+
return value + 1;
|
|
62
|
+
}
|
|
63
|
+
function fileFtsRowid(filePath) {
|
|
64
|
+
return stableFtsRowid(["file", filePath]);
|
|
65
|
+
}
|
|
66
|
+
const secondaryIndexSql = `
|
|
67
|
+
CREATE INDEX idx_symbols_file ON symbols(file_path);
|
|
68
|
+
CREATE INDEX idx_symbols_name ON symbols(name);
|
|
69
|
+
CREATE INDEX idx_imports_from ON imports(from_file);
|
|
70
|
+
CREATE INDEX idx_routes_path ON routes(route);
|
|
71
|
+
CREATE INDEX idx_configs_file ON configs(file_path);
|
|
72
|
+
CREATE INDEX idx_edges_source ON edges(source_kind, source);
|
|
73
|
+
CREATE INDEX idx_edges_target ON edges(target_kind, target);
|
|
74
|
+
CREATE INDEX idx_edges_kind ON edges(kind);
|
|
75
|
+
`;
|
|
76
|
+
function createSecondaryIndexes(database) {
|
|
77
|
+
database.exec(secondaryIndexSql);
|
|
78
|
+
}
|
|
79
|
+
function setupDatabase(database, options = {}) {
|
|
16
80
|
database.exec(`
|
|
17
81
|
PRAGMA journal_mode = WAL;
|
|
18
82
|
CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
19
83
|
CREATE TABLE files (
|
|
20
84
|
path TEXT PRIMARY KEY,
|
|
85
|
+
fts_rowid INTEGER NOT NULL UNIQUE,
|
|
21
86
|
language TEXT NOT NULL,
|
|
22
87
|
profile TEXT NOT NULL,
|
|
23
88
|
kind TEXT NOT NULL,
|
|
@@ -71,30 +136,24 @@ function setupDatabase(database) {
|
|
|
71
136
|
);
|
|
72
137
|
CREATE VIRTUAL TABLE files_fts USING fts5(path, language, profile, content);
|
|
73
138
|
CREATE VIRTUAL TABLE symbols_fts USING fts5(name, kind, file_path, signature);
|
|
74
|
-
CREATE INDEX idx_symbols_file ON symbols(file_path);
|
|
75
|
-
CREATE INDEX idx_symbols_name ON symbols(name);
|
|
76
|
-
CREATE INDEX idx_imports_from ON imports(from_file);
|
|
77
|
-
CREATE INDEX idx_routes_path ON routes(route);
|
|
78
|
-
CREATE INDEX idx_configs_file ON configs(file_path);
|
|
79
|
-
CREATE INDEX idx_edges_source ON edges(source_kind, source);
|
|
80
|
-
CREATE INDEX idx_edges_target ON edges(target_kind, target);
|
|
81
|
-
CREATE INDEX idx_edges_kind ON edges(kind);
|
|
82
139
|
`);
|
|
140
|
+
if (options.secondaryIndexes ?? true)
|
|
141
|
+
createSecondaryIndexes(database);
|
|
83
142
|
}
|
|
84
143
|
function createIndexStatements(database) {
|
|
85
144
|
return {
|
|
86
145
|
deleteConfig: database.prepare("DELETE FROM configs WHERE file_path = ?"),
|
|
87
146
|
deleteEdge: database.prepare("DELETE FROM edges WHERE file_path = ?"),
|
|
88
147
|
deleteFile: database.prepare("DELETE FROM files WHERE path = ?"),
|
|
89
|
-
deleteFileFts: database.prepare("DELETE FROM files_fts WHERE path = ?"),
|
|
148
|
+
deleteFileFts: database.prepare("DELETE FROM files_fts WHERE rowid = (SELECT fts_rowid FROM files WHERE path = ?)"),
|
|
90
149
|
deleteImport: database.prepare("DELETE FROM imports WHERE from_file = ?"),
|
|
91
150
|
deleteRoute: database.prepare("DELETE FROM routes WHERE file_path = ?"),
|
|
92
151
|
deleteSymbol: database.prepare("DELETE FROM symbols WHERE file_path = ?"),
|
|
93
152
|
deleteSymbolFts: database.prepare("DELETE FROM symbols_fts WHERE file_path = ?"),
|
|
94
153
|
insertConfig: database.prepare("INSERT INTO configs (key, value, file_path, line) VALUES (?, ?, ?, ?)"),
|
|
95
154
|
insertEdge: database.prepare("INSERT INTO edges (kind, source_kind, source, target_kind, target, file_path, line, evidence) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"),
|
|
96
|
-
insertFile: database.prepare("INSERT INTO files (path, language, profile, kind, bytes, lines, hash, mtime_ms, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
|
|
97
|
-
insertFileFts: database.prepare("INSERT INTO files_fts (path, language, profile, content) VALUES (?, ?, ?, ?)"),
|
|
155
|
+
insertFile: database.prepare("INSERT INTO files (path, fts_rowid, language, profile, kind, bytes, lines, hash, mtime_ms, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
|
|
156
|
+
insertFileFts: database.prepare("INSERT INTO files_fts (rowid, path, language, profile, content) VALUES (?, ?, ?, ?, ?)"),
|
|
98
157
|
insertImport: database.prepare("INSERT INTO imports (from_file, to_ref, imported, line, raw) VALUES (?, ?, ?, ?, ?)"),
|
|
99
158
|
insertMeta: database.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)"),
|
|
100
159
|
insertRoute: database.prepare("INSERT INTO routes (method, route, file_path, line, handler) VALUES (?, ?, ?, ?, ?)"),
|
|
@@ -82,7 +82,7 @@ function searchFiles(database, term, limit = 25) {
|
|
|
82
82
|
const ftsRows = database.prepare(`
|
|
83
83
|
SELECT files.path, files.language, files.profile, files.lines, files.bytes
|
|
84
84
|
FROM files_fts
|
|
85
|
-
JOIN files ON files.
|
|
85
|
+
JOIN files ON files.fts_rowid = files_fts.rowid
|
|
86
86
|
WHERE files_fts MATCH ?
|
|
87
87
|
ORDER BY bm25(files_fts, 8.0, 1.0, 1.0, 0.25), files.path
|
|
88
88
|
LIMIT ?
|
package/dist/code-index-db.js
CHANGED
|
@@ -4,17 +4,27 @@ exports.codeEvidenceNodeRuntimeRequirement = void 0;
|
|
|
4
4
|
exports.loadDatabaseSync = loadDatabaseSync;
|
|
5
5
|
exports.openDatabase = openDatabase;
|
|
6
6
|
exports.codeEvidenceNodeRuntimeRequirement = "Node.js 22.13+ or 24+; node:sqlite was added in Node.js 22.5.0 and became available without --experimental-sqlite in Node.js 22.13.0";
|
|
7
|
+
function warningType(option) {
|
|
8
|
+
if (typeof option === "string")
|
|
9
|
+
return option;
|
|
10
|
+
if (typeof option !== "object" || option === null || !("type" in option))
|
|
11
|
+
return "";
|
|
12
|
+
const value = option.type;
|
|
13
|
+
return typeof value === "string" ? value : "";
|
|
14
|
+
}
|
|
15
|
+
function isSqliteExperimentalWarning(warning, options) {
|
|
16
|
+
const message = warning instanceof Error ? warning.message : typeof warning === "string" ? warning : "";
|
|
17
|
+
const type = warning instanceof Error ? warning.name : warningType(options[0]);
|
|
18
|
+
return type === "ExperimentalWarning" && message.includes("SQLite");
|
|
19
|
+
}
|
|
7
20
|
function loadDatabaseSync(fail) {
|
|
8
|
-
const
|
|
9
|
-
const suppressExperimentalSqliteWarning = (warning) => {
|
|
10
|
-
if (warning.name !== "ExperimentalWarning" || !warning.message.includes("SQLite")) {
|
|
11
|
-
for (const listener of previousListeners)
|
|
12
|
-
listener.call(process, warning);
|
|
13
|
-
}
|
|
14
|
-
};
|
|
21
|
+
const previousEmitWarning = process.emitWarning;
|
|
15
22
|
try {
|
|
16
|
-
process.
|
|
17
|
-
|
|
23
|
+
process.emitWarning = ((warning, ...options) => {
|
|
24
|
+
if (isSqliteExperimentalWarning(warning, options))
|
|
25
|
+
return;
|
|
26
|
+
previousEmitWarning.call(process, warning, ...options);
|
|
27
|
+
});
|
|
18
28
|
const sqlite = require("node:sqlite");
|
|
19
29
|
return sqlite.DatabaseSync;
|
|
20
30
|
}
|
|
@@ -23,9 +33,7 @@ function loadDatabaseSync(fail) {
|
|
|
23
33
|
return fail(`code evidence index requires Node.js 22.13+ because it uses node:sqlite without experimental flags; current Node is ${process.version}. Runtime policy: ${exports.codeEvidenceNodeRuntimeRequirement}. Error: ${message}`);
|
|
24
34
|
}
|
|
25
35
|
finally {
|
|
26
|
-
process.
|
|
27
|
-
for (const listener of previousListeners)
|
|
28
|
-
process.on("warning", listener);
|
|
36
|
+
process.emitWarning = previousEmitWarning;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
function openDatabase(databasePath, fail) {
|
|
@@ -38,6 +38,7 @@ exports.fileLanguage = fileLanguage;
|
|
|
38
38
|
exports.isJavaScriptLike = isJavaScriptLike;
|
|
39
39
|
exports.shouldIndexFile = shouldIndexFile;
|
|
40
40
|
exports.isIgnoredCodePath = isIgnoredCodePath;
|
|
41
|
+
exports.cachedDiscoveredCodeFileStat = cachedDiscoveredCodeFileStat;
|
|
41
42
|
exports.discoverCodeFiles = discoverCodeFiles;
|
|
42
43
|
exports.smallRepoCodeIndexGate = smallRepoCodeIndexGate;
|
|
43
44
|
const childProcess = __importStar(require("node:child_process"));
|
|
@@ -76,6 +77,7 @@ const languageByExtension = {
|
|
|
76
77
|
};
|
|
77
78
|
const configExtensions = new Set([".json", ".yaml", ".yml", ".toml"]);
|
|
78
79
|
exports.maxIndexedBytes = 1024 * 1024;
|
|
80
|
+
const discoveredCodeFileStats = new Map();
|
|
79
81
|
function fileLanguage(relativePath) {
|
|
80
82
|
if (path.basename(relativePath) === ".env.example")
|
|
81
83
|
return "config";
|
|
@@ -92,6 +94,8 @@ function isBlockedSensitiveConfigFile(relativePath) {
|
|
|
92
94
|
const base = path.basename(relativePath).toLowerCase();
|
|
93
95
|
if (base === ".env.example")
|
|
94
96
|
return false;
|
|
97
|
+
if (base.startsWith("."))
|
|
98
|
+
return true;
|
|
95
99
|
return /(^|[._-])(secret|secrets|credential|credentials|token|tokens|private|key|keys)([._-]|$)/i.test(base);
|
|
96
100
|
}
|
|
97
101
|
function isJavaScriptLike(relativePath) {
|
|
@@ -130,7 +134,9 @@ function walkCodeFiles(relativePath, files = []) {
|
|
|
130
134
|
const target = (0, workspace_1.abs)(relativePath);
|
|
131
135
|
if (!fs.existsSync(target))
|
|
132
136
|
return files;
|
|
133
|
-
const stat = fs.
|
|
137
|
+
const stat = fs.lstatSync(target);
|
|
138
|
+
if (stat.isSymbolicLink())
|
|
139
|
+
return files.sort();
|
|
134
140
|
if (stat.isFile()) {
|
|
135
141
|
if (stat.size <= exports.maxIndexedBytes && shouldIndexFile(relativePath))
|
|
136
142
|
files.push(relativePath);
|
|
@@ -143,8 +149,8 @@ function walkCodeFiles(relativePath, files = []) {
|
|
|
143
149
|
walkCodeFiles(child, files);
|
|
144
150
|
}
|
|
145
151
|
else if (entry.isFile() && shouldIndexFile(child)) {
|
|
146
|
-
const childStat =
|
|
147
|
-
if (childStat.size <= exports.maxIndexedBytes)
|
|
152
|
+
const childStat = (0, workspace_1.containedProjectFileStat)(child);
|
|
153
|
+
if (childStat && childStat.size <= exports.maxIndexedBytes)
|
|
148
154
|
files.push(child);
|
|
149
155
|
}
|
|
150
156
|
}
|
|
@@ -164,15 +170,13 @@ function gitTrackedAndUnignoredFiles(scopes) {
|
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
172
|
function indexableFileStat(file) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
catch {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
173
|
+
return (0, workspace_1.containedProjectFileStat)(file);
|
|
174
|
+
}
|
|
175
|
+
function cachedDiscoveredCodeFileStat(relativePath) {
|
|
176
|
+
return discoveredCodeFileStats.get(relativePath);
|
|
174
177
|
}
|
|
175
178
|
function discoverCodeFiles(scopes) {
|
|
179
|
+
discoveredCodeFileStats.clear();
|
|
176
180
|
const gitFiles = gitTrackedAndUnignoredFiles(scopes);
|
|
177
181
|
const candidates = gitFiles ?? scopes.flatMap((scope) => walkCodeFiles(scope));
|
|
178
182
|
const files = [];
|
|
@@ -180,8 +184,10 @@ function discoverCodeFiles(scopes) {
|
|
|
180
184
|
if (isIgnoredCodePath(file) || !shouldIndexFile(file))
|
|
181
185
|
continue;
|
|
182
186
|
const stat = indexableFileStat(file);
|
|
183
|
-
if (stat && stat.size <= exports.maxIndexedBytes)
|
|
187
|
+
if (stat && stat.size <= exports.maxIndexedBytes) {
|
|
188
|
+
discoveredCodeFileStats.set(file, { absolutePath: (0, workspace_1.abs)(file), stat });
|
|
184
189
|
files.push(file);
|
|
190
|
+
}
|
|
185
191
|
}
|
|
186
192
|
return files.sort();
|
|
187
193
|
}
|