@codragraph/cli 2.1.6 → 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 (72) hide show
  1. package/README.md +7 -7
  2. package/dist/cli/graphpack.d.ts +48 -0
  3. package/dist/cli/graphpack.js +217 -0
  4. package/dist/cli/index.js +72 -0
  5. package/dist/cli/tool.d.ts +1 -0
  6. package/dist/cli/tool.js +111 -2
  7. package/dist/core/graphpack/index.d.ts +14 -0
  8. package/dist/core/graphpack/index.js +474 -0
  9. package/dist/core/graphpack/types.d.ts +129 -0
  10. package/dist/core/graphpack/types.js +4 -0
  11. package/dist/core/semantic/relationships.d.ts +36 -0
  12. package/dist/core/semantic/relationships.js +261 -0
  13. package/dist/mcp/local/local-backend.js +42 -0
  14. package/dist/mcp/resources.js +125 -0
  15. package/dist/mcp/tools.js +105 -0
  16. package/dist/server/api.js +112 -0
  17. package/dist/web/assets/agent-CQNZQ-hg.js +1139 -0
  18. package/dist/web/assets/{architectureDiagram-UL44E2DR-DFSpa3Hb.js → architectureDiagram-UL44E2DR-B5_goS_i.js} +1 -1
  19. package/dist/web/assets/{blockDiagram-7IZFK4PR-DlFaxH1b.js → blockDiagram-7IZFK4PR-D7ZAlDyv.js} +1 -1
  20. package/dist/web/assets/{c4Diagram-Y2BXMSZH-BjJ_Yrim.js → c4Diagram-Y2BXMSZH-Djcgm_54.js} +1 -1
  21. package/dist/web/assets/{chunk-3SSMPTDK-KGZSzG3Y.js → chunk-3SSMPTDK-Cv2Zy2FO.js} +1 -1
  22. package/dist/web/assets/{chunk-6764PJDD-p1sGJgVm.js → chunk-6764PJDD-Cppb-jH-.js} +1 -1
  23. package/dist/web/assets/{chunk-AZZRMDJM-DIDkQA4V.js → chunk-AZZRMDJM-BHlLC7p3.js} +1 -1
  24. package/dist/web/assets/{chunk-JQRUD6KW-DAwg-yCU.js → chunk-JQRUD6KW-3F8Zg-1N.js} +1 -1
  25. package/dist/web/assets/{chunk-KRXBNO2N-ChVO_XdS.js → chunk-KRXBNO2N-C0mbN9a7.js} +1 -1
  26. package/dist/web/assets/{chunk-LCXTWHL2-DGYdb_Eh.js → chunk-LCXTWHL2-BoiuJpIF.js} +1 -1
  27. package/dist/web/assets/{chunk-LII3EMHJ-Bzh9SNgD.js → chunk-LII3EMHJ-Dqq0Qguw.js} +1 -1
  28. package/dist/web/assets/{chunk-RG4AUYOV-Bcl7U_IV.js → chunk-RG4AUYOV-Bl5F_gDs.js} +1 -1
  29. package/dist/web/assets/{chunk-T5OCTHI4-CZYMg5sc.js → chunk-T5OCTHI4-B2tIcggA.js} +1 -1
  30. package/dist/web/assets/{chunk-W44A43WB-REOI67PN.js → chunk-W44A43WB-BHe37iN7.js} +1 -1
  31. package/dist/web/assets/{chunk-ZXARS5L4-BfFdV1tf.js → chunk-ZXARS5L4-wcrIaQvY.js} +1 -1
  32. package/dist/web/assets/classDiagram-KGZ6W3CR-IbI6v_24.js +1 -0
  33. package/dist/web/assets/classDiagram-v2-72OJOZXJ-IbI6v_24.js +1 -0
  34. package/dist/web/assets/{cose-bilkent-UX7MHV2Q-D6vANJGG.js → cose-bilkent-UX7MHV2Q-BWr7v0Wr.js} +1 -1
  35. package/dist/web/assets/{dagre-ND4H6XIP-BiHe5Lal.js → dagre-ND4H6XIP-De5LIh1B.js} +1 -1
  36. package/dist/web/assets/{diagram-3NCE3AQN-CEutBCOW.js → diagram-3NCE3AQN-Dd22FSHy.js} +1 -1
  37. package/dist/web/assets/{diagram-GF46GFSD-CZns6HPQ.js → diagram-GF46GFSD-Cev3THY8.js} +1 -1
  38. package/dist/web/assets/{diagram-HNR7UZ2L-Vz8fE5of.js → diagram-HNR7UZ2L-D8Z8RQGs.js} +1 -1
  39. package/dist/web/assets/{diagram-QXG6HAR7-D60HKZ_y.js → diagram-QXG6HAR7-B8VOJOiE.js} +1 -1
  40. package/dist/web/assets/{diagram-WEQXMOUZ-vGAf1p3E.js → diagram-WEQXMOUZ-va1bLoMD.js} +1 -1
  41. package/dist/web/assets/{erDiagram-L5TCEMPS-DZaplJA6.js → erDiagram-L5TCEMPS-B3_9uAoP.js} +1 -1
  42. package/dist/web/assets/{flowDiagram-H6V6AXG4-BqUqeAsI.js → flowDiagram-H6V6AXG4-98m6maI1.js} +1 -1
  43. package/dist/web/assets/{ganttDiagram-JCBTUEKG-XEB6H-0G.js → ganttDiagram-JCBTUEKG-vE2nzETb.js} +1 -1
  44. package/dist/web/assets/{gitGraphDiagram-S2ZK5IYY-7G50u1Cd.js → gitGraphDiagram-S2ZK5IYY-DKc8uUg_.js} +1 -1
  45. package/dist/web/assets/index-BAhe1HSk.css +1 -0
  46. package/dist/web/assets/{index-B5WxtMpv.js → index-VTKdaklA.js} +230 -230
  47. package/dist/web/assets/{infoDiagram-3YFTVSEB-Cut_rzaf.js → infoDiagram-3YFTVSEB-DYP-Srzx.js} +1 -1
  48. package/dist/web/assets/{ishikawaDiagram-BNXS4ZKH-B4DGfGi3.js → ishikawaDiagram-BNXS4ZKH-QZnkpmmb.js} +1 -1
  49. package/dist/web/assets/{journeyDiagram-M6C3CM3L-BBFhsL3E.js → journeyDiagram-M6C3CM3L-B5ojIuqu.js} +1 -1
  50. package/dist/web/assets/{kanban-definition-75IXJCU3-DarGRyn3.js → kanban-definition-75IXJCU3-BJA8liRR.js} +1 -1
  51. package/dist/web/assets/{katex-K3KEBU37-W5XTYMhr.js → katex-K3KEBU37-DUqZiCRL.js} +1 -1
  52. package/dist/web/assets/{mindmap-definition-2TDM6QVE-BgeczIJM.js → mindmap-definition-2TDM6QVE-BQj5yylD.js} +1 -1
  53. package/dist/web/assets/{pieDiagram-CU6KROY3-Kkoo-Noq.js → pieDiagram-CU6KROY3-4eSrPiQz.js} +1 -1
  54. package/dist/web/assets/{quadrantDiagram-VICAPDV7-CDQFeRWN.js → quadrantDiagram-VICAPDV7-PzxN8j55.js} +1 -1
  55. package/dist/web/assets/{requirementDiagram-JXO7QTGE-Cz9-XnkA.js → requirementDiagram-JXO7QTGE-CtplTc5y.js} +1 -1
  56. package/dist/web/assets/{sankeyDiagram-URQDO5SZ-CU26z0n7.js → sankeyDiagram-URQDO5SZ-CoSgvkxv.js} +1 -1
  57. package/dist/web/assets/{sequenceDiagram-VS2MUI6T-OGK1FLOt.js → sequenceDiagram-VS2MUI6T-D7ygyXvJ.js} +1 -1
  58. package/dist/web/assets/{stateDiagram-7D4R322I-DJ9brq0U.js → stateDiagram-7D4R322I-v01gvwji.js} +1 -1
  59. package/dist/web/assets/stateDiagram-v2-36443NZ5-DFD2b8_x.js +1 -0
  60. package/dist/web/assets/{timeline-definition-O6YCAMPW-XZvnjqTT.js → timeline-definition-O6YCAMPW-CTI3M65J.js} +1 -1
  61. package/dist/web/assets/{vennDiagram-MWXL3ELB-CJUssEjA.js → vennDiagram-MWXL3ELB-RnB0XMP7.js} +1 -1
  62. package/dist/web/assets/{wardley-L42UT6IY-5TKZOOLJ-DZr11zBG.js → wardley-L42UT6IY-5TKZOOLJ-C-ZcgEBb.js} +1 -1
  63. package/dist/web/assets/{wardleyDiagram-CUQ6CDDI-C276iqrN.js → wardleyDiagram-CUQ6CDDI-EwRi4kwo.js} +1 -1
  64. package/dist/web/assets/{xychartDiagram-N2JHSOCM-B9-uCZyP.js → xychartDiagram-N2JHSOCM-DA38II6y.js} +1 -1
  65. package/dist/web/index.html +2 -2
  66. package/package.json +2 -2
  67. package/dist/web/assets/__vite-browser-external-BIHI7g3E.js +0 -1
  68. package/dist/web/assets/agent-DcdaQnmu.js +0 -1104
  69. package/dist/web/assets/classDiagram-KGZ6W3CR-B-qkKMYi.js +0 -1
  70. package/dist/web/assets/classDiagram-v2-72OJOZXJ-B-qkKMYi.js +0 -1
  71. package/dist/web/assets/index-CT0GtFLZ.css +0 -1
  72. package/dist/web/assets/stateDiagram-v2-36443NZ5-DhJ4Ky-7.js +0 -1
