gitnexus 1.4.7 → 1.4.9
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.
- package/README.md +29 -1
- package/dist/cli/ai-context.d.ts +1 -1
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +54 -21
- package/dist/cli/index-repo.d.ts +15 -0
- package/dist/cli/index-repo.js +115 -0
- package/dist/cli/index.js +13 -3
- package/dist/cli/setup.js +90 -10
- package/dist/cli/wiki.d.ts +4 -0
- package/dist/cli/wiki.js +174 -53
- package/dist/config/supported-languages.d.ts +33 -1
- package/dist/config/supported-languages.js +32 -0
- package/dist/core/embeddings/embedder.d.ts +6 -1
- package/dist/core/embeddings/embedder.js +65 -5
- package/dist/core/embeddings/embedding-pipeline.js +11 -9
- package/dist/core/embeddings/http-client.d.ts +31 -0
- package/dist/core/embeddings/http-client.js +179 -0
- package/dist/core/embeddings/index.d.ts +1 -0
- package/dist/core/embeddings/index.js +1 -0
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/graph.js +9 -1
- package/dist/core/graph/types.d.ts +11 -2
- package/dist/core/ingestion/call-processor.d.ts +66 -2
- package/dist/core/ingestion/call-processor.js +650 -30
- package/dist/core/ingestion/call-routing.d.ts +9 -18
- package/dist/core/ingestion/call-routing.js +0 -19
- package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
- package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
- package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
- package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
- package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
- package/dist/core/ingestion/cobol-processor.d.ts +54 -0
- package/dist/core/ingestion/cobol-processor.js +1186 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
- package/dist/core/ingestion/entry-point-scoring.js +52 -28
- package/dist/core/ingestion/export-detection.d.ts +47 -8
- package/dist/core/ingestion/export-detection.js +29 -50
- package/dist/core/ingestion/field-extractor.d.ts +29 -0
- package/dist/core/ingestion/field-extractor.js +25 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
- package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
- package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
- package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
- package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
- package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
- package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
- package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
- package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
- package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
- package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
- package/dist/core/ingestion/field-extractors/generic.js +111 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
- package/dist/core/ingestion/field-extractors/typescript.js +291 -0
- package/dist/core/ingestion/field-types.d.ts +59 -0
- package/dist/core/ingestion/field-types.js +2 -0
- package/dist/core/ingestion/framework-detection.d.ts +97 -2
- package/dist/core/ingestion/framework-detection.js +114 -14
- package/dist/core/ingestion/heritage-processor.js +62 -66
- package/dist/core/ingestion/import-processor.d.ts +9 -10
- package/dist/core/ingestion/import-processor.js +150 -196
- package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
- package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
- package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
- package/dist/core/ingestion/import-resolvers/dart.js +44 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
- package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +10 -1
- package/dist/core/ingestion/import-resolvers/jvm.js +159 -0
- package/dist/core/ingestion/import-resolvers/php.d.ts +25 -0
- package/dist/core/ingestion/import-resolvers/php.js +80 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
- package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
- package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
- package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
- package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
- package/dist/core/ingestion/import-resolvers/swift.js +23 -0
- package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
- package/dist/core/ingestion/import-resolvers/types.js +6 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +2 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +7 -0
- package/dist/core/ingestion/language-config.d.ts +6 -0
- package/dist/core/ingestion/language-config.js +13 -0
- package/dist/core/ingestion/language-provider.d.ts +121 -0
- package/dist/core/ingestion/language-provider.js +24 -0
- package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
- package/dist/core/ingestion/languages/c-cpp.js +71 -0
- package/dist/core/ingestion/languages/cobol.d.ts +1 -0
- package/dist/core/ingestion/languages/cobol.js +26 -0
- package/dist/core/ingestion/languages/csharp.d.ts +8 -0
- package/dist/core/ingestion/languages/csharp.js +49 -0
- package/dist/core/ingestion/languages/dart.d.ts +12 -0
- package/dist/core/ingestion/languages/dart.js +58 -0
- package/dist/core/ingestion/languages/go.d.ts +11 -0
- package/dist/core/ingestion/languages/go.js +28 -0
- package/dist/core/ingestion/languages/index.d.ts +38 -0
- package/dist/core/ingestion/languages/index.js +63 -0
- package/dist/core/ingestion/languages/java.d.ts +9 -0
- package/dist/core/ingestion/languages/java.js +29 -0
- package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
- package/dist/core/ingestion/languages/kotlin.js +53 -0
- package/dist/core/ingestion/languages/php.d.ts +8 -0
- package/dist/core/ingestion/languages/php.js +145 -0
- package/dist/core/ingestion/languages/python.d.ts +12 -0
- package/dist/core/ingestion/languages/python.js +39 -0
- package/dist/core/ingestion/languages/ruby.d.ts +9 -0
- package/dist/core/ingestion/languages/ruby.js +44 -0
- package/dist/core/ingestion/languages/rust.d.ts +12 -0
- package/dist/core/ingestion/languages/rust.js +44 -0
- package/dist/core/ingestion/languages/swift.d.ts +12 -0
- package/dist/core/ingestion/languages/swift.js +133 -0
- package/dist/core/ingestion/languages/typescript.d.ts +10 -0
- package/dist/core/ingestion/languages/typescript.js +60 -0
- package/dist/core/ingestion/markdown-processor.d.ts +17 -0
- package/dist/core/ingestion/markdown-processor.js +124 -0
- package/dist/core/ingestion/mro-processor.js +22 -18
- package/dist/core/ingestion/named-binding-processor.d.ts +18 -0
- package/dist/core/ingestion/named-binding-processor.js +42 -0
- package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/csharp.js +37 -0
- package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/java.js +29 -0
- package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
- package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/php.js +61 -0
- package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/python.js +49 -0
- package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/rust.js +64 -0
- package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
- package/dist/core/ingestion/named-bindings/types.js +6 -0
- package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/typescript.js +58 -0
- package/dist/core/ingestion/parsing-processor.d.ts +6 -2
- package/dist/core/ingestion/parsing-processor.js +125 -85
- package/dist/core/ingestion/pipeline.d.ts +10 -0
- package/dist/core/ingestion/pipeline.js +1235 -317
- package/dist/core/ingestion/resolution-context.d.ts +5 -0
- package/dist/core/ingestion/resolution-context.js +8 -5
- package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
- package/dist/core/ingestion/route-extractors/expo.js +36 -0
- package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
- package/dist/core/ingestion/route-extractors/middleware.js +143 -0
- package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
- package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
- package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
- package/dist/core/ingestion/route-extractors/php.js +21 -0
- package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
- package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
- package/dist/core/ingestion/symbol-table.d.ts +16 -0
- package/dist/core/ingestion/symbol-table.js +20 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +10 -9
- package/dist/core/ingestion/tree-sitter-queries.js +274 -11
- package/dist/core/ingestion/type-env.d.ts +42 -18
- package/dist/core/ingestion/type-env.js +481 -106
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +119 -0
- package/dist/core/ingestion/type-extractors/csharp.js +149 -16
- package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
- package/dist/core/ingestion/type-extractors/dart.js +371 -0
- package/dist/core/ingestion/type-extractors/jvm.js +169 -66
- package/dist/core/ingestion/type-extractors/rust.js +35 -1
- package/dist/core/ingestion/type-extractors/shared.d.ts +1 -15
- package/dist/core/ingestion/type-extractors/shared.js +14 -112
- package/dist/core/ingestion/type-extractors/swift.js +338 -7
- package/dist/core/ingestion/type-extractors/types.d.ts +40 -8
- package/dist/core/ingestion/type-extractors/typescript.js +141 -9
- package/dist/core/ingestion/utils/ast-helpers.d.ts +83 -0
- package/dist/core/ingestion/utils/ast-helpers.js +817 -0
- package/dist/core/ingestion/utils/call-analysis.d.ts +73 -0
- package/dist/core/ingestion/utils/call-analysis.js +527 -0
- package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
- package/dist/core/ingestion/utils/event-loop.js +5 -0
- package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
- package/dist/core/ingestion/utils/language-detection.js +70 -0
- package/dist/core/ingestion/utils/verbose.d.ts +1 -0
- package/dist/core/ingestion/utils/verbose.js +7 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +55 -5
- package/dist/core/ingestion/workers/parse-worker.js +415 -225
- package/dist/core/lbug/csv-generator.js +51 -1
- package/dist/core/lbug/lbug-adapter.d.ts +10 -0
- package/dist/core/lbug/lbug-adapter.js +75 -4
- package/dist/core/lbug/schema.d.ts +8 -4
- package/dist/core/lbug/schema.js +65 -4
- package/dist/core/tree-sitter/parser-loader.js +7 -1
- package/dist/core/wiki/cursor-client.d.ts +31 -0
- package/dist/core/wiki/cursor-client.js +127 -0
- package/dist/core/wiki/generator.d.ts +28 -9
- package/dist/core/wiki/generator.js +115 -18
- package/dist/core/wiki/graph-queries.d.ts +4 -0
- package/dist/core/wiki/graph-queries.js +7 -1
- package/dist/core/wiki/llm-client.d.ts +2 -0
- package/dist/core/wiki/llm-client.js +8 -4
- package/dist/core/wiki/prompts.d.ts +3 -3
- package/dist/core/wiki/prompts.js +6 -0
- package/dist/mcp/core/embedder.js +11 -3
- package/dist/mcp/core/lbug-adapter.d.ts +5 -0
- package/dist/mcp/core/lbug-adapter.js +23 -2
- package/dist/mcp/local/local-backend.d.ts +38 -5
- package/dist/mcp/local/local-backend.js +804 -63
- package/dist/mcp/resources.js +2 -0
- package/dist/mcp/tools.js +73 -4
- package/dist/server/api.d.ts +19 -1
- package/dist/server/api.js +66 -6
- package/dist/storage/git.d.ts +12 -0
- package/dist/storage/git.js +21 -0
- package/dist/storage/repo-manager.d.ts +3 -0
- package/package.json +25 -16
- package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
- package/dist/core/ingestion/named-binding-extraction.js +0 -363
- package/dist/core/ingestion/resolvers/index.d.ts +0 -18
- package/dist/core/ingestion/resolvers/index.js +0 -13
- package/dist/core/ingestion/resolvers/jvm.js +0 -87
- package/dist/core/ingestion/resolvers/php.d.ts +0 -15
- package/dist/core/ingestion/resolvers/php.js +0 -35
- package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
- package/dist/core/ingestion/type-extractors/index.js +0 -31
- package/dist/core/ingestion/utils.d.ts +0 -138
- package/dist/core/ingestion/utils.js +0 -1290
- package/scripts/patch-tree-sitter-swift.cjs +0 -74
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Graph-powered code intelligence for AI agents.** Index any codebase into a knowledge graph, then query it via MCP or CLI.
|
|
4
4
|
|
|
5
|
-
Works with **Cursor**, **Claude Code**, **Windsurf**, **Cline**, **OpenCode**, and any MCP-compatible tool.
|
|
5
|
+
Works with **Cursor**, **Claude Code**, **Codex**, **Windsurf**, **Cline**, **OpenCode**, and any MCP-compatible tool.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/gitnexus)
|
|
8
8
|
[](https://polyformproject.org/licenses/noncommercial/1.0.0/)
|
|
@@ -34,6 +34,7 @@ To configure MCP for your editor, run `npx gitnexus setup` once — or set it up
|
|
|
34
34
|
|--------|-----|--------|---------------------|---------|
|
|
35
35
|
| **Claude Code** | Yes | Yes | Yes (PreToolUse) | **Full** |
|
|
36
36
|
| **Cursor** | Yes | Yes | — | MCP + Skills |
|
|
37
|
+
| **Codex** | Yes | Yes | — | MCP + Skills |
|
|
37
38
|
| **Windsurf** | Yes | — | — | MCP |
|
|
38
39
|
| **OpenCode** | Yes | Yes | — | MCP + Skills |
|
|
39
40
|
|
|
@@ -52,7 +53,17 @@ If you prefer to configure manually instead of using `gitnexus setup`:
|
|
|
52
53
|
### Claude Code (full support — MCP + skills + hooks)
|
|
53
54
|
|
|
54
55
|
```bash
|
|
56
|
+
# macOS / Linux
|
|
55
57
|
claude mcp add gitnexus -- npx -y gitnexus@latest mcp
|
|
58
|
+
|
|
59
|
+
# Windows
|
|
60
|
+
claude mcp add gitnexus -- cmd /c npx -y gitnexus@latest mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Codex (full support — MCP + skills)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
codex mcp add gitnexus -- npx -y gitnexus@latest mcp
|
|
56
67
|
```
|
|
57
68
|
|
|
58
69
|
### Cursor / Windsurf
|
|
@@ -92,6 +103,8 @@ GitNexus builds a complete knowledge graph of your codebase through a multi-phas
|
|
|
92
103
|
1. **Structure** — Walks the file tree and maps folder/file relationships
|
|
93
104
|
2. **Parsing** — Extracts functions, classes, methods, and interfaces using Tree-sitter ASTs
|
|
94
105
|
3. **Resolution** — Resolves imports and function calls across files with language-aware logic
|
|
106
|
+
- **Field & Property Type Resolution** — Tracks field types across classes and interfaces for deep chain resolution (e.g., `user.address.city.getName()`)
|
|
107
|
+
- **Return-Type-Aware Variable Binding** — Infers variable types from function return types, enabling accurate call-result binding
|
|
95
108
|
4. **Clustering** — Groups related symbols into functional communities
|
|
96
109
|
5. **Processes** — Traces execution flows from entry points through call chains
|
|
97
110
|
6. **Search** — Builds hybrid search indexes for fast retrieval
|
|
@@ -143,6 +156,7 @@ gitnexus analyze --embeddings # Enable embedding generation (slower, better
|
|
|
143
156
|
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
|
|
144
157
|
gitnexus mcp # Start MCP server (stdio) — serves all indexed repos
|
|
145
158
|
gitnexus serve # Start local HTTP server (multi-repo) for web UI
|
|
159
|
+
gitnexus index # Register an existing .gitnexus/ folder into the global registry
|
|
146
160
|
gitnexus list # List all indexed repositories
|
|
147
161
|
gitnexus status # Show index status for current repo
|
|
148
162
|
gitnexus clean # Delete index for current repo
|
|
@@ -151,6 +165,20 @@ gitnexus wiki [path] # Generate LLM-powered docs from knowledge grap
|
|
|
151
165
|
gitnexus wiki --model <model> # Wiki with custom LLM model (default: gpt-4o-mini)
|
|
152
166
|
```
|
|
153
167
|
|
|
168
|
+
## Remote Embeddings
|
|
169
|
+
|
|
170
|
+
Set these env vars to use a remote OpenAI-compatible `/v1/embeddings` endpoint instead of the local model:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
export GITNEXUS_EMBEDDING_URL=http://your-server:8080/v1
|
|
174
|
+
export GITNEXUS_EMBEDDING_MODEL=BAAI/bge-large-en-v1.5
|
|
175
|
+
export GITNEXUS_EMBEDDING_DIMS=1024 # optional, default 384
|
|
176
|
+
export GITNEXUS_EMBEDDING_API_KEY=your-key # optional, default: "unused"
|
|
177
|
+
gitnexus analyze . --embeddings
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Works with Infinity, vLLM, TEI, llama.cpp, Ollama, LM Studio, or OpenAI. When unset, local embeddings are used unchanged.
|
|
181
|
+
|
|
154
182
|
## Multi-Repo Support
|
|
155
183
|
|
|
156
184
|
GitNexus supports indexing multiple repositories. Each `gitnexus analyze` registers the repo in a global registry (`~/.gitnexus/registry.json`). The MCP server serves all indexed repos automatically.
|
package/dist/cli/ai-context.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI Context Generator
|
|
3
3
|
*
|
|
4
4
|
* Creates AGENTS.md and CLAUDE.md with full inline GitNexus context.
|
|
5
|
-
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Cline, etc.
|
|
5
|
+
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Codex, Cline, etc.
|
|
6
6
|
* CLAUDE.md is for Claude Code which only reads that file.
|
|
7
7
|
*/
|
|
8
8
|
import { type GeneratedSkillInfo } from './skill-gen.js';
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI Context Generator
|
|
3
3
|
*
|
|
4
4
|
* Creates AGENTS.md and CLAUDE.md with full inline GitNexus context.
|
|
5
|
-
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Cline, etc.
|
|
5
|
+
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Codex, Cline, etc.
|
|
6
6
|
* CLAUDE.md is for Claude Code which only reads that file.
|
|
7
7
|
*/
|
|
8
8
|
import fs from 'fs/promises';
|
package/dist/cli/analyze.d.ts
CHANGED
|
@@ -8,5 +8,7 @@ export interface AnalyzeOptions {
|
|
|
8
8
|
embeddings?: boolean;
|
|
9
9
|
skills?: boolean;
|
|
10
10
|
verbose?: boolean;
|
|
11
|
+
/** Index the folder even when no .git directory is present. */
|
|
12
|
+
skipGit?: boolean;
|
|
11
13
|
}
|
|
12
14
|
export declare const analyzeCommand: (inputPath?: string, options?: AnalyzeOptions) => Promise<void>;
|
package/dist/cli/analyze.js
CHANGED
|
@@ -14,7 +14,7 @@ import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReuse
|
|
|
14
14
|
// versions whose ABI is not yet supported by the native binary (#89).
|
|
15
15
|
// disposeEmbedder intentionally not called — ONNX Runtime segfaults on cleanup (see #38)
|
|
16
16
|
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath, cleanupOldKuzuFiles } from '../storage/repo-manager.js';
|
|
17
|
-
import { getCurrentCommit,
|
|
17
|
+
import { getCurrentCommit, getGitRoot, hasGitDir } from '../storage/git.js';
|
|
18
18
|
import { generateAIContextFiles } from './ai-context.js';
|
|
19
19
|
import { generateSkillFiles } from './skill-gen.js';
|
|
20
20
|
import fs from 'fs/promises';
|
|
@@ -70,17 +70,27 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
70
70
|
else {
|
|
71
71
|
const gitRoot = getGitRoot(process.cwd());
|
|
72
72
|
if (!gitRoot) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
if (!options?.skipGit) {
|
|
74
|
+
console.log(' Not inside a git repository.\n Tip: pass --skip-git to index any folder without a .git directory.\n');
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// --skip-git: fall back to cwd as the root
|
|
79
|
+
repoPath = path.resolve(process.cwd());
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
repoPath = gitRoot;
|
|
76
83
|
}
|
|
77
|
-
repoPath = gitRoot;
|
|
78
84
|
}
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
const repoHasGit = hasGitDir(repoPath);
|
|
86
|
+
if (!repoHasGit && !options?.skipGit) {
|
|
87
|
+
console.log(' Not a git repository.\n Tip: pass --skip-git to index any folder without a .git directory.\n');
|
|
81
88
|
process.exitCode = 1;
|
|
82
89
|
return;
|
|
83
90
|
}
|
|
91
|
+
if (!repoHasGit) {
|
|
92
|
+
console.log(' Warning: no .git directory found \u2014 commit-tracking and incremental updates disabled.\n');
|
|
93
|
+
}
|
|
84
94
|
const { storagePath, lbugPath } = getStoragePaths(repoPath);
|
|
85
95
|
// Clean up stale KuzuDB files from before the LadybugDB migration.
|
|
86
96
|
// If kuzu existed but lbug doesn't, we're doing a migration re-index — say so.
|
|
@@ -88,11 +98,14 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
88
98
|
if (kuzuResult.found && kuzuResult.needsReindex) {
|
|
89
99
|
console.log(' Migrating from KuzuDB to LadybugDB — rebuilding index...\n');
|
|
90
100
|
}
|
|
91
|
-
const currentCommit = getCurrentCommit(repoPath);
|
|
101
|
+
const currentCommit = repoHasGit ? getCurrentCommit(repoPath) : '';
|
|
92
102
|
const existingMeta = await loadMeta(storagePath);
|
|
93
103
|
if (existingMeta && !options?.force && !options?.skills && existingMeta.lastCommit === currentCommit) {
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
// Non-git folders have currentCommit = '' — always rebuild since we can't detect changes
|
|
105
|
+
if (currentCommit !== '') {
|
|
106
|
+
console.log(' Already up to date\n');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
96
109
|
}
|
|
97
110
|
if (process.env.GITNEXUS_NO_GITIGNORE) {
|
|
98
111
|
console.log(' GITNEXUS_NO_GITIGNORE is set — skipping .gitignore (still reading .gitnexusignore)\n');
|
|
@@ -218,15 +231,26 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
218
231
|
const ftsTime = ((Date.now() - t0Fts) / 1000).toFixed(1);
|
|
219
232
|
// ── Phase 3.5: Re-insert cached embeddings ────────────────────────
|
|
220
233
|
if (cachedEmbeddings.length > 0) {
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
// Check if cached embedding dimensions match current schema
|
|
235
|
+
const cachedDims = cachedEmbeddings[0].embedding.length;
|
|
236
|
+
const { EMBEDDING_DIMS } = await import('../core/lbug/schema.js');
|
|
237
|
+
if (cachedDims !== EMBEDDING_DIMS) {
|
|
238
|
+
// Dimensions changed (e.g. switched embedding model) — discard cache and re-embed all
|
|
239
|
+
console.error(`⚠️ Embedding dimensions changed (${cachedDims}d → ${EMBEDDING_DIMS}d), discarding cache`);
|
|
240
|
+
cachedEmbeddings = [];
|
|
241
|
+
cachedEmbeddingNodeIds = new Set();
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
updateBar(88, `Restoring ${cachedEmbeddings.length} cached embeddings...`);
|
|
245
|
+
const EMBED_BATCH = 200;
|
|
246
|
+
for (let i = 0; i < cachedEmbeddings.length; i += EMBED_BATCH) {
|
|
247
|
+
const batch = cachedEmbeddings.slice(i, i + EMBED_BATCH);
|
|
248
|
+
const paramsList = batch.map(e => ({ nodeId: e.nodeId, embedding: e.embedding }));
|
|
249
|
+
try {
|
|
250
|
+
await executeWithReusedStatement(`CREATE (e:CodeEmbedding {nodeId: $nodeId, embedding: $embedding})`, paramsList);
|
|
251
|
+
}
|
|
252
|
+
catch { /* some may fail if node was removed, that's fine */ }
|
|
228
253
|
}
|
|
229
|
-
catch { /* some may fail if node was removed, that's fine */ }
|
|
230
254
|
}
|
|
231
255
|
}
|
|
232
256
|
// ── Phase 4: Embeddings (90–98%) ──────────────────────────────────
|
|
@@ -243,12 +267,16 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
243
267
|
}
|
|
244
268
|
}
|
|
245
269
|
if (!embeddingSkipped) {
|
|
246
|
-
|
|
270
|
+
const { isHttpMode } = await import('../core/embeddings/http-client.js');
|
|
271
|
+
const httpMode = isHttpMode();
|
|
272
|
+
updateBar(90, httpMode ? 'Connecting to embedding endpoint...' : 'Loading embedding model...');
|
|
247
273
|
const t0Emb = Date.now();
|
|
248
274
|
const { runEmbeddingPipeline } = await import('../core/embeddings/embedding-pipeline.js');
|
|
249
275
|
await runEmbeddingPipeline(executeQuery, executeWithReusedStatement, (progress) => {
|
|
250
276
|
const scaled = 90 + Math.round((progress.percent / 100) * 8);
|
|
251
|
-
const label = progress.phase === 'loading-model'
|
|
277
|
+
const label = progress.phase === 'loading-model'
|
|
278
|
+
? (httpMode ? 'Connecting to embedding endpoint...' : 'Loading embedding model...')
|
|
279
|
+
: `Embedding ${progress.nodesProcessed || 0}/${progress.totalNodes || '?'}`;
|
|
252
280
|
updateBar(scaled, label);
|
|
253
281
|
}, {}, cachedEmbeddingNodeIds.size > 0 ? cachedEmbeddingNodeIds : undefined);
|
|
254
282
|
embeddingTime = ((Date.now() - t0Emb) / 1000).toFixed(1);
|
|
@@ -277,7 +305,12 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
277
305
|
};
|
|
278
306
|
await saveMeta(storagePath, meta);
|
|
279
307
|
await registerRepo(repoPath, meta);
|
|
280
|
-
|
|
308
|
+
// Only attempt to update .gitignore when a .git directory is present.
|
|
309
|
+
// Use hasGitDir (filesystem check) rather than git CLI subprocess
|
|
310
|
+
// so we skip correctly for --skip-git folders even if git CLI is available.
|
|
311
|
+
if (hasGitDir(repoPath)) {
|
|
312
|
+
await addToGitignore(repoPath);
|
|
313
|
+
}
|
|
281
314
|
const projectName = path.basename(repoPath);
|
|
282
315
|
let aggregatedClusterCount = 0;
|
|
283
316
|
if (pipelineResult.communityResult?.communities) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Command
|
|
3
|
+
*
|
|
4
|
+
* Registers an existing .gitnexus/ folder into the global registry so the
|
|
5
|
+
* MCP server can discover the repo without running a full `gitnexus analyze`.
|
|
6
|
+
*
|
|
7
|
+
* Useful when a pre-built .gitnexus/ directory is already present (e.g. after
|
|
8
|
+
* cloning a repo that ships its index, restoring from backup, or using a
|
|
9
|
+
* shared team index).
|
|
10
|
+
*/
|
|
11
|
+
export interface IndexOptions {
|
|
12
|
+
force?: boolean;
|
|
13
|
+
allowNonGit?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const indexCommand: (inputPathParts?: string[], options?: IndexOptions) => Promise<void>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Command
|
|
3
|
+
*
|
|
4
|
+
* Registers an existing .gitnexus/ folder into the global registry so the
|
|
5
|
+
* MCP server can discover the repo without running a full `gitnexus analyze`.
|
|
6
|
+
*
|
|
7
|
+
* Useful when a pre-built .gitnexus/ directory is already present (e.g. after
|
|
8
|
+
* cloning a repo that ships its index, restoring from backup, or using a
|
|
9
|
+
* shared team index).
|
|
10
|
+
*/
|
|
11
|
+
import path from "path";
|
|
12
|
+
import fs from "fs/promises";
|
|
13
|
+
import { getStoragePaths, loadMeta, addToGitignore, registerRepo, } from "../storage/repo-manager.js";
|
|
14
|
+
import { getGitRoot, isGitRepo } from "../storage/git.js";
|
|
15
|
+
export const indexCommand = async (inputPathParts, options) => {
|
|
16
|
+
console.log("\n GitNexus Index\n");
|
|
17
|
+
const inputPath = inputPathParts?.length
|
|
18
|
+
? inputPathParts.join(" ")
|
|
19
|
+
: undefined;
|
|
20
|
+
if (inputPathParts && inputPathParts.length > 1) {
|
|
21
|
+
const resolvedCombinedPath = path.resolve(inputPath);
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(resolvedCombinedPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.log(" The `index` command accepts a single path only.");
|
|
27
|
+
console.log(" If your path contains spaces, wrap it in quotes.");
|
|
28
|
+
console.log(` Received multiple path parts: ${inputPathParts.join(", ")}`);
|
|
29
|
+
console.log("");
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let repoPath;
|
|
35
|
+
if (inputPath) {
|
|
36
|
+
repoPath = path.resolve(inputPath);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const gitRoot = getGitRoot(process.cwd());
|
|
40
|
+
if (!gitRoot) {
|
|
41
|
+
console.log(" Not inside a git repository, try to run git init\n");
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
repoPath = gitRoot;
|
|
46
|
+
}
|
|
47
|
+
if (!options?.allowNonGit && !isGitRepo(repoPath)) {
|
|
48
|
+
console.log(` Not a git repository: ${repoPath}`);
|
|
49
|
+
console.log(" Initialize one with `git init` or choose a valid repo path.\n");
|
|
50
|
+
console.log(" Or use --allow-non-git to register an existing .gitnexus index anyway.\n");
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const { storagePath, lbugPath } = getStoragePaths(repoPath);
|
|
55
|
+
// ── Verify .gitnexus/ exists ──────────────────────────────────────
|
|
56
|
+
try {
|
|
57
|
+
await fs.access(storagePath);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
console.log(` No .gitnexus/ folder found at: ${storagePath}`);
|
|
61
|
+
console.log(" Run `gitnexus analyze` to build the index first.\n");
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// ── Verify lbug database exists ───────────────────────────────────
|
|
66
|
+
try {
|
|
67
|
+
await fs.access(lbugPath);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
console.log(` .gitnexus/ folder exists but contains no LadybugDB index.`);
|
|
71
|
+
console.log(" Run `gitnexus analyze` to build the index.\n");
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// ── Load or reconstruct meta ──────────────────────────────────────
|
|
76
|
+
let meta = await loadMeta(storagePath);
|
|
77
|
+
if (!meta) {
|
|
78
|
+
if (!options?.force) {
|
|
79
|
+
console.log(` .gitnexus/ exists but meta.json is missing.`);
|
|
80
|
+
console.log(" Use --force to register anyway (stats will be empty),");
|
|
81
|
+
console.log(" or run `gitnexus analyze` to rebuild properly.\n");
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// --force: build a minimal meta so the repo can be registered
|
|
86
|
+
meta = {
|
|
87
|
+
repoPath,
|
|
88
|
+
lastCommit: "",
|
|
89
|
+
indexedAt: new Date().toISOString(),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// ── Register in global registry ───────────────────────────────────
|
|
93
|
+
await registerRepo(repoPath, meta);
|
|
94
|
+
await addToGitignore(repoPath);
|
|
95
|
+
const projectName = path.basename(repoPath);
|
|
96
|
+
const { stats } = meta;
|
|
97
|
+
console.log(` Repository registered: ${projectName}`);
|
|
98
|
+
if (stats) {
|
|
99
|
+
const parts = [];
|
|
100
|
+
if (stats.nodes != null) {
|
|
101
|
+
parts.push(`${stats.nodes.toLocaleString()} nodes`);
|
|
102
|
+
}
|
|
103
|
+
if (stats.edges != null) {
|
|
104
|
+
parts.push(`${stats.edges.toLocaleString()} edges`);
|
|
105
|
+
}
|
|
106
|
+
if (stats.communities != null)
|
|
107
|
+
parts.push(`${stats.communities} clusters`);
|
|
108
|
+
if (stats.processes != null)
|
|
109
|
+
parts.push(`${stats.processes} flows`);
|
|
110
|
+
if (parts.length)
|
|
111
|
+
console.log(` ${parts.join(" | ")}`);
|
|
112
|
+
}
|
|
113
|
+
console.log(` ${repoPath}`);
|
|
114
|
+
console.log("");
|
|
115
|
+
};
|
package/dist/cli/index.js
CHANGED
|
@@ -13,7 +13,7 @@ program
|
|
|
13
13
|
.version(pkg.version);
|
|
14
14
|
program
|
|
15
15
|
.command('setup')
|
|
16
|
-
.description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode')
|
|
16
|
+
.description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode, Codex')
|
|
17
17
|
.action(createLazyAction(() => import('./setup.js'), 'setupCommand'));
|
|
18
18
|
program
|
|
19
19
|
.command('analyze [path]')
|
|
@@ -21,9 +21,16 @@ program
|
|
|
21
21
|
.option('-f, --force', 'Force full re-index even if up to date')
|
|
22
22
|
.option('--embeddings', 'Enable embedding generation for semantic search (off by default)')
|
|
23
23
|
.option('--skills', 'Generate repo-specific skill files from detected communities')
|
|
24
|
+
.option('--skip-git', 'Index a folder without requiring a .git directory')
|
|
24
25
|
.option('-v, --verbose', 'Enable verbose ingestion warnings (default: false)')
|
|
25
26
|
.addHelpText('after', '\nEnvironment variables:\n GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)')
|
|
26
27
|
.action(createLazyAction(() => import('./analyze.js'), 'analyzeCommand'));
|
|
28
|
+
program
|
|
29
|
+
.command('index [path...]')
|
|
30
|
+
.description('Register an existing .gitnexus/ folder into the global registry (no re-analysis needed)')
|
|
31
|
+
.option('-f, --force', 'Register even if meta.json is missing (stats will be empty)')
|
|
32
|
+
.option('--allow-non-git', 'Allow registering folders that are not Git repositories')
|
|
33
|
+
.action(createLazyAction(() => import('./index-repo.js'), 'indexCommand'));
|
|
27
34
|
program
|
|
28
35
|
.command('serve')
|
|
29
36
|
.description('Start local HTTP server for web UI connection')
|
|
@@ -52,11 +59,14 @@ program
|
|
|
52
59
|
.command('wiki [path]')
|
|
53
60
|
.description('Generate repository wiki from knowledge graph')
|
|
54
61
|
.option('-f, --force', 'Force full regeneration even if up to date')
|
|
55
|
-
.option('--
|
|
56
|
-
.option('--
|
|
62
|
+
.option('--provider <provider>', 'LLM provider: openai or cursor (default: openai)')
|
|
63
|
+
.option('--model <model>', 'LLM model name (default depends on provider)')
|
|
64
|
+
.option('--base-url <url>', 'LLM API base URL (for openai provider)')
|
|
57
65
|
.option('--api-key <key>', 'LLM API key (saved to ~/.gitnexus/config.json)')
|
|
58
66
|
.option('--concurrency <n>', 'Parallel LLM calls (default: 3)', '3')
|
|
59
67
|
.option('--gist', 'Publish wiki as a public GitHub Gist after generation')
|
|
68
|
+
.option('-v, --verbose', 'Enable verbose output (show LLM commands and responses)')
|
|
69
|
+
.option('--review', 'Stop after grouping to review module structure before generating pages')
|
|
60
70
|
.action(createLazyAction(() => import('./wiki.js'), 'wikiCommand'));
|
|
61
71
|
program
|
|
62
72
|
.command('augment <pattern>')
|
package/dist/cli/setup.js
CHANGED
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import os from 'os';
|
|
11
|
+
import { execFile } from 'child_process';
|
|
12
|
+
import { promisify } from 'util';
|
|
11
13
|
import { fileURLToPath } from 'url';
|
|
12
14
|
import { glob } from 'glob';
|
|
13
15
|
import { getGlobalDir } from '../storage/repo-manager.js';
|
|
14
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
17
|
const __dirname = path.dirname(__filename);
|
|
18
|
+
const execFileAsync = promisify(execFile);
|
|
16
19
|
/**
|
|
17
20
|
* The MCP server entry for all editors.
|
|
18
21
|
* On Windows, npx must be invoked via cmd /c since it's a .cmd script.
|
|
@@ -94,18 +97,21 @@ async function setupCursor(result) {
|
|
|
94
97
|
}
|
|
95
98
|
async function setupClaudeCode(result) {
|
|
96
99
|
const claudeDir = path.join(os.homedir(), '.claude');
|
|
97
|
-
|
|
98
|
-
if (!hasClaude) {
|
|
100
|
+
if (!(await dirExists(claudeDir))) {
|
|
99
101
|
result.skipped.push('Claude Code (not installed)');
|
|
100
102
|
return;
|
|
101
103
|
}
|
|
102
|
-
// Claude Code
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
// Claude Code stores MCP config in ~/.claude.json
|
|
105
|
+
const mcpPath = path.join(os.homedir(), '.claude.json');
|
|
106
|
+
try {
|
|
107
|
+
const existing = await readJsonFile(mcpPath);
|
|
108
|
+
const updated = mergeMcpConfig(existing);
|
|
109
|
+
await writeJsonFile(mcpPath, updated);
|
|
110
|
+
result.configured.push('Claude Code');
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
result.errors.push(`Claude Code: ${err.message}`);
|
|
114
|
+
}
|
|
109
115
|
}
|
|
110
116
|
/**
|
|
111
117
|
* Install GitNexus skills to ~/.claude/skills/ for Claude Code.
|
|
@@ -201,11 +207,65 @@ async function setupOpenCode(result) {
|
|
|
201
207
|
result.errors.push(`OpenCode: ${err.message}`);
|
|
202
208
|
}
|
|
203
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Build a TOML section for Codex MCP config (~/.codex/config.toml).
|
|
212
|
+
*/
|
|
213
|
+
function getCodexMcpTomlSection() {
|
|
214
|
+
const entry = getMcpEntry();
|
|
215
|
+
const command = JSON.stringify(entry.command);
|
|
216
|
+
const args = `[${entry.args.map(arg => JSON.stringify(arg)).join(', ')}]`;
|
|
217
|
+
return `[mcp_servers.gitnexus]\ncommand = ${command}\nargs = ${args}\n`;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Append GitNexus MCP server config to Codex's config.toml if missing.
|
|
221
|
+
*/
|
|
222
|
+
async function upsertCodexConfigToml(configPath) {
|
|
223
|
+
let existing = '';
|
|
224
|
+
try {
|
|
225
|
+
existing = await fs.readFile(configPath, 'utf-8');
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
existing = '';
|
|
229
|
+
}
|
|
230
|
+
if (existing.includes('[mcp_servers.gitnexus]')) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const section = getCodexMcpTomlSection();
|
|
234
|
+
const nextContent = existing.trim().length > 0
|
|
235
|
+
? `${existing.trimEnd()}\n\n${section}`
|
|
236
|
+
: section;
|
|
237
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
238
|
+
await fs.writeFile(configPath, `${nextContent.trimEnd()}\n`, 'utf-8');
|
|
239
|
+
}
|
|
240
|
+
async function setupCodex(result) {
|
|
241
|
+
const codexDir = path.join(os.homedir(), '.codex');
|
|
242
|
+
if (!(await dirExists(codexDir))) {
|
|
243
|
+
result.skipped.push('Codex (not installed)');
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const entry = getMcpEntry();
|
|
248
|
+
await execFileAsync('codex', ['mcp', 'add', 'gitnexus', '--', entry.command, ...entry.args], { shell: process.platform === 'win32' });
|
|
249
|
+
result.configured.push('Codex');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// Fallback for environments where `codex` binary isn't on PATH.
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const configPath = path.join(codexDir, 'config.toml');
|
|
257
|
+
await upsertCodexConfigToml(configPath);
|
|
258
|
+
result.configured.push('Codex (MCP added to ~/.codex/config.toml)');
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
result.errors.push(`Codex: ${err.message}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
204
264
|
// ─── Skill Installation ───────────────────────────────────────────
|
|
205
265
|
/**
|
|
206
266
|
* Install GitNexus skills to a target directory.
|
|
207
267
|
* Each skill is installed as {targetDir}/gitnexus-{skillName}/SKILL.md
|
|
208
|
-
* following the Agent Skills standard (
|
|
268
|
+
* following the Agent Skills standard (Cursor, Claude Code, and Codex).
|
|
209
269
|
*
|
|
210
270
|
* Supports two source layouts:
|
|
211
271
|
* - Flat file: skills/{name}.md → copied as SKILL.md
|
|
@@ -310,6 +370,24 @@ async function installOpenCodeSkills(result) {
|
|
|
310
370
|
result.errors.push(`OpenCode skills: ${err.message}`);
|
|
311
371
|
}
|
|
312
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* Install global Codex skills to ~/.agents/skills/gitnexus/
|
|
375
|
+
*/
|
|
376
|
+
async function installCodexSkills(result) {
|
|
377
|
+
const codexDir = path.join(os.homedir(), '.codex');
|
|
378
|
+
if (!(await dirExists(codexDir)))
|
|
379
|
+
return;
|
|
380
|
+
const skillsDir = path.join(os.homedir(), '.agents', 'skills');
|
|
381
|
+
try {
|
|
382
|
+
const installed = await installSkillsTo(skillsDir);
|
|
383
|
+
if (installed.length > 0) {
|
|
384
|
+
result.configured.push(`Codex skills (${installed.length} skills → ~/.agents/skills/)`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
result.errors.push(`Codex skills: ${err.message}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
313
391
|
// ─── Main command ──────────────────────────────────────────────────
|
|
314
392
|
export const setupCommand = async () => {
|
|
315
393
|
console.log('');
|
|
@@ -328,11 +406,13 @@ export const setupCommand = async () => {
|
|
|
328
406
|
await setupCursor(result);
|
|
329
407
|
await setupClaudeCode(result);
|
|
330
408
|
await setupOpenCode(result);
|
|
409
|
+
await setupCodex(result);
|
|
331
410
|
// Install global skills for platforms that support them
|
|
332
411
|
await installClaudeCodeSkills(result);
|
|
333
412
|
await installClaudeCodeHooks(result);
|
|
334
413
|
await installCursorSkills(result);
|
|
335
414
|
await installOpenCodeSkills(result);
|
|
415
|
+
await installCodexSkills(result);
|
|
336
416
|
// Print results
|
|
337
417
|
if (result.configured.length > 0) {
|
|
338
418
|
console.log(' Configured:');
|
package/dist/cli/wiki.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Generates repository documentation from the knowledge graph.
|
|
5
5
|
* Usage: gitnexus wiki [path] [options]
|
|
6
6
|
*/
|
|
7
|
+
import { type LLMProvider } from '../core/wiki/llm-client.js';
|
|
7
8
|
export interface WikiCommandOptions {
|
|
8
9
|
force?: boolean;
|
|
9
10
|
model?: string;
|
|
@@ -11,5 +12,8 @@ export interface WikiCommandOptions {
|
|
|
11
12
|
apiKey?: string;
|
|
12
13
|
concurrency?: string;
|
|
13
14
|
gist?: boolean;
|
|
15
|
+
provider?: LLMProvider;
|
|
16
|
+
verbose?: boolean;
|
|
17
|
+
review?: boolean;
|
|
14
18
|
}
|
|
15
19
|
export declare const wikiCommand: (inputPath?: string, options?: WikiCommandOptions) => Promise<void>;
|