gitnexus 1.3.3 → 1.3.5
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 +1 -1
- package/dist/cli/ai-context.js +23 -52
- package/dist/cli/analyze.js +4 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/mcp.js +11 -22
- package/dist/cli/serve.d.ts +1 -0
- package/dist/cli/serve.js +2 -1
- package/dist/cli/setup.js +2 -2
- package/dist/cli/wiki.js +6 -2
- package/dist/config/supported-languages.d.ts +3 -1
- package/dist/config/supported-languages.js +2 -2
- package/dist/core/embeddings/embedder.js +40 -1
- package/dist/core/graph/types.d.ts +2 -0
- package/dist/core/ingestion/call-processor.js +39 -0
- package/dist/core/ingestion/entry-point-scoring.js +49 -1
- package/dist/core/ingestion/framework-detection.d.ts +15 -4
- package/dist/core/ingestion/framework-detection.js +146 -5
- package/dist/core/ingestion/import-processor.js +140 -0
- package/dist/core/ingestion/parsing-processor.js +61 -8
- package/dist/core/ingestion/process-processor.js +7 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -0
- package/dist/core/ingestion/tree-sitter-queries.js +414 -282
- package/dist/core/ingestion/utils.js +8 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +3 -0
- package/dist/core/ingestion/workers/parse-worker.js +240 -0
- package/dist/core/kuzu/csv-generator.js +4 -2
- package/dist/core/kuzu/kuzu-adapter.d.ts +9 -0
- package/dist/core/kuzu/kuzu-adapter.js +68 -9
- package/dist/core/kuzu/schema.d.ts +6 -6
- package/dist/core/kuzu/schema.js +16 -0
- package/dist/core/tree-sitter/parser-loader.js +4 -0
- package/dist/core/wiki/generator.js +2 -2
- package/dist/mcp/local/local-backend.js +25 -13
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.js +13 -2
- package/dist/mcp/staleness.js +2 -2
- package/dist/server/api.d.ts +7 -5
- package/dist/server/api.js +145 -127
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/package.json +6 -2
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/{debugging.md → gitnexus-debugging.md} +12 -8
- package/skills/{exploring.md → gitnexus-exploring.md} +10 -7
- package/skills/gitnexus-guide.md +64 -0
- package/skills/{impact-analysis.md → gitnexus-impact-analysis.md} +14 -11
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/{refactoring.md → gitnexus-refactoring.md} +15 -7
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ GitNexus supports indexing multiple repositories. Each `gitnexus analyze` regist
|
|
|
156
156
|
|
|
157
157
|
## Supported Languages
|
|
158
158
|
|
|
159
|
-
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust
|
|
159
|
+
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust, PHP, Swift
|
|
160
160
|
|
|
161
161
|
## Agent Skills
|
|
162
162
|
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -29,12 +29,8 @@ function generateGitNexusContent(projectName, stats) {
|
|
|
29
29
|
|
|
30
30
|
This project is indexed by GitNexus as **${projectName}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows).
|
|
31
31
|
|
|
32
|
-
GitNexus provides a knowledge graph over this codebase — call chains, blast radius, execution flows, and semantic search.
|
|
33
|
-
|
|
34
32
|
## Always Start Here
|
|
35
33
|
|
|
36
|
-
For any task involving code understanding, debugging, impact analysis, or refactoring, you must:
|
|
37
|
-
|
|
38
34
|
1. **Read \`gitnexus://repo/{name}/context\`** — codebase overview + check index freshness
|
|
39
35
|
2. **Match your task to a skill below** and **read that skill file**
|
|
40
36
|
3. **Follow the skill's workflow and checklist**
|
|
@@ -45,45 +41,12 @@ For any task involving code understanding, debugging, impact analysis, or refact
|
|
|
45
41
|
|
|
46
42
|
| Task | Read this skill file |
|
|
47
43
|
|------|---------------------|
|
|
48
|
-
| Understand architecture / "How does X work?" | \`.claude/skills/gitnexus/exploring/SKILL.md\` |
|
|
49
|
-
| Blast radius / "What breaks if I change X?" | \`.claude/skills/gitnexus/impact-analysis/SKILL.md\` |
|
|
50
|
-
| Trace bugs / "Why is X failing?" | \`.claude/skills/gitnexus/debugging/SKILL.md\` |
|
|
51
|
-
| Rename / extract / split / refactor | \`.claude/skills/gitnexus/refactoring/SKILL.md\` |
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| Tool | What it gives you |
|
|
56
|
-
|------|-------------------|
|
|
57
|
-
| \`query\` | Process-grouped code intelligence — execution flows related to a concept |
|
|
58
|
-
| \`context\` | 360-degree symbol view — categorized refs, processes it participates in |
|
|
59
|
-
| \`impact\` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
|
|
60
|
-
| \`detect_changes\` | Git-diff impact — what do your current changes affect |
|
|
61
|
-
| \`rename\` | Multi-file coordinated rename with confidence-tagged edits |
|
|
62
|
-
| \`cypher\` | Raw graph queries (read \`gitnexus://repo/{name}/schema\` first) |
|
|
63
|
-
| \`list_repos\` | Discover indexed repos |
|
|
64
|
-
|
|
65
|
-
## Resources Reference
|
|
66
|
-
|
|
67
|
-
Lightweight reads (~100-500 tokens) for navigation:
|
|
68
|
-
|
|
69
|
-
| Resource | Content |
|
|
70
|
-
|----------|---------|
|
|
71
|
-
| \`gitnexus://repo/{name}/context\` | Stats, staleness check |
|
|
72
|
-
| \`gitnexus://repo/{name}/clusters\` | All functional areas with cohesion scores |
|
|
73
|
-
| \`gitnexus://repo/{name}/cluster/{clusterName}\` | Area members |
|
|
74
|
-
| \`gitnexus://repo/{name}/processes\` | All execution flows |
|
|
75
|
-
| \`gitnexus://repo/{name}/process/{processName}\` | Step-by-step trace |
|
|
76
|
-
| \`gitnexus://repo/{name}/schema\` | Graph schema for Cypher |
|
|
77
|
-
|
|
78
|
-
## Graph Schema
|
|
79
|
-
|
|
80
|
-
**Nodes:** File, Function, Class, Interface, Method, Community, Process
|
|
81
|
-
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
|
|
82
|
-
|
|
83
|
-
\`\`\`cypher
|
|
84
|
-
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
|
|
85
|
-
RETURN caller.name, caller.filePath
|
|
86
|
-
\`\`\`
|
|
44
|
+
| Understand architecture / "How does X work?" | \`.claude/skills/gitnexus/gitnexus-exploring/SKILL.md\` |
|
|
45
|
+
| Blast radius / "What breaks if I change X?" | \`.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md\` |
|
|
46
|
+
| Trace bugs / "Why is X failing?" | \`.claude/skills/gitnexus/gitnexus-debugging/SKILL.md\` |
|
|
47
|
+
| Rename / extract / split / refactor | \`.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md\` |
|
|
48
|
+
| Tools, resources, schema reference | \`.claude/skills/gitnexus/gitnexus-guide/SKILL.md\` |
|
|
49
|
+
| Index, status, clean, wiki CLI commands | \`.claude/skills/gitnexus/gitnexus-cli/SKILL.md\` |
|
|
87
50
|
|
|
88
51
|
${GITNEXUS_END_MARKER}`;
|
|
89
52
|
}
|
|
@@ -138,20 +101,28 @@ async function installSkills(repoPath) {
|
|
|
138
101
|
// Skill definitions bundled with the package
|
|
139
102
|
const skills = [
|
|
140
103
|
{
|
|
141
|
-
name: 'exploring',
|
|
142
|
-
description: '
|
|
104
|
+
name: 'gitnexus-exploring',
|
|
105
|
+
description: 'Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: "How does X work?", "What calls this function?", "Show me the auth flow"',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'gitnexus-debugging',
|
|
109
|
+
description: 'Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: "Why is X failing?", "Where does this error come from?", "Trace this bug"',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'gitnexus-impact-analysis',
|
|
113
|
+
description: 'Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: "Is it safe to change X?", "What depends on this?", "What will break?"',
|
|
143
114
|
},
|
|
144
115
|
{
|
|
145
|
-
name: '
|
|
146
|
-
description: '
|
|
116
|
+
name: 'gitnexus-refactoring',
|
|
117
|
+
description: 'Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: "Rename this function", "Extract this into a module", "Refactor this class", "Move this to a separate file"',
|
|
147
118
|
},
|
|
148
119
|
{
|
|
149
|
-
name: '
|
|
150
|
-
description: '
|
|
120
|
+
name: 'gitnexus-guide',
|
|
121
|
+
description: 'Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: "What GitNexus tools are available?", "How do I use GitNexus?"',
|
|
151
122
|
},
|
|
152
123
|
{
|
|
153
|
-
name: '
|
|
154
|
-
description: '
|
|
124
|
+
name: 'gitnexus-cli',
|
|
125
|
+
description: 'Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: "Index this repo", "Reanalyze the codebase", "Generate a wiki"',
|
|
155
126
|
},
|
|
156
127
|
];
|
|
157
128
|
for (const skill of skills) {
|
|
@@ -169,7 +140,7 @@ async function installSkills(repoPath) {
|
|
|
169
140
|
catch {
|
|
170
141
|
// Fallback: generate minimal skill content
|
|
171
142
|
skillContent = `---
|
|
172
|
-
name:
|
|
143
|
+
name: ${skill.name}
|
|
173
144
|
description: ${skill.description}
|
|
174
145
|
---
|
|
175
146
|
|
package/dist/cli/analyze.js
CHANGED
|
@@ -9,7 +9,9 @@ import v8 from 'v8';
|
|
|
9
9
|
import cliProgress from 'cli-progress';
|
|
10
10
|
import { runPipelineFromRepo } from '../core/ingestion/pipeline.js';
|
|
11
11
|
import { initKuzu, loadGraphToKuzu, getKuzuStats, executeQuery, executeWithReusedStatement, closeKuzu, createFTSIndex, loadCachedEmbeddings } from '../core/kuzu/kuzu-adapter.js';
|
|
12
|
-
|
|
12
|
+
// Embedding imports are lazy (dynamic import) so onnxruntime-node is never
|
|
13
|
+
// loaded when embeddings are not requested. This avoids crashes on Node
|
|
14
|
+
// versions whose ABI is not yet supported by the native binary (#89).
|
|
13
15
|
// disposeEmbedder intentionally not called — ONNX Runtime segfaults on cleanup (see #38)
|
|
14
16
|
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath } from '../storage/repo-manager.js';
|
|
15
17
|
import { getCurrentCommit, isGitRepo, getGitRoot } from '../storage/git.js';
|
|
@@ -231,6 +233,7 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
231
233
|
if (!embeddingSkipped) {
|
|
232
234
|
updateBar(90, 'Loading embedding model...');
|
|
233
235
|
const t0Emb = Date.now();
|
|
236
|
+
const { runEmbeddingPipeline } = await import('../core/embeddings/embedding-pipeline.js');
|
|
234
237
|
await runEmbeddingPipeline(executeQuery, executeWithReusedStatement, (progress) => {
|
|
235
238
|
const scaled = 90 + Math.round((progress.percent / 100) * 8);
|
|
236
239
|
const label = progress.phase === 'loading-model' ? 'Loading embedding model...' : `Embedding ${progress.nodesProcessed || 0}/${progress.totalNodes || '?'}`;
|
package/dist/cli/index.js
CHANGED
|
@@ -50,6 +50,7 @@ program
|
|
|
50
50
|
.command('serve')
|
|
51
51
|
.description('Start local HTTP server for web UI connection')
|
|
52
52
|
.option('-p, --port <port>', 'Port number', '4747')
|
|
53
|
+
.option('--host <host>', 'Bind address (default: 127.0.0.1, use 0.0.0.0 for remote access)')
|
|
53
54
|
.action(serveCommand);
|
|
54
55
|
program
|
|
55
56
|
.command('mcp')
|
package/dist/cli/mcp.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { startMCPServer } from '../mcp/server.js';
|
|
9
9
|
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
10
|
-
import { listRegisteredRepos } from '../storage/repo-manager.js';
|
|
11
10
|
export const mcpCommand = async () => {
|
|
12
11
|
// Prevent unhandled errors from crashing the MCP server process.
|
|
13
12
|
// KuzuDB lock conflicts and transient errors should degrade gracefully.
|
|
@@ -18,28 +17,18 @@ export const mcpCommand = async () => {
|
|
|
18
17
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
19
18
|
console.error(`GitNexus MCP: unhandled rejection — ${msg}`);
|
|
20
19
|
});
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.error('');
|
|
25
|
-
console.error(' GitNexus: No indexed repositories found.');
|
|
26
|
-
console.error('');
|
|
27
|
-
console.error(' To get started:');
|
|
28
|
-
console.error(' 1. cd into a git repository');
|
|
29
|
-
console.error(' 2. Run: gitnexus analyze');
|
|
30
|
-
console.error(' 3. Restart your editor');
|
|
31
|
-
console.error('');
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
// Initialize multi-repo backend from registry
|
|
20
|
+
// Initialize multi-repo backend from registry.
|
|
21
|
+
// The server starts even with 0 repos — tools call refreshRepos() lazily,
|
|
22
|
+
// so repos indexed after the server starts are discovered automatically.
|
|
35
23
|
const backend = new LocalBackend();
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
await backend.init();
|
|
25
|
+
const repos = await backend.listRepos();
|
|
26
|
+
if (repos.length === 0) {
|
|
27
|
+
console.error('GitNexus: No indexed repos yet. Run `gitnexus analyze` in a git repo — the server will pick it up automatically.');
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.error(`GitNexus: MCP server starting with ${repos.length} repo(s): ${repos.map(r => r.name).join(', ')}`);
|
|
40
31
|
}
|
|
41
|
-
|
|
42
|
-
console.error(`GitNexus: MCP server starting with ${repoNames.length} repo(s): ${repoNames.join(', ')}`);
|
|
43
|
-
// Start MCP server (serves all repos)
|
|
32
|
+
// Start MCP server (serves all repos, discovers new ones lazily)
|
|
44
33
|
await startMCPServer(backend);
|
|
45
34
|
};
|
package/dist/cli/serve.d.ts
CHANGED
package/dist/cli/serve.js
CHANGED
package/dist/cli/setup.js
CHANGED
|
@@ -198,7 +198,7 @@ async function setupOpenCode(result) {
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
// ─── Skill Installation ───────────────────────────────────────────
|
|
201
|
-
const SKILL_NAMES = ['exploring', 'debugging', 'impact-analysis', 'refactoring'];
|
|
201
|
+
const SKILL_NAMES = ['gitnexus-exploring', 'gitnexus-debugging', 'gitnexus-impact-analysis', 'gitnexus-refactoring', 'gitnexus-guide', 'gitnexus-cli'];
|
|
202
202
|
/**
|
|
203
203
|
* Install GitNexus skills to a target directory.
|
|
204
204
|
* Each skill is installed as {targetDir}/gitnexus-{skillName}/SKILL.md
|
|
@@ -212,7 +212,7 @@ async function installSkillsTo(targetDir) {
|
|
|
212
212
|
const installed = [];
|
|
213
213
|
const skillsRoot = path.join(__dirname, '..', '..', 'skills');
|
|
214
214
|
for (const skillName of SKILL_NAMES) {
|
|
215
|
-
const skillDir = path.join(targetDir,
|
|
215
|
+
const skillDir = path.join(targetDir, skillName);
|
|
216
216
|
try {
|
|
217
217
|
// Try directory-based skill first (skills/{name}/SKILL.md)
|
|
218
218
|
const dirSource = path.join(skillsRoot, skillName);
|
package/dist/cli/wiki.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import readline from 'readline';
|
|
9
|
-
import { execSync } from 'child_process';
|
|
9
|
+
import { execSync, execFileSync } from 'child_process';
|
|
10
10
|
import cliProgress from 'cli-progress';
|
|
11
11
|
import { getGitRoot, isGitRepo } from '../storage/git.js';
|
|
12
12
|
import { getStoragePaths, loadMeta, loadCLIConfig, saveCLIConfig } from '../storage/repo-manager.js';
|
|
@@ -299,7 +299,11 @@ function hasGhCLI() {
|
|
|
299
299
|
}
|
|
300
300
|
function publishGist(htmlPath) {
|
|
301
301
|
try {
|
|
302
|
-
const output =
|
|
302
|
+
const output = execFileSync('gh', [
|
|
303
|
+
'gist', 'create', htmlPath,
|
|
304
|
+
'--desc', 'Repository Wiki — generated by GitNexus',
|
|
305
|
+
'--public',
|
|
306
|
+
], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
303
307
|
// gh gist create prints the gist URL as the last line
|
|
304
308
|
const lines = output.split('\n');
|
|
305
309
|
const gistUrl = lines.find(l => l.includes('gist.github.com')) || lines[lines.length - 1];
|
|
@@ -9,7 +9,7 @@ export var SupportedLanguages;
|
|
|
9
9
|
SupportedLanguages["CSharp"] = "csharp";
|
|
10
10
|
SupportedLanguages["Go"] = "go";
|
|
11
11
|
SupportedLanguages["Rust"] = "rust";
|
|
12
|
-
|
|
12
|
+
SupportedLanguages["PHP"] = "php";
|
|
13
13
|
// Ruby = 'ruby',
|
|
14
|
-
|
|
14
|
+
SupportedLanguages["Swift"] = "swift";
|
|
15
15
|
})(SupportedLanguages || (SupportedLanguages = {}));
|
|
@@ -13,7 +13,44 @@ if (!process.env.ORT_LOG_LEVEL) {
|
|
|
13
13
|
process.env.ORT_LOG_LEVEL = '3';
|
|
14
14
|
}
|
|
15
15
|
import { pipeline, env } from '@huggingface/transformers';
|
|
16
|
+
import { existsSync } from 'fs';
|
|
17
|
+
import { execFileSync } from 'child_process';
|
|
18
|
+
import { join } from 'path';
|
|
16
19
|
import { DEFAULT_EMBEDDING_CONFIG } from './types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Check whether CUDA libraries are actually available on this system.
|
|
22
|
+
* ONNX Runtime's native layer crashes (uncatchable) if we attempt CUDA
|
|
23
|
+
* without the required shared libraries, so we probe first.
|
|
24
|
+
*
|
|
25
|
+
* Checks the dynamic linker cache (ldconfig) which covers all architectures
|
|
26
|
+
* and install paths, then falls back to CUDA_PATH / LD_LIBRARY_PATH env vars.
|
|
27
|
+
*/
|
|
28
|
+
function isCudaAvailable() {
|
|
29
|
+
// Primary: query the dynamic linker cache — covers all architectures,
|
|
30
|
+
// distro layouts, and custom install paths registered with ldconfig
|
|
31
|
+
try {
|
|
32
|
+
const out = execFileSync('ldconfig', ['-p'], { timeout: 3000, encoding: 'utf-8' });
|
|
33
|
+
if (out.includes('libcublasLt.so.12'))
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ldconfig not available (e.g. non-standard container)
|
|
38
|
+
}
|
|
39
|
+
// Fallback: check CUDA_PATH and LD_LIBRARY_PATH for environments where
|
|
40
|
+
// ldconfig doesn't know about the CUDA install (conda, manual /opt/cuda, etc.)
|
|
41
|
+
for (const envVar of ['CUDA_PATH', 'LD_LIBRARY_PATH']) {
|
|
42
|
+
const val = process.env[envVar];
|
|
43
|
+
if (!val)
|
|
44
|
+
continue;
|
|
45
|
+
for (const dir of val.split(':').filter(Boolean)) {
|
|
46
|
+
if (existsSync(join(dir, 'lib64', 'libcublasLt.so.12')) ||
|
|
47
|
+
existsSync(join(dir, 'lib', 'libcublasLt.so.12')) ||
|
|
48
|
+
existsSync(join(dir, 'libcublasLt.so.12')))
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
17
54
|
// Module-level state for singleton pattern
|
|
18
55
|
let embedderInstance = null;
|
|
19
56
|
let isInitializing = false;
|
|
@@ -45,8 +82,10 @@ export const initEmbedder = async (onProgress, config = {}, forceDevice) => {
|
|
|
45
82
|
const finalConfig = { ...DEFAULT_EMBEDDING_CONFIG, ...config };
|
|
46
83
|
// On Windows, use DirectML for GPU acceleration (via DirectX12)
|
|
47
84
|
// CUDA is only available on Linux x64 with onnxruntime-node
|
|
85
|
+
// Probe for CUDA first — ONNX Runtime crashes (uncatchable native error)
|
|
86
|
+
// if we attempt CUDA without the required shared libraries
|
|
48
87
|
const isWindows = process.platform === 'win32';
|
|
49
|
-
const gpuDevice = isWindows ? 'dml' : 'cuda';
|
|
88
|
+
const gpuDevice = isWindows ? 'dml' : (isCudaAvailable() ? 'cuda' : 'cpu');
|
|
50
89
|
let requestedDevice = forceDevice || (finalConfig.device === 'auto' ? gpuDevice : finalConfig.device);
|
|
51
90
|
initPromise = (async () => {
|
|
52
91
|
try {
|
|
@@ -31,6 +31,9 @@ const FUNCTION_NODE_TYPES = new Set([
|
|
|
31
31
|
// Rust
|
|
32
32
|
'function_item',
|
|
33
33
|
'impl_item', // Methods inside impl blocks
|
|
34
|
+
// Swift
|
|
35
|
+
'init_declaration',
|
|
36
|
+
'deinit_declaration',
|
|
34
37
|
]);
|
|
35
38
|
/**
|
|
36
39
|
* Walk up the AST from a node to find the enclosing function/method.
|
|
@@ -44,6 +47,11 @@ const findEnclosingFunction = (node, filePath, symbolTable) => {
|
|
|
44
47
|
let funcName = null;
|
|
45
48
|
let label = 'Function';
|
|
46
49
|
// Different node types have different name locations
|
|
50
|
+
// Swift init/deinit — handle before generic cases (more specific)
|
|
51
|
+
if (current.type === 'init_declaration' || current.type === 'deinit_declaration') {
|
|
52
|
+
const funcName = current.type === 'init_declaration' ? 'init' : 'deinit';
|
|
53
|
+
return generateId('Constructor', `${filePath}:${funcName}`);
|
|
54
|
+
}
|
|
47
55
|
if (current.type === 'function_declaration' ||
|
|
48
56
|
current.type === 'function_definition' ||
|
|
49
57
|
current.type === 'async_function_declaration' ||
|
|
@@ -282,6 +290,37 @@ const BUILT_IN_NAMES = new Set([
|
|
|
282
290
|
'mutex_lock', 'mutex_unlock', 'mutex_init',
|
|
283
291
|
'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
|
|
284
292
|
'get', 'put',
|
|
293
|
+
// Swift/iOS built-ins and standard library
|
|
294
|
+
'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
|
|
295
|
+
'assert', 'assertionFailure', 'NSLog',
|
|
296
|
+
'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
|
|
297
|
+
'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
|
|
298
|
+
'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
|
|
299
|
+
'type', 'MemoryLayout',
|
|
300
|
+
// Swift collection/string methods (common noise)
|
|
301
|
+
'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
|
|
302
|
+
'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
|
|
303
|
+
'sorted', 'reversed', 'enumerated', 'joined', 'split',
|
|
304
|
+
'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
|
|
305
|
+
'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
|
|
306
|
+
// UIKit/Foundation common methods (noise in call graph)
|
|
307
|
+
'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
|
|
308
|
+
'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
|
|
309
|
+
'addTarget', 'removeTarget', 'addGestureRecognizer',
|
|
310
|
+
'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
|
|
311
|
+
'NSLocalizedString', 'Bundle',
|
|
312
|
+
'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
|
|
313
|
+
'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
|
|
314
|
+
'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
|
|
315
|
+
'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
|
|
316
|
+
'performSegue', 'prepare',
|
|
317
|
+
// GCD / async
|
|
318
|
+
'DispatchQueue', 'async', 'sync', 'asyncAfter',
|
|
319
|
+
'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
|
|
320
|
+
// Combine
|
|
321
|
+
'sink', 'store', 'assign', 'receive', 'subscribe',
|
|
322
|
+
// Notification / KVO
|
|
323
|
+
'addObserver', 'removeObserver', 'post', 'NotificationCenter',
|
|
285
324
|
]);
|
|
286
325
|
const isBuiltInOrNoise = (name) => BUILT_IN_NAMES.has(name);
|
|
287
326
|
/**
|
|
@@ -91,6 +91,45 @@ const ENTRY_POINT_PATTERNS = {
|
|
|
91
91
|
/^Run$/, // Run methods
|
|
92
92
|
/^Start$/, // Start methods
|
|
93
93
|
],
|
|
94
|
+
// Swift / iOS
|
|
95
|
+
'swift': [
|
|
96
|
+
/^viewDidLoad$/, // UIKit lifecycle
|
|
97
|
+
/^viewWillAppear$/, // UIKit lifecycle
|
|
98
|
+
/^viewDidAppear$/, // UIKit lifecycle
|
|
99
|
+
/^viewWillDisappear$/, // UIKit lifecycle
|
|
100
|
+
/^viewDidDisappear$/, // UIKit lifecycle
|
|
101
|
+
/^application\(/, // AppDelegate methods
|
|
102
|
+
/^scene\(/, // SceneDelegate methods
|
|
103
|
+
/^body$/, // SwiftUI View.body
|
|
104
|
+
/Coordinator$/, // Coordinator pattern
|
|
105
|
+
/^sceneDidBecomeActive$/, // SceneDelegate lifecycle
|
|
106
|
+
/^sceneWillResignActive$/, // SceneDelegate lifecycle
|
|
107
|
+
/^didFinishLaunchingWithOptions$/, // AppDelegate
|
|
108
|
+
/ViewController$/, // ViewController classes
|
|
109
|
+
/^configure[A-Z]/, // Configuration methods
|
|
110
|
+
/^setup[A-Z]/, // Setup methods
|
|
111
|
+
/^makeBody$/, // SwiftUI ViewModifier
|
|
112
|
+
],
|
|
113
|
+
// PHP / Laravel
|
|
114
|
+
'php': [
|
|
115
|
+
/Controller$/, // UserController (class name convention)
|
|
116
|
+
/^handle$/, // Job::handle(), Listener::handle()
|
|
117
|
+
/^execute$/, // Command::execute()
|
|
118
|
+
/^boot$/, // ServiceProvider::boot()
|
|
119
|
+
/^register$/, // ServiceProvider::register()
|
|
120
|
+
/^__invoke$/, // Invokable controllers/actions
|
|
121
|
+
/^(index|show|store|update|destroy|create|edit)$/, // RESTful resource methods
|
|
122
|
+
/^(get|post|put|delete|patch)[A-Z]/, // Explicit HTTP method actions
|
|
123
|
+
/^run$/, // Command/Job run()
|
|
124
|
+
/^fire$/, // Event fire()
|
|
125
|
+
/^dispatch$/, // Dispatchable jobs
|
|
126
|
+
/Service$/, // UserService (Service layer)
|
|
127
|
+
/Repository$/, // UserRepository (Repository pattern)
|
|
128
|
+
/^find$/, // Repository::find()
|
|
129
|
+
/^findAll$/, // Repository::findAll()
|
|
130
|
+
/^save$/, // Repository::save()
|
|
131
|
+
/^delete$/, // Repository::delete()
|
|
132
|
+
],
|
|
94
133
|
};
|
|
95
134
|
// ============================================================================
|
|
96
135
|
// UTILITY PATTERNS - Functions that should be penalized
|
|
@@ -209,9 +248,18 @@ export function isTestFile(filePath) {
|
|
|
209
248
|
p.includes('/src/test/') ||
|
|
210
249
|
// Rust test patterns (inline tests are different, but test files)
|
|
211
250
|
p.includes('/tests/') ||
|
|
251
|
+
// Swift/iOS test patterns
|
|
252
|
+
p.endsWith('tests.swift') ||
|
|
253
|
+
p.endsWith('test.swift') ||
|
|
254
|
+
p.includes('uitests/') ||
|
|
212
255
|
// C# test patterns
|
|
213
256
|
p.includes('.tests/') ||
|
|
214
|
-
p.includes('tests.cs')
|
|
257
|
+
p.includes('tests.cs') ||
|
|
258
|
+
// PHP/Laravel test patterns
|
|
259
|
+
p.endsWith('test.php') ||
|
|
260
|
+
p.endsWith('spec.php') ||
|
|
261
|
+
p.includes('/tests/feature/') ||
|
|
262
|
+
p.includes('/tests/unit/'));
|
|
215
263
|
}
|
|
216
264
|
/**
|
|
217
265
|
* Check if a file path is likely a utility/helper file
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Framework Detection
|
|
3
3
|
*
|
|
4
|
-
* Detects frameworks from
|
|
5
|
-
*
|
|
4
|
+
* Detects frameworks from:
|
|
5
|
+
* 1) file path patterns
|
|
6
|
+
* 2) AST definition text (decorators/annotations/attributes)
|
|
7
|
+
* and provides entry point multipliers for process scoring.
|
|
6
8
|
*
|
|
7
9
|
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
8
10
|
* (no bonus, no penalty) - same behavior as before this feature.
|
|
@@ -20,8 +22,8 @@ export interface FrameworkHint {
|
|
|
20
22
|
*/
|
|
21
23
|
export declare function detectFrameworkFromPath(filePath: string): FrameworkHint | null;
|
|
22
24
|
/**
|
|
23
|
-
* Patterns that indicate entry points within code
|
|
24
|
-
* These
|
|
25
|
+
* Patterns that indicate framework entry points within code definitions.
|
|
26
|
+
* These are matched against AST node text (class/method/function declaration text).
|
|
25
27
|
*/
|
|
26
28
|
export declare const FRAMEWORK_AST_PATTERNS: {
|
|
27
29
|
nestjs: string[];
|
|
@@ -32,7 +34,16 @@ export declare const FRAMEWORK_AST_PATTERNS: {
|
|
|
32
34
|
jaxrs: string[];
|
|
33
35
|
aspnet: string[];
|
|
34
36
|
'go-http': string[];
|
|
37
|
+
laravel: string[];
|
|
35
38
|
actix: string[];
|
|
36
39
|
axum: string[];
|
|
37
40
|
rocket: string[];
|
|
41
|
+
uikit: string[];
|
|
42
|
+
swiftui: string[];
|
|
43
|
+
combine: string[];
|
|
38
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
47
|
+
* Returns null if no known pattern is found.
|
|
48
|
+
*/
|
|
49
|
+
export declare function detectFrameworkFromAST(language: string, definitionText: string): FrameworkHint | null;
|