@veewo/gitnexus 1.3.11 → 1.4.6-rc
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 +37 -80
- package/dist/benchmark/agent-context/tool-runner.js +2 -2
- package/dist/benchmark/neonspark-candidates.js +3 -3
- package/dist/benchmark/tool-runner.js +2 -2
- package/dist/cli/ai-context.d.ts +2 -1
- package/dist/cli/ai-context.js +16 -12
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +68 -48
- package/dist/cli/augment.js +1 -1
- package/dist/cli/eval-server.d.ts +8 -1
- package/dist/cli/eval-server.js +30 -13
- package/dist/cli/index.js +28 -82
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/mcp.js +3 -1
- package/dist/cli/setup.js +87 -48
- package/dist/cli/setup.test.js +18 -13
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.js +13 -4
- package/dist/cli/tool.d.ts +3 -2
- package/dist/cli/tool.js +50 -16
- package/dist/cli/wiki.js +8 -4
- package/dist/config/ignore-service.d.ts +25 -0
- package/dist/config/ignore-service.js +76 -0
- package/dist/config/supported-languages.d.ts +4 -1
- package/dist/config/supported-languages.js +3 -2
- package/dist/core/augmentation/engine.js +94 -67
- package/dist/core/embeddings/embedder.d.ts +1 -1
- package/dist/core/embeddings/embedder.js +1 -1
- package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
- package/dist/core/embeddings/embedding-pipeline.js +52 -25
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/types.d.ts +7 -2
- package/dist/core/ingestion/ast-cache.js +3 -2
- package/dist/core/ingestion/call-processor.d.ts +8 -6
- package/dist/core/ingestion/call-processor.js +468 -206
- package/dist/core/ingestion/call-routing.d.ts +53 -0
- package/dist/core/ingestion/call-routing.js +108 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +2 -1
- package/dist/core/ingestion/entry-point-scoring.js +116 -23
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.js +4 -3
- package/dist/core/ingestion/framework-detection.d.ts +19 -4
- package/dist/core/ingestion/framework-detection.js +182 -6
- package/dist/core/ingestion/heritage-processor.d.ts +13 -5
- package/dist/core/ingestion/heritage-processor.js +109 -55
- package/dist/core/ingestion/import-processor.d.ts +16 -20
- package/dist/core/ingestion/import-processor.js +199 -579
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +4 -1
- package/dist/core/ingestion/parsing-processor.js +107 -109
- package/dist/core/ingestion/pipeline.d.ts +6 -3
- package/dist/core/ingestion/pipeline.js +208 -114
- package/dist/core/ingestion/process-processor.js +8 -2
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/symbol-table.d.ts +21 -1
- package/dist/core/ingestion/symbol-table.js +40 -12
- package/dist/core/ingestion/tree-sitter-queries.d.ts +13 -10
- package/dist/core/ingestion/tree-sitter-queries.js +297 -7
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +611 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +406 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +449 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +133 -0
- package/dist/core/ingestion/type-extractors/shared.js +703 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +103 -0
- package/dist/core/ingestion/utils.js +1085 -4
- package/dist/core/ingestion/workers/parse-worker.d.ts +51 -4
- package/dist/core/ingestion/workers/parse-worker.js +634 -222
- package/dist/core/ingestion/workers/worker-pool.js +8 -0
- package/dist/core/{kuzu → lbug}/csv-generator.d.ts +12 -10
- package/dist/core/{kuzu → lbug}/csv-generator.js +82 -101
- package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +20 -25
- package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +150 -122
- package/dist/core/{kuzu → lbug}/schema.d.ts +4 -4
- package/dist/core/{kuzu → lbug}/schema.js +23 -22
- package/dist/core/lbug/schema.test.d.ts +1 -0
- package/dist/core/search/bm25-index.d.ts +4 -4
- package/dist/core/search/bm25-index.js +12 -11
- package/dist/core/search/hybrid-search.d.ts +2 -2
- package/dist/core/search/hybrid-search.js +6 -6
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
- package/dist/core/tree-sitter/parser-loader.js +19 -0
- package/dist/core/wiki/generator.d.ts +2 -2
- package/dist/core/wiki/generator.js +6 -6
- package/dist/core/wiki/graph-queries.d.ts +4 -4
- package/dist/core/wiki/graph-queries.js +7 -7
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/{kuzu-adapter.d.ts → lbug-adapter.d.ts} +11 -10
- package/dist/mcp/core/lbug-adapter.js +327 -0
- package/dist/mcp/local/local-backend.d.ts +21 -16
- package/dist/mcp/local/local-backend.js +306 -706
- package/dist/mcp/local/unity-parity-seed-loader.d.ts +6 -1
- package/dist/mcp/local/unity-parity-seed-loader.js +119 -9
- package/dist/mcp/local/unity-parity-seed-loader.test.js +95 -7
- package/dist/mcp/resources.js +2 -2
- package/dist/mcp/server.js +28 -13
- package/dist/mcp/staleness.js +2 -2
- package/dist/mcp/tools.js +12 -3
- package/dist/server/api.js +12 -12
- package/dist/server/mcp-http.d.ts +1 -1
- package/dist/server/mcp-http.js +1 -1
- package/dist/storage/git.js +4 -1
- package/dist/storage/repo-manager.d.ts +20 -2
- package/dist/storage/repo-manager.js +74 -4
- package/dist/types/pipeline.d.ts +1 -1
- package/hooks/claude/gitnexus-hook.cjs +149 -46
- package/hooks/claude/pre-tool-use.sh +2 -1
- package/hooks/claude/session-start.sh +0 -0
- package/package.json +20 -4
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/skills/gitnexus-cli.md +8 -8
- package/skills/gitnexus-debugging.md +1 -1
- package/skills/gitnexus-exploring.md +1 -1
- package/skills/gitnexus-guide.md +1 -1
- package/skills/gitnexus-impact-analysis.md +1 -1
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/dist/cli/claude-hooks.d.ts +0 -22
- package/dist/cli/claude-hooks.js +0 -97
- package/dist/mcp/core/kuzu-adapter.js +0 -231
- /package/dist/core/{kuzu/csv-generator.test.d.ts → ingestion/type-extractors/types.js} +0 -0
- /package/dist/core/{kuzu/relationship-pair-buckets.test.d.ts → lbug/csv-generator.test.d.ts} +0 -0
- /package/dist/core/{kuzu → lbug}/csv-generator.test.js +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.d.ts +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.js +0 -0
- /package/dist/core/{kuzu/schema.test.d.ts → lbug/relationship-pair-buckets.test.d.ts} +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.test.js +0 -0
- /package/dist/core/{kuzu → lbug}/schema.test.js +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gitnexus-pr-review
|
|
3
|
+
description: "Use when the user wants to review a pull request, understand what a PR changes, assess risk of merging, or check for missing test coverage. Examples: \"Review this PR\", \"What does PR #42 change?\", \"Is this PR safe to merge?\""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PR Review with GitNexus
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- "Review this PR"
|
|
11
|
+
- "What does PR #42 change?"
|
|
12
|
+
- "Is this safe to merge?"
|
|
13
|
+
- "What's the blast radius of this PR?"
|
|
14
|
+
- "Are there missing tests for this PR?"
|
|
15
|
+
- Reviewing someone else's code changes before merge
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
1. gh pr diff <number> → Get the raw diff
|
|
21
|
+
2. gitnexus_detect_changes({scope: "compare", base_ref: "main"}) → Map diff to affected flows
|
|
22
|
+
3. For each changed symbol:
|
|
23
|
+
gitnexus_impact({target: "<symbol>", direction: "upstream"}) → Blast radius per change
|
|
24
|
+
4. gitnexus_context({name: "<key symbol>"}) → Understand callers/callees
|
|
25
|
+
5. READ gitnexus://repo/{name}/processes → Check affected execution flows
|
|
26
|
+
6. Summarize findings with risk assessment
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> If "Index is stale" → run `npx -y @veewo/gitnexus@latest analyze` in terminal before reviewing.
|
|
30
|
+
|
|
31
|
+
## Checklist
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
- [ ] Fetch PR diff (gh pr diff or git diff base...head)
|
|
35
|
+
- [ ] gitnexus_detect_changes to map changes to affected execution flows
|
|
36
|
+
- [ ] gitnexus_impact on each non-trivial changed symbol
|
|
37
|
+
- [ ] Review d=1 items (WILL BREAK) — are callers updated?
|
|
38
|
+
- [ ] gitnexus_context on key changed symbols to understand full picture
|
|
39
|
+
- [ ] Check if affected processes have test coverage
|
|
40
|
+
- [ ] Assess overall risk level
|
|
41
|
+
- [ ] Write review summary with findings
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Review Dimensions
|
|
45
|
+
|
|
46
|
+
| Dimension | How GitNexus Helps |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| **Correctness** | `context` shows callers — are they all compatible with the change? |
|
|
49
|
+
| **Blast radius** | `impact` shows d=1/d=2/d=3 dependents — anything missed? |
|
|
50
|
+
| **Completeness** | `detect_changes` shows all affected flows — are they all handled? |
|
|
51
|
+
| **Test coverage** | `impact({includeTests: true})` shows which tests touch changed code |
|
|
52
|
+
| **Breaking changes** | d=1 upstream items that aren't updated in the PR = potential breakage |
|
|
53
|
+
|
|
54
|
+
## Risk Assessment
|
|
55
|
+
|
|
56
|
+
| Signal | Risk |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| Changes touch <3 symbols, 0-1 processes | LOW |
|
|
59
|
+
| Changes touch 3-10 symbols, 2-5 processes | MEDIUM |
|
|
60
|
+
| Changes touch >10 symbols or many processes | HIGH |
|
|
61
|
+
| Changes touch auth, payments, or data integrity code | CRITICAL |
|
|
62
|
+
| d=1 callers exist outside the PR diff | Potential breakage — flag it |
|
|
63
|
+
|
|
64
|
+
## Tools
|
|
65
|
+
|
|
66
|
+
**gitnexus_detect_changes** — map PR diff to affected execution flows:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
gitnexus_detect_changes({scope: "compare", base_ref: "main"})
|
|
70
|
+
|
|
71
|
+
→ Changed: 8 symbols in 4 files
|
|
72
|
+
→ Affected processes: CheckoutFlow, RefundFlow, WebhookHandler
|
|
73
|
+
→ Risk: MEDIUM
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**gitnexus_impact** — blast radius per changed symbol:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
gitnexus_impact({target: "validatePayment", direction: "upstream"})
|
|
80
|
+
|
|
81
|
+
→ d=1 (WILL BREAK):
|
|
82
|
+
- processCheckout (src/checkout.ts:42) [CALLS, 100%]
|
|
83
|
+
- webhookHandler (src/webhooks.ts:15) [CALLS, 100%]
|
|
84
|
+
|
|
85
|
+
→ d=2 (LIKELY AFFECTED):
|
|
86
|
+
- checkoutRouter (src/routes/checkout.ts:22) [CALLS, 95%]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**gitnexus_impact with tests** — check test coverage:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
gitnexus_impact({target: "validatePayment", direction: "upstream", includeTests: true})
|
|
93
|
+
|
|
94
|
+
→ Tests that cover this symbol:
|
|
95
|
+
- validatePayment.test.ts [direct]
|
|
96
|
+
- checkout.integration.test.ts [via processCheckout]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**gitnexus_context** — understand a changed symbol's role:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
gitnexus_context({name: "validatePayment"})
|
|
103
|
+
|
|
104
|
+
→ Incoming calls: processCheckout, webhookHandler
|
|
105
|
+
→ Outgoing calls: verifyCard, fetchRates
|
|
106
|
+
→ Processes: CheckoutFlow (step 3/7), RefundFlow (step 1/5)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Example: "Review PR #42"
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
1. gh pr diff 42 > /tmp/pr42.diff
|
|
113
|
+
→ 4 files changed: payments.ts, checkout.ts, types.ts, utils.ts
|
|
114
|
+
|
|
115
|
+
2. gitnexus_detect_changes({scope: "compare", base_ref: "main"})
|
|
116
|
+
→ Changed symbols: validatePayment, PaymentInput, formatAmount
|
|
117
|
+
→ Affected processes: CheckoutFlow, RefundFlow
|
|
118
|
+
→ Risk: MEDIUM
|
|
119
|
+
|
|
120
|
+
3. gitnexus_impact({target: "validatePayment", direction: "upstream"})
|
|
121
|
+
→ d=1: processCheckout, webhookHandler (WILL BREAK)
|
|
122
|
+
→ webhookHandler is NOT in the PR diff — potential breakage!
|
|
123
|
+
|
|
124
|
+
4. gitnexus_impact({target: "PaymentInput", direction: "upstream"})
|
|
125
|
+
→ d=1: validatePayment (in PR), createPayment (NOT in PR)
|
|
126
|
+
→ createPayment uses the old PaymentInput shape — breaking change!
|
|
127
|
+
|
|
128
|
+
5. gitnexus_context({name: "formatAmount"})
|
|
129
|
+
→ Called by 12 functions — but change is backwards-compatible (added optional param)
|
|
130
|
+
|
|
131
|
+
6. Review summary:
|
|
132
|
+
- MEDIUM risk — 3 changed symbols affect 2 execution flows
|
|
133
|
+
- BUG: webhookHandler calls validatePayment but isn't updated for new signature
|
|
134
|
+
- BUG: createPayment depends on PaymentInput type which changed
|
|
135
|
+
- OK: formatAmount change is backwards-compatible
|
|
136
|
+
- Tests: checkout.test.ts covers processCheckout path, but no webhook test
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Review Output Format
|
|
140
|
+
|
|
141
|
+
Structure your review as:
|
|
142
|
+
|
|
143
|
+
```markdown
|
|
144
|
+
## PR Review: <title>
|
|
145
|
+
|
|
146
|
+
**Risk: LOW / MEDIUM / HIGH / CRITICAL**
|
|
147
|
+
|
|
148
|
+
### Changes Summary
|
|
149
|
+
- <N> symbols changed across <M> files
|
|
150
|
+
- <P> execution flows affected
|
|
151
|
+
|
|
152
|
+
### Findings
|
|
153
|
+
1. **[severity]** Description of finding
|
|
154
|
+
- Evidence from GitNexus tools
|
|
155
|
+
- Affected callers/flows
|
|
156
|
+
|
|
157
|
+
### Missing Coverage
|
|
158
|
+
- Callers not updated in PR: ...
|
|
159
|
+
- Untested flows: ...
|
|
160
|
+
|
|
161
|
+
### Recommendation
|
|
162
|
+
APPROVE / REQUEST CHANGES / NEEDS DISCUSSION
|
|
163
|
+
```
|
|
@@ -23,7 +23,7 @@ description: "Use when the user wants to rename, extract, split, move, or restru
|
|
|
23
23
|
5. Plan update order: interfaces → implementations → callers → tests
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
|
|
26
|
+
> If "Index is stale" → run `npx -y @veewo/gitnexus@latest analyze` in terminal.
|
|
27
27
|
|
|
28
28
|
## Checklists
|
|
29
29
|
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Hook Registration
|
|
3
|
-
*
|
|
4
|
-
* Registers the GitNexus PreToolUse hook in ~/.claude/hooks.json
|
|
5
|
-
* so that grep/glob/bash calls are automatically augmented with
|
|
6
|
-
* knowledge graph context.
|
|
7
|
-
*
|
|
8
|
-
* Idempotent — safe to call multiple times.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Register (or verify) the GitNexus hook in Claude Code's global hooks.json.
|
|
12
|
-
*
|
|
13
|
-
* - Creates ~/.claude/ and hooks.json if they don't exist
|
|
14
|
-
* - Preserves existing hooks from other tools
|
|
15
|
-
* - Skips if GitNexus hook is already registered
|
|
16
|
-
*
|
|
17
|
-
* Returns a status message for the CLI output.
|
|
18
|
-
*/
|
|
19
|
-
export declare function registerClaudeHook(): Promise<{
|
|
20
|
-
registered: boolean;
|
|
21
|
-
message: string;
|
|
22
|
-
}>;
|
package/dist/cli/claude-hooks.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Hook Registration
|
|
3
|
-
*
|
|
4
|
-
* Registers the GitNexus PreToolUse hook in ~/.claude/hooks.json
|
|
5
|
-
* so that grep/glob/bash calls are automatically augmented with
|
|
6
|
-
* knowledge graph context.
|
|
7
|
-
*
|
|
8
|
-
* Idempotent — safe to call multiple times.
|
|
9
|
-
*/
|
|
10
|
-
import fs from 'fs/promises';
|
|
11
|
-
import path from 'path';
|
|
12
|
-
import os from 'os';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
-
const __dirname = path.dirname(__filename);
|
|
16
|
-
/**
|
|
17
|
-
* Get the absolute path to the gitnexus-hook.js file.
|
|
18
|
-
* Works for both local dev and npm-installed packages.
|
|
19
|
-
*/
|
|
20
|
-
function getHookScriptPath() {
|
|
21
|
-
// From dist/cli/claude-hooks.js → hooks/claude/gitnexus-hook.js
|
|
22
|
-
const packageRoot = path.resolve(__dirname, '..', '..');
|
|
23
|
-
return path.join(packageRoot, 'hooks', 'claude', 'gitnexus-hook.cjs');
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Register (or verify) the GitNexus hook in Claude Code's global hooks.json.
|
|
27
|
-
*
|
|
28
|
-
* - Creates ~/.claude/ and hooks.json if they don't exist
|
|
29
|
-
* - Preserves existing hooks from other tools
|
|
30
|
-
* - Skips if GitNexus hook is already registered
|
|
31
|
-
*
|
|
32
|
-
* Returns a status message for the CLI output.
|
|
33
|
-
*/
|
|
34
|
-
export async function registerClaudeHook() {
|
|
35
|
-
const claudeDir = path.join(os.homedir(), '.claude');
|
|
36
|
-
const hooksFile = path.join(claudeDir, 'hooks.json');
|
|
37
|
-
const hookScript = getHookScriptPath();
|
|
38
|
-
// Check if the hook script exists
|
|
39
|
-
try {
|
|
40
|
-
await fs.access(hookScript);
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return { registered: false, message: 'Hook script not found (package may be incomplete)' };
|
|
44
|
-
}
|
|
45
|
-
// Build the hook command — use node + absolute path for reliability
|
|
46
|
-
const hookCommand = `node "${hookScript}"`;
|
|
47
|
-
// Check if ~/.claude/ exists (user has Claude Code installed)
|
|
48
|
-
try {
|
|
49
|
-
await fs.access(claudeDir);
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// No Claude Code installation — skip silently
|
|
53
|
-
return { registered: false, message: 'Claude Code not detected (~/.claude/ not found)' };
|
|
54
|
-
}
|
|
55
|
-
// Read existing hooks.json or start fresh
|
|
56
|
-
let hooksConfig = {};
|
|
57
|
-
try {
|
|
58
|
-
const existing = await fs.readFile(hooksFile, 'utf-8');
|
|
59
|
-
hooksConfig = JSON.parse(existing);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// File doesn't exist or is invalid — we'll create it
|
|
63
|
-
}
|
|
64
|
-
// Ensure the hooks structure exists
|
|
65
|
-
if (!hooksConfig.hooks) {
|
|
66
|
-
hooksConfig.hooks = {};
|
|
67
|
-
}
|
|
68
|
-
if (!Array.isArray(hooksConfig.hooks.PreToolUse)) {
|
|
69
|
-
hooksConfig.hooks.PreToolUse = [];
|
|
70
|
-
}
|
|
71
|
-
// Check if GitNexus hook is already registered
|
|
72
|
-
const existingEntry = hooksConfig.hooks.PreToolUse.find((entry) => {
|
|
73
|
-
if (!entry.hooks || !Array.isArray(entry.hooks))
|
|
74
|
-
return false;
|
|
75
|
-
return entry.hooks.some((h) => h.command && (h.command.includes('gitnexus-hook') ||
|
|
76
|
-
h.command.includes('gitnexus augment')));
|
|
77
|
-
});
|
|
78
|
-
if (existingEntry) {
|
|
79
|
-
return { registered: true, message: 'Claude Code hook already registered' };
|
|
80
|
-
}
|
|
81
|
-
// Add the GitNexus hook entry
|
|
82
|
-
hooksConfig.hooks.PreToolUse.push({
|
|
83
|
-
matcher: {
|
|
84
|
-
tool_name: "Grep|Glob|Bash"
|
|
85
|
-
},
|
|
86
|
-
hooks: [
|
|
87
|
-
{
|
|
88
|
-
type: "command",
|
|
89
|
-
command: hookCommand,
|
|
90
|
-
timeout: 8000
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
});
|
|
94
|
-
// Write back
|
|
95
|
-
await fs.writeFile(hooksFile, JSON.stringify(hooksConfig, null, 2) + '\n', 'utf-8');
|
|
96
|
-
return { registered: true, message: 'Claude Code hook registered' };
|
|
97
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* KuzuDB Adapter (Connection Pool)
|
|
3
|
-
*
|
|
4
|
-
* Manages a pool of KuzuDB databases keyed by repoId, each with
|
|
5
|
-
* multiple Connection objects for safe concurrent query execution.
|
|
6
|
-
*
|
|
7
|
-
* KuzuDB Connections are NOT thread-safe — a single Connection
|
|
8
|
-
* segfaults if concurrent .query() calls hit it simultaneously.
|
|
9
|
-
* This adapter provides a checkout/return connection pool so each
|
|
10
|
-
* concurrent query gets its own Connection from the same Database.
|
|
11
|
-
*
|
|
12
|
-
* @see https://docs.kuzudb.com/concurrency — multiple Connections
|
|
13
|
-
* from the same Database is the officially supported concurrency pattern.
|
|
14
|
-
*/
|
|
15
|
-
import fs from 'fs/promises';
|
|
16
|
-
import kuzu from 'kuzu';
|
|
17
|
-
const pool = new Map();
|
|
18
|
-
/** Max repos in the pool (LRU eviction) */
|
|
19
|
-
const MAX_POOL_SIZE = 5;
|
|
20
|
-
/** Idle timeout before closing a repo's connections */
|
|
21
|
-
const IDLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
22
|
-
/** Max connections per repo (caps concurrent queries per repo) */
|
|
23
|
-
const MAX_CONNS_PER_REPO = 8;
|
|
24
|
-
/** Connections created eagerly on init */
|
|
25
|
-
const INITIAL_CONNS_PER_REPO = 2;
|
|
26
|
-
let idleTimer = null;
|
|
27
|
-
/**
|
|
28
|
-
* Start the idle cleanup timer (runs every 60s)
|
|
29
|
-
*/
|
|
30
|
-
function ensureIdleTimer() {
|
|
31
|
-
if (idleTimer)
|
|
32
|
-
return;
|
|
33
|
-
idleTimer = setInterval(() => {
|
|
34
|
-
const now = Date.now();
|
|
35
|
-
for (const [repoId, entry] of pool) {
|
|
36
|
-
if (now - entry.lastUsed > IDLE_TIMEOUT_MS) {
|
|
37
|
-
closeOne(repoId);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}, 60_000);
|
|
41
|
-
if (idleTimer && typeof idleTimer === 'object' && 'unref' in idleTimer) {
|
|
42
|
-
idleTimer.unref();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Evict the least-recently-used repo if pool is at capacity
|
|
47
|
-
*/
|
|
48
|
-
function evictLRU() {
|
|
49
|
-
if (pool.size < MAX_POOL_SIZE)
|
|
50
|
-
return;
|
|
51
|
-
let oldestId = null;
|
|
52
|
-
let oldestTime = Infinity;
|
|
53
|
-
for (const [id, entry] of pool) {
|
|
54
|
-
if (entry.lastUsed < oldestTime) {
|
|
55
|
-
oldestTime = entry.lastUsed;
|
|
56
|
-
oldestId = id;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (oldestId) {
|
|
60
|
-
closeOne(oldestId);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Close all connections for a repo and remove it from the pool
|
|
65
|
-
*/
|
|
66
|
-
function closeOne(repoId) {
|
|
67
|
-
const entry = pool.get(repoId);
|
|
68
|
-
if (!entry)
|
|
69
|
-
return;
|
|
70
|
-
for (const conn of entry.available) {
|
|
71
|
-
try {
|
|
72
|
-
conn.close();
|
|
73
|
-
}
|
|
74
|
-
catch { }
|
|
75
|
-
}
|
|
76
|
-
try {
|
|
77
|
-
entry.db.close();
|
|
78
|
-
}
|
|
79
|
-
catch { }
|
|
80
|
-
pool.delete(repoId);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Create a new Connection from a repo's Database.
|
|
84
|
-
* Silences stdout to prevent native module output from corrupting MCP stdio.
|
|
85
|
-
*/
|
|
86
|
-
function createConnection(db) {
|
|
87
|
-
const origWrite = process.stdout.write;
|
|
88
|
-
process.stdout.write = (() => true);
|
|
89
|
-
try {
|
|
90
|
-
return new kuzu.Connection(db);
|
|
91
|
-
}
|
|
92
|
-
finally {
|
|
93
|
-
process.stdout.write = origWrite;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const LOCK_RETRY_ATTEMPTS = 3;
|
|
97
|
-
const LOCK_RETRY_DELAY_MS = 2000;
|
|
98
|
-
/**
|
|
99
|
-
* Initialize (or reuse) a Database + connection pool for a specific repo.
|
|
100
|
-
* Retries on lock errors (e.g., when `gitnexus analyze` is running).
|
|
101
|
-
*/
|
|
102
|
-
export const initKuzu = async (repoId, dbPath) => {
|
|
103
|
-
const existing = pool.get(repoId);
|
|
104
|
-
if (existing) {
|
|
105
|
-
existing.lastUsed = Date.now();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
// Check if database exists
|
|
109
|
-
try {
|
|
110
|
-
await fs.stat(dbPath);
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
throw new Error(`KuzuDB not found at ${dbPath}. Run: gitnexus analyze`);
|
|
114
|
-
}
|
|
115
|
-
evictLRU();
|
|
116
|
-
// Open in read-only mode — MCP server never writes to the database.
|
|
117
|
-
// This allows multiple MCP server instances to read concurrently, and
|
|
118
|
-
// avoids lock conflicts when `gitnexus analyze` is writing.
|
|
119
|
-
let lastError = null;
|
|
120
|
-
for (let attempt = 1; attempt <= LOCK_RETRY_ATTEMPTS; attempt++) {
|
|
121
|
-
const origWrite = process.stdout.write;
|
|
122
|
-
process.stdout.write = (() => true);
|
|
123
|
-
try {
|
|
124
|
-
const db = new kuzu.Database(dbPath, 0, // bufferManagerSize (default)
|
|
125
|
-
false, // enableCompression (default)
|
|
126
|
-
true);
|
|
127
|
-
process.stdout.write = origWrite;
|
|
128
|
-
// Pre-create a small pool of connections
|
|
129
|
-
const available = [];
|
|
130
|
-
for (let i = 0; i < INITIAL_CONNS_PER_REPO; i++) {
|
|
131
|
-
available.push(createConnection(db));
|
|
132
|
-
}
|
|
133
|
-
pool.set(repoId, { db, available, checkedOut: 0, waiters: [], lastUsed: Date.now(), dbPath });
|
|
134
|
-
ensureIdleTimer();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
catch (err) {
|
|
138
|
-
process.stdout.write = origWrite;
|
|
139
|
-
lastError = err instanceof Error ? err : new Error(String(err));
|
|
140
|
-
const isLockError = lastError.message.includes('Could not set lock')
|
|
141
|
-
|| lastError.message.includes('lock');
|
|
142
|
-
if (!isLockError || attempt === LOCK_RETRY_ATTEMPTS)
|
|
143
|
-
break;
|
|
144
|
-
await new Promise(resolve => setTimeout(resolve, LOCK_RETRY_DELAY_MS * attempt));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
throw new Error(`KuzuDB unavailable for ${repoId}. Another process may be rebuilding the index. ` +
|
|
148
|
-
`Retry later. (${lastError?.message || 'unknown error'})`);
|
|
149
|
-
};
|
|
150
|
-
/**
|
|
151
|
-
* Checkout a connection from the pool.
|
|
152
|
-
* Returns an available connection, or creates a new one if under the cap.
|
|
153
|
-
* If all connections are busy and at cap, queues the caller until one is returned.
|
|
154
|
-
*/
|
|
155
|
-
function checkout(entry) {
|
|
156
|
-
// Fast path: grab an available connection
|
|
157
|
-
if (entry.available.length > 0) {
|
|
158
|
-
entry.checkedOut++;
|
|
159
|
-
return Promise.resolve(entry.available.pop());
|
|
160
|
-
}
|
|
161
|
-
// Grow the pool if under the cap
|
|
162
|
-
const totalConns = entry.available.length + entry.checkedOut;
|
|
163
|
-
if (totalConns < MAX_CONNS_PER_REPO) {
|
|
164
|
-
entry.checkedOut++;
|
|
165
|
-
return Promise.resolve(createConnection(entry.db));
|
|
166
|
-
}
|
|
167
|
-
// At capacity — queue the caller. checkin() will resolve this when
|
|
168
|
-
// a connection is returned, handing it directly to the next waiter.
|
|
169
|
-
return new Promise(resolve => {
|
|
170
|
-
entry.waiters.push(resolve);
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Return a connection to the pool after use.
|
|
175
|
-
* If there are queued waiters, hand the connection directly to the next one
|
|
176
|
-
* instead of putting it back in the available array (avoids race conditions).
|
|
177
|
-
*/
|
|
178
|
-
function checkin(entry, conn) {
|
|
179
|
-
if (entry.waiters.length > 0) {
|
|
180
|
-
// Hand directly to the next waiter — no intermediate available state
|
|
181
|
-
const waiter = entry.waiters.shift();
|
|
182
|
-
waiter(conn);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
entry.checkedOut--;
|
|
186
|
-
entry.available.push(conn);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Execute a query on a specific repo's connection pool.
|
|
191
|
-
* Automatically checks out a connection, runs the query, and returns it.
|
|
192
|
-
*/
|
|
193
|
-
export const executeQuery = async (repoId, cypher) => {
|
|
194
|
-
const entry = pool.get(repoId);
|
|
195
|
-
if (!entry) {
|
|
196
|
-
throw new Error(`KuzuDB not initialized for repo "${repoId}". Call initKuzu first.`);
|
|
197
|
-
}
|
|
198
|
-
entry.lastUsed = Date.now();
|
|
199
|
-
const conn = await checkout(entry);
|
|
200
|
-
try {
|
|
201
|
-
const queryResult = await conn.query(cypher);
|
|
202
|
-
const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
|
|
203
|
-
const rows = await result.getAll();
|
|
204
|
-
return rows;
|
|
205
|
-
}
|
|
206
|
-
finally {
|
|
207
|
-
checkin(entry, conn);
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
/**
|
|
211
|
-
* Close one or all repo pools.
|
|
212
|
-
* If repoId is provided, close only that repo's connections.
|
|
213
|
-
* If omitted, close all repos.
|
|
214
|
-
*/
|
|
215
|
-
export const closeKuzu = async (repoId) => {
|
|
216
|
-
if (repoId) {
|
|
217
|
-
closeOne(repoId);
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
for (const id of [...pool.keys()]) {
|
|
221
|
-
closeOne(id);
|
|
222
|
-
}
|
|
223
|
-
if (idleTimer) {
|
|
224
|
-
clearInterval(idleTimer);
|
|
225
|
-
idleTimer = null;
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* Check if a specific repo's pool is active
|
|
230
|
-
*/
|
|
231
|
-
export const isKuzuReady = (repoId) => pool.has(repoId);
|
|
File without changes
|
/package/dist/core/{kuzu/relationship-pair-buckets.test.d.ts → lbug/csv-generator.test.d.ts}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|