@codragraph/cli 2.1.4 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +36 -7
  2. package/dist/cli/ai-context.js +297 -0
  3. package/dist/cli/analyze.d.ts +9 -4
  4. package/dist/cli/analyze.js +37 -13
  5. package/dist/cli/index.js +40 -14
  6. package/dist/cli/status.d.ts +1 -1
  7. package/dist/cli/status.js +8 -0
  8. package/dist/cli/tool.d.ts +10 -2
  9. package/dist/cli/tool.js +100 -39
  10. package/dist/config/ignore-service.js +1 -0
  11. package/dist/core/adaptive-profile.d.ts +52 -0
  12. package/dist/core/adaptive-profile.js +180 -0
  13. package/dist/core/cgdb/cgdb-adapter.d.ts +34 -5
  14. package/dist/core/cgdb/cgdb-adapter.js +418 -5
  15. package/dist/core/cgdb/pool-adapter.js +130 -20
  16. package/dist/core/ingestion/parsing-processor.js +7 -1
  17. package/dist/core/ingestion/pipeline-phases/parse-impl.js +7 -1
  18. package/dist/core/ingestion/pipeline-phases/structure.js +19 -3
  19. package/dist/core/ingestion/pipeline.d.ts +10 -0
  20. package/dist/core/ingestion/workers/parse-worker.js +1 -1
  21. package/dist/core/ingestion/workers/worker-pool.d.ts +14 -1
  22. package/dist/core/ingestion/workers/worker-pool.js +33 -17
  23. package/dist/core/run-analyze.d.ts +27 -2
  24. package/dist/core/run-analyze.js +626 -32
  25. package/dist/core/search/bm25-index.d.ts +16 -8
  26. package/dist/core/search/bm25-index.js +72 -110
  27. package/dist/mcp/local/local-backend.d.ts +2 -0
  28. package/dist/mcp/local/local-backend.js +241 -21
  29. package/dist/storage/repo-manager.d.ts +29 -0
  30. package/dist/web/assets/__vite-browser-external-BIHI7g3E.js +1 -0
  31. package/dist/web/assets/agent-DcdaQnmu.js +1104 -0
  32. package/dist/web/assets/architectureDiagram-UL44E2DR-DFSpa3Hb.js +36 -0
  33. package/dist/web/assets/blockDiagram-7IZFK4PR-DlFaxH1b.js +132 -0
  34. package/dist/web/assets/{c4Diagram-DFAF54RM-C4Hl3J2U.js → c4Diagram-Y2BXMSZH-BjJ_Yrim.js} +1 -1
  35. package/dist/web/assets/{chunk-7RZVMHOQ-BitYcNVR.js → chunk-3SSMPTDK-KGZSzG3Y.js} +1 -1
  36. package/dist/web/assets/{chunk-TBF5ZNIQ-DL5stGM1.js → chunk-6764PJDD-p1sGJgVm.js} +1 -1
  37. package/dist/web/assets/{chunk-KSICW3F5-BYzvDLNI.js → chunk-AZZRMDJM-DIDkQA4V.js} +1 -1
  38. package/dist/web/assets/{chunk-AEOMTBSW-BgTIXPsY.js → chunk-JQRUD6KW-DAwg-yCU.js} +1 -1
  39. package/dist/web/assets/chunk-KRXBNO2N-ChVO_XdS.js +1 -0
  40. package/dist/web/assets/chunk-LCXTWHL2-DGYdb_Eh.js +231 -0
  41. package/dist/web/assets/{chunk-O5ABG6QK-dHwHzA6n.js → chunk-LII3EMHJ-Bzh9SNgD.js} +1 -1
  42. package/dist/web/assets/chunk-RG4AUYOV-Bcl7U_IV.js +206 -0
  43. package/dist/web/assets/{chunk-TU3PZOEN-RLyvLcv-.js → chunk-T5OCTHI4-CZYMg5sc.js} +1 -1
  44. package/dist/web/assets/chunk-W44A43WB-REOI67PN.js +13 -0
  45. package/dist/web/assets/{chunk-RWUO3TPN-BgRTY0_k.js → chunk-ZXARS5L4-BfFdV1tf.js} +1 -1
  46. package/dist/web/assets/classDiagram-KGZ6W3CR-B-qkKMYi.js +1 -0
  47. package/dist/web/assets/classDiagram-v2-72OJOZXJ-B-qkKMYi.js +1 -0
  48. package/dist/web/assets/{cose-bilkent-PNC4W37J-DVhePRYg.js → cose-bilkent-UX7MHV2Q-D6vANJGG.js} +1 -1
  49. package/dist/web/assets/dagre-ND4H6XIP-BiHe5Lal.js +4 -0
  50. package/dist/web/assets/diagram-3NCE3AQN-CEutBCOW.js +43 -0
  51. package/dist/web/assets/diagram-GF46GFSD-CZns6HPQ.js +24 -0
  52. package/dist/web/assets/diagram-HNR7UZ2L-Vz8fE5of.js +3 -0
  53. package/dist/web/assets/diagram-QXG6HAR7-D60HKZ_y.js +24 -0
  54. package/dist/web/assets/diagram-WEQXMOUZ-vGAf1p3E.js +10 -0
  55. package/dist/web/assets/{erDiagram-GCSMX5X6-C3dhDFA8.js → erDiagram-L5TCEMPS-DZaplJA6.js} +5 -5
  56. package/dist/web/assets/{flowDiagram-OTCZ4VVT-CWSFWmhr.js → flowDiagram-H6V6AXG4-BqUqeAsI.js} +9 -9
  57. package/dist/web/assets/ganttDiagram-JCBTUEKG-XEB6H-0G.js +292 -0
  58. package/dist/web/assets/gitGraphDiagram-S2ZK5IYY-7G50u1Cd.js +106 -0
  59. package/dist/web/assets/index-B5WxtMpv.js +1415 -0
  60. package/dist/web/assets/infoDiagram-3YFTVSEB-Cut_rzaf.js +2 -0
  61. package/dist/web/assets/{ishikawaDiagram-YMYX4NHK-DUoJvNP2.js → ishikawaDiagram-BNXS4ZKH-B4DGfGi3.js} +3 -3
  62. package/dist/web/assets/{journeyDiagram-SO5T7YLQ-RMFPNNqz.js → journeyDiagram-M6C3CM3L-BBFhsL3E.js} +1 -1
  63. package/dist/web/assets/{kanban-definition-LJHFXRCJ-BzpDs1K9.js → kanban-definition-75IXJCU3-DarGRyn3.js} +4 -4
  64. package/dist/web/assets/{katex-GD7MH7QM-DBQvrix-.js → katex-K3KEBU37-W5XTYMhr.js} +1 -1
  65. package/dist/web/assets/mindmap-definition-2TDM6QVE-BgeczIJM.js +96 -0
  66. package/dist/web/assets/pieDiagram-CU6KROY3-Kkoo-Noq.js +30 -0
  67. package/dist/web/assets/quadrantDiagram-VICAPDV7-CDQFeRWN.js +7 -0
  68. package/dist/web/assets/{requirementDiagram-M5DCFWZL-DLHOVTSv.js → requirementDiagram-JXO7QTGE-Cz9-XnkA.js} +2 -2
  69. package/dist/web/assets/sankeyDiagram-URQDO5SZ-CU26z0n7.js +40 -0
  70. package/dist/web/assets/sequenceDiagram-VS2MUI6T-OGK1FLOt.js +162 -0
  71. package/dist/web/assets/stateDiagram-7D4R322I-DJ9brq0U.js +1 -0
  72. package/dist/web/assets/stateDiagram-v2-36443NZ5-DhJ4Ky-7.js +1 -0
  73. package/dist/web/assets/{timeline-definition-5SPVSISX-TRSDRgPw.js → timeline-definition-O6YCAMPW-XZvnjqTT.js} +4 -4
  74. package/dist/web/assets/{vennDiagram-IE5QUKF5-DNy7HRBM.js → vennDiagram-MWXL3ELB-CJUssEjA.js} +6 -6
  75. package/dist/web/assets/wardley-L42UT6IY-5TKZOOLJ-DZr11zBG.js +173 -0
  76. package/dist/web/assets/wardleyDiagram-CUQ6CDDI-C276iqrN.js +78 -0
  77. package/dist/web/assets/{xychartDiagram-ZHJ5623Y-Dr9r7a35.js → xychartDiagram-N2JHSOCM-B9-uCZyP.js} +4 -4
  78. package/dist/web/index.html +1 -1
  79. package/hooks/claude/codragraph-hook.cjs +15 -122
  80. package/package.json +1 -1
  81. package/vendor/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  82. package/dist/web/assets/agent-D5lb0zXz.js +0 -1089
  83. package/dist/web/assets/architectureDiagram-EMZXCZ2Q-CZtc99v_.js +0 -36
  84. package/dist/web/assets/blockDiagram-IGV67L2C-BtoUp-6Y.js +0 -132
  85. package/dist/web/assets/chunk-3GS5O3IE-DkUjU0WD.js +0 -231
  86. package/dist/web/assets/chunk-3YCYZ6SJ-CQkVgT_z.js +0 -1
  87. package/dist/web/assets/chunk-H3VCZNTA-Cx5XV_aC.js +0 -13
  88. package/dist/web/assets/chunk-HN6EAY2L-BBnyTNdB.js +0 -1
  89. package/dist/web/assets/chunk-PK6DOVAG-CvsEnugt.js +0 -206
  90. package/dist/web/assets/classDiagram-PPOCWD7C-DTr8QIOf.js +0 -1
  91. package/dist/web/assets/classDiagram-v2-23LJLIIU-DTr8QIOf.js +0 -1
  92. package/dist/web/assets/dagre-E77IOHMT-Dzx0A6ZU.js +0 -4
  93. package/dist/web/assets/diagram-H7BISOXX-CC9pRew1.js +0 -43
  94. package/dist/web/assets/diagram-JC5VWROH-Bau_i9tf.js +0 -24
  95. package/dist/web/assets/diagram-LXUTUG65-D9_FM2Gt.js +0 -10
  96. package/dist/web/assets/diagram-WEHSV5V5-BMlayouL.js +0 -24
  97. package/dist/web/assets/ganttDiagram-MUNLMDZQ-D3a67Yol.js +0 -292
  98. package/dist/web/assets/gitGraphDiagram-3HKGZ4G3-7jmry-vM.js +0 -106
  99. package/dist/web/assets/index-BgeqpYgd.js +0 -1415
  100. package/dist/web/assets/infoDiagram-MN7RKWGX-G7lhP0Ib.js +0 -2
  101. package/dist/web/assets/mindmap-definition-2EUWGEK5-Bk0O4roa.js +0 -96
  102. package/dist/web/assets/pieDiagram-3IATQBI2-DKU7kpgS.js +0 -30
  103. package/dist/web/assets/quadrantDiagram-E256RVCF-BY0TGWCS.js +0 -7
  104. package/dist/web/assets/sankeyDiagram-L3NBLAOT-DVMj5rX2.js +0 -10
  105. package/dist/web/assets/sequenceDiagram-ZOUHS735-CJC73bV-.js +0 -157
  106. package/dist/web/assets/stateDiagram-MLPALWAM-BCFyESls.js +0 -1
  107. package/dist/web/assets/stateDiagram-v2-B5LQ5ZB2-DahzzIca.js +0 -1
  108. package/dist/web/assets/wardley-RL74JXVD-BCRCBASE-B-eZEzf9.js +0 -161
  109. package/dist/web/assets/wardleyDiagram-XU3VSMPF-BP-r1xzR.js +0 -20
