@reactgraph/cli 0.1.1

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 (178) hide show
  1. package/README.md +319 -0
  2. package/bun.lock +527 -0
  3. package/dist/cli/components/IndexProgress.d.ts +18 -0
  4. package/dist/cli/components/IndexProgress.d.ts.map +1 -0
  5. package/dist/cli/components/IndexProgress.js +26 -0
  6. package/dist/cli/components/IndexProgress.js.map +1 -0
  7. package/dist/cli/components/InitResult.d.ts +7 -0
  8. package/dist/cli/components/InitResult.d.ts.map +1 -0
  9. package/dist/cli/components/InitResult.js +6 -0
  10. package/dist/cli/components/InitResult.js.map +1 -0
  11. package/dist/cli/index-cmd.d.ts +7 -0
  12. package/dist/cli/index-cmd.d.ts.map +1 -0
  13. package/dist/cli/index-cmd.js +28 -0
  14. package/dist/cli/index-cmd.js.map +1 -0
  15. package/dist/cli/index.d.ts +3 -0
  16. package/dist/cli/index.d.ts.map +1 -0
  17. package/dist/cli/index.js +81 -0
  18. package/dist/cli/index.js.map +1 -0
  19. package/dist/cli/init.d.ts +8 -0
  20. package/dist/cli/init.d.ts.map +1 -0
  21. package/dist/cli/init.js +77 -0
  22. package/dist/cli/init.js.map +1 -0
  23. package/dist/cli/serve.d.ts +2 -0
  24. package/dist/cli/serve.d.ts.map +1 -0
  25. package/dist/cli/serve.js +28 -0
  26. package/dist/cli/serve.js.map +1 -0
  27. package/dist/cli/unused.d.ts +2 -0
  28. package/dist/cli/unused.d.ts.map +1 -0
  29. package/dist/cli/unused.js +56 -0
  30. package/dist/cli/unused.js.map +1 -0
  31. package/dist/graph/graph.d.ts +30 -0
  32. package/dist/graph/graph.d.ts.map +1 -0
  33. package/dist/graph/graph.js +166 -0
  34. package/dist/graph/graph.js.map +1 -0
  35. package/dist/graph/index.d.ts +5 -0
  36. package/dist/graph/index.d.ts.map +1 -0
  37. package/dist/graph/index.js +5 -0
  38. package/dist/graph/index.js.map +1 -0
  39. package/dist/graph/schema.d.ts +33 -0
  40. package/dist/graph/schema.d.ts.map +1 -0
  41. package/dist/graph/schema.js +3 -0
  42. package/dist/graph/schema.js.map +1 -0
  43. package/dist/graph/serialize.d.ts +7 -0
  44. package/dist/graph/serialize.d.ts.map +1 -0
  45. package/dist/graph/serialize.js +39 -0
  46. package/dist/graph/serialize.js.map +1 -0
  47. package/dist/graph/traverse.d.ts +14 -0
  48. package/dist/graph/traverse.d.ts.map +1 -0
  49. package/dist/graph/traverse.js +50 -0
  50. package/dist/graph/traverse.js.map +1 -0
  51. package/dist/mcp/formatter.d.ts +26 -0
  52. package/dist/mcp/formatter.d.ts.map +1 -0
  53. package/dist/mcp/formatter.js +691 -0
  54. package/dist/mcp/formatter.js.map +1 -0
  55. package/dist/mcp/server.d.ts +2 -0
  56. package/dist/mcp/server.d.ts.map +1 -0
  57. package/dist/mcp/server.js +45 -0
  58. package/dist/mcp/server.js.map +1 -0
  59. package/dist/mcp/tools.d.ts +9 -0
  60. package/dist/mcp/tools.d.ts.map +1 -0
  61. package/dist/mcp/tools.js +136 -0
  62. package/dist/mcp/tools.js.map +1 -0
  63. package/dist/output/ai-context.d.ts +7 -0
  64. package/dist/output/ai-context.d.ts.map +1 -0
  65. package/dist/output/ai-context.js +26 -0
  66. package/dist/output/ai-context.js.map +1 -0
  67. package/dist/parser/extractors/api-calls.d.ts +15 -0
  68. package/dist/parser/extractors/api-calls.d.ts.map +1 -0
  69. package/dist/parser/extractors/api-calls.js +168 -0
  70. package/dist/parser/extractors/api-calls.js.map +1 -0
  71. package/dist/parser/extractors/components.d.ts +5 -0
  72. package/dist/parser/extractors/components.d.ts.map +1 -0
  73. package/dist/parser/extractors/components.js +236 -0
  74. package/dist/parser/extractors/components.js.map +1 -0
  75. package/dist/parser/extractors/context.d.ts +14 -0
  76. package/dist/parser/extractors/context.d.ts.map +1 -0
  77. package/dist/parser/extractors/context.js +196 -0
  78. package/dist/parser/extractors/context.js.map +1 -0
  79. package/dist/parser/extractors/effects.d.ts +14 -0
  80. package/dist/parser/extractors/effects.d.ts.map +1 -0
  81. package/dist/parser/extractors/effects.js +175 -0
  82. package/dist/parser/extractors/effects.js.map +1 -0
  83. package/dist/parser/extractors/hooks.d.ts +5 -0
  84. package/dist/parser/extractors/hooks.d.ts.map +1 -0
  85. package/dist/parser/extractors/hooks.js +242 -0
  86. package/dist/parser/extractors/hooks.js.map +1 -0
  87. package/dist/parser/extractors/imports.d.ts +6 -0
  88. package/dist/parser/extractors/imports.d.ts.map +1 -0
  89. package/dist/parser/extractors/imports.js +148 -0
  90. package/dist/parser/extractors/imports.js.map +1 -0
  91. package/dist/parser/extractors/index.d.ts +12 -0
  92. package/dist/parser/extractors/index.d.ts.map +1 -0
  93. package/dist/parser/extractors/index.js +11 -0
  94. package/dist/parser/extractors/index.js.map +1 -0
  95. package/dist/parser/extractors/jsx-tree.d.ts +5 -0
  96. package/dist/parser/extractors/jsx-tree.d.ts.map +1 -0
  97. package/dist/parser/extractors/jsx-tree.js +226 -0
  98. package/dist/parser/extractors/jsx-tree.js.map +1 -0
  99. package/dist/parser/extractors/routes.d.ts +13 -0
  100. package/dist/parser/extractors/routes.d.ts.map +1 -0
  101. package/dist/parser/extractors/routes.js +275 -0
  102. package/dist/parser/extractors/routes.js.map +1 -0
  103. package/dist/parser/extractors/state.d.ts +14 -0
  104. package/dist/parser/extractors/state.d.ts.map +1 -0
  105. package/dist/parser/extractors/state.js +368 -0
  106. package/dist/parser/extractors/state.js.map +1 -0
  107. package/dist/parser/extractors/types.d.ts +22 -0
  108. package/dist/parser/extractors/types.d.ts.map +1 -0
  109. package/dist/parser/extractors/types.js +51 -0
  110. package/dist/parser/extractors/types.js.map +1 -0
  111. package/dist/parser/indexer.d.ts +14 -0
  112. package/dist/parser/indexer.d.ts.map +1 -0
  113. package/dist/parser/indexer.js +167 -0
  114. package/dist/parser/indexer.js.map +1 -0
  115. package/dist/parser/pipeline.d.ts +16 -0
  116. package/dist/parser/pipeline.d.ts.map +1 -0
  117. package/dist/parser/pipeline.js +63 -0
  118. package/dist/parser/pipeline.js.map +1 -0
  119. package/dist/parser/setup.d.ts +4 -0
  120. package/dist/parser/setup.d.ts.map +1 -0
  121. package/dist/parser/setup.js +29 -0
  122. package/dist/parser/setup.js.map +1 -0
  123. package/dist/parser/walker.d.ts +6 -0
  124. package/dist/parser/walker.d.ts.map +1 -0
  125. package/dist/parser/walker.js +45 -0
  126. package/dist/parser/walker.js.map +1 -0
  127. package/dist/watcher.d.ts +12 -0
  128. package/dist/watcher.d.ts.map +1 -0
  129. package/dist/watcher.js +72 -0
  130. package/dist/watcher.js.map +1 -0
  131. package/package.json +51 -0
  132. package/src/cli/components/IndexProgress.tsx +79 -0
  133. package/src/cli/components/InitResult.tsx +28 -0
  134. package/src/cli/index-cmd.ts +41 -0
  135. package/src/cli/index.ts +92 -0
  136. package/src/cli/init.ts +97 -0
  137. package/src/cli/serve.ts +29 -0
  138. package/src/cli/unused.ts +88 -0
  139. package/src/graph/graph.ts +179 -0
  140. package/src/graph/index.ts +4 -0
  141. package/src/graph/schema.ts +68 -0
  142. package/src/graph/serialize.ts +40 -0
  143. package/src/graph/traverse.ts +66 -0
  144. package/src/mcp/formatter.ts +757 -0
  145. package/src/mcp/server.ts +59 -0
  146. package/src/mcp/tools.ts +154 -0
  147. package/src/output/ai-context.ts +29 -0
  148. package/src/parser/extractors/api-calls.ts +192 -0
  149. package/src/parser/extractors/components.ts +273 -0
  150. package/src/parser/extractors/context.ts +216 -0
  151. package/src/parser/extractors/effects.ts +205 -0
  152. package/src/parser/extractors/hooks.ts +268 -0
  153. package/src/parser/extractors/imports.ts +192 -0
  154. package/src/parser/extractors/index.ts +11 -0
  155. package/src/parser/extractors/jsx-tree.ts +271 -0
  156. package/src/parser/extractors/routes.ts +331 -0
  157. package/src/parser/extractors/state.ts +392 -0
  158. package/src/parser/extractors/types.ts +71 -0
  159. package/src/parser/indexer.ts +197 -0
  160. package/src/parser/pipeline.ts +89 -0
  161. package/src/parser/setup.ts +33 -0
  162. package/src/parser/walker.ts +61 -0
  163. package/src/watcher.ts +91 -0
  164. package/templates/CLAUDE.md +7 -0
  165. package/tests/extractors.test.ts +164 -0
  166. package/tests/fixtures/basic/src/App.tsx +12 -0
  167. package/tests/fixtures/basic/src/components/Dashboard.tsx +24 -0
  168. package/tests/fixtures/basic/src/components/MetricsCard.tsx +15 -0
  169. package/tests/fixtures/basic/src/components/Sidebar.tsx +20 -0
  170. package/tests/fixtures/basic/src/contexts/ThemeContext.tsx +16 -0
  171. package/tests/fixtures/basic/src/hooks/useAuth.ts +25 -0
  172. package/tests/fixtures/basic/src/stores/authStore.ts +15 -0
  173. package/tests/fixtures/basic/src/utils.ts +7 -0
  174. package/tests/graph.test.ts +91 -0
  175. package/tests/phase2.test.ts +309 -0
  176. package/tests/smoke.test.ts +77 -0
  177. package/tsconfig.json +20 -0
  178. package/vitest.config.ts +8 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/parser/indexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { GraphNode, GraphEdge } from '../graph/schema.js';
