@veewo/gitnexus 1.3.4

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 (231) hide show
  1. package/README.md +234 -0
  2. package/dist/benchmark/agent-context/evaluators.d.ts +9 -0
  3. package/dist/benchmark/agent-context/evaluators.js +196 -0
  4. package/dist/benchmark/agent-context/evaluators.test.d.ts +1 -0
  5. package/dist/benchmark/agent-context/evaluators.test.js +39 -0
  6. package/dist/benchmark/agent-context/io.d.ts +2 -0
  7. package/dist/benchmark/agent-context/io.js +23 -0
  8. package/dist/benchmark/agent-context/io.test.d.ts +1 -0
  9. package/dist/benchmark/agent-context/io.test.js +19 -0
  10. package/dist/benchmark/agent-context/report.d.ts +2 -0
  11. package/dist/benchmark/agent-context/report.js +59 -0
  12. package/dist/benchmark/agent-context/report.test.d.ts +1 -0
  13. package/dist/benchmark/agent-context/report.test.js +85 -0
  14. package/dist/benchmark/agent-context/runner.d.ts +46 -0
  15. package/dist/benchmark/agent-context/runner.js +111 -0
  16. package/dist/benchmark/agent-context/runner.test.d.ts +1 -0
  17. package/dist/benchmark/agent-context/runner.test.js +79 -0
  18. package/dist/benchmark/agent-context/tool-runner.d.ts +7 -0
  19. package/dist/benchmark/agent-context/tool-runner.js +18 -0
  20. package/dist/benchmark/agent-context/tool-runner.test.d.ts +1 -0
  21. package/dist/benchmark/agent-context/tool-runner.test.js +11 -0
  22. package/dist/benchmark/agent-context/types.d.ts +40 -0
  23. package/dist/benchmark/agent-context/types.js +1 -0
  24. package/dist/benchmark/analyze-runner.d.ts +16 -0
  25. package/dist/benchmark/analyze-runner.js +51 -0
  26. package/dist/benchmark/analyze-runner.test.d.ts +1 -0
  27. package/dist/benchmark/analyze-runner.test.js +37 -0
  28. package/dist/benchmark/evaluators.d.ts +6 -0
  29. package/dist/benchmark/evaluators.js +10 -0
  30. package/dist/benchmark/evaluators.test.d.ts +1 -0
  31. package/dist/benchmark/evaluators.test.js +12 -0
  32. package/dist/benchmark/io.d.ts +7 -0
  33. package/dist/benchmark/io.js +25 -0
  34. package/dist/benchmark/io.test.d.ts +1 -0
  35. package/dist/benchmark/io.test.js +35 -0
  36. package/dist/benchmark/neonspark-candidates.d.ts +19 -0
  37. package/dist/benchmark/neonspark-candidates.js +94 -0
  38. package/dist/benchmark/neonspark-candidates.test.d.ts +1 -0
  39. package/dist/benchmark/neonspark-candidates.test.js +43 -0
  40. package/dist/benchmark/neonspark-materialize.d.ts +19 -0
  41. package/dist/benchmark/neonspark-materialize.js +111 -0
  42. package/dist/benchmark/neonspark-materialize.test.d.ts +1 -0
  43. package/dist/benchmark/neonspark-materialize.test.js +124 -0
  44. package/dist/benchmark/neonspark-sync.d.ts +3 -0
  45. package/dist/benchmark/neonspark-sync.js +53 -0
  46. package/dist/benchmark/neonspark-sync.test.d.ts +1 -0
  47. package/dist/benchmark/neonspark-sync.test.js +20 -0
  48. package/dist/benchmark/report.d.ts +1 -0
  49. package/dist/benchmark/report.js +7 -0
  50. package/dist/benchmark/runner.d.ts +48 -0
  51. package/dist/benchmark/runner.js +302 -0
  52. package/dist/benchmark/runner.test.d.ts +1 -0
  53. package/dist/benchmark/runner.test.js +50 -0
  54. package/dist/benchmark/scoring.d.ts +16 -0
  55. package/dist/benchmark/scoring.js +27 -0
  56. package/dist/benchmark/scoring.test.d.ts +1 -0
  57. package/dist/benchmark/scoring.test.js +24 -0
  58. package/dist/benchmark/tool-runner.d.ts +6 -0
  59. package/dist/benchmark/tool-runner.js +17 -0
  60. package/dist/benchmark/types.d.ts +36 -0
  61. package/dist/benchmark/types.js +1 -0
  62. package/dist/cli/ai-context.d.ts +22 -0
  63. package/dist/cli/ai-context.js +184 -0
  64. package/dist/cli/ai-context.test.d.ts +1 -0
  65. package/dist/cli/ai-context.test.js +30 -0
  66. package/dist/cli/analyze-multi-scope-regression.test.d.ts +1 -0
  67. package/dist/cli/analyze-multi-scope-regression.test.js +22 -0
  68. package/dist/cli/analyze-options.d.ts +7 -0
  69. package/dist/cli/analyze-options.js +56 -0
  70. package/dist/cli/analyze-options.test.d.ts +1 -0
  71. package/dist/cli/analyze-options.test.js +36 -0
  72. package/dist/cli/analyze.d.ts +14 -0
  73. package/dist/cli/analyze.js +384 -0
  74. package/dist/cli/augment.d.ts +13 -0
  75. package/dist/cli/augment.js +33 -0
  76. package/dist/cli/benchmark-agent-context.d.ts +29 -0
  77. package/dist/cli/benchmark-agent-context.js +61 -0
  78. package/dist/cli/benchmark-agent-context.test.d.ts +1 -0
  79. package/dist/cli/benchmark-agent-context.test.js +80 -0
  80. package/dist/cli/benchmark-unity.d.ts +15 -0
  81. package/dist/cli/benchmark-unity.js +31 -0
  82. package/dist/cli/benchmark-unity.test.d.ts +1 -0
  83. package/dist/cli/benchmark-unity.test.js +18 -0
  84. package/dist/cli/claude-hooks.d.ts +22 -0
  85. package/dist/cli/claude-hooks.js +97 -0
  86. package/dist/cli/clean.d.ts +10 -0
  87. package/dist/cli/clean.js +60 -0
  88. package/dist/cli/eval-server.d.ts +30 -0
  89. package/dist/cli/eval-server.js +372 -0
  90. package/dist/cli/index.d.ts +2 -0
  91. package/dist/cli/index.js +182 -0
  92. package/dist/cli/list.d.ts +6 -0
  93. package/dist/cli/list.js +33 -0
  94. package/dist/cli/mcp.d.ts +8 -0
  95. package/dist/cli/mcp.js +34 -0
  96. package/dist/cli/repo-manager-alias.test.d.ts +1 -0
  97. package/dist/cli/repo-manager-alias.test.js +40 -0
  98. package/dist/cli/scope-filter.test.d.ts +1 -0
  99. package/dist/cli/scope-filter.test.js +49 -0
  100. package/dist/cli/serve.d.ts +4 -0
  101. package/dist/cli/serve.js +6 -0
  102. package/dist/cli/setup.d.ts +8 -0
  103. package/dist/cli/setup.js +311 -0
  104. package/dist/cli/setup.test.d.ts +1 -0
  105. package/dist/cli/setup.test.js +31 -0
  106. package/dist/cli/status.d.ts +6 -0
  107. package/dist/cli/status.js +27 -0
  108. package/dist/cli/tool.d.ts +40 -0
  109. package/dist/cli/tool.js +94 -0
  110. package/dist/cli/version.test.d.ts +1 -0
  111. package/dist/cli/version.test.js +19 -0
  112. package/dist/cli/wiki.d.ts +15 -0
  113. package/dist/cli/wiki.js +361 -0
  114. package/dist/config/ignore-service.d.ts +1 -0
  115. package/dist/config/ignore-service.js +210 -0
  116. package/dist/config/supported-languages.d.ts +12 -0
  117. package/dist/config/supported-languages.js +15 -0
  118. package/dist/core/augmentation/engine.d.ts +26 -0
  119. package/dist/core/augmentation/engine.js +213 -0
  120. package/dist/core/embeddings/embedder.d.ts +60 -0
  121. package/dist/core/embeddings/embedder.js +251 -0
  122. package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
  123. package/dist/core/embeddings/embedding-pipeline.js +329 -0
  124. package/dist/core/embeddings/index.d.ts +9 -0
  125. package/dist/core/embeddings/index.js +9 -0
  126. package/dist/core/embeddings/text-generator.d.ts +24 -0
  127. package/dist/core/embeddings/text-generator.js +182 -0
  128. package/dist/core/embeddings/types.d.ts +87 -0
  129. package/dist/core/embeddings/types.js +32 -0
  130. package/dist/core/graph/graph.d.ts +2 -0
  131. package/dist/core/graph/graph.js +66 -0
  132. package/dist/core/graph/types.d.ts +61 -0
  133. package/dist/core/graph/types.js +1 -0
  134. package/dist/core/ingestion/ast-cache.d.ts +11 -0
  135. package/dist/core/ingestion/ast-cache.js +34 -0
  136. package/dist/core/ingestion/call-processor.d.ts +15 -0
  137. package/dist/core/ingestion/call-processor.js +327 -0
  138. package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
  139. package/dist/core/ingestion/cluster-enricher.js +170 -0
  140. package/dist/core/ingestion/community-processor.d.ts +39 -0
  141. package/dist/core/ingestion/community-processor.js +312 -0
  142. package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
  143. package/dist/core/ingestion/entry-point-scoring.js +260 -0
  144. package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
  145. package/dist/core/ingestion/filesystem-walker.js +80 -0
  146. package/dist/core/ingestion/framework-detection.d.ts +39 -0
  147. package/dist/core/ingestion/framework-detection.js +235 -0
  148. package/dist/core/ingestion/heritage-processor.d.ts +20 -0
  149. package/dist/core/ingestion/heritage-processor.js +197 -0
  150. package/dist/core/ingestion/import-processor.d.ts +38 -0
  151. package/dist/core/ingestion/import-processor.js +778 -0
  152. package/dist/core/ingestion/parsing-processor.d.ts +15 -0
  153. package/dist/core/ingestion/parsing-processor.js +291 -0
  154. package/dist/core/ingestion/pipeline.d.ts +5 -0
  155. package/dist/core/ingestion/pipeline.js +323 -0
  156. package/dist/core/ingestion/process-processor.d.ts +51 -0
  157. package/dist/core/ingestion/process-processor.js +309 -0
  158. package/dist/core/ingestion/scope-filter.d.ts +25 -0
  159. package/dist/core/ingestion/scope-filter.js +100 -0
  160. package/dist/core/ingestion/structure-processor.d.ts +2 -0
  161. package/dist/core/ingestion/structure-processor.js +36 -0
  162. package/dist/core/ingestion/symbol-table.d.ts +33 -0
  163. package/dist/core/ingestion/symbol-table.js +38 -0
  164. package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -0
  165. package/dist/core/ingestion/tree-sitter-queries.js +398 -0
  166. package/dist/core/ingestion/utils.d.ts +10 -0
  167. package/dist/core/ingestion/utils.js +50 -0
  168. package/dist/core/ingestion/workers/parse-worker.d.ts +59 -0
  169. package/dist/core/ingestion/workers/parse-worker.js +672 -0
  170. package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
  171. package/dist/core/ingestion/workers/worker-pool.js +120 -0
  172. package/dist/core/kuzu/csv-generator.d.ts +29 -0
  173. package/dist/core/kuzu/csv-generator.js +336 -0
  174. package/dist/core/kuzu/kuzu-adapter.d.ts +101 -0
  175. package/dist/core/kuzu/kuzu-adapter.js +753 -0
  176. package/dist/core/kuzu/schema.d.ts +53 -0
  177. package/dist/core/kuzu/schema.js +407 -0
  178. package/dist/core/search/bm25-index.d.ts +23 -0
  179. package/dist/core/search/bm25-index.js +95 -0
  180. package/dist/core/search/hybrid-search.d.ts +49 -0
  181. package/dist/core/search/hybrid-search.js +118 -0
  182. package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
  183. package/dist/core/tree-sitter/parser-loader.js +44 -0
  184. package/dist/core/wiki/generator.d.ts +110 -0
  185. package/dist/core/wiki/generator.js +786 -0
  186. package/dist/core/wiki/graph-queries.d.ts +80 -0
  187. package/dist/core/wiki/graph-queries.js +238 -0
  188. package/dist/core/wiki/html-viewer.d.ts +10 -0
  189. package/dist/core/wiki/html-viewer.js +297 -0
  190. package/dist/core/wiki/llm-client.d.ts +40 -0
  191. package/dist/core/wiki/llm-client.js +162 -0
  192. package/dist/core/wiki/prompts.d.ts +53 -0
  193. package/dist/core/wiki/prompts.js +174 -0
  194. package/dist/lib/utils.d.ts +1 -0
  195. package/dist/lib/utils.js +3 -0
  196. package/dist/mcp/core/embedder.d.ts +27 -0
  197. package/dist/mcp/core/embedder.js +108 -0
  198. package/dist/mcp/core/kuzu-adapter.d.ts +34 -0
  199. package/dist/mcp/core/kuzu-adapter.js +231 -0
  200. package/dist/mcp/local/local-backend.d.ts +160 -0
  201. package/dist/mcp/local/local-backend.js +1646 -0
  202. package/dist/mcp/resources.d.ts +31 -0
  203. package/dist/mcp/resources.js +407 -0
  204. package/dist/mcp/server.d.ts +23 -0
  205. package/dist/mcp/server.js +251 -0
  206. package/dist/mcp/staleness.d.ts +15 -0
  207. package/dist/mcp/staleness.js +29 -0
  208. package/dist/mcp/tools.d.ts +24 -0
  209. package/dist/mcp/tools.js +195 -0
  210. package/dist/server/api.d.ts +10 -0
  211. package/dist/server/api.js +344 -0
  212. package/dist/server/mcp-http.d.ts +13 -0
  213. package/dist/server/mcp-http.js +100 -0
  214. package/dist/storage/git.d.ts +6 -0
  215. package/dist/storage/git.js +32 -0
  216. package/dist/storage/repo-manager.d.ts +125 -0
  217. package/dist/storage/repo-manager.js +257 -0
  218. package/dist/types/pipeline.d.ts +34 -0
  219. package/dist/types/pipeline.js +18 -0
  220. package/hooks/claude/gitnexus-hook.cjs +135 -0
  221. package/hooks/claude/pre-tool-use.sh +78 -0
  222. package/hooks/claude/session-start.sh +42 -0
  223. package/package.json +92 -0
  224. package/skills/gitnexus-cli.md +82 -0
  225. package/skills/gitnexus-debugging.md +89 -0
  226. package/skills/gitnexus-exploring.md +78 -0
  227. package/skills/gitnexus-guide.md +64 -0
  228. package/skills/gitnexus-impact-analysis.md +97 -0
  229. package/skills/gitnexus-refactoring.md +121 -0
  230. package/vendor/leiden/index.cjs +355 -0
  231. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Setup Command
