gitnexus 1.6.6-rc.42 → 1.6.6-rc.44
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 +2 -0
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +30 -1
- package/dist/cli/clean.d.ts +1 -0
- package/dist/cli/clean.js +39 -9
- package/dist/cli/cli-message.d.ts +33 -3
- package/dist/cli/cli-message.js +14 -0
- package/dist/cli/detect-changes-format.d.ts +1 -0
- package/dist/cli/detect-changes-format.js +45 -0
- package/dist/cli/doctor.d.ts +2 -0
- package/dist/cli/doctor.js +59 -20
- package/dist/cli/eval-server.d.ts +1 -1
- package/dist/cli/eval-server.js +2 -31
- package/dist/cli/help-i18n.d.ts +2 -0
- package/dist/cli/help-i18n.js +198 -0
- package/dist/cli/i18n/en.d.ts +206 -0
- package/dist/cli/i18n/en.js +206 -0
- package/dist/cli/i18n/index.d.ts +9 -0
- package/dist/cli/i18n/index.js +41 -0
- package/dist/cli/i18n/resources.d.ts +414 -0
- package/dist/cli/i18n/resources.js +6 -0
- package/dist/cli/i18n/zh-CN.d.ts +206 -0
- package/dist/cli/i18n/zh-CN.js +206 -0
- package/dist/cli/index.js +7 -14
- package/dist/cli/list.js +15 -10
- package/dist/cli/remove.js +12 -11
- package/dist/cli/serve.js +4 -13
- package/dist/cli/status.js +11 -10
- package/dist/cli/tool.js +7 -39
- package/dist/core/lbug/lbug-adapter.d.ts +15 -0
- package/dist/core/lbug/lbug-adapter.js +21 -0
- package/dist/core/lbug/lbug-config.d.ts +7 -0
- package/dist/core/lbug/lbug-config.js +82 -2
- package/dist/core/lbug/wal-checkpoint-driver.d.ts +98 -0
- package/dist/core/lbug/wal-checkpoint-driver.js +189 -0
- package/dist/core/run-analyze.js +21 -1
- package/package.json +1 -1
- package/web/assets/{agent-CBcds30d.js → agent-CNGl256w.js} +1 -1
- package/web/assets/{architectureDiagram-UL44E2DR-dIoPPr6x.js → architectureDiagram-UL44E2DR-DJTnN4-A.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-B8hbjKUm.js → chunk-LCXTWHL2-D6tMtD_-.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-EfsAenro.js → chunk-RG4AUYOV-C3CY7gW4.js} +1 -1
- package/web/assets/{classDiagram-KGZ6W3CR-_hSUwNQJ.js → classDiagram-KGZ6W3CR-COdiqi1G.js} +1 -1
- package/web/assets/{classDiagram-v2-72OJOZXJ-C0NcgLqj.js → classDiagram-v2-72OJOZXJ-B7YiUGDv.js} +1 -1
- package/web/assets/{diagram-3NCE3AQN-CYrNJJUh.js → diagram-3NCE3AQN-aSkD3QID.js} +1 -1
- package/web/assets/{diagram-GF46GFSD-56NpS1jw.js → diagram-GF46GFSD-DlsGDkUv.js} +1 -1
- package/web/assets/{diagram-QXG6HAR7-DwXkFq_r.js → diagram-QXG6HAR7-NPw8jZAE.js} +1 -1
- package/web/assets/{diagram-WEQXMOUZ-C6BTq9za.js → diagram-WEQXMOUZ-CsLi0zm5.js} +1 -1
- package/web/assets/{erDiagram-L5TCEMPS-BcEjYsUQ.js → erDiagram-L5TCEMPS-cjritYTk.js} +1 -1
- package/web/assets/{flowDiagram-H6V6AXG4-DWAVIV6V.js → flowDiagram-H6V6AXG4-hAr62LB-.js} +1 -1
- package/web/assets/index-BeHwDjNI.css +2 -0
- package/web/assets/index-Cj2GDX22.js +626 -0
- package/web/assets/{infoDiagram-3YFTVSEB-ui-e52GZ.js → infoDiagram-3YFTVSEB-_sF9KVQz.js} +1 -1
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-DGimV4zg.js → ishikawaDiagram-BNXS4ZKH-BtwawoWC.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-BOyfgvKL.js → kanban-definition-75IXJCU3-CljJPOuK.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-Ba3QrYSU.js → mindmap-definition-2TDM6QVE-DsqPS_X-.js} +1 -1
- package/web/assets/{pieDiagram-CU6KROY3-DMFBXNrM.js → pieDiagram-CU6KROY3-CTUDdOgg.js} +1 -1
- package/web/assets/{requirementDiagram-JXO7QTGE-bS4xboSz.js → requirementDiagram-JXO7QTGE-DM8hDKq-.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-BqKET_2i.js → sequenceDiagram-VS2MUI6T-m6_R47U2.js} +1 -1
- package/web/assets/{stateDiagram-7D4R322I-DP9kvX2i.js → stateDiagram-7D4R322I-Cc1HvF6o.js} +1 -1
- package/web/assets/{stateDiagram-v2-36443NZ5-DB-cZ1VL.js → stateDiagram-v2-36443NZ5-Kw9j23FO.js} +1 -1
- package/web/assets/{timeline-definition-O6YCAMPW-DNScSOi7.js → timeline-definition-O6YCAMPW-BtENAtHS.js} +1 -1
- package/web/assets/{vennDiagram-MWXL3ELB-Bd1zTNWW.js → vennDiagram-MWXL3ELB-DYHpZsEN.js} +1 -1
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DqCDQKFt.js → wardleyDiagram-CUQ6CDDI-BNPunZ-h.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-B8Cje_Ei.js → xychartDiagram-N2JHSOCM-BGBiR7xJ.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-Czp-OFT-.js +0 -624
- package/web/assets/index-nSZgUaIx.css +0 -2
package/README.md
CHANGED
|
@@ -158,6 +158,7 @@ gitnexus analyze --skip-agents-md # Preserve custom AGENTS.md/CLAUDE.md gitnexu
|
|
|
158
158
|
gitnexus analyze --verbose # Log skipped files when parsers are unavailable
|
|
159
159
|
gitnexus analyze --max-file-size 1024 # Skip files larger than N KB (default: 512, cap: 32768)
|
|
160
160
|
gitnexus analyze --worker-timeout 60 # Increase worker idle timeout for slow parses
|
|
161
|
+
gitnexus analyze --wal-checkpoint-threshold 67108864 # 64 MiB. Control LadybugDB WAL auto-checkpoint threshold (default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB)
|
|
161
162
|
gitnexus mcp # Start MCP server (stdio) — serves all indexed repos
|
|
162
163
|
gitnexus serve # Start local HTTP server (multi-repo) for web UI
|
|
163
164
|
gitnexus index # Register an existing .gitnexus/ folder into the global registry
|
|
@@ -307,6 +308,7 @@ Configure the behavior with two environment variables:
|
|
|
307
308
|
|----------|--------|---------|--------|
|
|
308
309
|
| `GITNEXUS_LBUG_EXTENSION_INSTALL` | `auto`, `load-only`, `never` | `auto` | `auto` runs one bounded INSTALL if LOAD fails. `load-only` only uses already-installed extensions (recommended for offline / firewalled environments). `never` skips optional extensions entirely. |
|
|
309
310
|
| `GITNEXUS_LBUG_EXTENSION_INSTALL_TIMEOUT_MS` | positive integer | `15000` | Wall-clock budget for the out-of-process `INSTALL` child before it is killed. |
|
|
311
|
+
| `GITNEXUS_WAL_CHECKPOINT_THRESHOLD` | integer `>= -1` | `67108864` (64 MiB) | LadybugDB WAL auto-checkpoint threshold during analyze (bytes). Auto-checkpoint remains enabled; `-1` keeps Ladybug's stock ~16 MiB. Larger thresholds reduce checkpoint frequency but increase the WAL size at rotation time — choose a smaller value on disk-constrained environments. |
|
|
310
312
|
|
|
311
313
|
```bash
|
|
312
314
|
# Offline/airgapped: never reach the network for extensions
|
package/dist/cli/analyze.d.ts
CHANGED
|
@@ -69,6 +69,8 @@ export interface AnalyzeOptions {
|
|
|
69
69
|
maxFileSize?: string;
|
|
70
70
|
/** Override worker sub-batch idle timeout in seconds. */
|
|
71
71
|
workerTimeout?: string;
|
|
72
|
+
/** Control LadybugDB WAL auto-checkpoint threshold during analyze. */
|
|
73
|
+
walCheckpointThreshold?: string;
|
|
72
74
|
/** Parse worker pool size; 0 disables workers (sequential fallback). */
|
|
73
75
|
workers?: string;
|
|
74
76
|
embeddingThreads?: string;
|
package/dist/cli/analyze.js
CHANGED
|
@@ -12,7 +12,7 @@ import { spawn } from 'child_process';
|
|
|
12
12
|
import v8 from 'v8';
|
|
13
13
|
import cliProgress from 'cli-progress';
|
|
14
14
|
import { closeLbug } from '../core/lbug/lbug-adapter.js';
|
|
15
|
-
import { isWalCorruptionError, WAL_RECOVERY_SUGGESTION } from '../core/lbug/lbug-config.js';
|
|
15
|
+
import { isLbugCheckpointIoError, isWalCorruptionError, parseWalCheckpointThreshold, WAL_RECOVERY_SUGGESTION, } from '../core/lbug/lbug-config.js';
|
|
16
16
|
import { getStoragePaths, getGlobalRegistryPath, RegistryNameCollisionError, AnalysisNotFinalizedError, assertAnalysisFinalized, } from '../storage/repo-manager.js';
|
|
17
17
|
import { getGitRoot, hasGitDir } from '../storage/git.js';
|
|
18
18
|
import { runFullAnalysis } from '../core/run-analyze.js';
|
|
@@ -322,6 +322,14 @@ const forceHeapOOMForTestIfEnabled = () => {
|
|
|
322
322
|
for (;;)
|
|
323
323
|
chunks.push('x'.repeat(1024 * 1024));
|
|
324
324
|
};
|
|
325
|
+
// 64 MiB keeps auto-checkpoint enabled but triggers less frequently than
|
|
326
|
+
// Ladybug's stock ~16 MiB threshold, reducing rename/remove churn on large
|
|
327
|
+
// runs. Also matches the GitNexus default in `lbug-config.ts`.
|
|
328
|
+
//
|
|
329
|
+
// IMPORTANT: keep README examples (`README.md`, `gitnexus/README.md`) and
|
|
330
|
+
// the `DEFAULT_WAL_CHECKPOINT_THRESHOLD` constant in
|
|
331
|
+
// `gitnexus/src/core/lbug/lbug-config.ts` in sync with this value.
|
|
332
|
+
const RECOMMENDED_WAL_CHECKPOINT_THRESHOLD = 64 * 1024 * 1024;
|
|
325
333
|
/** Re-exec the process with a 16GB heap and larger stack if we're currently below that. */
|
|
326
334
|
async function ensureHeap() {
|
|
327
335
|
const nodeOpts = process.env.NODE_OPTIONS || '';
|
|
@@ -378,6 +386,8 @@ const ANALYZE_CLI_ENV_KEYS = [
|
|
|
378
386
|
'GITNEXUS_PROFILE_DEFERRED_SLOW_MS',
|
|
379
387
|
'GITNEXUS_MAX_FILE_SIZE',
|
|
380
388
|
'GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS',
|
|
389
|
+
'GITNEXUS_WAL_CHECKPOINT_THRESHOLD',
|
|
390
|
+
'GITNEXUS_WAL_MANUAL_CHECKPOINT',
|
|
381
391
|
'GITNEXUS_EMBEDDING_THREADS',
|
|
382
392
|
'GITNEXUS_EMBEDDING_BATCH_SIZE',
|
|
383
393
|
'GITNEXUS_EMBEDDING_SUB_BATCH_SIZE',
|
|
@@ -452,6 +462,15 @@ const analyzeCommandImpl = async (inputPath, options) => {
|
|
|
452
462
|
}
|
|
453
463
|
process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS = String(Math.round(workerTimeoutSeconds * 1000));
|
|
454
464
|
}
|
|
465
|
+
if (options?.walCheckpointThreshold !== undefined) {
|
|
466
|
+
const parsed = parseWalCheckpointThreshold(options.walCheckpointThreshold);
|
|
467
|
+
if (parsed === undefined) {
|
|
468
|
+
cliError(' --wal-checkpoint-threshold must be an integer >= -1.\n');
|
|
469
|
+
process.exitCode = 1;
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
process.env.GITNEXUS_WAL_CHECKPOINT_THRESHOLD = String(parsed);
|
|
473
|
+
}
|
|
455
474
|
// `--workers` is threaded through `runFullAnalysis` options → PipelineOptions
|
|
456
475
|
// → createWorkerPool, intentionally bypassing the GITNEXUS_WORKER_POOL_SIZE
|
|
457
476
|
// env channel so this CLI surface never mutates `process.env` for pool size.
|
|
@@ -859,6 +878,16 @@ const analyzeCommandImpl = async (inputPath, options) => {
|
|
|
859
878
|
process.exitCode = 1;
|
|
860
879
|
return;
|
|
861
880
|
}
|
|
881
|
+
if (isLbugCheckpointIoError(err)) {
|
|
882
|
+
cliError(` LadybugDB failed while rotating/removing WAL checkpoint files.\n` +
|
|
883
|
+
` This can happen when auto-checkpoint runs at the default threshold (~16MB).\n` +
|
|
884
|
+
` Retry with a larger checkpoint threshold to reduce checkpoint frequency:\n` +
|
|
885
|
+
` gitnexus analyze --wal-checkpoint-threshold ${RECOMMENDED_WAL_CHECKPOINT_THRESHOLD}\n` +
|
|
886
|
+
` (or set GITNEXUS_WAL_CHECKPOINT_THRESHOLD=${RECOMMENDED_WAL_CHECKPOINT_THRESHOLD})\n` +
|
|
887
|
+
` (Try 33554432 = 32 MiB on small-disk / CI runners.)\n`, { recoveryHint: 'wal-checkpoint-threshold' });
|
|
888
|
+
process.exitCode = 1;
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
862
891
|
// HF download failure — show clean guidance without the raw stack trace.
|
|
863
892
|
// Checked before writeFatalToStderr so the user sees one focused message
|
|
864
893
|
// rather than a stack-trace dump followed by a second remediation block.
|
package/dist/cli/clean.d.ts
CHANGED
package/dist/cli/clean.js
CHANGED
|
@@ -5,22 +5,52 @@
|
|
|
5
5
|
* Also unregisters it from the global registry.
|
|
6
6
|
*/
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
8
9
|
import { logger } from '../core/logger.js';
|
|
9
10
|
import { findRepo, unregisterRepo, listRegisteredRepos, assertSafeStoragePath, UnsafeStoragePathError, } from '../storage/repo-manager.js';
|
|
11
|
+
import { cleanQuarantinedMissingShadowWals, inspectLbugSidecars, listQuarantinedMissingShadowWals, } from '../core/lbug/sidecar-recovery.js';
|
|
12
|
+
import { t } from './i18n/index.js';
|
|
10
13
|
export const cleanCommand = async (options) => {
|
|
14
|
+
if (options?.lbugSidecars) {
|
|
15
|
+
const cwd = process.cwd();
|
|
16
|
+
const repo = await findRepo(cwd);
|
|
17
|
+
if (!repo) {
|
|
18
|
+
console.log(t('clean.notFoundHere'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const lbugPath = path.join(repo.storagePath, 'lbug');
|
|
22
|
+
const state = await inspectLbugSidecars(lbugPath);
|
|
23
|
+
const quarantined = await listQuarantinedMissingShadowWals(lbugPath);
|
|
24
|
+
console.log(t('clean.lbugSidecars.state', { state: state.kind }));
|
|
25
|
+
if (quarantined.length === 0) {
|
|
26
|
+
console.log(t('clean.lbugSidecars.none'));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!options.force) {
|
|
30
|
+
console.log(t('clean.lbugSidecars.preview', { count: quarantined.length }));
|
|
31
|
+
for (const file of quarantined) {
|
|
32
|
+
console.log(` - ${file}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const deleted = await cleanQuarantinedMissingShadowWals(lbugPath);
|
|
38
|
+
console.log(t('clean.lbugSidecars.deleted', { count: deleted.length }));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
11
41
|
// --all flag: clean all indexed repos
|
|
12
42
|
if (options?.all) {
|
|
13
43
|
if (!options?.force) {
|
|
14
44
|
const entries = await listRegisteredRepos();
|
|
15
45
|
if (entries.length === 0) {
|
|
16
|
-
console.log('
|
|
46
|
+
console.log(t('common.notIndexed'));
|
|
17
47
|
return;
|
|
18
48
|
}
|
|
19
|
-
console.log(
|
|
49
|
+
console.log(t('clean.deleteAll', { count: entries.length }));
|
|
20
50
|
for (const entry of entries) {
|
|
21
51
|
console.log(` - ${entry.name} (${entry.path})`);
|
|
22
52
|
}
|
|
23
|
-
console.log('
|
|
53
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
24
54
|
return;
|
|
25
55
|
}
|
|
26
56
|
const entries = await listRegisteredRepos();
|
|
@@ -46,7 +76,7 @@ export const cleanCommand = async (options) => {
|
|
|
46
76
|
try {
|
|
47
77
|
await fs.rm(entry.storagePath, { recursive: true, force: true });
|
|
48
78
|
await unregisterRepo(entry.path);
|
|
49
|
-
console.log(
|
|
79
|
+
console.log(t('clean.deletedRepo', { name: entry.name, storagePath: entry.storagePath }));
|
|
50
80
|
}
|
|
51
81
|
catch (err) {
|
|
52
82
|
logger.error({ err }, `Failed to delete ${entry.name}:`);
|
|
@@ -58,20 +88,20 @@ export const cleanCommand = async (options) => {
|
|
|
58
88
|
const cwd = process.cwd();
|
|
59
89
|
const repo = await findRepo(cwd);
|
|
60
90
|
if (!repo) {
|
|
61
|
-
console.log('
|
|
91
|
+
console.log(t('clean.notFoundHere'));
|
|
62
92
|
return;
|
|
63
93
|
}
|
|
64
94
|
const repoName = repo.repoPath.split(/[/\\]/).pop() || repo.repoPath;
|
|
65
95
|
if (!options?.force) {
|
|
66
|
-
console.log(
|
|
67
|
-
console.log(`
|
|
68
|
-
console.log('
|
|
96
|
+
console.log(t('clean.deleteCurrent', { repoName }));
|
|
97
|
+
console.log(` ${t('common.path')}: ${repo.storagePath}`);
|
|
98
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
69
99
|
return;
|
|
70
100
|
}
|
|
71
101
|
try {
|
|
72
102
|
await fs.rm(repo.storagePath, { recursive: true, force: true });
|
|
73
103
|
await unregisterRepo(repo.repoPath);
|
|
74
|
-
console.log(
|
|
104
|
+
console.log(t('common.deleted', { target: repo.storagePath }));
|
|
75
105
|
}
|
|
76
106
|
catch (err) {
|
|
77
107
|
logger.error({ err }, 'Failed to delete:');
|
|
@@ -1,15 +1,45 @@
|
|
|
1
|
+
import { type CliMessageKey, type CliMessageVars } from './i18n/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* String-literal union of all `recoveryHint` tags emitted by the CLI.
|
|
4
|
+
*
|
|
5
|
+
* Centralized so a new recovery branch added in `analyze.ts` cannot land
|
|
6
|
+
* without updating this union — TypeScript will reject the unknown literal
|
|
7
|
+
* passed via `cliError({ recoveryHint: '...' })`. To add a new hint:
|
|
8
|
+
* 1. Add the tag string to this union.
|
|
9
|
+
* 2. Pass it as the `recoveryHint` field at the relevant `cliError`
|
|
10
|
+
* call site.
|
|
11
|
+
*
|
|
12
|
+
* Consumers can import this type to narrow log-record `recoveryHint`
|
|
13
|
+
* fields without restating the literal list.
|
|
14
|
+
*/
|
|
15
|
+
export type RecoveryHint = 'wal-corruption' | 'wal-checkpoint-threshold' | 'heap-oom-respawn' | 'native-worker-abort' | 'hf-endpoint-unreachable' | 'large-repo' | 'npm-resolution' | 'module-not-found';
|
|
16
|
+
/**
|
|
17
|
+
* Common shape for the optional structured-field bag passed to
|
|
18
|
+
* `cliError`/`cliWarn`/`cliInfo`. Typed so the `recoveryHint` slot is
|
|
19
|
+
* checked against the {@link RecoveryHint} union.
|
|
20
|
+
*/
|
|
21
|
+
export interface CliMessageFields extends Record<string, unknown> {
|
|
22
|
+
recoveryHint?: RecoveryHint;
|
|
23
|
+
}
|
|
1
24
|
/**
|
|
2
25
|
* User-facing informational message. Use for banners, listening URLs,
|
|
3
26
|
* and any message the user expects to read in plain text.
|
|
4
27
|
*/
|
|
5
|
-
export declare function cliInfo(msg: string, fields?:
|
|
28
|
+
export declare function cliInfo(msg: string, fields?: CliMessageFields): void;
|
|
29
|
+
/**
|
|
30
|
+
* Key-based informational message. Keeps the legacy string API intact while
|
|
31
|
+
* allowing commands to opt into localized user-facing stderr output.
|
|
32
|
+
*/
|
|
33
|
+
export declare function cliInfoKey(key: CliMessageKey, vars?: CliMessageVars, fields?: Record<string, unknown>): void;
|
|
6
34
|
/**
|
|
7
35
|
* User-facing warning. Operator-actionable but non-fatal — `cliWarn`
|
|
8
36
|
* indicates the command can still proceed in some form.
|
|
9
37
|
*/
|
|
10
|
-
export declare function cliWarn(msg: string, fields?:
|
|
38
|
+
export declare function cliWarn(msg: string, fields?: CliMessageFields): void;
|
|
39
|
+
export declare function cliWarnKey(key: CliMessageKey, vars?: CliMessageVars, fields?: Record<string, unknown>): void;
|
|
11
40
|
/**
|
|
12
41
|
* User-facing error. Indicates the command cannot proceed; usually
|
|
13
42
|
* paired with a non-zero exit code at the call site.
|
|
14
43
|
*/
|
|
15
|
-
export declare function cliError(msg: string, fields?:
|
|
44
|
+
export declare function cliError(msg: string, fields?: CliMessageFields): void;
|
|
45
|
+
export declare function cliErrorKey(key: CliMessageKey, vars?: CliMessageVars, fields?: Record<string, unknown>): void;
|
package/dist/cli/cli-message.js
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* stdout would corrupt that pipeline.
|
|
29
29
|
*/
|
|
30
30
|
import { logger } from '../core/logger.js';
|
|
31
|
+
import { t } from './i18n/index.js';
|
|
31
32
|
function writeStderr(msg) {
|
|
32
33
|
// Direct write — bypassing `console.*` so it cannot be intercepted by
|
|
33
34
|
// progress-bar redirection (see `cli/analyze.ts:barLog`) or other
|
|
@@ -43,6 +44,13 @@ export function cliInfo(msg, fields) {
|
|
|
43
44
|
writeStderr(msg);
|
|
44
45
|
logger.info(fields ?? {}, msg);
|
|
45
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Key-based informational message. Keeps the legacy string API intact while
|
|
49
|
+
* allowing commands to opt into localized user-facing stderr output.
|
|
50
|
+
*/
|
|
51
|
+
export function cliInfoKey(key, vars, fields) {
|
|
52
|
+
cliInfo(t(key, vars), fields);
|
|
53
|
+
}
|
|
46
54
|
/**
|
|
47
55
|
* User-facing warning. Operator-actionable but non-fatal — `cliWarn`
|
|
48
56
|
* indicates the command can still proceed in some form.
|
|
@@ -51,6 +59,9 @@ export function cliWarn(msg, fields) {
|
|
|
51
59
|
writeStderr(msg);
|
|
52
60
|
logger.warn(fields ?? {}, msg);
|
|
53
61
|
}
|
|
62
|
+
export function cliWarnKey(key, vars, fields) {
|
|
63
|
+
cliWarn(t(key, vars), fields);
|
|
64
|
+
}
|
|
54
65
|
/**
|
|
55
66
|
* User-facing error. Indicates the command cannot proceed; usually
|
|
56
67
|
* paired with a non-zero exit code at the call site.
|
|
@@ -59,3 +70,6 @@ export function cliError(msg, fields) {
|
|
|
59
70
|
writeStderr(msg);
|
|
60
71
|
logger.error(fields ?? {}, msg);
|
|
61
72
|
}
|
|
73
|
+
export function cliErrorKey(key, vars, fields) {
|
|
74
|
+
cliError(t(key, vars), fields);
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatDetectChangesResult(result: unknown): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { t } from './i18n/index.js';
|
|
2
|
+
export function formatDetectChangesResult(result) {
|
|
3
|
+
const payload = (result ?? {});
|
|
4
|
+
if (payload.error)
|
|
5
|
+
return t('common.error', { message: String(payload.error) });
|
|
6
|
+
const summary = payload.summary ?? {};
|
|
7
|
+
if ((summary.changed_count ?? 0) === 0) {
|
|
8
|
+
return t('tool.detectChanges.noChanges');
|
|
9
|
+
}
|
|
10
|
+
const lines = [];
|
|
11
|
+
lines.push(t('tool.detectChanges.changesSummary', {
|
|
12
|
+
files: summary.changed_files ?? 0,
|
|
13
|
+
symbols: summary.changed_count ?? 0,
|
|
14
|
+
}));
|
|
15
|
+
lines.push(t('tool.detectChanges.affectedProcesses', { count: summary.affected_count ?? 0 }));
|
|
16
|
+
lines.push(t('tool.detectChanges.riskLevel', {
|
|
17
|
+
risk: summary.risk_level || t('tool.detectChanges.unknownRisk'),
|
|
18
|
+
}));
|
|
19
|
+
lines.push('');
|
|
20
|
+
const changed = Array.isArray(payload.changed_symbols) ? payload.changed_symbols : [];
|
|
21
|
+
if (changed.length > 0) {
|
|
22
|
+
lines.push(t('tool.detectChanges.changedSymbols'));
|
|
23
|
+
for (const symbol of changed.slice(0, 15)) {
|
|
24
|
+
lines.push(` ${symbol.type ?? 'Symbol'} ${symbol.name ?? '?'} → ${symbol.filePath ?? '?'}`);
|
|
25
|
+
}
|
|
26
|
+
if (changed.length > 15) {
|
|
27
|
+
lines.push(t('tool.detectChanges.overflowMore', { count: changed.length - 15 }));
|
|
28
|
+
}
|
|
29
|
+
lines.push('');
|
|
30
|
+
}
|
|
31
|
+
const affected = Array.isArray(payload.affected_processes) ? payload.affected_processes : [];
|
|
32
|
+
if (affected.length > 0) {
|
|
33
|
+
lines.push(t('tool.detectChanges.affectedExecutionFlows'));
|
|
34
|
+
for (const processInfo of affected.slice(0, 10)) {
|
|
35
|
+
const changedSteps = Array.isArray(processInfo.changed_steps)
|
|
36
|
+
? processInfo.changed_steps
|
|
37
|
+
: [];
|
|
38
|
+
const steps = changedSteps.map((step) => step.symbol ?? '?').join(', ');
|
|
39
|
+
lines.push(` • ${processInfo.name ?? '?'} (${t('tool.detectChanges.steps', {
|
|
40
|
+
count: processInfo.step_count ?? 0,
|
|
41
|
+
})}) — ${t('tool.detectChanges.changedSteps', { steps })}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return lines.join('\n').trim();
|
|
45
|
+
}
|
package/dist/cli/doctor.d.ts
CHANGED
package/dist/cli/doctor.js
CHANGED
|
@@ -1,31 +1,70 @@
|
|
|
1
1
|
import { getRuntimeCapabilities, getRuntimeFingerprint } from '../core/platform/capabilities.js';
|
|
2
2
|
import { resolveEmbeddingConfig } from '../core/embeddings/config.js';
|
|
3
3
|
import { isHttpMode } from '../core/embeddings/http-client.js';
|
|
4
|
+
import { t } from './i18n/index.js';
|
|
5
|
+
function isCombiningMark(codePoint) {
|
|
6
|
+
return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
|
|
7
|
+
(codePoint >= 0x1ab0 && codePoint <= 0x1aff) ||
|
|
8
|
+
(codePoint >= 0x1dc0 && codePoint <= 0x1dff) ||
|
|
9
|
+
(codePoint >= 0x20d0 && codePoint <= 0x20ff) ||
|
|
10
|
+
(codePoint >= 0xfe20 && codePoint <= 0xfe2f));
|
|
11
|
+
}
|
|
12
|
+
function isWideCodePoint(codePoint) {
|
|
13
|
+
return ((codePoint >= 0x1100 && codePoint <= 0x115f) ||
|
|
14
|
+
codePoint === 0x2329 ||
|
|
15
|
+
codePoint === 0x232a ||
|
|
16
|
+
(codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
|
|
17
|
+
(codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
|
|
18
|
+
(codePoint >= 0xf900 && codePoint <= 0xfaff) ||
|
|
19
|
+
(codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
|
|
20
|
+
(codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
|
|
21
|
+
(codePoint >= 0xff00 && codePoint <= 0xff60) ||
|
|
22
|
+
(codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
|
|
23
|
+
(codePoint >= 0x1f300 && codePoint <= 0x1f64f) ||
|
|
24
|
+
(codePoint >= 0x1f900 && codePoint <= 0x1f9ff) ||
|
|
25
|
+
(codePoint >= 0x20000 && codePoint <= 0x3fffd));
|
|
26
|
+
}
|
|
27
|
+
export function displayWidth(value) {
|
|
28
|
+
let width = 0;
|
|
29
|
+
for (const char of value) {
|
|
30
|
+
const codePoint = char.codePointAt(0);
|
|
31
|
+
if (codePoint === undefined || codePoint === 0)
|
|
32
|
+
continue;
|
|
33
|
+
if (isCombiningMark(codePoint))
|
|
34
|
+
continue;
|
|
35
|
+
width += isWideCodePoint(codePoint) ? 2 : 1;
|
|
36
|
+
}
|
|
37
|
+
return width;
|
|
38
|
+
}
|
|
39
|
+
export function padDisplayEnd(value, columns) {
|
|
40
|
+
return value + ' '.repeat(Math.max(0, columns - displayWidth(value)));
|
|
41
|
+
}
|
|
42
|
+
const label = (key, width) => padDisplayEnd(t(key), width);
|
|
4
43
|
export const doctorCommand = async () => {
|
|
5
44
|
const fingerprint = getRuntimeFingerprint();
|
|
6
45
|
const capabilities = getRuntimeCapabilities();
|
|
7
46
|
const embeddingConfig = resolveEmbeddingConfig();
|
|
8
|
-
console.log('
|
|
9
|
-
console.log('
|
|
10
|
-
console.log(`
|
|
11
|
-
console.log(`
|
|
12
|
-
console.log(`
|
|
13
|
-
console.log(`
|
|
14
|
-
console.log(`
|
|
47
|
+
console.log(t('doctor.title') + '\n');
|
|
48
|
+
console.log(t('doctor.runtime'));
|
|
49
|
+
console.log(` ${label('doctor.labels.os', 10)}${fingerprint.platform}/${fingerprint.arch}`);
|
|
50
|
+
console.log(` ${label('doctor.labels.node', 10)}${fingerprint.node}`);
|
|
51
|
+
console.log(` ${label('doctor.labels.gitnexus', 10)}${fingerprint.gitnexus}`);
|
|
52
|
+
console.log(` ${label('doctor.labels.ladybugdb', 10)}${fingerprint.ladybugdb ?? 'unknown'}`);
|
|
53
|
+
console.log(` ${label('doctor.labels.onnx', 10)}${fingerprint.onnxruntime ?? 'unknown'}`);
|
|
15
54
|
console.log('');
|
|
16
|
-
console.log('
|
|
17
|
-
console.log(`
|
|
18
|
-
console.log(`
|
|
19
|
-
console.log(`
|
|
20
|
-
console.log(`
|
|
21
|
-
console.log(`
|
|
55
|
+
console.log(t('doctor.capabilities'));
|
|
56
|
+
console.log(` ${label('doctor.labels.graphStore', 18)}${capabilities.graph}`);
|
|
57
|
+
console.log(` ${label('doctor.labels.fullTextSearch', 18)}${capabilities.fts}`);
|
|
58
|
+
console.log(` ${label('doctor.labels.vectorIndex', 18)}${capabilities.vector}`);
|
|
59
|
+
console.log(` ${label('doctor.labels.semanticMode', 18)}${capabilities.semanticMode}`);
|
|
60
|
+
console.log(` ${label('doctor.labels.exactScanLimit', 18)}${t('doctor.chunks', { count: capabilities.exactScanLimit })}`);
|
|
22
61
|
if (capabilities.reason)
|
|
23
|
-
console.log(`
|
|
62
|
+
console.log(` ${label('doctor.labels.note', 18)}${capabilities.reason}`);
|
|
24
63
|
console.log('');
|
|
25
|
-
console.log('
|
|
26
|
-
console.log(`
|
|
27
|
-
console.log(`
|
|
28
|
-
console.log(`
|
|
29
|
-
console.log(`
|
|
30
|
-
console.log(`
|
|
64
|
+
console.log(t('doctor.embeddings'));
|
|
65
|
+
console.log(` ${label('doctor.labels.backend', 12)}${isHttpMode() ? 'http' : 'local'}`);
|
|
66
|
+
console.log(` ${label('doctor.labels.device', 12)}${embeddingConfig.device}`);
|
|
67
|
+
console.log(` ${label('doctor.labels.threads', 12)}${embeddingConfig.threads}`);
|
|
68
|
+
console.log(` ${label('doctor.labels.batch', 12)}${t('doctor.nodes', { count: embeddingConfig.batchSize })}`);
|
|
69
|
+
console.log(` ${label('doctor.labels.subBatch', 12)}${t('doctor.chunks', { count: embeddingConfig.subBatchSize })}`);
|
|
31
70
|
};
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* GET /health — Health check. Returns {"status":"ok","repos":[...]}
|
|
29
29
|
* POST /shutdown — Graceful shutdown.
|
|
30
30
|
*/
|
|
31
|
+
export { formatDetectChangesResult } from './detect-changes-format.js';
|
|
31
32
|
export interface EvalServerOptions {
|
|
32
33
|
port?: string;
|
|
33
34
|
host?: string;
|
|
@@ -44,7 +45,6 @@ export declare function formatQueryResult(result: any): string;
|
|
|
44
45
|
export declare function formatContextResult(result: any): string;
|
|
45
46
|
export declare function formatImpactResult(result: any): string;
|
|
46
47
|
export declare function formatCypherResult(result: any): string;
|
|
47
|
-
export declare function formatDetectChangesResult(result: any): string;
|
|
48
48
|
export declare function formatListReposResult(result: any): string;
|
|
49
49
|
export declare function evalServerCommand(options?: EvalServerOptions): Promise<void>;
|
|
50
50
|
export declare const MAX_BODY_SIZE: number;
|
package/dist/cli/eval-server.js
CHANGED
|
@@ -34,6 +34,8 @@ import { writeSync } from 'node:fs';
|
|
|
34
34
|
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
35
35
|
import { logger } from '../core/logger.js';
|
|
36
36
|
import { cliInfo, cliWarn, cliError } from './cli-message.js';
|
|
37
|
+
import { formatDetectChangesResult } from './detect-changes-format.js';
|
|
38
|
+
export { formatDetectChangesResult } from './detect-changes-format.js';
|
|
37
39
|
/**
|
|
38
40
|
* Validate the --host value. Accepts IPv4, IPv6, or "localhost".
|
|
39
41
|
* Returns the host string unchanged, or null if invalid.
|
|
@@ -204,37 +206,6 @@ export function formatCypherResult(result) {
|
|
|
204
206
|
}
|
|
205
207
|
return typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
206
208
|
}
|
|
207
|
-
export function formatDetectChangesResult(result) {
|
|
208
|
-
if (result.error)
|
|
209
|
-
return `Error: ${result.error}`;
|
|
210
|
-
const summary = result.summary || {};
|
|
211
|
-
const lines = [];
|
|
212
|
-
if (summary.changed_count === 0) {
|
|
213
|
-
return 'No changes detected.';
|
|
214
|
-
}
|
|
215
|
-
lines.push(`Changes: ${summary.changed_files || 0} files, ${summary.changed_count || 0} symbols`);
|
|
216
|
-
lines.push(`Affected processes: ${summary.affected_count || 0}`);
|
|
217
|
-
lines.push(`Risk level: ${summary.risk_level || 'unknown'}\n`);
|
|
218
|
-
const changed = result.changed_symbols || [];
|
|
219
|
-
if (changed.length > 0) {
|
|
220
|
-
lines.push(`Changed symbols:`);
|
|
221
|
-
for (const s of changed.slice(0, 15)) {
|
|
222
|
-
lines.push(` ${s.type} ${s.name} → ${s.filePath}`);
|
|
223
|
-
}
|
|
224
|
-
if (changed.length > 15)
|
|
225
|
-
lines.push(` ... and ${changed.length - 15} more`);
|
|
226
|
-
lines.push('');
|
|
227
|
-
}
|
|
228
|
-
const affected = result.affected_processes || [];
|
|
229
|
-
if (affected.length > 0) {
|
|
230
|
-
lines.push(`Affected execution flows:`);
|
|
231
|
-
for (const p of affected.slice(0, 10)) {
|
|
232
|
-
const steps = (p.changed_steps || []).map((s) => s.symbol).join(', ');
|
|
233
|
-
lines.push(` • ${p.name} (${p.step_count} steps) — changed: ${steps}`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return lines.join('\n').trim();
|
|
237
|
-
}
|
|
238
209
|
export function formatListReposResult(result) {
|
|
239
210
|
if (!Array.isArray(result) || result.length === 0) {
|
|
240
211
|
return 'No indexed repositories.';
|