project-librarian 0.5.5 → 0.5.7

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.
Files changed (41) hide show
  1. package/CONTRIBUTING.md +36 -0
  2. package/README.ko.md +58 -365
  3. package/README.md +56 -363
  4. package/SKILL.md +7 -0
  5. package/dist/args.js +9 -1
  6. package/dist/code-index/extractors/light-languages.js +285 -0
  7. package/dist/code-index/extractors/registry.js +12 -0
  8. package/dist/code-index/extractors/shared.js +18 -1
  9. package/dist/code-index/extractors/typescript.js +30 -16
  10. package/dist/code-index/index-health.js +4 -3
  11. package/dist/code-index/modes.js +193 -33
  12. package/dist/code-index/native-helper-matrix.js +99 -0
  13. package/dist/code-index/native-helper.js +292 -0
  14. package/dist/code-index/schema.js +72 -13
  15. package/dist/code-index/search.js +1 -1
  16. package/dist/code-index-file-policy.js +9 -1
  17. package/dist/code-index.js +363 -12
  18. package/dist/init-project-wiki.js +14 -0
  19. package/dist/install-skill.js +22 -2
  20. package/dist/native/darwin-arm64/project-librarian-indexer +0 -0
  21. package/dist/native/darwin-x64/project-librarian-indexer +0 -0
  22. package/dist/native/linux-arm64/project-librarian-indexer +0 -0
  23. package/dist/native/linux-arm64-musl/project-librarian-indexer +0 -0
  24. package/dist/native/linux-x64/project-librarian-indexer +0 -0
  25. package/dist/native/linux-x64-musl/project-librarian-indexer +0 -0
  26. package/dist/native/project-librarian-indexer-manifest.json +70 -0
  27. package/dist/native/win32-arm64/project-librarian-indexer.exe +0 -0
  28. package/dist/native/win32-x64/project-librarian-indexer.exe +0 -0
  29. package/docs/README.md +11 -0
  30. package/docs/benchmarks.md +64 -0
  31. package/docs/cli-reference.md +61 -0
  32. package/docs/code-evidence.md +93 -0
  33. package/docs/ko/README.md +13 -0
  34. package/docs/ko/benchmarks.md +64 -0
  35. package/docs/ko/cli-reference.md +61 -0
  36. package/docs/ko/code-evidence.md +93 -0
  37. package/docs/ko/maintainer.md +76 -0
  38. package/docs/ko/usage.md +168 -0
  39. package/docs/maintainer.md +76 -0
  40. package/docs/usage.md +176 -0
  41. package/package.json +11 -1
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveCodeIndexEngine = resolveCodeIndexEngine;
36
37
  exports.runCodeIndexMode = runCodeIndexMode;
37
38
  exports.runCodeQueryMode = runCodeQueryMode;
38
39
  exports.runCodeReportMode = runCodeReportMode;
@@ -70,45 +71,162 @@ function requireCompatibleDatabase(database, runtime) {
70
71
  ].join("\n"));
71
72
  }
72
73
  }