3
+ *
4
+ * One-time global MCP configuration writer.
5
+ * Detects installed AI editors and writes the appropriate MCP config
6
+ * so the GitNexus MCP server is available in all projects.
7
+ */
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ import { fileURLToPath } from 'url';
12
+ import { getGlobalDir } from '../storage/repo-manager.js';
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ /**
16
+ * The MCP server entry for all editors.
17
+ * On Windows, npx must be invoked via cmd /c since it's a .cmd script.
18
+ */
19
+ function getMcpEntry() {
20
+ if (process.platform === 'win32') {
21
+ return {
22
+ command: 'cmd',
23
+ args: ['/c', 'npx', '-y', 'gitnexus@latest', 'mcp'],
24
+ };
25
+ }
26
+ return {
27
+ command: 'npx',
28
+ args: ['-y', 'gitnexus@latest', 'mcp'],
29
+ };
30
+ }
31
+ /**
32
+ * Merge gitnexus entry into an existing MCP config JSON object.
33
+ * Returns the updated config.
34
+ */
35
+ function mergeMcpConfig(existing) {
36
+ if (!existing || typeof existing !== 'object') {
37
+ existing = {};
38
+ }
39
+ if (!existing.mcpServers || typeof existing.mcpServers !== 'object') {
40
+ existing.mcpServers = {};
41
+ }
42
+ existing.mcpServers.gitnexus = getMcpEntry();
43
+ return existing;
44
+ }
45
+ /**
46
+ * Try to read a JSON file, returning null if it doesn't exist or is invalid.
47
+ */
48
+ async function readJsonFile(filePath) {
49
+ try {
50
+ const raw = await fs.readFile(filePath, 'utf-8');
51
+ return JSON.parse(raw);
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ /**
58
+ * Write JSON to a file, creating parent directories if needed.
59
+ */
60
+ async function writeJsonFile(filePath, data) {
61
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
62
+ await fs.writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
63
+ }
64
+ /**
65
+ * Check if a directory exists
66
+ */
67
+ async function dirExists(dirPath) {
68
+ try {
69
+ const stat = await fs.stat(dirPath);
70
+ return stat.isDirectory();
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ // ─── Editor-specific setup ─────────────────────────────────────────
77
+ async function setupCursor(result) {
78
+ const cursorDir = path.join(os.homedir(), '.cursor');
79
+ if (!(await dirExists(cursorDir))) {
80
+ result.skipped.push('Cursor (not installed)');
81
+ return;
82
+ }
83
+ const mcpPath = path.join(cursorDir, 'mcp.json');
84
+ try {
85
+ const existing = await readJsonFile(mcpPath);
86
+ const updated = mergeMcpConfig(existing);
87
+ await writeJsonFile(mcpPath, updated);
88
+ result.configured.push('Cursor');
89
+ }
90
+ catch (err) {
91
+ result.errors.push(`Cursor: ${err.message}`);
92
+ }
93
+ }
94
+ async function setupClaudeCode(result) {
95
+ const claudeDir = path.join(os.homedir(), '.claude');
96
+ const hasClaude = await dirExists(claudeDir);
97
+ if (!hasClaude) {
98
+ result.skipped.push('Claude Code (not installed)');
99
+ return;
100
+ }
101
+ // Claude Code uses a JSON settings file at ~/.claude.json or claude mcp add
102
+ console.log('');
103
+ console.log(' Claude Code detected. Run this command to add GitNexus MCP:');
104
+ console.log('');
105
+ console.log(' claude mcp add gitnexus -- npx -y gitnexus mcp');
106
+ console.log('');
107
+ result.configured.push('Claude Code (MCP manual step printed)');
108
+ }
109
+ /**
110
+ * Install GitNexus global skills to ~/.agents/skills/gitnexus/
111
+ * Users can create editor-specific symlinks if they want.
112
+ */
113
+ async function installGlobalAgentSkills(result) {
114
+ const skillsDir = path.join(os.homedir(), '.agents', 'skills', 'gitnexus');
115
+ try {
116
+ const installed = await installSkillsTo(skillsDir);
117
+ if (installed.length > 0) {
118
+ result.configured.push(`Global agent skills (${installed.length} skills → ~/.agents/skills/gitnexus/)`);
119
+ }
120
+ }
121
+ catch (err) {
122
+ result.errors.push(`Global agent skills: ${err.message}`);
123
+ }
124
+ }
125
+ /**
126
+ * Install GitNexus hooks to ~/.claude/settings.json for Claude Code.
127
+ * Merges hook config without overwriting existing hooks.
128
+ */
129
+ async function installClaudeCodeHooks(result) {
130
+ const claudeDir = path.join(os.homedir(), '.claude');
131
+ if (!(await dirExists(claudeDir)))
132
+ return;
133
+ const settingsPath = path.join(claudeDir, 'settings.json');
134
+ // Source hooks bundled within the gitnexus package (hooks/claude/)
135
+ const pluginHooksPath = path.join(__dirname, '..', '..', 'hooks', 'claude');
136
+ // Copy unified hook script to ~/.claude/hooks/gitnexus/
137
+ const destHooksDir = path.join(claudeDir, 'hooks', 'gitnexus');
138
+ try {
139
+ await fs.mkdir(destHooksDir, { recursive: true });
140
+ const src = path.join(pluginHooksPath, 'gitnexus-hook.cjs');
141
+ const dest = path.join(destHooksDir, 'gitnexus-hook.cjs');
142
+ try {
143
+ const content = await fs.readFile(src, 'utf-8');
144
+ await fs.writeFile(dest, content, 'utf-8');
145
+ }
146
+ catch {
147
+ // Script not found in source — skip
148
+ }
149
+ const hookCmd = `node "${path.join(destHooksDir, 'gitnexus-hook.cjs').replace(/\\/g, '/')}"`;
150
+ // Merge hook config into ~/.claude/settings.json
151
+ const existing = await readJsonFile(settingsPath) || {};
152
+ if (!existing.hooks)
153
+ existing.hooks = {};
154
+ // NOTE: SessionStart hooks are broken on Windows (Claude Code bug #23576).
155
+ // Session context is delivered via CLAUDE.md / skills instead.
156
+ // Add PreToolUse hook if not already present
157
+ if (!existing.hooks.PreToolUse)
158
+ existing.hooks.PreToolUse = [];
159
+ const hasPreToolHook = existing.hooks.PreToolUse.some((h) => h.hooks?.some((hh) => hh.command?.includes('gitnexus')));
160
+ if (!hasPreToolHook) {
161
+ existing.hooks.PreToolUse.push({
162
+ matcher: 'Grep|Glob|Bash',
163
+ hooks: [{
164
+ type: 'command',
165
+ command: hookCmd,
166
+ timeout: 8000,
167
+ statusMessage: 'Enriching with GitNexus graph context...',
168
+ }],
169
+ });
170
+ }
171
+ await writeJsonFile(settingsPath, existing);
172
+ result.configured.push('Claude Code hooks (PreToolUse)');
173
+ }
174
+ catch (err) {
175
+ result.errors.push(`Claude Code hooks: ${err.message}`);
176
+ }
177
+ }
178
+ async function setupOpenCode(result) {
179
+ const opencodeDir = path.join(os.homedir(), '.config', 'opencode');
180
+ if (!(await dirExists(opencodeDir))) {
181
+ result.skipped.push('OpenCode (not installed)');
182
+ return;
183
+ }
184
+ const configPath = path.join(opencodeDir, 'config.json');
185
+ try {
186
+ const existing = await readJsonFile(configPath);
187
+ const config = existing || {};
188
+ if (!config.mcp)
189
+ config.mcp = {};
190
+ config.mcp.gitnexus = getMcpEntry();
191
+ await writeJsonFile(configPath, config);
192
+ result.configured.push('OpenCode');
193
+ }
194
+ catch (err) {
195
+ result.errors.push(`OpenCode: ${err.message}`);
196
+ }
197
+ }
198
+ // ─── Skill Installation ───────────────────────────────────────────
199
+ const SKILL_NAMES = ['gitnexus-exploring', 'gitnexus-debugging', 'gitnexus-impact-analysis', 'gitnexus-refactoring', 'gitnexus-guide', 'gitnexus-cli'];
200
+ /**
201
+ * Install GitNexus skills to a target directory.
202
+ * Each skill is installed as {targetDir}/{skillName}/SKILL.md.
203
+ *
204
+ * Supports two source layouts:
205
+ * - Flat file: skills/{name}.md → copied as SKILL.md
206
+ * - Directory: skills/{name}/SKILL.md → copied recursively (includes references/, etc.)
207
+ */
208
+ async function installSkillsTo(targetDir) {
209
+ const installed = [];
210
+ const skillsRoot = path.join(__dirname, '..', '..', 'skills');
211
+ for (const skillName of SKILL_NAMES) {
212
+ const skillDir = path.join(targetDir, skillName);
213
+ try {
214
+ // Try directory-based skill first (skills/{name}/SKILL.md)
215
+ const dirSource = path.join(skillsRoot, skillName);
216
+ let isDirectory = false;
217
+ try {
218
+ const stat = await fs.stat(dirSource);
219
+ isDirectory = stat.isDirectory();
220
+ }
221
+ catch { /* not a directory */ }
222
+ if (isDirectory) {
223
+ await copyDirRecursive(dirSource, skillDir);
224
+ installed.push(skillName);
225
+ }
226
+ else {
227
+ // Fall back to flat file (skills/{name}.md)
228
+ const flatSource = path.join(skillsRoot, `${skillName}.md`);
229
+ const content = await fs.readFile(flatSource, 'utf-8');
230
+ await fs.mkdir(skillDir, { recursive: true });
231
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
232
+ installed.push(skillName);
233
+ }
234
+ }
235
+ catch {
236
+ // Source skill not found — skip
237
+ }
238
+ }
239
+ return installed;
240
+ }
241
+ /**
242
+ * Recursively copy a directory tree.
243
+ */
244
+ async function copyDirRecursive(src, dest) {
245
+ await fs.mkdir(dest, { recursive: true });
246
+ const entries = await fs.readdir(src, { withFileTypes: true });
247
+ for (const entry of entries) {
248
+ const srcPath = path.join(src, entry.name);
249
+ const destPath = path.join(dest, entry.name);
250
+ if (entry.isDirectory()) {
251
+ await copyDirRecursive(srcPath, destPath);
252
+ }
253
+ else {
254
+ await fs.copyFile(srcPath, destPath);
255
+ }
256
+ }
257
+ }
258
+ // ─── Main command ──────────────────────────────────────────────────
259
+ export const setupCommand = async () => {
260
+ console.log('');
261
+ console.log(' GitNexus Setup');
262
+ console.log(' ==============');
263
+ console.log('');
264
+ // Ensure global directory exists
265
+ const globalDir = getGlobalDir();
266
+ await fs.mkdir(globalDir, { recursive: true });
267
+ const result = {
268
+ configured: [],
269
+ skipped: [],
270
+ errors: [],
271
+ };
272
+ // Detect and configure each editor's MCP
273
+ await setupCursor(result);
274
+ await setupClaudeCode(result);
275
+ await setupOpenCode(result);
276
+ // Install shared global skills once
277
+ await installGlobalAgentSkills(result);
278
+ // Optional Claude-specific hooks
279
+ await installClaudeCodeHooks(result);
280
+ // Print results
281
+ if (result.configured.length > 0) {
282
+ console.log(' Configured:');
283
+ for (const name of result.configured) {
284
+ console.log(` + ${name}`);
285
+ }
286
+ }
287
+ if (result.skipped.length > 0) {
288
+ console.log('');
289
+ console.log(' Skipped:');
290
+ for (const name of result.skipped) {
291
+ console.log(` - ${name}`);
292
+ }
293
+ }
294
+ if (result.errors.length > 0) {
295
+ console.log('');
296
+ console.log(' Errors:');
297
+ for (const err of result.errors) {
298
+ console.log(` ! ${err}`);
299
+ }
300
+ }
301
+ console.log('');
302
+ console.log(' Summary:');
303
+ console.log(` MCP configured for: ${result.configured.filter(c => !c.includes('skills')).join(', ') || 'none'}`);
304
+ console.log(` Skills installed to: ${result.configured.filter(c => c.includes('skills')).length > 0 ? result.configured.filter(c => c.includes('skills')).join(', ') : 'none'}`);
305
+ console.log('');
306
+ console.log(' Next steps:');
307
+ console.log(' 1. cd into any git repo');
308
+ console.log(' 2. Run: gitnexus analyze');
309
+ console.log(' 3. Open the repo in your editor — MCP is ready!');
310
+ console.log('');
311
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import fs from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { execFile } from 'node:child_process';
7
+ import { promisify } from 'node:util';
8
+ import { fileURLToPath } from 'node:url';
9
+ const execFileAsync = promisify(execFile);
10
+ test('setup installs global skills under ~/.agents/skills/gitnexus', async () => {
11
+ const fakeHome = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-setup-home-'));
12
+ const here = path.dirname(fileURLToPath(import.meta.url));
13
+ const packageRoot = path.resolve(here, '..', '..');
14
+ const cliPath = path.join(packageRoot, 'dist', 'cli', 'index.js');
15
+ try {
16
+ await execFileAsync(process.execPath, [cliPath, 'setup'], {
17
+ cwd: packageRoot,
18
+ env: {
19
+ ...process.env,
20
+ HOME: fakeHome,
21
+ USERPROFILE: fakeHome,
22
+ },
23
+ });
24
+ const skillPath = path.join(fakeHome, '.agents', 'skills', 'gitnexus', 'gitnexus-exploring', 'SKILL.md');
25
+ await fs.access(skillPath);
26
+ assert.ok(true);
27
+ }
28
+ finally {
29
+ await fs.rm(fakeHome, { recursive: true, force: true });
30
+ }
31
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Status Command
3
+ *
4
+ * Shows the indexing status of the current repository.
5
+ */
6
+ export declare const statusCommand: () => Promise<void>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Status Command
3
+ *
4
+ * Shows the indexing status of the current repository.
5
+ */
6
+ import { findRepo } from '../storage/repo-manager.js';
7
+ import { getCurrentCommit, isGitRepo } from '../storage/git.js';
8
+ export const statusCommand = async () => {
9
+ const cwd = process.cwd();
10
+ if (!isGitRepo(cwd)) {
11
+ console.log('Not a git repository.');
12
+ return;
13
+ }
14
+ const repo = await findRepo(cwd);
15
+ if (!repo) {
16
+ console.log('Repository not indexed.');
17
+ console.log('Run: gitnexus analyze');
18
+ return;
19
+ }
20
+ const currentCommit = getCurrentCommit(repo.repoPath);
21
+ const isUpToDate = currentCommit === repo.meta.lastCommit;
22
+ console.log(`Repository: ${repo.repoPath}`);
23
+ console.log(`Indexed: ${new Date(repo.meta.indexedAt).toLocaleString()}`);
24
+ console.log(`Indexed commit: ${repo.meta.lastCommit?.slice(0, 7)}`);
25
+ console.log(`Current commit: ${currentCommit?.slice(0, 7)}`);
26
+ console.log(`Status: ${isUpToDate ? '✅ up-to-date' : '⚠️ stale (re-run gitnexus analyze)'}`);
27
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Direct CLI Tool Commands
3
+ *
4
+ * Exposes GitNexus tools (query, context, impact, cypher) as direct CLI commands.
5
+ * Bypasses MCP entirely — invokes LocalBackend directly for minimal overhead.
6
+ *
7
+ * Usage:
8
+ * gitnexus query "authentication flow"
9
+ * gitnexus context --name "validateUser"
10
+ * gitnexus impact --target "AuthService" --direction upstream
11
+ * gitnexus cypher "MATCH (n:Function) RETURN n.name LIMIT 10"
12
+ *
13
+ * Note: Output goes to stderr because KuzuDB's native module captures stdout
14
+ * at the OS level during init. This is consistent with augment.ts.
15
+ */
16
+ export declare function queryCommand(queryText: string, options?: {
17
+ repo?: string;
18
+ context?: string;
19
+ goal?: string;
20
+ limit?: string;
21
+ content?: boolean;
22
+ }): Promise<void>;
23
+ export declare function contextCommand(name: string, options?: {
24
+ repo?: string;
25
+ file?: string;
26
+ uid?: string;
27
+ content?: boolean;
28
+ }): Promise<void>;
29
+ export declare function impactCommand(target: string, options?: {
30
+ direction?: string;
31
+ repo?: string;
32
+ depth?: string;
33
+ uid?: string;
34
+ file?: string;
35
+ minConfidence?: string;
36
+ includeTests?: boolean;
37
+ }): Promise<void>;
38
+ export declare function cypherCommand(query: string, options?: {
39
+ repo?: string;
40
+ }): Promise<void>;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Direct CLI Tool Commands
3
+ *
4
+ * Exposes GitNexus tools (query, context, impact, cypher) as direct CLI commands.
5
+ * Bypasses MCP entirely — invokes LocalBackend directly for minimal overhead.
6
+ *
7
+ * Usage:
8
+ * gitnexus query "authentication flow"
9
+ * gitnexus context --name "validateUser"
10
+ * gitnexus impact --target "AuthService" --direction upstream
11
+ * gitnexus cypher "MATCH (n:Function) RETURN n.name LIMIT 10"
12
+ *
13
+ * Note: Output goes to stderr because KuzuDB's native module captures stdout
14
+ * at the OS level during init. This is consistent with augment.ts.
15
+ */
16
+ import { LocalBackend } from '../mcp/local/local-backend.js';
17
+ let _backend = null;
18
+ async function getBackend() {
19
+ if (_backend)
20
+ return _backend;
21
+ _backend = new LocalBackend();
22
+ const ok = await _backend.init();
23
+ if (!ok) {
24
+ console.error('GitNexus: No indexed repositories found. Run: gitnexus analyze');
25
+ process.exit(1);
26
+ }
27
+ return _backend;
28
+ }
29
+ function output(data) {
30
+ const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
31
+ // stderr because KuzuDB captures stdout at OS level
32
+ process.stderr.write(text + '\n');
33
+ }
34
+ export async function queryCommand(queryText, options) {
35
+ if (!queryText?.trim()) {
36
+ console.error('Usage: gitnexus query <search_query>');
37
+ process.exit(1);
38
+ }
39
+ const backend = await getBackend();
40
+ const result = await backend.callTool('query', {
41
+ query: queryText,
42
+ task_context: options?.context,
43
+ goal: options?.goal,
44
+ limit: options?.limit ? parseInt(options.limit) : undefined,
45
+ include_content: options?.content ?? false,
46
+ repo: options?.repo,
47
+ });
48
+ output(result);
49
+ }
50
+ export async function contextCommand(name, options) {
51
+ if (!name?.trim() && !options?.uid) {
52
+ console.error('Usage: gitnexus context <symbol_name> [--uid <uid>] [--file <path>]');
53
+ process.exit(1);
54
+ }
55
+ const backend = await getBackend();
56
+ const result = await backend.callTool('context', {
57
+ name: name || undefined,
58
+ uid: options?.uid,
59
+ file_path: options?.file,
60
+ include_content: options?.content ?? false,
61
+ repo: options?.repo,
62
+ });
63
+ output(result);
64
+ }
65
+ export async function impactCommand(target, options) {
66
+ if (!target?.trim()) {
67
+ console.error('Usage: gitnexus impact <symbol_name> [--direction upstream|downstream]');
68
+ process.exit(1);
69
+ }
70
+ const backend = await getBackend();
71
+ const result = await backend.callTool('impact', {
72
+ target,
73
+ target_uid: options?.uid,
74
+ file_path: options?.file,
75
+ direction: options?.direction || 'upstream',
76
+ maxDepth: options?.depth ? parseInt(options.depth) : undefined,
77
+ minConfidence: options?.minConfidence ? parseFloat(options.minConfidence) : undefined,
78
+ includeTests: options?.includeTests ?? false,
79
+ repo: options?.repo,
80
+ });
81
+ output(result);
82
+ }
83
+ export async function cypherCommand(query, options) {
84
+ if (!query?.trim()) {
85
+ console.error('Usage: gitnexus cypher <cypher_query>');
86
+ process.exit(1);
87
+ }
88
+ const backend = await getBackend();
89
+ const result = await backend.callTool('cypher', {
90
+ query,
91
+ repo: options?.repo,
92
+ });
93
+ output(result);
94
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import fs from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { execFile } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ import { fileURLToPath } from 'node:url';
8
+ const execFileAsync = promisify(execFile);
9
+ test('cli --version matches package.json version', async () => {
10
+ const here = path.dirname(fileURLToPath(import.meta.url));
11
+ const packageRoot = path.resolve(here, '..', '..');
12
+ const cliPath = path.join(packageRoot, 'dist', 'cli', 'index.js');
13
+ const packageJsonPath = path.join(packageRoot, 'package.json');
14
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
15
+ const { stdout } = await execFileAsync(process.execPath, [cliPath, '--version'], {
16
+ cwd: packageRoot,
17
+ });
18
+ assert.equal(stdout.trim(), packageJson.version);
19
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Wiki Command
3
+ *
4
+ * Generates repository documentation from the knowledge graph.
5
+ * Usage: gitnexus wiki [path] [options]
6
+ */
7
+ export interface WikiCommandOptions {
8
+ force?: boolean;
9
+ model?: string;
10
+ baseUrl?: string;
11
+ apiKey?: string;
12
+ concurrency?: string;
13
+ gist?: boolean;
14
+ }
15
+ export declare const wikiCommand: (inputPath?: string, options?: WikiCommandOptions) => Promise<void>;