@codragraph/cli 2.1.5 → 2.2.0-rc.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 (113) hide show
  1. package/README.md +18 -13
  2. package/dist/cli/analyze.d.ts +9 -4
  3. package/dist/cli/analyze.js +37 -13
  4. package/dist/cli/graphpack.d.ts +48 -0
  5. package/dist/cli/graphpack.js +217 -0
  6. package/dist/cli/index.js +81 -3
  7. package/dist/cli/status.d.ts +1 -1
  8. package/dist/cli/status.js +8 -0
  9. package/dist/cli/tool.d.ts +11 -2
  10. package/dist/cli/tool.js +138 -8
  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 +1 -1
  16. package/dist/core/graphpack/index.d.ts +14 -0
  17. package/dist/core/graphpack/index.js +474 -0
  18. package/dist/core/graphpack/types.d.ts +129 -0
  19. package/dist/core/graphpack/types.js +4 -0
  20. package/dist/core/ingestion/pipeline-phases/parse-impl.js +3 -1
  21. package/dist/core/ingestion/pipeline-phases/structure.js +19 -3
  22. package/dist/core/ingestion/pipeline.d.ts +10 -0
  23. package/dist/core/run-analyze.d.ts +27 -2
  24. package/dist/core/run-analyze.js +598 -27
  25. package/dist/core/search/bm25-index.d.ts +19 -0
  26. package/dist/core/search/bm25-index.js +68 -29
  27. package/dist/core/semantic/relationships.d.ts +36 -0
  28. package/dist/core/semantic/relationships.js +261 -0
  29. package/dist/mcp/local/local-backend.js +48 -3
  30. package/dist/mcp/resources.js +125 -0
  31. package/dist/mcp/tools.js +105 -0
  32. package/dist/server/api.js +112 -0
  33. package/dist/storage/repo-manager.d.ts +29 -0
  34. package/dist/web/assets/agent-CQNZQ-hg.js +1139 -0
  35. package/dist/web/assets/architectureDiagram-UL44E2DR-B5_goS_i.js +36 -0
  36. package/dist/web/assets/blockDiagram-7IZFK4PR-D7ZAlDyv.js +132 -0
  37. package/dist/web/assets/{c4Diagram-DFAF54RM-C4Hl3J2U.js → c4Diagram-Y2BXMSZH-Djcgm_54.js} +1 -1
  38. package/dist/web/assets/{chunk-7RZVMHOQ-BitYcNVR.js → chunk-3SSMPTDK-Cv2Zy2FO.js} +1 -1
  39. package/dist/web/assets/{chunk-TBF5ZNIQ-DL5stGM1.js → chunk-6764PJDD-Cppb-jH-.js} +1 -1
  40. package/dist/web/assets/{chunk-KSICW3F5-BYzvDLNI.js → chunk-AZZRMDJM-BHlLC7p3.js} +1 -1
  41. package/dist/web/assets/{chunk-AEOMTBSW-BgTIXPsY.js → chunk-JQRUD6KW-3F8Zg-1N.js} +1 -1
  42. package/dist/web/assets/chunk-KRXBNO2N-C0mbN9a7.js +1 -0
  43. package/dist/web/assets/chunk-LCXTWHL2-BoiuJpIF.js +231 -0
  44. package/dist/web/assets/{chunk-O5ABG6QK-dHwHzA6n.js → chunk-LII3EMHJ-Dqq0Qguw.js} +1 -1
  45. package/dist/web/assets/chunk-RG4AUYOV-Bl5F_gDs.js +206 -0
  46. package/dist/web/assets/{chunk-TU3PZOEN-RLyvLcv-.js → chunk-T5OCTHI4-B2tIcggA.js} +1 -1
  47. package/dist/web/assets/chunk-W44A43WB-BHe37iN7.js +13 -0
  48. package/dist/web/assets/{chunk-RWUO3TPN-BgRTY0_k.js → chunk-ZXARS5L4-wcrIaQvY.js} +1 -1
  49. package/dist/web/assets/classDiagram-KGZ6W3CR-IbI6v_24.js +1 -0
  50. package/dist/web/assets/classDiagram-v2-72OJOZXJ-IbI6v_24.js +1 -0
  51. package/dist/web/assets/{cose-bilkent-PNC4W37J-DVhePRYg.js → cose-bilkent-UX7MHV2Q-BWr7v0Wr.js} +1 -1
  52. package/dist/web/assets/dagre-ND4H6XIP-De5LIh1B.js +4 -0
  53. package/dist/web/assets/diagram-3NCE3AQN-Dd22FSHy.js +43 -0
  54. package/dist/web/assets/diagram-GF46GFSD-Cev3THY8.js +24 -0
  55. package/dist/web/assets/diagram-HNR7UZ2L-D8Z8RQGs.js +3 -0
  56. package/dist/web/assets/diagram-QXG6HAR7-B8VOJOiE.js +24 -0
  57. package/dist/web/assets/diagram-WEQXMOUZ-va1bLoMD.js +10 -0
  58. package/dist/web/assets/{erDiagram-GCSMX5X6-C3dhDFA8.js → erDiagram-L5TCEMPS-B3_9uAoP.js} +5 -5
  59. package/dist/web/assets/{flowDiagram-OTCZ4VVT-CWSFWmhr.js → flowDiagram-H6V6AXG4-98m6maI1.js} +9 -9
  60. package/dist/web/assets/ganttDiagram-JCBTUEKG-vE2nzETb.js +292 -0
  61. package/dist/web/assets/gitGraphDiagram-S2ZK5IYY-DKc8uUg_.js +106 -0
  62. package/dist/web/assets/index-BAhe1HSk.css +1 -0
  63. package/dist/web/assets/index-VTKdaklA.js +1415 -0
  64. package/dist/web/assets/infoDiagram-3YFTVSEB-DYP-Srzx.js +2 -0
  65. package/dist/web/assets/{ishikawaDiagram-YMYX4NHK-DUoJvNP2.js → ishikawaDiagram-BNXS4ZKH-QZnkpmmb.js} +3 -3
  66. package/dist/web/assets/{journeyDiagram-SO5T7YLQ-RMFPNNqz.js → journeyDiagram-M6C3CM3L-B5ojIuqu.js} +1 -1
  67. package/dist/web/assets/{kanban-definition-LJHFXRCJ-BzpDs1K9.js → kanban-definition-75IXJCU3-BJA8liRR.js} +4 -4
  68. package/dist/web/assets/{katex-GD7MH7QM-DBQvrix-.js → katex-K3KEBU37-DUqZiCRL.js} +1 -1
  69. package/dist/web/assets/mindmap-definition-2TDM6QVE-BQj5yylD.js +96 -0
  70. package/dist/web/assets/pieDiagram-CU6KROY3-4eSrPiQz.js +30 -0
  71. package/dist/web/assets/quadrantDiagram-VICAPDV7-PzxN8j55.js +7 -0
  72. package/dist/web/assets/{requirementDiagram-M5DCFWZL-DLHOVTSv.js → requirementDiagram-JXO7QTGE-CtplTc5y.js} +2 -2
  73. package/dist/web/assets/sankeyDiagram-URQDO5SZ-CoSgvkxv.js +40 -0
  74. package/dist/web/assets/sequenceDiagram-VS2MUI6T-D7ygyXvJ.js +162 -0
  75. package/dist/web/assets/stateDiagram-7D4R322I-v01gvwji.js +1 -0
  76. package/dist/web/assets/stateDiagram-v2-36443NZ5-DFD2b8_x.js +1 -0
  77. package/dist/web/assets/{timeline-definition-5SPVSISX-TRSDRgPw.js → timeline-definition-O6YCAMPW-CTI3M65J.js} +4 -4
  78. package/dist/web/assets/{vennDiagram-IE5QUKF5-DNy7HRBM.js → vennDiagram-MWXL3ELB-RnB0XMP7.js} +6 -6
  79. package/dist/web/assets/wardley-L42UT6IY-5TKZOOLJ-C-ZcgEBb.js +173 -0
  80. package/dist/web/assets/wardleyDiagram-CUQ6CDDI-EwRi4kwo.js +78 -0
  81. package/dist/web/assets/{xychartDiagram-ZHJ5623Y-Dr9r7a35.js → xychartDiagram-N2JHSOCM-DA38II6y.js} +4 -4
  82. package/dist/web/index.html +2 -2
  83. package/package.json +2 -2
  84. package/vendor/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  85. package/dist/web/assets/agent-D5lb0zXz.js +0 -1089
  86. package/dist/web/assets/architectureDiagram-EMZXCZ2Q-CZtc99v_.js +0 -36
  87. package/dist/web/assets/blockDiagram-IGV67L2C-BtoUp-6Y.js +0 -132
  88. package/dist/web/assets/chunk-3GS5O3IE-DkUjU0WD.js +0 -231
  89. package/dist/web/assets/chunk-3YCYZ6SJ-CQkVgT_z.js +0 -1
  90. package/dist/web/assets/chunk-H3VCZNTA-Cx5XV_aC.js +0 -13
  91. package/dist/web/assets/chunk-HN6EAY2L-BBnyTNdB.js +0 -1
  92. package/dist/web/assets/chunk-PK6DOVAG-CvsEnugt.js +0 -206
  93. package/dist/web/assets/classDiagram-PPOCWD7C-DTr8QIOf.js +0 -1
  94. package/dist/web/assets/classDiagram-v2-23LJLIIU-DTr8QIOf.js +0 -1
  95. package/dist/web/assets/dagre-E77IOHMT-Dzx0A6ZU.js +0 -4
  96. package/dist/web/assets/diagram-H7BISOXX-CC9pRew1.js +0 -43
  97. package/dist/web/assets/diagram-JC5VWROH-Bau_i9tf.js +0 -24
  98. package/dist/web/assets/diagram-LXUTUG65-D9_FM2Gt.js +0 -10
  99. package/dist/web/assets/diagram-WEHSV5V5-BMlayouL.js +0 -24
  100. package/dist/web/assets/ganttDiagram-MUNLMDZQ-D3a67Yol.js +0 -292
  101. package/dist/web/assets/gitGraphDiagram-3HKGZ4G3-7jmry-vM.js +0 -106
  102. package/dist/web/assets/index-BgeqpYgd.js +0 -1415
  103. package/dist/web/assets/index-CT0GtFLZ.css +0 -1
  104. package/dist/web/assets/infoDiagram-MN7RKWGX-G7lhP0Ib.js +0 -2
  105. package/dist/web/assets/mindmap-definition-2EUWGEK5-Bk0O4roa.js +0 -96
  106. package/dist/web/assets/pieDiagram-3IATQBI2-DKU7kpgS.js +0 -30
  107. package/dist/web/assets/quadrantDiagram-E256RVCF-BY0TGWCS.js +0 -7
  108. package/dist/web/assets/sankeyDiagram-L3NBLAOT-DVMj5rX2.js +0 -10
  109. package/dist/web/assets/sequenceDiagram-ZOUHS735-CJC73bV-.js +0 -157
  110. package/dist/web/assets/stateDiagram-MLPALWAM-BCFyESls.js +0 -1
  111. package/dist/web/assets/stateDiagram-v2-B5LQ5ZB2-DahzzIca.js +0 -1
  112. package/dist/web/assets/wardley-RL74JXVD-BCRCBASE-B-eZEzf9.js +0 -161
  113. package/dist/web/assets/wardleyDiagram-XU3VSMPF-BP-r1xzR.js +0 -20
