wogiflow 1.0.0

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 (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,760 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Code Intelligence (Priority 5: Better Code Understanding)
5
+ *
6
+ * Enhanced code analysis with:
7
+ * - Import/export relationship mapping
8
+ * - Type dependencies
9
+ * - Function call graphs
10
+ * - Semantic code search
11
+ *
12
+ * Uses semantic code analysis for better understanding.
13
+ *
14
+ * Usage:
15
+ * const { analyzeRelationships, findRelatedCode } = require('./flow-code-intelligence');
16
+ * const relationships = await analyzeRelationships('src/components/Button.tsx');
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const { getProjectRoot, getConfig, PATHS, colors } = require('./flow-utils');
22
+ const { safeGrep, safeFind, escapeRegex } = require('./flow-security');
23
+
24
+ const PROJECT_ROOT = getProjectRoot();
25
+
26
+ // ============================================================
27
+ // Relationship Analysis
28
+ // ============================================================
29
+
30
+ /**
31
+ * Analyze import/export relationships for a file
32
+ *
33
+ * @param {string} filePath - Path to the file to analyze
34
+ * @returns {object} Relationships object
35
+ */
36
+ function analyzeRelationships(filePath) {
37
+ const fullPath = path.isAbsolute(filePath)
38
+ ? filePath
39
+ : path.join(PROJECT_ROOT, filePath);
40
+
41
+ if (!fs.existsSync(fullPath)) {
42
+ return { error: 'File not found' };
43
+ }
44
+
45
+ const content = fs.readFileSync(fullPath, 'utf-8');
46
+ const relPath = path.relative(PROJECT_ROOT, fullPath);
47
+
48
+ const relationships = {
49
+ file: relPath,
50
+ analyzedAt: new Date().toISOString(),
51
+ imports: extractImports(content, path.dirname(fullPath)),
52
+ exports: extractExports(content),
53
+ dependencies: {
54
+ internal: [],
55
+ external: []
56
+ },
57
+ dependents: [],
58
+ types: extractTypeUsage(content),
59
+ functions: extractFunctions(content)
60
+ };
61
+
62
+ // Categorize imports
63
+ for (const imp of relationships.imports) {
64
+ if (imp.source.startsWith('.') || imp.source.startsWith('@/')) {
65
+ relationships.dependencies.internal.push(imp);
66
+ } else {
67
+ relationships.dependencies.external.push(imp);
68
+ }
69
+ }
70
+
71
+ return relationships;
72
+ }
73
+
74
+ /**
75
+ * Extract imports from file content
76
+ */
77
+ function extractImports(content, fileDir) {
78
+ const imports = [];
79
+
80
+ // ES6 imports
81
+ const importRegex = /import\s+(?:(\{[^}]+\})|(\w+)(?:\s*,\s*\{([^}]+)\})?)\s+from\s+['"]([^'"]+)['"]/g;
82
+ let match;
83
+
84
+ while ((match = importRegex.exec(content)) !== null) {
85
+ const namedImports = match[1] || match[3];
86
+ const defaultImport = match[2];
87
+ const source = match[4];
88
+
89
+ const imp = {
90
+ source,
91
+ default: defaultImport || null,
92
+ named: []
93
+ };
94
+
95
+ if (namedImports) {
96
+ imp.named = namedImports
97
+ .replace(/[{}]/g, '')
98
+ .split(',')
99
+ .map(s => s.trim().split(' as ')[0].trim())
100
+ .filter(Boolean);
101
+ }
102
+
103
+ imports.push(imp);
104
+ }
105
+
106
+ // Side-effect imports
107
+ const sideEffectRegex = /import\s+['"]([^'"]+)['"]/g;
108
+ while ((match = sideEffectRegex.exec(content)) !== null) {
109
+ imports.push({
110
+ source: match[1],
111
+ sideEffect: true
112
+ });
113
+ }
114
+
115
+ // Dynamic imports
116
+ const dynamicRegex = /import\(['"]([^'"]+)['"]\)/g;
117
+ while ((match = dynamicRegex.exec(content)) !== null) {
118
+ imports.push({
119
+ source: match[1],
120
+ dynamic: true
121
+ });
122
+ }
123
+
124
+ return imports;
125
+ }
126
+
127
+ /**
128
+ * Extract exports from file content
129
+ */
130
+ function extractExports(content) {
131
+ const exports = {
132
+ default: null,
133
+ named: [],
134
+ types: []
135
+ };
136
+
137
+ // Default export
138
+ const defaultMatch = content.match(/export\s+default\s+(?:function\s+)?(\w+)/);
139
+ if (defaultMatch) {
140
+ exports.default = defaultMatch[1];
141
+ }
142
+
143
+ // Named exports
144
+ const namedRegex = /export\s+(?:const|let|var|function|class)\s+(\w+)/g;
145
+ let match;
146
+ while ((match = namedRegex.exec(content)) !== null) {
147
+ if (!exports.named.includes(match[1])) {
148
+ exports.named.push(match[1]);
149
+ }
150
+ }
151
+
152
+ // Export block
153
+ const blockRegex = /export\s+\{([^}]+)\}/g;
154
+ while ((match = blockRegex.exec(content)) !== null) {
155
+ const items = match[1].split(',').map(s => s.trim().split(' as ')[0].trim());
156
+ for (const item of items) {
157
+ if (item && !exports.named.includes(item)) {
158
+ exports.named.push(item);
159
+ }
160
+ }
161
+ }
162
+
163
+ // Type exports
164
+ const typeRegex = /export\s+(?:type|interface)\s+(\w+)/g;
165
+ while ((match = typeRegex.exec(content)) !== null) {
166
+ exports.types.push(match[1]);
167
+ }
168
+
169
+ return exports;
170
+ }
171
+
172
+ /**
173
+ * Extract type usage from file content
174
+ */
175
+ function extractTypeUsage(content) {
176
+ const types = {
177
+ interfaces: [],
178
+ types: [],
179
+ generics: []
180
+ };
181
+
182
+ // Interface definitions
183
+ const interfaceRegex = /interface\s+(\w+)(?:<([^>]+)>)?/g;
184
+ let match;
185
+ while ((match = interfaceRegex.exec(content)) !== null) {
186
+ types.interfaces.push({
187
+ name: match[1],
188
+ generics: match[2] ? match[2].split(',').map(s => s.trim()) : []
189
+ });
190
+ }
191
+
192
+ // Type definitions
193
+ const typeRegex = /type\s+(\w+)(?:<([^>]+)>)?\s*=/g;
194
+ while ((match = typeRegex.exec(content)) !== null) {
195
+ types.types.push({
196
+ name: match[1],
197
+ generics: match[2] ? match[2].split(',').map(s => s.trim()) : []
198
+ });
199
+ }
200
+
201
+ // Generic usage
202
+ const genericRegex = /:\s*(\w+)<([^>]+)>/g;
203
+ while ((match = genericRegex.exec(content)) !== null) {
204
+ types.generics.push({
205
+ type: match[1],
206
+ params: match[2].split(',').map(s => s.trim())
207
+ });
208
+ }
209
+
210
+ return types;
211
+ }
212
+
213
+ /**
214
+ * Extract function definitions
215
+ */
216
+ function extractFunctions(content) {
217
+ const functions = [];
218
+
219
+ // Regular functions
220
+ const funcRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
221
+ let match;
222
+ while ((match = funcRegex.exec(content)) !== null) {
223
+ functions.push({
224
+ name: match[1],
225
+ params: match[2].split(',').map(s => s.trim().split(':')[0].trim()).filter(Boolean),
226
+ async: content.slice(match.index - 10, match.index).includes('async')
227
+ });
228
+ }
229
+
230
+ // Arrow functions (const/let)
231
+ const arrowRegex = /(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*(?::\s*[^=]+)?\s*=>/g;
232
+ while ((match = arrowRegex.exec(content)) !== null) {
233
+ functions.push({
234
+ name: match[1],
235
+ type: 'arrow',
236
+ async: content.slice(match.index, match.index + 100).includes('async')
237
+ });
238
+ }
239
+
240
+ return functions.slice(0, 20); // Limit to 20
241
+ }
242
+
243
+ // ============================================================
244
+ // Dependency Graph
245
+ // ============================================================
246
+
247
+ /**
248
+ * Build dependency graph for a set of files
249
+ *
250
+ * @param {string[]} filePaths - Files to analyze
251
+ * @returns {object} Dependency graph
252
+ */
253
+ function buildDependencyGraph(filePaths) {
254
+ const graph = {
255
+ nodes: [],
256
+ edges: [],
257
+ clusters: {}
258
+ };
259
+
260
+ const nodeMap = new Map();
261
+
262
+ for (const filePath of filePaths) {
263
+ const relationships = analyzeRelationships(filePath);
264
+ if (relationships.error) continue;
265
+
266
+ const nodeId = relationships.file;
267
+
268
+ // Add node
269
+ if (!nodeMap.has(nodeId)) {
270
+ nodeMap.set(nodeId, {
271
+ id: nodeId,
272
+ exports: relationships.exports,
273
+ category: categorizeFile(nodeId)
274
+ });
275
+ graph.nodes.push(nodeMap.get(nodeId));
276
+ }
277
+
278
+ // Add edges for internal dependencies
279
+ for (const dep of relationships.dependencies.internal) {
280
+ const resolvedPath = resolveImportPath(dep.source, path.dirname(filePath));
281
+ if (resolvedPath) {
282
+ graph.edges.push({
283
+ from: nodeId,
284
+ to: resolvedPath,
285
+ type: 'import',
286
+ imports: [...(dep.named || []), dep.default].filter(Boolean)
287
+ });
288
+ }
289
+ }
290
+ }
291
+
292
+ // Group into clusters
293
+ for (const node of graph.nodes) {
294
+ const category = node.category;
295
+ if (!graph.clusters[category]) {
296
+ graph.clusters[category] = [];
297
+ }
298
+ graph.clusters[category].push(node.id);
299
+ }
300
+
301
+ return graph;
302
+ }
303
+
304
+ /**
305
+ * Categorize file based on path
306
+ */
307
+ function categorizeFile(filePath) {
308
+ const lower = filePath.toLowerCase();
309
+
310
+ if (lower.includes('/components/')) return 'components';
311
+ if (lower.includes('/hooks/') || lower.match(/\/use\w+\./)) return 'hooks';
312
+ if (lower.includes('/services/')) return 'services';
313
+ if (lower.includes('/pages/') || lower.includes('/app/')) return 'pages';
314
+ if (lower.includes('/api/')) return 'api';
315
+ if (lower.includes('/utils/') || lower.includes('/lib/')) return 'utils';
316
+ if (lower.includes('/types/')) return 'types';
317
+
318
+ return 'other';
319
+ }
320
+
321
+ /**
322
+ * Resolve import path to actual file
323
+ */
324
+ function resolveImportPath(importSource, fromDir) {
325
+ if (!importSource.startsWith('.')) {
326
+ // Handle alias imports like @/
327
+ if (importSource.startsWith('@/')) {
328
+ importSource = importSource.replace('@/', 'src/');
329
+ } else {
330
+ return null; // External package
331
+ }
332
+ }
333
+
334
+ const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];
335
+
336
+ for (const ext of extensions) {
337
+ const candidate = path.join(fromDir, importSource + ext);
338
+ const relPath = path.relative(PROJECT_ROOT, candidate);
339
+
340
+ if (fs.existsSync(path.join(PROJECT_ROOT, relPath))) {
341
+ return relPath;
342
+ }
343
+ }
344
+
345
+ return null;
346
+ }
347
+
348
+ // ============================================================
349
+ // Related Code Search
350
+ // ============================================================
351
+
352
+ /**
353
+ * Find code related to a given file or function
354
+ *
355
+ * @param {string} query - File path, function name, or keyword
356
+ * @param {object} options - Search options
357
+ */
358
+ async function findRelatedCode(query, options = {}) {
359
+ const results = {
360
+ query,
361
+ timestamp: new Date().toISOString(),
362
+ directDependencies: [],
363
+ reverseDependencies: [],
364
+ similarFiles: [],
365
+ relatedFunctions: []
366
+ };
367
+
368
+ // If query is a file path, analyze its relationships
369
+ if (query.includes('/') || query.includes('.')) {
370
+ const relationships = analyzeRelationships(query);
371
+ if (!relationships.error) {
372
+ results.directDependencies = relationships.dependencies.internal
373
+ .map(d => d.source)
374
+ .slice(0, 10);
375
+
376
+ // Find files that import this file
377
+ results.reverseDependencies = await findFilesImporting(query);
378
+ }
379
+ }
380
+
381
+ // Search for keyword in codebase
382
+ results.similarFiles = await searchCodebase(query, options.maxResults || 10);
383
+
384
+ return results;
385
+ }
386
+
387
+ /**
388
+ * Find files that import a given file
389
+ */
390
+ async function findFilesImporting(filePath) {
391
+ const basename = path.basename(filePath, path.extname(filePath));
392
+
393
+ // Use safe grep with escaped pattern to prevent injection
394
+ const pattern = `from.*${escapeRegex(basename)}`;
395
+ return safeGrep(pattern, {
396
+ cwd: PROJECT_ROOT,
397
+ searchDir: 'src/',
398
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
399
+ maxResults: 20
400
+ });
401
+ }
402
+
403
+ /**
404
+ * Search codebase for keyword
405
+ */
406
+ async function searchCodebase(keyword, maxResults = 10) {
407
+ // Use safe grep with escaped pattern to prevent injection
408
+ return safeGrep(keyword, {
409
+ cwd: PROJECT_ROOT,
410
+ searchDir: 'src/',
411
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
412
+ maxResults
413
+ });
414
+ }
415
+
416
+ // ============================================================
417
+ // Enhanced Component Index
418
+ // ============================================================
419
+
420
+ /**
421
+ * Generate enhanced component index with relationships
422
+ */
423
+ async function generateEnhancedIndex() {
424
+ const config = getConfig();
425
+ const indexPath = path.join(PATHS.state, 'component-index.json');
426
+
427
+ // Read existing index
428
+ let existingIndex = { components: [] };
429
+ if (fs.existsSync(indexPath)) {
430
+ try {
431
+ existingIndex = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
432
+ } catch {
433
+ // Ignore
434
+ }
435
+ }
436
+
437
+ // Enhance with relationships
438
+ const enhanced = {
439
+ ...existingIndex,
440
+ lastEnhanced: new Date().toISOString(),
441
+ relationships: {},
442
+ dependencyGraph: {
443
+ nodes: [],
444
+ edges: []
445
+ }
446
+ };
447
+
448
+ // Analyze relationships for each component
449
+ const allComponents = [
450
+ ...(existingIndex.components || []),
451
+ ...(existingIndex.hooks || []),
452
+ ...(existingIndex.services || []),
453
+ ...(existingIndex.pages || [])
454
+ ];
455
+
456
+ const filePaths = allComponents.map(c => c.path).filter(Boolean);
457
+
458
+ // Build dependency graph
459
+ const graph = buildDependencyGraph(filePaths);
460
+ enhanced.dependencyGraph = graph;
461
+
462
+ // Add individual relationship data
463
+ for (const comp of allComponents.slice(0, 50)) { // Limit to 50 for performance
464
+ if (comp.path) {
465
+ const rel = analyzeRelationships(comp.path);
466
+ if (!rel.error) {
467
+ enhanced.relationships[comp.path] = {
468
+ imports: rel.dependencies.internal.map(d => d.source),
469
+ exports: rel.exports.named,
470
+ types: rel.types.interfaces.concat(rel.types.types).map(t => t.name)
471
+ };
472
+ }
473
+ }
474
+ }
475
+
476
+ // Save enhanced index
477
+ fs.writeFileSync(indexPath, JSON.stringify(enhanced, null, 2), 'utf-8');
478
+
479
+ return enhanced;
480
+ }
481
+
482
+ /**
483
+ * Get smart context for a task based on code intelligence
484
+ *
485
+ * @param {string} taskDescription - Task description
486
+ * @param {object} options - Options
487
+ */
488
+ async function getSmartContext(taskDescription, options = {}) {
489
+ const config = getConfig();
490
+ const indexPath = path.join(PATHS.state, 'component-index.json');
491
+
492
+ if (!fs.existsSync(indexPath)) {
493
+ return { files: [], reason: 'No component index' };
494
+ }
495
+
496
+ const index = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
497
+ const desc = taskDescription.toLowerCase();
498
+
499
+ const relevantFiles = [];
500
+ const seen = new Set();
501
+
502
+ // 1. Direct keyword matches
503
+ const allComponents = [
504
+ ...(index.components || []),
505
+ ...(index.hooks || []),
506
+ ...(index.services || []),
507
+ ...(index.pages || [])
508
+ ];
509
+
510
+ for (const comp of allComponents) {
511
+ const name = (comp.name || '').toLowerCase();
512
+ const filePath = (comp.path || '').toLowerCase();
513
+
514
+ // Check if any word in description matches component
515
+ const words = desc.split(/\s+/).filter(w => w.length > 3);
516
+ for (const word of words) {
517
+ if (name.includes(word) || filePath.includes(word)) {
518
+ if (!seen.has(comp.path)) {
519
+ relevantFiles.push({
520
+ path: comp.path,
521
+ reason: `keyword match: "${word}"`,
522
+ score: 3
523
+ });
524
+ seen.add(comp.path);
525
+ }
526
+ break;
527
+ }
528
+ }
529
+ }
530
+
531
+ // 2. Follow relationships for matched files
532
+ if (index.relationships && relevantFiles.length > 0) {
533
+ for (const file of relevantFiles.slice(0, 5)) {
534
+ const rel = index.relationships[file.path];
535
+ if (rel?.imports) {
536
+ for (const imp of rel.imports.slice(0, 3)) {
537
+ // Resolve import to actual path
538
+ const resolved = resolveImportPath(imp, path.dirname(file.path));
539
+ if (resolved && !seen.has(resolved)) {
540
+ relevantFiles.push({
541
+ path: resolved,
542
+ reason: `imported by ${file.path}`,
543
+ score: 2
544
+ });
545
+ seen.add(resolved);
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+
552
+ // Sort by score
553
+ relevantFiles.sort((a, b) => b.score - a.score);
554
+
555
+ return {
556
+ files: relevantFiles.slice(0, options.maxFiles || 10),
557
+ totalMatches: relevantFiles.length
558
+ };
559
+ }
560
+
561
+ // ============================================================
562
+ // CLI
563
+ // ============================================================
564
+
565
+ function showHelp() {
566
+ console.log(`
567
+ Wogi Flow - Code Intelligence
568
+
569
+ Enhanced code analysis with relationships and semantic search.
570
+
571
+ Usage:
572
+ flow code-intel analyze <file>
573
+ flow code-intel graph [directory]
574
+ flow code-intel related <query>
575
+ flow code-intel enhance
576
+
577
+ Commands:
578
+ analyze Analyze relationships for a file
579
+ graph Build dependency graph
580
+ related Find related code
581
+ enhance Enhance component index with relationships
582
+
583
+ Options:
584
+ --json Output as JSON
585
+ --help Show this help
586
+
587
+ Examples:
588
+ flow code-intel analyze src/components/Button.tsx
589
+ flow code-intel related "authentication"
590
+ flow code-intel enhance
591
+ `);
592
+ }
593
+
594
+ async function main() {
595
+ const args = process.argv.slice(2);
596
+
597
+ if (args.includes('--help') || args.includes('-h') || args.length === 0) {
598
+ showHelp();
599
+ process.exit(0);
600
+ }
601
+
602
+ const command = args[0];
603
+ const target = args[1];
604
+ const jsonOutput = args.includes('--json');
605
+
606
+ switch (command) {
607
+ case 'analyze': {
608
+ if (!target) {
609
+ console.log(`${colors.red}Error: File path required${colors.reset}`);
610
+ process.exit(1);
611
+ }
612
+
613
+ const relationships = analyzeRelationships(target);
614
+
615
+ if (jsonOutput) {
616
+ console.log(JSON.stringify(relationships, null, 2));
617
+ } else {
618
+ console.log(`\n${colors.cyan}File: ${relationships.file}${colors.reset}\n`);
619
+
620
+ console.log(`${colors.bold}Imports:${colors.reset}`);
621
+ for (const imp of relationships.imports.slice(0, 10)) {
622
+ console.log(` ${imp.source}`);
623
+ if (imp.named?.length > 0) {
624
+ console.log(` → ${imp.named.join(', ')}`);
625
+ }
626
+ }
627
+
628
+ console.log(`\n${colors.bold}Exports:${colors.reset}`);
629
+ if (relationships.exports.default) {
630
+ console.log(` default: ${relationships.exports.default}`);
631
+ }
632
+ if (relationships.exports.named.length > 0) {
633
+ console.log(` named: ${relationships.exports.named.join(', ')}`);
634
+ }
635
+
636
+ console.log(`\n${colors.bold}Functions:${colors.reset}`);
637
+ for (const func of relationships.functions.slice(0, 10)) {
638
+ console.log(` ${func.async ? 'async ' : ''}${func.name}()`);
639
+ }
640
+ }
641
+ break;
642
+ }
643
+
644
+ case 'graph': {
645
+ const dir = target || 'src';
646
+
647
+ // Use safe find to prevent command injection
648
+ const files = safeFind(dir, {
649
+ cwd: PROJECT_ROOT,
650
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
651
+ maxResults: 100
652
+ });
653
+
654
+ if (files.length === 0) {
655
+ console.log(`${colors.red}Error scanning directory or no files found${colors.reset}`);
656
+ process.exit(1);
657
+ }
658
+
659
+ const graph = buildDependencyGraph(files);
660
+
661
+ if (jsonOutput) {
662
+ console.log(JSON.stringify(graph, null, 2));
663
+ } else {
664
+ console.log(`\n${colors.cyan}Dependency Graph${colors.reset}\n`);
665
+ console.log(`Nodes: ${graph.nodes.length}`);
666
+ console.log(`Edges: ${graph.edges.length}`);
667
+
668
+ console.log(`\n${colors.bold}Clusters:${colors.reset}`);
669
+ for (const [category, items] of Object.entries(graph.clusters)) {
670
+ console.log(` ${category}: ${items.length} files`);
671
+ }
672
+ }
673
+ break;
674
+ }
675
+
676
+ case 'related': {
677
+ if (!target) {
678
+ console.log(`${colors.red}Error: Query required${colors.reset}`);
679
+ process.exit(1);
680
+ }
681
+
682
+ const results = await findRelatedCode(target);
683
+
684
+ if (jsonOutput) {
685
+ console.log(JSON.stringify(results, null, 2));
686
+ } else {
687
+ console.log(`\n${colors.cyan}Related to: ${target}${colors.reset}\n`);
688
+
689
+ if (results.directDependencies.length > 0) {
690
+ console.log(`${colors.bold}Direct Dependencies:${colors.reset}`);
691
+ for (const dep of results.directDependencies) {
692
+ console.log(` → ${dep}`);
693
+ }
694
+ }
695
+
696
+ if (results.reverseDependencies.length > 0) {
697
+ console.log(`\n${colors.bold}Imported By:${colors.reset}`);
698
+ for (const dep of results.reverseDependencies) {
699
+ console.log(` ← ${dep}`);
700
+ }
701
+ }
702
+
703
+ if (results.similarFiles.length > 0) {
704
+ console.log(`\n${colors.bold}Similar Files:${colors.reset}`);
705
+ for (const file of results.similarFiles) {
706
+ console.log(` • ${file}`);
707
+ }
708
+ }
709
+ }
710
+ break;
711
+ }
712
+
713
+ case 'enhance': {
714
+ console.log(`${colors.cyan}Enhancing component index with relationships...${colors.reset}\n`);
715
+ const enhanced = await generateEnhancedIndex();
716
+
717
+ if (jsonOutput) {
718
+ console.log(JSON.stringify(enhanced, null, 2));
719
+ } else {
720
+ console.log(`${colors.green}✓ Enhanced index generated${colors.reset}`);
721
+ console.log(` Nodes: ${enhanced.dependencyGraph.nodes.length}`);
722
+ console.log(` Edges: ${enhanced.dependencyGraph.edges.length}`);
723
+ console.log(` Relationships: ${Object.keys(enhanced.relationships || {}).length}`);
724
+ }
725
+ break;
726
+ }
727
+
728
+ default:
729
+ console.log(`${colors.red}Unknown command: ${command}${colors.reset}`);
730
+ showHelp();
731
+ process.exit(1);
732
+ }
733
+ }
734
+
735
+ // ============================================================
736
+ // Exports
737
+ // ============================================================
738
+
739
+ module.exports = {
740
+ analyzeRelationships,
741
+ extractImports,
742
+ extractExports,
743
+ extractTypeUsage,
744
+ extractFunctions,
745
+ buildDependencyGraph,
746
+ findRelatedCode,
747
+ findFilesImporting,
748
+ searchCodebase,
749
+ generateEnhancedIndex,
750
+ getSmartContext,
751
+ categorizeFile,
752
+ resolveImportPath
753
+ };
754
+
755
+ if (require.main === module) {
756
+ main().catch(err => {
757
+ console.error(`Error: ${err.message}`);
758
+ process.exit(1);
759
+ });
760
+ }