package/dist/cli/index.js CHANGED
@@ -8,6 +8,26 @@ import { registerGroupCommands } from './group.js';
8
8
  const _require = createRequire(import.meta.url);
9
9
  const pkg = _require('../../package.json');
10
10
  const program = new Command();
11
+ const exitOneShot = (code) => {
12
+ const reallyExit = process
13
+ .reallyExit;
14
+ if (typeof reallyExit === 'function') {
15
+ reallyExit(code);
16
+ }
17
+ process.exit(code);
18
+ };
19
+ const createOneShotLazyAction = (loader, exportName) => {
20
+ const action = createLazyAction(loader, exportName);
21
+ return async (...args) => {
22
+ await action(...args);
23
+ const code = typeof process.exitCode === 'number'
24
+ ? process.exitCode
25
+ : process.exitCode
26
+ ? Number(process.exitCode) || 1
27
+ : 0;
28
+ exitOneShot(code);
29
+ };
30
+ };
11
31
  program.name('codragraph').description('CodraGraph local CLI and MCP server').version(pkg.version);
12
32
  program
13
33
  .command('setup')
@@ -17,7 +37,9 @@ program
17
37
  .command('analyze [path]')
18
38
  .description('Index a repository (full analysis)')
19
39
  .option('-f, --force', 'Force full re-index even if up to date')
