gitnexus 1.6.10-rc.50 → 1.6.10-rc.52
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 +3 -0
- package/dist/cli/ai-context.js +7 -36
- package/dist/cli/analyze.d.ts +4 -1
- package/dist/cli/analyze.js +13 -6
- package/dist/cli/help-i18n.js +1 -0
- package/dist/cli/i18n/en.d.ts +5 -1
- package/dist/cli/i18n/en.js +5 -1
- package/dist/cli/i18n/resources.d.ts +9 -1
- package/dist/cli/i18n/zh-CN.d.ts +4 -0
- package/dist/cli/i18n/zh-CN.js +5 -1
- package/dist/cli/index.js +4 -2
- package/dist/cli/lazy-action.d.ts +7 -0
- package/dist/cli/lazy-action.js +27 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +26 -4
- package/dist/cli/standard-skills.d.ts +76 -0
- package/dist/cli/standard-skills.js +45 -0
- package/dist/cli/status.d.ts +4 -1
- package/dist/cli/status.js +57 -4
- package/dist/cli/uninstall.js +7 -2
- package/dist/core/analyzer-identity.d.ts +74 -0
- package/dist/core/analyzer-identity.js +1820 -0
- package/dist/core/index-freshness.d.ts +5 -0
- package/dist/core/index-freshness.js +13 -0
- package/dist/core/run-analyze.d.ts +2 -2
- package/dist/core/run-analyze.js +32 -30
- package/dist/mcp/resources.js +17 -0
- package/dist/server/analyze-worker-core.d.ts +2 -1
- package/dist/server/analyze-worker-core.js +5 -2
- package/dist/server/analyze-worker.js +29 -6
- package/dist/storage/git.d.ts +9 -0
- package/dist/storage/git.js +36 -1
- package/dist/storage/repo-manager.d.ts +50 -0
- package/package.json +1 -1
- package/scripts/sync-plugin-manifests.mjs +61 -10
- package/skills/gitnexus-lfg/README.md +55 -0
- package/skills/gitnexus-lfg/SKILL.md +86 -0
- package/skills/gitnexus-plan/README.md +142 -0
- package/skills/gitnexus-plan/SKILL.md +348 -0
- package/skills/gitnexus-plan/references/context-ledger.md +137 -0
- package/skills/gitnexus-plan/references/context-pack.md +126 -0
- package/skills/gitnexus-plan/references/evidence-provenance.md +272 -0
- package/skills/gitnexus-plan/references/pdg-slice.md +109 -0
- package/skills/gitnexus-plan/references/plan-template.md +201 -0
- package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +2084 -0
- package/skills/gitnexus-review/SKILL.md +228 -0
- package/skills/gitnexus-work/README.md +71 -0
- package/skills/gitnexus-work/SKILL.md +269 -0
- package/skills/gitnexus-work/references/evidence-provenance.md +272 -0
- package/skills/gitnexus-work/scripts/evidence-provenance.mjs +2084 -0
- package/skills/gitnexus-pr-review.md +0 -163
package/README.md
CHANGED
|
@@ -332,6 +332,9 @@ GitNexus ships with skill files that teach AI agents how to use the tools effect
|
|
|
332
332
|
- **Refactoring** — Plan safe refactors using dependency mapping
|
|
333
333
|
- **Guide** — GitNexus tool/resource/schema reference for the agent
|
|
334
334
|
- **CLI** — Run analyze/status/clean/wiki commands on request
|
|
335
|
+
- **PDG Query** — Statement-level control/data dependence queries (`--pdg` index)
|
|
336
|
+
- **Taint Analysis** — Source→sink data-flow findings (`--pdg` index)
|
|
337
|
+
- **Plan / Work / Review / LFG** — The engineering family: implementation-ready plans, gated plan execution, graph-backed change review with taint + expert lenses, and the end-to-end pipeline
|
|
335
338
|
|
|
336
339
|
Installed automatically by both `gitnexus analyze` (per-repo) and `gitnexus setup` (global). Run `gitnexus analyze --skills` to additionally generate each detected functional area as a direct project skill under `.claude/skills/gitnexus-area-<name>/`.
|
|
337
340
|
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
|
+
import { STANDARD_SKILL_CATALOG } from './standard-skills.js';
|
|
11
12
|
import { logger } from '../core/logger.js';
|
|
12
13
|
// ESM equivalent of __dirname
|
|
13
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -91,12 +92,9 @@ export function generateGitNexusContent(projectName, stats, opts = {}) {
|
|
|
91
92
|
// are independent of --skip-skills, so they remain when present.
|
|
92
93
|
const standardSkillsRows = skipSkills
|
|
93
94
|
? ''
|
|
94
|
-
:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
| Rename / extract / split / refactor | \`.claude/skills/gitnexus-refactoring/SKILL.md\` |
|
|
98
|
-
| Tools, resources, schema reference | \`.claude/skills/gitnexus-guide/SKILL.md\` |
|
|
99
|
-
| Index, status, clean, wiki CLI commands | \`.claude/skills/gitnexus-cli/SKILL.md\` |`;
|
|
95
|
+
: STANDARD_SKILL_CATALOG.filter((skill) => skill.distributions.project)
|
|
96
|
+
.map((skill) => `| ${skill.agentTableTask} | \`.claude/skills/${skill.name}/SKILL.md\` |`)
|
|
97
|
+
.join('\n');
|
|
100
98
|
const tableBody = [standardSkillsRows, generatedRows].filter(Boolean).join('\n');
|
|
101
99
|
const skillsTable = tableBody
|
|
102
100
|
? `| Task | Read this skill file |
|
|
@@ -260,34 +258,7 @@ async function installSkills(repoPath) {
|
|
|
260
258
|
const skillsDir = path.join(repoPath, '.claude', 'skills');
|
|
261
259
|
const legacySkillsDir = path.join(skillsDir, 'gitnexus');
|
|
262
260
|
const installedSkills = [];
|
|
263
|
-
|
|
264
|
-
const skills = [
|
|
265
|
-
{
|
|
266
|
-
name: 'gitnexus-exploring',
|
|
267
|
-
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"',
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
name: 'gitnexus-debugging',
|
|
271
|
-
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"',
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
name: 'gitnexus-impact-analysis',
|
|
275
|
-
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?"',
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
name: 'gitnexus-refactoring',
|
|
279
|
-
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"',
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
name: 'gitnexus-guide',
|
|
283
|
-
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?"',
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
name: 'gitnexus-cli',
|
|
287
|
-
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"',
|
|
288
|
-
},
|
|
289
|
-
];
|
|
290
|
-
for (const skill of skills) {
|
|
261
|
+
for (const skill of STANDARD_SKILL_CATALOG.filter((entry) => entry.distributions.project && entry.distributions.npm)) {
|
|
291
262
|
const skillDir = path.join(skillsDir, skill.name);
|
|
292
263
|
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
293
264
|
try {
|
|
@@ -303,12 +274,12 @@ async function installSkills(repoPath) {
|
|
|
303
274
|
// Fallback: generate minimal skill content
|
|
304
275
|
skillContent = `---
|
|
305
276
|
name: ${skill.name}
|
|
306
|
-
description: ${skill.
|
|
277
|
+
description: ${skill.fallbackDescription}
|
|
307
278
|
---
|
|
308
279
|
|
|
309
280
|
# ${skill.name.charAt(0).toUpperCase() + skill.name.slice(1)}
|
|
310
281
|
|
|
311
|
-
${skill.
|
|
282
|
+
${skill.fallbackDescription}
|
|
312
283
|
|
|
313
284
|
Use GitNexus tools to accomplish this task.
|
|
314
285
|
`;
|
package/dist/cli/analyze.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* This CLI wrapper handles: heap management, progress bar, SIGINT,
|
|
8
8
|
* skill generation (--skills), summary output, and process.exit().
|
|
9
9
|
*/
|
|
10
|
+
import { type AnalyzerRunnerIdentity } from '../storage/repo-manager.js';
|
|
10
11
|
/**
|
|
11
12
|
* RAM-aware re-exec heap cap (MB): `0.75 × effective RAM`, clamped to
|
|
12
13
|
* `>= DEFAULT_HEAP_MB`. Kept BELOW physical RAM on purpose — a cap `>=` RAM makes
|
|
@@ -138,4 +139,6 @@ export interface AnalyzeOptions {
|
|
|
138
139
|
* without booting the full analyze pipeline (#742 review).
|
|
139
140
|
*/
|
|
140
141
|
export declare const shouldGenerateCommunitySkillFiles: (options: Pick<AnalyzeOptions, "skills" | "indexOnly"> | undefined, pipelineResult: unknown) => boolean;
|
|
141
|
-
export declare const analyzeCommand: (inputPath?: string, options?: AnalyzeOptions) => Promise<void>;
|
|
142
|
+
export declare const analyzeCommand: (inputPath?: string, options?: AnalyzeOptions, runnerIdentityAtBootstrap?: AnalyzerRunnerIdentity) => Promise<void>;
|
|
143
|
+
/** Commander entrypoint used only by the capture-before-import lazy bootstrap. */
|
|
144
|
+
export declare const analyzeCommandWithRunnerIdentity: (runnerIdentityAtBootstrap: AnalyzerRunnerIdentity, inputPath?: string, options?: AnalyzeOptions) => Promise<void>;
|
package/dist/cli/analyze.js
CHANGED
|
@@ -485,7 +485,7 @@ const restoreAnalyzeEnv = (snap) => {
|
|
|
485
485
|
* without booting the full analyze pipeline (#742 review).
|
|
486
486
|
*/
|
|
487
487
|
export const shouldGenerateCommunitySkillFiles = (options, pipelineResult) => Boolean(options?.skills && pipelineResult && !options?.indexOnly);
|
|
488
|
-
export const analyzeCommand = async (inputPath, options) => {
|
|
488
|
+
export const analyzeCommand = async (inputPath, options, runnerIdentityAtBootstrap) => {
|
|
489
489
|
if (await ensureHeap())
|
|
490
490
|
return;
|
|
491
491
|
forceHeapOOMForTestIfEnabled();
|
|
@@ -506,7 +506,7 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
506
506
|
// pre-call values.
|
|
507
507
|
const envSnap = snapshotAnalyzeEnv();
|
|
508
508
|
try {
|
|
509
|
-
await analyzeCommandImpl(inputPath, options);
|
|
509
|
+
await analyzeCommandImpl(inputPath, options, runnerIdentityAtBootstrap);
|
|
510
510
|
}
|
|
511
511
|
finally {
|
|
512
512
|
restoreAnalyzeEnv(envSnap);
|
|
@@ -523,7 +523,9 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
523
523
|
process.exit(typeof process.exitCode === 'number' ? process.exitCode : 1);
|
|
524
524
|
}
|
|
525
525
|
};
|
|
526
|
-
|
|
526
|
+
/** Commander entrypoint used only by the capture-before-import lazy bootstrap. */
|
|
527
|
+
export const analyzeCommandWithRunnerIdentity = async (runnerIdentityAtBootstrap, inputPath, options) => analyzeCommand(inputPath, options, runnerIdentityAtBootstrap);
|
|
528
|
+
const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstrap) => {
|
|
527
529
|
console.log('\n GitNexus Analyzer\n');
|
|
528
530
|
// ── Resolve the target repo root ──────────────────────────────────
|
|
529
531
|
// Resolved FIRST because `.gitnexusrc` is read from the repo root (not the
|
|
@@ -988,7 +990,7 @@ const analyzeCommandImpl = async (inputPath, cliOptions) => {
|
|
|
988
990
|
const skipAll = options.indexOnly;
|
|
989
991
|
const skipAgentsMd = skipAll || options.skipAgentsMd;
|
|
990
992
|
const skipSkills = skipAll || options.skipSkills;
|
|
991
|
-
const
|
|
993
|
+
const runOptions = {
|
|
992
994
|
// Pipeline re-index — OR'd with --skills because skill generation
|
|
993
995
|
// needs a fresh pipelineResult. Has no bearing on the registry
|
|
994
996
|
// collision guard (see allowDuplicateName below).
|
|
@@ -1035,12 +1037,17 @@ const analyzeCommandImpl = async (inputPath, cliOptions) => {
|
|
|
1035
1037
|
// in LadybugDB's ClientContext destructor after --pdg writes (#2264). The
|
|
1036
1038
|
// CHECKPOINT keeps the index durable; process exit reclaims the handles.
|
|
1037
1039
|
skipNativeCloseOnExit: true,
|
|
1038
|
-
}
|
|
1040
|
+
};
|
|
1041
|
+
const runCallbacks = {
|
|
1039
1042
|
onProgress: (_phase, percent, message) => {
|
|
1040
1043
|
updateBar(percent, message);
|
|
1041
1044
|
},
|
|
1042
1045
|
onLog: barLog,
|
|
1043
|
-
}
|
|
1046
|
+
};
|
|
1047
|
+
const bootstrapArgs = runnerIdentityAtBootstrap
|
|
1048
|
+
? [runnerIdentityAtBootstrap]
|
|
1049
|
+
: [];
|
|
1050
|
+
const result = await runFullAnalysis(repoPath, runOptions, runCallbacks, ...bootstrapArgs);
|
|
1044
1051
|
if (result.alreadyUpToDate) {
|
|
1045
1052
|
// Even the fast path must prove the repo is discoverable. A prior
|
|
1046
1053
|
// run can write meta.json and then fail before registerRepo(); in
|
package/dist/cli/help-i18n.js
CHANGED
|
@@ -75,6 +75,7 @@ const OPTION_DESCRIPTION_KEYS = {
|
|
|
75
75
|
'mcp|--auth-token <token>': 'help.option.mcp.authToken',
|
|
76
76
|
'serve|-p, --port <port>': 'help.option.port',
|
|
77
77
|
'serve|--host <host>': 'help.option.serve.host',
|
|
78
|
+
'status|--json': 'help.option.status.json',
|
|
78
79
|
'uninstall|-f, --force': 'help.option.uninstall.force',
|
|
79
80
|
'clean|-f, --force': 'help.option.force.confirmation',
|
|
80
81
|
'clean|--all': 'help.option.clean.all',
|
package/dist/cli/i18n/en.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare const en: {
|
|
|
26
26
|
readonly 'status.indexed': "Indexed";
|
|
27
27
|
readonly 'status.indexedCommit': "Indexed commit";
|
|
28
28
|
readonly 'status.currentCommit': "Current commit";
|
|
29
|
+
readonly 'status.indexRunnerIdentity': "Indexed analyzer runner identity";
|
|
30
|
+
readonly 'status.currentRunnerIdentity': "Current analyzer runner identity";
|
|
29
31
|
readonly 'status.branch': "Branch";
|
|
30
32
|
readonly 'status.detached': "(detached HEAD)";
|
|
31
33
|
readonly 'status.workspaceIndexLabel': "Workspace index: last analyzed on '{{primary}}' (re-run gitnexus analyze to follow the current branch)";
|
|
@@ -231,6 +233,7 @@ export declare const en: {
|
|
|
231
233
|
readonly 'help.option.group.sync.exactOnly': "Exact match only";
|
|
232
234
|
readonly 'help.option.group.sync.allowStale': "Skip stale index warnings";
|
|
233
235
|
readonly 'help.option.group.sync.verbose': "Show each cross-link detail";
|
|
236
|
+
readonly 'help.option.status.json': "Emit machine-readable index and analyzer provenance";
|
|
234
237
|
readonly 'help.option.json': "JSON output";
|
|
235
238
|
readonly 'help.option.group.impact.target': "Symbol or file name to analyze";
|
|
236
239
|
readonly 'help.option.group.impact.repo': "Member path from group.yaml (e.g. app/backend), not the indexed repo name";
|
|
@@ -244,5 +247,6 @@ export declare const en: {
|
|
|
244
247
|
readonly 'help.option.group.contracts.type': "Filter by contract type";
|
|
245
248
|
readonly 'help.option.group.contracts.repo': "Filter by repo";
|
|
246
249
|
readonly 'help.option.group.contracts.unmatched': "Show only unmatched contracts";
|
|
247
|
-
readonly 'help.
|
|
250
|
+
readonly 'help.identityCache.environment': "\nAnalyzer identity cache:\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir\n Operator-trusted persistent cache for warm cross-process status. The directory must pre-exist, be outside the GitNexus package/build roots, and contain no symlink or junction components. Defaults remain fail-closed on platforms without POSIX ownership APIs.";
|
|
251
|
+
readonly 'help.analyze.environment': "\nEnvironment variables:\n GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir Operator-trusted persistent analyzer identity cache; must pre-exist, be outside package/build roots, and contain no symlink/junction components.\n GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=N Worker idle timeout in milliseconds. Default 30000.\n GITNEXUS_WAL_CHECKPOINT_THRESHOLD=N LadybugDB WAL auto-checkpoint threshold in bytes (default 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).\n GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES=N Worker job byte budget. Default 8388608.\n GITNEXUS_WORKER_POOL_SIZE=N Parse worker count override. Default cores-1 capped at 16.\n GITNEXUS_PARSE_CHUNK_CONCURRENCY=N Concurrent in-flight parse chunks. Default 2.\n GITNEXUS_WORKER_MAX_RESPAWNS_PER_SLOT=N Max replacement spawns per slot before drop. Default 3.\n GITNEXUS_WORKER_MAX_CUMULATIVE_TIMEOUT_MS=N Total retry wall-time per job. Default 5x sub-batch timeout.\n GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD=N Per-slot deaths to trip circuit breaker. Default max(3, poolSize).\n GITNEXUS_WORKER_SHUTDOWN_DRAIN_MS=N Max wait at pool shutdown for a retired worker still inside native code (terminated at its next safe point instead of aborting the process). Default 30000.\n GITNEXUS_CPP_CAPTURE_BUDGET_MS=N Per-file wall-clock budget for C++ capture extraction; on breach the file keeps partial captures with a warning. Default 20000.\n GITNEXUS_EMBEDDING_THREADS=N Limit local ONNX CPU threads for --embeddings.\n GITNEXUS_SEMANTIC_EXACT_SCAN_LIMIT=N Max embedding chunks for exact-scan fallback. Default 10000.\n GITNEXUS_VECTOR_MAX_DISTANCE=N Max accepted semantic/vector cosine distance (0 < N <= 2; higher values clamp to 2). Default 0.6 for MCP, 0.5 elsewhere.\n\nFlags override the corresponding env vars when both are provided.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).";
|
|
248
252
|
};
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -26,6 +26,8 @@ export const en = {
|
|
|
26
26
|
'status.indexed': 'Indexed',
|
|
27
27
|
'status.indexedCommit': 'Indexed commit',
|
|
28
28
|
'status.currentCommit': 'Current commit',
|
|
29
|
+
'status.indexRunnerIdentity': 'Indexed analyzer runner identity',
|
|
30
|
+
'status.currentRunnerIdentity': 'Current analyzer runner identity',
|
|
29
31
|
'status.branch': 'Branch',
|
|
30
32
|
'status.detached': '(detached HEAD)',
|
|
31
33
|
'status.workspaceIndexLabel': "Workspace index: last analyzed on '{{primary}}' (re-run gitnexus analyze to follow the current branch)",
|
|
@@ -231,6 +233,7 @@ export const en = {
|
|
|
231
233
|
'help.option.group.sync.exactOnly': 'Exact match only',
|
|
232
234
|
'help.option.group.sync.allowStale': 'Skip stale index warnings',
|
|
233
235
|
'help.option.group.sync.verbose': 'Show each cross-link detail',
|
|
236
|
+
'help.option.status.json': 'Emit machine-readable index and analyzer provenance',
|
|
234
237
|
'help.option.json': 'JSON output',
|
|
235
238
|
'help.option.group.impact.target': 'Symbol or file name to analyze',
|
|
236
239
|
'help.option.group.impact.repo': 'Member path from group.yaml (e.g. app/backend), not the indexed repo name',
|
|
@@ -244,5 +247,6 @@ export const en = {
|
|
|
244
247
|
'help.option.group.contracts.type': 'Filter by contract type',
|
|
245
248
|
'help.option.group.contracts.repo': 'Filter by repo',
|
|
246
249
|
'help.option.group.contracts.unmatched': 'Show only unmatched contracts',
|
|
247
|
-
'help.
|
|
250
|
+
'help.identityCache.environment': '\nAnalyzer identity cache:\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir\n Operator-trusted persistent cache for warm cross-process status. The directory must pre-exist, be outside the GitNexus package/build roots, and contain no symlink or junction components. Defaults remain fail-closed on platforms without POSIX ownership APIs.',
|
|
251
|
+
'help.analyze.environment': '\nEnvironment variables:\n GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir Operator-trusted persistent analyzer identity cache; must pre-exist, be outside package/build roots, and contain no symlink/junction components.\n GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=N Worker idle timeout in milliseconds. Default 30000.\n GITNEXUS_WAL_CHECKPOINT_THRESHOLD=N LadybugDB WAL auto-checkpoint threshold in bytes (default 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).\n GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES=N Worker job byte budget. Default 8388608.\n GITNEXUS_WORKER_POOL_SIZE=N Parse worker count override. Default cores-1 capped at 16.\n GITNEXUS_PARSE_CHUNK_CONCURRENCY=N Concurrent in-flight parse chunks. Default 2.\n GITNEXUS_WORKER_MAX_RESPAWNS_PER_SLOT=N Max replacement spawns per slot before drop. Default 3.\n GITNEXUS_WORKER_MAX_CUMULATIVE_TIMEOUT_MS=N Total retry wall-time per job. Default 5x sub-batch timeout.\n GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD=N Per-slot deaths to trip circuit breaker. Default max(3, poolSize).\n GITNEXUS_WORKER_SHUTDOWN_DRAIN_MS=N Max wait at pool shutdown for a retired worker still inside native code (terminated at its next safe point instead of aborting the process). Default 30000.\n GITNEXUS_CPP_CAPTURE_BUDGET_MS=N Per-file wall-clock budget for C++ capture extraction; on breach the file keeps partial captures with a warning. Default 20000.\n GITNEXUS_EMBEDDING_THREADS=N Limit local ONNX CPU threads for --embeddings.\n GITNEXUS_SEMANTIC_EXACT_SCAN_LIMIT=N Max embedding chunks for exact-scan fallback. Default 10000.\n GITNEXUS_VECTOR_MAX_DISTANCE=N Max accepted semantic/vector cosine distance (0 < N <= 2; higher values clamp to 2). Default 0.6 for MCP, 0.5 elsewhere.\n\nFlags override the corresponding env vars when both are provided.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).',
|
|
248
252
|
};
|
|
@@ -27,6 +27,8 @@ export declare const cliResources: {
|
|
|
27
27
|
readonly 'status.indexed': "Indexed";
|
|
28
28
|
readonly 'status.indexedCommit': "Indexed commit";
|
|
29
29
|
readonly 'status.currentCommit': "Current commit";
|
|
30
|
+
readonly 'status.indexRunnerIdentity': "Indexed analyzer runner identity";
|
|
31
|
+
readonly 'status.currentRunnerIdentity': "Current analyzer runner identity";
|
|
30
32
|
readonly 'status.branch': "Branch";
|
|
31
33
|
readonly 'status.detached': "(detached HEAD)";
|
|
32
34
|
readonly 'status.workspaceIndexLabel': "Workspace index: last analyzed on '{{primary}}' (re-run gitnexus analyze to follow the current branch)";
|
|
@@ -232,6 +234,7 @@ export declare const cliResources: {
|
|
|
232
234
|
readonly 'help.option.group.sync.exactOnly': "Exact match only";
|
|
233
235
|
readonly 'help.option.group.sync.allowStale': "Skip stale index warnings";
|
|
234
236
|
readonly 'help.option.group.sync.verbose': "Show each cross-link detail";
|
|
237
|
+
readonly 'help.option.status.json': "Emit machine-readable index and analyzer provenance";
|
|
235
238
|
readonly 'help.option.json': "JSON output";
|
|
236
239
|
readonly 'help.option.group.impact.target': "Symbol or file name to analyze";
|
|
237
240
|
readonly 'help.option.group.impact.repo': "Member path from group.yaml (e.g. app/backend), not the indexed repo name";
|
|
@@ -245,7 +248,8 @@ export declare const cliResources: {
|
|
|
245
248
|
readonly 'help.option.group.contracts.type': "Filter by contract type";
|
|
246
249
|
readonly 'help.option.group.contracts.repo': "Filter by repo";
|
|
247
250
|
readonly 'help.option.group.contracts.unmatched': "Show only unmatched contracts";
|
|
248
|
-
readonly 'help.
|
|
251
|
+
readonly 'help.identityCache.environment': "\nAnalyzer identity cache:\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir\n Operator-trusted persistent cache for warm cross-process status. The directory must pre-exist, be outside the GitNexus package/build roots, and contain no symlink or junction components. Defaults remain fail-closed on platforms without POSIX ownership APIs.";
|
|
252
|
+
readonly 'help.analyze.environment': "\nEnvironment variables:\n GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir Operator-trusted persistent analyzer identity cache; must pre-exist, be outside package/build roots, and contain no symlink/junction components.\n GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=N Worker idle timeout in milliseconds. Default 30000.\n GITNEXUS_WAL_CHECKPOINT_THRESHOLD=N LadybugDB WAL auto-checkpoint threshold in bytes (default 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).\n GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES=N Worker job byte budget. Default 8388608.\n GITNEXUS_WORKER_POOL_SIZE=N Parse worker count override. Default cores-1 capped at 16.\n GITNEXUS_PARSE_CHUNK_CONCURRENCY=N Concurrent in-flight parse chunks. Default 2.\n GITNEXUS_WORKER_MAX_RESPAWNS_PER_SLOT=N Max replacement spawns per slot before drop. Default 3.\n GITNEXUS_WORKER_MAX_CUMULATIVE_TIMEOUT_MS=N Total retry wall-time per job. Default 5x sub-batch timeout.\n GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD=N Per-slot deaths to trip circuit breaker. Default max(3, poolSize).\n GITNEXUS_WORKER_SHUTDOWN_DRAIN_MS=N Max wait at pool shutdown for a retired worker still inside native code (terminated at its next safe point instead of aborting the process). Default 30000.\n GITNEXUS_CPP_CAPTURE_BUDGET_MS=N Per-file wall-clock budget for C++ capture extraction; on breach the file keeps partial captures with a warning. Default 20000.\n GITNEXUS_EMBEDDING_THREADS=N Limit local ONNX CPU threads for --embeddings.\n GITNEXUS_SEMANTIC_EXACT_SCAN_LIMIT=N Max embedding chunks for exact-scan fallback. Default 10000.\n GITNEXUS_VECTOR_MAX_DISTANCE=N Max accepted semantic/vector cosine distance (0 < N <= 2; higher values clamp to 2). Default 0.6 for MCP, 0.5 elsewhere.\n\nFlags override the corresponding env vars when both are provided.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).";
|
|
249
253
|
};
|
|
250
254
|
readonly 'zh-CN': {
|
|
251
255
|
'common.notIndexed': string;
|
|
@@ -275,6 +279,8 @@ export declare const cliResources: {
|
|
|
275
279
|
'status.indexed': string;
|
|
276
280
|
'status.indexedCommit': string;
|
|
277
281
|
'status.currentCommit': string;
|
|
282
|
+
'status.indexRunnerIdentity': string;
|
|
283
|
+
'status.currentRunnerIdentity': string;
|
|
278
284
|
'status.branch': string;
|
|
279
285
|
'status.detached': string;
|
|
280
286
|
'status.workspaceIndexLabel': string;
|
|
@@ -480,6 +486,7 @@ export declare const cliResources: {
|
|
|
480
486
|
'help.option.group.sync.exactOnly': string;
|
|
481
487
|
'help.option.group.sync.allowStale': string;
|
|
482
488
|
'help.option.group.sync.verbose': string;
|
|
489
|
+
'help.option.status.json': string;
|
|
483
490
|
'help.option.json': string;
|
|
484
491
|
'help.option.group.impact.target': string;
|
|
485
492
|
'help.option.group.impact.repo': string;
|
|
@@ -493,6 +500,7 @@ export declare const cliResources: {
|
|
|
493
500
|
'help.option.group.contracts.type': string;
|
|
494
501
|
'help.option.group.contracts.repo': string;
|
|
495
502
|
'help.option.group.contracts.unmatched': string;
|
|
503
|
+
'help.identityCache.environment': string;
|
|
496
504
|
'help.analyze.environment': string;
|
|
497
505
|
};
|
|
498
506
|
};
|
package/dist/cli/i18n/zh-CN.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare const zhCN: {
|
|
|
26
26
|
'status.indexed': string;
|
|
27
27
|
'status.indexedCommit': string;
|
|
28
28
|
'status.currentCommit': string;
|
|
29
|
+
'status.indexRunnerIdentity': string;
|
|
30
|
+
'status.currentRunnerIdentity': string;
|
|
29
31
|
'status.branch': string;
|
|
30
32
|
'status.detached': string;
|
|
31
33
|
'status.workspaceIndexLabel': string;
|
|
@@ -231,6 +233,7 @@ export declare const zhCN: {
|
|
|
231
233
|
'help.option.group.sync.exactOnly': string;
|
|
232
234
|
'help.option.group.sync.allowStale': string;
|
|
233
235
|
'help.option.group.sync.verbose': string;
|
|
236
|
+
'help.option.status.json': string;
|
|
234
237
|
'help.option.json': string;
|
|
235
238
|
'help.option.group.impact.target': string;
|
|
236
239
|
'help.option.group.impact.repo': string;
|
|
@@ -244,5 +247,6 @@ export declare const zhCN: {
|
|
|
244
247
|
'help.option.group.contracts.type': string;
|
|
245
248
|
'help.option.group.contracts.repo': string;
|
|
246
249
|
'help.option.group.contracts.unmatched': string;
|
|
250
|
+
'help.identityCache.environment': string;
|
|
247
251
|
'help.analyze.environment': string;
|
|
248
252
|
};
|
package/dist/cli/i18n/zh-CN.js
CHANGED
|
@@ -26,6 +26,8 @@ export const zhCN = {
|
|
|
26
26
|
'status.indexed': '索引时间',
|
|
27
27
|
'status.indexedCommit': '索引提交',
|
|
28
28
|
'status.currentCommit': '当前提交',
|
|
29
|
+
'status.indexRunnerIdentity': '索引记录的分析器运行身份',
|
|
30
|
+
'status.currentRunnerIdentity': '当前分析器运行身份',
|
|
29
31
|
'status.branch': '分支',
|
|
30
32
|
'status.detached': '(分离 HEAD)',
|
|
31
33
|
'status.workspaceIndexLabel': "工作区索引:最近在 '{{primary}}' 分支上分析(重新运行 gitnexus analyze 以跟随当前分支)",
|
|
@@ -231,6 +233,7 @@ export const zhCN = {
|
|
|
231
233
|
'help.option.group.sync.exactOnly': '仅精确匹配',
|
|
232
234
|
'help.option.group.sync.allowStale': '跳过过期索引警告',
|
|
233
235
|
'help.option.group.sync.verbose': '显示每条跨仓库链接详情',
|
|
236
|
+
'help.option.status.json': '输出机器可读的索引和分析器来源信息',
|
|
234
237
|
'help.option.json': 'JSON 输出',
|
|
235
238
|
'help.option.group.impact.target': '要分析的符号或文件名',
|
|
236
239
|
'help.option.group.impact.repo': 'group.yaml 中的成员路径(如 app/backend),不是已索引仓库名称',
|
|
@@ -244,5 +247,6 @@ export const zhCN = {
|
|
|
244
247
|
'help.option.group.contracts.type': '按契约类型过滤',
|
|
245
248
|
'help.option.group.contracts.repo': '按仓库过滤',
|
|
246
249
|
'help.option.group.contracts.unmatched': '仅显示未匹配契约',
|
|
247
|
-
'help.
|
|
250
|
+
'help.identityCache.environment': '\n分析器身份缓存:\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir\n 由操作员明确信任的持久缓存,用于跨进程快速查询状态。目录必须预先存在、位于 GitNexus 包/构建根目录之外,且路径中不得包含符号链接或 junction。缺少 POSIX 所有权 API 的平台默认保持故障关闭。',
|
|
251
|
+
'help.analyze.environment': '\n环境变量:\n GITNEXUS_NO_GITIGNORE=1 跳过 .gitignore 解析(仍读取 .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N 覆盖大文件跳过阈值(KB)。默认 512,最大 32768。\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir 由操作员明确信任的持久分析器身份缓存;目录必须预先存在、位于包/构建根目录之外,且路径中不得包含符号链接或 junction。\n GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=N Worker 空闲超时(毫秒)。默认 30000。\n GITNEXUS_WAL_CHECKPOINT_THRESHOLD=N LadybugDB WAL 自动 checkpoint 阈值(字节,默认 67108864 = 64 MiB;-1 保持 Ladybug 默认约 16 MiB)。\n GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES=N Worker 作业字节预算。默认 8388608。\n GITNEXUS_WORKER_POOL_SIZE=N 解析 worker 数量覆盖值。默认 cores-1,最多 16。\n GITNEXUS_PARSE_CHUNK_CONCURRENCY=N 并发进行中的解析分块数。默认 2。\n GITNEXUS_WORKER_MAX_RESPAWNS_PER_SLOT=N 每个 slot 丢弃前允许的最大替换进程数。默认 3。\n GITNEXUS_WORKER_MAX_CUMULATIVE_TIMEOUT_MS=N 每个作业的总重试墙钟时间。默认 5 倍子批次超时。\n GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD=N 每个 slot 触发熔断的死亡次数。默认 max(3, poolSize)。\n GITNEXUS_WORKER_SHUTDOWN_DRAIN_MS=N 线程池关闭时等待仍在原生代码中的已退役 worker 的最长时间(到达安全点后再终止,避免进程级 abort)。默认 30000。\n GITNEXUS_CPP_CAPTURE_BUDGET_MS=N C++ 捕获提取的每文件墙钟预算;超出后该文件保留部分捕获并输出警告。默认 20000。\n GITNEXUS_EMBEDDING_THREADS=N 限制 --embeddings 的本地 ONNX CPU 线程数。\n GITNEXUS_SEMANTIC_EXACT_SCAN_LIMIT=N exact-scan 回退的最大嵌入分块数。默认 10000。\n GITNEXUS_VECTOR_MAX_DISTANCE=N 语义/向量搜索接受的最大余弦距离(0 < N <= 2;超出则钳制为 2)。MCP 默认 0.6,其他路径默认 0.5。\n\n当参数和对应环境变量同时提供时,参数优先。\n\n提示:`.gitnexusignore` 支持 `.gitignore` 风格的取反。比如添加\n `!__tests__/` 可以索引默认自动过滤的目录(#771)。',
|
|
248
252
|
};
|
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Removing it from here improves MCP server startup time significantly.
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
|
-
import { createLazyAction, createLbugLazyAction } from './lazy-action.js';
|
|
6
|
+
import { createAnalyzerLbugLazyAction, createLazyAction, createLbugLazyAction, } from './lazy-action.js';
|
|
7
7
|
import { EMBEDDING_DIMS_ERROR, normalizeEmbeddingDims } from './embedding-dims.js';
|
|
8
8
|
import { registerGroupCommands } from './group.js';
|
|
9
9
|
import { localizeCliHelp } from './help-i18n.js';
|
|
@@ -119,7 +119,7 @@ program
|
|
|
119
119
|
process.env.GITNEXUS_EMBEDDING_DIMS = dimsEnvBaseline;
|
|
120
120
|
}
|
|
121
121
|
})
|
|
122
|
-
.action(
|
|
122
|
+
.action(createAnalyzerLbugLazyAction(() => import('../core/analyzer-identity.js'), () => import('./analyze.js'), 'analyzeCommandWithRunnerIdentity', import.meta.url));
|
|
123
123
|
program
|
|
124
124
|
.command('index [path...]')
|
|
125
125
|
.description('Register an existing .gitnexus/ folder into the global registry (no re-analysis needed)')
|
|
@@ -148,6 +148,8 @@ program
|
|
|
148
148
|
program
|
|
149
149
|
.command('status')
|
|
150
150
|
.description('Show index status for current repo')
|
|
151
|
+
.option('--json', 'Emit machine-readable index and analyzer provenance')
|
|
152
|
+
.addHelpText('after', () => t('help.identityCache.environment'))
|
|
151
153
|
.action(createLazyAction(() => import('./status.js'), 'statusCommand'));
|
|
152
154
|
program
|
|
153
155
|
.command('doctor')
|
|
@@ -5,3 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function createLazyAction<TModule extends Record<string, unknown>, TKey extends string & keyof TModule>(loader: () => Promise<TModule>, exportName: TKey): (...args: unknown[]) => Promise<void>;
|
|
7
7
|
export declare function createLbugLazyAction<TModule extends Record<string, unknown>, TKey extends string & keyof TModule>(loader: () => Promise<TModule>, exportName: TKey): (...args: unknown[]) => Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Analyze-specific lazy action. Unlike the generic LadybugDB wrapper, this
|
|
10
|
+
* captures the complete analyzer receipt before probing/loading native code or
|
|
11
|
+
* evaluating the analyzer module graph. The target export receives that start
|
|
12
|
+
* receipt as its first argument and threads it to runFullAnalysis.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAnalyzerLbugLazyAction<TModule extends Record<string, unknown>, TKey extends string & keyof TModule>(identityLoader: () => Promise<Pick<typeof import('../core/analyzer-identity.js'), 'captureAnalyzerIdentityBeforeLoad'>>, loader: () => Promise<TModule>, exportName: TKey, analyzerModuleUrl: string): (...args: unknown[]) => Promise<void>;
|
package/dist/cli/lazy-action.js
CHANGED
|
@@ -33,3 +33,30 @@ export function createLbugLazyAction(loader, exportName) {
|
|
|
33
33
|
await action(...args);
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Analyze-specific lazy action. Unlike the generic LadybugDB wrapper, this
|
|
38
|
+
* captures the complete analyzer receipt before probing/loading native code or
|
|
39
|
+
* evaluating the analyzer module graph. The target export receives that start
|
|
40
|
+
* receipt as its first argument and threads it to runFullAnalysis.
|
|
41
|
+
*/
|
|
42
|
+
export function createAnalyzerLbugLazyAction(identityLoader, loader, exportName, analyzerModuleUrl) {
|
|
43
|
+
return async (...args) => {
|
|
44
|
+
const identityModule = await identityLoader();
|
|
45
|
+
const prepared = await identityModule.captureAnalyzerIdentityBeforeLoad(analyzerModuleUrl, async () => {
|
|
46
|
+
const check = checkLbugNative();
|
|
47
|
+
if (!check.ok)
|
|
48
|
+
return { check, module: null };
|
|
49
|
+
return { check, module: await loader() };
|
|
50
|
+
});
|
|
51
|
+
if (!prepared.loaded.check.ok) {
|
|
52
|
+
process.stderr.write(`\n ${prepared.loaded.check.message?.replace(/\n/g, '\n ')}\n\n`);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const action = prepared.loaded.module?.[exportName];
|
|
57
|
+
if (!isCallable(action)) {
|
|
58
|
+
throw new Error(`Lazy action export not found: ${exportName}`);
|
|
59
|
+
}
|
|
60
|
+
await action(prepared.runnerIdentity, ...args);
|
|
61
|
+
};
|
|
62
|
+
}
|
package/dist/cli/setup.d.ts
CHANGED
|
@@ -37,6 +37,14 @@ interface SetupResult {
|
|
|
37
37
|
* install paths copy this same list from hooks/claude/ (the canonical source).
|
|
38
38
|
*/
|
|
39
39
|
export declare function copyHookHelpers(srcDir: string, destDir: string, label: string, result: SetupResult): Promise<string[]>;
|
|
40
|
+
export declare const RENAMED_SKILL_DIRS: Readonly<Record<string, readonly string[]>>;
|
|
41
|
+
/**
|
|
42
|
+
* Every legacy directory name superseded by a shipped rename. These no longer
|
|
43
|
+
* exist in the bundled skills/ source, but a pre-rename install left them
|
|
44
|
+
* behind in every editor target. Setup only warns about them (it cannot prove
|
|
45
|
+
* it owns the contents); uninstall's ownership-by-name contract removes them.
|
|
46
|
+
*/
|
|
47
|
+
export declare const LEGACY_SKILL_DIR_NAMES: readonly string[];
|
|
40
48
|
export declare const setupCommand: (options?: {
|
|
41
49
|
codingAgent?: string[] | string;
|
|
42
50
|
}) => Promise<void>;
|
package/dist/cli/setup.js
CHANGED
|
@@ -22,8 +22,10 @@ const execFileAsync = promisify(execFile);
|
|
|
22
22
|
// a config that persists in the user's editor and is invoked on every MCP
|
|
23
23
|
// connect. Pinning to the installed version means subsequent invocations
|
|
24
24
|
// skip the npm-registry metadata roundtrip (and stay reproducible until
|
|
25
|
-
// the user upgrades).
|
|
26
|
-
//
|
|
25
|
+
// the user upgrades). The plugin skill mcp.json are likewise pinned and
|
|
26
|
+
// re-stamped every release by scripts/sync-plugin-manifests.mjs (#2445),
|
|
27
|
+
// since they too execute `gitnexus@<version>` on connect. Only the READMEs
|
|
28
|
+
// stay on `gitnexus@latest` — they're quickstart docs, not executed state.
|
|
27
29
|
const _require = createRequire(import.meta.url);
|
|
28
30
|
const _pkg = _require('../../package.json');
|
|
29
31
|
if (typeof _pkg.version !== 'string' || !_pkg.version) {
|
|
@@ -882,6 +884,16 @@ async function setupCodex(result) {
|
|
|
882
884
|
}
|
|
883
885
|
}
|
|
884
886
|
// ─── Skill Installation ───────────────────────────────────────────
|
|
887
|
+
export const RENAMED_SKILL_DIRS = {
|
|
888
|
+
'gitnexus-review': ['gitnexus-pr-review'],
|
|
889
|
+
};
|
|
890
|
+
/**
|
|
891
|
+
* Every legacy directory name superseded by a shipped rename. These no longer
|
|
892
|
+
* exist in the bundled skills/ source, but a pre-rename install left them
|
|
893
|
+
* behind in every editor target. Setup only warns about them (it cannot prove
|
|
894
|
+
* it owns the contents); uninstall's ownership-by-name contract removes them.
|
|
895
|
+
*/
|
|
896
|
+
export const LEGACY_SKILL_DIR_NAMES = Object.values(RENAMED_SKILL_DIRS).flat();
|
|
885
897
|
/**
|
|
886
898
|
* Install GitNexus skills to a target directory.
|
|
887
899
|
* Each skill is installed as {targetDir}/gitnexus-{skillName}/SKILL.md
|
|
@@ -937,15 +949,25 @@ async function installSkillsTo(targetDir) {
|
|
|
937
949
|
if (source.isDirectory) {
|
|
938
950
|
const dirSource = path.join(skillsRoot, skillName);
|
|
939
951
|
await copyDirRecursive(dirSource, skillDir);
|
|
940
|
-
installed.push(skillName);
|
|
941
952
|
}
|
|
942
953
|
else {
|
|
943
954
|
const flatSource = path.join(skillsRoot, `${skillName}.md`);
|
|
944
955
|
const content = await fs.readFile(flatSource, 'utf-8');
|
|
945
956
|
await fs.mkdir(skillDir, { recursive: true });
|
|
946
957
|
await fs.writeFile(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
|
|
947
|
-
installed.push(skillName);
|
|
948
958
|
}
|
|
959
|
+
// A directory superseded by a shipped rename is warned about, never
|
|
960
|
+
// deleted: the installer cannot prove it owns the contents (users
|
|
961
|
+
// customize installed skills or hand-write their own under these
|
|
962
|
+
// names), so an upgrade must not destroy data.
|
|
963
|
+
for (const oldName of RENAMED_SKILL_DIRS[skillName] ?? []) {
|
|
964
|
+
const legacyDir = path.join(targetDir, oldName);
|
|
965
|
+
if (await dirExists(legacyDir)) {
|
|
966
|
+
console.log(`[gitnexus] skill "${oldName}" was renamed to "${skillName}"; ` +
|
|
967
|
+
`left ${legacyDir} in place — delete it manually if you have not customized it.`);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
installed.push(skillName);
|
|
949
971
|
}
|
|
950
972
|
catch {
|
|
951
973
|
// Source skill not found — skip
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type StandardSkillDistribution = 'project' | 'npm' | 'claudePlugin' | 'cursor';
|
|
2
|
+
export interface StandardSkillCatalogEntry {
|
|
3
|
+
readonly name: `gitnexus-${string}`;
|
|
4
|
+
readonly agentTableTask: string;
|
|
5
|
+
readonly fallbackDescription: string;
|
|
6
|
+
readonly distributions: Readonly<Record<StandardSkillDistribution, boolean>>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Canonical metadata for the standard skills installed by `gitnexus analyze`.
|
|
10
|
+
*
|
|
11
|
+
* Keep distribution intent here so generated agent guidance and drift guards
|
|
12
|
+
* cannot disagree about which copies should exist. The ordering intentionally
|
|
13
|
+
* matches the generated AGENTS.md / CLAUDE.md task table.
|
|
14
|
+
*/
|
|
15
|
+
export declare const STANDARD_SKILL_CATALOG: readonly [{
|
|
16
|
+
readonly name: "gitnexus-exploring";
|
|
17
|
+
readonly agentTableTask: "Understand architecture / \"How does X work?\"";
|
|
18
|
+
readonly fallbackDescription: "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\"";
|
|
19
|
+
readonly distributions: {
|
|
20
|
+
readonly project: true;
|
|
21
|
+
readonly npm: true;
|
|
22
|
+
readonly claudePlugin: true;
|
|
23
|
+
readonly cursor: true;
|
|
24
|
+
};
|
|
25
|
+
}, {
|
|
26
|
+
readonly name: "gitnexus-impact-analysis";
|
|
27
|
+
readonly agentTableTask: "Blast radius / \"What breaks if I change X?\"";
|
|
28
|
+
readonly fallbackDescription: "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?\"";
|
|
29
|
+
readonly distributions: {
|
|
30
|
+
readonly project: true;
|
|
31
|
+
readonly npm: true;
|
|
32
|
+
readonly claudePlugin: true;
|
|
33
|
+
readonly cursor: true;
|
|
34
|
+
};
|
|
35
|
+
}, {
|
|
36
|
+
readonly name: "gitnexus-debugging";
|
|
37
|
+
readonly agentTableTask: "Trace bugs / \"Why is X failing?\"";
|
|
38
|
+
readonly fallbackDescription: "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\"";
|
|
39
|
+
readonly distributions: {
|
|
40
|
+
readonly project: true;
|
|
41
|
+
readonly npm: true;
|
|
42
|
+
readonly claudePlugin: true;
|
|
43
|
+
readonly cursor: true;
|
|
44
|
+
};
|
|
45
|
+
}, {
|
|
46
|
+
readonly name: "gitnexus-refactoring";
|
|
47
|
+
readonly agentTableTask: "Rename / extract / split / refactor";
|
|
48
|
+
readonly fallbackDescription: "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\"";
|
|
49
|
+
readonly distributions: {
|
|
50
|
+
readonly project: true;
|
|
51
|
+
readonly npm: true;
|
|
52
|
+
readonly claudePlugin: true;
|
|
53
|
+
readonly cursor: true;
|
|
54
|
+
};
|
|
55
|
+
}, {
|
|
56
|
+
readonly name: "gitnexus-guide";
|
|
57
|
+
readonly agentTableTask: "Tools, resources, schema reference";
|
|
58
|
+
readonly fallbackDescription: "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?\"";
|
|
59
|
+
readonly distributions: {
|
|
60
|
+
readonly project: true;
|
|
61
|
+
readonly npm: true;
|
|
62
|
+
readonly claudePlugin: true;
|
|
63
|
+
readonly cursor: false;
|
|
64
|
+
};
|
|
65
|
+
}, {
|
|
66
|
+
readonly name: "gitnexus-cli";
|
|
67
|
+
readonly agentTableTask: "Index, status, clean, wiki CLI commands";
|
|
68
|
+
readonly fallbackDescription: "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\"";
|
|
69
|
+
readonly distributions: {
|
|
70
|
+
readonly project: true;
|
|
71
|
+
readonly npm: true;
|
|
72
|
+
readonly claudePlugin: true;
|
|
73
|
+
readonly cursor: false;
|
|
74
|
+
};
|
|
75
|
+
}];
|
|
76
|
+
export type StandardSkillName = (typeof STANDARD_SKILL_CATALOG)[number]['name'];
|