@veewo/gitnexus 1.5.0-rc.4 → 1.5.0
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/dist/benchmark/analyze-runner.d.ts +1 -1
- package/dist/benchmark/analyze-runner.js +4 -3
- package/dist/benchmark/analyze-runner.test.js +7 -0
- package/dist/cli/ai-context.d.ts +0 -1
- package/dist/cli/ai-context.js +15 -6
- package/dist/cli/analyze-options.js +58 -34
- package/dist/cli/analyze-options.test.js +57 -0
- package/dist/cli/analyze-runtime-summary.js +1 -0
- package/dist/cli/analyze-runtime-summary.test.js +10 -0
- package/dist/cli/analyze-summary.d.ts +2 -0
- package/dist/cli/analyze-summary.js +19 -0
- package/dist/cli/analyze.d.ts +11 -0
- package/dist/cli/analyze.js +30 -5
- package/dist/cli/analyze.test.d.ts +1 -0
- package/dist/cli/analyze.test.js +25 -0
- package/dist/cli/benchmark-agent-context.js +1 -1
- package/dist/cli/benchmark-unity.js +1 -1
- package/dist/cli/benchmark-unity.test.js +5 -1
- package/dist/cli/index.js +4 -2
- package/dist/cli/scope-manifest-config.d.ts +9 -0
- package/dist/cli/scope-manifest-config.js +37 -0
- package/dist/cli/setup.js +40 -41
- package/dist/cli/setup.test.js +14 -14
- package/dist/cli/sync-manifest.d.ts +27 -0
- package/dist/cli/sync-manifest.js +200 -0
- package/dist/cli/sync-manifest.test.d.ts +1 -0
- package/dist/cli/sync-manifest.test.js +88 -0
- package/dist/core/config/unity-config.d.ts +1 -0
- package/dist/core/config/unity-config.js +1 -0
- package/dist/core/ingestion/call-processor.d.ts +2 -1
- package/dist/core/ingestion/call-processor.js +28 -6
- package/dist/core/ingestion/heritage-processor.d.ts +2 -1
- package/dist/core/ingestion/heritage-processor.js +30 -7
- package/dist/core/ingestion/import-processor.d.ts +2 -1
- package/dist/core/ingestion/import-processor.js +28 -6
- package/dist/core/ingestion/parsing-processor.d.ts +5 -3
- package/dist/core/ingestion/parsing-processor.js +46 -13
- package/dist/core/ingestion/pipeline.js +65 -13
- package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +1 -1
- package/dist/core/ingestion/unity-runtime-binding-rules.js +21 -18
- package/dist/core/ingestion/workers/parse-worker.d.ts +2 -0
- package/dist/core/ingestion/workers/parse-worker.js +50 -6
- package/dist/core/tree-sitter/csharp-define-profile.d.ts +6 -0
- package/dist/core/tree-sitter/csharp-define-profile.js +43 -0
- package/dist/core/tree-sitter/csharp-preproc-normalizer.d.ts +14 -0
- package/dist/core/tree-sitter/csharp-preproc-normalizer.js +261 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +10 -0
- package/dist/core/tree-sitter/parser-loader.js +19 -0
- package/dist/types/pipeline.d.ts +13 -0
- package/package.json +12 -12
- package/scripts/check-sync-manifest-traceability.mjs +203 -0
- package/scripts/tree-sitter-audit-classify.mjs +172 -0
- package/skills/gitnexus-cli.md +36 -4
- package/skills/gitnexus-unity-rule-gen.md +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veewo/gitnexus",
|
|
3
|
-
"version": "1.5.0
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"vendor"
|
|
38
38
|
],
|
|
39
39
|
"scripts": {
|
|
40
|
-
"build": "rm -rf dist && tsc",
|
|
40
|
+
"build": "rm -rf dist && tsc && chmod +x dist/cli/index.js",
|
|
41
41
|
"dev": "tsx watch src/cli/index.ts",
|
|
42
42
|
"test": "vitest run test/unit",
|
|
43
43
|
"test:integration": "vitest run test/integration",
|
|
@@ -84,18 +84,18 @@
|
|
|
84
84
|
"lru-cache": "^11.0.0",
|
|
85
85
|
"mnemonist": "^0.39.0",
|
|
86
86
|
"pandemonium": "^2.4.0",
|
|
87
|
-
"tree-sitter": "^0.
|
|
88
|
-
"tree-sitter-c": "^0.
|
|
89
|
-
"tree-sitter-c-sharp": "^0.
|
|
90
|
-
"tree-sitter-cpp": "^0.
|
|
91
|
-
"tree-sitter-go": "^0.
|
|
92
|
-
"tree-sitter-java": "^0.
|
|
93
|
-
"tree-sitter-javascript": "^0.
|
|
87
|
+
"tree-sitter": "^0.22.0",
|
|
88
|
+
"tree-sitter-c": "^0.23.0",
|
|
89
|
+
"tree-sitter-c-sharp": "^0.23.1",
|
|
90
|
+
"tree-sitter-cpp": "^0.23.0",
|
|
91
|
+
"tree-sitter-go": "^0.23.0",
|
|
92
|
+
"tree-sitter-java": "^0.23.2",
|
|
93
|
+
"tree-sitter-javascript": "^0.23.0",
|
|
94
94
|
"tree-sitter-php": "^0.23.12",
|
|
95
|
-
"tree-sitter-python": "^0.
|
|
95
|
+
"tree-sitter-python": "^0.23.2",
|
|
96
96
|
"tree-sitter-ruby": "^0.23.1",
|
|
97
|
-
"tree-sitter-rust": "^0.
|
|
98
|
-
"tree-sitter-typescript": "^0.
|
|
97
|
+
"tree-sitter-rust": "^0.23.0",
|
|
98
|
+
"tree-sitter-typescript": "^0.23.0",
|
|
99
99
|
"uuid": "^13.0.0"
|
|
100
100
|
},
|
|
101
101
|
"optionalDependencies": {
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const planArg = process.argv[2];
|
|
6
|
+
if (!planArg) {
|
|
7
|
+
console.error('Usage: node gitnexus/scripts/check-sync-manifest-traceability.mjs <plan.md>');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const root = process.cwd();
|
|
12
|
+
const planPath = path.resolve(root, planArg);
|
|
13
|
+
|
|
14
|
+
const requiredCriticalDc = {
|
|
15
|
+
'DC-01': {
|
|
16
|
+
semanticCases: [
|
|
17
|
+
{
|
|
18
|
+
id: 'directive parsing',
|
|
19
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
20
|
+
pattern: "resolveEffectiveAnalyzeOptions reads @extensions/@repoAlias/@embeddings from manifest",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'unknown directive fail-fast',
|
|
24
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
25
|
+
pattern: 'resolveEffectiveAnalyzeOptions rejects unknown manifest directives',
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
29
|
+
},
|
|
30
|
+
'DC-02': {
|
|
31
|
+
semanticCases: [
|
|
32
|
+
{
|
|
33
|
+
id: 'precedence merge case',
|
|
34
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
35
|
+
pattern: 'resolveEffectiveAnalyzeOptions enforces precedence CLI > manifest > meta',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
39
|
+
},
|
|
40
|
+
'DC-03': {
|
|
41
|
+
semanticCases: [
|
|
42
|
+
{
|
|
43
|
+
id: 'auto default sync-manifest load case',
|
|
44
|
+
file: 'gitnexus/src/cli/analyze.test.ts',
|
|
45
|
+
pattern: 'analyze auto-loads .gitnexus/sync-manifest.txt when CLI scope options are omitted',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze.test.js'],
|
|
49
|
+
},
|
|
50
|
+
'DC-04': {
|
|
51
|
+
semanticCases: [
|
|
52
|
+
{
|
|
53
|
+
id: 'mismatch prompt decision case',
|
|
54
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
55
|
+
pattern: 'when explicit CLI values differ from manifest, TTY mode asks whether to update manifest',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'update decision case',
|
|
59
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
60
|
+
pattern: 'policy=update rewrites manifest with normalized directives',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
commandMustInclude: [
|
|
64
|
+
'gitnexus/dist/cli/sync-manifest.test.js',
|
|
65
|
+
'gitnexus/dist/cli/analyze.test.js',
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
'DC-05': {
|
|
69
|
+
semanticCases: [
|
|
70
|
+
{
|
|
71
|
+
id: 'unknown directive fail-fast case',
|
|
72
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
73
|
+
pattern: 'resolveEffectiveAnalyzeOptions rejects unknown manifest directives',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
77
|
+
},
|
|
78
|
+
'DC-08': {
|
|
79
|
+
semanticCases: [
|
|
80
|
+
{
|
|
81
|
+
id: 'placeholder rejection case',
|
|
82
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
83
|
+
pattern: 'rejects placeholder manifest path values',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'non-TTY policy gate case',
|
|
87
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
88
|
+
pattern: 'non-TTY without explicit policy exits with actionable error',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
commandMustInclude: [
|
|
92
|
+
'gitnexus/dist/cli/sync-manifest.test.js',
|
|
93
|
+
'gitnexus/dist/cli/analyze.test.js',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function normalizeCell(value) {
|
|
99
|
+
return value.trim().replace(/^`|`$/g, '').trim();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseTraceabilityRows(planText) {
|
|
103
|
+
const rows = [];
|
|
104
|
+
for (const line of planText.split(/\r?\n/)) {
|
|
105
|
+
if (!line.startsWith('DC-')) continue;
|
|
106
|
+
const parts = line.split(' | ').map((p) => p.trim());
|
|
107
|
+
if (parts.length < 6) continue;
|
|
108
|
+
|
|
109
|
+
const idMatch = parts[0].match(/^(DC-\d+)/);
|
|
110
|
+
if (!idMatch) continue;
|
|
111
|
+
|
|
112
|
+
rows.push({
|
|
113
|
+
id: idMatch[1],
|
|
114
|
+
criticality: parts[1],
|
|
115
|
+
mappedTasks: normalizeCell(parts[2]),
|
|
116
|
+
verificationCommand: normalizeCell(parts[3]),
|
|
117
|
+
artifactEvidenceField: normalizeCell(parts[4]),
|
|
118
|
+
failureSignal: normalizeCell(parts.slice(5).join(' | ')),
|
|
119
|
+
raw: line,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return rows;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function validateCriticalRowShape(row, errors) {
|
|
126
|
+
if (!row.mappedTasks || row.mappedTasks === '-') {
|
|
127
|
+
errors.push(`${row.id}: missing mapped tasks`);
|
|
128
|
+
}
|
|
129
|
+
if (!/Task\s*\d+/i.test(row.mappedTasks)) {
|
|
130
|
+
errors.push(`${row.id}: mapped tasks do not reference concrete task ids`);
|
|
131
|
+
}
|
|
132
|
+
if (!row.verificationCommand || row.verificationCommand === '-') {
|
|
133
|
+
errors.push(`${row.id}: missing verification command`);
|
|
134
|
+
}
|
|
135
|
+
if (!row.artifactEvidenceField || row.artifactEvidenceField === '-') {
|
|
136
|
+
errors.push(`${row.id}: missing artifact evidence field`);
|
|
137
|
+
}
|
|
138
|
+
if (!row.failureSignal || row.failureSignal === '-') {
|
|
139
|
+
errors.push(`${row.id}: missing failure signal`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function validateSemanticCases(dcId, config, errors) {
|
|
144
|
+
for (const semanticCase of config.semanticCases) {
|
|
145
|
+
const casePath = path.resolve(root, semanticCase.file);
|
|
146
|
+
let content = '';
|
|
147
|
+
try {
|
|
148
|
+
content = await fs.readFile(casePath, 'utf-8');
|
|
149
|
+
} catch {
|
|
150
|
+
errors.push(`${dcId}: missing semantic case file ${semanticCase.file}`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (!content.includes(semanticCase.pattern)) {
|
|
154
|
+
errors.push(`${dcId}: missing semantic case '${semanticCase.id}' in ${semanticCase.file}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function validateCommandCoverage(row, config, errors) {
|
|
160
|
+
for (const requiredFragment of config.commandMustInclude) {
|
|
161
|
+
if (!row.verificationCommand.includes(requiredFragment)) {
|
|
162
|
+
errors.push(`${row.id}: verification command missing '${requiredFragment}'`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function main() {
|
|
168
|
+
const planText = await fs.readFile(planPath, 'utf-8');
|
|
169
|
+
const rows = parseTraceabilityRows(planText);
|
|
170
|
+
const rowById = new Map(rows.map((row) => [row.id, row]));
|
|
171
|
+
const errors = [];
|
|
172
|
+
|
|
173
|
+
for (const dcId of Object.keys(requiredCriticalDc)) {
|
|
174
|
+
const row = rowById.get(dcId);
|
|
175
|
+
if (!row) {
|
|
176
|
+
errors.push(`missing critical row ${dcId} in Design Traceability Matrix`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (row.criticality !== 'critical') {
|
|
181
|
+
errors.push(`${dcId}: expected critical criticality, got '${row.criticality}'`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
validateCriticalRowShape(row, errors);
|
|
185
|
+
validateCommandCoverage(row, requiredCriticalDc[dcId], errors);
|
|
186
|
+
await validateSemanticCases(dcId, requiredCriticalDc[dcId], errors);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (errors.length > 0) {
|
|
190
|
+
console.error('Sync-manifest traceability check failed:\n');
|
|
191
|
+
for (const error of errors) {
|
|
192
|
+
console.error(`- ${error}`);
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log('Sync-manifest traceability check passed.');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
main().catch((error) => {
|
|
201
|
+
console.error(error?.stack || String(error));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const CONTAINER_KEYS = ['class', 'interface', 'struct', 'record', 'delegate', 'enum'];
|
|
7
|
+
|
|
8
|
+
function toNumber(value) {
|
|
9
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
10
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
11
|
+
const parsed = Number(value);
|
|
12
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
13
|
+
}
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeContainerCounts(record) {
|
|
18
|
+
const counts = {
|
|
19
|
+
class: toNumber(record.class_count),
|
|
20
|
+
interface: toNumber(record.interface_count),
|
|
21
|
+
struct: toNumber(record.struct_count),
|
|
22
|
+
record: toNumber(record.record_count),
|
|
23
|
+
delegate: toNumber(record.delegate_count),
|
|
24
|
+
enum: toNumber(record.enum_count),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (record.container_counts && typeof record.container_counts === 'object') {
|
|
28
|
+
for (const key of CONTAINER_KEYS) {
|
|
29
|
+
counts[key] = toNumber(record.container_counts[key] ?? counts[key]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return counts;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function computeClassifiedType(record, containerCounts) {
|
|
37
|
+
const methodCount = toNumber(record.method_count);
|
|
38
|
+
const rootHasError = Boolean(record.root_has_error);
|
|
39
|
+
const rawErrorType = String(record.error_type || '');
|
|
40
|
+
const totalContainers = CONTAINER_KEYS.reduce((sum, key) => sum + containerCounts[key], 0);
|
|
41
|
+
const legacyMissingClass = methodCount > 0 && containerCounts.class === 0;
|
|
42
|
+
const missingContainer = methodCount > 0 && totalContainers === 0;
|
|
43
|
+
const isFalsePositiveLikely = legacyMissingClass && !missingContainer;
|
|
44
|
+
|
|
45
|
+
let errorType = 'ok';
|
|
46
|
+
if (rawErrorType === 'parse_throw') {
|
|
47
|
+
errorType = 'parse_throw';
|
|
48
|
+
} else if (rootHasError || rawErrorType === 'root_has_error') {
|
|
49
|
+
errorType = 'root_has_error';
|
|
50
|
+
} else if (missingContainer) {
|
|
51
|
+
errorType = 'missing_container_with_methods';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
errorType,
|
|
56
|
+
legacyMissingClass,
|
|
57
|
+
missingContainer,
|
|
58
|
+
isFalsePositiveLikely,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function classifyTreeSitterAuditRecords(records) {
|
|
63
|
+
const byType = {
|
|
64
|
+
parse_throw: 0,
|
|
65
|
+
root_has_error: 0,
|
|
66
|
+
missing_container_with_methods: 0,
|
|
67
|
+
ok: 0,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const containerTotals = {
|
|
71
|
+
class: 0,
|
|
72
|
+
interface: 0,
|
|
73
|
+
struct: 0,
|
|
74
|
+
record: 0,
|
|
75
|
+
delegate: 0,
|
|
76
|
+
enum: 0,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
let compatibilityMissingClassCount = 0;
|
|
80
|
+
let falsePositiveLikelyCount = 0;
|
|
81
|
+
|
|
82
|
+
const classified = records.map((record) => {
|
|
83
|
+
const containerCounts = normalizeContainerCounts(record);
|
|
84
|
+
const classification = computeClassifiedType(record, containerCounts);
|
|
85
|
+
const compatibilityTags = [];
|
|
86
|
+
|
|
87
|
+
if (classification.legacyMissingClass) {
|
|
88
|
+
compatibilityTags.push('missing_class_with_methods');
|
|
89
|
+
compatibilityMissingClassCount += 1;
|
|
90
|
+
}
|
|
91
|
+
if (classification.isFalsePositiveLikely) {
|
|
92
|
+
falsePositiveLikelyCount += 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key of CONTAINER_KEYS) {
|
|
96
|
+
containerTotals[key] += containerCounts[key];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
byType[classification.errorType] += 1;
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
...record,
|
|
103
|
+
container_counts: containerCounts,
|
|
104
|
+
classified_error_type: classification.errorType,
|
|
105
|
+
compatibility_tags: compatibilityTags,
|
|
106
|
+
is_false_positive_likely: classification.isFalsePositiveLikely,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
summary: {
|
|
112
|
+
total: classified.length,
|
|
113
|
+
byType,
|
|
114
|
+
compatibility: {
|
|
115
|
+
missing_class_with_methods: compatibilityMissingClassCount,
|
|
116
|
+
},
|
|
117
|
+
falsePositiveLikely: falsePositiveLikelyCount,
|
|
118
|
+
containerTotals,
|
|
119
|
+
},
|
|
120
|
+
records: classified,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseArgs(argv) {
|
|
125
|
+
const args = {};
|
|
126
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
127
|
+
const arg = argv[i];
|
|
128
|
+
if (arg === '--input') args.input = argv[i + 1];
|
|
129
|
+
if (arg === '--output') args.output = argv[i + 1];
|
|
130
|
+
}
|
|
131
|
+
return args;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function readJsonl(inputPath) {
|
|
135
|
+
const raw = await fs.readFile(inputPath, 'utf-8');
|
|
136
|
+
return raw
|
|
137
|
+
.split(/\r?\n/)
|
|
138
|
+
.map((line) => line.trim())
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.map((line) => JSON.parse(line));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function writeOutput(outputPath, data) {
|
|
144
|
+
const resolved = path.resolve(outputPath);
|
|
145
|
+
await fs.mkdir(path.dirname(resolved), { recursive: true });
|
|
146
|
+
await fs.writeFile(resolved, `${JSON.stringify(data, null, 2)}\n`, 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function main() {
|
|
150
|
+
const args = parseArgs(process.argv);
|
|
151
|
+
if (!args.input) {
|
|
152
|
+
console.error('Usage: node scripts/tree-sitter-audit-classify.mjs --input <diagnostics.jsonl> [--output <report.json>]');
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const records = await readJsonl(path.resolve(args.input));
|
|
158
|
+
const report = classifyTreeSitterAuditRecords(records);
|
|
159
|
+
|
|
160
|
+
if (args.output) {
|
|
161
|
+
await writeOutput(args.output, report);
|
|
162
|
+
} else {
|
|
163
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
168
|
+
main().catch((error) => {
|
|
169
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
170
|
+
process.exitCode = 1;
|
|
171
|
+
});
|
|
172
|
+
}
|
package/skills/gitnexus-cli.md
CHANGED
|
@@ -5,7 +5,25 @@ description: "Use when the user needs to run GitNexus CLI commands like analyze/
|
|
|
5
5
|
|
|
6
6
|
# GitNexus CLI Commands
|
|
7
7
|
|
|
8
|
-
Use one command alias in the session so every CLI/MCP call stays on one version line. After `setup`,
|
|
8
|
+
Use one command alias in the session so every CLI/MCP call stays on one version line. After `setup`, use `~/.gitnexus/config.json` as the CLI package spec source (`cliPackageSpec` first, then `cliVersion`). MCP wiring and skill install locations are scope-dependent (`project` vs `global`).
|
|
9
|
+
|
|
10
|
+
### setup — choose scope explicitly
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
gitnexus setup --scope project --agent codex --cli-spec @veewo/gitnexus@<version>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Rules:
|
|
17
|
+
|
|
18
|
+
- If user asks "setup this repository" / "本仓库 setup", use `--scope project`.
|
|
19
|
+
- `--scope project` updates repo-local files:
|
|
20
|
+
- Codex MCP config: `.codex/config.toml`
|
|
21
|
+
- Skills: `.agents/skills/gitnexus/`
|
|
22
|
+
- `--scope global` updates user-global files:
|
|
23
|
+
- Codex MCP config: `~/.codex/config.toml`
|
|
24
|
+
- Skills: `~/.agents/skills/gitnexus/`
|
|
25
|
+
- `--scope global` does not overwrite repo-local `.agents/skills` or `.codex/config.toml`.
|
|
26
|
+
- Never rely on setup defaults for scope; pass `--scope` explicitly to avoid global/project mismatch.
|
|
9
27
|
|
|
10
28
|
```bash
|
|
11
29
|
if command -v gitnexus >/dev/null 2>&1; then
|
|
@@ -46,16 +64,30 @@ Run from the project root. This parses all source files, builds the knowledge gr
|
|
|
46
64
|
| -------------------------- | ----------------------------------------------------------------------------------------- |
|
|
47
65
|
| `--force` | Force full re-index even if up to date |
|
|
48
66
|
| `--embeddings` | Enable embedding generation for semantic search (off by default) |
|
|
49
|
-
| `--extensions <ext>` | Limit parsing to specific file types (e.g., `--extensions ".cs
|
|
67
|
+
| `--extensions <ext>` | Limit parsing to specific file types (comma-separated, e.g., `--extensions ".cs,.meta"`) |
|
|
68
|
+
| `--csharp-define-csproj <path>` | Load C# `DefineConstants` from a `.csproj` and normalize `#if/#elif/#else/#endif` before parsing |
|
|
50
69
|
| `--scope-prefix <prefix>` | Limit analysis to a path prefix (e.g., `--scope-prefix Assets/` for Unity) |
|
|
51
70
|
| `--scope-manifest <file>` | Read scope rules from a manifest file (e.g., `.gitnexus/sync-manifest.txt`) |
|
|
71
|
+
| `--sync-manifest-policy <policy>` | Drift policy when explicit CLI values differ from manifest directives: `ask|update|keep|error` |
|
|
52
72
|
| `--skills` | Generate repo-specific skill files from detected code communities |
|
|
53
73
|
|
|
54
|
-
**Scope manifest syntax:**
|
|
74
|
+
**Scope manifest syntax:** Non-`@` lines are path-prefix scope rules (same semantics as before). `@key=value` directives set analyze options: `@extensions=<csv>`, `@repoAlias=<name>`, `@embeddings=<true|false>`. Unknown directives fail fast.
|
|
75
|
+
|
|
76
|
+
**Defaulting + drift guard:** If `.gitnexus/sync-manifest.txt` exists and you do not pass `--scope-manifest`/`--scope-prefix`, analyze auto-uses that file. When explicit CLI values (`--extensions`, `--repo-alias`, `--embeddings`) differ from manifest directives, CLI follows `--sync-manifest-policy` (default `ask`; non-TTY requires explicit policy).
|
|
55
77
|
|
|
56
78
|
**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook runs `analyze` automatically after `git commit` and `git merge`, preserving embeddings if previously generated.
|
|
57
79
|
|
|
58
|
-
**Unity projects:** Add `--extensions ".cs
|
|
80
|
+
**Unity projects:** Add `--extensions ".cs,.meta"` to ensure Unity asset edges (`UNITY_ASSET_GUID_REF`, `UNITY_COMPONENT_INSTANCE`) are parsed. Add `--scope-prefix Assets/` to limit scope if all code lives under `Assets/`.
|
|
81
|
+
|
|
82
|
+
**C# conditional-compilation projects (recommended):**
|
|
83
|
+
|
|
84
|
+
- Unity: pass `--csharp-define-csproj /path/to/Assembly-CSharp.csproj` (for neonspark, use `/Volumes/Shuttle/projects/neonspark/Assembly-CSharp.csproj`).
|
|
85
|
+
- Non-Unity: discover candidate project files first, then pass the intended one explicitly:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
rg --files -g '*.csproj'
|
|
89
|
+
$GN analyze --extensions ".cs" --csharp-define-csproj <picked-project>.csproj
|
|
90
|
+
```
|
|
59
91
|
|
|
60
92
|
### status — Check index freshness
|
|
61
93
|
|
|
@@ -28,7 +28,7 @@ mcp__gitnexus__cypher:
|
|
|
28
28
|
如果这两种边不存在,说明索引时未启用 Unity 资源解析,需要重新 analyze,**必须加 Unity 参数**:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
gitnexus analyze --force --extensions ".cs
|
|
31
|
+
gitnexus analyze --force --extensions ".cs,.meta"
|
|
32
32
|
# 如果所有代码都在 Assets/ 下,可加 --scope-prefix Assets/ 缩短分析时间
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -254,7 +254,7 @@ gitnexus rule-lab compile --repo-path "$TARGET_REPO"
|
|
|
254
254
|
### 2.4 重建索引
|
|
255
255
|
|
|
256
256
|
```bash
|
|
257
|
-
gitnexus analyze "$TARGET_REPO" --force --extensions ".cs
|
|
257
|
+
gitnexus analyze "$TARGET_REPO" --force --extensions ".cs,.meta"
|
|
258
258
|
# 如果所有代码都在 Assets/ 下,可加 --scope-prefix Assets/
|
|
259
259
|
```
|
|
260
260
|
|