20
- .option('--embeddings', 'Enable embedding generation for semantic search (off by default)')
40
+ .option('--profile <mode>', 'Adaptive runtime profile: auto, lean, balanced, power', 'auto')
41
+ .option('--embedding-mode <mode>', 'Embedding policy: auto, off, on', 'auto')
42
+ .option('--embeddings', 'Enable embedding generation for semantic search (same as --embedding-mode on)')
21
43
  .option('--skills', 'Generate repo-specific skill files from detected communities')
22
44
  .option('--skill-targets <list>', 'CSV of editor targets for --skills (claude, cursor, opencode, codex). Default: claude.')
23
45
  .option('--skip-agents-md', 'Skip updating the codragraph section in AGENTS.md and CLAUDE.md')
@@ -30,7 +52,7 @@ program
30
52
  .option('-v, --verbose', 'Enable verbose ingestion warnings (default: false)')
31
53
  .option('--max-file-size <kb>', 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).')
32
54
  .option('--no-setup', 'Skip the first-run editor setup (auto-runs once when ~/.codragraph/registry.json is missing)')
33
- .option('--compress <encoding>', 'Compress per-row content (RFC 0001 Phase 2). One of: none (default), brotli, zstd. zstd requires Node 22.15.', 'none')
55
+ .option('--compress <encoding>', 'Compress per-row content. One of: auto (default), none, brotli, zstd. zstd requires Node >= 22.15.', 'auto')
34
56
  .addHelpText('after', '\nEnvironment variables:\n' +
35
57
  ' CODRAGRAPH_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .codragraphignore)\n' +
36
58
  ' CODRAGRAPH_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n' +
@@ -114,65 +136,69 @@ program
114
136
  .option('-g, --goal <text>', 'What you want to find')
115
137
  .option('-l, --limit <n>', 'Max processes to return (default: 5)')
116
138
  .option('--content', 'Include full symbol source code')
117
- .action(createLazyAction(() => import('./tool.js'), 'queryCommand'));
139
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'queryCommand'));
118
140
  program
