ultra-dex 2.2.0 → 3.1.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 (61) hide show
  1. package/README.md +84 -122
  2. package/assets/agents/0-orchestration/orchestrator.md +2 -2
  3. package/assets/agents/00-AGENT_INDEX.md +1 -1
  4. package/assets/docs/LAUNCH-POSTS.md +1 -1
  5. package/assets/docs/QUICK-REFERENCE.md +12 -7
  6. package/assets/docs/ROADMAP.md +5 -5
  7. package/assets/docs/VISION-V2.md +1 -1
  8. package/assets/docs/WORKFLOW-DIAGRAMS.md +1 -1
  9. package/assets/hooks/pre-commit +98 -0
  10. package/assets/saas-plan/04-Imp-Template.md +1 -1
  11. package/assets/templates/README.md +1 -1
  12. package/bin/ultra-dex.js +93 -2096
  13. package/lib/commands/advanced.js +471 -0
  14. package/lib/commands/agent-builder.js +226 -0
  15. package/lib/commands/agents.js +101 -47
  16. package/lib/commands/auto-implement.js +68 -0
  17. package/lib/commands/build.js +73 -187
  18. package/lib/commands/ci-monitor.js +84 -0
  19. package/lib/commands/config.js +207 -0
  20. package/lib/commands/dashboard.js +770 -0
  21. package/lib/commands/diff.js +233 -0
  22. package/lib/commands/doctor.js +397 -0
  23. package/lib/commands/export.js +408 -0
  24. package/lib/commands/fix.js +96 -0
  25. package/lib/commands/generate.js +96 -72
  26. package/lib/commands/hooks.js +251 -76
  27. package/lib/commands/init.js +56 -6
  28. package/lib/commands/memory.js +80 -0
  29. package/lib/commands/plan.js +82 -0
  30. package/lib/commands/review.js +34 -5
  31. package/lib/commands/run.js +233 -0
  32. package/lib/commands/serve.js +188 -40
  33. package/lib/commands/state.js +354 -0
  34. package/lib/commands/swarm.js +284 -0
  35. package/lib/commands/sync.js +94 -0
  36. package/lib/commands/team.js +275 -0
  37. package/lib/commands/upgrade.js +190 -0
  38. package/lib/commands/validate.js +34 -0
  39. package/lib/commands/verify.js +81 -0
  40. package/lib/commands/watch.js +79 -0
  41. package/lib/mcp/graph.js +92 -0
  42. package/lib/mcp/memory.js +95 -0
  43. package/lib/mcp/resources.js +152 -0
  44. package/lib/mcp/server.js +34 -0
  45. package/lib/mcp/tools.js +481 -0
  46. package/lib/mcp/websocket.js +117 -0
  47. package/lib/providers/index.js +49 -4
  48. package/lib/providers/ollama.js +136 -0
  49. package/lib/providers/router.js +63 -0
  50. package/lib/quality/scanner.js +128 -0
  51. package/lib/swarm/coordinator.js +97 -0
  52. package/lib/swarm/index.js +598 -0
  53. package/lib/swarm/protocol.js +677 -0
  54. package/lib/swarm/tiers.js +485 -0
  55. package/lib/templates/context.js +2 -2
  56. package/lib/templates/custom-agent.md +10 -0
  57. package/lib/utils/fallback.js +4 -2
  58. package/lib/utils/files.js +7 -34
  59. package/lib/utils/graph.js +108 -0
  60. package/lib/utils/sync.js +216 -0
  61. package/package.json +22 -13