74
+ function schemaMigrationRequired(reason) {
75
+ return reason.startsWith("existing schema version ") && !reason.includes("(missing)");
76
+ }
77
+ function shellQuote(value) {
78
+ if (/^[A-Za-z0-9_./:=@+-]+$/.test(value))
79
+ return value;
80
+ return `'${value.replace(/'/g, "'\\''")}'`;
81
+ }
82
+ function schemaMigrationApprovalCommand(options) {
83
+ const parts = ["project-librarian", "--code-index", "--code-index-migrate"];
84
+ for (const scope of options.scopes) {
85
+ if (scope !== ".")
86
+ parts.push("--code-scope", scope);
87
+ }
88
+ if (args_1.codeIndexOutput !== ".project-wiki/code-evidence.sqlite")
89
+ parts.push("--code-index-out", args_1.codeIndexOutput);
90
+ if (args_1.acknowledgeSmallRepoMode)
91
+ parts.push("--acknowledge-small-repo");
92
+ if (options.requestedEngine !== "auto")
93
+ parts.push("--code-index-engine", options.requestedEngine);
94
+ if (options.parserMode !== "default")
95
+ parts.push("--code-parser", options.parserMode);
96
+ return parts.map(shellQuote).join(" ");
97
+ }
98
+ function schemaMigrationRequiredMessage(runtime, reason, options) {
99
+ const databasePath = runtime.codeEvidenceDatabasePath();
100
+ return [
101
+ `code evidence index schema migration required: ${reason}`,
102
+ "The existing disposable code evidence index must be replaced before this version can write it.",
103
+ `approve: ${schemaMigrationApprovalCommand(options)}`,
104
+ "inspect: project-librarian --code-index-health",
105
+ `database: ${databasePath.relativePath}`,
106
+ ].join("\n");
107
+ }
108
+ function unreadableIndexMessage(runtime) {
109
+ const health = runtime.codeIndexHealth();
110
+ return [
111
+ health.message,
112
+ "inspect: project-librarian --code-index-health",
113
+ `rebuild: ${health.recommended_rebuild_command}`,
114
+ `database: ${health.database_path}`,
115
+ ].join("\n");
116
+ }
117
+ function elapsedMs(started) {
118
+ return Number(process.hrtime.bigint() - started) / 1_000_000;
119
+ }
120
+ function measurePhase(timings, key, fn) {
121
+ const started = process.hrtime.bigint();
122
+ try {
123
+ return fn();
124
+ }
125
+ finally {
126
+ timings[key] = Number(((timings[key] ?? 0) + elapsedMs(started)).toFixed(3));
127
+ }
128
+ }
129
+ function emitCodeIndexPhaseTimings(timings) {
130
+ if (process.env.PROJECT_LIBRARIAN_CODE_INDEX_TIMINGS !== "1")
131
+ return;
132
+ console.error(`code_index_phase_timings ${JSON.stringify(timings)}`);
133
+ }
134
+ function configureBulkWriteConnection(database) {
135
+ database.exec(`
136
+ PRAGMA synchronous = OFF;
137
+ PRAGMA temp_store = MEMORY;
138
+ PRAGMA cache_size = -20000;
139
+ `);
140
+ }
141
+ function shouldUseNativeIncrementalForAuto(requestedEngine, runtime, staleFileCount) {
142
+ if (requestedEngine !== "auto" || !args_1.codeIndexIncrementalMode)
143
+ return false;
144
+ if (staleFileCount <= 0 || !runtime.nativeCodeIndexAvailable())
145
+ return false;
146
+ return true;
147
+ }
148
+ function resolveCodeIndexEngine(requestedEngine, context, shouldUseNativeAuto, incrementalMode = args_1.codeIndexIncrementalMode) {
149
+ if (requestedEngine !== "auto")
150
+ return requestedEngine;
151
+ if (incrementalMode)
152
+ return "typescript";
153
+ return shouldUseNativeAuto(context) ? "native-rust" : "typescript";
154
+ }
73
155
  function runCodeIndexMode(runtime) {
156
+ const totalStarted = process.hrtime.bigint();
157
+ const phaseTimings = {};
74
158
  const databasePath = runtime.codeEvidenceDatabasePath();
75
159
  const scopes = runtime.codeScopes();
76
160
  const parserMode = runtime.selectedCodeParserMode();
161
+ const requestedEngine = runtime.selectedCodeIndexEngine();
77
162
  // Scale gate before ANY write or database work: below the measured threshold
78
163
  // the build halts with the evidence-citing warning unless --acknowledge-small-repo
79
164
  // was passed (2026-06-12 scale-aware guidance decision).
80
- const discoveredFiles = (0, code_index_file_policy_1.discoverCodeFiles)(scopes);
165
+ const discoveredFiles = measurePhase(phaseTimings, "discover_files_ms", () => (0, code_index_file_policy_1.discoverCodeFiles)(scopes));
81
166
  const scaleGate = (0, code_index_file_policy_1.smallRepoCodeIndexGate)(discoveredFiles.length, args_1.acknowledgeSmallRepoMode);
82
167
  if (!scaleGate.proceed)
83
168
  runtime.fail(scaleGate.warning);
169
+ const engineSelectionContext = runtime.codeIndexEngineSelectionContext(discoveredFiles, parserMode);
170
+ const engine = resolveCodeIndexEngine(requestedEngine, engineSelectionContext, runtime.shouldUseNativeCodeIndexAuto);
84
171
  const existingIndex = fs.existsSync(databasePath.absolutePath);
85
172
  if (args_1.codeIndexIncrementalMode && !existingIndex) {
86
173
  runtime.fail(`--incremental requires an existing compatible code evidence index: ${databasePath.relativePath}`);
87
174
  }
88
- let incremental = false;
89
- if (existingIndex && !args_1.codeIndexFullMode) {
90
- let compatibility = { compatible: false, reason: "compatibility was not checked" };
91
- const existingDatabase = runtime.openDatabase(databasePath.absolutePath);
175
+ let compatibility = { compatible: false, reason: "compatibility was not checked" };
176
+ let checkedCompatibility = false;
177
+ if (existingIndex) {
92
178
  try {
93
- compatibility = (0, schema_1.incrementalCompatibility)(existingDatabase, scopes, parserMode);
179
+ measurePhase(phaseTimings, "compatibility_ms", () => {
180
+ const existingDatabase = runtime.openDatabase(databasePath.absolutePath);
181
+ try {
182
+ compatibility = (0, schema_1.incrementalCompatibility)(existingDatabase, scopes, parserMode);
183
+ checkedCompatibility = true;
184
+ }
185
+ finally {
186
+ existingDatabase.close();
187
+ }
188
+ });
94
189
  }
95
- finally {
96
- existingDatabase.close();
190
+ catch {
191
+ if (!args_1.codeIndexFullMode && !args_1.codeIndexMigrateMode)
192
+ runtime.fail(unreadableIndexMessage(runtime));
97
193
  }
98
- incremental = !args_1.codeIndexFullMode && compatibility.compatible;
194
+ if (!compatibility.compatible && schemaMigrationRequired(compatibility.reason) && !args_1.codeIndexMigrateMode) {
195
+ runtime.fail(schemaMigrationRequiredMessage(runtime, compatibility.reason, { parserMode, requestedEngine, scopes }));
196
+ }
197
+ }
198
+ if (engine === "native-rust") {
199
+ if (!args_1.codeIndexIncrementalMode) {
200
+ try {
201
+ measurePhase(phaseTimings, "native_helper_ms", () => runtime.runNativeCodeIndexMode({ databasePath, discoveredFiles, parserMode, requestedEngine, scopes }));
202
+ phaseTimings.total_ms = Number(elapsedMs(totalStarted).toFixed(3));
203
+ emitCodeIndexPhaseTimings(phaseTimings);
204
+ return;
205
+ }
206
+ catch (error) {
207
+ phaseTimings.total_ms = Number(elapsedMs(totalStarted).toFixed(3));
208
+ emitCodeIndexPhaseTimings(phaseTimings);
209
+ throw error;
210
+ }
211
+ }
212
+ }
213
+ let incremental = false;
214
+ if (existingIndex && checkedCompatibility && !args_1.codeIndexFullMode && !args_1.codeIndexMigrateMode) {
215
+ incremental = compatibility.compatible;
99
216
  if (args_1.codeIndexIncrementalMode && !compatibility.compatible)
100
217
  runtime.fail(`--incremental cannot update ${databasePath.relativePath}: ${compatibility.reason}`);
101
218
  }
102
- runtime.prepareOutputPath();
103
- if (!incremental)
104
- runtime.removeDatabaseFiles(databasePath.absolutePath);
105
- const database = runtime.openDatabase(databasePath.absolutePath);
219
+ measurePhase(phaseTimings, "prepare_output_ms", () => {
220
+ runtime.prepareOutputPath();
221
+ if (!incremental)
222
+ runtime.removeDatabaseFiles(databasePath.absolutePath);
223
+ });
224
+ let database = runtime.openDatabase(databasePath.absolutePath);
106
225
  try {
107
226
  if (!incremental)
108
- (0, schema_1.setupDatabase)(database);
109
- const statements = (0, schema_1.createIndexStatements)(database);
110
- const currentFingerprints = discoveredFiles.map((filePath) => runtime.readCodeFileFingerprint(filePath));
111
- let reindexedFiles;
227
+ (0, schema_1.setupDatabase)(database, { secondaryIndexes: false });
228
+ const currentFingerprints = measurePhase(phaseTimings, "fingerprints_ms", () => discoveredFiles.map((filePath) => runtime.readCodeFileFingerprint(filePath)));
229
+ let reindexedFingerprints;
112
230
  let deletedPaths;
113
231
  let indexedPaths = new Set();
114
232
  let unchangedFiles = 0;
@@ -122,45 +240,87 @@ function runCodeIndexMode(runtime) {
122
240
  }]));
123
241
  const currentPaths = new Set(currentFingerprints.map((file) => file.path));
124
242
  deletedPaths = indexedRows.map((row) => String(row.path)).filter((filePath) => !currentPaths.has(filePath));
125
- reindexedFiles = [];
243
+ reindexedFingerprints = [];
126
244
  for (const file of currentFingerprints) {
127
245
  const existing = indexed.get(file.path);
128
246
  if (existing && existing.mtimeMs === file.mtimeMs && existing.size === file.size) {
129
247
  unchangedFiles += 1;
130
248
  continue;
131
249
  }
132
- reindexedFiles.push(runtime.readCodeFile(file.path, parserMode));
250
+ reindexedFingerprints.push(file);
133
251
  }
134
252
  }