package/README.md CHANGED
@@ -65,16 +65,16 @@ If you prefer to configure manually instead of using `codragraph setup`:
65
65
 
66
66
  ```bash
67
67
  # macOS / Linux
68
- claude mcp add codragraph -- npx -y @codragraph/cli@2.1.6 mcp
68
+ claude mcp add codragraph -- npx -y @codragraph/cli@2.2.0-rc.6 mcp
69
69
 
70
70
  # Windows
71
- claude mcp add codragraph -- cmd /c npx -y @codragraph/cli@2.1.6 mcp
71
+ claude mcp add codragraph -- cmd /c npx -y @codragraph/cli@2.2.0-rc.6 mcp
72
72
  ```
73
73
 
74
74
  ### Codex (full support — MCP + skills)
75
75
 
76
76
  ```bash
77
- codex mcp add codragraph -- npx -y @codragraph/cli@2.1.6 mcp
77
+ codex mcp add codragraph -- npx -y @codragraph/cli@2.2.0-rc.6 mcp
78
78
  ```
79
79
 
80
80
  ### Cursor / Windsurf
@@ -86,7 +86,7 @@ Add to `~/.cursor/mcp.json` (global — works for all projects):
86
86
  "mcpServers": {
87
87
  "codragraph": {
88
88
  "command": "npx",
89
- "args": ["-y", "@codragraph/cli@2.1.6", "mcp"]
89
+ "args": ["-y", "@codragraph/cli@2.2.0-rc.6", "mcp"]
90
90
  }
91
91
  }