119
141
  .command('context [name]')
120
142
  .description('360-degree view of a code symbol: callers, callees, processes')
121
143
  .option('-r, --repo <name>', 'Target repository')
122
144
  .option('-u, --uid <uid>', 'Direct symbol UID (zero-ambiguity lookup)')
123
145
  .option('-f, --file <path>', 'File path to disambiguate common names')
146
+ .option('-k, --kind <kind>', 'Symbol kind to disambiguate common names')
124
147
  .option('--content', 'Include full symbol source code')
125
- .action(createLazyAction(() => import('./tool.js'), 'contextCommand'));
148
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'contextCommand'));
126
149
  program
127
- .command('impact <target>')
150
+ .command('impact [target]')
128
151
  .description('Blast radius analysis: what breaks if you change a symbol')
129
152
  .option('-d, --direction <dir>', 'upstream (dependants) or downstream (dependencies)', 'upstream')
130
153
  .option('-r, --repo <name>', 'Target repository')
154
+ .option('-u, --uid <uid>', 'Direct target symbol UID (zero-ambiguity lookup)')
155
+ .option('-f, --file <path>', 'File path to disambiguate common names')
156
+ .option('-k, --kind <kind>', 'Symbol kind to disambiguate common names')
131
157
  .option('--depth <n>', 'Max relationship depth (default: 3)')
132
158
  .option('--include-tests', 'Include test files in results')
133
- .action(createLazyAction(() => import('./tool.js'), 'impactCommand'));
159
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'impactCommand'));
134
160
  program
135
161
  .command('cypher <query>')
136
162
  .description('Execute raw Cypher query against the knowledge graph')
137
163
  .option('-r, --repo <name>', 'Target repository')
138
- .action(createLazyAction(() => import('./tool.js'), 'cypherCommand'));
164
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'cypherCommand'));
139
165
  program
140
166
  .command('feature-clusters')
141
167
  .description('List human-facing feature clusters for targeted context building')
142
168
  .option('-r, --repo <name>', 'Target repository')
143
169
  .option('-l, --limit <n>', 'Max feature clusters to return (default: 100)')
144
- .action(createLazyAction(() => import('./tool.js'), 'featureClustersCommand'));
170
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'featureClustersCommand'));
145
171
  program
146
172
  .command('cluster-query [query]')
147
173
  .description('Alias for feature-clusters: list product/domain clusters')
148
174
  .option('-r, --repo <name>', 'Target repository')
149
175
  .option('-l, --limit <n>', 'Max feature clusters to return (default: 100)')
150
- .action(createLazyAction(() => import('./tool.js'), 'clusterQueryCommand'));
176
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'clusterQueryCommand'));
151
177
  program
152
178
  .command('feature-context <name>')
153
179
  .description('Show members, line ranges, and dependencies for a feature cluster')
154
180
  .option('-r, --repo <name>', 'Target repository')
155
181
  .option('-l, --limit <n>', 'Max members to return (default: 100)')
156
- .action(createLazyAction(() => import('./tool.js'), 'featureContextCommand'));
182
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'featureContextCommand'));
157
183
  program
158
184
  .command('cluster-context <name>')
159
185
  .description('Alias for feature-context: show a feature cluster context pack')
160
186
  .option('-r, --repo <name>', 'Target repository')
161
187
  .option('-l, --limit <n>', 'Max members to return (default: 100)')
162
- .action(createLazyAction(() => import('./tool.js'), 'clusterContextCommand'));
188
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'clusterContextCommand'));
163
189
  program
164
190
  .command('context-pack <name>')