package/README.md CHANGED
@@ -25,12 +25,15 @@ That's it. This indexes the codebase, installs agent skills, registers Claude Co
25
25
 
26
26
  The same CLI commands work in Windows PowerShell, macOS bash/zsh, and Linux shells. Use `npx @codragraph/cli ...` for no-install runs or `codragraph ...` after a global install.
27
27
 
28
- Smart analyze rebuilds when indexed source, Markdown/MDX graph docs, language
29
- config, schema, compression, or requested embedding settings changed. Generated
30
- agent context, lockfile-only, and ignored asset changes reuse the existing
31
- graph and advance metadata. Each pass refreshes `.codragraph/structure/`, a
32
- compact what/why/how/when/where markdown pack with branch/index state, bounded
33
- history, and SQLite seed SQL for external agent memory.
28
+ Smart analyze now patches the existing graph for normal day-to-day changes:
29
+ source edits, renames, large diffs, and topology-only files replace only the
30
+ affected file-scoped rows, then recompute communities, execution flows, and
31
+ FeatureCluster packs. Package/config or ignore-rule inputs refresh all
32
+ file-scoped rows without falling back to a full cold rebuild. Generated agent
33
+ context, lockfile-only, and ignored asset changes reuse the existing graph and
34
+ advance metadata. Each pass refreshes `.codragraph/structure/`, a compact
35
+ what/why/how/when/where markdown pack with branch/index state, bounded history,
36
+ and SQLite seed SQL for external agent memory.
34
37
 