92
92
  }
@@ -101,7 +101,7 @@ Add to `~/.config/opencode/config.json`:
101
101
  "mcp": {
102
102
  "codragraph": {
103
103
  "command": "npx",
104
- "args": ["-y", "@codragraph/cli@2.1.6", "mcp"]
104
+ "args": ["-y", "@codragraph/cli@2.2.0-rc.6", "mcp"]
105
105
  }
106
106
  }
107
107
  }
@@ -309,9 +309,9 @@ It is fixed in **codragraph v1.6.2+**. Upgrade to the current workspace
309
309
  version, or pin the version your team has validated:
310
310
 
311
311
  ```bash
312
- npx @codragraph/cli@2.1.6 analyze # no global install
312
+ npx @codragraph/cli@2.2.0-rc.6 analyze # no global install
313
313
  # or
314
- npm install -g @codragraph/cli@2.1.6 # upgrade a global install
314
+ npm install -g @codragraph/cli@2.2.0-rc.6 # upgrade a global install
315
315
  ```
316
316
 
317
317
  If you still hit npm install issues after upgrading, these generic workarounds
@@ -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
@@ -94,6 +94,14 @@ program
94
94
  .command('status')
95
95
  .description('Show index status for current repo')
96
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'));
97
105
  program
98
106
  .command('clean')
