indexer-cli 0.2.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.
Files changed (139) hide show
  1. package/README.md +156 -0
  2. package/bin/indexer-cli.js +97 -0
  3. package/dist/_temp_test.d.ts +1 -0
  4. package/dist/_temp_test.js +4 -0
  5. package/dist/_temp_test.js.map +1 -0
  6. package/dist/chunking/adaptive.d.ts +15 -0
  7. package/dist/chunking/adaptive.js +43 -0
  8. package/dist/chunking/adaptive.js.map +1 -0
  9. package/dist/chunking/function.d.ts +6 -0
  10. package/dist/chunking/function.js +96 -0
  11. package/dist/chunking/function.js.map +1 -0
  12. package/dist/chunking/index.d.ts +5 -0
  13. package/dist/chunking/index.js +22 -0
  14. package/dist/chunking/index.js.map +1 -0
  15. package/dist/chunking/module.d.ts +6 -0
  16. package/dist/chunking/module.js +33 -0
  17. package/dist/chunking/module.js.map +1 -0
  18. package/dist/chunking/single.d.ts +4 -0
  19. package/dist/chunking/single.js +19 -0
  20. package/dist/chunking/single.js.map +1 -0
  21. package/dist/chunking/types.d.ts +17 -0
  22. package/dist/chunking/types.js +3 -0
  23. package/dist/chunking/types.js.map +1 -0
  24. package/dist/cli/commands/architecture.d.ts +2 -0
  25. package/dist/cli/commands/architecture.js +162 -0
  26. package/dist/cli/commands/architecture.js.map +1 -0
  27. package/dist/cli/commands/context.d.ts +2 -0
  28. package/dist/cli/commands/context.js +241 -0
  29. package/dist/cli/commands/context.js.map +1 -0
  30. package/dist/cli/commands/deps.d.ts +2 -0
  31. package/dist/cli/commands/deps.js +129 -0
  32. package/dist/cli/commands/deps.js.map +1 -0
  33. package/dist/cli/commands/enrich.d.ts +2 -0
  34. package/dist/cli/commands/ensure-indexed.d.ts +4 -0
  35. package/dist/cli/commands/ensure-indexed.js +168 -0
  36. package/dist/cli/commands/ensure-indexed.js.map +1 -0
  37. package/dist/cli/commands/explain.d.ts +2 -0
  38. package/dist/cli/commands/explain.js +165 -0
  39. package/dist/cli/commands/explain.js.map +1 -0
  40. package/dist/cli/commands/index.d.ts +2 -0
  41. package/dist/cli/commands/index.js +271 -0
  42. package/dist/cli/commands/index.js.map +1 -0
  43. package/dist/cli/commands/init.d.ts +2 -0
  44. package/dist/cli/commands/init.js +132 -0
  45. package/dist/cli/commands/init.js.map +1 -0
  46. package/dist/cli/commands/search.d.ts +2 -0
  47. package/dist/cli/commands/search.js +206 -0
  48. package/dist/cli/commands/search.js.map +1 -0
  49. package/dist/cli/commands/setup.d.ts +2 -0
  50. package/dist/cli/commands/setup.js +425 -0
  51. package/dist/cli/commands/setup.js.map +1 -0
  52. package/dist/cli/commands/skill-template.d.ts +6 -0
  53. package/dist/cli/commands/skill-template.js +72 -0
  54. package/dist/cli/commands/skill-template.js.map +1 -0
  55. package/dist/cli/commands/structure.d.ts +2 -0
  56. package/dist/cli/commands/structure.js +243 -0
  57. package/dist/cli/commands/structure.js.map +1 -0
  58. package/dist/cli/commands/uninstall.d.ts +2 -0
  59. package/dist/cli/commands/uninstall.js +138 -0
  60. package/dist/cli/commands/uninstall.js.map +1 -0
  61. package/dist/cli/entry.d.ts +1 -0
  62. package/dist/cli/entry.js +55 -0
  63. package/dist/cli/entry.js.map +1 -0
  64. package/dist/cli/help-text.d.ts +2 -0
  65. package/dist/cli/help-text.js +9 -0
  66. package/dist/cli/help-text.js.map +1 -0
  67. package/dist/cli/version.d.ts +1 -0
  68. package/dist/cli/version.js +9 -0
  69. package/dist/cli/version.js.map +1 -0
  70. package/dist/core/config.d.ts +21 -0
  71. package/dist/core/config.js +77 -0
  72. package/dist/core/config.js.map +1 -0
  73. package/dist/core/logger.d.ts +19 -0
  74. package/dist/core/logger.js +116 -0
  75. package/dist/core/logger.js.map +1 -0
  76. package/dist/core/types.d.ts +194 -0
  77. package/dist/core/types.js +5 -0
  78. package/dist/core/types.js.map +1 -0
  79. package/dist/core/update-check.d.ts +1 -0
  80. package/dist/core/update-check.js +61 -0
  81. package/dist/core/update-check.js.map +1 -0
  82. package/dist/embedding/ollama.d.ts +29 -0
  83. package/dist/embedding/ollama.js +264 -0
  84. package/dist/embedding/ollama.js.map +1 -0
  85. package/dist/engine/architecture.d.ts +55 -0
  86. package/dist/engine/architecture.js +359 -0
  87. package/dist/engine/architecture.js.map +1 -0
  88. package/dist/engine/dependency-resolver.d.ts +4 -0
  89. package/dist/engine/dependency-resolver.js +69 -0
  90. package/dist/engine/dependency-resolver.js.map +1 -0
  91. package/dist/engine/git.d.ts +11 -0
  92. package/dist/engine/git.js +246 -0
  93. package/dist/engine/git.js.map +1 -0
  94. package/dist/engine/indexer.d.ts +86 -0
  95. package/dist/engine/indexer.js +933 -0
  96. package/dist/engine/indexer.js.map +1 -0
  97. package/dist/engine/scanner.d.ts +1 -0
  98. package/dist/engine/scanner.js +42 -0
  99. package/dist/engine/scanner.js.map +1 -0
  100. package/dist/engine/searcher.d.ts +26 -0
  101. package/dist/engine/searcher.js +70 -0
  102. package/dist/engine/searcher.js.map +1 -0
  103. package/dist/index.d.ts +1 -0
  104. package/dist/index.js +4 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/languages/csharp.d.ts +25 -0
  107. package/dist/languages/csharp.js +311 -0
  108. package/dist/languages/csharp.js.map +1 -0
  109. package/dist/languages/gdscript.d.ts +25 -0
  110. package/dist/languages/gdscript.js +382 -0
  111. package/dist/languages/gdscript.js.map +1 -0
  112. package/dist/languages/plugin.d.ts +73 -0
  113. package/dist/languages/plugin.js +35 -0
  114. package/dist/languages/plugin.js.map +1 -0
  115. package/dist/languages/python.d.ts +24 -0
  116. package/dist/languages/python.js +292 -0
  117. package/dist/languages/python.js.map +1 -0
  118. package/dist/languages/ruby.d.ts +25 -0
  119. package/dist/languages/ruby.js +328 -0
  120. package/dist/languages/ruby.js.map +1 -0
  121. package/dist/languages/typescript.d.ts +21 -0
  122. package/dist/languages/typescript.js +439 -0
  123. package/dist/languages/typescript.js.map +1 -0
  124. package/dist/storage/sqlite.d.ts +51 -0
  125. package/dist/storage/sqlite.js +726 -0
  126. package/dist/storage/sqlite.js.map +1 -0
  127. package/dist/storage/vectors.d.ts +39 -0
  128. package/dist/storage/vectors.js +450 -0
  129. package/dist/storage/vectors.js.map +1 -0
  130. package/dist/utils/gitignore.d.ts +4 -0
  131. package/dist/utils/gitignore.js +85 -0
  132. package/dist/utils/gitignore.js.map +1 -0
  133. package/dist/utils/hash.d.ts +1 -0
  134. package/dist/utils/hash.js +12 -0
  135. package/dist/utils/hash.js.map +1 -0
  136. package/dist/utils/token-estimator.d.ts +3 -0
  137. package/dist/utils/token-estimator.js +13 -0
  138. package/dist/utils/token-estimator.js.map +1 -0
  139. package/package.json +54 -0
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ensureIndexed = ensureIndexed;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_path_2 = require("node:path");
10
+ const config_js_1 = require("../../core/config.js");
11
+ const types_js_1 = require("../../core/types.js");
12
+ const ollama_js_1 = require("../../embedding/ollama.js");
13
+ const git_js_1 = require("../../engine/git.js");
14
+ const git_js_2 = require("../../engine/git.js");
15
+ const indexer_js_1 = require("../../engine/indexer.js");
16
+ const hash_js_1 = require("../../utils/hash.js");
17
+ const vectors_js_1 = require("../../storage/vectors.js");
18
+ // Extensions that the indexer actually processes (from language plugins).
19
+ // Non-code files in workspace changes are irrelevant for re-index decisions.
20
+ const INDEXED_EXTENSIONS = new Set([
21
+ ".ts", ".tsx", ".mts", ".cts",
22
+ ".js", ".jsx", ".mjs", ".cjs",
23
+ ".py", ".pyi",
24
+ ".cs",
25
+ ".gd",
26
+ ".rb",
27
+ ]);
28
+ /**
29
+ * Returns true if every workspace-modified/added file in workspaceChanges
30
+ * is already captured in `snapshot` with the same sha256 as on disk.
31
+ * This prevents repeated reindexing of persistent uncommitted changes.
32
+ */
33
+ async function workspaceAlreadyIndexed(metadata, repoRoot, snapshot, workspaceChanges) {
34
+ // Deleted files can't be verified as "already indexed"
35
+ if (workspaceChanges.deleted.length > 0)
36
+ return false;
37
+ const filesToCheck = [
38
+ ...workspaceChanges.modified,
39
+ ...workspaceChanges.added,
40
+ ];
41
+ if (filesToCheck.length === 0)
42
+ return true;
43
+ for (const filePath of filesToCheck) {
44
+ if (!INDEXED_EXTENSIONS.has((0, node_path_2.extname)(filePath).toLowerCase())) {
45
+ continue; // Non-code file — not indexed, irrelevant for re-index decision
46
+ }
47
+ const record = await metadata.getFile(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, filePath);
48
+ if (!record)
49
+ return false; // Code file not in snapshot
50
+ let content;
51
+ try {
52
+ content = await (0, promises_1.readFile)(node_path_1.default.join(repoRoot, filePath), "utf8");
53
+ }
54
+ catch {
55
+ return false; // Unreadable
56
+ }
57
+ if ((0, hash_js_1.computeHash)(content) !== record.sha256)
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+ async function getIndexPlan(git, repoRoot, metadata, snapshot) {
63
+ if (!snapshot) {
64
+ return { isFullReindex: true, changedFiles: undefined };
65
+ }
66
+ if (!snapshot.meta.headCommit) {
67
+ return { isFullReindex: true, changedFiles: undefined };
68
+ }
69
+ const headCommit = await git.getHeadCommit(repoRoot);
70
+ const workspaceChanges = await git.getWorkingTreeChanges(repoRoot);
71
+ const committedChanges = headCommit && headCommit !== snapshot.meta.headCommit
72
+ ? await git.getChangedFiles(repoRoot, snapshot.meta.headCommit)
73
+ : { added: [], modified: [], deleted: [] };
74
+ const changedFiles = (0, git_js_2.mergeGitDiffs)(committedChanges, workspaceChanges);
75
+ const hasChanges = changedFiles.added.length > 0 ||
76
+ changedFiles.modified.length > 0 ||
77
+ changedFiles.deleted.length > 0;
78
+ if (!hasChanges)
79
+ return null;
80
+ // Optimisation: if the only "changes" are workspace changes that were
81
+ // already indexed in the latest snapshot (same sha256 on disk), skip.
82
+ const noCommittedChanges = committedChanges.added.length === 0 &&
83
+ committedChanges.modified.length === 0 &&
84
+ committedChanges.deleted.length === 0;
85
+ if (noCommittedChanges) {
86
+ const alreadyIndexed = await workspaceAlreadyIndexed(metadata, repoRoot, snapshot, workspaceChanges);
87
+ if (alreadyIndexed)
88
+ return null;
89
+ }
90
+ return { isFullReindex: false, changedFiles };
91
+ }
92
+ async function ensureIndexed(metadata, repoRoot, options) {
93
+ const silent = options?.silent ?? false;
94
+ const git = new git_js_1.SimpleGitOperations();
95
+ const snapshot = (await metadata.getLatestCompletedSnapshot(types_js_1.DEFAULT_PROJECT_ID)) ??
96
+ undefined;
97
+ const indexPlan = await getIndexPlan(git, repoRoot, metadata, snapshot);
98
+ if (!indexPlan) {
99
+ return;
100
+ }
101
+ const dataDir = node_path_1.default.join(repoRoot, ".indexer-cli");
102
+ const vectorsPath = node_path_1.default.join(dataDir, "vectors");
103
+ const vectors = new vectors_js_1.LanceDbVectorStore({
104
+ dbPath: vectorsPath,
105
+ vectorSize: config_js_1.config.get("vectorSize"),
106
+ });
107
+ const startedAt = Date.now();
108
+ const embedder = new ollama_js_1.OllamaEmbeddingProvider(config_js_1.config.get("ollamaBaseUrl"), config_js_1.config.get("embeddingModel"), config_js_1.config.get("indexBatchSize"), config_js_1.config.get("indexConcurrency"), config_js_1.config.get("ollamaNumCtx"));
109
+ let engine = null;
110
+ try {
111
+ await vectors.initialize();
112
+ await embedder.initialize();
113
+ engine = new indexer_js_1.IndexerEngine({
114
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
115
+ repoRoot,
116
+ metadata,
117
+ vectors,
118
+ embedder,
119
+ git,
120
+ languagePlugins: (0, indexer_js_1.createDefaultLanguagePlugins)(),
121
+ });
122
+ const headCommit = await git.getHeadCommit(repoRoot);
123
+ // metadata is already initialized by the caller — skip engine.initialize()
124
+ // to avoid redundant schema/migration checks.
125
+ const mode = indexPlan.isFullReindex ? "full" : "incremental";
126
+ if (!silent) {
127
+ console.log(`Indexing (${mode})...`);
128
+ }
129
+ const result = await engine.indexProject({
130
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
131
+ repoRoot,
132
+ gitRef: headCommit ?? "unknown",
133
+ isFullReindex: indexPlan.isFullReindex,
134
+ changedFiles: indexPlan.changedFiles,
135
+ onProgress: silent
136
+ ? undefined
137
+ : (processed, total) => {
138
+ console.log(` ${processed}/${total} files...`);
139
+ },
140
+ });
141
+ const elapsedMs = Date.now() - startedAt;
142
+ const chunkCount = await vectors.countVectors({
143
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
144
+ snapshotId: result.snapshotId,
145
+ });
146
+ if (!silent) {
147
+ console.log("Index updated.");
148
+ console.log(` Snapshot: ${result.snapshotId}`);
149
+ console.log(` Files indexed: ${result.filesIndexed}`);
150
+ console.log(` Chunks created: ${chunkCount}`);
151
+ console.log(` Time elapsed: ${(elapsedMs / 1000).toFixed(2)}s`);
152
+ }
153
+ if (!silent && result.errors.length > 0) {
154
+ for (const error of result.errors) {
155
+ console.error(` Error: ${error}`);
156
+ }
157
+ }
158
+ }
159
+ catch (indexError) {
160
+ const message = indexError instanceof Error ? indexError.message : String(indexError);
161
+ throw new Error(`Auto-indexing failed: ${message}`);
162
+ }
163
+ finally {
164
+ // metadata is borrowed from caller — do NOT close it here
165
+ await Promise.allSettled([vectors.close(), embedder.close()]);
166
+ }
167
+ }
168
+ //# sourceMappingURL=ensure-indexed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-indexed.js","sourceRoot":"","sources":["../../../src/cli/commands/ensure-indexed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerExplainCommand(program: Command): void;
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerExplainCommand = registerExplainCommand;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const config_js_1 = require("../../core/config.js");
9
+ const logger_js_1 = require("../../core/logger.js");
10
+ const types_js_1 = require("../../core/types.js");
11
+ const sqlite_js_1 = require("../../storage/sqlite.js");
12
+ const help_text_js_1 = require("../help-text.js");
13
+ const ensure_indexed_js_1 = require("./ensure-indexed.js");
14
+ function registerExplainCommand(program) {
15
+ program
16
+ .command("explain <symbol>")
17
+ .description("Show context for a symbol: signature, callers, and module")
18
+ .addHelpText("after", `\n${help_text_js_1.PROJECT_ROOT_COMMAND_HELP}\n`)
19
+ .option("--json", "output as JSON")
20
+ .action(async (symbolArg, options) => {
21
+ const resolvedProjectPath = process.cwd();
22
+ const dataDir = node_path_1.default.join(resolvedProjectPath, ".indexer-cli");
23
+ const dbPath = node_path_1.default.join(dataDir, "db.sqlite");
24
+ const isJson = Boolean(options?.json);
25
+ const rankSymbolMatch = (candidateName, query) => {
26
+ if (candidateName === query) {
27
+ return 0;
28
+ }
29
+ const candidateNameLower = candidateName.toLowerCase();
30
+ const queryLower = query.toLowerCase();
31
+ if (candidateNameLower === queryLower) {
32
+ return 1;
33
+ }
34
+ if (candidateNameLower.startsWith(queryLower)) {
35
+ return 2;
36
+ }
37
+ return 3;
38
+ };
39
+ (0, logger_js_1.initLogger)(dataDir);
40
+ config_js_1.config.load(dataDir);
41
+ const metadata = new sqlite_js_1.SqliteMetadataStore(dbPath);
42
+ try {
43
+ await metadata.initialize();
44
+ await (0, ensure_indexed_js_1.ensureIndexed)(metadata, resolvedProjectPath, { silent: isJson });
45
+ const snapshot = await metadata.getLatestCompletedSnapshot(types_js_1.DEFAULT_PROJECT_ID);
46
+ if (!snapshot) {
47
+ throw new Error("No completed snapshot found.");
48
+ }
49
+ // Parse "file::symbol" or just "symbol"
50
+ let symbolName;
51
+ let filterFilePath;
52
+ if (symbolArg.includes("::")) {
53
+ const parts = symbolArg.split("::");
54
+ filterFilePath = parts[0];
55
+ symbolName = parts[1] ?? symbolArg;
56
+ }
57
+ else {
58
+ symbolName = symbolArg;
59
+ }
60
+ // Search symbols by name
61
+ let symbols = await metadata.searchSymbols(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, symbolName);
62
+ if (symbols.length === 0) {
63
+ const camelCaseParts = symbolName
64
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
65
+ .split(/\s+/)
66
+ .filter(Boolean);
67
+ const fallbackQuery = camelCaseParts[0];
68
+ if (fallbackQuery && fallbackQuery !== symbolName) {
69
+ symbols = await metadata.searchSymbols(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, fallbackQuery);
70
+ }
71
+ }
72
+ const matches = filterFilePath
73
+ ? symbols.filter((s) => s.filePath === filterFilePath)
74
+ : [...symbols].sort((a, b) => {
75
+ const rankDiff = rankSymbolMatch(a.name, symbolName) -
76
+ rankSymbolMatch(b.name, symbolName);
77
+ if (rankDiff !== 0) {
78
+ return rankDiff;
79
+ }
80
+ return a.name.localeCompare(b.name);
81
+ });
82
+ if (matches.length === 0) {
83
+ const fuzzy = symbols.slice(0, 5).map((s) => ({
84
+ name: s.name,
85
+ kind: s.kind,
86
+ filePath: s.filePath,
87
+ }));
88
+ if (isJson) {
89
+ console.log(JSON.stringify({ error: "Symbol not found", suggestions: fuzzy }));
90
+ }
91
+ else {
92
+ console.error(`Symbol "${symbolName}" not found.`);
93
+ if (fuzzy.length > 0) {
94
+ console.error(`Did you mean: ${fuzzy.map((s) => `${s.name} (${s.kind}) in ${s.filePath}`).join(", ")}?`);
95
+ }
96
+ }
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ const results = await Promise.all(matches.map(async (sym) => {
101
+ const [deps, dependents] = await Promise.all([
102
+ metadata.listDependencies(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, sym.filePath),
103
+ metadata.getDependents(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, sym.filePath),
104
+ ]);
105
+ return {
106
+ name: sym.name,
107
+ kind: sym.kind,
108
+ file: sym.filePath,
109
+ lines: {
110
+ start: sym.range.start.line,
111
+ end: sym.range.end.line,
112
+ },
113
+ exported: sym.exported,
114
+ signature: sym.signature,
115
+ docComment: sym.docComment ?? null,
116
+ callers: dependents
117
+ .map((d) => d.fromPath)
118
+ .filter((v, i, arr) => arr.indexOf(v) === i),
119
+ callees: deps
120
+ .filter((d) => d.dependencyType === "internal" && d.toPath)
121
+ .map((d) => d.toPath)
122
+ .filter((v, i, arr) => arr.indexOf(v) === i),
123
+ };
124
+ }));
125
+ if (isJson) {
126
+ console.log(JSON.stringify(results.length === 1 ? results[0] : results, null, 2));
127
+ return;
128
+ }
129
+ for (const result of results) {
130
+ console.log(`Symbol: ${result.name}`);
131
+ console.log(`File: ${result.file} (lines ${result.lines.start}-${result.lines.end})`);
132
+ console.log(`Kind: ${result.kind}${result.exported ? " (exported)" : ""}`);
133
+ if (result.signature) {
134
+ console.log(`Signature: ${result.signature}`);
135
+ }
136
+ if (result.docComment) {
137
+ console.log(`Docs: ${result.docComment.split("\n")[0]}`);
138
+ }
139
+ if (result.callers.length > 0) {
140
+ console.log(`\nCallers (${result.callers.length}):`);
141
+ for (const caller of result.callers) {
142
+ console.log(` ${caller}`);
143
+ }
144
+ }
145
+ if (result.callees.length > 0) {
146
+ console.log(`\nCallees (${result.callees.length}):`);
147
+ for (const callee of result.callees) {
148
+ console.log(` ${callee}`);
149
+ }
150
+ }
151
+ if (results.length > 1)
152
+ console.log("");
153
+ }
154
+ }
155
+ catch (error) {
156
+ const message = error instanceof Error ? error.message : String(error);
157
+ console.error(`Explain failed: ${message}`);
158
+ process.exitCode = 1;
159
+ }
160
+ finally {
161
+ await metadata.close().catch(() => undefined);
162
+ }
163
+ });
164
+ }
165
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerIndexCommand(program: Command): void;
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerIndexCommand = registerIndexCommand;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const config_js_1 = require("../../core/config.js");
9
+ const types_js_1 = require("../../core/types.js");
10
+ const logger_js_1 = require("../../core/logger.js");
11
+ const ollama_js_1 = require("../../embedding/ollama.js");
12
+ const git_js_1 = require("../../engine/git.js");
13
+ const indexer_js_1 = require("../../engine/indexer.js");
14
+ const scanner_js_1 = require("../../engine/scanner.js");
15
+ const sqlite_js_1 = require("../../storage/sqlite.js");
16
+ const vectors_js_1 = require("../../storage/vectors.js");
17
+ const help_text_js_1 = require("../help-text.js");
18
+ function countChangedFiles(diff) {
19
+ return diff.added.length + diff.modified.length + diff.deleted.length;
20
+ }
21
+ function buildFileTree(filePaths) {
22
+ const root = { dirs: new Map(), files: new Set() };
23
+ for (const filePath of filePaths) {
24
+ const parts = filePath.split("/");
25
+ let node = root;
26
+ for (let i = 0; i < parts.length - 1; i++) {
27
+ const dir = parts[i];
28
+ let child = node.dirs.get(dir);
29
+ if (!child) {
30
+ child = { dirs: new Map(), files: new Set() };
31
+ node.dirs.set(dir, child);
32
+ }
33
+ node = child;
34
+ }
35
+ node.files.add(parts[parts.length - 1]);
36
+ }
37
+ return root;
38
+ }
39
+ function printFileTree(node, indent) {
40
+ const dirs = Array.from(node.dirs.entries()).sort((a, b) => a[0].localeCompare(b[0]));
41
+ const files = Array.from(node.files).sort((a, b) => a.localeCompare(b));
42
+ for (const [name, child] of dirs) {
43
+ console.log(`${indent}${name}/`);
44
+ printFileTree(child, `${indent} `);
45
+ }
46
+ for (const name of files) {
47
+ console.log(`${indent}${name}`);
48
+ }
49
+ }
50
+ function registerIndexCommand(program) {
51
+ program
52
+ .command("index")
53
+ .description("Index project files for semantic search")
54
+ .addHelpText("after", `\n${help_text_js_1.PROJECT_ROOT_COMMAND_HELP}\n`)
55
+ .option("--full", "force a full reindex")
56
+ .option("--dry-run", "show what would change without indexing")
57
+ .option("--status", "show indexing status for the current project")
58
+ .option("--tree", "show indexed file tree (use with --status)")
59
+ .option("--json", "output status as JSON (use with --status)")
60
+ .action(async (options) => {
61
+ const resolvedProjectPath = process.cwd();
62
+ const dataDir = node_path_1.default.join(resolvedProjectPath, ".indexer-cli");
63
+ const dbPath = node_path_1.default.join(dataDir, "db.sqlite");
64
+ const vectorsPath = node_path_1.default.join(dataDir, "vectors");
65
+ (0, logger_js_1.initLogger)(dataDir);
66
+ config_js_1.config.load(dataDir);
67
+ const metadata = new sqlite_js_1.SqliteMetadataStore(dbPath);
68
+ try {
69
+ await metadata.initialize();
70
+ if (options?.status) {
71
+ const snapshot = await metadata.getLatestCompletedSnapshot(types_js_1.DEFAULT_PROJECT_ID);
72
+ if (!snapshot) {
73
+ if (options?.json) {
74
+ console.log(JSON.stringify({ indexed: false }, null, 2));
75
+ }
76
+ else {
77
+ console.log("No completed snapshot found. Run `indexer-cli index` first.");
78
+ }
79
+ return;
80
+ }
81
+ const [files, symbols, dependencies] = await Promise.all([
82
+ metadata.listFiles(types_js_1.DEFAULT_PROJECT_ID, snapshot.id, {}),
83
+ metadata.listSymbols(types_js_1.DEFAULT_PROJECT_ID, snapshot.id),
84
+ metadata.listDependencies(types_js_1.DEFAULT_PROJECT_ID, snapshot.id),
85
+ ]);
86
+ const vectors = new vectors_js_1.LanceDbVectorStore({
87
+ dbPath: vectorsPath,
88
+ vectorSize: config_js_1.config.get("vectorSize"),
89
+ });
90
+ let vectorCount = 0;
91
+ try {
92
+ await vectors.initialize();
93
+ vectorCount = await vectors.countVectors({
94
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
95
+ snapshotId: snapshot.id,
96
+ });
97
+ }
98
+ finally {
99
+ await vectors.close().catch(() => undefined);
100
+ }
101
+ const languages = new Map();
102
+ for (const file of files) {
103
+ const lang = file.languageId || "unknown";
104
+ languages.set(lang, (languages.get(lang) ?? 0) + 1);
105
+ }
106
+ const symbolKinds = new Map();
107
+ for (const symbol of symbols) {
108
+ symbolKinds.set(symbol.kind, (symbolKinds.get(symbol.kind) ?? 0) + 1);
109
+ }
110
+ if (options?.json) {
111
+ const output = {
112
+ indexed: true,
113
+ snapshot: {
114
+ id: snapshot.id,
115
+ status: snapshot.status,
116
+ createdAt: snapshot.createdAt,
117
+ gitRef: snapshot.meta.headCommit ?? null,
118
+ },
119
+ stats: {
120
+ files: files.length,
121
+ symbols: symbols.length,
122
+ chunks: vectorCount,
123
+ dependencies: dependencies.length,
124
+ },
125
+ languages: Object.fromEntries(languages),
126
+ symbolKinds: Object.fromEntries(symbolKinds),
127
+ };
128
+ if (options?.tree) {
129
+ output.files = files.map((f) => f.path);
130
+ }
131
+ console.log(JSON.stringify(output, null, 2));
132
+ return;
133
+ }
134
+ console.log(`Snapshot: ${snapshot.id} (${snapshot.status})`);
135
+ console.log(`Created: ${snapshot.createdAt} | Git ref: ${snapshot.meta.headCommit ?? "unknown"}`);
136
+ console.log(`Files: ${files.length} | Symbols: ${symbols.length} | Chunks: ${vectorCount} | Dependencies: ${dependencies.length}`);
137
+ if (languages.size > 0) {
138
+ const langEntries = Array.from(languages.entries())
139
+ .sort((a, b) => b[1] - a[1])
140
+ .map(([lang, count]) => `${lang}: ${count}`)
141
+ .join(", ");
142
+ console.log(`Languages: ${langEntries}`);
143
+ }
144
+ if (symbolKinds.size > 0) {
145
+ const kindEntries = Array.from(symbolKinds.entries())
146
+ .sort((a, b) => b[1] - a[1])
147
+ .map(([kind, count]) => `${kind}: ${count}`)
148
+ .join(", ");
149
+ console.log(`Symbol kinds: ${kindEntries}`);
150
+ }
151
+ if (options?.tree) {
152
+ console.log("");
153
+ const filePaths = files.map((f) => f.path);
154
+ printFileTree(buildFileTree(filePaths), "");
155
+ }
156
+ return;
157
+ }
158
+ const startedAt = Date.now();
159
+ console.log("Preparing indexer...");
160
+ const vectors = new vectors_js_1.LanceDbVectorStore({
161
+ dbPath: vectorsPath,
162
+ vectorSize: config_js_1.config.get("vectorSize"),
163
+ });
164
+ const embedder = new ollama_js_1.OllamaEmbeddingProvider(config_js_1.config.get("ollamaBaseUrl"), config_js_1.config.get("embeddingModel"), config_js_1.config.get("indexBatchSize"), config_js_1.config.get("indexConcurrency"), config_js_1.config.get("ollamaNumCtx"));
165
+ const git = new git_js_1.SimpleGitOperations();
166
+ let engine = null;
167
+ try {
168
+ engine = new indexer_js_1.IndexerEngine({
169
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
170
+ repoRoot: resolvedProjectPath,
171
+ metadata,
172
+ vectors,
173
+ embedder,
174
+ git,
175
+ languagePlugins: (0, indexer_js_1.createDefaultLanguagePlugins)(),
176
+ });
177
+ const latestSnapshot = await metadata.getLatestCompletedSnapshot(types_js_1.DEFAULT_PROJECT_ID);
178
+ const headCommit = await git.getHeadCommit(resolvedProjectPath);
179
+ const changedFiles = !options?.full && latestSnapshot?.meta.headCommit
180
+ ? (0, git_js_1.mergeGitDiffs)(await git.getChangedFiles(resolvedProjectPath, latestSnapshot.meta.headCommit), await git.getWorkingTreeChanges(resolvedProjectPath))
181
+ : undefined;
182
+ if (options?.dryRun) {
183
+ if (options.full || !latestSnapshot) {
184
+ const plannedFiles = await (0, scanner_js_1.scanProjectFiles)(resolvedProjectPath, [
185
+ ".ts",
186
+ ".tsx",
187
+ ".mts",
188
+ ".cts",
189
+ ".js",
190
+ ".jsx",
191
+ ".mjs",
192
+ ".cjs",
193
+ ".py",
194
+ ".pyi",
195
+ ".cs",
196
+ ".gd",
197
+ ]);
198
+ console.log("Dry run complete.");
199
+ console.log("Mode: full reindex");
200
+ console.log(`Files to index: ${plannedFiles.length}`);
201
+ }
202
+ else {
203
+ const diff = changedFiles ?? {
204
+ added: [],
205
+ modified: [],
206
+ deleted: [],
207
+ };
208
+ console.log("Dry run complete.");
209
+ console.log("Mode: incremental");
210
+ console.log(`Added: ${diff.added.length}`);
211
+ console.log(`Modified: ${diff.modified.length}`);
212
+ console.log(`Deleted: ${diff.deleted.length}`);
213
+ console.log(`Changed total: ${countChangedFiles(diff)}`);
214
+ }
215
+ return;
216
+ }
217
+ await engine.initialize();
218
+ const mode = options?.full
219
+ ? "Running full reindex..."
220
+ : "Running incremental index...";
221
+ console.log(mode);
222
+ const result = await engine.indexProject({
223
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
224
+ repoRoot: resolvedProjectPath,
225
+ gitRef: headCommit ?? "unknown",
226
+ isFullReindex: Boolean(options?.full),
227
+ changedFiles,
228
+ onProgress: (processed, total) => {
229
+ console.log(` ${processed}/${total} files...`);
230
+ },
231
+ });
232
+ const snapshot = await metadata.getSnapshot(result.snapshotId);
233
+ const elapsedMs = Date.now() - startedAt;
234
+ const totalFiles = snapshot?.totalFiles
235
+ ? ` / ${snapshot.totalFiles}`
236
+ : "";
237
+ console.log("Index completed successfully.");
238
+ console.log(` Snapshot: ${result.snapshotId}`);
239
+ console.log(` Files indexed: ${result.filesIndexed}${totalFiles}`);
240
+ console.log(` Chunks created: ${await vectors.countVectors({
241
+ projectId: types_js_1.DEFAULT_PROJECT_ID,
242
+ snapshotId: result.snapshotId
243
+ })}`);
244
+ console.log(` Time elapsed: ${(elapsedMs / 1000).toFixed(2)}s`);
245
+ console.log(` Errors: ${result.errors.length}`);
246
+ if (result.errors.length > 0) {
247
+ for (const error of result.errors) {
248
+ console.error(` - ${error}`);
249
+ }
250
+ }
251
+ }
252
+ catch (error) {
253
+ const message = error instanceof Error ? error.message : String(error);
254
+ console.error(`Indexing failed: ${message}`);
255
+ process.exitCode = 1;
256
+ }
257
+ finally {
258
+ if (engine) {
259
+ await engine.close().catch(() => undefined);
260
+ }
261
+ else {
262
+ await Promise.allSettled([vectors.close(), embedder.close()]);
263
+ }
264
+ }
265
+ }
266
+ finally {
267
+ await metadata.close().catch(() => undefined);
268
+ }
269
+ });
270
+ }
271
+ //# sourceMappingURL=index.js.map