@@ -0,0 +1,485 @@
1
+ /**
2
+ * Ultra-Dex Agent Tier System v3.0
3
+ * Defines the hierarchical structure of agents and their dependencies.
4
+ */
5
+
6
+ // ============================================================================
7
+ // TIER DEFINITIONS
8
+ // ============================================================================
9
+
10
+ /**
11
+ * Tier structure for all 16 agents.
12
+ * Lower tier numbers indicate higher-level strategic roles.
13
+ */
14
+ export const TIERS = {
15
+ META: {
16
+ id: 0,
17
+ name: 'Meta Orchestration',
18
+ description: 'Coordinates all other agents',
19
+ agents: ['orchestrator']
20
+ },
21
+ LEADERSHIP: {
22
+ id: 1,
23
+ name: 'Leadership',
24
+ description: 'Strategic planning and technology decisions',
25
+ agents: ['cto', 'planner', 'research']
26
+ },
27
+ DEVELOPMENT: {
28
+ id: 2,
29
+ name: 'Development',
30
+ description: 'Core implementation of features',
31
+ agents: ['backend', 'frontend', 'database']
32
+ },
33
+ SECURITY: {
34
+ id: 3,
35
+ name: 'Security',
36
+ description: 'Authentication, authorization, and security audits',
37
+ agents: ['auth', 'security']
38
+ },
39
+ DEVOPS: {
40
+ id: 4,
41
+ name: 'DevOps',
42
+ description: 'Deployment and infrastructure management',
43
+ agents: ['devops']
44
+ },
45
+ QUALITY: {
46
+ id: 5,
47
+ name: 'Quality',
48
+ description: 'Testing, debugging, and code review',
49
+ agents: ['testing', 'reviewer', 'debugger', 'documentation']
50
+ },
51
+ SPECIALIST: {
52
+ id: 6,
53
+ name: 'Specialist',
54
+ description: 'Advanced optimization and code improvement',
55
+ agents: ['performance', 'refactoring']
56
+ }
57
+ };
58
+
59
+ // ============================================================================
60
+ // AGENT REGISTRY
61
+ // ============================================================================
62
+
63
+ /**
64
+ * Complete agent registry with metadata.
65
+ */
66
+ export const AGENTS = {
67
+ // Tier 0: Meta
68
+ orchestrator: {
69
+ name: 'Orchestrator',
70
+ tier: 0,
71
+ tierName: 'Meta Orchestration',
72
+ role: 'Coordinate all agents for complete features',
73
+ invocation: '@orchestrator',
74
+ file: '0-orchestration/orchestrator.md',
75
+ capabilities: ['task_decomposition', 'agent_selection', 'pipeline_execution', 'result_synthesis'],
76
+ canInvoke: ['all']
77
+ },
78
+
79
+ // Tier 1: Leadership
80
+ cto: {
81
+ name: 'CTO',
82
+ tier: 1,
83
+ tierName: 'Leadership',
84
+ role: 'Architecture & tech stack decisions',
85
+ invocation: '@cto',
86
+ file: '1-leadership/cto.md',
87
+ capabilities: ['architecture_design', 'tech_selection', 'system_design'],
88
+ canInvoke: ['research']
89
+ },
90
+ planner: {
91
+ name: 'Planner',
92
+ tier: 1,
93
+ tierName: 'Leadership',
94
+ role: 'Task breakdown & sprint planning',
95
+ invocation: '@planner',
96
+ file: '1-leadership/planner.md',
97
+ capabilities: ['task_breakdown', 'estimation', 'prioritization'],
98
+ canInvoke: []
99
+ },
100
+ research: {
101
+ name: 'Research',
102
+ tier: 1,
103
+ tierName: 'Leadership',
104
+ role: 'Technology evaluation & comparison',
105
+ invocation: '@research',
106
+ file: '1-leadership/research.md',
107
+ capabilities: ['technology_evaluation', 'comparison', 'recommendations'],
108
+ canInvoke: []
109
+ },
110
+
111
+ // Tier 2: Development
112
+ backend: {
113
+ name: 'Backend',
114
+ tier: 2,
115
+ tierName: 'Development',
116
+ role: 'API & server implementation',
117
+ invocation: '@backend',
118
+ file: '2-development/backend.md',
119
+ capabilities: ['api_development', 'business_logic', 'integrations'],
120
+ canInvoke: ['database']
121
+ },
122
+ frontend: {
123
+ name: 'Frontend',
124
+ tier: 2,
125
+ tierName: 'Development',
126
+ role: 'UI & component implementation',
127
+ invocation: '@frontend',
128
+ file: '2-development/frontend.md',
129
+ capabilities: ['ui_development', 'components', 'state_management'],
130
+ canInvoke: []
131
+ },
132
+ database: {
133
+ name: 'Database',
134
+ tier: 2,
135
+ tierName: 'Development',
136
+ role: 'Schema design & query optimization',
137
+ invocation: '@database',
138
+ file: '2-development/database.md',
139
+ capabilities: ['schema_design', 'migrations', 'query_optimization'],
140
+ canInvoke: []
141
+ },
142
+
143
+ // Tier 3: Security
144
+ auth: {
145
+ name: 'Auth',
146
+ tier: 3,
147
+ tierName: 'Security',
148
+ role: 'Authentication & authorization',
149
+ invocation: '@auth',
150
+ file: '3-security/auth.md',
151
+ capabilities: ['authentication', 'authorization', 'session_management'],
152
+ canInvoke: ['backend', 'database']
153
+ },
154
+ security: {
155
+ name: 'Security',
156
+ tier: 3,
157
+ tierName: 'Security',
158
+ role: 'Security audits & vulnerability fixes',
159
+ invocation: '@security',
160
+ file: '3-security/security.md',
161
+ capabilities: ['security_audit', 'vulnerability_detection', 'hardening'],
162
+ canInvoke: []
163
+ },
164
+
165
+ // Tier 4: DevOps
166
+ devops: {
167
+ name: 'DevOps',
168
+ tier: 4,
169
+ tierName: 'DevOps',
170
+ role: 'Deployment & infrastructure',
171
+ invocation: '@devops',
172
+ file: '4-devops/devops.md',
173
+ capabilities: ['deployment', 'ci_cd', 'infrastructure', 'monitoring'],
174
+ canInvoke: []
175
+ },
176
+
177
+ // Tier 5: Quality
178
+ testing: {
179
+ name: 'Testing',
180
+ tier: 5,
181
+ tierName: 'Quality',
182
+ role: 'QA & test automation',
183
+ invocation: '@testing',
184
+ file: '5-quality/testing.md',
185
+ capabilities: ['unit_testing', 'integration_testing', 'e2e_testing'],
186
+ canInvoke: []
187
+ },
188
+ reviewer: {
189
+ name: 'Reviewer',
190
+ tier: 5,
191
+ tierName: 'Quality',
192
+ role: 'Code review & quality checks',
193
+ invocation: '@reviewer',
194
+ file: '5-quality/reviewer.md',
195
+ capabilities: ['code_review', 'best_practices', 'quality_gates'],
196
+ canInvoke: []
197
+ },
198
+ debugger: {
199
+ name: 'Debugger',
200
+ tier: 5,
201
+ tierName: 'Quality',
202
+ role: 'Bug investigation & fixes',
203
+ invocation: '@debugger',
204
+ file: '5-quality/debugger.md',
205
+ capabilities: ['debugging', 'root_cause_analysis', 'bug_fixing'],
206
+ canInvoke: ['backend', 'frontend', 'database']
207
+ },
208
+ documentation: {
209
+ name: 'Documentation',
210
+ tier: 5,
211
+ tierName: 'Quality',
212
+ role: 'Technical writing & docs maintenance',
213
+ invocation: '@documentation',
214
+ file: '5-quality/documentation.md',
215
+ capabilities: ['technical_writing', 'api_docs', 'user_guides'],
216
+ canInvoke: []
217
+ },
218
+
219
+ // Tier 6: Specialist
220
+ performance: {
221
+ name: 'Performance',
222
+ tier: 6,
223
+ tierName: 'Specialist',
224
+ role: 'Performance optimization',
225
+ invocation: '@performance',
226
+ file: '6-specialist/performance.md',
227
+ capabilities: ['profiling', 'optimization', 'caching', 'load_testing'],
228
+ canInvoke: ['backend', 'frontend', 'database']
229
+ },
230
+ refactoring: {
231
+ name: 'Refactoring',
232
+ tier: 6,
233
+ tierName: 'Specialist',
234
+ role: 'Code quality & design patterns',
235
+ invocation: '@refactoring',
236
+ file: '6-specialist/refactoring.md',
237
+ capabilities: ['code_cleanup', 'design_patterns', 'architecture_improvement'],
238
+ canInvoke: ['backend', 'frontend']
239
+ }
240
+ };
241
+
242
+ // ============================================================================
243
+ // TIER DEPENDENCY GRAPH
244
+ // ============================================================================
245
+
246
+ /**
247
+ * Defines standard execution flow between tiers.
248
+ * This represents the typical order of operations for a full feature.
249
+ */
250
+ export const TIER_FLOW = {
251
+ standard: [
252
+ { tier: 1, phase: 'Planning', required: true },
253
+ { tier: 2, phase: 'Implementation', required: true },
254
+ { tier: 3, phase: 'Security', required: false },
255
+ { tier: 5, phase: 'Quality', required: true },
256
+ { tier: 4, phase: 'Deployment', required: false },
257
+ { tier: 6, phase: 'Optimization', required: false }
258
+ ],
259
+ hotfix: [
260
+ { tier: 5, phase: 'Debug', agents: ['debugger'], required: true },
261
+ { tier: 5, phase: 'Test', agents: ['testing'], required: true },
262
+ { tier: 4, phase: 'Deploy', agents: ['devops'], required: true }
263
+ ],
264
+ optimization: [
265
+ { tier: 6, phase: 'Optimize', required: true },
266
+ { tier: 5, phase: 'Test', agents: ['testing'], required: true },
267
+ { tier: 5, phase: 'Review', agents: ['reviewer'], required: true }
268
+ ]
269
+ };
270
+
271
+ /**
272
+ * Agent dependency graph - which agents depend on outputs from others.
273
+ */
274
+ export const AGENT_DEPENDENCIES = {
275
+ // Leadership tier has no dependencies (entry points)
276
+ planner: [],
277
+ cto: ['planner'],
278
+ research: ['planner'],
279
+
280
+ // Development depends on leadership decisions
281
+ database: ['cto'],
282
+ backend: ['cto', 'database'],
283
+ frontend: ['cto', 'backend'],
284
+
285
+ // Security depends on implementation
286
+ auth: ['backend', 'database'],
287
+ security: ['backend', 'frontend', 'auth'],
288
+
289
+ // Quality depends on implementation
290
+ testing: ['backend', 'frontend'],
291
+ reviewer: ['backend', 'frontend', 'testing'],
292
+ debugger: [], // Can be invoked anytime
293
+ documentation: ['backend', 'frontend'],
294
+
295
+ // DevOps depends on quality approval
296
+ devops: ['testing', 'reviewer'],
297
+
298
+ // Specialist can run after implementation
299
+ performance: ['backend', 'frontend'],
300
+ refactoring: ['backend', 'frontend']
301
+ };
302
+
303
+ // ============================================================================
304
+ // UTILITY FUNCTIONS
305
+ // ============================================================================
306
+
307
+ /**
308
+ * Get agent by name.
309
+ */
310
+ export function getAgent(name) {
311
+ const normalized = name.toLowerCase().replace('@', '');
312
+ return AGENTS[normalized] || null;
313
+ }
314
+
315
+ /**
316
+ * Get all agents in a tier.
317
+ */
318
+ export function getAgentsByTier(tierId) {
319
+ return Object.values(AGENTS).filter(agent => agent.tier === tierId);
320
+ }
321
+
322
+ /**
323
+ * Get tier by ID.
324
+ */
325
+ export function getTier(tierId) {
326
+ return Object.values(TIERS).find(tier => tier.id === tierId) || null;
327
+ }
328
+
329
+ /**
330
+ * Get tier by agent name.
331
+ */
332
+ export function getTierForAgent(agentName) {
333
+ const agent = getAgent(agentName);
334
+ return agent ? getTier(agent.tier) : null;
335
+ }
336
+
337
+ /**
338
+ * Get dependencies for an agent.
339
+ */
340
+ export function getAgentDependencies(agentName) {
341
+ const normalized = agentName.toLowerCase().replace('@', '');
342
+ return AGENT_DEPENDENCIES[normalized] || [];
343
+ }
344
+
345
+ /**
346
+ * Check if agent A can invoke agent B.
347
+ */
348
+ export function canInvoke(agentA, agentB) {
349
+ const a = getAgent(agentA);
350
+ if (!a) return false;
351
+ if (a.canInvoke.includes('all')) return true;
352
+ return a.canInvoke.includes(agentB.toLowerCase().replace('@', ''));
353
+ }
354
+
355
+ /**
356
+ * Get execution order for a set of agents based on dependencies.
357
+ */
358
+ export function getExecutionOrder(agentNames) {
359
+ const normalized = agentNames.map(n => n.toLowerCase().replace('@', ''));
360
+ const visited = new Set();
361
+ const order = [];
362
+
363
+ function visit(agent) {
364
+ if (visited.has(agent)) return;
365
+ visited.add(agent);
366
+
367
+ const deps = AGENT_DEPENDENCIES[agent] || [];
368
+ for (const dep of deps) {
369
+ if (normalized.includes(dep)) {
370
+ visit(dep);
371
+ }
372
+ }
373
+ order.push(agent);
374
+ }
375
+
376
+ for (const agent of normalized) {
377
+ visit(agent);
378
+ }
379
+
380
+ return order;
381
+ }
382
+
383
+ /**
384
+ * Identify parallel execution opportunities.
385
+ */
386
+ export function findParallelGroups(agentNames) {
387
+ const order = getExecutionOrder(agentNames);
388
+ const groups = [];
389
+ const scheduled = new Set();
390
+
391
+ while (scheduled.size < order.length) {
392
+ const group = [];
393
+
394
+ for (const agent of order) {
395
+ if (scheduled.has(agent)) continue;
396
+
397
+ const deps = AGENT_DEPENDENCIES[agent] || [];
398
+ const depsInList = deps.filter(d => order.includes(d));
399
+ const depsMet = depsInList.every(d => scheduled.has(d));
400
+
401
+ if (depsMet) {
402
+ group.push(agent);
403
+ }
404
+ }
405
+
406
+ if (group.length === 0) break; // Prevent infinite loop
407
+
408
+ for (const agent of group) {
409
+ scheduled.add(agent);
410
+ }
411
+ groups.push(group);
412
+ }
413
+
414
+ return groups;
415
+ }
416
+
417
+ /**
418
+ * Generate a tier summary for display.
419
+ */
420
+ export function getTierSummary() {
421
+ return Object.values(TIERS).map(tier => ({
422
+ id: tier.id,
423
+ name: tier.name,
424
+ description: tier.description,
425
+ agentCount: tier.agents.length,
426
+ agents: tier.agents.map(a => AGENTS[a]?.name || a)
427
+ }));
428
+ }
429
+
430
+ /**
431
+ * Validate a pipeline for dependency violations.
432
+ */
433
+ export function validatePipeline(pipeline) {
434
+ const errors = [];
435
+ const completed = new Set();
436
+
437
+ for (let i = 0; i < pipeline.length; i++) {
438
+ const step = pipeline[i];
439
+ const agent = step.agent?.toLowerCase().replace('@', '');
440
+ const deps = AGENT_DEPENDENCIES[agent] || [];
441
+
442
+ for (const dep of deps) {
443
+ // Check if dependency is in pipeline and comes before
444
+ const depIndex = pipeline.findIndex(s =>
445
+ s.agent?.toLowerCase().replace('@', '') === dep
446
+ );
447
+
448
+ if (depIndex > i) {
449
+ errors.push({
450
+ step: i + 1,
451
+ agent,
452
+ error: `Depends on ${dep} which is scheduled after (step ${depIndex + 1})`
453
+ });
454
+ }
455
+ }
456
+
457
+ completed.add(agent);
458
+ }
459
+
460
+ return {
461
+ valid: errors.length === 0,
462
+ errors
463
+ };
464
+ }
465
+
466
+ // ============================================================================
467
+ // EXPORTS
468
+ // ============================================================================
469
+
470
+ export default {
471
+ TIERS,
472
+ AGENTS,
473
+ TIER_FLOW,
474
+ AGENT_DEPENDENCIES,
475
+ getAgent,
476
+ getAgentsByTier,
477
+ getTier,
478
+ getTierForAgent,
479
+ getAgentDependencies,
480
+ canInvoke,
481
+ getExecutionOrder,
482
+ findParallelGroups,
483
+ getTierSummary,
484
+ validatePipeline
485
+ };
@@ -1,4 +1,4 @@
1
- import { githubBlobUrl, githubTreeUrl } from '../config/urls.js';
1
+ import { githubBlobUrl, githubWebUrl } from '../config/urls.js';
2
2
 
