gitnexus 1.3.8 → 1.3.10

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 (39) hide show
  1. package/README.md +194 -194
  2. package/dist/cli/ai-context.js +87 -87
  3. package/dist/cli/index.js +15 -25
  4. package/dist/cli/lazy-action.d.ts +6 -0
  5. package/dist/cli/lazy-action.js +18 -0
  6. package/dist/core/augmentation/engine.js +20 -20
  7. package/dist/core/embeddings/embedding-pipeline.js +26 -26
  8. package/dist/core/ingestion/ast-cache.js +3 -2
  9. package/dist/core/ingestion/cluster-enricher.js +16 -16
  10. package/dist/core/ingestion/pipeline.js +8 -0
  11. package/dist/core/ingestion/tree-sitter-queries.js +484 -484
  12. package/dist/core/ingestion/workers/parse-worker.js +4 -2
  13. package/dist/core/kuzu/kuzu-adapter.js +9 -9
  14. package/dist/core/kuzu/schema.js +287 -287
  15. package/dist/core/search/bm25-index.js +5 -5
  16. package/dist/core/search/hybrid-search.js +3 -3
  17. package/dist/core/wiki/graph-queries.js +52 -52
  18. package/dist/core/wiki/html-viewer.js +192 -192
  19. package/dist/core/wiki/prompts.js +82 -82
  20. package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
  21. package/dist/mcp/compatible-stdio-transport.js +200 -0
  22. package/dist/mcp/local/local-backend.js +128 -128
  23. package/dist/mcp/resources.js +42 -42
  24. package/dist/mcp/server.js +18 -18
  25. package/dist/mcp/tools.js +86 -86
  26. package/hooks/claude/gitnexus-hook.cjs +155 -155
  27. package/hooks/claude/pre-tool-use.sh +79 -79
  28. package/hooks/claude/session-start.sh +42 -42
  29. package/package.json +96 -96
  30. package/scripts/patch-tree-sitter-swift.cjs +74 -74
  31. package/skills/gitnexus-cli.md +82 -82
  32. package/skills/gitnexus-debugging.md +89 -89
  33. package/skills/gitnexus-exploring.md +78 -78
  34. package/skills/gitnexus-guide.md +64 -64
  35. package/skills/gitnexus-impact-analysis.md +97 -97
  36. package/skills/gitnexus-pr-review.md +163 -163
  37. package/skills/gitnexus-refactoring.md +121 -121
  38. package/vendor/leiden/index.cjs +355 -355
  39. package/vendor/leiden/utils.cjs +392 -392
