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,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CodeEvidenceIndexUnavailableError = exports.codeContextPackTruncationNotice = exports.codeContextPackCharCap = exports.codeIndexSnapshot = exports.workspaceSummary = exports.workspaceDependencyGraph = exports.searchSymbols = exports.ownershipInfo = exports.ownershipContext = exports.matchedCodeownerRules = exports.evidenceCoverage = exports.codeownerRules = void 0;
36
+ exports.CodeEvidenceIndexUnavailableError = exports.nativeCodeIndexAutoFileThreshold = exports.codeContextPackTruncationNotice = exports.codeContextPackCharCap = exports.codeIndexSnapshot = exports.workspaceSummary = exports.workspaceDependencyGraph = exports.searchSymbols = exports.ownershipInfo = exports.ownershipContext = exports.matchedCodeownerRules = exports.evidenceCoverage = exports.codeownerRules = void 0;
37
37
  exports.codeIndexStaleness = codeIndexStaleness;
38
38
  exports.codeIndexHealth = codeIndexHealth;
39
39
  exports.codeImpact = codeImpact;
@@ -61,6 +61,7 @@ const registry_1 = require("./code-index/extractors/registry");
61
61
  const shared_1 = require("./code-index/extractors/shared");
62
62
  const index_health_1 = require("./code-index/index-health");
63
63
  const modes_1 = require("./code-index/modes");
64
+ const native_helper_1 = require("./code-index/native-helper");
64
65
  const ownership_1 = require("./code-index/ownership");
65
66
  Object.defineProperty(exports, "codeownerRules", { enumerable: true, get: function () { return ownership_1.codeownerRules; } });
66
67
  Object.defineProperty(exports, "matchedCodeownerRules", { enumerable: true, get: function () { return ownership_1.matchedCodeownerRules; } });
