@veewo/gitnexus 1.3.5 → 1.3.6
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 +11 -7
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -13
- package/dist/cli/ai-context.test.js +23 -1
- package/dist/cli/analyze.js +3 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/setup.d.ts +5 -1
- package/dist/cli/setup.js +76 -11
- package/dist/cli/setup.test.js +42 -0
- package/dist/storage/repo-manager.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,11 +22,13 @@ AI coding tools don't understand your codebase structure. They edit a function w
|
|
|
22
22
|
npx gitnexus analyze
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
That's it. This indexes the codebase,
|
|
25
|
+
That's it. This indexes the codebase, updates `AGENTS.md` / `CLAUDE.md` context files, and (when using project scope) installs repo-local agent skills.
|
|
26
26
|
|
|
27
|
-
To configure MCP
|
|
27
|
+
To configure MCP + skills, run `npx gitnexus setup` once (default global mode), or use `npx gitnexus setup --scope project` for project-local mode.
|
|
28
28
|
|
|
29
|
-
`gitnexus setup`
|
|
29
|
+
`gitnexus setup` supports two scopes:
|
|
30
|
+
- `global` (default): configures global editor MCP + installs global skills
|
|
31
|
+
- `project`: writes repo-local `.mcp.json` + installs repo-local skills
|
|
30
32
|
|
|
31
33
|
## Team Deployment and Distribution
|
|
32
34
|
|
|
@@ -152,7 +154,8 @@ Your AI agent gets these tools automatically:
|
|
|
152
154
|
## CLI Commands
|
|
153
155
|
|
|
154
156
|
```bash
|
|
155
|
-
gitnexus setup #
|
|
157
|
+
gitnexus setup # Default: global MCP + global skills
|
|
158
|
+
gitnexus setup --scope project # Project-local MCP + project-local skills
|
|
156
159
|
gitnexus analyze [path] # Index a repository (or update stale index)
|
|
157
160
|
gitnexus analyze --force # Force full re-index
|
|
158
161
|
gitnexus analyze --embeddings # Enable semantic embeddings (off by default)
|
|
@@ -212,9 +215,10 @@ GitNexus ships with skill files that teach AI agents how to use the tools effect
|
|
|
212
215
|
|
|
213
216
|
Installation rules:
|
|
214
217
|
|
|
215
|
-
- `gitnexus
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
+
- `gitnexus setup` controls skill scope:
|
|
219
|
+
- default `global`: installs to `~/.agents/skills/gitnexus/`
|
|
220
|
+
- `--scope project`: installs to `.agents/skills/gitnexus/` in current repo
|
|
221
|
+
- `gitnexus analyze` always updates `AGENTS.md` / `CLAUDE.md`; skill install follows configured setup scope.
|
|
218
222
|
|
|
219
223
|
## Requirements
|
|
220
224
|
|
package/dist/cli/ai-context.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Codex, Cline, etc.
|
|
6
6
|
* CLAUDE.md is for Claude Code which only reads that file.
|
|
7
7
|
*/
|
|
8
|
+
type SkillScope = 'project' | 'global';
|
|
8
9
|
interface RepoStats {
|
|
9
10
|
files?: number;
|
|
10
11
|
nodes?: number;
|
|
@@ -16,7 +17,9 @@ interface RepoStats {
|
|
|
16
17
|
/**
|
|
17
18
|
* Generate AI context files after indexing
|
|
18
19
|
*/
|
|
19
|
-
export declare function generateAIContextFiles(repoPath: string, _storagePath: string, projectName: string, stats: RepoStats
|
|
20
|
+
export declare function generateAIContextFiles(repoPath: string, _storagePath: string, projectName: string, stats: RepoStats, options?: {
|
|
21
|
+
skillScope?: SkillScope;
|
|
22
|
+
}): Promise<{
|
|
20
23
|
files: string[];
|
|
21
24
|
}>;
|
|
22
25
|
export {};
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -23,7 +23,10 @@ const GITNEXUS_END_MARKER = '<!-- gitnexus:end -->';
|
|
|
23
23
|
* - One-line quick start (read context resource) gives agents an entry point
|
|
24
24
|
* - Tools/Resources sections are labeled "Reference" — agents treat them as lookup, not workflow
|
|
25
25
|
*/
|
|
26
|
-
function generateGitNexusContent(projectName, stats) {
|
|
26
|
+
function generateGitNexusContent(projectName, stats, skillScope) {
|
|
27
|
+
const skillRoot = skillScope === 'global'
|
|
28
|
+
? '~/.agents/skills/gitnexus'
|
|
29
|
+
: '.agents/skills/gitnexus';
|
|
27
30
|
return `${GITNEXUS_START_MARKER}
|
|
28
31
|
# GitNexus MCP
|
|
29
32
|
|
|
@@ -41,12 +44,12 @@ This project is indexed by GitNexus as **${projectName}** (${stats.nodes || 0} s
|
|
|
41
44
|
|
|
42
45
|
| Task | Read this skill file |
|
|
43
46
|
|------|---------------------|
|
|
44
|
-
| Understand architecture / "How does X work?" |
|
|
45
|
-
| Blast radius / "What breaks if I change X?" |
|
|
46
|
-
| Trace bugs / "Why is X failing?" |
|
|
47
|
-
| Rename / extract / split / refactor |
|
|
48
|
-
| Tools, resources, schema reference |
|
|
49
|
-
| Index, status, clean, wiki CLI commands |
|
|
47
|
+
| Understand architecture / "How does X work?" | \`${skillRoot}/gitnexus-exploring/SKILL.md\` |
|
|
48
|
+
| Blast radius / "What breaks if I change X?" | \`${skillRoot}/gitnexus-impact-analysis/SKILL.md\` |
|
|
49
|
+
| Trace bugs / "Why is X failing?" | \`${skillRoot}/gitnexus-debugging/SKILL.md\` |
|
|
50
|
+
| Rename / extract / split / refactor | \`${skillRoot}/gitnexus-refactoring/SKILL.md\` |
|
|
51
|
+
| Tools, resources, schema reference | \`${skillRoot}/gitnexus-guide/SKILL.md\` |
|
|
52
|
+
| Index, status, clean, wiki CLI commands | \`${skillRoot}/gitnexus-cli/SKILL.md\` |
|
|
50
53
|
|
|
51
54
|
${GITNEXUS_END_MARKER}`;
|
|
52
55
|
}
|
|
@@ -164,8 +167,9 @@ Use GitNexus tools to accomplish this task.
|
|
|
164
167
|
/**
|
|
165
168
|
* Generate AI context files after indexing
|
|
166
169
|
*/
|
|
167
|
-
export async function generateAIContextFiles(repoPath, _storagePath, projectName, stats) {
|
|
168
|
-
const
|
|
170
|
+
export async function generateAIContextFiles(repoPath, _storagePath, projectName, stats, options) {
|
|
171
|
+
const skillScope = options?.skillScope === 'global' ? 'global' : 'project';
|
|
172
|
+
const content = generateGitNexusContent(projectName, stats, skillScope);
|
|
169
173
|
const createdFiles = [];
|
|
170
174
|
// Create AGENTS.md (standard for Cursor, Windsurf, OpenCode, Codex, Cline, etc.)
|
|
171
175
|
const agentsPath = path.join(repoPath, 'AGENTS.md');
|
|
@@ -175,10 +179,12 @@ export async function generateAIContextFiles(repoPath, _storagePath, projectName
|
|
|
175
179
|
const claudePath = path.join(repoPath, 'CLAUDE.md');
|
|
176
180
|
const claudeResult = await upsertGitNexusSection(claudePath, content);
|
|
177
181
|
createdFiles.push(`CLAUDE.md (${claudeResult})`);
|
|
178
|
-
// Install skills
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
// Install repo-local skills only when project scope is selected.
|
|
183
|
+
if (skillScope === 'project') {
|
|
184
|
+
const installedSkills = await installSkills(repoPath);
|
|
185
|
+
if (installedSkills.length > 0) {
|
|
186
|
+
createdFiles.push(`.agents/skills/gitnexus/ (${installedSkills.length} skills)`);
|
|
187
|
+
}
|
|
182
188
|
}
|
|
183
189
|
return { files: createdFiles };
|
|
184
190
|
}
|
|
@@ -11,7 +11,7 @@ test('generateAIContextFiles installs repo skills under .agents/skills/gitnexus'
|
|
|
11
11
|
nodes: 1,
|
|
12
12
|
edges: 2,
|
|
13
13
|
processes: 3,
|
|
14
|
-
});
|
|
14
|
+
}, { skillScope: 'project' });
|
|
15
15
|
const agentsPath = path.join(repoPath, 'AGENTS.md');
|
|
16
16
|
const claudePath = path.join(repoPath, 'CLAUDE.md');
|
|
17
17
|
const skillPath = path.join(repoPath, '.agents', 'skills', 'gitnexus', 'gitnexus-exploring', 'SKILL.md');
|
|
@@ -28,3 +28,25 @@ test('generateAIContextFiles installs repo skills under .agents/skills/gitnexus'
|
|
|
28
28
|
await fs.rm(repoPath, { recursive: true, force: true });
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
+
test('generateAIContextFiles with global scope skips repo skill install', async () => {
|
|
32
|
+
const repoPath = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-ai-context-global-'));
|
|
33
|
+
try {
|
|
34
|
+
const result = await generateAIContextFiles(repoPath, '', 'demo-repo', {
|
|
35
|
+
nodes: 1,
|
|
36
|
+
edges: 2,
|
|
37
|
+
processes: 3,
|
|
38
|
+
}, { skillScope: 'global' });
|
|
39
|
+
const agentsPath = path.join(repoPath, 'AGENTS.md');
|
|
40
|
+
const claudePath = path.join(repoPath, 'CLAUDE.md');
|
|
41
|
+
const localSkillsDir = path.join(repoPath, '.agents', 'skills', 'gitnexus');
|
|
42
|
+
const agentsContent = await fs.readFile(agentsPath, 'utf-8');
|
|
43
|
+
const claudeContent = await fs.readFile(claudePath, 'utf-8');
|
|
44
|
+
assert.match(agentsContent, /~\/\.agents\/skills\/gitnexus\/gitnexus-exploring\/SKILL\.md/);
|
|
45
|
+
assert.match(claudeContent, /~\/\.agents\/skills\/gitnexus\/gitnexus-exploring\/SKILL\.md/);
|
|
46
|
+
assert.ok(!result.files.some((entry) => entry.includes('.agents/skills/gitnexus/')), 'did not expect repo-local skills in generated file summary');
|
|
47
|
+
await assert.rejects(fs.access(localSkillsDir));
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await fs.rm(repoPath, { recursive: true, force: true });
|
|
51
|
+
}
|
|
52
|
+
});
|
package/dist/cli/analyze.js
CHANGED
|
@@ -13,7 +13,7 @@ import { initKuzu, loadGraphToKuzu, getKuzuStats, executeQuery, executeWithReuse
|
|
|
13
13
|
// loaded when embeddings are not requested. This avoids crashes on Node
|
|
14
14
|
// versions whose ABI is not yet supported by the native binary (#89).
|
|
15
15
|
// disposeEmbedder intentionally not called — ONNX Runtime segfaults on cleanup (see #38)
|
|
16
|
-
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath } from '../storage/repo-manager.js';
|
|
16
|
+
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath, loadCLIConfig } from '../storage/repo-manager.js';
|
|
17
17
|
import { getCurrentCommit, isGitRepo, getGitRoot } from '../storage/git.js';
|
|
18
18
|
import { generateAIContextFiles } from './ai-context.js';
|
|
19
19
|
import fs from 'fs/promises';
|
|
@@ -312,6 +312,8 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
312
312
|
communities: pipelineResult.communityResult?.stats.totalCommunities,
|
|
313
313
|
clusters: aggregatedClusterCount,
|
|
314
314
|
processes: pipelineResult.processResult?.stats.totalProcesses,
|
|
315
|
+
}, {
|
|
316
|
+
skillScope: ((await loadCLIConfig()).setupScope === 'global') ? 'global' : 'project',
|
|
315
317
|
});
|
|
316
318
|
await closeKuzu();
|
|
317
319
|
// Note: we intentionally do NOT call disposeEmbedder() here.
|
package/dist/cli/index.js
CHANGED
|
@@ -60,6 +60,7 @@ program
|
|
|
60
60
|
program
|
|
61
61
|
.command('setup')
|
|
62
62
|
.description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode, Codex')
|
|
63
|
+
.option('--scope <scope>', 'Install target: global (default) or project')
|
|
63
64
|
.action(setupCommand);
|
|
64
65
|
program
|
|
65
66
|
.command('analyze [path]')
|
package/dist/cli/setup.d.ts
CHANGED
|
@@ -5,4 +5,8 @@
|
|
|
5
5
|
* Detects installed AI editors and writes the appropriate MCP config
|
|
6
6
|
* so the GitNexus MCP server is available in all projects.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
interface SetupOptions {
|
|
9
|
+
scope?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const setupCommand: (options?: SetupOptions) => Promise<void>;
|
|
12
|
+
export {};
|
package/dist/cli/setup.js
CHANGED
|
@@ -11,10 +11,18 @@ import os from 'os';
|
|
|
11
11
|
import { execFile } from 'node:child_process';
|
|
12
12
|
import { promisify } from 'node:util';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
|
-
import { getGlobalDir } from '../storage/repo-manager.js';
|
|
14
|
+
import { getGlobalDir, loadCLIConfig, saveCLIConfig } from '../storage/repo-manager.js';
|
|
15
|
+
import { getGitRoot } from '../storage/git.js';
|
|
15
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
17
|
const __dirname = path.dirname(__filename);
|
|
17
18
|
const execFileAsync = promisify(execFile);
|
|
19
|
+
function resolveSetupScope(rawScope) {
|
|
20
|
+
if (!rawScope || rawScope.trim() === '')
|
|
21
|
+
return 'global';
|
|
22
|
+
if (rawScope === 'global' || rawScope === 'project')
|
|
23
|
+
return rawScope;
|
|
24
|
+
throw new Error(`Invalid --scope value "${rawScope}". Use "global" or "project".`);
|
|
25
|
+
}
|
|
18
26
|
/**
|
|
19
27
|
* The MCP server entry for all editors.
|
|
20
28
|
* On Windows, npx must be invoked via cmd /c since it's a .cmd script.
|
|
@@ -125,6 +133,18 @@ async function installGlobalAgentSkills(result) {
|
|
|
125
133
|
result.errors.push(`Global agent skills: ${err.message}`);
|
|
126
134
|
}
|
|
127
135
|
}
|
|
136
|
+
async function installProjectAgentSkills(repoRoot, result) {
|
|
137
|
+
const skillsDir = path.join(repoRoot, '.agents', 'skills', 'gitnexus');
|
|
138
|
+
try {
|
|
139
|
+
const installed = await installSkillsTo(skillsDir);
|
|
140
|
+
if (installed.length > 0) {
|
|
141
|
+
result.configured.push(`Project agent skills (${installed.length} skills → ${path.relative(repoRoot, skillsDir)}/)`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
result.errors.push(`Project agent skills: ${err.message}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
128
148
|
/**
|
|
129
149
|
* Install GitNexus hooks to ~/.claude/settings.json for Claude Code.
|
|
130
150
|
* Merges hook config without overwriting existing hooks.
|
|
@@ -212,6 +232,28 @@ async function setupCodex(result) {
|
|
|
212
232
|
result.errors.push(`Codex: ${err.message}`);
|
|
213
233
|
}
|
|
214
234
|
}
|
|
235
|
+
async function setupProjectMcp(repoRoot, result) {
|
|
236
|
+
const mcpPath = path.join(repoRoot, '.mcp.json');
|
|
237
|
+
try {
|
|
238
|
+
const existing = await readJsonFile(mcpPath);
|
|
239
|
+
const updated = mergeMcpConfig(existing);
|
|
240
|
+
await writeJsonFile(mcpPath, updated);
|
|
241
|
+
result.configured.push(`Project MCP (${path.relative(repoRoot, mcpPath)})`);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
result.errors.push(`Project MCP: ${err.message}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function saveSetupScope(scope, result) {
|
|
248
|
+
try {
|
|
249
|
+
const existing = await loadCLIConfig();
|
|
250
|
+
await saveCLIConfig({ ...existing, setupScope: scope });
|
|
251
|
+
result.configured.push(`Default setup scope (${scope})`);
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
result.errors.push(`Persist setup scope: ${err.message}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
215
257
|
// ─── Skill Installation ───────────────────────────────────────────
|
|
216
258
|
const SKILL_NAMES = ['gitnexus-exploring', 'gitnexus-debugging', 'gitnexus-impact-analysis', 'gitnexus-refactoring', 'gitnexus-guide', 'gitnexus-cli'];
|
|
217
259
|
/**
|
|
@@ -273,11 +315,20 @@ async function copyDirRecursive(src, dest) {
|
|
|
273
315
|
}
|
|
274
316
|
}
|
|
275
317
|
// ─── Main command ──────────────────────────────────────────────────
|
|
276
|
-
export const setupCommand = async () => {
|
|
318
|
+
export const setupCommand = async (options = {}) => {
|
|
277
319
|
console.log('');
|
|
278
320
|
console.log(' GitNexus Setup');
|
|
279
321
|
console.log(' ==============');
|
|
280
322
|
console.log('');
|
|
323
|
+
let scope;
|
|
324
|
+
try {
|
|
325
|
+
scope = resolveSetupScope(options.scope);
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
console.log(` ${err?.message || String(err)}\n`);
|
|
329
|
+
process.exitCode = 1;
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
281
332
|
// Ensure global directory exists
|
|
282
333
|
const globalDir = getGlobalDir();
|
|
283
334
|
await fs.mkdir(globalDir, { recursive: true });
|
|
@@ -286,15 +337,28 @@ export const setupCommand = async () => {
|
|
|
286
337
|
skipped: [],
|
|
287
338
|
errors: [],
|
|
288
339
|
};
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
340
|
+
if (scope === 'global') {
|
|
341
|
+
// Detect and configure each editor's MCP
|
|
342
|
+
await setupCursor(result);
|
|
343
|
+
await setupClaudeCode(result);
|
|
344
|
+
await setupOpenCode(result);
|
|
345
|
+
await setupCodex(result);
|
|
346
|
+
// Install shared global skills once
|
|
347
|
+
await installGlobalAgentSkills(result);
|
|
348
|
+
// Optional Claude-specific hooks
|
|
349
|
+
await installClaudeCodeHooks(result);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
const repoRoot = getGitRoot(process.cwd());
|
|
353
|
+
if (!repoRoot) {
|
|
354
|
+
console.log(' --scope project requires running inside a git repository\n');
|
|
355
|
+
process.exitCode = 1;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
await setupProjectMcp(repoRoot, result);
|
|
359
|
+
await installProjectAgentSkills(repoRoot, result);
|
|
360
|
+
}
|
|
361
|
+
await saveSetupScope(scope, result);
|
|
298
362
|
// Print results
|
|
299
363
|
if (result.configured.length > 0) {
|
|
300
364
|
console.log(' Configured:');
|
|
@@ -318,6 +382,7 @@ export const setupCommand = async () => {
|
|
|
318
382
|
}
|
|
319
383
|
console.log('');
|
|
320
384
|
console.log(' Summary:');
|
|
385
|
+
console.log(` Scope: ${scope}`);
|
|
321
386
|
console.log(` MCP configured for: ${result.configured.filter(c => !c.includes('skills')).join(', ') || 'none'}`);
|
|
322
387
|
console.log(` Skills installed to: ${result.configured.filter(c => c.includes('skills')).length > 0 ? result.configured.filter(c => c.includes('skills')).join(', ') : 'none'}`);
|
|
323
388
|
console.log('');
|
package/dist/cli/setup.test.js
CHANGED
|
@@ -22,7 +22,11 @@ test('setup installs global skills under ~/.agents/skills/gitnexus', async () =>
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
const skillPath = path.join(fakeHome, '.agents', 'skills', 'gitnexus', 'gitnexus-exploring', 'SKILL.md');
|
|
25
|
+
const configPath = path.join(fakeHome, '.gitnexus', 'config.json');
|
|
25
26
|
await fs.access(skillPath);
|
|
27
|
+
const configRaw = await fs.readFile(configPath, 'utf-8');
|
|
28
|
+
const config = JSON.parse(configRaw);
|
|
29
|
+
assert.equal(config.setupScope, 'global');
|
|
26
30
|
assert.ok(true);
|
|
27
31
|
}
|
|
28
32
|
finally {
|
|
@@ -80,3 +84,41 @@ process.exit(0);
|
|
|
80
84
|
await fs.rm(fakeBin, { recursive: true, force: true });
|
|
81
85
|
}
|
|
82
86
|
});
|
|
87
|
+
test('setup with --scope project writes local MCP and repo-local skills only', async () => {
|
|
88
|
+
const fakeHome = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-setup-home-'));
|
|
89
|
+
const fakeRepo = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-setup-repo-'));
|
|
90
|
+
try {
|
|
91
|
+
await execFileAsync('git', ['init'], {
|
|
92
|
+
cwd: fakeRepo,
|
|
93
|
+
env: {
|
|
94
|
+
...process.env,
|
|
95
|
+
HOME: fakeHome,
|
|
96
|
+
USERPROFILE: fakeHome,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
await execFileAsync(process.execPath, [cliPath, 'setup', '--scope', 'project'], {
|
|
100
|
+
cwd: fakeRepo,
|
|
101
|
+
env: {
|
|
102
|
+
...process.env,
|
|
103
|
+
HOME: fakeHome,
|
|
104
|
+
USERPROFILE: fakeHome,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
const projectMcpPath = path.join(fakeRepo, '.mcp.json');
|
|
108
|
+
const localSkillPath = path.join(fakeRepo, '.agents', 'skills', 'gitnexus', 'gitnexus-exploring', 'SKILL.md');
|
|
109
|
+
const globalSkillPath = path.join(fakeHome, '.agents', 'skills', 'gitnexus', 'gitnexus-exploring', 'SKILL.md');
|
|
110
|
+
const configPath = path.join(fakeHome, '.gitnexus', 'config.json');
|
|
111
|
+
const projectMcpRaw = await fs.readFile(projectMcpPath, 'utf-8');
|
|
112
|
+
const projectMcp = JSON.parse(projectMcpRaw);
|
|
113
|
+
const configRaw = await fs.readFile(configPath, 'utf-8');
|
|
114
|
+
const config = JSON.parse(configRaw);
|
|
115
|
+
assert.equal(projectMcp.mcpServers?.gitnexus?.command, 'npx');
|
|
116
|
+
await fs.access(localSkillPath);
|
|
117
|
+
await assert.rejects(fs.access(globalSkillPath));
|
|
118
|
+
assert.equal(config.setupScope, 'project');
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
await fs.rm(fakeHome, { recursive: true, force: true });
|
|
122
|
+
await fs.rm(fakeRepo, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
package/package.json
CHANGED