99
107
  .description('Delete CodraGraph index for current repo')
@@ -191,6 +199,7 @@ program
191
199
  .description('Generate the compact agent context pack for a feature cluster')
192
200
  .option('-r, --repo <name>', 'Target repository')
193
201
  .option('-l, --limit <n>', 'Max members to return (default: 100)')
202
+ .option('--compress <level>', 'Compression level: balanced, lean, or max')
194
203
  .action(createOneShotLazyAction(() => import('./tool.js'), 'contextPackCommand'));
195
204
  program
196
205
  .command('cluster-impact <name>')
@@ -215,6 +224,69 @@ program
215
224
  .option('--idle-timeout <seconds>', 'Auto-shutdown after N seconds idle (0 = disabled)', '0')
216
225
  .action(createLazyAction(() => import('./eval-server.js'), 'evalServerCommand'));
217
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'));
218
290
  // ─── Config: unified API-key model (~/.codragraph/config.json) ─────
219
291
  const configCmd = program
220
292
  .command('config')
@@ -63,6 +63,7 @@ export declare function clusterContextCommand(name: string, options?: {
63
63
  export declare function contextPackCommand(name: string, options?: {
64
64
  repo?: string;
65
65
  limit?: string;
66
+ compress?: string;
66
67
  }): Promise<void>;
67
68
  export declare function clusterImpactCommand(name: string, options?: {
68
69
  direction?: string;
package/dist/cli/tool.js CHANGED
@@ -14,6 +14,7 @@
14
14
  * native module which captures the Node.js process.stdout stream during init.
15
15
  * See the output() function for details (#324).
16
16
  */
17
+ import crypto from 'node:crypto';
17
18
  import { writeSync } from 'node:fs';
18
19
  import { LocalBackend } from '../mcp/local/local-backend.js';
19
20
  import { emitTokenStats } from './compress-stats.js';
@@ -238,8 +239,116 @@ export async function contextPackCommand(name, options) {
238
239
  repo,
239
240
  limit: options?.limit ? parseInt(options.limit, 10) : undefined,
240
241
  });
241
- output(result);
242
- emitTokenStats(result);
242
+ const maybeCompressed = options?.compress
243
+ ? compressContextPackForCli(result, name, options.compress)
244
+ : result;
245
+ output(maybeCompressed);
246
+ emitTokenStats(maybeCompressed);
247
+ }
248
+ function compressContextPackForCli(result, featureName, rawLevel) {
249
+ const level = normalizeCliCompressionLevel(rawLevel);
250
+ const originalText = JSON.stringify(result);
251
+ const compressed = pruneContextPack(result, level);
252
+ const compressedText = JSON.stringify(compressed);
253
+ const originalTokens = estimateJsonTokens(originalText);
254
+ const compressedTokens = estimateJsonTokens(compressedText);
255
+ const snapshotId = result?.snapshotId ??
256
+ result?.snapshot_id ??
257
+ result?.cluster?.lastIndexedCommit ??
258
+ result?.cluster?.snapshotId ??
259
+ 'unknown';
260
+ const clusterId = result?.cluster?.id ?? result?.cluster?.slug ?? featureName;
261
+ const cacheKey = crypto
262
+ .createHash('sha256')
263
+ .update(`${snapshotId}\n${clusterId}\n${level}\ncli-context-pack-compressor-v1`)
264
+ .digest('hex');
265
+ return {
266
+ ...compressed,
267
+ compression: {
268
+ level,
269
+ compressorVersion: 'cli-context-pack-compressor-v1',
270
+ cacheKey: `ctxpack:${cacheKey.slice(0, 32)}`,
271
+ originalTokens,
272
+ compressedTokens,
273
+ tokenSavingsPct: originalTokens > 0
274
+ ? Number((((originalTokens - compressedTokens) / originalTokens) * 100).toFixed(1))
275
+ : 0,
276
+ preserved: [
277
+ 'feature cluster',
278
+ 'files',
279
+ 'line ranges',
280
+ 'symbols',
281
+ 'tests',
282
+ 'routes',
283
+ 'tools',
284
+ 'dependencies',
285
+ 'warnings',
286
+ ],
287
+ },
288
+ };
289
+ }
290
+ function normalizeCliCompressionLevel(raw) {
291
+ if (raw === 'balanced' || raw === 'lean' || raw === 'max')
292
+ return raw;
293
+ throw new Error('context-pack --compress must be one of: balanced, lean, max');
294
+ }
295
+ function pruneContextPack(value, level) {
296
+ if (!value || typeof value !== 'object')
297
+ return value;
298
+ const memberLimit = level === 'max' ? 20 : level === 'lean' ? 40 : 80;
299
+ const processLimit = level === 'max' ? 5 : level === 'lean' ? 8 : 15;
300
+ const supportLimit = level === 'max' ? 5 : level === 'lean' ? 10 : 20;
301
+ return {
302
+ cluster: value.cluster,
303
+ members: Array.isArray(value.members)
304
+ ? value.members.slice(0, memberLimit).map(compactContextPackItem)
305
+ : value.members,
306
+ entryPoints: Array.isArray(value.entryPoints)
307
+ ? value.entryPoints.slice(0, supportLimit).map(compactContextPackItem)
308
+ : value.entryPoints,
309
+ routes: value.routes,
310
+ tools: value.tools,
311
+ dependencies: value.dependencies,
312
+ processes: Array.isArray(value.processes)
313
+ ? value.processes.slice(0, processLimit).map(compactContextPackItem)
314
+ : value.processes,
315
+ tests: Array.isArray(value.tests)
316
+ ? value.tests.slice(0, supportLimit).map(compactContextPackItem)
317
+ : value.tests,
318
+ docs: Array.isArray(value.docs)
319
+ ? value.docs.slice(0, supportLimit).map(compactContextPackItem)
320
+ : value.docs,
321
+ warnings: value.warnings ?? value.safeEditSurface?.warnings,
322
+ safeEditSurface: value.safeEditSurface,
323
+ };
324
+ }
325
+ function compactContextPackItem(item) {
326
+ if (!item || typeof item !== 'object')
327
+ return item;
328
+ const keys = [
329
+ 'id',
330
+ 'uid',
331
+ 'name',
332
+ 'type',
333
+ 'kind',
334
+ 'filePath',
335
+ 'file',
336
+ 'startLine',
337
+ 'endLine',
338
+ 'route',
339
+ 'method',
340
+ 'summary',
341
+ 'confidence',
342
+ ];
343
+ const compact = {};
344
+ for (const key of keys) {
345
+ if (item[key] !== undefined)
346
+ compact[key] = item[key];
347
+ }
348
+ return compact;
349
+ }
350
+ function estimateJsonTokens(text) {
351
+ return Math.ceil(text.length / 4);
243
352
  }
244
353
  export async function clusterImpactCommand(name, options) {
245
354
  if (!name?.trim()) {
@@ -0,0 +1,14 @@
1
+ import { type GraphpackBootstrapResult, type GraphpackPublishOptions, type GraphpackPublishResult, type GraphpackPullOptions, type GraphpackPullResult, type GraphpackStatus, type GraphpackLock } from './types.js';
2
+ export * from './types.js';
3
+ export declare const defaultLockPath: (repoPath: string) => string;
4
+ export declare const readGraphpackLock: (lockPath: string) => Promise<GraphpackLock | null>;
5
+ export declare const writeGraphpackLock: (lockPath: string, lock: GraphpackLock) => Promise<void>;
6
+ export declare const publishGraphpack: (opts: GraphpackPublishOptions) => Promise<GraphpackPublishResult>;
7
+ export declare const getGraphpackStatus: (opts: {
8
+ repoPath: string;
9
+ storagePath: string;
10
+ lockPath?: string;
11
+ strict?: boolean;
12
+ }) => Promise<GraphpackStatus>;
13
+ export declare const pullGraphpack: (opts: GraphpackPullOptions) => Promise<GraphpackPullResult>;
14
+ export declare const bootstrapGraphpack: (opts: GraphpackPullOptions) => Promise<GraphpackBootstrapResult>;