graph-indexer 2.1.1 → 3.0.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 (131) hide show
  1. package/CHANGELOG.md +312 -1
  2. package/README.md +236 -312
  3. package/SECURITY.md +53 -58
  4. package/bin/graph-indexer.mjs +251 -0
  5. package/integrations/claude-code/.claude-plugin/plugin.json +9 -0
  6. package/integrations/claude-code/.mcp.json +8 -0
  7. package/integrations/claude-code/agents/code-structure.md +22 -0
  8. package/integrations/claude-code/hooks/gi-hook.mjs +103 -0
  9. package/integrations/claude-code/hooks/hooks.json +16 -0
  10. package/integrations/opencode/graph-indexer.js +129 -0
  11. package/package.json +32 -109
  12. package/src/cli/helper.mjs +67 -0
  13. package/src/cli/hook.mjs +366 -0
  14. package/src/cli/init.mjs +272 -0
  15. package/src/cli/resident.mjs +185 -0
  16. package/src/index/discover.mjs +128 -0
  17. package/src/index/fingerprint.mjs +30 -0
  18. package/src/index/graph.mjs +61 -0
  19. package/src/index/indexer.mjs +476 -0
  20. package/src/index/modules.mjs +332 -0
  21. package/src/index/resolver.mjs +961 -0
  22. package/src/mcp/render.mjs +60 -0
  23. package/src/mcp/server.mjs +147 -0
  24. package/src/mcp/tools.mjs +974 -0
  25. package/src/parse/arity.mjs +153 -0
  26. package/src/parse/extract.mjs +1038 -0
  27. package/src/parse/lang/csharp.mjs +106 -0
  28. package/src/parse/lang/ecma.mjs +438 -0
  29. package/src/parse/lang/go.mjs +194 -0
  30. package/src/parse/lang/jvm.mjs +118 -0
  31. package/src/parse/lang/kotlin.mjs +97 -0
  32. package/src/parse/lang/misc.mjs +115 -0
  33. package/src/parse/lang/native.mjs +126 -0
  34. package/src/parse/lang/python.mjs +153 -0
  35. package/src/parse/lang/rust.mjs +157 -0
  36. package/src/parse/lang/scripting.mjs +219 -0
  37. package/src/parse/languages.mjs +48 -0
  38. package/src/parse/runtime.mjs +56 -0
  39. package/src/query/check.mjs +345 -0
  40. package/src/query/facts.mjs +323 -0
  41. package/src/query/intel.mjs +683 -0
  42. package/src/query/read.mjs +81 -0
  43. package/src/query/testcmd.mjs +130 -0
  44. package/src/query/textsearch.mjs +178 -0
  45. package/src/search/search.mjs +210 -0
  46. package/src/search/tokenize.mjs +188 -0
  47. package/src/store/db.mjs +169 -0
  48. package/src/util/git.mjs +30 -0
  49. package/src/util/paths.mjs +63 -0
  50. package/src/util/regex.mjs +2 -0
  51. package/vendor/grammars/bash.wasm.gz +0 -0
  52. package/vendor/grammars/c.wasm.gz +0 -0
  53. package/vendor/grammars/c_sharp.wasm.gz +0 -0
  54. package/vendor/grammars/cpp.wasm.gz +0 -0
  55. package/vendor/grammars/css.wasm.gz +0 -0
  56. package/vendor/grammars/go.wasm.gz +0 -0
  57. package/vendor/grammars/java.wasm.gz +0 -0
  58. package/vendor/grammars/javascript.wasm.gz +0 -0
  59. package/vendor/grammars/kotlin.wasm.gz +0 -0
  60. package/vendor/grammars/manifest.json +148 -0
  61. package/vendor/grammars/php.wasm.gz +0 -0
  62. package/vendor/grammars/python.wasm.gz +0 -0
  63. package/vendor/grammars/ruby.wasm.gz +0 -0
  64. package/vendor/grammars/rust.wasm.gz +0 -0
  65. package/vendor/grammars/scala.wasm.gz +0 -0
  66. package/vendor/grammars/tsx.wasm.gz +0 -0
  67. package/vendor/grammars/typescript.wasm.gz +0 -0
  68. package/vendor/web-tree-sitter/web-tree-sitter.js +3980 -0
  69. package/vendor/web-tree-sitter/web-tree-sitter.wasm +0 -0
  70. package/cli-ui.mjs +0 -78
  71. package/colbert.mjs +0 -168
  72. package/config.mjs +0 -494
  73. package/daemon-ctl.mjs +0 -175
  74. package/daemon-lock.mjs +0 -69
  75. package/embedders/python/mlx_embed_server.py +0 -61
  76. package/embedders/python/requirements-mlx.txt +0 -5
  77. package/embedders/setup-mlx.mjs +0 -110
  78. package/embeddings.mjs +0 -571
  79. package/engine/binary.mjs +0 -437
  80. package/engine/memory.mjs +0 -1003
  81. package/engine/sqlite.mjs +0 -1136
  82. package/enrichment.mjs +0 -521
  83. package/git-signals.mjs +0 -248
  84. package/indexer.mjs +0 -546
  85. package/init.mjs +0 -1809
  86. package/layout.mjs +0 -123
  87. package/mcp/centrality.mjs +0 -117
  88. package/mcp/format.mjs +0 -61
  89. package/mcp/resolver.mjs +0 -116
  90. package/mcp/symbolgraph.mjs +0 -137
  91. package/mcp/taint.mjs +0 -225
  92. package/mcp/tools.mjs +0 -1582
  93. package/mcp/topology.mjs +0 -676
  94. package/mcp-server.mjs +0 -197
  95. package/parse/extractor.mjs +0 -628
  96. package/parse/imports.mjs +0 -365
  97. package/parse/interprocedural.mjs +0 -134
  98. package/parse/languages.mjs +0 -253
  99. package/parse/metadata.mjs +0 -701
  100. package/parse/routes.mjs +0 -327
  101. package/parse/scip.mjs +0 -391
  102. package/parse/taint-patterns.mjs +0 -119
  103. package/prompts/CORE.md +0 -91
  104. package/prompts/DOMAIN_TEMPLATE.md +0 -46
  105. package/prompts/INTEGRATION.md +0 -123
  106. package/prompts/frameworks/ANDROID.md +0 -17
  107. package/prompts/frameworks/ASPNET_CORE.md +0 -19
  108. package/prompts/frameworks/FASTAPI_DJANGO.md +0 -20
  109. package/prompts/frameworks/LARAVEL_SYMFONY.md +0 -22
  110. package/prompts/frameworks/NODE_EXPRESS_NESTJS.md +0 -19
  111. package/prompts/frameworks/RAILS.md +0 -20
  112. package/prompts/frameworks/REACT.md +0 -20
  113. package/prompts/frameworks/SPRING_BOOT.md +0 -20
  114. package/prompts/languages/BASH.md +0 -22
  115. package/prompts/languages/C.md +0 -21
  116. package/prompts/languages/CSHARP.md +0 -24
  117. package/prompts/languages/CSS_SCSS.md +0 -22
  118. package/prompts/languages/GO.md +0 -24
  119. package/prompts/languages/JAVA.md +0 -23
  120. package/prompts/languages/JAVASCRIPT_TYPESCRIPT.md +0 -24
  121. package/prompts/languages/KOTLIN.md +0 -24
  122. package/prompts/languages/PHP.md +0 -23
  123. package/prompts/languages/PYTHON.md +0 -23
  124. package/prompts/languages/RUBY.md +0 -23
  125. package/prompts/languages/RUST.md +0 -21
  126. package/prompts/languages/SWIFT.md +0 -21
  127. package/seal.mjs +0 -400
  128. package/search-core.mjs +0 -777
  129. package/search-sparse.mjs +0 -183
  130. package/storage.mjs +0 -73
  131. package/watch-daemon.mjs +0 -289