165
191
  .description('Generate the compact agent context pack for a feature cluster')
166
192
  .option('-r, --repo <name>', 'Target repository')
167
193
  .option('-l, --limit <n>', 'Max members to return (default: 100)')
168
- .action(createLazyAction(() => import('./tool.js'), 'contextPackCommand'));
194
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'contextPackCommand'));
169
195
  program
170
196
  .command('cluster-impact <name>')
171
197
  .description('Feature-level blast radius analysis for a cluster')
172
198
  .option('-d, --direction <dir>', 'upstream, downstream, or both', 'upstream')
173
199
  .option('-r, --repo <name>', 'Target repository')
174
200
  .option('-l, --limit <n>', 'Max context-pack members to include (default: 100)')
175
- .action(createLazyAction(() => import('./tool.js'), 'clusterImpactCommand'));
201
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'clusterImpactCommand'));
176
202
  program
177
203
  .command('detect-changes')
178
204
  .alias('detect_changes')
@@ -180,7 +206,7 @@ program
180
206
  .option('-s, --scope <scope>', 'What to analyze: unstaged, staged, all, or compare', 'unstaged')
181
207
  .option('-b, --base-ref <ref>', 'Branch/commit for compare scope (e.g. main)')
182
208
  .option('-r, --repo <name>', 'Target repository')
183
- .action(createLazyAction(() => import('./tool.js'), 'detectChangesCommand'));
209
+ .action(createOneShotLazyAction(() => import('./tool.js'), 'detectChangesCommand'));
184
210
  // ─── Eval Server (persistent daemon for SWE-bench) ─────────────────
185
211
  program
186
212
  .command('eval-server')
@@ -13,7 +13,7 @@ export interface IndexStorageSummary {
13
13
  }
14
14
  export declare const formatBytes: (bytes: number) => string;
15
15
  export declare const summarizeIndexStorage: (storagePath: string) => Promise<IndexStorageSummary | null>;