@@ -77,6 +78,8 @@ Object.defineProperty(exports, "searchSymbols", { enumerable: true, get: functio
77
78
  const workspace_1 = require("./workspace");
78
79
  exports.codeContextPackCharCap = 4000;
79
80
  exports.codeContextPackTruncationNotice = "[truncated - refine the query]";
81
+ exports.nativeCodeIndexAutoFileThreshold = 1;
82
+ const codeFileFingerprintPaths = new Map();
80
83
  function fail(message) {
81
84
  console.error(message);
82
85
  process.exit(1);
@@ -110,31 +113,82 @@ function selectedCodeParserMode() {
110
113
  return "tree-sitter";
111
114
  fail(`invalid --code-parser: ${args_1.codeParser}; expected one of: default, tree-sitter`);
112
115
  }
116
+ function selectedCodeIndexEngine() {
117
+ const requested = args_1.codeIndexEngine.trim().toLowerCase();
118
+ if (!requested || requested === "auto")
119
+ return "auto";
120
+ if (requested === "typescript")
121
+ return "typescript";
122
+ if (requested === "native-rust")
123
+ return "native-rust";
124
+ fail(`invalid --code-index-engine: ${args_1.codeIndexEngine}; expected one of: auto, typescript, native-rust`);
125
+ }
126
+ function codeIndexEngineSelectionContext(discoveredFiles, parserMode) {
127
+ let nativeEligibleFileCount = 0;
128
+ for (const filePath of discoveredFiles) {
129
+ const language = (0, code_index_file_policy_1.fileLanguage)(filePath) || "config";
130
+ if (nativeAutoEligibleProfile((0, registry_1.extractionProfile)(filePath, language, parserMode)))
131
+ nativeEligibleFileCount += 1;
132
+ }
133
+ return {
134
+ discoveredFileCount: discoveredFiles.length,
135
+ nativeEligibleFileCount,
136
+ nativeIneligibleFileCount: discoveredFiles.length - nativeEligibleFileCount,
137
+ };
138
+ }
139
+ function shouldUseNativeCodeIndexAuto(context) {
140
+ return context.nativeEligibleFileCount >= exports.nativeCodeIndexAutoFileThreshold
141
+ && (0, native_helper_1.nativeCodeIndexHelperAvailable)();
142
+ }
143
+ function nativeCodeIndexAvailable() {
144
+ return (0, native_helper_1.nativeCodeIndexHelperAvailable)();
145
+ }
113
146
  function normalizedMtimeMs(stat) {
114
147
  return Number(stat.mtimeMs.toFixed(3));
115
148
  }
116
149
  function readCodeFileFingerprint(relativePath) {
117
- const { stat } = (0, workspace_1.requireContainedProjectFile)(relativePath, "code-index file");
150
+ const discovered = (0, code_index_file_policy_1.cachedDiscoveredCodeFileStat)(relativePath);
151
+ const { absolutePath, stat } = discovered ?? (0, workspace_1.requireContainedProjectFile)(relativePath, "code-index file");
152
+ codeFileFingerprintPaths.set(relativePath, absolutePath);
118
153
  return {
119
154
  mtimeMs: normalizedMtimeMs(stat),
120
155
  path: relativePath,
121
156
  size: stat.size,
122
157
  };
123
158
  }
124
- function readCodeFile(relativePath, parserMode = "default") {
125
- const { absolutePath } = (0, workspace_1.requireContainedProjectFile)(relativePath, "code-index file");
159
+ function lineCount(text) {
160
+ if (text.length === 0)
161
+ return 0;
162
+ let lines = 1;
163
+ for (let index = 0; index < text.length; index += 1) {
164
+ if (text.charCodeAt(index) === 10)
165
+ lines += 1;
166
+ }
167
+ return lines;
168
+ }
169
+ function readCodeFile(relativePath, parserMode = "default", fingerprint) {
170
+ let effectiveFingerprint = fingerprint;
171
+ let absolutePath = effectiveFingerprint ? codeFileFingerprintPaths.get(relativePath) : undefined;
172
+ if (!absolutePath || !effectiveFingerprint) {
173
+ const contained = (0, workspace_1.requireContainedProjectFile)(relativePath, "code-index file");
174
+ absolutePath = contained.absolutePath;
175
+ effectiveFingerprint ??= {
176
+ mtimeMs: normalizedMtimeMs(contained.stat),
177
+ path: relativePath,
178
+ size: contained.stat.size,
179
+ };
180
+ }
126
181
  const text = fs.readFileSync(absolutePath, "utf8");
127
- const fingerprint = readCodeFileFingerprint(relativePath);
128
182
  const language = (0, code_index_file_policy_1.fileLanguage)(relativePath) || "config";
129
183
  return {
130
- bytes: fingerprint.size,
184
+ bytes: effectiveFingerprint.size,
131
185
  hash: crypto.createHash("sha256").update(text).digest("hex"),
132
186
  language,
133
- lines: text.length === 0 ? 0 : text.split(/\r?\n/).length,
134
- mtimeMs: fingerprint.mtimeMs,
187
+ lines: lineCount(text),
188
+ mtimeMs: effectiveFingerprint.mtimeMs,
135
189
  path: relativePath,
136
190
  profile: (0, registry_1.extractionProfile)(relativePath, language, parserMode),
137
- size: fingerprint.size,
191
+ size: effectiveFingerprint.size,
138
192
  text,
139
193
  };
140
194
  }
@@ -143,8 +197,9 @@ function extractionBackendForProfile(profile) {
143
197
  return extractionBackendRegistry.backendForProfile(profile);
144
198
  }
145
199
  function indexCodeFile(file, statements) {
146
- statements.insertFile.run(file.path, file.language, file.profile, file.language === "config" ? "config" : "source", file.bytes, file.lines, file.hash, file.mtimeMs, file.size);
147
- statements.insertFileFts.run(file.path, file.language, file.profile, file.text);
200
+ const ftsRowid = (0, schema_1.fileFtsRowid)(file.path);
201
+ statements.insertFile.run(file.path, ftsRowid, file.language, file.profile, file.language === "config" ? "config" : "source", file.bytes, file.lines, file.hash, file.mtimeMs, file.size);
202
+ statements.insertFileFts.run(ftsRowid, file.path, file.language, file.profile, file.text);
148
203
  extractionBackendForProfile(file.profile).index(file, statements);
149
204
  }
150
205
  function printRows(rows) {
@@ -173,6 +228,295 @@ function removeDatabaseFiles(databasePath) {
173
228
  fs.unlinkSync(filePath);
174
229
  }
175
230
  }
231
+ function moveDatabaseFiles(sourcePath, targetPath) {
232
+ const backupPath = `${targetPath}.backup-${process.pid}-${Date.now()}`;
233
+ removeDatabaseFiles(backupPath);
234
+ for (const suffix of ["", "-wal", "-shm"]) {
235
+ const target = `${targetPath}${suffix}`;
236
+ if (fs.existsSync(target))
237
+ fs.renameSync(target, `${backupPath}${suffix}`);
238
+ }
239
+ try {
240
+ for (const suffix of ["", "-wal", "-shm"]) {
241
+ const source = `${sourcePath}${suffix}`;
242
+ if (fs.existsSync(source))
243
+ fs.renameSync(source, `${targetPath}${suffix}`);
244
+ }
245
+ removeDatabaseFiles(backupPath);
246
+ }
247
+ catch (error) {
248
+ removeDatabaseFiles(targetPath);
249
+ for (const suffix of ["", "-wal", "-shm"]) {
250
+ const backup = `${backupPath}${suffix}`;
251
+ if (fs.existsSync(backup))
252
+ fs.renameSync(backup, `${targetPath}${suffix}`);
253
+ }
254
+ throw error;
255
+ }
256
+ }
257
+ function removeTemporaryDatabaseFiles(databasePath) {
258
+ for (const suffix of ["", "-wal", "-shm"]) {
259
+ const filePath = `${databasePath}${suffix}`;
260
+ if (fs.existsSync(filePath))
261
+ fs.unlinkSync(filePath);
262
+ }
263
+ }
264
+ function nativeCodeIndexFileFor(filePath, parserMode) {
265
+ const fingerprint = readCodeFileFingerprint(filePath);
266
+ const language = (0, code_index_file_policy_1.fileLanguage)(filePath) || "config";
267
+ return {
268
+ ...fingerprint,
269
+ language,
270
+ profile: (0, registry_1.extractionProfile)(filePath, language, parserMode),
271
+ };
272
+ }
273
+ function nativeCodeIndexFileFromCodeFile(file) {
274
+ return {
275
+ language: file.language,
276
+ mtimeMs: file.mtimeMs,
277
+ path: file.path,
278
+ profile: file.profile,
279
+ size: file.size,
280
+ };
281
+ }
282
+ function nativeCodeIndexFileFromFingerprint(file, parserMode) {
283
+ const language = (0, code_index_file_policy_1.fileLanguage)(file.path) || "config";
284
+ return {
285
+ language,
286
+ mtimeMs: file.mtimeMs,
287
+ path: file.path,
288
+ profile: (0, registry_1.extractionProfile)(file.path, language, parserMode),
289
+ size: file.size,
290
+ };
291
+ }
292
+ function nativeEligibleProfile(profile) {
293
+ return nativeAutoEligibleProfile(profile) || profile === "config" || profile === "inventory-only";
294
+ }
295
+ function nativeCodeIndexIncrementalEligible(files, parserMode) {
296
+ return files.every((file) => nativeEligibleProfile(nativeCodeIndexFileFromFingerprint(file, parserMode).profile));
297
+ }
298
+ function nativeAutoEligibleProfile(profile) {
299
+ return [
300
+ "typescript-ast",
301
+ "python-light",
302
+ "go-light",
303
+ "c-light",
304
+ "cpp-light",
305
+ "csharp-light",
306
+ "java-light",
307
+ "kotlin-light",
308
+ "php-light",
309
+ "rust-light",
310
+ "swift-light",
311
+ ].includes(profile);
312
+ }
313
+ function nativeCodeIndexOutputMode() {
314
+ const requested = (process.env.PROJECT_LIBRARIAN_NATIVE_INDEXER_STRATEGY ?? "sqlite-direct").trim();
315
+ if (requested === "row-stream" || requested === "sqlite-bridge" || requested === "sqlite-direct")
316
+ return requested;
317
+ fail(`invalid PROJECT_LIBRARIAN_NATIVE_INDEXER_STRATEGY: ${requested}; expected row-stream, sqlite-bridge, or sqlite-direct`);
318
+ }
319
+ function appendTypeScriptPartitionToNativeDatabase(databasePath, files, parserMode) {
320
+ if (files.length === 0)
321
+ return 0;
322
+ const database = openDatabase(databasePath);
323
+ try {
324
+ const statements = (0, schema_1.createIndexStatements)(database);
325
+ database.exec("BEGIN");
326
+ for (const file of files)
327
+ indexCodeFile(readCodeFile(file.path, parserMode, file), statements);
328
+ database.exec("COMMIT");
329
+ return files.length;
330
+ }
331
+ catch (error) {
332
+ try {
333
+ database.exec("ROLLBACK");
334
+ }
335
+ catch {
336
+ // Ignore rollback failures after helper-created database errors.
337
+ }
338
+ throw error;
339
+ }
340
+ finally {
341
+ database.close();
342
+ }
343
+ }
344
+ function writeNativeRowsToDatabase(databasePath, rows, scopes, parserMode) {
345
+ removeDatabaseFiles(databasePath);
346
+ const database = openDatabase(databasePath);
347
+ try {
348
+ (0, schema_1.setupDatabase)(database, { secondaryIndexes: false });
349
+ const statements = (0, schema_1.createIndexStatements)(database);
350
+ database.exec("BEGIN");
351
+ statements.insertMeta.run("created_at", new Date().toISOString());
352
+ (0, schema_1.writeIndexMetadata)(scopes, parserMode, statements);
353
+ for (const file of rows.files) {
354
+ const ftsRowid = (0, schema_1.fileFtsRowid)(file.path);
355
+ statements.insertFile.run(file.path, ftsRowid, file.language, file.profile, file.kind, file.bytes, file.lines, file.hash, file.mtime_ms, file.size);
356
+ statements.insertFileFts.run(ftsRowid, file.path, file.language, file.profile, file.content);
357
+ }
358
+ for (const symbol of rows.symbols) {
359
+ statements.insertSymbol.run(symbol.name, symbol.kind, symbol.file_path, symbol.line, symbol.signature);
360
+ statements.insertSymbolFts.run(symbol.name, symbol.kind, symbol.file_path, symbol.signature);
361
+ }
362
+ for (const imported of rows.imports) {
363
+ statements.insertImport.run(imported.from_file, imported.to_ref, imported.imported, imported.line, imported.raw);
364
+ }
365
+ for (const route of rows.routes) {
366
+ statements.insertRoute.run(route.method, route.route, route.file_path, route.line, route.handler);
367
+ }
368
+ for (const config of rows.configs) {
369
+ statements.insertConfig.run(config.key, config.value, config.file_path, config.line);
370
+ }
371
+ for (const edge of rows.edges) {
372
+ statements.insertEdge.run(edge.kind, edge.source_kind, edge.source, edge.target_kind, edge.target, edge.file_path, edge.line, edge.evidence);
373
+ }
374
+ (0, schema_1.createSecondaryIndexes)(database);
375
+ database.exec("COMMIT");
376
+ }
377
+ catch (error) {
378
+ try {
379
+ database.exec("ROLLBACK");
380
+ }
381
+ catch {
382
+ // Ignore rollback failures after row-stream setup errors.
383
+ }
384
+ throw error;
385
+ }
386
+ finally {
387
+ database.close();
388
+ }
389
+ }
390
+ function runNativeCodeIndexMode(request) {
391
+ let helperPath = "";
392
+ try {
393
+ helperPath = (0, native_helper_1.requireNativeCodeIndexHelperPath)();
394
+ }
395
+ catch (error) {
396
+ fail(error instanceof Error ? error.message : String(error));
397
+ }
398
+ prepareOutputPath();
399
+ const tempDatabasePath = `${request.databasePath.absolutePath}.native-${process.pid}-${Date.now()}.tmp`;
400
+ removeDatabaseFiles(tempDatabasePath);
401
+ const manifestFiles = [];
402
+ const nativeFiles = [];
403
+ const typescriptFiles = [];
404
+ for (const filePath of request.discoveredFiles) {
405
+ const file = nativeCodeIndexFileFor(filePath, request.parserMode);
406
+ manifestFiles.push(file);
407
+ if (nativeEligibleProfile(file.profile))
408
+ nativeFiles.push(file);
409
+ else
410
+ typescriptFiles.push(file);
411
+ }
412
+ const typescriptProfiles = [...new Set(typescriptFiles.map((file) => file.profile))].sort();
413
+ const outputMode = nativeCodeIndexOutputMode();
414
+ const rowsPath = `${tempDatabasePath}.rows.json`;
415
+ const job = (0, native_helper_1.buildNativeCodeIndexJob)({
416
+ database_path: tempDatabasePath,
417
+ files: nativeFiles,
418
+ output_mode: outputMode,
419
+ parser_mode: request.parserMode,
420
+ schema_version: schema_1.codeIndexSchemaVersion,
421
+ scopes: request.scopes,
422
+ ...(outputMode === "row-stream" ? { rows_path: rowsPath } : {}),
423
+ });
424
+ let summary;
425
+ let typescriptIndexedFiles = 0;
426
+ try {
427
+ if (outputMode === "row-stream") {
428
+ const result = (0, native_helper_1.runNativeCodeIndexRowsHelper)(job, { helperPath });
429
+ summary = result.summary;
430
+ writeNativeRowsToDatabase(tempDatabasePath, result.rows, request.scopes, request.parserMode);
431
+ }
432
+ else {
433
+ summary = (0, native_helper_1.runNativeCodeIndexHelper)(job, { helperPath });
434
+ }
435
+ if (!fs.existsSync(tempDatabasePath)) {
436
+ fail(`native code index helper did not create database: ${tempDatabasePath}`);
437
+ }
438
+ typescriptIndexedFiles = appendTypeScriptPartitionToNativeDatabase(tempDatabasePath, typescriptFiles, request.parserMode);
439
+ moveDatabaseFiles(tempDatabasePath, request.databasePath.absolutePath);
440
+ }
441
+ catch (error) {
442
+ removeTemporaryDatabaseFiles(tempDatabasePath);
443
+ fail(error instanceof Error ? error.message : String(error));
444
+ }
445
+ finally {
446
+ if (fs.existsSync(rowsPath))
447
+ fs.unlinkSync(rowsPath);
448
+ }
449
+ console.log("Project wiki code evidence index complete.");
450
+ console.log(`database: ${request.databasePath.relativePath}`);
451
+ console.log("mode: full");
452
+ console.log(`parser_mode: ${request.parserMode}`);
453
+ console.log(`engine: ${typescriptIndexedFiles > 0 ? "mixed-native-rust" : "native-rust"}`);
454
+ if (request.requestedEngine === "auto")
455
+ console.log("engine_selection: auto");
456
+ console.log(`native_strategy: ${outputMode}`);
457
+ console.log(`scopes: ${request.scopes.join(", ")}`);
458
+ console.log(`files: ${manifestFiles.length}`);
459
+ console.log(`native_files: ${nativeFiles.length}`);
460
+ console.log(`typescript_files: ${typescriptIndexedFiles}`);
461
+ if (typescriptProfiles.length > 0)
462
+ console.log(`typescript_profiles: ${typescriptProfiles.join(", ")}`);
463
+ console.log(`reindexed_files: ${manifestFiles.length}`);
464
+ console.log(`deleted_files: ${summary.deleted_files ?? 0}`);
465
+ console.log(`unchanged_files: ${summary.unchanged_files ?? 0}`);
466
+ }
467
+ function runNativeCodeIndexIncrementalMode(request) {
468
+ let helperPath = "";
469
+ try {
470
+ helperPath = (0, native_helper_1.requireNativeCodeIndexHelperPath)();
471
+ }
472
+ catch (error) {
473
+ fail(error instanceof Error ? error.message : String(error));
474
+ }
475
+ const nativeFiles = request.reindexedFiles.map((file) => nativeCodeIndexFileFromFingerprint(file, request.parserMode));
476
+ const ineligibleProfiles = [...new Set(nativeFiles
477
+ .filter((file) => !nativeEligibleProfile(file.profile))
478
+ .map((file) => file.profile))].sort();
479
+ if (ineligibleProfiles.length > 0) {
480
+ fail(`native incremental writer does not support parser profiles: ${ineligibleProfiles.join(", ")}`);
481
+ }
482
+ prepareOutputPath();
483
+ const outputMode = "sqlite-direct";
484
+ const job = (0, native_helper_1.buildNativeCodeIndexJob)({
485
+ database_path: request.databasePath.absolutePath,
486
+ deleted_paths: request.deletedPaths,
487
+ files: nativeFiles,
488
+ mode: "incremental",
489
+ output_mode: outputMode,
490
+ parser_mode: request.parserMode,
491
+ schema_version: schema_1.codeIndexSchemaVersion,
492
+ scopes: request.scopes,
493
+ });
494
+ let summary;
495
+ try {
496
+ summary = (0, native_helper_1.runNativeCodeIndexHelper)(job, { helperPath });
497
+ if (!fs.existsSync(request.databasePath.absolutePath)) {
498
+ fail(`native incremental writer did not preserve database: ${request.databasePath.absolutePath}`);
499
+ }
500
+ }
501
+ catch (error) {
502
+ fail(error instanceof Error ? error.message : String(error));
503
+ }
504
+ console.log("Project wiki code evidence index complete.");
505
+ console.log(`database: ${request.databasePath.relativePath}`);
506
+ console.log("mode: incremental");
507
+ console.log(`parser_mode: ${request.parserMode}`);
508
+ console.log("engine: native-rust");
509
+ if (request.requestedEngine === "auto")
510
+ console.log("engine_selection: auto");
511
+ console.log(`native_strategy: ${outputMode}`);
512
+ console.log(`scopes: ${request.scopes.join(", ")}`);
513
+ console.log(`files: ${request.discoveredFiles.length}`);
514
+ console.log(`native_files: ${nativeFiles.length}`);
515
+ console.log("typescript_files: 0");
516
+ console.log(`reindexed_files: ${summary.reindexed_files ?? nativeFiles.length}`);
517
+ console.log(`deleted_files: ${summary.deleted_files ?? request.deletedPaths.length}`);
518
+ console.log(`unchanged_files: ${request.unchangedFiles}`);
519
+ }
176
520
  function codeIndexStaleness(database) {
177
521
  const scopes = (0, schema_1.indexedScopes)(database);
178
522
  const parserMode = (0, schema_1.indexedParserMode)(database);
@@ -194,7 +538,7 @@ function codeIndexStaleness(database) {
194
538
  }
195
539
  if (existing.mtimeMs === file.mtimeMs && existing.size === file.size)
196
540
  continue;
197
- if (readCodeFile(file.path, parserMode).hash !== existing.hash)
541
+ if (readCodeFile(file.path, parserMode, file).hash !== existing.hash)
198
542
  changed += 1;
199
543
  }
200
544
  const deleted = indexedRows.filter((row) => !currentPaths.has(String(row.path))).length;
@@ -397,13 +741,20 @@ function codeIndexModeRuntime() {
397
741
  codeScopes,
398
742
  fail,
399
743
  indexCodeFile,
744
+ nativeCodeIndexAvailable,
745
+ nativeCodeIndexIncrementalEligible,
400
746
  openDatabase,
401
747
  prepareOutputPath,
402
748
  readCodeFileFingerprint,
403
749
  readCodeFile,
404
750
  removeDatabaseFiles,
405
751
  requireExistingIndex,
752
+ runNativeCodeIndexIncrementalMode,
753
+ runNativeCodeIndexMode,
754
+ selectedCodeIndexEngine,
406
755
  selectedCodeParserMode,
756
+ codeIndexEngineSelectionContext,
757
+ shouldUseNativeCodeIndexAuto,
407
758
  warnIfCodeIndexStale,
408
759
  };
409
760
  }
@@ -62,6 +62,8 @@ Options:
62
62
  --acknowledge-small-repo With --code-index, proceed below the small-repo scale gate after its cost warning.
63
63
  --incremental With --code-index, require an existing compatible index and update only changes.
64
64
  --code-index-full With --code-index, force a full rebuild even when incremental update is possible.
65
+ --code-index-migrate With --code-index, approve replacing an incompatible schema-version index.
66
+ --code-index-engine <engine> With --code-index, override default auto engine: typescript or native-rust.
65
67
  --code-parser <mode> With --code-index, use parser mode default or tree-sitter.
66
68
  --code-query <sql> Run conservative read-only SQL over the code evidence index.
67
69
  --code-status, --code-files Inspect the code evidence index.
@@ -165,6 +167,14 @@ if (args_1.codeIndexFullMode && !args_1.codeIndexMode) {
165
167
  console.error("--code-index-full is only supported with --code-index.");
166
168
  process.exit(1);
167
169
  }
170
+ if (args_1.codeIndexMigrateMode && !args_1.codeIndexMode) {
171
+ console.error("--code-index-migrate is only supported with --code-index.");
172
+ process.exit(1);
173
+ }
174
+ if (args_1.codeIndexEngineMode && !args_1.codeIndexMode) {
175
+ console.error("--code-index-engine is only supported with --code-index.");
176
+ process.exit(1);
177
+ }
168
178
  if (args_1.codeParserMode && !args_1.codeIndexMode) {
169
179
  console.error("--code-parser is only supported with --code-index.");
170
180
  process.exit(1);
@@ -173,6 +183,10 @@ if (args_1.codeIndexIncrementalMode && args_1.codeIndexFullMode) {
173
183
  console.error("Use one code index update mode at a time: --incremental or --code-index-full.");
174
184
  process.exit(1);
175
185
  }
186
+ if (args_1.codeIndexIncrementalMode && args_1.codeIndexMigrateMode) {
187
+ console.error("Use one code index update mode at a time: --incremental or --code-index-migrate.");
188
+ process.exit(1);
189
+ }
176
190
  const activeHandoffModes = [
177
191
  args_1.handoffSaveMode ? "--handoff-save" : "",
178
192
  args_1.handoffShowMode ? "--handoff-show" : "",
@@ -52,6 +52,7 @@ const packageFiles = [
52
52
  "package.json",
53
53
  "agents",
54
54
  ];
55
+ const runtimeDependencyPackages = ["typescript"];
55
56
  function fail(message) {
56
57
  console.error(message);
57
58
  process.exit(1);
@@ -83,6 +84,18 @@ function installAgents() {
83
84
  function packageRoot() {
84
85
  return path.resolve(__dirname, "..");
85
86
  }
87
+ function runtimeDependencySource(packageName) {
88
+ try {
89
+ return path.dirname(require.resolve(`${packageName}/package.json`, { paths: [packageRoot()] }));
90
+ }
91
+ catch (error) {
92
+ const message = error instanceof Error ? error.message : String(error);
93
+ return fail(`missing runtime dependency ${packageName}: run npm install before installing the Project Librarian skill. Error: ${message}`);
94
+ }
95
+ }
96
+ function runtimeDependencyTarget(packageName) {
97
+ return path.join("node_modules", ...packageName.split("/"));
98
+ }
86
99
  function userAgentRoot(agent) {
87
100
  const home = os.homedir();
88
101
  if (agent === "codex")
@@ -236,11 +249,18 @@ function installedProjectSkillSurfaces() {
236
249
  }
237
250
  function copyPackageFiles(targetRoot, dryRun, labelRoot = targetRoot) {
238
251
  const root = packageRoot();
239
- return packageFiles.map((relativePath) => {
252
+ const packageRows = packageFiles.map((relativePath) => {
240
253
  const source = path.join(root, relativePath);
241
254
  const target = path.join(targetRoot, relativePath);
242
255
  return [path.join(labelRoot, relativePath), copyPath(source, target, targetRoot, dryRun)];
243
256
  });
257
+ const dependencyRows = runtimeDependencyPackages.map((packageName) => {
258
+ const relativePath = runtimeDependencyTarget(packageName);
259
+ const source = runtimeDependencySource(packageName);
260
+ const target = path.join(targetRoot, relativePath);
261
+ return [path.join(labelRoot, relativePath), copyPath(source, target, targetRoot, dryRun)];
262
+ });
263
+ return [...packageRows, ...dependencyRows];
244
264
  }
245
265
  function syncProjectSkillInstall(agent) {
246
266
  return copyPackageFiles(projectSkillTarget(agent), false, projectSkillRelativeRoot(agent)).map(([label, status]) => {
@@ -261,7 +281,7 @@ function runInstallSkillMode() {
261
281
  console.log(`Project Librarian skill ${dryRun ? "install dry-run" : "install"} complete.`);
262
282
  console.log(`scope: ${scope}`);
263
283
  console.log(`agents: ${agents.join(", ")}`);
264
- console.log("note: install only installs the reusable skill files; it does not create or update AGENTS.md, CLAUDE.md, GEMINI.md, wiki/, .cursor/rules/, .cursor/hooks.json, .gemini/settings.json, .codex/hooks.json, or .claude/settings.json.");
284
+ console.log("note: install only installs the reusable skill files and required local-runner runtime dependencies; it does not create or update AGENTS.md, CLAUDE.md, GEMINI.md, wiki/, .cursor/rules/, .cursor/hooks.json, .gemini/settings.json, .codex/hooks.json, or .claude/settings.json.");
265
285
  console.log("compatibility: install-skill remains supported as an alias for install.");
266
286
  console.log("next: ask your agent to use Project Librarian from the target project root; the installed skill resolves the local runner.");
267
287
  for (const [label, status] of rows) {
@@ -0,0 +1,70 @@
1
+ {
2
+ "artifact": "project-librarian-indexer",
3
+ "helpers": [
4
+ {
5
+ "architecture": "arm64",
6
+ "format": "mach-o",
7
+ "path": "dist/native/darwin-arm64/project-librarian-indexer",
8
+ "sha256": "f5c69130f6c0441044141c761f1ccdc7e6ee4d06e327ce0f50d43a7aed76cc95",
9
+ "size": 2697520,
10
+ "triple": "darwin-arm64"
11
+ },
12
+ {
13
+ "architecture": "x64",
14
+ "format": "mach-o",
15
+ "path": "dist/native/darwin-x64/project-librarian-indexer",
16
+ "sha256": "25041398ba2de3ed749c14103d358ed4a7934a05459eb63c6cf5f6ae58c7fb03",
17
+ "size": 2770592,
18
+ "triple": "darwin-x64"
19
+ },
20
+ {
21
+ "architecture": "arm64",
22
+ "format": "elf",
23
+ "path": "dist/native/linux-arm64/project-librarian-indexer",
24
+ "sha256": "01bf4437fd62446958438ac58e9ca8bef811bdc6d70a63fc1a0ca1b627521e67",
25
+ "size": 3065520,
26
+ "triple": "linux-arm64"
27
+ },
28
+ {
29
+ "architecture": "arm64",
30
+ "format": "elf",
31
+ "path": "dist/native/linux-arm64-musl/project-librarian-indexer",
32
+ "sha256": "b7287995bea678a6f55bd03761e5b0985d483e875d7594395b81bdb1e90a8dd9",
33
+ "size": 3100840,
34
+ "triple": "linux-arm64-musl"
35
+ },
36
+ {
37
+ "architecture": "x64",
38
+ "format": "elf",
39
+ "path": "dist/native/linux-x64/project-librarian-indexer",
40
+ "sha256": "5d93bb7576afbdde0acbde7983a874f2666f0d59227524c1eb42cc75b457c5ed",
41
+ "size": 3110696,
42
+ "triple": "linux-x64"
43
+ },
44
+ {
45
+ "architecture": "x64",
46
+ "format": "elf",
47
+ "path": "dist/native/linux-x64-musl/project-librarian-indexer",
48
+ "sha256": "518aea0fc53ed7731751db4bb436a0be98f8583659d51aeff769bedb7a7cb8ab",
49
+ "size": 3247384,
50
+ "triple": "linux-x64-musl"
51
+ },
52
+ {
53
+ "architecture": "arm64",
54
+ "format": "pe",
55
+ "path": "dist/native/win32-arm64/project-librarian-indexer.exe",
56
+ "sha256": "e8e5200660a8852d1b7554daf0d16361e29e5599baa5cd406eb3f2266abd98f6",
57
+ "size": 2098688,
58
+ "triple": "win32-arm64"
59
+ },
60
+ {
61
+ "architecture": "x64",
62
+ "format": "pe",
63
+ "path": "dist/native/win32-x64/project-librarian-indexer.exe",
64
+ "sha256": "dc076bd61271f23ab87b428c7cbfa3af45911c00f7bf7986a2ed9d517e1cfb6f",
65
+ "size": 2375680,
66
+ "triple": "win32-x64"
67
+ }
68
+ ],
69
+ "schema_version": 1
70
+ }
package/docs/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # Project Librarian Docs
2
+
3
+ Start from the main [README](../README.md) when evaluating the project. These pages hold the details that are useful after the first-screen overview.
4
+
5
+ | Document | Contents |
6
+ | --- | --- |
7
+ | [Usage](usage.md) | Install scopes, runner paths, generated files, migration behavior, and common agent requests. |
8
+ | [Code Evidence](code-evidence.md) | Code-evidence index, MCP server, freshness contract, scale gate, language support, and native helper policy. |
9
+ | [CLI Reference](cli-reference.md) | Complete command and option reference. |
10
+ | [Benchmark Evidence](benchmarks.md) | Published benchmark claims, limits, task-family definitions, and reproduction commands. |
11
+ | [Maintainer Guide](maintainer.md) | Local development, release readiness, trusted publishing, and benchmark operations. |