35
38
  To configure MCP for your editor, run `npx @codragraph/cli setup` once — or set it up manually below.
36
39
 
@@ -62,16 +65,16 @@ If you prefer to configure manually instead of using `codragraph setup`:
62
65
 
63
66
  ```bash
64
67
  # macOS / Linux
65
- claude mcp add codragraph -- npx -y @codragraph/cli@2.1.5 mcp
68
+ claude mcp add codragraph -- npx -y @codragraph/cli@2.2.0-rc.6 mcp
66
69
 
67
70
  # Windows
68
- claude mcp add codragraph -- cmd /c npx -y @codragraph/cli@2.1.5 mcp
71
+ claude mcp add codragraph -- cmd /c npx -y @codragraph/cli@2.2.0-rc.6 mcp
69
72
  ```
70
73
 
71
74
  ### Codex (full support — MCP + skills)
72
75
 
73
76
  ```bash
74
- codex mcp add codragraph -- npx -y @codragraph/cli@2.1.5 mcp
77
+ codex mcp add codragraph -- npx -y @codragraph/cli@2.2.0-rc.6 mcp
75
78
  ```
76
79
 
77
80
  ### Cursor / Windsurf
@@ -83,7 +86,7 @@ Add to `~/.cursor/mcp.json` (global — works for all projects):
83
86
  "mcpServers": {
84
87
  "codragraph": {
85
88
  "command": "npx",
86
- "args": ["-y", "@codragraph/cli@2.1.5", "mcp"]
89
+ "args": ["-y", "@codragraph/cli@2.2.0-rc.6", "mcp"]
87
90
  }
88
91
  }
89
92
  }
@@ -98,7 +101,7 @@ Add to `~/.config/opencode/config.json`:
98
101
  "mcp": {
99
102
  "codragraph": {
100
103
  "command": "npx",
101
- "args": ["-y", "@codragraph/cli@2.1.5", "mcp"]
104
+ "args": ["-y", "@codragraph/cli@2.2.0-rc.6", "mcp"]
102
105
  }
103
106
  }
104
107
  }
@@ -184,6 +187,8 @@ codragraph serve --web hosted # API only; connect from hosted web UI
184
187
  codragraph index # Register an existing .codragraph/ folder into the global registry
185
188
  codragraph list # List all indexed repositories
186
189
  codragraph status # Show index status for current repo
190
+ codragraph detect-changes --scope unstaged # Map working-tree diff to symbols/processes
191
+ codragraph detect-changes --scope all # Include staged + unstaged changes
187
192
  codragraph clean # Delete index for current repo
188
193
  codragraph clean --all --force # Delete all indexes
189
194
  codragraph wiki [path] # Generate LLM-powered docs from knowledge graph
@@ -304,9 +309,9 @@ It is fixed in **codragraph v1.6.2+**. Upgrade to the current workspace
304
309
  version, or pin the version your team has validated:
305
310
 
306
311
  ```bash
307
- npx @codragraph/cli@2.1.5 analyze # no global install
312
+ npx @codragraph/cli@2.2.0-rc.6 analyze # no global install
308
313
  # or
309
- npm install -g @codragraph/cli@2.1.5 # upgrade a global install
314
+ npm install -g @codragraph/cli@2.2.0-rc.6 # upgrade a global install
310
315
  ```
311
316
 
312
317
  If you still hit npm install issues after upgrading, these generic workarounds
@@ -7,9 +7,14 @@
7
7
  * This CLI wrapper handles: heap management, progress bar, SIGINT,
8
8
  * skill generation (--skills), summary output, and process.exit().
9
9
  */