16
- export declare const formatIndexStatusLines: (summary: IndexStorageSummary | null, meta: Pick<RepoMeta, "stats" | "compress">, options?: {
16
+ export declare const formatIndexStatusLines: (summary: IndexStorageSummary | null, meta: Pick<RepoMeta, "stats" | "compress" | "adaptiveProfile">, options?: {
17
17
  largeIndexWarningBytes?: number;
18
18
  }) => string[];
19
19
  export declare const statusCommand: () => Promise<void>;
@@ -94,6 +94,14 @@ export const formatIndexStatusLines = (summary, meta, options = {}) => {
94
94
  const embeddings = meta.stats?.embeddings;
95
95
  lines.push(`Embeddings: ${typeof embeddings === 'number' ? embeddings.toLocaleString('en-US') : 'unknown'}`);
96
96
  lines.push(`Compression: ${meta.compress ?? 'none'}`);
97
+ if (meta.adaptiveProfile?.resolved) {
98
+ const profile = meta.adaptiveProfile;
99
+ const workerText = typeof profile.workerPoolSize === 'number' ? `, workers ${profile.workerPoolSize}` : '';
100
+ const embeddingText = profile.embeddingDecision
101
+ ? `, embeddings ${profile.embeddingDecision}`
102
+ : '';
103
+ lines.push(`Adaptive profile: ${profile.resolved}${workerText}${embeddingText}`);
104
+ }
97
105
  return lines;
98
106
  };
99
107
  export const statusCommand = async () => {
@@ -21,15 +21,23 @@ export declare function queryCommand(queryText: string, options?: {
21
21
  limit?: string;
22
22
  content?: boolean;
23
23
  }): Promise<void>;
24
- export declare function contextCommand(name: string, options?: {
24
+ export declare function contextCommand(name: string | undefined | {
25
+ opts?: () => Record<string, unknown>;
26
+ }, options?: {
25
27
  repo?: string;
26
28
  file?: string;
27
29
  uid?: string;
30
+ kind?: string;
28
31
  content?: boolean;
29
32
  }): Promise<void>;
30
- export declare function impactCommand(target: string, options?: {
33
+ export declare function impactCommand(target: string | undefined | {
34
+ opts?: () => Record<string, unknown>;
35
+ }, options?: {
31
36
  direction?: string;
32
37
  repo?: string;
38
+ uid?: string;
39
+ file?: string;
40
+ kind?: string;
33
41
  depth?: string;
34
42
  includeTests?: boolean;
35
43
  }): Promise<void>;
package/dist/cli/tool.js CHANGED
@@ -17,6 +17,7 @@
17
17
  import { writeSync } from 'node:fs';
18
18
  import { LocalBackend } from '../mcp/local/local-backend.js';
19
19
  import { emitTokenStats } from './compress-stats.js';
20
+ import { findRepo } from '../storage/repo-manager.js';
20
21
  let _backend = null;
21
22
  async function getBackend() {
22
23
  if (_backend)
@@ -29,6 +30,27 @@ async function getBackend() {
29
30
  }
30
31
  return _backend;
31
32
  }
33
+ async function callToolOnce(toolName, params) {
34
+ const backend = await getBackend();
35
+ return backend.callTool(toolName, params);
36
+ }
37
+ async function resolveCliRepoParam(repoParam) {
38
+ if (repoParam)
39
+ return repoParam;
40
+ const currentRepo = await findRepo(process.cwd());
41
+ if (currentRepo)
42
+ return currentRepo.repoPath;
43
+ output(`Error: Current repository is not indexed: ${process.cwd()}\n` +
44
+ 'Run: npx @codragraph/cli analyze');
45
+ process.exitCode = 1;
46
+ return null;
47
+ }
48
+ function unwrapCommanderOptions(value) {
49
+ if (!value || typeof value !== 'object')
50
+ return value;
51
+ const maybeCommand = value;
52
+ return typeof maybeCommand.opts === 'function' ? maybeCommand.opts() : value;
53
+ }
32
54
  /**
33
55
  * Write tool output to stdout using low-level fd write.
34
56
  *
@@ -59,47 +81,67 @@ export async function queryCommand(queryText, options) {
59
81
  console.error('Usage: codragraph query <search_query>');
60
82
  process.exit(1);
61
83
  }
62
- const backend = await getBackend();
63
- const result = await backend.callTool('query', {
84
+ const repo = await resolveCliRepoParam(options?.repo);
85
+ if (!repo)
86
+ return;
87
+ const result = await callToolOnce('query', {
64
88
  query: queryText,
65
89
  task_context: options?.context,
66
90
  goal: options?.goal,
67
91
  limit: options?.limit ? parseInt(options.limit) : undefined,
68
92
  include_content: options?.content ?? false,
69
- repo: options?.repo,
93
+ repo,
70
94
  });
71
95
  output(result);
72
96
  emitTokenStats(result);
73
97
  }
74
98
  export async function contextCommand(name, options) {
75
- if (!name?.trim() && !options?.uid) {
99
+ let symbolName = typeof name === 'string' ? name : undefined;
100
+ if (typeof name !== 'string' && name && !options) {
101
+ options = unwrapCommanderOptions(name);
102
+ symbolName = undefined;
103
+ }
104
+ if (!symbolName?.trim() && !options?.uid) {
76
105
  console.error('Usage: codragraph context <symbol_name> [--uid <uid>] [--file <path>]');
77
106
  process.exit(1);
78
107
  }
79
- const backend = await getBackend();
80
- const result = await backend.callTool('context', {
81
- name: name || undefined,
108
+ const repo = await resolveCliRepoParam(options?.repo);
109
+ if (!repo)
110
+ return;
111
+ const result = await callToolOnce('context', {
112
+ name: symbolName || undefined,
82
113
  uid: options?.uid,
83
114
  file_path: options?.file,
115
+ kind: options?.kind,
84
116
  include_content: options?.content ?? false,
85
- repo: options?.repo,
117
+ repo,
86
118
  });
87
119
  output(result);
88
120
  emitTokenStats(result);
89
121
  }
90
122
  export async function impactCommand(target, options) {
91
- if (!target?.trim()) {
92
- console.error('Usage: codragraph impact <symbol_name> [--direction upstream|downstream]');
123
+ let targetName = typeof target === 'string' ? target : undefined;
124
+ if (typeof target !== 'string' && target && !options) {
125
+ options = unwrapCommanderOptions(target);
126
+ targetName = undefined;
127
+ }
128
+ if (!targetName?.trim() && !options?.uid) {
129
+ console.error('Usage: codragraph impact <symbol_name> [--uid <uid>] [--direction upstream|downstream]');
93
130
  process.exit(1);
94
131
  }
95
132
  try {
96
- const backend = await getBackend();
97
- const result = await backend.callTool('impact', {
98
- target,
133
+ const repo = await resolveCliRepoParam(options?.repo);
134
+ if (!repo)
135
+ return;
136
+ const result = await callToolOnce('impact', {
137
+ target: targetName || undefined,
138
+ target_uid: options?.uid,
139
+ file_path: options?.file,
140
+ kind: options?.kind,
99
141
  direction: options?.direction || 'upstream',
100
142
  maxDepth: options?.depth ? parseInt(options.depth, 10) : undefined,
101
143
  includeTests: options?.includeTests ?? false,
102
- repo: options?.repo,
144
+ repo,
103
145
  });
104
146
  output(result);
105
147
  emitTokenStats(result);
@@ -109,7 +151,7 @@ export async function impactCommand(target, options) {
109
151
  // The backend's impact() already returns structured errors for graph query failures
110
152
  output({
111
153
  error: (err instanceof Error ? err.message : String(err)) || 'Impact analysis failed unexpectedly',
112
- target: { name: target },
154
+ target: { name: targetName || options?.uid },
113
155
  direction: options?.direction || 'upstream',
114
156
  suggestion: 'Try reducing --depth or using codragraph context <symbol> as a fallback',
115
157
  });
@@ -121,26 +163,32 @@ export async function cypherCommand(query, options) {
121
163
  console.error('Usage: codragraph cypher <cypher_query>');
122
164
  process.exit(1);
123
165
  }
124
- const backend = await getBackend();
125
- const result = await backend.callTool('cypher', {
166
+ const repo = await resolveCliRepoParam(options?.repo);
167
+ if (!repo)
168
+ return;
169
+ const result = await callToolOnce('cypher', {
126
170
  query,
127
- repo: options?.repo,
171
+ repo,
128
172
  });
129
173
  output(result);
130
174
  }
131
175
  export async function featureClustersCommand(options) {
132
- const backend = await getBackend();
133
- const result = await backend.callTool('feature_clusters', {
134
- repo: options?.repo,
176
+ const repo = await resolveCliRepoParam(options?.repo);
177
+ if (!repo)
178
+ return;
179
+ const result = await callToolOnce('feature_clusters', {
180
+ repo,
135
181
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
136
182
  });
137
183
  output(result);
138
184
  }
139
185
  export async function clusterQueryCommand(query, options) {
140
- const backend = await getBackend();
141
- const result = await backend.callTool('cluster_query', {
186
+ const repo = await resolveCliRepoParam(options?.repo);
187
+ if (!repo)
188
+ return;
189
+ const result = await callToolOnce('cluster_query', {
142
190
  query,
143
- repo: options?.repo,
191
+ repo,
144
192
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
145
193
  });
146
194
  output(result);
@@ -150,10 +198,12 @@ export async function featureContextCommand(name, options) {
150
198
  console.error('Usage: codragraph feature-context <name>');
151
199
  process.exit(1);
152
200
  }
153
- const backend = await getBackend();
154
- const result = await backend.callTool('feature_context', {
201
+ const repo = await resolveCliRepoParam(options?.repo);
202
+ if (!repo)
203
+ return;
204
+ const result = await callToolOnce('feature_context', {
155
205
  name,
156
- repo: options?.repo,
206
+ repo,
157
207
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
158
208
  });
159
209
  output(result);
@@ -164,10 +214,12 @@ export async function clusterContextCommand(name, options) {
164
214
  console.error('Usage: codragraph cluster-context <name>');
165
215
  process.exit(1);
166
216
  }
167
- const backend = await getBackend();
168
- const result = await backend.callTool('cluster_context', {
217
+ const repo = await resolveCliRepoParam(options?.repo);
218
+ if (!repo)
219
+ return;
220
+ const result = await callToolOnce('cluster_context', {
169
221
  name,
170
- repo: options?.repo,
222
+ repo,
171
223
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
172
224
  });
173
225
  output(result);
@@ -178,10 +230,12 @@ export async function contextPackCommand(name, options) {
178
230
  console.error('Usage: codragraph context-pack <name>');
179
231
  process.exit(1);
180
232
  }
181
- const backend = await getBackend();
182
- const result = await backend.callTool('context_pack', {
233
+ const repo = await resolveCliRepoParam(options?.repo);
234
+ if (!repo)
235
+ return;
236
+ const result = await callToolOnce('context_pack', {
183
237
  name,
184
- repo: options?.repo,
238
+ repo,
185
239
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
186
240
  });
187
241
  output(result);
@@ -192,11 +246,13 @@ export async function clusterImpactCommand(name, options) {
192
246
  console.error('Usage: codragraph cluster-impact <name>');
193
247
  process.exit(1);
194
248
  }
195
- const backend = await getBackend();
196
- const result = await backend.callTool('cluster_impact', {
249
+ const repo = await resolveCliRepoParam(options?.repo);
250
+ if (!repo)
251
+ return;
252
+ const result = await callToolOnce('cluster_impact', {
197
253
  name,
198
254
  direction: options?.direction,
199
- repo: options?.repo,
255
+ repo,
200
256
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
201
257
  });
202
258
  output(result);
@@ -236,11 +292,16 @@ function formatDetectChangesResult(result) {
236
292
  return lines.join('\n').trim();
237
293
  }
238
294
  export async function detectChangesCommand(options) {
239
- const backend = await getBackend();
240
- const result = await backend.callTool('detect_changes', {
295
+ options = unwrapCommanderOptions(options);
296
+ const repo = await resolveCliRepoParam(options?.repo);
297
+ if (!repo)
298
+ return;
299
+ const result = await callToolOnce('detect_changes', {
241
300
  scope: options?.scope || 'unstaged',
242
301
  base_ref: options?.baseRef,
243
- repo: options?.repo,
302
+ repo,
244
303
  });
245
304
  output(formatDetectChangesResult(result));
305
+ if (result?.error)
306
+ process.exitCode = 1;
246
307
  }
@@ -4,6 +4,7 @@ import nodePath from 'path';
4
4
  const DEFAULT_IGNORE_LIST = new Set([
5
5
  // Version Control
6
6
  '.git',
7
+ '.codragraph',
7
8
  '.svn',
8
9
  '.hg',
9
10
  '.bzr',
@@ -0,0 +1,52 @@
1
+ import type { ContentEncoding } from '@codragraph/graphstore';
2
+ import type { RepoMeta } from '../storage/repo-manager.js';
3
+ export type AnalyzeProfileOption = 'auto' | 'lean' | 'balanced' | 'power';
4
+ export type ResolvedAnalyzeProfile = Exclude<AnalyzeProfileOption, 'auto'>;
5
+ export type EmbeddingMode = 'auto' | 'off' | 'on';
6
+ export type CompressionOption = ContentEncoding | 'auto';
7
+ export interface MachineSnapshot {
8
+ platform: NodeJS.Platform;
9
+ arch: NodeJS.Architecture;
10
+ logicalCpus: number;
11
+ availableParallelism: number;
12
+ totalMemoryBytes: number;
13
+ freeMemoryBytes: number;
14
+ heapLimitBytes: number;
15
+ nodeVersion: string;
16
+ httpEmbeddingsConfigured: boolean;
17
+ }
18
+ export interface AdaptiveAnalyzePlan {
19
+ requestedProfile: AnalyzeProfileOption;
20
+ profile: ResolvedAnalyzeProfile;
21
+ machine: MachineSnapshot;
22
+ compress: ContentEncoding;
23
+ embeddingMode: EmbeddingMode;
24
+ embeddingNodeLimit: number;
25
+ workerPoolSize: number;
26
+ workerSubBatchSize: number;
27
+ reasons: string[];
28
+ }
29
+ export interface EmbeddingDecision {
30
+ enabled: boolean;
31
+ reason: string;
32
+ limit: number;
33
+ }
34
+ export declare const parseAnalyzeProfile: (value?: string) => AnalyzeProfileOption;
35
+ export declare const parseEmbeddingMode: (value?: string) => EmbeddingMode;
36
+ export declare const parseCompressionOption: (value?: string) => CompressionOption;
37
+ export declare const detectMachineSnapshot: () => MachineSnapshot;
38
+ export declare const resolveAnalyzeProfile: (requested: AnalyzeProfileOption, machine: MachineSnapshot) => ResolvedAnalyzeProfile;
39
+ export declare const resolveEmbeddingMode: (embeddingsFlag: boolean | undefined, requestedMode: string | undefined) => EmbeddingMode;
40
+ export declare const resolveCompression: (requested: CompressionOption, profile: ResolvedAnalyzeProfile, existingMeta?: Pick<RepoMeta, "compress"> | null) => ContentEncoding;
41
+ export declare const embeddingLimitForProfile: (profile: ResolvedAnalyzeProfile, httpEmbeddingsConfigured: boolean) => number;
42
+ export declare const workerPlanForProfile: (profile: ResolvedAnalyzeProfile, machine: Pick<MachineSnapshot, "availableParallelism">) => Pick<AdaptiveAnalyzePlan, "workerPoolSize" | "workerSubBatchSize">;
43
+ export declare const resolveAdaptiveAnalyzePlan: (input: {
44
+ profile?: string;
45
+ embeddingMode?: string;
46
+ embeddings?: boolean;
47
+ compress?: string;
48
+ existingMeta?: Pick<RepoMeta, "compress"> | null;
49
+ machine?: MachineSnapshot;
50
+ }) => AdaptiveAnalyzePlan;
51
+ export declare const decideEmbeddingRun: (plan: Pick<AdaptiveAnalyzePlan, "embeddingMode" | "embeddingNodeLimit" | "profile" | "machine">, stats?: Pick<NonNullable<RepoMeta["stats"]>, "nodes" | "embeddings">) => EmbeddingDecision;
52
+ export declare const formatAdaptiveAnalyzePlan: (plan: AdaptiveAnalyzePlan) => string;