135
253
  else {
136
254
  deletedPaths = [];
137
- reindexedFiles = discoveredFiles.map((filePath) => runtime.readCodeFile(filePath, parserMode));
255
+ reindexedFingerprints = currentFingerprints;
138
256
  }
139
- database.exec("BEGIN");
140
- if (!incremental)
141
- statements.insertMeta.run("created_at", new Date().toISOString());
142
- (0, schema_1.writeIndexMetadata)(scopes, parserMode, statements);
143
- for (const filePath of deletedPaths)
144
- (0, schema_1.removeIndexedFile)(filePath, statements);
145
- for (const file of reindexedFiles) {
146
- if (incremental && indexedPaths.has(file.path))
147
- (0, schema_1.removeIndexedFile)(file.path, statements);
148
- runtime.indexCodeFile(file, statements);
257
+ const nativeIncrementalRequested = engine === "native-rust"
258
+ || shouldUseNativeIncrementalForAuto(requestedEngine, runtime, reindexedFingerprints.length + deletedPaths.length);
259
+ if (nativeIncrementalRequested) {
260
+ if (!runtime.nativeCodeIndexAvailable()) {
261
+ runtime.fail("--code-index-engine native-rust --incremental requires PROJECT_LIBRARIAN_NATIVE_INDEXER or a packaged native helper.");
262
+ }
263
+ if (!runtime.nativeCodeIndexIncrementalEligible(reindexedFingerprints, parserMode)) {
264
+ if (engine === "native-rust") {
265
+ runtime.fail("--code-index-engine native-rust --incremental only supports native-eligible parser profiles; use --code-index-engine typescript for this incremental update.");
266
+ }
267
+ }
268
+ else {
269
+ database.close();
270
+ database = undefined;
271
+ measurePhase(phaseTimings, "native_helper_ms", () => runtime.runNativeCodeIndexIncrementalMode({
272
+ databasePath,
273
+ deletedPaths,
274
+ discoveredFiles,
275
+ parserMode,
276
+ requestedEngine,
277
+ reindexedFiles: reindexedFingerprints,
278
+ scopes,
279
+ unchangedFiles,
280
+ }));
281
+ phaseTimings.total_ms = Number(elapsedMs(totalStarted).toFixed(3));
282
+ emitCodeIndexPhaseTimings(phaseTimings);
283
+ return;
284
+ }
149
285
  }
150
- database.exec("COMMIT");
286
+ const reindexedFiles = measurePhase(phaseTimings, "read_files_ms", () => reindexedFingerprints.map((file) => runtime.readCodeFile(file.path, parserMode, file)));
287
+ const activeDatabase = database;
288
+ const statements = (0, schema_1.createIndexStatements)(activeDatabase);
289
+ measurePhase(phaseTimings, "sqlite_write_ms", () => {
290
+ configureBulkWriteConnection(activeDatabase);
291
+ activeDatabase.exec("BEGIN");
292
+ if (!incremental)
293
+ statements.insertMeta.run("created_at", new Date().toISOString());
294
+ (0, schema_1.writeIndexMetadata)(scopes, parserMode, statements);
295
+ for (const filePath of deletedPaths)
296
+ (0, schema_1.removeIndexedFile)(filePath, statements);
297
+ for (const file of reindexedFiles) {
298
+ if (incremental && indexedPaths.has(file.path))
299
+ (0, schema_1.removeIndexedFile)(file.path, statements);
300
+ runtime.indexCodeFile(file, statements);
301
+ }
302
+ if (!incremental)
303
+ (0, schema_1.createSecondaryIndexes)(activeDatabase);
304
+ activeDatabase.exec("COMMIT");
305
+ });
306
+ phaseTimings.total_ms = Number(elapsedMs(totalStarted).toFixed(3));
151
307
  console.log("Project wiki code evidence index complete.");
152
308
  console.log(`database: ${databasePath.relativePath}`);
153
309
  console.log(`mode: ${incremental ? "incremental" : "full"}`);
310
+ console.log(`engine: ${engine}`);
311
+ if (requestedEngine === "auto")
312
+ console.log("engine_selection: auto");
154
313
  console.log(`parser_mode: ${parserMode}`);
155
314
  console.log(`scopes: ${scopes.join(", ")}`);
156
315
  console.log(`files: ${currentFingerprints.length}`);
157
316
  console.log(`reindexed_files: ${reindexedFiles.length}`);
158
317
  console.log(`deleted_files: ${deletedPaths.length}`);
159
318
  console.log(`unchanged_files: ${unchangedFiles}`);
319
+ emitCodeIndexPhaseTimings(phaseTimings);
160
320
  }