package/mcp-server.mjs DELETED
@@ -1,197 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * @file mcp-server.mjs
4
- * @description MCP server bootstrap. Resolves configuration, selects the storage
5
- * backend (in-memory by default, SQLite when configured), registers
6
- * the tool surface (mcp/tools.mjs) and connects over stdio. All
7
- * retrieval logic lives in the store + search-core; all tool logic in
8
- * mcp/tools.mjs — this file is wiring only.
9
- * @author MaquinaTech <https://github.com/MaquinaTech>
10
- * @copyright (c) 2026 MaquinaTech. All rights reserved.
11
- * @license MIT
12
- */
13
- import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
14
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
- import fs from 'fs';
16
- import path from 'path';
17
- import { fileURLToPath } from 'url';
18
- import { spawn } from 'child_process';
19
- import { resolveConfig, describeConfig, configNotices } from './config.mjs';
20
- import { ensureDataDir, migrateLegacyLayout } from './layout.mjs';
21
- import { daemonStatus } from './daemon-lock.mjs';
22
- import { createStore } from './storage.mjs';
23
- import { registerTools } from './mcp/tools.mjs';
24
- import { ensureLanguagesReady } from './parse/languages.mjs';
25
- import { createEmbedder, readEmbedMeta } from './embeddings.mjs';
26
- import { loadGitSignals } from './git-signals.mjs';
27
- import { installEgressGuard } from './seal.mjs';
28
-
29
- let config;
30
- try {
31
- config = resolveConfig();
32
- } catch (err) {
33
- if (err && err.name === 'SealViolation') { process.stderr.write(`🔒 ${err.message}\n`); process.exit(2); }
34
- throw err;
35
- }
36
- // F1: install the deny-by-default egress guard before the store / embedder / providers load.
37
- if (config.sealed !== 'off') {
38
- installEgressGuard({ allow: config.sealed === 'local' ? ['loopback'] : [] });
39
- }
40
- const PROJECT_ROOT = config.projectRoot;
41
- const PID_FILE = config.pidFile;
42
- const PACKAGE_DIR = path.dirname(fileURLToPath(import.meta.url));
43
-
44
- ensureDataDir(PROJECT_ROOT);
45
- migrateLegacyLayout(PROJECT_ROOT);
46
-
47
- // get_file_skeleton parses on demand at query time — grammars must be resolved
48
- // (and, outside sealed mode, installed if this server is starting before the
49
- // first `idx-index` run) before the transport connects and starts serving tools.
50
- await ensureLanguagesReady({
51
- projectRoot: PROJECT_ROOT,
52
- enabledLangs: config.languages,
53
- autoInstall: config.sealed === 'off',
54
- log: (msg) => process.stderr.write(msg + '\n'),
55
- });
56
-
57
- function readPackageVersion() {
58
- try {
59
- return JSON.parse(fs.readFileSync(path.join(PACKAGE_DIR, 'package.json'), 'utf-8')).version || '0.0.0';
60
- } catch { return '0.0.0'; }
61
- }
62
-
63
- // ─── Watch-daemon orchestration (both backends) ─────────────────────────────────
64
- // The incremental watcher keeps the configured backend fresh: it rewrites the
65
- // JSON snapshot for the in-memory engine (picked up below via an fs watch), and
66
- // applies per-file WAL transactions for SQLite (picked up by the store via
67
- // PRAGMA data_version). Either way, a long-running MCP server stays consistent
68
- // with the working tree without restarts or full re-indexes.
69
- function ensureDaemonRunning() {
70
- // The daemon owns the PID lock exclusively (it acquires it atomically on
71
- // startup — see daemon-lock.mjs). We only check whether one is already live;
72
- // if not, we spawn it detached. Even if two servers race here, the losing
73
- // daemon fails to acquire the lock and exits, so never more than one runs.
74
- const { running, pid } = daemonStatus(PID_FILE);
75
- if (running) { process.stderr.write(`✅ Daemon already active (PID: ${pid}).\n`); return; }
76
-
77
- const daemonPath = path.join(PACKAGE_DIR, 'watch-daemon.mjs');
78
- process.stderr.write(`🚀 Starting Watcher Daemon...\n Log: ${config.logFile}\n`);
79
- let logFd;
80
- try { logFd = fs.openSync(config.logFile, 'a'); } catch { logFd = null; }
81
- const child = spawn(process.execPath, [daemonPath], {
82
- detached: true,
83
- stdio: logFd !== null ? ['ignore', logFd, logFd] : 'ignore',
84
- env: { ...process.env, MCP_PROJECT_ROOT: PROJECT_ROOT },
85
- });
86
- child.unref();
87
- if (logFd !== null) fs.closeSync(logFd);
88
- }
89
-
90
- // ─── Boot ──────────────────────────────────────────────────────────────────────
91
-
92
- ensureDaemonRunning();
93
-
94
- const version = readPackageVersion();
95
- const server = new McpServer({ name: 'graph-indexer', version });
96
-
97
- const db = await createStore(config, { cacheEmbeddings: false });
98
- const backend = db.backend;
99
-
100
- process.stderr.write('⚙️ Effective configuration:\n');
101
- for (const line of describeConfig(config, { backend })) process.stderr.write(` ${line}\n`);
102
- for (const notice of configNotices(config)) process.stderr.write(`⚠️ ${notice}\n`);
103
-
104
- try { db.load(); } catch (err) { process.stderr.write(`⏳ Waiting for initial indexing… (${err.message})\n`); }
105
-
106
- // In-memory backend: the daemon is a separate process that rewrites
107
- // code-index.json — without reloading, this server would answer from a stale
108
- // snapshot until restart. (The SQLite store refreshes itself per query via
109
- // PRAGMA data_version, so no watcher is needed there.)
110
- if (backend !== 'sqlite' && typeof db.reload === 'function') {
111
- let reloadTimer = null;
112
- const scheduleReload = () => {
113
- if (reloadTimer) clearTimeout(reloadTimer);
114
- reloadTimer = setTimeout(() => {
115
- reloadTimer = null;
116
- try {
117
- db.reload();
118
- process.stderr.write('🔄 Index reloaded from disk (daemon update).\n');
119
- } catch (err) {
120
- process.stderr.write(`⚠️ Index reload failed: ${err.message}\n`);
121
- }
122
- }, 1000);
123
- };
124
- try {
125
- fs.watch(path.dirname(config.indexPath), (event, name) => {
126
- if (name === path.basename(config.indexPath)) scheduleReload();
127
- });
128
- } catch { /* fs.watch unavailable — index stays load-time static */ }
129
- }
130
-
131
- process.on('SIGTERM', () => { db.close(); process.exit(0); });
132
- process.on('SIGINT', () => { db.close(); process.exit(0); });
133
-
134
- // ─── Graph dependency resource ─────────────────────────────────────────────────
135
- server.resource(
136
- 'graph-dependencies',
137
- new ResourceTemplate('graph://dependencies/{file_path}', {
138
- list: async () => ({
139
- resources: Object.keys(db.graph.dependencies).map(fp => ({
140
- uri: `graph://dependencies/${encodeURIComponent(fp)}`,
141
- name: fp, mimeType: 'text/markdown',
142
- description: `Dependency topology for ${fp}`,
143
- }))
144
- })
145
- }),
146
- async (uri, { file_path }) => {
147
- const p = decodeURIComponent(String(file_path));
148
- const deps = db.getDependencies(p);
149
- const usedBy = db.getImportedBy(p);
150
- const md = [
151
- `# Dependency Topology: \`${p}\``, '',
152
- `## Imports (${deps.length})`,
153
- deps.length ? deps.map(d => `- \`${d}\``).join('\n') : '_No local imports_', '',
154
- `## Imported By (${usedBy.length})`,
155
- usedBy.length ? usedBy.map(d => `- \`${d}\``).join('\n') : '_No files import this_',
156
- ].join('\n');
157
- return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text: md }] };
158
- }
159
- );
160
-
161
- // ─── Query embedder ────────────────────────────────────────────────────────────
162
- // Query with the SAME provider/model the index was built with (stamped in the
163
- // embeddings-bin sidecar). No stamp → an index from an older version: keep the
164
- // legacy behaviour (try Ollama, fall back to lexical). The local pipeline loads
165
- // lazily on first query, so an unused provider costs nothing at startup.
166
- const embedMeta = readEmbedMeta(config.embeddingPath);
167
- const embedder = await createEmbedder(
168
- config,
169
- embedMeta?.provider
170
- ? { provider: embedMeta.provider, model: embedMeta.model }
171
- : { provider: config.embeddingsEnabled ? 'ollama' : 'off', model: config.embedModel }
172
- );
173
-
174
- // ─── Git signals (air-gapped sidecar; blast-radius hint + opt-in rank boost) ────
175
- const gitSignals = config.gitSignals ? loadGitSignals(config.gitSignalsPath) : null;
176
-
177
- // ─── Tools ───────────────────────────────────────────────────────────────────
178
- registerTools(server, db, {
179
- projectRoot: PROJECT_ROOT,
180
- artifactPath: backend === 'sqlite' ? config.sqlitePath : config.indexPath,
181
- pidFile: PID_FILE,
182
- embeddingsEnabled: config.embeddingsEnabled && embedder.provider !== 'off',
183
- embedder,
184
- rerank: config.rerank,
185
- hyde: config.hyde,
186
- ollamaHost: config.ollamaHost,
187
- llmProvider: config.llmProvider,
188
- mlxLmHost: config.mlxLmHost,
189
- gitSignals,
190
- gitRankBoost: config.gitRankBoost,
191
- sealed: config.sealed,
192
- ranker: config.ranker,
193
- });
194
-
195
- const transport = new StdioServerTransport();
196
- await server.connect(transport);
197
- process.stderr.write(`✅ graph-indexer MCP server running (v${version}, ${backend} backend).\n`);