gitnexus 1.6.13-rc.15 → 1.6.13-rc.17

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 CHANGED
@@ -245,6 +245,8 @@ gitnexus analyze --skip-agents-md # Preserve custom AGENTS.md/CLAUDE.md gitnexu
245
245
  gitnexus analyze --skip-skills # Skip installing standard .claude/skills/gitnexus-* skill files
246
246
  gitnexus analyze --skip-git # Index folders that are not Git repositories
247
247
  gitnexus analyze --workers <n> # Parse worker pool size (>=1; default: cores-1, capped at 16)
248
+ gitnexus analyze --max-processes <n> # Process-detection process cap (replaces dynamic max(20, round(symbols/10)))
249
+ gitnexus analyze --max-entry-point-candidates <n> # Ranked entry-point pool (default 200; raise when the warning names it)
248
250
  gitnexus analyze --spring-actuator ./actuator # Enrich with local Spring Boot Actuator JSON snapshots
249
251
  gitnexus analyze --verbose # Log skipped files when parsers are unavailable
250
252
  gitnexus analyze --max-file-size 1024 # Skip files larger than N KB (default: 512, cap: 32768)
@@ -298,7 +300,8 @@ installation. Run a one-shot `gitnexus analyze` when those generated files need
298
300
  updating. Stop watch mode with Ctrl+C.
299
301
 
300
302
  Watch mode accepts `--debounce`, `--workers`, `--worker-timeout`,
301
- `--max-file-size`, `--branch`, `--pdg`, `--name`, `--allow-duplicate-name`, and
303
+ `--max-file-size`, `--max-processes`, `--max-process-branching`,
304
+ `--max-process-trace-depth`, `--max-entry-point-candidates`, `--branch`, `--pdg`, `--name`, `--allow-duplicate-name`, and
302
305
  `--verbose`. Explicit one-shot options such as `--force`, `--repair-fts`,
303
306
  embedding flags, `--skills`, `--default-branch`, `--skip-agents-md`,
304
307
  `--skip-skills`, `--no-stats`, `--self-commit`, `--index-only`, and `--skip-git`
@@ -764,6 +767,22 @@ npx gitnexus analyze
764
767
 
765
768
  Values above **32768 KB (32 MB)** are clamped to the tree-sitter parser ceiling; invalid values fall back to the 512 KB default with a one-time warning. When an override is active, `analyze` prints the effective threshold in its startup banner (e.g. `GITNEXUS_MAX_FILE_SIZE: effective threshold 2048KB (default 512KB)`).
766
769
 
770
+ ### Process detection reports missing flows
771
+
772
+ On a large repository, `analyze` may warn that `[processes] … whole flows are MISSING`. That means ranked entry points or completed flows were sampled away by the analyze-time detection budget — not that the code path is absent, and not the query-time `IMPACT_MAX_CHUNKS` cap.
773
+
774
+ Defaults stay in place when nothing is set: dynamic `maxProcesses = max(20, round(non-File symbols / 10))`, branching `4`, trace depth `10`, entry-point candidate pool `200`. Raise a knob only when the warning names it:
775
+
776
+ ```bash
777
+ # Usual first move when entryPointCandidatesDropped is the loud counter
778
+ npx gitnexus analyze --max-entry-point-candidates 400
779
+
780
+ # When ranked entry points were never traced, or flows were dropped at maxProcesses
781
+ npx gitnexus analyze --max-processes 80
782
+ ```
783
+
784
+ Equivalent `.gitnexusrc` keys: `maxProcesses`, `maxProcessBranching`, `maxProcessTraceDepth`, `maxEntryPointCandidates`. Equivalent env vars: `GITNEXUS_MAX_PROCESSES`, `GITNEXUS_MAX_PROCESS_BRANCHING`, `GITNEXUS_MAX_PROCESS_TRACE_DEPTH`, `GITNEXUS_MAX_ENTRY_POINT_CANDIDATES`. Precedence is CLI > `.gitnexusrc` > env > default. `0` is invalid, not unlimited. Changing these knobs re-runs process detection on the next `analyze` without `--force`. Raising them increases CPU and memory; this is not a heap-OOM fix.
785
+
767
786
  ### Analyze reports a worker timeout
768
787
 
769
788
  Worker parse timeouts are recoverable. GitNexus retries stalled worker jobs with backoff, splits large jobs to isolate slow files, and quarantines a file that repeatedly crashes its worker (respawning the slot so the pool keeps going). If a large repository needs more time per worker job, use either:
@@ -27,6 +27,8 @@
27
27
  * documented precedence). Conflicting *aliases at the same level* (e.g. both
28
28
  * `defaultBranch` and `branch`) are rejected.
29
29
  */
30
+ import { sanitizeDetectedBranch } from '../core/git-ref.js';
31
+ export { sanitizeDetectedBranch };
30
32
  import type { AnalyzeOptions } from './analyze-options.js';
31
33
  export declare const GITNEXUS_RC_FILENAME = ".gitnexusrc";
32
34
  /** Final fallback when no branch is configured or detectable. */