3
3
  export const CONTEXT_TEMPLATE = `# {{PROJECT_NAME}} - Context
4
4
 
@@ -21,6 +21,6 @@ export const CONTEXT_TEMPLATE = `# {{PROJECT_NAME}} - Context
21
21
  Setting up the implementation plan.
22
22
 
23
23
  ## Resources
24
- - [Ultra-Dex Template](${githubTreeUrl('')})
24
+ - [Ultra-Dex Template](${githubWebUrl()})
25
25
  - [TaskFlow Example](${githubBlobUrl('@%20Ultra%20DeX/Saas%20plan/Examples/TaskFlow-Complete.md')})
26
26
  `;
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: {{name}}
3
+ tier: {{tier}}
4
+ role: {{role}}
5
+ ---
6
+ # {{name}} Agent
7
+ ## Expertise
8
+ {{expertise}}
9
+ ## System Prompt
10
+ {{prompt}}
@@ -26,11 +26,13 @@ export async function copyWithFallback(primaryPath, fallbackPath, destinationPat
26
26
 
27
27
  export async function listWithFallback(primaryPath, fallbackPath) {
28
28
  try {
29
- return await fs.readdir(primaryPath);
29
+ const files = await fs.readdir(primaryPath);
30
+ return { files, sourcePath: primaryPath };
30
31
  } catch (primaryError) {
31
32
  if (!fallbackPath) {
32
33
  throw primaryError;
33
34
  }
34
- return await fs.readdir(fallbackPath);
35
+ const files = await fs.readdir(fallbackPath);
36
+ return { files, sourcePath: fallbackPath };
35
37
  }
36
38
  }
@@ -21,47 +21,20 @@ export async function pathExists(targetPath, type = 'file') {
21
21
  }
22
22
  }
23
23
 
24
- export async function copyWithFallback({ primary, fallback, destination, onPrimaryMissing }) {
25
- try {
26
- await fs.copyFile(primary, destination);
27
- return 'primary';
28
- } catch (primaryError) {
29
- if (onPrimaryMissing) {
30
- onPrimaryMissing(primaryError);
31
- }
32
- if (!fallback) {
33
- throw primaryError;
34
- }
35
- await fs.copyFile(fallback, destination);
36
- return 'fallback';
37
- }
38
- }
39
-
40
- export async function readWithFallback({ primary, fallback, encoding = 'utf-8' }) {
41
- try {
42
- return await fs.readFile(primary, encoding);
43
- } catch (primaryError) {
44
- if (!fallback) {
45
- throw primaryError;
46
- }
47
- return await fs.readFile(fallback, encoding);
48
- }
49
- }
50
-
51
24
  export function resolveAssetPath(basePath, relativePath) {
52
25
  return path.join(basePath, relativePath);
53
26
  }
54
27
 
55
- export async function copyDirectory(srcDir, destDir) {
56
- await fs.mkdir(destDir, { recursive: true });
57
- const entries = await fs.readdir(srcDir, { withFileTypes: true });
28
+ export async function copyDirectory(sourceDir, targetDir) {
29
+ await fs.mkdir(targetDir, { recursive: true });
30
+ const entries = await fs.readdir(sourceDir, { withFileTypes: true });
58
31
  for (const entry of entries) {
59
- const srcPath = path.join(srcDir, entry.name);
60
- const destPath = path.join(destDir, entry.name);
32
+ const sourcePath = path.join(sourceDir, entry.name);
33
+ const targetPath = path.join(targetDir, entry.name);
61
34
  if (entry.isDirectory()) {
62
- await copyDirectory(srcPath, destPath);
35
+ await copyDirectory(sourcePath, targetPath);
63
36
  } else if (entry.isFile()) {
64
- await fs.copyFile(srcPath, destPath);
37
+ await fs.copyFile(sourcePath, targetPath);
65
38
  }
66
39
  }
67
40
  }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Graph Utility (CPG Implementation)
3
+ * Manages the Code Property Graph (CPG) for architectural memory
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { glob } from 'glob';
9
+
10
+ /**
11
+ * Build a simple Code Property Graph (CPG)
12
+ * Maps files, functions, and dependencies
13
+ */
14
+ export async function buildGraph() {
15
+ const files = await glob('**/*.{js,ts,jsx,tsx}', {
16
+ ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**'],
17
+ nodir: true
18
+ });
19
+
20
+ const graph = {
21
+ nodes: [],
22
+ edges: [],
23
+ lastUpdated: new Date().toISOString()
24
+ };
25
+
26
+ for (const file of files) {
27
+ try {
28
+ const content = await fs.readFile(file, 'utf8');
29
+ const fileNode = {
30
+ id: file,
31
+ type: 'file',
32
+ path: file,
33
+ exports: [],
34
+ imports: []
35
+ };
36
+
37
+ // Naive parsing using Regex (Phase 2.1)
38
+ // In Phase 2.2+ this would use tree-sitter
39
+
40
+ // Extract imports
41
+ const importRegex = /import\s+.*?\s+from\s+['"](.+?)['"]/g;
42
+ let match;
43
+ while ((match = importRegex.exec(content)) !== null) {
44
+ fileNode.imports.push(match[1]);
45
+ graph.edges.push({
46
+ source: file,
47
+ target: match[1],
48
+ type: 'depends_on'
49
+ });
50
+ }
51
+
52
+ // Extract function declarations
53
+ const funcRegex = /(?:export\s+)?(?:async\s+)?function\s+([a-zA-Z0-9_]+)/g;
54
+ while ((match = funcRegex.exec(content)) !== null) {
55
+ const funcName = match[1];
56
+ const funcId = `${file}:${funcName}`;
57
+ graph.nodes.push({
58
+ id: funcId,
59
+ type: 'function',
60
+ name: funcName,
61
+ parent: file
62
+ });
63
+ graph.edges.push({
64
+ source: funcId,
65
+ target: file,
66
+ type: 'contained_in'
67
+ });
68
+ fileNode.exports.push(funcName);
69
+ }
70
+
71
+ graph.nodes.push(fileNode);
72
+ } catch (e) {
73
+ // Skip files that can't be read
74
+ }
75
+ }
76
+
77
+ return graph;
78
+ }
79
+
80
+ /**
81
+ * Find the impact of changing a file
82
+ * @param {Object} graph - The CPG
83
+ * @param {string} filePath - The file being changed
84
+ */
85
+ export function getImpactAnalysis(graph, filePath) {
86
+ const impactedBy = graph.edges
87
+ .filter(edge => edge.target === filePath || filePath.endsWith(edge.target))
88
+ .map(edge => edge.source);
89
+
90
+ return [...new Set(impactedBy)];
91
+ }
92
+
93
+ /**
94
+ * Find structural truth (exact subgraph)
95
+ * @param {Object} graph - The CPG
96
+ * @param {string} query - Symbol name
97
+ */
98
+ export function queryGraph(graph, query) {
99
+ return graph.nodes.filter(node =>
100
+ node.id.includes(query) || (node.name && node.name === query)
101
+ );
102
+ }
103
+
104
+ export default {
105
+ buildGraph,
106
+ getImpactAnalysis,
107
+ queryGraph
108
+ };