@@ -1,79 +1,79 @@
1
- #!/bin/bash
2
- # GitNexus PreToolUse hook for Claude Code
3
- # Intercepts Grep/Glob/Bash searches and augments with graph context.
4
- # Receives JSON on stdin with { tool_name, tool_input, cwd, ... }
5
- # Returns JSON with additionalContext for graph-enriched results.
6
-
7
- INPUT=$(cat)
8
-
9
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
10
- CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
11
-
12
- # Extract search pattern based on tool type
13
- PATTERN=""
14
-
15
- case "$TOOL_NAME" in
16
- Grep)
17
- PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
18
- ;;
19
- Glob)
20
- # Glob patterns are file paths, not search terms — extract meaningful part
21
- RAW=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
22
- # Strip glob syntax to get the meaningful name (e.g., "**/*.ts" → skip, "auth*.ts" → "auth")
23
- PATTERN=$(echo "$RAW" | sed -n 's/.*[*\/]\([a-zA-Z][a-zA-Z0-9_-]*\).*/\1/p')
24
- ;;
25
- Bash)
26
- CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
27
- # Only augment grep/rg commands
28
- if echo "$CMD" | grep -qE '\brg\b|\bgrep\b'; then
29
- # Extract pattern from rg/grep
30
- if echo "$CMD" | grep -qE '\brg\b'; then
31
- PATTERN=$(echo "$CMD" | sed -n "s/.*\brg\s\+\(--[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
32
- elif echo "$CMD" | grep -qE '\bgrep\b'; then
33
- PATTERN=$(echo "$CMD" | sed -n "s/.*\bgrep\s\+\(-[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
34
- fi
35
- fi
36
- ;;
37
- *)
38
- # Not a search tool — skip
39
- exit 0
40
- ;;
41
- esac
42
-
43
- # Skip if pattern too short or empty
44
- if [ -z "$PATTERN" ] || [ ${#PATTERN} -lt 3 ]; then
45
- exit 0
46
- fi
47
-
48
- # Check if we're in a GitNexus-indexed repo
49
- dir="${CWD:-$PWD}"
50
- found=false
51
- for i in 1 2 3 4 5; do
52
- if [ -d "$dir/.gitnexus" ]; then
53
- found=true
54
- break
55
- fi
56
- parent="$(dirname "$dir")"
57
- [ "$parent" = "$dir" ] && break
58
- dir="$parent"
59
- done
60
-
61
- if [ "$found" = false ]; then
62
- exit 0
63
- fi
64
-
65
- # Run gitnexus augment — must be fast (<500ms target)
66
- # augment writes to stderr (KuzuDB captures stdout at OS level), so capture stderr and discard stdout
67
- RESULT=$(cd "$CWD" && npx -y gitnexus augment "$PATTERN" 2>&1 1>/dev/null)
68
-
69
- if [ -n "$RESULT" ]; then
70
- ESCAPED=$(echo "$RESULT" | jq -Rs .)
71
- jq -n --argjson ctx "$ESCAPED" '{
72
- hookSpecificOutput: {
73
- hookEventName: "PreToolUse",
74
- additionalContext: $ctx
75
- }
76
- }'
77
- else
78
- exit 0
79
- fi
1
+ #!/bin/bash
2
+ # GitNexus PreToolUse hook for Claude Code
3
+ # Intercepts Grep/Glob/Bash searches and augments with graph context.
4
+ # Receives JSON on stdin with { tool_name, tool_input, cwd, ... }
5
+ # Returns JSON with additionalContext for graph-enriched results.
6
+
7
+ INPUT=$(cat)
8
+
9
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
10
+ CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
11
+
12
+ # Extract search pattern based on tool type
13
+ PATTERN=""
14
+
15
+ case "$TOOL_NAME" in
16
+ Grep)
17
+ PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
18
+ ;;
19
+ Glob)
20
+ # Glob patterns are file paths, not search terms — extract meaningful part
21
+ RAW=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
22
+ # Strip glob syntax to get the meaningful name (e.g., "**/*.ts" → skip, "auth*.ts" → "auth")
23
+ PATTERN=$(echo "$RAW" | sed -n 's/.*[*\/]\([a-zA-Z][a-zA-Z0-9_-]*\).*/\1/p')
24
+ ;;
25
+ Bash)
26
+ CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
27
+ # Only augment grep/rg commands
28
+ if echo "$CMD" | grep -qE '\brg\b|\bgrep\b'; then
29
+ # Extract pattern from rg/grep
30
+ if echo "$CMD" | grep -qE '\brg\b'; then
31
+ PATTERN=$(echo "$CMD" | sed -n "s/.*\brg\s\+\(--[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
32
+ elif echo "$CMD" | grep -qE '\bgrep\b'; then
33
+ PATTERN=$(echo "$CMD" | sed -n "s/.*\bgrep\s\+\(-[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
34
+ fi
35
+ fi
36
+ ;;
37
+ *)
38
+ # Not a search tool — skip
39
+ exit 0
40
+ ;;
41
+ esac
42
+
43
+ # Skip if pattern too short or empty
44
+ if [ -z "$PATTERN" ] || [ ${#PATTERN} -lt 3 ]; then
45
+ exit 0
46
+ fi
47
+
48
+ # Check if we're in a GitNexus-indexed repo
49
+ dir="${CWD:-$PWD}"
50
+ found=false
51
+ for i in 1 2 3 4 5; do
52
+ if [ -d "$dir/.gitnexus" ]; then
53
+ found=true
54
+ break
55
+ fi
56
+ parent="$(dirname "$dir")"
57
+ [ "$parent" = "$dir" ] && break
58
+ dir="$parent"
59
+ done
60
+
61
+ if [ "$found" = false ]; then
62
+ exit 0
63
+ fi
64
+
65
+ # Run gitnexus augment — must be fast (<500ms target)
66
+ # augment writes to stderr (KuzuDB captures stdout at OS level), so capture stderr and discard stdout
67
+ RESULT=$(cd "$CWD" && npx -y gitnexus augment "$PATTERN" 2>&1 1>/dev/null)
68
+
69
+ if [ -n "$RESULT" ]; then
70
+ ESCAPED=$(echo "$RESULT" | jq -Rs .)
71
+ jq -n --argjson ctx "$ESCAPED" '{
72
+ hookSpecificOutput: {
73
+ hookEventName: "PreToolUse",
74
+ additionalContext: $ctx
75
+ }
76
+ }'
77
+ else
78
+ exit 0
79
+ fi
@@ -1,42 +1,42 @@
1
- #!/bin/bash
2
- # GitNexus SessionStart hook for Claude Code
3
- # Fires on session startup. Stdout is injected into Claude's context.
4
- # Checks if the current directory has a GitNexus index.
5
-
6
- dir="$PWD"
7
- found=false
8
- for i in 1 2 3 4 5; do
9
- if [ -d "$dir/.gitnexus" ]; then
10
- found=true
11
- break
12
- fi
13
- parent="$(dirname "$dir")"
14
- [ "$parent" = "$dir" ] && break
15
- dir="$parent"
16
- done
17
-
18
- if [ "$found" = false ]; then
19
- exit 0
20
- fi
21
-
22
- # Inject GitNexus context — this stdout goes directly into Claude's context
23
- cat << 'EOF'
24
- ## GitNexus Code Intelligence
25
-
26
- This codebase is indexed by GitNexus, providing a knowledge graph with execution flows, relationships, and semantic search.
27
-
28
- **Available MCP Tools:**
29
- - `query` — Process-grouped code intelligence (execution flows related to a concept)
30
- - `context` — 360-degree symbol view (categorized refs, process participation)
31
- - `impact` — Blast radius analysis (what breaks if you change a symbol)
32
- - `detect_changes` — Git-diff impact analysis (what do your changes affect)
33
- - `rename` — Multi-file coordinated rename with confidence tags
34
- - `cypher` — Raw graph queries
35
- - `list_repos` — Discover indexed repos
36
-
37
- **Quick Start:** READ `gitnexus://repo/{name}/context` for codebase overview, then use `query` to find execution flows.
38
-
39
- **Resources:** `gitnexus://repo/{name}/context` (overview), `/processes` (execution flows), `/schema` (for Cypher)
40
- EOF
41
-
42
- exit 0
1
+ #!/bin/bash
2
+ # GitNexus SessionStart hook for Claude Code
3
+ # Fires on session startup. Stdout is injected into Claude's context.
4
+ # Checks if the current directory has a GitNexus index.
5
+
6
+ dir="$PWD"
7
+ found=false
8
+ for i in 1 2 3 4 5; do
9
+ if [ -d "$dir/.gitnexus" ]; then
10
+ found=true
11
+ break
12
+ fi
13
+ parent="$(dirname "$dir")"
14
+ [ "$parent" = "$dir" ] && break
15
+ dir="$parent"
16
+ done
17
+
18
+ if [ "$found" = false ]; then
19
+ exit 0
20
+ fi
21
+
22
+ # Inject GitNexus context — this stdout goes directly into Claude's context
23
+ cat << 'EOF'
24
+ ## GitNexus Code Intelligence
25
+
26
+ This codebase is indexed by GitNexus, providing a knowledge graph with execution flows, relationships, and semantic search.
27
+
28
+ **Available MCP Tools:**
29
+ - `query` — Process-grouped code intelligence (execution flows related to a concept)
30
+ - `context` — 360-degree symbol view (categorized refs, process participation)
31
+ - `impact` — Blast radius analysis (what breaks if you change a symbol)
32
+ - `detect_changes` — Git-diff impact analysis (what do your changes affect)
33
+ - `rename` — Multi-file coordinated rename with confidence tags
34
+ - `cypher` — Raw graph queries
35
+ - `list_repos` — Discover indexed repos
36
+
37
+ **Quick Start:** READ `gitnexus://repo/{name}/context` for codebase overview, then use `query` to find execution flows.
38
+
39
+ **Resources:** `gitnexus://repo/{name}/context` (overview), `/processes` (execution flows), `/schema` (for Cypher)
40
+ EOF
41
+
42
+ exit 0
package/package.json CHANGED
@@ -1,96 +1,96 @@
1
- {
2
- "name": "gitnexus",
3
- "version": "1.3.8",
4
- "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
- "author": "Abhigyan Patwari",
6
- "license": "PolyForm-Noncommercial-1.0.0",
7
- "homepage": "https://github.com/abhigyanpatwari/GitNexus#readme",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/abhigyanpatwari/GitNexus.git",
11
- "directory": "gitnexus"
12
- },
13
- "bugs": {
14
- "url": "https://github.com/abhigyanpatwari/GitNexus/issues"
15
- },
16
- "keywords": [
17
- "mcp",
18
- "model-context-protocol",
19
- "code-intelligence",
20
- "knowledge-graph",
21
- "cursor",
22
- "claude",
23
- "ai-agent",
24
- "gitnexus",
25
- "static-analysis",
26
- "codebase-indexing"
27
- ],
28
- "type": "module",
29
- "bin": {
30
- "gitnexus": "dist/cli/index.js"
31
- },
32
- "files": [
33
- "dist",
34
- "hooks",
35
- "scripts",
36
- "skills",
37
- "vendor"
38
- ],
39
- "scripts": {
40
- "build": "tsc",
41
- "dev": "tsx watch src/cli/index.ts",
42
- "test": "vitest run test/unit",
43
- "test:integration": "vitest run test/integration",
44
- "test:all": "vitest run",
45
- "test:watch": "vitest",
46
- "test:coverage": "vitest run --coverage",
47
- "prepare": "npm run build",
48
- "postinstall": "node scripts/patch-tree-sitter-swift.cjs"
49
- },
50
- "dependencies": {
51
- "@huggingface/transformers": "^3.0.0",
52
- "@modelcontextprotocol/sdk": "^1.0.0",
53
- "cli-progress": "^3.12.0",
54
- "commander": "^12.0.0",
55
- "cors": "^2.8.5",
56
- "express": "^4.19.2",
57
- "glob": "^11.0.0",
58
- "graphology": "^0.25.4",
59
- "graphology-indices": "^0.17.0",
60
- "graphology-utils": "^2.3.0",
61
- "kuzu": "^0.11.3",
62
- "lru-cache": "^11.0.0",
63
- "mnemonist": "^0.39.0",
64
- "pandemonium": "^2.4.0",
65
- "tree-sitter": "^0.21.0",
66
- "tree-sitter-c": "^0.21.0",
67
- "tree-sitter-c-sharp": "^0.21.0",
68
- "tree-sitter-cpp": "^0.22.0",
69
- "tree-sitter-go": "^0.21.0",
70
- "tree-sitter-java": "^0.21.0",
71
- "tree-sitter-javascript": "^0.21.0",
72
- "tree-sitter-kotlin": "^0.3.8",
73
- "tree-sitter-php": "^0.23.12",
74
- "tree-sitter-python": "^0.21.0",
75
- "tree-sitter-rust": "^0.21.0",
76
- "tree-sitter-typescript": "^0.21.0",
77
- "uuid": "^13.0.0"
78
- },
79
- "optionalDependencies": {
80
- "tree-sitter-swift": "^0.6.0"
81
- },
82
- "devDependencies": {
83
- "@types/cli-progress": "^3.11.6",
84
- "@types/cors": "^2.8.17",
85
- "@types/express": "^4.17.21",
86
- "@types/node": "^20.0.0",
87
- "@types/uuid": "^10.0.0",
88
- "@vitest/coverage-v8": "^4.0.18",
89
- "tsx": "^4.0.0",
90
- "typescript": "^5.4.5",
91
- "vitest": "^4.0.18"
92
- },
93
- "engines": {
94
- "node": ">=18.0.0"
95
- }
96
- }
1
+ {
2
+ "name": "gitnexus",
3
+ "version": "1.3.10",
4
+ "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
+ "author": "Abhigyan Patwari",
6
+ "license": "PolyForm-Noncommercial-1.0.0",
7
+ "homepage": "https://github.com/abhigyanpatwari/GitNexus#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/abhigyanpatwari/GitNexus.git",
11
+ "directory": "gitnexus"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/abhigyanpatwari/GitNexus/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "code-intelligence",
20
+ "knowledge-graph",
21
+ "cursor",
22
+ "claude",
23
+ "ai-agent",
24
+ "gitnexus",
25
+ "static-analysis",
26
+ "codebase-indexing"
27
+ ],
28
+ "type": "module",
29
+ "bin": {
30
+ "gitnexus": "dist/cli/index.js"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "hooks",
35
+ "scripts",
36
+ "skills",
37
+ "vendor"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc",
41
+ "dev": "tsx watch src/cli/index.ts",
42
+ "test": "vitest run test/unit",
43
+ "test:integration": "vitest run test/integration",
44
+ "test:all": "vitest run",
45
+ "test:watch": "vitest",
46
+ "test:coverage": "vitest run --coverage",
47
+ "prepare": "npm run build",
48
+ "postinstall": "node scripts/patch-tree-sitter-swift.cjs"
49
+ },
50
+ "dependencies": {
51
+ "@huggingface/transformers": "^3.0.0",
52
+ "@modelcontextprotocol/sdk": "^1.0.0",
53
+ "cli-progress": "^3.12.0",
54
+ "commander": "^12.0.0",
55
+ "cors": "^2.8.5",
56
+ "express": "^4.19.2",
57
+ "glob": "^11.0.0",
58
+ "graphology": "^0.25.4",
59
+ "graphology-indices": "^0.17.0",
60
+ "graphology-utils": "^2.3.0",
61
+ "kuzu": "^0.11.3",
62
+ "lru-cache": "^11.0.0",
63
+ "mnemonist": "^0.39.0",
64
+ "pandemonium": "^2.4.0",
65
+ "tree-sitter": "^0.21.0",
66
+ "tree-sitter-c": "^0.21.0",
67
+ "tree-sitter-c-sharp": "^0.21.0",
68
+ "tree-sitter-cpp": "^0.22.0",
69
+ "tree-sitter-go": "^0.21.0",
70
+ "tree-sitter-java": "^0.21.0",
71
+ "tree-sitter-javascript": "^0.21.0",
72
+ "tree-sitter-kotlin": "^0.3.8",
73
+ "tree-sitter-php": "^0.23.12",
74
+ "tree-sitter-python": "^0.21.0",
75
+ "tree-sitter-rust": "^0.21.0",
76
+ "tree-sitter-typescript": "^0.21.0",
77
+ "uuid": "^13.0.0"
78
+ },
79
+ "optionalDependencies": {
80
+ "tree-sitter-swift": "^0.6.0"
81
+ },
82
+ "devDependencies": {
83
+ "@types/cli-progress": "^3.11.6",
84
+ "@types/cors": "^2.8.17",
85
+ "@types/express": "^4.17.21",
86
+ "@types/node": "^20.0.0",
87
+ "@types/uuid": "^10.0.0",
88
+ "@vitest/coverage-v8": "^4.0.18",
89
+ "tsx": "^4.0.0",
90
+ "typescript": "^5.4.5",
91
+ "vitest": "^4.0.18"
92
+ },
93
+ "engines": {
94
+ "node": ">=18.0.0"
95
+ }
96
+ }
@@ -1,74 +1,74 @@
1
- #!/usr/bin/env node
2
- /**
3
- * WORKAROUND: tree-sitter-swift@0.6.0 binding.gyp build failure
4
- *
5
- * Background:
6
- * tree-sitter-swift@0.6.0's binding.gyp contains an "actions" array that
7
- * invokes `tree-sitter generate` to regenerate parser.c from grammar.js.
8
- * This is intended for grammar developers, but the published npm package
9
- * already ships pre-generated parser files (parser.c, scanner.c), so the
10
- * actions are unnecessary for consumers. Since consumers don't have
11
- * tree-sitter-cli installed, the actions always fail during `npm install`.
12
- *
13
- * Why we can't just upgrade:
14
- * tree-sitter-swift@0.7.1 fixes this (removes postinstall, ships prebuilds),
15
- * but it requires tree-sitter@^0.22.1. The upstream project pins tree-sitter
16
- * to ^0.21.0 and all other grammar packages depend on that version.
17
- * Upgrading tree-sitter would be a separate breaking change.
18
- *
19
- * How this workaround works:
20
- * 1. tree-sitter-swift's own postinstall fails (npm warns but continues)
21
- * 2. This script runs as gitnexus's postinstall
22
- * 3. It removes the "actions" array from binding.gyp
23
- * 4. It rebuilds the native binding with the cleaned binding.gyp
24
- *
25
- * TODO: Remove this script when tree-sitter is upgraded to ^0.22.x,
26
- * which allows using tree-sitter-swift@0.7.1+ directly.
27
- */
28
- const fs = require('fs');
29
- const path = require('path');
30
- const { execSync } = require('child_process');
31
-
32
- const swiftDir = path.join(__dirname, '..', 'node_modules', 'tree-sitter-swift');
33
- const bindingPath = path.join(swiftDir, 'binding.gyp');
34
-
35
- try {
36
- if (!fs.existsSync(bindingPath)) {
37
- process.exit(0);
38
- }
39
-
40
- const content = fs.readFileSync(bindingPath, 'utf8');
41
- let needsRebuild = false;
42
-
43
- if (content.includes('"actions"')) {
44
- // Strip Python-style comments (#) before JSON parsing
45
- const cleaned = content.replace(/#[^\n]*/g, '');
46
- const gyp = JSON.parse(cleaned);
47
-
48
- if (gyp.targets && gyp.targets[0] && gyp.targets[0].actions) {
49
- delete gyp.targets[0].actions;
50
- fs.writeFileSync(bindingPath, JSON.stringify(gyp, null, 2) + '\n');
51
- console.log('[tree-sitter-swift] Patched binding.gyp (removed actions array)');
52
- needsRebuild = true;
53
- }
54
- }
55
-
56
- // Check if native binding exists
57
- const bindingNode = path.join(swiftDir, 'build', 'Release', 'tree_sitter_swift_binding.node');
58
- if (!fs.existsSync(bindingNode)) {
59
- needsRebuild = true;
60
- }
61
-
62
- if (needsRebuild) {
63
- console.log('[tree-sitter-swift] Rebuilding native binding...');
64
- execSync('npx node-gyp rebuild', {
65
- cwd: swiftDir,
66
- stdio: 'pipe',
67
- timeout: 120000,
68
- });
69
- console.log('[tree-sitter-swift] Native binding built successfully');
70
- }
71
- } catch (err) {
72
- console.warn('[tree-sitter-swift] Could not build native binding:', err.message);
73
- console.warn('[tree-sitter-swift] You may need to manually run: cd node_modules/tree-sitter-swift && npx node-gyp rebuild');
74
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * WORKAROUND: tree-sitter-swift@0.6.0 binding.gyp build failure
4
+ *
5
+ * Background:
6
+ * tree-sitter-swift@0.6.0's binding.gyp contains an "actions" array that
7
+ * invokes `tree-sitter generate` to regenerate parser.c from grammar.js.
8
+ * This is intended for grammar developers, but the published npm package
9
+ * already ships pre-generated parser files (parser.c, scanner.c), so the
10
+ * actions are unnecessary for consumers. Since consumers don't have
11
+ * tree-sitter-cli installed, the actions always fail during `npm install`.
12
+ *
13
+ * Why we can't just upgrade:
14
+ * tree-sitter-swift@0.7.1 fixes this (removes postinstall, ships prebuilds),
15
+ * but it requires tree-sitter@^0.22.1. The upstream project pins tree-sitter
16
+ * to ^0.21.0 and all other grammar packages depend on that version.
17
+ * Upgrading tree-sitter would be a separate breaking change.
18
+ *
19
+ * How this workaround works:
20
+ * 1. tree-sitter-swift's own postinstall fails (npm warns but continues)
21
+ * 2. This script runs as gitnexus's postinstall
22
+ * 3. It removes the "actions" array from binding.gyp
23
+ * 4. It rebuilds the native binding with the cleaned binding.gyp
24
+ *
25
+ * TODO: Remove this script when tree-sitter is upgraded to ^0.22.x,
26
+ * which allows using tree-sitter-swift@0.7.1+ directly.
27
+ */
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+ const { execSync } = require('child_process');
31
+
32
+ const swiftDir = path.join(__dirname, '..', 'node_modules', 'tree-sitter-swift');
33
+ const bindingPath = path.join(swiftDir, 'binding.gyp');
34
+
35
+ try {
36
+ if (!fs.existsSync(bindingPath)) {
37
+ process.exit(0);
38
+ }
39
+
40
+ const content = fs.readFileSync(bindingPath, 'utf8');
41
+ let needsRebuild = false;
42
+
43
+ if (content.includes('"actions"')) {
44
+ // Strip Python-style comments (#) before JSON parsing
45
+ const cleaned = content.replace(/#[^\n]*/g, '');
46
+ const gyp = JSON.parse(cleaned);
47
+
48
+ if (gyp.targets && gyp.targets[0] && gyp.targets[0].actions) {
49
+ delete gyp.targets[0].actions;
50
+ fs.writeFileSync(bindingPath, JSON.stringify(gyp, null, 2) + '\n');
51
+ console.log('[tree-sitter-swift] Patched binding.gyp (removed actions array)');
52
+ needsRebuild = true;
53
+ }
54
+ }
55
+
56
+ // Check if native binding exists
57
+ const bindingNode = path.join(swiftDir, 'build', 'Release', 'tree_sitter_swift_binding.node');
58
+ if (!fs.existsSync(bindingNode)) {
59
+ needsRebuild = true;
60
+ }
61
+
62
+ if (needsRebuild) {
63
+ console.log('[tree-sitter-swift] Rebuilding native binding...');
64
+ execSync('npx node-gyp rebuild', {
65
+ cwd: swiftDir,
66
+ stdio: 'pipe',
67
+ timeout: 120000,
68
+ });
69
+ console.log('[tree-sitter-swift] Native binding built successfully');
70
+ }
71
+ } catch (err) {
72
+ console.warn('[tree-sitter-swift] Could not build native binding:', err.message);
73
+ console.warn('[tree-sitter-swift] You may need to manually run: cd node_modules/tree-sitter-swift && npx node-gyp rebuild');
74
+ }