161
321
  catch (error) {
162
322
  try {
163
- database.exec("ROLLBACK");
323
+ database?.exec("ROLLBACK");
164
324
  }
165
325
  catch {
166
326
  // Ignore rollback failures after setup errors.
@@ -168,7 +328,7 @@ function runCodeIndexMode(runtime) {
168
328
  throw error;
169
329
  }
170
330
  finally {
171
- database.close();
331
+ database?.close();
172
332
  }
173
333
  }
174
334
  function runCodeQueryMode(runtime) {
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.supportedNativeHelperTriples = exports.nativeCodeIndexHelperTargets = void 0;
4
+ exports.nativeCodeIndexHelperTargetForTriple = nativeCodeIndexHelperTargetForTriple;
5
+ exports.nativeCodeIndexHelperPlatformFromTriple = nativeCodeIndexHelperPlatformFromTriple;
6
+ exports.nativeCodeIndexHelperTripleForPlatform = nativeCodeIndexHelperTripleForPlatform;
7
+ exports.nativeCodeIndexHelperTargets = [
8
+ {
9
+ arch: "arm64",
10
+ architecture: "arm64",
11
+ format: "mach-o",
12
+ libc: "",
13
+ platform: "darwin",
14
+ runner: "macos-14",
15
+ rustTarget: "aarch64-apple-darwin",
16
+ triple: "darwin-arm64",
17
+ },
18
+ {
19
+ arch: "x64",
20
+ architecture: "x64",
21
+ format: "mach-o",
22
+ libc: "",
23
+ platform: "darwin",
24
+ runner: "macos-15-intel",
25
+ rustTarget: "x86_64-apple-darwin",
26
+ triple: "darwin-x64",
27
+ },
28
+ {
29
+ arch: "arm64",
30
+ architecture: "arm64",
31
+ format: "elf",
32
+ libc: "",
33
+ platform: "linux",
34
+ runner: "ubuntu-24.04-arm",
35
+ rustTarget: "aarch64-unknown-linux-gnu",
36
+ triple: "linux-arm64",
37
+ },
38
+ {
39
+ arch: "arm64",
40
+ architecture: "arm64",
41
+ format: "elf",
42
+ libc: "musl",
43
+ platform: "linux",
44
+ runner: "ubuntu-24.04-arm",
45
+ rustTarget: "aarch64-unknown-linux-musl",
46
+ triple: "linux-arm64-musl",
47
+ },
48
+ {
49
+ arch: "x64",
50
+ architecture: "x64",
51
+ format: "elf",
52
+ libc: "",
53
+ platform: "linux",
54
+ runner: "ubuntu-latest",
55
+ rustTarget: "x86_64-unknown-linux-gnu",
56
+ triple: "linux-x64",
57
+ },
58
+ {
59
+ arch: "x64",
60
+ architecture: "x64",
61
+ format: "elf",
62
+ libc: "musl",
63
+ platform: "linux",
64
+ runner: "ubuntu-latest",
65
+ rustTarget: "x86_64-unknown-linux-musl",
66
+ triple: "linux-x64-musl",
67
+ },
68
+ {
69
+ arch: "arm64",
70
+ architecture: "arm64",
71
+ format: "pe",
72
+ libc: "",
73
+ platform: "win32",
74
+ runner: "windows-11-arm",
75
+ rustTarget: "aarch64-pc-windows-msvc",
76
+ triple: "win32-arm64",
77
+ },
78
+ {
79
+ arch: "x64",
80
+ architecture: "x64",
81
+ format: "pe",
82
+ libc: "",
83
+ platform: "win32",
84
+ runner: "windows-latest",
85
+ rustTarget: "x86_64-pc-windows-msvc",
86
+ triple: "win32-x64",
87
+ },
88
+ ];
89
+ exports.supportedNativeHelperTriples = exports.nativeCodeIndexHelperTargets.map((target) => target.triple);
90
+ function nativeCodeIndexHelperTargetForTriple(triple) {
91
+ return exports.nativeCodeIndexHelperTargets.find((target) => target.triple === triple);
92
+ }
93
+ function nativeCodeIndexHelperPlatformFromTriple(triple) {
94
+ return nativeCodeIndexHelperTargetForTriple(triple)?.platform ?? String(triple).split("-")[0] ?? "";
95
+ }
96
+ function nativeCodeIndexHelperTripleForPlatform(platform, arch, libc = "") {
97
+ const normalizedLibc = platform === "linux" && libc === "musl" ? "musl" : "";
98
+ return exports.nativeCodeIndexHelperTargets.find((target) => (target.platform === platform && target.arch === arch && target.libc === normalizedLibc))?.triple ?? `${platform}-${arch}`;
99
+ }