10
+ import { type AnalyzeProfileOption, type CompressionOption, type EmbeddingMode } from '../core/adaptive-profile.js';
10
11
  export interface AnalyzeOptions {
11
12
  force?: boolean;
12
13
  embeddings?: boolean;
14
+ /** Adaptive runtime profile. `auto` detects CPU/RAM/heap and chooses lean/balanced/power. */
15
+ profile?: AnalyzeProfileOption;
16
+ /** Embedding policy. `--embeddings` is kept as a shortcut for `on`. */
17
+ embeddingMode?: EmbeddingMode;
13
18
  skills?: boolean;
14
19
  verbose?: boolean;
15
20
  /** Skip AGENTS.md and CLAUDE.md codragraph block updates. */
@@ -54,12 +59,12 @@ export interface AnalyzeOptions {
54
59
  */
55
60
  skillTargets?: string;
56
61
  /**
57
- * RFC 0001 Phase 2 — opt-in per-row content compression. Accepts
58
- * `'none'` (default), `'brotli'` (Node 18), or `'zstd'` (Node ≥
59
- * 22.15). Compressed indexes are still queryable via the standard
62
+ * RFC 0001 Phase 2 - per-row content compression. Accepts `'auto'`
63
+ * (default), `'none'`, `'brotli'` (Node >= 18), or `'zstd'`
64
+ * (Node >= 22.15). Compressed indexes are still queryable via the standard
60
65
  * read path; decode happens at every external-consumer boundary
61
66
  * (MCP, HTTP API, embeddings, CLI tools).
62
67
  */
63
- compress?: 'none' | 'brotli' | 'zstd';
68
+ compress?: CompressionOption;
64
69
  }
65
70
  export declare const analyzeCommand: (inputPath?: string, options?: AnalyzeOptions) => Promise<void>;
@@ -17,6 +17,7 @@ import { closeCgdb } from '../core/cgdb/cgdb-adapter.js';
17
17
  import { getStoragePaths, getGlobalRegistryPath, RegistryNameCollisionError, } from '../storage/repo-manager.js';
18
18
  import { getGitRoot, hasGitDir } from '../storage/git.js';
19
19
  import { runFullAnalysis } from '../core/run-analyze.js';
20
+ import { parseAnalyzeProfile, parseCompressionOption, parseEmbeddingMode, } from '../core/adaptive-profile.js';
20
21
  import { getMaxFileSizeBannerMessage } from '../core/ingestion/utils/max-file-size.js';
21
22
  import fs from 'fs/promises';
22
23
  import { formatBytes, LARGE_INDEX_WARNING_BYTES, summarizeIndexStorage } from './status.js';
@@ -28,10 +29,14 @@ const HEAP_FLAG = `--max-old-space-size=${HEAP_MB}`;
28
29
  /** Increase default stack size (KB) to prevent stack overflow on deep class hierarchies. */
29
30
  const STACK_KB = 4096;
30
31
  const STACK_FLAG = `--stack-size=${STACK_KB}`;
32
+ function hasNodeFlag(flagName, nodeOpts, execArgv) {
33
+ return (nodeOpts.includes(flagName) ||
34
+ execArgv.some((arg) => arg === flagName || arg.startsWith(`${flagName}=`)));
35
+ }
31
36
  /** Re-exec the process with an 8GB heap and larger stack if we're currently below that. */
32
37
  function ensureHeap() {
33
38
  const nodeOpts = process.env.NODE_OPTIONS || '';
34
- if (nodeOpts.includes('--max-old-space-size'))
39
+ if (hasNodeFlag('--max-old-space-size', nodeOpts, process.execArgv))
35
40
  return false;
36
41
  const v8Heap = v8.getHeapStatistics().heap_size_limit;
37
42
  if (v8Heap >= HEAP_MB * 1024 * 1024 * 0.9)
@@ -39,10 +44,14 @@ function ensureHeap() {
39
44
  // --stack-size is a V8 flag not allowed in NODE_OPTIONS on Node 24+,
40
45
  // so pass it only as a direct CLI argument, not via the environment.
41
46
  const cliFlags = [HEAP_FLAG];
42
- if (!nodeOpts.includes('--stack-size'))
47
+ if (!hasNodeFlag('--stack-size', nodeOpts, process.execArgv))
43
48
  cliFlags.push(STACK_FLAG);
44
49
  try {
45
- execFileSync(process.execPath, [...cliFlags, ...process.argv.slice(1)], {
50
+ // Preserve loader/debug flags from the outer process. This is required
51
+ // for source-mode invocations such as `tsx src/cli/index.ts analyze`;
52
+ // otherwise the child runs plain node against .ts files and cannot
53
+ // resolve the emitted .js import specifiers.
54
+ execFileSync(process.execPath, [...process.execArgv, ...cliFlags, ...process.argv.slice(1)], {
46
55
  stdio: 'inherit',
47
56
  env: { ...process.env, NODE_OPTIONS: `${nodeOpts} ${HEAP_FLAG}`.trim() },
48
57
  });
@@ -58,18 +67,31 @@ export const analyzeCommand = async (inputPath, options) => {
58
67
  if (options?.verbose) {
59
68
  process.env.CODRAGRAPH_VERBOSE = '1';
60
69
  }
61
- // RFC 0001 Phase 2 — validate --compress before doing any work. Catching
70
+ try {
71
+ parseAnalyzeProfile(options?.profile);
72
+ parseEmbeddingMode(options?.embeddingMode);
73
+ }
74
+ catch (err) {
75
+ console.error(` ${err.message}`);
76
+ process.exitCode = 2;
77
+ return;
78
+ }
79
+ // RFC 0001 Phase 2 - validate --compress before doing any work. Catching
62
80
  // a typo or an unsupported encoding here is much friendlier than failing
63
81
  // mid-analyze with an opaque CSV-write error. Node-version gating for
64
82
  // zstd lives in @codragraph/graphstore via isEncodingSupported, but we
65
83
  // import the check here so the CLI can offer the brotli fallback hint.
66
- if (options?.compress && options.compress !== 'none') {
67
- if (options.compress !== 'brotli' && options.compress !== 'zstd') {
68
- console.error(` --compress must be one of: none, brotli, zstd (got: ${options.compress})`);
69
- process.exitCode = 2;
70
- return;
71
- }
72
- if (options.compress === 'zstd') {
84
+ const requestedCompress = options?.compress ?? 'auto';
85
+ try {
86
+ parseCompressionOption(requestedCompress);
87
+ }
88
+ catch (err) {
89
+ console.error(` ${err.message}`);
90
+ process.exitCode = 2;
91
+ return;
92
+ }
93
+ if (requestedCompress !== 'auto' && requestedCompress !== 'none') {
94
+ if (requestedCompress === 'zstd') {
73
95
  const { isEncodingSupported } = await import('@codragraph/graphstore');
74
96
  if (!isEncodingSupported('zstd')) {
75
97
  console.error(' --compress zstd requires Node ≥ 22.15.0 (native node:zlib zstd).\n' +
@@ -84,7 +106,7 @@ export const analyzeCommand = async (inputPath, options) => {
84
106
  // gracefully falls back to name-only matches instead of tokenising
85
107
  // base64 garbage. Surface the trade-off so users know what they're
86
108
  // opting into.
87
- console.warn(` Note: --compress ${options.compress} reduces .codragraph/cgdb size.\n` +
109
+ console.warn(` Note: --compress ${requestedCompress} reduces .codragraph/cgdb size.\n` +
88
110
  ` BM25 search will index symbol names only (function bodies are not tokenised\n` +
89
111
  ` when compressed); embeddings, graph queries, and \`context\` / \`impact\` are\n` +
90
112
  ` unaffected. Run with --compress none if you rely on full-text search inside\n` +
@@ -241,8 +263,10 @@ export const analyzeCommand = async (inputPath, options) => {
241
263
  // cost of a full pipeline re-index. See #829 review round 2.
242
264
  allowDuplicateName: options?.allowDuplicateName,
243
265
  // RFC 0001 Phase 2 — pass through the per-row encoding choice.
244
- // Default 'none' / undefined keeps the pre-Phase-2 wire layout.
266
+ // Default 'auto' lets the adaptive profile choose the storage tier.
245
267
  compress: options?.compress,
268
+ profile: options?.profile,
269
+ embeddingMode: options?.embeddingMode,
246
270
  }, {
247
271
  onProgress: (_phase, percent, message) => {
248
272
  updateBar(percent, message);
@@ -0,0 +1,48 @@
1
+ import { type GraphpackTarget } from '../core/graphpack/index.js';
2
+ export declare const bootstrapCommand: (opts?: {
3
+ lock?: string;
4
+ artifactDir?: string;
5
+ materialize?: boolean;
6
+ json?: boolean;
7
+ }) => Promise<void>;
8
+ export declare const graphpackPublishCommand: (opts?: {
9
+ target?: GraphpackTarget;
10
+ repo?: string;
11
+ artifactDir?: string;
12
+ artifactUrl?: string;
13
+ baseSnapshot?: string;
14
+ headSnapshot?: string;
15
+ pr?: string;
16
+ json?: boolean;
17
+ }) => Promise<void>;
18
+ export declare const graphpackPullCommand: (opts?: {
19
+ lock?: string;
20
+ artifactDir?: string;
21
+ materialize?: boolean;
22
+ json?: boolean;
23
+ }) => Promise<void>;
24
+ export declare const graphpackStatusCommand: (opts?: {
25
+ lock?: string;
26
+ strict?: boolean;
27
+ json?: boolean;
28
+ }) => Promise<void>;
29
+ export declare const semanticAnalyzeCommand: (opts?: {
30
+ llm?: boolean;
31
+ limit?: string;
32
+ write?: boolean;
33
+ json?: boolean;
34
+ }) => Promise<void>;
35
+ export declare const recipesLookupCommand: (opts?: {
36
+ taskFamily?: string;
37
+ snapshotId?: string;
38
+ recipeStore?: string;
39
+ requiredSubgraphSignature?: string;
40
+ limit?: string;
41
+ json?: boolean;
42
+ }) => Promise<void>;
43
+ export declare const teamServeCommand: (opts?: {
44
+ graphpack?: string;
45
+ port?: string;
46
+ host?: string;
47
+ web?: string;
48
+ }) => Promise<void>;
@@ -0,0 +1,217 @@
1
+ import path from 'node:path';
2
+ import { createRequire } from 'node:module';
3
+ import { bootstrapGraphpack, getGraphpackStatus, publishGraphpack, pullGraphpack, } from '../core/graphpack/index.js';
4
+ import { analyzeSemanticRelationships } from '../core/semantic/relationships.js';
5
+ import { findRepo, getStoragePaths, registerRepo } from '../storage/repo-manager.js';
6
+ import { getGitRoot, getInferredRepoName } from '../storage/git.js';
7
+ const require = createRequire(import.meta.url);
8
+ const pkg = require('../../package.json');
9
+ const resolveRepoForGraphpack = async () => {
10
+ const indexed = await findRepo(process.cwd());
11
+ if (indexed) {
12
+ return {
13
+ repoPath: indexed.repoPath,
14
+ storagePath: indexed.storagePath,
15
+ repoName: getInferredRepoName(indexed.repoPath) ?? path.basename(indexed.repoPath),
16
+ };
17
+ }
18
+ const gitRoot = getGitRoot(process.cwd());
19
+ if (!gitRoot) {
20
+ throw new Error('Not inside a git repository and no CodraGraph index was found.');
21
+ }
22
+ const paths = getStoragePaths(gitRoot);
23
+ return {
24
+ repoPath: gitRoot,
25
+ storagePath: paths.storagePath,
26
+ repoName: getInferredRepoName(gitRoot) ?? path.basename(gitRoot),
27
+ };
28
+ };
29
+ export const bootstrapCommand = async (opts = {}) => {
30
+ const repo = await resolveRepoForGraphpack();
31
+ const result = await bootstrapGraphpack({
32
+ repoPath: repo.repoPath,
33
+ storagePath: repo.storagePath,
34
+ lockPath: opts.lock ? path.resolve(opts.lock) : undefined,
35
+ artifactDir: opts.artifactDir ? path.resolve(opts.artifactDir) : undefined,
36
+ });
37
+ await maybeRegisterRepo(repo);
38
+ if (opts.materialize !== false && result.materializable) {
39
+ await materializeGraphpackHead(result.status.lock?.graphpack.graphstoreHeadCommit);
40
+ }
41
+ if (opts.json) {
42
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
43
+ return;
44
+ }
45
+ printPullLikeResult('bootstrap', result);
46
+ };
47
+ export const graphpackPublishCommand = async (opts = {}) => {
48
+ const repo = await resolveRepoForGraphpack();
49
+ const result = await publishGraphpack({
50
+ repoPath: repo.repoPath,
51
+ storagePath: repo.storagePath,
52
+ repoName: opts.repo ?? repo.repoName,
53
+ analyzerVersion: pkg.version,
54
+ target: opts.target ?? 'main',
55
+ artifactDir: opts.artifactDir ? path.resolve(opts.artifactDir) : undefined,
56
+ artifactUrl: opts.artifactUrl,
57
+ baseSnapshotId: opts.baseSnapshot,
58
+ headSnapshotId: opts.headSnapshot,
59
+ pullRequest: opts.pr,
60
+ });
61
+ if (opts.json) {
62
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
63
+ return;
64
+ }
65
+ process.stdout.write([
66
+ `graphpack: ${result.lock.graphpack.id}`,
67
+ `target: ${result.lock.graphpack.target}`,
68
+ `lock: ${result.lockPath}`,
69
+ `manifest: ${result.manifestPath}`,
70
+ `snapshot: ${result.lock.graphpack.graphstoreSnapshot ?? '(unknown)'}`,
71
+ `chunks: ${result.lock.chunks.length}`,
72
+ ].join('\n') + '\n');
73
+ };
74
+ export const graphpackPullCommand = async (opts = {}) => {
75
+ const repo = await resolveRepoForGraphpack();
76
+ const result = await pullGraphpack({
77
+ repoPath: repo.repoPath,
78
+ storagePath: repo.storagePath,
79
+ lockPath: opts.lock ? path.resolve(opts.lock) : undefined,
80
+ artifactDir: opts.artifactDir ? path.resolve(opts.artifactDir) : undefined,
81
+ });
82
+ await maybeRegisterRepo(repo);
83
+ if (opts.materialize !== false && result.materializable) {
84
+ await materializeGraphpackHead(result.status.lock?.graphpack.graphstoreHeadCommit);
85
+ }
86
+ if (opts.json) {
87
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
88
+ return;
89
+ }
90
+ printPullLikeResult('pull', result);
91
+ };
92
+ export const graphpackStatusCommand = async (opts = {}) => {
93
+ const repo = await resolveRepoForGraphpack();
94
+ const status = await getGraphpackStatus({
95
+ repoPath: repo.repoPath,
96
+ storagePath: repo.storagePath,
97
+ lockPath: opts.lock ? path.resolve(opts.lock) : undefined,
98
+ strict: opts.strict,
99
+ });
100
+ if (opts.json) {
101
+ process.stdout.write(`${JSON.stringify(status, null, 2)}\n`);
102
+ return;
103
+ }
104
+ const lines = [
105
+ `source: ${status.source}`,
106
+ `lock: ${status.lockPresent ? status.lockPath : 'missing'}`,
107
+ `local_graphstore: ${status.local.graphstorePresent ? 'present' : 'missing'}`,
108
+ status.local.headCommit ? `local_head: ${status.local.headCommit}` : undefined,
109
+ status.lock?.graphpack.graphstoreSnapshot
110
+ ? `lock_snapshot: ${status.lock.graphpack.graphstoreSnapshot}`
111
+ : undefined,
112
+ `chunks: ${status.chunks.verified}/${status.chunks.expected} verified`,
113
+ `compatible: ${status.compatibility.ok ? 'yes' : 'no'}`,
114
+ ].filter(Boolean);
115
+ if (status.compatibility.reasons.length > 0) {
116
+ lines.push('reasons:');
117
+ for (const reason of status.compatibility.reasons)
118
+ lines.push(` - ${reason}`);
119
+ }
120
+ if (status.chunks.missing.length > 0) {
121
+ lines.push('missing:');
122
+ for (const chunk of status.chunks.missing)
123
+ lines.push(` - ${chunk}`);
124
+ }
125
+ process.stdout.write(`${lines.join('\n')}\n`);
126
+ };
127
+ export const semanticAnalyzeCommand = async (opts = {}) => {
128
+ const repo = await resolveRepoForGraphpack();
129
+ const report = await analyzeSemanticRelationships({
130
+ storagePath: repo.storagePath,
131
+ llm: opts.llm,
132
+ write: opts.write !== false,
133
+ limit: opts.limit ? Number.parseInt(opts.limit, 10) : undefined,
134
+ });
135
+ if (opts.json) {
136
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
137
+ return;
138
+ }
139
+ const lines = [
140
+ `snapshot: ${report.snapshotId ?? '(unknown)'}`,
141
+ `extractor: ${report.extractorVersion}`,
142
+ `llm: ${report.llmEnabled ? 'enabled' : 'disabled'}`,
143
+ `relationships: ${report.relationships.length}`,
144
+ ];
145
+ for (const [family, count] of Object.entries(report.summary)) {
146
+ if (count > 0)
147
+ lines.push(` ${family}: ${count}`);
148
+ }
149
+ process.stdout.write(`${lines.join('\n')}\n`);
150
+ };
151
+ export const recipesLookupCommand = async (opts = {}) => {
152
+ if (!opts.taskFamily)
153
+ throw new Error('recipes lookup requires --task-family <name>');
154
+ const repo = await resolveRepoForGraphpack();
155
+ const snapshotId = opts.snapshotId ??
156
+ (await getGraphpackStatus({ repoPath: repo.repoPath, storagePath: repo.storagePath })).lock
157
+ ?.graphpack.graphstoreSnapshot;
158
+ if (!snapshotId) {
159
+ throw new Error('recipes lookup requires --snapshot-id when no graphpack lock is available.');
160
+ }
161
+ const moduleId = '@codragraph/harness/mcp/handler';
162
+ const mod = (await import(/* @vite-ignore */ moduleId));
163
+ if (!mod.handleHarnessRecipesLookup) {
164
+ throw new Error('@codragraph/harness/mcp/handler does not export handleHarnessRecipesLookup');
165
+ }
166
+ const result = await mod.handleHarnessRecipesLookup({
167
+ task_family: opts.taskFamily,
168
+ snapshot_id: snapshotId,
169
+ recipe_store: opts.recipeStore ?? path.join(repo.storagePath, 'recipes'),
170
+ required_subgraph_signature: opts.requiredSubgraphSignature,
171
+ limit: opts.limit ? Number.parseInt(opts.limit, 10) : undefined,
172
+ });
173
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
174
+ };
175
+ export const teamServeCommand = async (opts = {}) => {
176
+ const repo = await resolveRepoForGraphpack();
177
+ const status = await getGraphpackStatus({
178
+ repoPath: repo.repoPath,
179
+ storagePath: repo.storagePath,
180
+ });
181
+ if (opts.graphpack && status.lock?.graphpack.id !== opts.graphpack) {
182
+ throw new Error(`Requested graphpack ${opts.graphpack}, but lock points at ${status.lock?.graphpack.id ?? '(none)'}. Run graphpack pull or pass the matching id.`);
183
+ }
184
+ process.env.CODRAGRAPH_TEAM_GRAPH_MODE = '1';
185
+ process.env.CODRAGRAPH_ACTIVE_GRAPHPACK = opts.graphpack ?? status.lock?.graphpack.id ?? '';
186
+ const { serveCommand } = await import('./serve.js');
187
+ await serveCommand({ port: opts.port, host: opts.host, web: opts.web ?? 'hosted' });
188
+ };
189
+ const maybeRegisterRepo = async (repo) => {
190
+ const indexed = await findRepo(repo.repoPath);
191
+ if (!indexed?.meta)
192
+ return;
193
+ await registerRepo(repo.repoPath, indexed.meta);
194
+ };
195
+ const materializeGraphpackHead = async (headCommit) => {
196
+ if (!headCommit)
197
+ return;
198
+ const { checkoutCommand } = await import('./graphstore.js');
199
+ await checkoutCommand(headCommit, { materialize: true });
200
+ };
201
+ const printPullLikeResult = (label, result) => {
202
+ if (result.fallbackRequired) {
203
+ process.stdout.write([
204
+ `${label}: fallback required`,
205
+ `reason: ${result.reason ?? 'graphpack is not available locally'}`,
206
+ `fallback: ${result.fallbackCommand ?? 'codragraph analyze --skip-agents-md --no-setup'}`,
207
+ ].join('\n') + '\n');
208
+ process.exitCode = 1;
209
+ return;
210
+ }
211
+ process.stdout.write([
212
+ `${label}: ok`,
213
+ `source: ${result.status.source}`,
214
+ `graphpack: ${result.status.lock?.graphpack.id ?? '(none)'}`,
215
+ `materializable: ${result.materializable ? 'yes' : 'no'}`,
216
+ ].join('\n') + '\n');
217
+ };
package/dist/cli/index.js CHANGED
@@ -37,7 +37,9 @@ program
37
37
  .command('analyze [path]')
38
38
  .description('Index a repository (full analysis)')
39
39
  .option('-f, --force', 'Force full re-index even if up to date')
40
- .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)')
41
43
  .option('--skills', 'Generate repo-specific skill files from detected communities')
42
44
  .option('--skill-targets <list>', 'CSV of editor targets for --skills (claude, cursor, opencode, codex). Default: claude.')
43
45
  .option('--skip-agents-md', 'Skip updating the codragraph section in AGENTS.md and CLAUDE.md')
@@ -50,7 +52,7 @@ program
50
52
  .option('-v, --verbose', 'Enable verbose ingestion warnings (default: false)')
51
53
  .option('--max-file-size <kb>', 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).')
52
54
  .option('--no-setup', 'Skip the first-run editor setup (auto-runs once when ~/.codragraph/registry.json is missing)')
53
- .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')
54
56
  .addHelpText('after', '\nEnvironment variables:\n' +
55
57
  ' CODRAGRAPH_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .codragraphignore)\n' +
56
58
  ' CODRAGRAPH_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n' +
@@ -92,6 +94,14 @@ program
92
94
  .command('status')
93
95
  .description('Show index status for current repo')
94
96
  .action(createLazyAction(() => import('./status.js'), 'statusCommand'));
97
+ program
98
+ .command('bootstrap')
99
+ .description('Bootstrap a local graph from .codragraph/index.lock.json when available')
100
+ .option('--lock <path>', 'Path to graphpack lock file')
101
+ .option('--artifact-dir <path>', 'Local graphpack artifact directory to pull from')
102
+ .option('--no-materialize', 'Validate/pull graphpack chunks without rebuilding the local cgdb')
103
+ .option('--json', 'Emit machine-readable JSON')
104
+ .action(createLazyAction(() => import('./graphpack.js'), 'bootstrapCommand'));
95
105
  program
96
106
  .command('clean')
97
107
  .description('Delete CodraGraph index for current repo')
@@ -141,13 +151,17 @@ program
141
151
  .option('-r, --repo <name>', 'Target repository')
142
152
  .option('-u, --uid <uid>', 'Direct symbol UID (zero-ambiguity lookup)')
143
153
  .option('-f, --file <path>', 'File path to disambiguate common names')
154
+ .option('-k, --kind <kind>', 'Symbol kind to disambiguate common names')
144
155
  .option('--content', 'Include full symbol source code')
145
156
  .action(createOneShotLazyAction(() => import('./tool.js'), 'contextCommand'));
146
157
  program
147
- .command('impact <target>')
158
+ .command('impact [target]')
148
159
  .description('Blast radius analysis: what breaks if you change a symbol')
149
160
  .option('-d, --direction <dir>', 'upstream (dependants) or downstream (dependencies)', 'upstream')
150
161
  .option('-r, --repo <name>', 'Target repository')
162
+ .option('-u, --uid <uid>', 'Direct target symbol UID (zero-ambiguity lookup)')
163
+ .option('-f, --file <path>', 'File path to disambiguate common names')
164
+ .option('-k, --kind <kind>', 'Symbol kind to disambiguate common names')
151
165
  .option('--depth <n>', 'Max relationship depth (default: 3)')
152
166
  .option('--include-tests', 'Include test files in results')
153
167
  .action(createOneShotLazyAction(() => import('./tool.js'), 'impactCommand'));
@@ -185,6 +199,7 @@ program
185
199
  .description('Generate the compact agent context pack for a feature cluster')
186
200
  .option('-r, --repo <name>', 'Target repository')
187
201
  .option('-l, --limit <n>', 'Max members to return (default: 100)')
202
+ .option('--compress <level>', 'Compression level: balanced, lean, or max')
188
203
  .action(createOneShotLazyAction(() => import('./tool.js'), 'contextPackCommand'));
189
204
  program
190
205
  .command('cluster-impact <name>')
@@ -209,6 +224,69 @@ program
209
224
  .option('--idle-timeout <seconds>', 'Auto-shutdown after N seconds idle (0 = disabled)', '0')
210
225
  .action(createLazyAction(() => import('./eval-server.js'), 'evalServerCommand'));
211
226
  registerGroupCommands(program);
227
+ const graphpackCmd = program
228
+ .command('graphpack')
229
+ .description('Publish, pull, and inspect team graphpack artifacts');
230
+ graphpackCmd
231
+ .command('publish')
232
+ .description('Publish a graphpack lock/manifest for main or PR artifact workflows')
233
+ .option('--target <target>', 'Graphpack target: main or pr', 'main')
234
+ .option('--repo <name>', 'Repository identity stored in the lock')
235
+ .option('--artifact-dir <path>', 'Local artifact staging directory')
236
+ .option('--artifact-url <url>', 'Remote artifact URL recorded in the lock')
237
+ .option('--base-snapshot <id>', 'PR overlay base snapshot id')
238
+ .option('--head-snapshot <id>', 'PR overlay head snapshot id')
239
+ .option('--pr <ref>', 'Pull request number or URL for overlay graphpacks')
240
+ .option('--json', 'Emit machine-readable JSON')
241
+ .action(createLazyAction(() => import('./graphpack.js'), 'graphpackPublishCommand'));
242
+ graphpackCmd
243
+ .command('pull')
244
+ .description('Pull graphpack chunks and prepare local materialization')
245
+ .option('--lock <path>', 'Path to graphpack lock file')
246
+ .option('--artifact-dir <path>', 'Local graphpack artifact directory to pull from')
247
+ .option('--no-materialize', 'Pull/validate without rebuilding the local cgdb')
248
+ .option('--json', 'Emit machine-readable JSON')
249
+ .action(createLazyAction(() => import('./graphpack.js'), 'graphpackPullCommand'));
250
+ graphpackCmd
251
+ .command('status', { isDefault: true })
252
+ .description('Show graphpack lock, chunk, and local materialization status')
253
+ .option('--lock <path>', 'Path to graphpack lock file')
254
+ .option('--strict', 'Recompute graphstore CAS digest instead of trusting local presence')
255
+ .option('--json', 'Emit machine-readable JSON')
256
+ .action(createLazyAction(() => import('./graphpack.js'), 'graphpackStatusCommand'));
257
+ const semanticCmd = program
258
+ .command('semantic')
259
+ .description('Analyze developer-intent semantic relationships above raw graph edges');
260
+ semanticCmd
261
+ .command('analyze', { isDefault: true })
262
+ .description('Extract semantic relationship families with confidence and evidence')
263
+ .option('--llm', 'Allow optional LLM-inferred semantic edges when provider support is configured')
264
+ .option('--limit <n>', 'Maximum semantic relationships to return', '1000')
265
+ .option('--no-write', 'Do not write .codragraph/semantic-relationships.json')
266
+ .option('--json', 'Emit machine-readable JSON')
267
+ .action(createLazyAction(() => import('./graphpack.js'), 'semanticAnalyzeCommand'));
268
+ const recipesCmd = program
269
+ .command('recipes')
270
+ .description('Lookup graph-snapshot keyed harness recipes');
271
+ recipesCmd
272
+ .command('lookup')
273
+ .description('Find reusable harness recipes for a task family and graph snapshot')
274
+ .requiredOption('--task-family <name>', 'Task family identifier')
275
+ .option('--snapshot-id <id>', 'Graph snapshot id. Defaults to graphpack lock snapshot.')
276
+ .option('--required-subgraph-signature <sig>', 'Subgraph signature needed by the task')
277
+ .option('--recipe-store <path>', 'Recipe store root')
278
+ .option('--limit <n>', 'Max entries per match kind', '10')
279
+ .option('--json', 'Emit machine-readable JSON')
280
+ .action(createLazyAction(() => import('./graphpack.js'), 'recipesLookupCommand'));
281
+ const teamCmd = program.command('team').description('Team graph server commands');
282
+ teamCmd
283
+ .command('serve')
284
+ .description('Start hosted/team MCP-compatible HTTP mode for a graphpack')
285
+ .option('--graphpack <id>', 'Graphpack id to serve')
286
+ .option('-p, --port <port>', 'Port number', '4747')
287
+ .option('--host <host>', 'Bind address')
288
+ .option('--web <mode>', 'Dashboard mode: hosted, local, or off', 'hosted')
289
+ .action(createLazyAction(() => import('./graphpack.js'), 'teamServeCommand'));
212
290
  // ─── Config: unified API-key model (~/.codragraph/config.json) ─────
213
291
  const configCmd = program
214
292
  .command('config')
@@ -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 () => {