2
+ export interface PipelineResult {
3
+ nodes: GraphNode[];
4
+ edges: GraphEdge[];
5
+ filePath: string;
6
+ }
7
+ /**
8
+ * Run all extractors on a single file in order.
9
+ *
10
+ * @param globalNodes - Nodes from ALL previously-processed files.
11
+ * Cross-file extractors (state, context, hooks, jsx-tree) use this
12
+ * to resolve references to stores, contexts, and components defined
13
+ * in other files.
14
+ */
15
+ export declare function processFile(relativePath: string, projectDir: string, globalNodes?: GraphNode[]): Promise<PipelineResult>;
16
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/parser/pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAa/D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,WAAW,GAAE,SAAS,EAAO,GAC5B,OAAO,CAAC,cAAc,CAAC,CAuDzB"}
@@ -0,0 +1,63 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { parseFile } from './setup.js';
4
+ import { extractImports } from './extractors/imports.js';
5
+ import { extractComponents } from './extractors/components.js';
6
+ import { extractHooks } from './extractors/hooks.js';
7
+ import { extractJSXTree } from './extractors/jsx-tree.js';
8
+ import { extractContext } from './extractors/context.js';
9
+ import { extractState } from './extractors/state.js';
10
+ import { extractApiCalls } from './extractors/api-calls.js';
11
+ import { extractRoutes } from './extractors/routes.js';
12
+ import { extractEffects } from './extractors/effects.js';
13
+ /**
14
+ * Run all extractors on a single file in order.
15
+ *
16
+ * @param globalNodes - Nodes from ALL previously-processed files.
17
+ * Cross-file extractors (state, context, hooks, jsx-tree) use this
18
+ * to resolve references to stores, contexts, and components defined
19
+ * in other files.
20
+ */
21
+ export async function processFile(relativePath, projectDir, globalNodes = []) {
22
+ const absolutePath = resolve(projectDir, relativePath);
23
+ const sourceCode = await readFile(absolutePath, 'utf-8');
24
+ const tree = parseFile(relativePath, sourceCode);
25
+ if (!tree) {
26
+ return { nodes: [], edges: [], filePath: relativePath };
27
+ }
28
+ // allNodes = this file's nodes as they accumulate through extractors
29
+ const allNodes = [];
30
+ const allEdges = [];
31
+ // visibleNodes = this file's nodes + global nodes from other files
32
+ // Extractors see both when resolving cross-file references
33
+ function visibleNodes() {
34
+ return [...globalNodes, ...allNodes];
35
+ }
36
+ function run(extractor) {
37
+ const result = extractor(tree, relativePath, sourceCode, visibleNodes());
38
+ allNodes.push(...result.nodes);
39
+ allEdges.push(...result.edges);
40
+ }
41
+ // 1. Imports (creates Module nodes + import edges)
42
+ const importResult = extractImports(tree, relativePath, sourceCode, visibleNodes(), projectDir);
43
+ allNodes.push(...importResult.nodes);
44
+ allEdges.push(...importResult.edges);
45
+ // 2. Components
46
+ run(extractComponents);
47
+ // 3. Hooks
48
+ run(extractHooks);
49
+ // 4. JSX render tree
50
+ run(extractJSXTree);
51
+ // 5. Context (needs components/hooks for edge sources)
52
+ run(extractContext);
53
+ // 6. State management (needs components/hooks + cross-file stores)
54
+ run(extractState);
55
+ // 7. API calls (needs components/hooks for edge sources)
56
+ run(extractApiCalls);
57
+ // 8. Routes (needs components for linking)
58
+ run(extractRoutes);
59
+ // 9. Effects (annotates existing nodes — must run last)
60
+ run(extractEffects);
61
+ return { nodes: allNodes, edges: allEdges, filePath: relativePath };
62
+ }
63
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/parser/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AASzD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,YAAoB,EACpB,UAAkB,EAClB,cAA2B,EAAE;IAE7B,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAEjD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC1D,CAAC;IAED,qEAAqE;IACrE,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAgB,EAAE,CAAC;IAEjC,mEAAmE;IACnE,2DAA2D;IAC3D,SAAS,YAAY;QACnB,OAAO,CAAC,GAAG,WAAW,EAAE,GAAG,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,SAAS,GAAG,CAAC,SAAuF;QAClG,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;QACzE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,mDAAmD;IACnD,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC;IAChG,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACrC,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAErC,gBAAgB;IAChB,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEvB,WAAW;IACX,GAAG,CAAC,YAAY,CAAC,CAAC;IAElB,qBAAqB;IACrB,GAAG,CAAC,cAAc,CAAC,CAAC;IAEpB,uDAAuD;IACvD,GAAG,CAAC,cAAc,CAAC,CAAC;IAEpB,mEAAmE;IACnE,GAAG,CAAC,YAAY,CAAC,CAAC;IAElB,yDAAyD;IACzD,GAAG,CAAC,eAAe,CAAC,CAAC;IAErB,2CAA2C;IAC3C,GAAG,CAAC,aAAa,CAAC,CAAC;IAEnB,wDAAwD;IACxD,GAAG,CAAC,cAAc,CAAC,CAAC;IAEpB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACtE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import Parser from 'tree-sitter';
2
+ export declare function getParser(filePath: string): Parser | null;
3
+ export declare function parseFile(filePath: string, sourceCode: string): Parser.Tree | null;
4
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/parser/setup.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAuBjC,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,CAIlF"}
@@ -0,0 +1,29 @@
1
+ import Parser from 'tree-sitter';
2
+ // @ts-expect-error no declaration file for tree-sitter grammars
3
+ import TypeScript from 'tree-sitter-typescript/typescript';
4
+ // @ts-expect-error no declaration file for tree-sitter grammars
5
+ import TSX from 'tree-sitter-typescript/tsx';
6
+ import JavaScript from 'tree-sitter-javascript';
7
+ const tsParser = new Parser();
8
+ tsParser.setLanguage(TypeScript);
9
+ const tsxParser = new Parser();
10
+ tsxParser.setLanguage(TSX);
11
+ const jsParser = new Parser();
12
+ jsParser.setLanguage(JavaScript);
13
+ const EXT_MAP = {
14
+ '.ts': tsParser,
15
+ '.tsx': tsxParser,
16
+ '.js': jsParser,
17
+ '.jsx': tsxParser, // JSX uses TSX grammar
18
+ };
19
+ export function getParser(filePath) {
20
+ const ext = filePath.slice(filePath.lastIndexOf('.'));
21
+ return EXT_MAP[ext] ?? null;
22
+ }
23
+ export function parseFile(filePath, sourceCode) {
24
+ const parser = getParser(filePath);
25
+ if (!parser)
26
+ return null;
27
+ return parser.parse(sourceCode);
28
+ }
29
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/parser/setup.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,gEAAgE;AAChE,OAAO,UAAU,MAAM,mCAAmC,CAAC;AAC3D,gEAAgE;AAChE,OAAO,GAAG,MAAM,4BAA4B,CAAC;AAC7C,OAAO,UAAU,MAAM,wBAAwB,CAAC;AAEhD,MAAM,QAAQ,GAAG,IAAI,MAAM,EAAE,CAAC;AAC9B,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAEjC,MAAM,SAAS,GAAG,IAAI,MAAM,EAAE,CAAC;AAC/B,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAE3B,MAAM,QAAQ,GAAG,IAAI,MAAM,EAAE,CAAC;AAC9B,QAAQ,CAAC,WAAW,CAAC,UAAwC,CAAC,CAAC;AAE/D,MAAM,OAAO,GAA2B;IACtC,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,SAAS,EAAE,uBAAuB;CAC3C,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAkB;IAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface WalkedFile {
2
+ absolutePath: string;
3
+ relativePath: string;
4
+ }
5
+ export declare function walkProject(projectDir: string, extraExclude?: string[]): Promise<WalkedFile[]>;
6
+ //# sourceMappingURL=walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.d.ts","sourceRoot":"","sources":["../../src/parser/walker.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,YAAY,GAAE,MAAM,EAAO,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC,CAOvB"}
@@ -0,0 +1,45 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { join, relative } from 'node:path';
3
+ import ignore from 'ignore';
4
+ const ALWAYS_SKIP = new Set(['node_modules', '.next', 'dist', 'build', '.reactgraph', '.git']);
5
+ const EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx']);
6
+ export async function walkProject(projectDir, extraExclude = []) {
7
+ const ig = await loadGitignore(projectDir);
8
+ for (const pat of extraExclude)
9
+ ig.add(pat);
10
+ const files = [];
11
+ await walk(projectDir, projectDir, ig, files);
12
+ return files;
13
+ }
14
+ async function loadGitignore(projectDir) {
15
+ const ig = ignore();
16
+ try {
17
+ const content = await readFile(join(projectDir, '.gitignore'), 'utf-8');
18
+ ig.add(content);
19
+ }
20
+ catch {
21
+ // no .gitignore, that's fine
22
+ }
23
+ return ig;
24
+ }
25
+ async function walk(dir, projectDir, ig, files) {
26
+ const entries = await readdir(dir, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ if (ALWAYS_SKIP.has(entry.name))
29
+ continue;
30
+ const abs = join(dir, entry.name);
31
+ const rel = relative(projectDir, abs);
32
+ if (ig.ignores(rel))
33
+ continue;
34
+ if (entry.isDirectory()) {
35
+ await walk(abs, projectDir, ig, files);
36
+ }
37
+ else if (entry.isFile()) {
38
+ const ext = entry.name.slice(entry.name.lastIndexOf('.'));
39
+ if (EXTENSIONS.has(ext)) {
40
+ files.push({ absolutePath: abs, relativePath: rel });
41
+ }
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.js","sourceRoot":"","sources":["../../src/parser/walker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAQ,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,MAAuB,MAAM,QAAQ,CAAC;AAE7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/F,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAO3D,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,eAAyB,EAAE;IAE3B,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,YAAY;QAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE5C,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,UAAkB;IAC7C,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QACxE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,IAAI,CACjB,GAAW,EACX,UAAkB,EAClB,EAAU,EACV,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAE1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAEtC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,SAAS;QAE9B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { ReactGraph } from './graph/graph.js';
2
+ export interface WatcherOptions {
3
+ projectDir: string;
4
+ graph: ReactGraph;
5
+ onUpdate?: (file: string, stats: {
6
+ nodes: number;
7
+ edges: number;
8
+ }) => void;
9
+ onError?: (file: string, error: Error) => void;
10
+ }
11
+ export declare function startWatcher(opts: WatcherOptions): () => void;
12
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQ9C,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAChD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,IAAI,CAuE7D"}
@@ -0,0 +1,72 @@
1
+ import { watch } from 'chokidar';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { createHash } from 'node:crypto';
4
+ import { relative } from 'node:path';
5
+ import { saveGraph } from './graph/serialize.js';
6
+ import { processFile } from './parser/pipeline.js';
7
+ import { generateAIContext } from './output/ai-context.js';
8
+ const EXTENSIONS = /\.(tsx?|jsx?)$/;
9
+ const IGNORE = ['**/node_modules/**', '**/.next/**', '**/dist/**', '**/build/**', '**/.reactgraph/**'];
10
+ export function startWatcher(opts) {
11
+ const { projectDir, graph, onUpdate, onError } = opts;
12
+ const fileHashes = new Map();
13
+ // Initialize hashes for current graph files
14
+ // (We'll compute them on first change detection)
15
+ const watcher = watch(projectDir, {
16
+ ignored: IGNORE,
17
+ ignoreInitial: true,
18
+ persistent: true,
19
+ });
20
+ const handleChange = async (absPath) => {
21
+ if (!EXTENSIONS.test(absPath))
22
+ return;
23
+ const relPath = relative(projectDir, absPath).replace(/\\/g, '/');
24
+ try {
25
+ const content = await readFile(absPath, 'utf-8');
26
+ const hash = createHash('sha256').update(content).digest('hex').slice(0, 16);
27
+ // Skip if unchanged
28
+ if (fileHashes.get(relPath) === hash)
29
+ return;
30
+ fileHashes.set(relPath, hash);
31
+ // Remove old nodes/edges for this file
32
+ graph.removeNodesByFile(relPath);
33
+ // Re-process file
34
+ const result = await processFile(relPath, projectDir);
35
+ for (const node of result.nodes)
36
+ graph.addNode(node);
37
+ for (const edge of result.edges)
38
+ graph.addEdge(edge);
39
+ // Persist
40
+ await saveGraph(graph, projectDir);
41
+ await generateAIContext(graph, projectDir);
42
+ onUpdate?.(relPath, {
43
+ nodes: graph.stats().totalNodes,
44
+ edges: graph.stats().totalEdges,
45
+ });
46
+ }
47
+ catch (err) {
48
+ onError?.(relPath, err);
49
+ }
50
+ };
51
+ const handleDelete = async (absPath) => {
52
+ if (!EXTENSIONS.test(absPath))
53
+ return;
54
+ const relPath = relative(projectDir, absPath).replace(/\\/g, '/');
55
+ graph.removeNodesByFile(relPath);
56
+ fileHashes.delete(relPath);
57
+ await saveGraph(graph, projectDir);
58
+ await generateAIContext(graph, projectDir);
59
+ onUpdate?.(relPath, {
60
+ nodes: graph.stats().totalNodes,
61
+ edges: graph.stats().totalEdges,
62
+ });
63
+ };
64
+ watcher.on('change', handleChange);
65
+ watcher.on('add', handleChange);
66
+ watcher.on('unlink', handleDelete);
67
+ // Return cleanup function
68
+ return () => {
69
+ watcher.close();
70
+ };
71
+ }
72
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@reactgraph/cli",
3
+ "version": "0.1.1",
4
+ "description": "Pre-computed React project graph for AI-assisted development",
5
+ "type": "module",
6
+ "bin": {
7
+ "reactgraph": "./dist/cli/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "scripts": {
12
+ "build": "bun run --bun node_modules/.bin/tsc",
13
+ "dev": "bun run src/cli/index.ts",
14
+ "test": "bun test",
15
+ "lint": "bun run --bun node_modules/.bin/tsc --noEmit"
16
+ },
17
+ "keywords": [
18
+ "react",
19
+ "graph",
20
+ "mcp",
21
+ "claude",
22
+ "ai",
23
+ "ast",
24
+ "tree-sitter"
25
+ ],
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.1",
32
+ "chokidar": "^4.0.3",
33
+ "commander": "^13.1.0",
34
+ "ignore": "^7.0.4",
35
+ "ink": "^5.2.0",
36
+ "react": "^18.3.1",
37
+ "tree-sitter": "^0.22.4",
38
+ "tree-sitter-javascript": "^0.23.1",
39
+ "tree-sitter-typescript": "^0.23.2"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.13.14",
43
+ "@types/react": "^18.3.18",
44
+ "tsx": "^4.19.3",
45
+ "typescript": "^5.8.2",
46
+ "vitest": "^3.0.9"
47
+ },
48
+ "trustedDependencies": [
49
+ "tree-sitter-javascript"
50
+ ]
51
+ }
@@ -0,0 +1,79 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text } from 'ink';
3
+
4
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
5
+
6
+ function useSpinner() {
7
+ const [frame, setFrame] = useState(0);
8
+ useEffect(() => {
9
+ const timer = setInterval(() => {
10
+ setFrame(f => (f + 1) % SPINNER_FRAMES.length);
11
+ }, 80);
12
+ return () => clearInterval(timer);
13
+ }, []);
14
+ return SPINNER_FRAMES[frame];
15
+ }
16
+
17
+ interface IndexProgressProps {
18
+ currentFile: string;
19
+ current: number;
20
+ total: number;
21
+ done: boolean;
22
+ stats?: {
23
+ totalFiles: number;
24
+ parsedFiles: number;
25
+ skippedFiles: number;
26
+ nodes: number;
27
+ edges: number;
28
+ durationMs: number;
29
+ };
30
+ graphStats?: Record<string, number>;
31
+ }
32
+
33
+ export function IndexProgress({ currentFile, current, total, done, stats, graphStats }: IndexProgressProps) {
34
+ const spinner = useSpinner();
35
+
36
+ if (done && stats && graphStats) {
37
+ return (
38
+ <Box flexDirection="column" paddingTop={1}>
39
+ <Text color="green" bold>✓ Indexing complete</Text>
40
+ <Box paddingLeft={2} flexDirection="column" marginTop={1}>
41
+ <Text dimColor>Files: {stats.totalFiles} found, {stats.parsedFiles} parsed, {stats.skippedFiles} cached</Text>
42
+ <Text dimColor>Time: {(stats.durationMs / 1000).toFixed(2)}s</Text>
43
+ <Text dimColor>Nodes: {stats.nodes}</Text>
44
+ <Text dimColor>Edges: {stats.edges}</Text>
45
+ </Box>
46
+ <Box paddingLeft={2} flexDirection="column" marginTop={1}>
47
+ {graphStats.Component !== undefined && <Text> Components: {graphStats.Component}</Text>}
48
+ {graphStats.Hook !== undefined && <Text> Hooks: {graphStats.Hook}</Text>}
49
+ {graphStats.Module !== undefined && <Text> Modules: {graphStats.Module}</Text>}
50
+ </Box>
51
+ <Box marginTop={1}>
52
+ <Text color="cyan">→ .reactgraph/ai-context.md generated</Text>
53
+ </Box>
54
+ </Box>
55
+ );
56
+ }
57
+
58
+ const pct = total > 0 ? Math.round((current / total) * 100) : 0;
59
+ const barWidth = 30;
60
+ const filled = Math.round((pct / 100) * barWidth);
61
+ const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
62
+
63
+ return (
64
+ <Box flexDirection="column">
65
+ <Box>
66
+ <Text color="yellow">{spinner}</Text>
67
+ <Text> Indexing... </Text>
68
+ <Text dimColor>{current}/{total}</Text>
69
+ </Box>
70
+ <Box paddingLeft={2}>
71
+ <Text color="cyan">{bar}</Text>
72
+ <Text> {pct}%</Text>
73
+ </Box>
74
+ <Box paddingLeft={2}>
75
+ <Text dimColor>{currentFile}</Text>
76
+ </Box>
77
+ </Box>
78
+ );
79
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import type { InitResult as InitResultType } from '../init.js';
4
+
5
+ interface InitResultProps {
6
+ result: InitResultType;
7
+ }
8
+
9
+ export function InitResultView({ result }: InitResultProps) {
10
+ return (
11
+ <Box flexDirection="column" paddingTop={1}>
12
+ <Text color="green" bold>✓ ReactGraph initialized</Text>
13
+ <Box paddingLeft={2} flexDirection="column" marginTop={1}>
14
+ <Text>Framework: <Text color="cyan">{result.framework}</Text></Text>
15
+ <Text>Source dirs: <Text color="cyan">{result.srcDirs.join(', ')}</Text></Text>
16
+ <Text>Config: <Text dimColor>.reactgraph/config.json</Text></Text>
17
+ {result.gitignoreUpdated && (
18
+ <Text dimColor>Added .reactgraph/ to .gitignore</Text>
19
+ )}
20
+ </Box>
21
+ <Box marginTop={1} flexDirection="column">
22
+ <Text color="yellow">Next steps:</Text>
23
+ <Text> 1. Run <Text color="cyan" bold>reactgraph index</Text> to build the graph</Text>
24
+ <Text> 2. Add to CLAUDE.md: <Text dimColor>"Read .reactgraph/ai-context.md at session start"</Text></Text>
25
+ </Box>
26
+ </Box>
27
+ );
28
+ }
@@ -0,0 +1,41 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import type { ReactGraphConfig } from '../graph/schema.js';
4
+ import { indexProject, type IndexStats } from '../parser/indexer.js';
5
+ import { generateAIContext } from '../output/ai-context.js';
6
+
7
+ export interface IndexResult {
8
+ stats: IndexStats;
9
+ graphStats: Record<string, number>;
10
+ }
11
+
12
+ export async function runIndex(
13
+ projectDir: string,
14
+ onProgress?: (file: string, current: number, total: number) => void,
15
+ ): Promise<IndexResult> {
16
+ // Load config
17
+ const config = loadConfig(projectDir);
18
+
19
+ // Run indexer
20
+ const { graph, stats } = await indexProject(projectDir, config.exclude, onProgress);
21
+
22
+ // Always generate ai-context.md
23
+ await generateAIContext(graph, projectDir);
24
+
25
+ return {
26
+ stats,
27
+ graphStats: graph.stats(),
28
+ };
29
+ }
30
+
31
+ function loadConfig(projectDir: string): ReactGraphConfig {
32
+ const configPath = join(projectDir, '.reactgraph', 'config.json');
33
+ if (existsSync(configPath)) {
34
+ return JSON.parse(readFileSync(configPath, 'utf-8'));
35
+ }
36
+ return {
37
+ srcDirs: ['src'],
38
+ framework: 'unknown',
39
+ exclude: ['**/*.test.*', '**/*.spec.*'],
40
+ };
41
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { render } from 'ink';
5
+ import React from 'react';
6
+ import { runInit } from './init.js';
7
+ import { runIndex } from './index-cmd.js';
8
+ import { runServe } from './serve.js';
9
+ import { runUnused } from './unused.js';
10
+ import { InitResultView } from './components/InitResult.js';
11
+ import { IndexProgress } from './components/IndexProgress.js';
12
+
13
+ const program = new Command();
14
+
15
+ program
16
+ .name('reactgraph')
17
+ .description('Pre-computed React project graph for AI-assisted development')
18
+ .version('0.1.0');
19
+
20
+ program
21
+ .command('init')
22
+ .description('Initialize ReactGraph in the current project')
23
+ .action(() => {
24
+ const projectDir = process.cwd();
25
+ const result = runInit(projectDir);
26
+ const { unmount } = render(React.createElement(InitResultView, { result }));
27
+ setTimeout(() => unmount(), 100);
28
+ });
29
+
30
+ program
31
+ .command('index')
32
+ .description('Build the project graph')
33
+ .action(async () => {
34
+ const projectDir = process.cwd();
35
+
36
+ let currentFile = '';
37
+ let current = 0;
38
+ let total = 0;
39
+ let done = false;
40
+ let stats: any = null;
41
+ let graphStats: any = null;
42
+
43
+ const App = () => React.createElement(IndexProgress, {
44
+ currentFile,
45
+ current,
46
+ total,
47
+ done,
48
+ stats,
49
+ graphStats,
50
+ });
51
+
52
+ const { rerender, unmount } = render(React.createElement(App));
53
+
54
+ const onProgress = (file: string, cur: number, tot: number) => {
55
+ currentFile = file;
56
+ current = cur;
57
+ total = tot;
58
+ rerender(React.createElement(App));
59
+ };
60
+
61
+ try {
62
+ const result = await runIndex(projectDir, onProgress);
63
+ done = true;
64
+ stats = result.stats;
65
+ graphStats = result.graphStats;
66
+ rerender(React.createElement(App));
67
+ setTimeout(() => unmount(), 200);
68
+ } catch (err) {
69
+ unmount();
70
+ console.error('Index failed:', err);
71
+ process.exit(1);
72
+ }
73
+ });
74
+
75
+ program
76
+ .command('serve')
77
+ .description('Start the MCP server')
78
+ .option('--watch', 'Watch for file changes and update graph incrementally')
79
+ .action(async (opts) => {
80
+ const projectDir = process.cwd();
81
+ await runServe(projectDir, opts.watch ?? false);
82
+ });
83
+
84
+ program
85
+ .command('unused')
86
+ .description('Find orphan components, unused hooks, and dead exports')
87
+ .action(async () => {
88
+ const projectDir = process.cwd();
89
+ await runUnused(projectDir);
90
+ });
91
+
92
+ program.parse();