@@ -45,12 +47,6 @@ export declare class GitNexusRcError extends Error {
45
47
  * `core/git-ref.ts`; this wrapper keeps the CLI / `.gitnexusrc` error type.
46
48
  */
47
49
  export declare function validateBranchName(value: string, source: string): string;
48
- /**
49
- * Best-effort validation for an auto-detected branch (from git). Never throws —
50
- * returns `undefined` for anything unusable so the resolver falls back to the
51
- * next precedence tier.
52
- */
53
- export declare function sanitizeDetectedBranch(value: string | null | undefined): string | undefined;
54
50
  /**
55
51
  * Locate, read, parse, validate, and normalize `.gitnexusrc` at `repoRoot`.
56
52
  *
@@ -30,7 +30,8 @@
30
30
  import fs from 'node:fs';
31
31
  import path from 'node:path';
32
32
  import { readRepoControlFile } from '../config/repo-control-file.js';
33
- import { InvalidBranchError, validateBranchName as validateBranchNameCore, } from '../core/git-ref.js';
33
+ import { InvalidBranchError, sanitizeDetectedBranch, validateBranchName as validateBranchNameCore, } from '../core/git-ref.js';
34
+ export { sanitizeDetectedBranch };
34
35
  export const GITNEXUS_RC_FILENAME = '.gitnexusrc';
35
36
  /** Final fallback when no branch is configured or detectable. */
36
37
  export const DEFAULT_BRANCH_FALLBACK = 'main';
@@ -75,6 +76,10 @@ const KEY_SPECS = {
75
76
  workerTimeout: { target: 'workerTimeout', kind: 'numeric-string' },
76
77
  walCheckpointThreshold: { target: 'walCheckpointThreshold', kind: 'numeric-string' },
77
78
  workers: { target: 'workers', kind: 'numeric-string' },
79
+ maxProcesses: { target: 'maxProcesses', kind: 'numeric-string' },
80
+ maxProcessBranching: { target: 'maxProcessBranching', kind: 'numeric-string' },
81
+ maxProcessTraceDepth: { target: 'maxProcessTraceDepth', kind: 'numeric-string' },
82
+ maxEntryPointCandidates: { target: 'maxEntryPointCandidates', kind: 'numeric-string' },
78
83
  embeddingThreads: { target: 'embeddingThreads', kind: 'numeric-string' },
79
84
  embeddingBatchSize: { target: 'embeddingBatchSize', kind: 'numeric-string' },
80
85
  embeddingSubBatchSize: { target: 'embeddingSubBatchSize', kind: 'numeric-string' },
@@ -139,21 +144,6 @@ export function validateBranchName(value, source) {
139
144
  throw err;
140
145
  }
141
146
  }
142
- /**
143
- * Best-effort validation for an auto-detected branch (from git). Never throws —
144
- * returns `undefined` for anything unusable so the resolver falls back to the
145
- * next precedence tier.
146
- */
147
- export function sanitizeDetectedBranch(value) {
148
- if (!value)
149
- return undefined;
150
- try {
151
- return validateBranchName(value, 'detected branch');
152
- }
153
- catch {
154
- return undefined;
155
- }
156
- }
157
147
  const normalizeValue = (kind, value, key) => {
158
148
  const source = `${GITNEXUS_RC_FILENAME} "${key}"`;
159
149
  switch (kind) {
@@ -115,6 +115,14 @@ export interface AnalyzeOptions {
115
115
  walCheckpointThreshold?: string;
116
116
  /** Parse worker pool size (>=1); 0 is rejected (no sequential mode). */
117
117
  workers?: string;
118
+ /** Process-detection process cap. Positive integer string; `0` is invalid. */
119
+ maxProcesses?: string;
120
+ /** Process-detection per-node branching cap. Positive integer string. */
121
+ maxProcessBranching?: string;
122
+ /** Process-detection DFS depth cap. Positive integer string. */
123
+ maxProcessTraceDepth?: string;
124
+ /** Ranked entry-point candidate pool. Positive integer string. */
125
+ maxEntryPointCandidates?: string;
118
126
  embeddingThreads?: string;
119
127
  embeddingBatchSize?: string;
120
128
  embeddingSubBatchSize?: string;
@@ -11,6 +11,7 @@ import { GITNEXUS_DIR } from '../storage/repo-meta.js';
11
11
  import { loadAnalyzeConfigStrict, mergeAnalyzeOptions, validateBranchName, } from './analyze-config.js';
12
12
  import { ensureHeap } from './analyze.js';
13
13
  import { cliError, cliInfo, cliWarn } from './cli-message.js';
14
+ import { formatInvalidProcessDetectionOverride, parseProcessDetectionBudgetStrings, } from '../core/ingestion/process-detection-budget.js';
14
15
  import { WATCH_FULL_REFRESH_PATH, WatchRefreshQueue, } from './watch-queue.js';
15
16
  const DEFAULT_DEBOUNCE_MS = 300;
16
17
  const MAX_TIMER_DELAY_MS = 2_147_483_647;
@@ -119,6 +120,14 @@ export async function resolveWatchOptions(repoPath, cli, baseline, reportIgnored
119
120
  const workerPoolSize = positiveInteger(merged.workers, '--workers');
120
121
  const workerTimeoutSeconds = positiveInteger(merged.workerTimeout, 'workerTimeout');
121
122
  const maxFileSize = positiveInteger(merged.maxFileSize, 'maxFileSize', MAX_FILE_SIZE_KB);
123
+ const processDetection = parseProcessDetectionBudgetStrings({
124
+ maxProcesses: merged.maxProcesses,
125
+ maxProcessBranching: merged.maxProcessBranching,
126
+ maxProcessTraceDepth: merged.maxProcessTraceDepth,
127
+ maxEntryPointCandidates: merged.maxEntryPointCandidates,
128
+ }, (flag, raw) => {
129
+ cliWarn(formatInvalidProcessDetectionOverride(flag, raw));
130
+ });
122
131
  setEnvironment('GITNEXUS_MAX_FILE_SIZE', maxFileSize === undefined ? baseline.maxFileSize : String(maxFileSize));
123
132
  if (workerTimeoutSeconds !== undefined) {
124
133
  process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS = String(workerTimeoutSeconds * 1000);
@@ -134,6 +143,10 @@ export async function resolveWatchOptions(repoPath, cli, baseline, reportIgnored
134
143
  registryName: merged.name,
135
144
  allowDuplicateName: merged.allowDuplicateName,
136
145
  workerPoolSize,
146
+ maxProcesses: processDetection.maxProcesses,
147
+ maxProcessBranching: processDetection.maxProcessBranching,
148
+ maxProcessTraceDepth: processDetection.maxProcessTraceDepth,
149
+ maxEntryPointCandidates: processDetection.maxEntryPointCandidates,
137
150
  fetchWrappers: merged.fetchWrappers,
138
151
  skipAgentsMd: true,
139
152
  skipSkills: true,
@@ -25,6 +25,7 @@ import { loadAnalyzeConfig, mergeAnalyzeOptions, resolveDefaultBranch, validateB
25
25
  import { runFullAnalysis } from '../core/run-analyze.js';
26
26
  import { getRuntimeFingerprint } from '../core/platform/capabilities.js';
27
27
  import { getMaxFileSizeBannerMessage } from '../core/ingestion/utils/max-file-size.js';
28
+ import { formatInvalidProcessDetectionOverride, formatProcessDetectionBudgetBanner, parseProcessDetectionBudgetStrings, resolveProcessDetectionBudget, } from '../core/ingestion/process-detection-budget.js';
28
29
  import { warnMissingOptionalGrammars, getOptionalGrammarExtensions } from './optional-grammars.js';
29
30
  import { glob } from 'glob';
30
31
  import fs from 'fs/promises';
@@ -753,6 +754,14 @@ const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstr
753
754
  }
754
755
  workerPoolSize = parsedWorkers;
755
756
  }
757
+ const processDetectionFromFlags = parseProcessDetectionBudgetStrings({
758
+ maxProcesses: options.maxProcesses,
759
+ maxProcessBranching: options.maxProcessBranching,
760
+ maxProcessTraceDepth: options.maxProcessTraceDepth,
761
+ maxEntryPointCandidates: options.maxEntryPointCandidates,
762
+ }, (flag, raw) => {
763
+ cliWarn(` ${formatInvalidProcessDetectionOverride(flag, raw)}\n`);
764
+ });
756
765
  // Parse `--embeddings [limit]`: `true` → default cap, string → numeric cap
757
766
  // (0 disables the cap entirely). Validated up here so failures match the
758
767
  // sibling-validation pattern (exit before bar.start() — otherwise
@@ -987,6 +996,10 @@ const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstr
987
996
  if (maxFileSizeBanner) {
988
997
  console.log(`${maxFileSizeBanner}\n`);
989
998
  }
999
+ const processDetectionBanner = formatProcessDetectionBudgetBanner(resolveProcessDetectionBudget(processDetectionFromFlags));
1000
+ if (processDetectionBanner) {
1001
+ console.log(`${processDetectionBanner}\n`);
1002
+ }
990
1003
  // ── CLI progress bar setup ─────────────────────────────────────────
991
1004
  const barOptions = {
992
1005
  format: ' {bar} {percentage}% | {phase}',
@@ -1119,6 +1132,10 @@ const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstr
1119
1132
  // GITNEXUS_WORKER_POOL_SIZE env mutation. `undefined` defers to the
1120
1133
  // env / auto-formula fallback inside the pipeline.
1121
1134
  workerPoolSize,
1135
+ maxProcesses: processDetectionFromFlags.maxProcesses,
1136
+ maxProcessBranching: processDetectionFromFlags.maxProcessBranching,
1137
+ maxProcessTraceDepth: processDetectionFromFlags.maxProcessTraceDepth,
1138
+ maxEntryPointCandidates: processDetectionFromFlags.maxEntryPointCandidates,
1122
1139
  // Extra fetch-wrapper names from `.gitnexusrc` (#1589/#1852 residual);
1123
1140
  // forwarded to the routes phase consumer scan.
1124
1141
  fetchWrappers: options.fetchWrappers,
@@ -68,6 +68,10 @@ const OPTION_DESCRIPTION_KEYS = {
68
68
  'analyze|--worker-timeout <seconds>': 'help.option.analyze.workerTimeout',
69
69
  'analyze|--wal-checkpoint-threshold <bytes>': 'help.option.analyze.walCheckpointThreshold',
70
70
  'analyze|--workers <n>': 'help.option.analyze.workers',
71
+ 'analyze|--max-processes <n>': 'help.option.analyze.maxProcesses',
72
+ 'analyze|--max-process-branching <n>': 'help.option.analyze.maxProcessBranching',
73
+ 'analyze|--max-process-trace-depth <n>': 'help.option.analyze.maxProcessTraceDepth',
74
+ 'analyze|--max-entry-point-candidates <n>': 'help.option.analyze.maxEntryPointCandidates',
71
75
  'analyze|--embedding-threads <n>': 'help.option.analyze.embeddingThreads',
72
76
  'analyze|--embedding-batch-size <n>': 'help.option.analyze.embeddingBatchSize',
73
77
  'analyze|--embedding-sub-batch-size <n>': 'help.option.analyze.embeddingSubBatchSize',
@@ -193,6 +193,10 @@ export declare const en: {
193
193
  readonly 'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.';
194
194
  readonly 'help.option.analyze.walCheckpointThreshold': 'LadybugDB WAL auto-checkpoint threshold in bytes during analyze (integer >= -1; default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).';
195
195
  readonly 'help.option.analyze.workers': 'Parse worker pool size (>=1). Default: cores-1 capped at 16, auto-sized to the repo.';
196
+ readonly 'help.option.analyze.maxProcesses': 'Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Default: dynamic.';
197
+ readonly 'help.option.analyze.maxProcessBranching': 'Process-detection per-node branching cap (positive integer). Default: 4.';
198
+ readonly 'help.option.analyze.maxProcessTraceDepth': 'Process-detection DFS depth cap (positive integer). Default: 10.';
199
+ readonly 'help.option.analyze.maxEntryPointCandidates': 'Ranked entry-point candidate pool (positive integer). Default: 200. Raise when the warning names this knob; doubling is the usual first raise.';
196
200
  readonly 'help.option.analyze.embeddingThreads': 'Limit local ONNX embedding CPU threads';
197
201
  readonly 'help.option.analyze.embeddingBatchSize': 'Number of nodes per embedding batch';
198
202
  readonly 'help.option.analyze.embeddingSubBatchSize': 'Number of chunks per embedding model call';
@@ -278,5 +282,5 @@ export declare const en: {
278
282
  readonly 'help.option.group.contracts.repo': 'Filter by repo';
279
283
  readonly 'help.option.group.contracts.unmatched': 'Show only unmatched contracts';
280
284
  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.';
281
- 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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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).';
285
+ 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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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 GITNEXUS_MAX_PROCESSES=N Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Distinct from query-time IMPACT_MAX_CHUNKS.\n GITNEXUS_MAX_PROCESS_BRANCHING=N Process-detection per-node branching cap. Default 4.\n GITNEXUS_MAX_PROCESS_TRACE_DEPTH=N Process-detection DFS depth cap. Default 10.\n GITNEXUS_MAX_ENTRY_POINT_CANDIDATES=N Ranked entry-point candidate pool. Default 200. Raise when the warning names this knob; doubling is the usual first raise.\n\nCLI flags take precedence over `.gitnexusrc`, which takes precedence over env vars, which take precedence over built-in defaults.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).';
282
286
  };
@@ -195,6 +195,10 @@ export const en = {
195
195
  'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.',
196
196
  'help.option.analyze.walCheckpointThreshold': 'LadybugDB WAL auto-checkpoint threshold in bytes during analyze (integer >= -1; default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).',
197
197
  'help.option.analyze.workers': 'Parse worker pool size (>=1). Default: cores-1 capped at 16, auto-sized to the repo.',
198
+ 'help.option.analyze.maxProcesses': 'Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Default: dynamic.',
199
+ 'help.option.analyze.maxProcessBranching': 'Process-detection per-node branching cap (positive integer). Default: 4.',
200
+ 'help.option.analyze.maxProcessTraceDepth': 'Process-detection DFS depth cap (positive integer). Default: 10.',
201
+ 'help.option.analyze.maxEntryPointCandidates': 'Ranked entry-point candidate pool (positive integer). Default: 200. Raise when the warning names this knob; doubling is the usual first raise.',
198
202
  'help.option.analyze.embeddingThreads': 'Limit local ONNX embedding CPU threads',
199
203
  'help.option.analyze.embeddingBatchSize': 'Number of nodes per embedding batch',
200
204
  'help.option.analyze.embeddingSubBatchSize': 'Number of chunks per embedding model call',
@@ -280,5 +284,5 @@ export const en = {
280
284
  'help.option.group.contracts.repo': 'Filter by repo',
281
285
  'help.option.group.contracts.unmatched': 'Show only unmatched contracts',
282
286
  '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.',
283
- '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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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).',
287
+ '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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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 GITNEXUS_MAX_PROCESSES=N Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Distinct from query-time IMPACT_MAX_CHUNKS.\n GITNEXUS_MAX_PROCESS_BRANCHING=N Process-detection per-node branching cap. Default 4.\n GITNEXUS_MAX_PROCESS_TRACE_DEPTH=N Process-detection DFS depth cap. Default 10.\n GITNEXUS_MAX_ENTRY_POINT_CANDIDATES=N Ranked entry-point candidate pool. Default 200. Raise when the warning names this knob; doubling is the usual first raise.\n\nCLI flags take precedence over `.gitnexusrc`, which takes precedence over env vars, which take precedence over built-in defaults.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).',
284
288
  };
@@ -194,6 +194,10 @@ export declare const cliResources: {
194
194
  readonly 'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.';
195
195
  readonly 'help.option.analyze.walCheckpointThreshold': 'LadybugDB WAL auto-checkpoint threshold in bytes during analyze (integer >= -1; default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).';
196
196
  readonly 'help.option.analyze.workers': 'Parse worker pool size (>=1). Default: cores-1 capped at 16, auto-sized to the repo.';
197
+ readonly 'help.option.analyze.maxProcesses': 'Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Default: dynamic.';
198
+ readonly 'help.option.analyze.maxProcessBranching': 'Process-detection per-node branching cap (positive integer). Default: 4.';
199
+ readonly 'help.option.analyze.maxProcessTraceDepth': 'Process-detection DFS depth cap (positive integer). Default: 10.';
200
+ readonly 'help.option.analyze.maxEntryPointCandidates': 'Ranked entry-point candidate pool (positive integer). Default: 200. Raise when the warning names this knob; doubling is the usual first raise.';
197
201
  readonly 'help.option.analyze.embeddingThreads': 'Limit local ONNX embedding CPU threads';
198
202
  readonly 'help.option.analyze.embeddingBatchSize': 'Number of nodes per embedding batch';
199
203
  readonly 'help.option.analyze.embeddingSubBatchSize': 'Number of chunks per embedding model call';
@@ -279,7 +283,7 @@ export declare const cliResources: {
279
283
  readonly 'help.option.group.contracts.repo': 'Filter by repo';
280
284
  readonly 'help.option.group.contracts.unmatched': 'Show only unmatched contracts';
281
285
  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.';
282
- 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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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).';
286
+ 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_STORAGE_PATH=/absolute/index Complete external index directory. Preserves the existing configuration semantics and overrides GITNEXUS_STORAGE_ROOT when both are set.\n GITNEXUS_STORAGE_ROOT=/absolute/root External index root; each repository uses an isolated <repo-basename>-<canonical-path-hash>/ slot.\n GITNEXUS_CONTENT_RETENTION=full Source-text retention profile: full, symbol, or none. Default full.\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_EMBEDDING_RETRY_TIMEOUTS=1 Retry per-attempt HTTP embedding timeouts through GITNEXUS_EMBEDDING_MAX_ATTEMPTS (default off; timeouts stay terminal).\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 GITNEXUS_MAX_PROCESSES=N Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Distinct from query-time IMPACT_MAX_CHUNKS.\n GITNEXUS_MAX_PROCESS_BRANCHING=N Process-detection per-node branching cap. Default 4.\n GITNEXUS_MAX_PROCESS_TRACE_DEPTH=N Process-detection DFS depth cap. Default 10.\n GITNEXUS_MAX_ENTRY_POINT_CANDIDATES=N Ranked entry-point candidate pool. Default 200. Raise when the warning names this knob; doubling is the usual first raise.\n\nCLI flags take precedence over `.gitnexusrc`, which takes precedence over env vars, which take precedence over built-in defaults.\n\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n `!__tests__/` to index a directory that is auto-filtered by default (#771).';
283
287
  };
284
288
  readonly 'zh-CN': {
285
289
  'common.notIndexed': string;
@@ -476,6 +480,10 @@ export declare const cliResources: {
476
480
  'help.option.analyze.workerTimeout': string;
477
481
  'help.option.analyze.walCheckpointThreshold': string;
478
482
  'help.option.analyze.workers': string;
483
+ 'help.option.analyze.maxProcesses': string;
484
+ 'help.option.analyze.maxProcessBranching': string;
485
+ 'help.option.analyze.maxProcessTraceDepth': string;
486
+ 'help.option.analyze.maxEntryPointCandidates': string;
479
487
  'help.option.analyze.embeddingThreads': string;
480
488
  'help.option.analyze.embeddingBatchSize': string;
481
489
  'help.option.analyze.embeddingSubBatchSize': string;
@@ -193,6 +193,10 @@ export declare const zhCN: {
193
193
  'help.option.analyze.workerTimeout': string;
194
194
  'help.option.analyze.walCheckpointThreshold': string;
195
195
  'help.option.analyze.workers': string;
196
+ 'help.option.analyze.maxProcesses': string;
197
+ 'help.option.analyze.maxProcessBranching': string;
198
+ 'help.option.analyze.maxProcessTraceDepth': string;
199
+ 'help.option.analyze.maxEntryPointCandidates': string;
196
200
  'help.option.analyze.embeddingThreads': string;
197
201
  'help.option.analyze.embeddingBatchSize': string;
198
202
  'help.option.analyze.embeddingSubBatchSize': string;
@@ -193,6 +193,10 @@ export const zhCN = {
193
193
  'help.option.analyze.workerTimeout': 'Worker 子批次空闲超时,超时后重试/回退。默认:30。',
194
194
  'help.option.analyze.walCheckpointThreshold': 'analyze 期间 LadybugDB WAL 自动 checkpoint 阈值(字节,整数 >= -1;默认:67108864 = 64 MiB;-1 保持 Ladybug 默认约 16 MiB)。',
195
195
  'help.option.analyze.workers': '解析 worker 池大小(>=1)。默认:cores-1,最多 16,按仓库规模自适应。',
196
+ 'help.option.analyze.maxProcesses': '流程检测的流程数量上限(正整数)。覆盖动态的 max(20, round(symbols/10)) 公式。默认:动态。',
197
+ 'help.option.analyze.maxProcessBranching': '流程检测的单节点分支上限(正整数)。默认:4。',
198
+ 'help.option.analyze.maxProcessTraceDepth': '流程检测的 DFS 深度上限(正整数)。默认:10。',
199
+ 'help.option.analyze.maxEntryPointCandidates': '排序后的入口点候选池(正整数)。默认:200。仅在警告点名该上限时提高;那时通常先翻倍。',
196
200
  'help.option.analyze.embeddingThreads': '限制本地 ONNX 嵌入 CPU 线程数',
197
201
  'help.option.analyze.embeddingBatchSize': '每个嵌入批次的节点数',
198
202
  'help.option.analyze.embeddingSubBatchSize': '每次嵌入模型调用的分块数',
@@ -278,5 +282,5 @@ export const zhCN = {
278
282
  'help.option.group.contracts.repo': '按仓库过滤',
279
283
  'help.option.group.contracts.unmatched': '仅显示未匹配契约',
280
284
  'help.identityCache.environment': '\n分析器身份缓存:\n GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/absolute/protected/dir\n 由操作员明确信任的持久缓存,用于跨进程快速查询状态。目录必须预先存在、位于 GitNexus 包/构建根目录之外,且路径中不得包含符号链接或 junction。缺少 POSIX 所有权 API 的平台默认保持故障关闭。',
281
- 'help.analyze.environment': '\n环境变量:\n GITNEXUS_NO_GITIGNORE=1 跳过 .gitignore 解析(仍读取 .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N 覆盖大文件跳过阈值(KB)。默认 512,最大 32768。\n GITNEXUS_STORAGE_PATH=/absolute/index 完整外部索引目录。保留既有配置语义;与 GITNEXUS_STORAGE_ROOT 同时设置时优先使用。\n GITNEXUS_STORAGE_ROOT=/absolute/root 外部索引根目录;每个仓库使用独立的 <仓库名>-<规范路径哈希>/ 子目录。\n GITNEXUS_CONTENT_RETENTION=full 源码文本保留策略:full、symbol 或 none。默认 full。\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_EMBEDDING_RETRY_TIMEOUTS=1 将单次 HTTP 嵌入超时纳入 GITNEXUS_EMBEDDING_MAX_ATTEMPTS 重试(默认关闭,超时仍为终止错误)。\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)。',
285
+ 'help.analyze.environment': '\n环境变量:\n GITNEXUS_NO_GITIGNORE=1 跳过 .gitignore 解析(仍读取 .gitnexusignore)\n GITNEXUS_MAX_FILE_SIZE=N 覆盖大文件跳过阈值(KB)。默认 512,最大 32768。\n GITNEXUS_STORAGE_PATH=/absolute/index 完整外部索引目录。保留既有配置语义;与 GITNEXUS_STORAGE_ROOT 同时设置时优先使用。\n GITNEXUS_STORAGE_ROOT=/absolute/root 外部索引根目录;每个仓库使用独立的 <仓库名>-<规范路径哈希>/ 子目录。\n GITNEXUS_CONTENT_RETENTION=full 源码文本保留策略:full、symbol 或 none。默认 full。\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_EMBEDDING_RETRY_TIMEOUTS=1 将单次 HTTP 嵌入超时纳入 GITNEXUS_EMBEDDING_MAX_ATTEMPTS 重试(默认关闭,超时仍为终止错误)。\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 GITNEXUS_MAX_PROCESSES=N 流程检测的流程数量上限(正整数)。覆盖动态的 max(20, round(symbols/10)) 公式。与查询时的 IMPACT_MAX_CHUNKS 无关。\n GITNEXUS_MAX_PROCESS_BRANCHING=N 流程检测的单节点分支上限。默认 4。\n GITNEXUS_MAX_PROCESS_TRACE_DEPTH=N 流程检测的 DFS 深度上限。默认 10。\n GITNEXUS_MAX_ENTRY_POINT_CANDIDATES=N 排序后的入口点候选池。默认 200。仅在警告点名该上限时提高;那时通常先翻倍。\n\nCLI 参数优先于 `.gitnexusrc`,后者优先于环境变量,环境变量优先于内置默认值。\n\n提示:`.gitnexusignore` 支持 `.gitignore` 风格的取反。比如添加\n `!__tests__/` 可以索引默认自动过滤的目录(#771)。',
282
286
  };
package/dist/cli/index.js CHANGED
@@ -85,6 +85,10 @@ program
85
85
  .option('--wal-checkpoint-threshold <bytes>', 'LadybugDB WAL auto-checkpoint threshold in bytes during analyze ' +
86
86
  '(integer >= -1; default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB).')
87
87
  .option('--workers <n>', 'Parse worker pool size (>=1). Default: cores-1 capped at 16, auto-sized to the repo.')
88
+ .option('--max-processes <n>', 'Process-detection process cap (positive integer). Replaces the dynamic max(20, round(symbols/10)) formula. Default: dynamic.')
89
+ .option('--max-process-branching <n>', 'Process-detection per-node branching cap (positive integer). Default: 4.')
90
+ .option('--max-process-trace-depth <n>', 'Process-detection DFS depth cap (positive integer). Default: 10.')
91
+ .option('--max-entry-point-candidates <n>', 'Ranked entry-point candidate pool (positive integer). Default: 200. Raise when the warning names this knob; doubling is the usual first raise.')
88
92
  .option('--spring-actuator <path>', 'Import local Spring Boot Actuator JSON snapshots (mappings, beans, conditions, ' +
89
93
  'configprops, env). Explicit opt-in; disabled by default.')
90
94
  .option('--asyncapi-spec <path>', 'Read AsyncAPI 3.x documents from this directory or file and resolve broker ' +
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Git ref-name validation used by both the CLI and the HTTP analyze route.
3
3
  *
4
- * Lives in `core/` so `server/api.ts` does not import `cli/analyze-config`
5
- * (that import closed a cli → server → cli cycle: `cli/serve.ts` already
6
- * imports `createServer`). The CLI keeps a thin wrapper that rethrows
7
- * {@link InvalidBranchError} as `GitNexusRcError`.
4
+ * Lives in `core/` so `server/api.ts` and `run-analyze.ts` do not import
5
+ * `cli/analyze-config` (that import closed a cli → server → cli cycle:
6
+ * `cli/serve.ts` already imports `createServer`). The CLI keeps a thin
7
+ * wrapper that rethrows {@link InvalidBranchError} as `GitNexusRcError`.
8
8
  */
9
9
  /**
10
10
  * Thrown when a user-supplied branch name fails {@link validateBranchName}.
@@ -20,3 +20,21 @@ export declare class InvalidBranchError extends Error {
20
20
  * branches use (`feature/foo-bar`, `release/1.2`, `develop`).
21
21
  */
22
22
  export declare function validateBranchName(value: string, source: string): string;
23
+ /**
24
+ * Best-effort validation for an auto-detected branch (from git). Returns the
25
+ * trimmed name, or `undefined` for anything unusable so callers fall back to
26
+ * the next precedence tier or leave the index unlabeled. Swallows
27
+ * {@link InvalidBranchError} only; unexpected errors are rethrown.
28
+ */
29
+ export declare function sanitizeDetectedBranch(value: string | null | undefined): string | undefined;
30
+ /**
31
+ * Render a rejected checkout name for `onLog`. Hidden / bidi / control code
32
+ * points become `\uXXXX` so a git-legal U+202E name cannot reverse the
33
+ * warning in a terminal. C1 controls (U+0080–U+009F, including NEL U+0085)
34
+ * and remaining Unicode whitespace (`/\s/` — NBSP, U+2028/U+2029, ideographic
35
+ * space, etc.) are not all in {@link isHiddenOrControl}; escape them the same
36
+ * way so the ASCII escape survives `stripControlCharacters` and the warning
37
+ * stays one line. ASCII `"` is escaped; other characters (including backticks)
38
+ * stay visible.
39
+ */
40
+ export declare function formatRejectedBranchForLog(value: string): string;
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Git ref-name validation used by both the CLI and the HTTP analyze route.
3
3
  *
4
- * Lives in `core/` so `server/api.ts` does not import `cli/analyze-config`
5
- * (that import closed a cli → server → cli cycle: `cli/serve.ts` already
6
- * imports `createServer`). The CLI keeps a thin wrapper that rethrows
7
- * {@link InvalidBranchError} as `GitNexusRcError`.
4
+ * Lives in `core/` so `server/api.ts` and `run-analyze.ts` do not import
5
+ * `cli/analyze-config` (that import closed a cli → server → cli cycle:
6
+ * `cli/serve.ts` already imports `createServer`). The CLI keeps a thin
7
+ * wrapper that rethrows {@link InvalidBranchError} as `GitNexusRcError`.
8
8
  */
9
9
  /** Git refs longer than this are almost certainly a mistake / injection attempt. */
10
10
  const BRANCH_MAX_LENGTH = 255;
@@ -112,3 +112,48 @@ export function validateBranchName(value, source) {
112
112
  }
113
113
  return trimmed;
114
114
  }
115
+ /**
116
+ * Best-effort validation for an auto-detected branch (from git). Returns the
117
+ * trimmed name, or `undefined` for anything unusable so callers fall back to
118
+ * the next precedence tier or leave the index unlabeled. Swallows
119
+ * {@link InvalidBranchError} only; unexpected errors are rethrown.
120
+ */
121
+ export function sanitizeDetectedBranch(value) {
122
+ if (!value)
123
+ return undefined;
124
+ try {
125
+ return validateBranchName(value, 'detected branch');
126
+ }
127
+ catch (err) {
128
+ if (err instanceof InvalidBranchError)
129
+ return undefined;
130
+ throw err;
131
+ }
132
+ }
133
+ /**
134
+ * Render a rejected checkout name for `onLog`. Hidden / bidi / control code
135
+ * points become `\uXXXX` so a git-legal U+202E name cannot reverse the
136
+ * warning in a terminal. C1 controls (U+0080–U+009F, including NEL U+0085)
137
+ * and remaining Unicode whitespace (`/\s/` — NBSP, U+2028/U+2029, ideographic
138
+ * space, etc.) are not all in {@link isHiddenOrControl}; escape them the same
139
+ * way so the ASCII escape survives `stripControlCharacters` and the warning
140
+ * stays one line. ASCII `"` is escaped; other characters (including backticks)
141
+ * stay visible.
142
+ */
143
+ export function formatRejectedBranchForLog(value) {
144
+ const shouldEscapeRejectedBranchChar = (cp, ch) => isHiddenOrControl(cp) || (cp >= 0x80 && cp <= 0x9f) || /\s/.test(ch);
145
+ let out = '';
146
+ for (const ch of value) {
147
+ const cp = ch.codePointAt(0);
148
+ if (cp !== undefined && shouldEscapeRejectedBranchChar(cp, ch)) {
149
+ out += `\\u${cp.toString(16).padStart(4, '0')}`;
150
+ continue;
151
+ }
152
+ if (ch === '"') {
153
+ out += '\\"';
154
+ continue;
155
+ }
156
+ out += ch;
157
+ }
158
+ return out;
159
+ }
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { getPhaseOutput } from './types.js';
14
14
  import { processProcesses } from '../process-processor.js';
15
+ import { buildProcessDetectionPhaseConfig, formatWholeFlowsMissingRemedies, processDetectionEffectiveLimits, resolveProcessDetectionBudget, } from '../process-detection-budget.js';
15
16
  import { generateId } from '../../../lib/utils.js';
16
17
  import { routeNodeKey } from '../route-extractors/route-path.js';
17
18
  import { isDev } from '../utils/env.js';
@@ -60,12 +61,24 @@ export const processesPhase = {
60
61
  message: 'Detecting execution flows...',
61
62
  stats: { filesProcessed: totalFiles, totalFiles, nodesCreated: ctx.graph.nodeCount },
62
63
  });
64
+ const resolvedBudget = resolveProcessDetectionBudget({
65
+ maxProcesses: ctx.options?.maxProcesses,
66
+ maxProcessBranching: ctx.options?.maxProcessBranching,
67
+ maxProcessTraceDepth: ctx.options?.maxProcessTraceDepth,
68
+ maxEntryPointCandidates: ctx.options?.maxEntryPointCandidates,
69
+ },
70
+ // Env is resolved in `runFullAnalysis` and threaded on PipelineOptions.
71
+ // The phase reads only those fields so unit tests stay isolated from
72
+ // the host environment.
73
+ {});
63
74
  let symbolCount = 0;
64
- ctx.graph.forEachNode((n) => {
65
- if (n.label !== 'File')
66
- symbolCount++;
67
- });
68
- const dynamicMaxProcesses = computeDynamicMaxProcesses(symbolCount);
75
+ if (resolvedBudget.maxProcesses === undefined) {
76
+ ctx.graph.forEachNode((n) => {
77
+ if (n.label !== 'File')
78
+ symbolCount++;
79
+ });
80
+ }
81
+ const detectionConfig = buildProcessDetectionPhaseConfig(resolvedBudget, symbolCount, computeDynamicMaxProcesses);
69
82
  // R3-6: where the program reaches outward. Already collected by the parse
70
83
  // phase for FILE-level FETCHES/QUERIES edges; reused here at function
71
84
  // granularity so a trace can end somewhere meaningful instead of only at a
@@ -100,7 +113,7 @@ export const processesPhase = {
100
113
  message,
101
114
  stats: { filesProcessed: totalFiles, totalFiles, nodesCreated: ctx.graph.nodeCount },
102
115
  });
103
- }, { maxProcesses: dynamicMaxProcesses, minSteps: 3 }, outwardActionSites);
116
+ }, detectionConfig, outwardActionSites);
104
117
  if (isDev) {
105
118
  logger.info(`🔄 Process detection: ${processResult.stats.totalProcesses} processes found (${processResult.stats.crossCommunityCount} cross-community)`);
106
119
  }
@@ -114,8 +127,8 @@ export const processesPhase = {
114
127
  // "unexplored entry points mean whole flows are missing, while a
115
128
  // depth-capped trace means a flow is present but shorter than it really is"
116
129
  // — and it is what keeps the line worth reading. Warning on every counter
117
- // meant warning on every run: this phase overrides only `maxProcesses`, so
118
- // at the shipped defaults (`maxBranching: 4`, `maxTraceDepth: 10`,
130
+ // meant warning on every run: at the shipped defaults (`maxBranching: 4`,
131
+ // `maxTraceDepth: 10`,
119
132
  // per-entry trace budget 12) `calleesDropped` fires for any function with
120
133
  // five callees, `tracesDepthCapped` for any chain deeper than ten, and
121
134
  // `walksCutByBudget` for any entry point with twelve paths under it. All
@@ -140,6 +153,8 @@ export const processesPhase = {
140
153
  const flowsMissing = truncation.entryPointCandidatesDropped > 0 ||
141
154
  truncation.entryPointsUnexplored > 0 ||
142
155
  truncation.processesDropped > 0;
156
+ const effectiveLimits = processDetectionEffectiveLimits(detectionConfig.maxProcesses, resolvedBudget);
157
+ const remedies = formatWholeFlowsMissingRemedies(truncation, effectiveLimits, entryPointCandidates);
143
158
  const shape = `${truncation.entryPointCandidatesDropped} of ${entryPointCandidates} candidate entry point(s) never ranked in, ` +
144
159
  `${truncation.entryPointsUnexplored} ranked entry point(s) never traced, ` +
145
160
  `${truncation.processesDropped} deduplicated flow(s) dropped at maxProcesses, ` +
@@ -147,11 +162,11 @@ export const processesPhase = {
147
162
  `${truncation.calleesDropped} callee(s) skipped at maxBranching, ` +
148
163
  `${truncation.walksCutByBudget} walk(s) cut by the per-entry trace budget.`;
149
164
  if (flowsMissing) {
150
- logger.warn({ truncation }, `[processes] ${processResult.stats.totalProcesses} flows reported, but whole flows are MISSING: ` +
151
- `${shape} An absent flow does NOT mean the code path does not exist.`);
165
+ logger.warn({ truncation, effectiveLimits }, `[processes] ${processResult.stats.totalProcesses} flows reported, but whole flows are MISSING: ` +
166
+ `${shape}${remedies} An absent flow does NOT mean the code path does not exist.`);
152
167
  }
153
168
  else if (truncation.truncated) {
154
- logger.debug({ truncation }, `[processes] ${processResult.stats.totalProcesses} flows reported; every flow found is present, ` +
169
+ logger.debug({ truncation, effectiveLimits }, `[processes] ${processResult.stats.totalProcesses} flows reported; every flow found is present, ` +
155
170
  `but some are shorter than the code path they describe: ${shape}`);
156
171
  }
157
172
  processResult.processes.forEach((proc) => {
@@ -204,6 +204,15 @@ export interface PipelineOptions {
204
204
  * analyze invocations.
205
205
  */
206
206
  workerPoolSize?: number;
207
+ /**
208
+ * Process-detection budget (#3313). Explicit `maxProcesses` replaces the
209
+ * dynamic `symbols / 10` formula; the other three replace compiled defaults.
210
+ * Unset fields keep shipped behavior. `0` is rejected upstream — not unlimited.
211
+ */
212
+ maxProcesses?: number;
213
+ maxProcessBranching?: number;
214
+ maxProcessTraceDepth?: number;
215
+ maxEntryPointCandidates?: number;
207
216
  /**
208
217
  * Number of chunks whose file contents may be read into memory in
209
218
  * parallel while the worker pool is busy dispatching the current
@@ -136,8 +136,8 @@ export const runPipelineFromRepo = async (repoPath, onProgress, options) => {
136
136
  const pdgEmitManifest = scopeResolutionOutput.pdgEmitManifest;
137
137
  const propertyInference = scopeResolutionOutput.propertyInference;
138
138
  // Presence check, not `!skipGraphPhases`: phases can now be filtered out by
139
- // any `enabledWhen` predicate (streamGraphEmit disables communities/processes
140
- // too), and `getPhaseOutput` THROWS on a phase that was never resolved. Keying
139
+ // any `enabledWhen` predicate (`skipGraphPhases` drops communities/processes),
140
+ // and `getPhaseOutput` THROWS on a phase that was never resolved. Keying
141
141
  // off the options flag alone made every filtered-out combination crash here
142
142
  // rather than return undefined results.
143
143
  if (results.has('communities') && results.has('processes')) {