aios-core 4.1.0 → 4.2.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 (145) hide show
  1. package/.aios-core/.session/current-session.json +14 -0
  2. package/.aios-core/core/registry/registry-schema.json +166 -166
  3. package/.aios-core/core/registry/service-registry.json +6585 -6585
  4. package/.aios-core/data/entity-registry.yaml +208 -8
  5. package/.aios-core/data/registry-update-log.jsonl +165 -0
  6. package/.aios-core/development/scripts/approval-workflow.js +642 -642
  7. package/.aios-core/development/scripts/backup-manager.js +606 -606
  8. package/.aios-core/development/scripts/branch-manager.js +389 -389
  9. package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
  10. package/.aios-core/development/scripts/commit-message-generator.js +849 -849
  11. package/.aios-core/development/scripts/conflict-resolver.js +674 -674
  12. package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
  13. package/.aios-core/development/scripts/diff-generator.js +351 -351
  14. package/.aios-core/development/scripts/elicitation-engine.js +384 -384
  15. package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
  16. package/.aios-core/development/scripts/git-wrapper.js +461 -461
  17. package/.aios-core/development/scripts/manifest-preview.js +244 -244
  18. package/.aios-core/development/scripts/metrics-tracker.js +775 -775
  19. package/.aios-core/development/scripts/modification-validator.js +554 -554
  20. package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
  21. package/.aios-core/development/scripts/performance-analyzer.js +757 -757
  22. package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
  23. package/.aios-core/development/scripts/rollback-handler.js +530 -530
  24. package/.aios-core/development/scripts/security-checker.js +358 -358
  25. package/.aios-core/development/scripts/template-engine.js +239 -239
  26. package/.aios-core/development/scripts/template-validator.js +278 -278
  27. package/.aios-core/development/scripts/test-generator.js +843 -843
  28. package/.aios-core/development/scripts/transaction-manager.js +589 -589
  29. package/.aios-core/development/scripts/usage-tracker.js +673 -673
  30. package/.aios-core/development/scripts/validate-filenames.js +226 -226
  31. package/.aios-core/development/scripts/version-tracker.js +526 -526
  32. package/.aios-core/development/scripts/yaml-validator.js +396 -396
  33. package/.aios-core/development/tasks/validate-next-story.md +99 -2
  34. package/.aios-core/development/templates/service-template/README.md.hbs +158 -158
  35. package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
  36. package/.aios-core/development/templates/service-template/client.ts.hbs +403 -403
  37. package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -182
  38. package/.aios-core/development/templates/service-template/index.ts.hbs +120 -120
  39. package/.aios-core/development/templates/service-template/package.json.hbs +87 -87
  40. package/.aios-core/development/templates/service-template/types.ts.hbs +145 -145
  41. package/.aios-core/development/templates/squad-template/LICENSE +21 -21
  42. package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
  43. package/.aios-core/docs/component-creation-guide.md +458 -0
  44. package/.aios-core/docs/session-update-pattern.md +307 -0
  45. package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +1963 -0
  46. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +1190 -0
  47. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +439 -0
  48. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +5398 -0
  49. package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +523 -0
  50. package/.aios-core/docs/template-syntax.md +267 -0
  51. package/.aios-core/docs/troubleshooting-guide.md +625 -0
  52. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +193 -193
  53. package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
  54. package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
  55. package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
  56. package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
  57. package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
  58. package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
  59. package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
  60. package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
  61. package/.aios-core/infrastructure/tests/utilities-audit-results.json +501 -0
  62. package/.aios-core/install-manifest.yaml +101 -101
  63. package/.aios-core/local-config.yaml.template +70 -70
  64. package/.aios-core/manifests/agents.csv +29 -0
  65. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  66. package/.aios-core/manifests/tasks.csv +198 -0
  67. package/.aios-core/manifests/workers.csv +204 -0
  68. package/.aios-core/monitor/hooks/lib/__init__.py +1 -1
  69. package/.aios-core/monitor/hooks/lib/enrich.py +58 -58
  70. package/.aios-core/monitor/hooks/lib/send_event.py +47 -47
  71. package/.aios-core/monitor/hooks/notification.py +29 -29
  72. package/.aios-core/monitor/hooks/post_tool_use.py +45 -45
  73. package/.aios-core/monitor/hooks/pre_compact.py +29 -29
  74. package/.aios-core/monitor/hooks/pre_tool_use.py +40 -40
  75. package/.aios-core/monitor/hooks/stop.py +29 -29
  76. package/.aios-core/monitor/hooks/subagent_stop.py +29 -29
  77. package/.aios-core/monitor/hooks/user_prompt_submit.py +38 -38
  78. package/.aios-core/product/templates/adr.hbs +125 -125
  79. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  80. package/.aios-core/product/templates/dbdr.hbs +241 -241
  81. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  82. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  83. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  84. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  85. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  86. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  87. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  88. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  89. package/.aios-core/product/templates/epic.hbs +212 -212
  90. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  91. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  92. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  93. package/.aios-core/product/templates/pmdr.hbs +186 -186
  94. package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
  95. package/.aios-core/product/templates/prd.hbs +201 -201
  96. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  97. package/.aios-core/product/templates/story.hbs +263 -263
  98. package/.aios-core/product/templates/task.hbs +170 -170
  99. package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
  100. package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
  101. package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
  102. package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
  103. package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
  104. package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
  105. package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
  106. package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
  107. package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
  108. package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
  109. package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
  110. package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
  111. package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
  112. package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
  113. package/.aios-core/product/templates/tmpl-view.sql +177 -177
  114. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  115. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  116. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  117. package/.aios-core/scripts/pm.sh +0 -0
  118. package/.claude/hooks/enforce-architecture-first.py +196 -196
  119. package/.claude/hooks/mind-clone-governance.py +192 -192
  120. package/.claude/hooks/read-protection.py +151 -151
  121. package/.claude/hooks/slug-validation.py +176 -176
  122. package/.claude/hooks/sql-governance.py +182 -182
  123. package/.claude/hooks/write-path-validation.py +194 -194
  124. package/.claude/rules/agent-authority.md +105 -0
  125. package/.claude/rules/coderabbit-integration.md +93 -0
  126. package/.claude/rules/ids-principles.md +112 -0
  127. package/.claude/rules/story-lifecycle.md +139 -0
  128. package/.claude/rules/workflow-execution.md +150 -0
  129. package/LICENSE +48 -48
  130. package/bin/aios-minimal.js +0 -0
  131. package/bin/aios.js +0 -0
  132. package/package.json +1 -1
  133. package/packages/aios-install/bin/aios-install.js +0 -0
  134. package/packages/aios-install/bin/edmcp.js +0 -0
  135. package/packages/aios-pro-cli/bin/aios-pro.js +0 -0
  136. package/packages/installer/src/wizard/pro-setup.js +433 -49
  137. package/scripts/check-markdown-links.py +352 -352
  138. package/scripts/code-intel-health-check.js +343 -0
  139. package/scripts/dashboard-parallel-dev.sh +0 -0
  140. package/scripts/dashboard-parallel-phase3.sh +0 -0
  141. package/scripts/dashboard-parallel-phase4.sh +0 -0
  142. package/scripts/glue/README.md +355 -0
  143. package/scripts/glue/compose-agent-prompt.cjs +362 -0
  144. package/scripts/install-monitor-hooks.sh +0 -0
  145. package/.aios-core/lib/build.json +0 -1
@@ -1,674 +1,674 @@
1
- const fs = require('fs').promises;
2
- const path = require('path');
3
- const chalk = require('chalk');
4
-
5
- /**
6
- * Usage tracker for AIOS-FULLSTACK framework components
7
- * Tracks component usage patterns for deprecation warnings and impact analysis
8
- */
9
- class UsageTracker {
10
- constructor(options = {}) {
11
- this.rootPath = options.rootPath || process.cwd();
12
- this.usageDir = path.join(this.rootPath, '.aios', 'usage');
13
- this.usageCache = new Map();
14
- this.scanPatterns = this.initializeScanPatterns();
15
- }
16
-
17
- /**
18
- * Initialize usage tracker
19
- */
20
- async initialize() {
21
- try {
22
- // Create usage directory
23
- await fs.mkdir(this.usageDir, { recursive: true });
24
-
25
- console.log(chalk.green('✅ Usage tracker initialized'));
26
- return true;
27
-
28
- } catch (_error) {
29
- console.error(chalk.red(`Failed to initialize usage tracker: ${error.message}`));
30
- throw error;
31
- }
32
- }
33
-
34
- /**
35
- * Analyze component usage across the codebase
36
- */
37
- async analyzeComponentUsage(componentId, options = {}) {
38
- const analysis = {
39
- component_id: componentId,
40
- analysis_timestamp: new Date().toISOString(),
41
- total_references: 0,
42
- usage_locations: [],
43
- dependent_components: [],
44
- external_references: [],
45
- usage_patterns: {},
46
- risk_assessment: {
47
- impact_level: 'low',
48
- affected_areas: [],
49
- migration_complexity: 'simple'
50
- }
51
- };
52
-
53
- try {
54
- console.log(chalk.blue(`🔍 Analyzing usage for component: ${componentId}`));
55
-
56
- // Get component information
57
- const component = await this.getComponentInfo(componentId);
58
- if (!component) {
59
- throw new Error(`Component not found: ${componentId}`);
60
- }
61
-
62
- // Scan for direct references
63
- const directReferences = await this.scanForDirectReferences(component, options);
64
- analysis.usage_locations = directReferences;
65
- analysis.total_references = directReferences.length;
66
-
67
- // Analyze dependency relationships
68
- const dependencies = await this.analyzeDependencyRelationships(component, options);
69
- analysis.dependent_components = dependencies;
70
-
71
- // Check for external references (imports, configurations, etc.)
72
- const externalRefs = await this.scanForExternalReferences(component, options);
73
- analysis.external_references = externalRefs;
74
-
75
- // Analyze usage patterns
76
- analysis.usage_patterns = await this.analyzeUsagePatterns(component, directReferences);
77
-
78
- // Assess migration risk
79
- analysis.risk_assessment = this.assessMigrationRisk(analysis);
80
-
81
- // Cache results
82
- this.usageCache.set(componentId, analysis);
83
-
84
- // Save detailed analysis
85
- await this.saveUsageAnalysis(analysis);
86
-
87
- console.log(chalk.green(`✅ Usage analysis completed for ${componentId}`));
88
- console.log(chalk.gray(` Total references: ${analysis.total_references}`));
89
- console.log(chalk.gray(` Dependent components: ${analysis.dependent_components.length}`));
90
- console.log(chalk.gray(` Impact level: ${analysis.risk_assessment.impact_level}`));
91
-
92
- return analysis;
93
-
94
- } catch (_error) {
95
- console.error(chalk.red(`Usage analysis failed for ${componentId}: ${error.message}`));
96
- throw error;
97
- }
98
- }
99
-
100
- /**
101
- * Track usage changes over time for deprecated components
102
- */
103
- async trackUsageChanges(componentId, baselineAnalysis) {
104
- const currentAnalysis = await this.analyzeComponentUsage(componentId);
105
-
106
- const changes = {
107
- component_id: componentId,
108
- comparison_timestamp: new Date().toISOString(),
109
- baseline_timestamp: baselineAnalysis.analysis_timestamp,
110
- changes: {
111
- total_references: {
112
- before: baselineAnalysis.total_references,
113
- after: currentAnalysis.total_references,
114
- change: currentAnalysis.total_references - baselineAnalysis.total_references
115
- },
116
- dependent_components: {
117
- before: baselineAnalysis.dependent_components.length,
118
- after: currentAnalysis.dependent_components.length,
119
- change: currentAnalysis.dependent_components.length - baselineAnalysis.dependent_components.length
120
- },
121
- new_usages: this.findNewUsages(baselineAnalysis.usage_locations, currentAnalysis.usage_locations),
122
- removed_usages: this.findRemovedUsages(baselineAnalysis.usage_locations, currentAnalysis.usage_locations)
123
- },
124
- trend: this.calculateUsageTrend(baselineAnalysis, currentAnalysis),
125
- migration_progress: this.calculateMigrationProgress(baselineAnalysis, currentAnalysis)
126
- };
127
-
128
- // Save change tracking
129
- await this.saveUsageChanges(changes);
130
-
131
- return changes;
132
- }
133
-
134
- /**
135
- * Generate usage warnings for deprecated components
136
- */
137
- async generateUsageWarnings(componentId, deprecationInfo) {
138
- const analysis = await this.analyzeComponentUsage(componentId);
139
- const warnings = [];
140
-
141
- for (const _usage of analysis.usage_locations) {
142
- const warning = {
143
- type: 'deprecation_warning',
144
- component_id: componentId,
145
- usage_location: {
146
- file: usage.file,
147
- line: usage.line,
148
- context: usage.context
149
- },
150
- message: this.generateWarningMessage(componentId, deprecationInfo, usage),
151
- severity: this.calculateWarningSeverity(deprecationInfo, usage),
152
- suggested_actions: this.generateSuggestedActions(componentId, deprecationInfo, usage)
153
- };
154
-
155
- warnings.push(warning);
156
- }
157
-
158
- // Save warnings for later processing
159
- await this.saveUsageWarnings(componentId, warnings);
160
-
161
- return warnings;
162
- }
163
-
164
- /**
165
- * Get usage statistics for reporting
166
- */
167
- async getUsageStatistics(componentIds = null) {
168
- const stats = {
169
- generated_at: new Date().toISOString(),
170
- total_components_analyzed: 0,
171
- high_usage_components: [],
172
- zero_usage_components: [],
173
- usage_distribution: {},
174
- dependency_graph: {}
175
- };
176
-
177
- const componentsToAnalyze = componentIds || await this.getAllTrackedComponents();
178
-
179
- for (const componentId of componentsToAnalyze) {
180
- try {
181
- const analysis = await this.getOrAnalyzeUsage(componentId);
182
- stats.total_components_analyzed++;
183
-
184
- // Categorize by usage level
185
- if (analysis.total_references === 0) {
186
- stats.zero_usage_components.push(componentId);
187
- } else if (analysis.total_references >= 10) {
188
- stats.high_usage_components.push({
189
- component_id: componentId,
190
- reference_count: analysis.total_references,
191
- impact_level: analysis.risk_assessment.impact_level
192
- });
193
- }
194
-
195
- // Add to usage distribution
196
- const usageRange = this.categorizeUsageLevel(analysis.total_references);
197
- stats.usage_distribution[usageRange] = (stats.usage_distribution[usageRange] || 0) + 1;
198
-
199
- // Add to dependency graph
200
- stats.dependency_graph[componentId] = analysis.dependent_components.map(dep => dep.component_id);
201
-
202
- } catch (_error) {
203
- console.warn(chalk.yellow(`Failed to analyze usage for ${componentId}: ${error.message}`));
204
- }
205
- }
206
-
207
- return stats;
208
- }
209
-
210
- /**
211
- * Scan for direct references to a component
212
- */
213
- async scanForDirectReferences(component, options = {}) {
214
- const references = [];
215
- const scanPaths = await this.getScanPaths(_options);
216
-
217
- for (const scanPath of scanPaths) {
218
- try {
219
- const pathReferences = await this.scanPath(scanPath, component);
220
- references.push(...pathReferences);
221
- } catch (_error) {
222
- console.warn(chalk.yellow(`Failed to scan path ${scanPath}: ${error.message}`));
223
- }
224
- }
225
-
226
- return references;
227
- }
228
-
229
- /**
230
- * Scan a specific path for component references
231
- */
232
- async scanPath(scanPath, component) {
233
- const references = [];
234
- const files = await this.getFilesToScan(scanPath);
235
-
236
- for (const file of files) {
237
- try {
238
- const fileReferences = await this.scanFile(file, component);
239
- references.push(...fileReferences);
240
- } catch (_error) {
241
- // Skip files that can't be read
242
- continue;
243
- }
244
- }
245
-
246
- return references;
247
- }
248
-
249
- /**
250
- * Scan a single file for component references
251
- */
252
- async scanFile(filePath, component) {
253
- const references = [];
254
-
255
- try {
256
- const content = await fs.readFile(filePath, 'utf-8');
257
- const lines = content.split('\n');
258
-
259
- for (let i = 0; i < lines.length; i++) {
260
- const line = lines[i];
261
- const lineNumber = i + 1;
262
-
263
- // Check for various reference patterns
264
- const matches = this.findReferencesInLine(line, component);
265
-
266
- for (const match of matches) {
267
- references.push({
268
- file: filePath,
269
- line: lineNumber,
270
- column: match.column,
271
- context: line.trim(),
272
- reference_type: match.type,
273
- match_text: match.text
274
- });
275
- }
276
- }
277
- } catch (_error) {
278
- // File couldn't be read, skip
279
- }
280
-
281
- return references;
282
- }
283
-
284
- /**
285
- * Find references in a single line of code
286
- */
287
- findReferencesInLine(line, component) {
288
- const matches = [];
289
- const patterns = this.scanPatterns[component.type] || this.scanPatterns.default;
290
-
291
- for (const pattern of patterns) {
292
- const regex = new RegExp(pattern.pattern.replace('{component_name}', component.name), pattern.flags || 'gi');
293
- let match;
294
-
295
- while ((match = regex.exec(line)) !== null) {
296
- matches.push({
297
- type: pattern.type,
298
- text: match[0],
299
- column: match.index,
300
- confidence: pattern.confidence || 0.8
301
- });
302
- }
303
- }
304
-
305
- return matches;
306
- }
307
-
308
- /**
309
- * Analyze dependency relationships
310
- */
311
- async analyzeDependencyRelationships(component, options = {}) {
312
- const dependencies = [];
313
-
314
- // This would analyze manifest files, import statements, etc.
315
- // For now, return empty array as placeholder
316
-
317
- return dependencies;
318
- }
319
-
320
- /**
321
- * Scan for external references (config files, documentation, etc.)
322
- */
323
- async scanForExternalReferences(component, options = {}) {
324
- const externalRefs = [];
325
-
326
- // Check configuration files
327
- const configRefs = await this.scanConfigurationFiles(component);
328
- externalRefs.push(...configRefs);
329
-
330
- // Check documentation
331
- const docRefs = await this.scanDocumentationFiles(component);
332
- externalRefs.push(...docRefs);
333
-
334
- return externalRefs;
335
- }
336
-
337
- /**
338
- * Analyze usage patterns
339
- */
340
- async analyzeUsagePatterns(component, references) {
341
- const patterns = {
342
- by_file_type: {},
343
- by_usage_type: {},
344
- temporal_distribution: {},
345
- complexity_indicators: {}
346
- };
347
-
348
- for (const ref of references) {
349
- // Group by file extension
350
- const ext = path.extname(ref.file);
351
- patterns.by_file_type[ext] = (patterns.by_file_type[ext] || 0) + 1;
352
-
353
- // Group by reference type
354
- patterns.by_usage_type[ref.reference_type] = (patterns.by_usage_type[ref.reference_type] || 0) + 1;
355
- }
356
-
357
- return patterns;
358
- }
359
-
360
- /**
361
- * Assess migration risk based on usage analysis
362
- */
363
- assessMigrationRisk(analysis) {
364
- let impactLevel = 'low';
365
- let migrationComplexity = 'simple';
366
- const affectedAreas = [];
367
-
368
- // Assess based on total references
369
- if (analysis.total_references > 20) {
370
- impactLevel = 'high';
371
- migrationComplexity = 'complex';
372
- } else if (analysis.total_references > 10) {
373
- impactLevel = 'medium';
374
- migrationComplexity = 'moderate';
375
- }
376
-
377
- // Check for complex usage patterns
378
- if (analysis.dependent_components.length > 5) {
379
- migrationComplexity = 'complex';
380
- affectedAreas.push('component_dependencies');
381
- }
382
-
383
- if (analysis.external_references.length > 0) {
384
- affectedAreas.push('external_configuration');
385
- }
386
-
387
- return {
388
- impact_level: impactLevel,
389
- affected_areas: affectedAreas,
390
- migration_complexity: migrationComplexity
391
- };
392
- }
393
-
394
- // Helper methods
395
-
396
- async getComponentInfo(componentId) {
397
- // This would typically integrate with the component registry
398
- // For now, return a basic component structure
399
- const [type, name] = componentId.split('/');
400
-
401
- return {
402
- id: componentId,
403
- type: type,
404
- name: name,
405
- file_path: `aios-core/${type}s/${name}.md`
406
- };
407
- }
408
-
409
- async getScanPaths(_options) {
410
- const defaultPaths = [
411
- path.join(this.rootPath, 'aios-core'),
412
- path.join(this.rootPath, 'src'),
413
- path.join(this.rootPath, 'lib')
414
- ];
415
-
416
- if (options.scanPaths) {
417
- return options.scanPaths;
418
- }
419
-
420
- // Filter paths that exist
421
- const existingPaths = [];
422
- for (const scanPath of defaultPaths) {
423
- try {
424
- await fs.access(scanPath);
425
- existingPaths.push(scanPath);
426
- } catch (_error) {
427
- // Path doesn't exist, skip
428
- }
429
- }
430
-
431
- return existingPaths;
432
- }
433
-
434
- async getFilesToScan(scanPath) {
435
- const files = [];
436
-
437
- try {
438
- const entries = await fs.readdir(scanPath, { withFileTypes: true });
439
-
440
- for (const entry of entries) {
441
- const fullPath = path.join(scanPath, entry.name);
442
-
443
- if (entry.isDirectory()) {
444
- // Recursively scan subdirectories
445
- const subFiles = await this.getFilesToScan(fullPath);
446
- files.push(...subFiles);
447
- } else if (this.shouldScanFile(entry.name)) {
448
- files.push(fullPath);
449
- }
450
- }
451
- } catch (_error) {
452
- // Can't read directory, skip
453
- }
454
-
455
- return files;
456
- }
457
-
458
- shouldScanFile(filename) {
459
- const scanExtensions = ['.js', '.ts', '.md', '.yaml', '.yml', '.json'];
460
- const ext = path.extname(filename);
461
- return scanExtensions.includes(ext);
462
- }
463
-
464
- async scanConfigurationFiles(component) {
465
- const configRefs = [];
466
- const configFiles = [
467
- 'package.json',
468
- '.aiosrc',
469
- 'aios.config.js',
470
- 'manifest.yaml'
471
- ];
472
-
473
- for (const configFile of configFiles) {
474
- const configPath = path.join(this.rootPath, configFile);
475
-
476
- try {
477
- const refs = await this.scanFile(configPath, component);
478
- configRefs.push(...refs.map(ref => ({ ...ref, source: 'configuration' })));
479
- } catch (_error) {
480
- // Config file doesn't exist or can't be read
481
- }
482
- }
483
-
484
- return configRefs;
485
- }
486
-
487
- async scanDocumentationFiles(component) {
488
- const docRefs = [];
489
- const docsPath = path.join(this.rootPath, 'docs');
490
-
491
- try {
492
- const files = await this.getFilesToScan(docsPath);
493
-
494
- for (const file of files) {
495
- const refs = await this.scanFile(file, component);
496
- docRefs.push(...refs.map(ref => ({ ...ref, source: 'documentation' })));
497
- }
498
- } catch (_error) {
499
- // Docs directory doesn't exist
500
- }
501
-
502
- return docRefs;
503
- }
504
-
505
- findNewUsages(oldUsages, newUsages) {
506
- return newUsages.filter(newUsage =>
507
- !oldUsages.some(oldUsage =>
508
- oldUsage.file === newUsage.file && oldUsage.line === newUsage.line
509
- )
510
- );
511
- }
512
-
513
- findRemovedUsages(oldUsages, newUsages) {
514
- return oldUsages.filter(oldUsage =>
515
- !newUsages.some(newUsage =>
516
- newUsage.file === oldUsage.file && newUsage.line === oldUsage.line
517
- )
518
- );
519
- }
520
-
521
- calculateUsageTrend(baseline, current) {
522
- const referenceChange = current.total_references - baseline.total_references;
523
-
524
- if (referenceChange > 0) return 'increasing';
525
- if (referenceChange < 0) return 'decreasing';
526
- return 'stable';
527
- }
528
-
529
- calculateMigrationProgress(baseline, current) {
530
- if (baseline.total_references === 0) return 1.0;
531
-
532
- const remainingUsages = current.total_references;
533
- const originalUsages = baseline.total_references;
534
-
535
- return Math.max(0, (originalUsages - remainingUsages) / originalUsages);
536
- }
537
-
538
- generateWarningMessage(componentId, deprecationInfo, usage) {
539
- let message = `DEPRECATED: ${componentId} is deprecated`;
540
-
541
- if (deprecationInfo.replacement) {
542
- message += ` - use ${deprecationInfo.replacement} instead`;
543
- }
544
-
545
- if (deprecationInfo.removalVersion) {
546
- message += ` (will be removed in ${deprecationInfo.removalVersion})`;
547
- }
548
-
549
- return message;
550
- }
551
-
552
- calculateWarningSeverity(deprecationInfo, usage) {
553
- if (deprecationInfo.severity === 'critical') return 'error';
554
- if (deprecationInfo.severity === 'high') return 'warning';
555
- return 'info';
556
- }
557
-
558
- generateSuggestedActions(componentId, deprecationInfo, usage) {
559
- const actions = [];
560
-
561
- if (deprecationInfo.replacement) {
562
- actions.push(`Replace with ${deprecationInfo.replacement}`);
563
- }
564
-
565
- if (deprecationInfo.migrationGuide) {
566
- actions.push(`See migration guide: ${deprecationInfo.migrationGuide}`);
567
- }
568
-
569
- actions.push('Update imports and references');
570
- actions.push('Test functionality after replacement');
571
-
572
- return actions;
573
- }
574
-
575
- categorizeUsageLevel(referenceCount) {
576
- if (referenceCount === 0) return 'zero';
577
- if (referenceCount <= 5) return 'low';
578
- if (referenceCount <= 15) return 'medium';
579
- if (referenceCount <= 30) return 'high';
580
- return 'very_high';
581
- }
582
-
583
- async getOrAnalyzeUsage(componentId) {
584
- if (this.usageCache.has(componentId)) {
585
- return this.usageCache.get(componentId);
586
- }
587
-
588
- return await this.analyzeComponentUsage(componentId);
589
- }
590
-
591
- async getAllTrackedComponents() {
592
- // This would typically come from a component registry
593
- // For now, return empty array
594
- return [];
595
- }
596
-
597
- async saveUsageAnalysis(analysis) {
598
- const filename = `usage-${analysis.component_id.replace('/', '-')}-${Date.now()}.json`;
599
- const filePath = path.join(this.usageDir, filename);
600
-
601
- await fs.writeFile(filePath, JSON.stringify(analysis, null, 2));
602
- }
603
-
604
- async saveUsageChanges(changes) {
605
- const filename = `changes-${changes.component_id.replace('/', '-')}-${Date.now()}.json`;
606
- const filePath = path.join(this.usageDir, filename);
607
-
608
- await fs.writeFile(filePath, JSON.stringify(changes, null, 2));
609
- }
610
-
611
- async saveUsageWarnings(componentId, warnings) {
612
- const filename = `warnings-${componentId.replace('/', '-')}-${Date.now()}.json`;
613
- const filePath = path.join(this.usageDir, filename);
614
-
615
- await fs.writeFile(filePath, JSON.stringify(warnings, null, 2));
616
- }
617
-
618
- initializeScanPatterns() {
619
- return {
620
- agent: [
621
- {
622
- pattern: 'agent:\\s*{component_name}',
623
- type: 'yaml_reference',
624
- confidence: 0.9
625
- },
626
- {
627
- pattern: 'use\\s+{component_name}',
628
- type: 'usage_statement',
629
- confidence: 0.8
630
- }
631
- ],
632
- task: [
633
- {
634
- pattern: '\\*{component_name}',
635
- type: 'task_invocation',
636
- confidence: 0.9
637
- },
638
- {
639
- pattern: 'require\\(.*{component_name}.*\\)',
640
- type: 'import_statement',
641
- confidence: 0.8
642
- }
643
- ],
644
- workflow: [
645
- {
646
- pattern: 'workflow:\\s*{component_name}',
647
- type: 'workflow_reference',
648
- confidence: 0.9
649
- }
650
- ],
651
- util: [
652
- {
653
- pattern: 'require\\(.*{component_name}.*\\)',
654
- type: 'import_statement',
655
- confidence: 0.9
656
- },
657
- {
658
- pattern: 'import.*{component_name}',
659
- type: 'import_statement',
660
- confidence: 0.9
661
- }
662
- ],
663
- default: [
664
- {
665
- pattern: '{component_name}',
666
- type: 'general_reference',
667
- confidence: 0.6
668
- }
669
- ]
670
- };
671
- }
672
- }
673
-
1
+ const fs = require('fs').promises;
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+
5
+ /**
6
+ * Usage tracker for AIOS-FULLSTACK framework components
7
+ * Tracks component usage patterns for deprecation warnings and impact analysis
8
+ */
9
+ class UsageTracker {
10
+ constructor(options = {}) {
11
+ this.rootPath = options.rootPath || process.cwd();
12
+ this.usageDir = path.join(this.rootPath, '.aios', 'usage');
13
+ this.usageCache = new Map();
14
+ this.scanPatterns = this.initializeScanPatterns();
15
+ }
16
+
17
+ /**
18
+ * Initialize usage tracker
19
+ */
20
+ async initialize() {
21
+ try {
22
+ // Create usage directory
23
+ await fs.mkdir(this.usageDir, { recursive: true });
24
+
25
+ console.log(chalk.green('✅ Usage tracker initialized'));
26
+ return true;
27
+
28
+ } catch (_error) {
29
+ console.error(chalk.red(`Failed to initialize usage tracker: ${error.message}`));
30
+ throw error;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Analyze component usage across the codebase
36
+ */
37
+ async analyzeComponentUsage(componentId, options = {}) {
38
+ const analysis = {
39
+ component_id: componentId,
40
+ analysis_timestamp: new Date().toISOString(),
41
+ total_references: 0,
42
+ usage_locations: [],
43
+ dependent_components: [],
44
+ external_references: [],
45
+ usage_patterns: {},
46
+ risk_assessment: {
47
+ impact_level: 'low',
48
+ affected_areas: [],
49
+ migration_complexity: 'simple'
50
+ }
51
+ };
52
+
53
+ try {
54
+ console.log(chalk.blue(`🔍 Analyzing usage for component: ${componentId}`));
55
+
56
+ // Get component information
57
+ const component = await this.getComponentInfo(componentId);
58
+ if (!component) {
59
+ throw new Error(`Component not found: ${componentId}`);
60
+ }
61
+
62
+ // Scan for direct references
63
+ const directReferences = await this.scanForDirectReferences(component, options);
64
+ analysis.usage_locations = directReferences;
65
+ analysis.total_references = directReferences.length;
66
+
67
+ // Analyze dependency relationships
68
+ const dependencies = await this.analyzeDependencyRelationships(component, options);
69
+ analysis.dependent_components = dependencies;
70
+
71
+ // Check for external references (imports, configurations, etc.)
72
+ const externalRefs = await this.scanForExternalReferences(component, options);
73
+ analysis.external_references = externalRefs;
74
+
75
+ // Analyze usage patterns
76
+ analysis.usage_patterns = await this.analyzeUsagePatterns(component, directReferences);
77
+
78
+ // Assess migration risk
79
+ analysis.risk_assessment = this.assessMigrationRisk(analysis);
80
+
81
+ // Cache results
82
+ this.usageCache.set(componentId, analysis);
83
+
84
+ // Save detailed analysis
85
+ await this.saveUsageAnalysis(analysis);
86
+
87
+ console.log(chalk.green(`✅ Usage analysis completed for ${componentId}`));
88
+ console.log(chalk.gray(` Total references: ${analysis.total_references}`));
89
+ console.log(chalk.gray(` Dependent components: ${analysis.dependent_components.length}`));
90
+ console.log(chalk.gray(` Impact level: ${analysis.risk_assessment.impact_level}`));
91
+
92
+ return analysis;
93
+
94
+ } catch (_error) {
95
+ console.error(chalk.red(`Usage analysis failed for ${componentId}: ${error.message}`));
96
+ throw error;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Track usage changes over time for deprecated components
102
+ */
103
+ async trackUsageChanges(componentId, baselineAnalysis) {
104
+ const currentAnalysis = await this.analyzeComponentUsage(componentId);
105
+
106
+ const changes = {
107
+ component_id: componentId,
108
+ comparison_timestamp: new Date().toISOString(),
109
+ baseline_timestamp: baselineAnalysis.analysis_timestamp,
110
+ changes: {
111
+ total_references: {
112
+ before: baselineAnalysis.total_references,
113
+ after: currentAnalysis.total_references,
114
+ change: currentAnalysis.total_references - baselineAnalysis.total_references
115
+ },
116
+ dependent_components: {
117
+ before: baselineAnalysis.dependent_components.length,
118
+ after: currentAnalysis.dependent_components.length,
119
+ change: currentAnalysis.dependent_components.length - baselineAnalysis.dependent_components.length
120
+ },
121
+ new_usages: this.findNewUsages(baselineAnalysis.usage_locations, currentAnalysis.usage_locations),
122
+ removed_usages: this.findRemovedUsages(baselineAnalysis.usage_locations, currentAnalysis.usage_locations)
123
+ },
124
+ trend: this.calculateUsageTrend(baselineAnalysis, currentAnalysis),
125
+ migration_progress: this.calculateMigrationProgress(baselineAnalysis, currentAnalysis)
126
+ };
127
+
128
+ // Save change tracking
129
+ await this.saveUsageChanges(changes);
130
+
131
+ return changes;
132
+ }
133
+
134
+ /**
135
+ * Generate usage warnings for deprecated components
136
+ */
137
+ async generateUsageWarnings(componentId, deprecationInfo) {
138
+ const analysis = await this.analyzeComponentUsage(componentId);
139
+ const warnings = [];
140
+
141
+ for (const _usage of analysis.usage_locations) {
142
+ const warning = {
143
+ type: 'deprecation_warning',
144
+ component_id: componentId,
145
+ usage_location: {
146
+ file: usage.file,
147
+ line: usage.line,
148
+ context: usage.context
149
+ },
150
+ message: this.generateWarningMessage(componentId, deprecationInfo, usage),
151
+ severity: this.calculateWarningSeverity(deprecationInfo, usage),
152
+ suggested_actions: this.generateSuggestedActions(componentId, deprecationInfo, usage)
153
+ };
154
+
155
+ warnings.push(warning);
156
+ }
157
+
158
+ // Save warnings for later processing
159
+ await this.saveUsageWarnings(componentId, warnings);
160
+
161
+ return warnings;
162
+ }
163
+
164
+ /**
165
+ * Get usage statistics for reporting
166
+ */
167
+ async getUsageStatistics(componentIds = null) {
168
+ const stats = {
169
+ generated_at: new Date().toISOString(),
170
+ total_components_analyzed: 0,
171
+ high_usage_components: [],
172
+ zero_usage_components: [],
173
+ usage_distribution: {},
174
+ dependency_graph: {}
175
+ };
176
+
177
+ const componentsToAnalyze = componentIds || await this.getAllTrackedComponents();
178
+
179
+ for (const componentId of componentsToAnalyze) {
180
+ try {
181
+ const analysis = await this.getOrAnalyzeUsage(componentId);
182
+ stats.total_components_analyzed++;
183
+
184
+ // Categorize by usage level
185
+ if (analysis.total_references === 0) {
186
+ stats.zero_usage_components.push(componentId);
187
+ } else if (analysis.total_references >= 10) {
188
+ stats.high_usage_components.push({
189
+ component_id: componentId,
190
+ reference_count: analysis.total_references,
191
+ impact_level: analysis.risk_assessment.impact_level
192
+ });
193
+ }
194
+
195
+ // Add to usage distribution
196
+ const usageRange = this.categorizeUsageLevel(analysis.total_references);
197
+ stats.usage_distribution[usageRange] = (stats.usage_distribution[usageRange] || 0) + 1;
198
+
199
+ // Add to dependency graph
200
+ stats.dependency_graph[componentId] = analysis.dependent_components.map(dep => dep.component_id);
201
+
202
+ } catch (_error) {
203
+ console.warn(chalk.yellow(`Failed to analyze usage for ${componentId}: ${error.message}`));
204
+ }
205
+ }
206
+
207
+ return stats;
208
+ }
209
+
210
+ /**
211
+ * Scan for direct references to a component
212
+ */
213
+ async scanForDirectReferences(component, options = {}) {
214
+ const references = [];
215
+ const scanPaths = await this.getScanPaths(_options);
216
+
217
+ for (const scanPath of scanPaths) {
218
+ try {
219
+ const pathReferences = await this.scanPath(scanPath, component);
220
+ references.push(...pathReferences);
221
+ } catch (_error) {
222
+ console.warn(chalk.yellow(`Failed to scan path ${scanPath}: ${error.message}`));
223
+ }
224
+ }
225
+
226
+ return references;
227
+ }
228
+
229
+ /**
230
+ * Scan a specific path for component references
231
+ */
232
+ async scanPath(scanPath, component) {
233
+ const references = [];
234
+ const files = await this.getFilesToScan(scanPath);
235
+
236
+ for (const file of files) {
237
+ try {
238
+ const fileReferences = await this.scanFile(file, component);
239
+ references.push(...fileReferences);
240
+ } catch (_error) {
241
+ // Skip files that can't be read
242
+ continue;
243
+ }
244
+ }
245
+
246
+ return references;
247
+ }
248
+
249
+ /**
250
+ * Scan a single file for component references
251
+ */
252
+ async scanFile(filePath, component) {
253
+ const references = [];
254
+
255
+ try {
256
+ const content = await fs.readFile(filePath, 'utf-8');
257
+ const lines = content.split('\n');
258
+
259
+ for (let i = 0; i < lines.length; i++) {
260
+ const line = lines[i];
261
+ const lineNumber = i + 1;
262
+
263
+ // Check for various reference patterns
264
+ const matches = this.findReferencesInLine(line, component);
265
+
266
+ for (const match of matches) {
267
+ references.push({
268
+ file: filePath,
269
+ line: lineNumber,
270
+ column: match.column,
271
+ context: line.trim(),
272
+ reference_type: match.type,
273
+ match_text: match.text
274
+ });
275
+ }
276
+ }
277
+ } catch (_error) {
278
+ // File couldn't be read, skip
279
+ }
280
+
281
+ return references;
282
+ }
283
+
284
+ /**
285
+ * Find references in a single line of code
286
+ */
287
+ findReferencesInLine(line, component) {
288
+ const matches = [];
289
+ const patterns = this.scanPatterns[component.type] || this.scanPatterns.default;
290
+
291
+ for (const pattern of patterns) {
292
+ const regex = new RegExp(pattern.pattern.replace('{component_name}', component.name), pattern.flags || 'gi');
293
+ let match;
294
+
295
+ while ((match = regex.exec(line)) !== null) {
296
+ matches.push({
297
+ type: pattern.type,
298
+ text: match[0],
299
+ column: match.index,
300
+ confidence: pattern.confidence || 0.8
301
+ });
302
+ }
303
+ }
304
+
305
+ return matches;
306
+ }
307
+
308
+ /**
309
+ * Analyze dependency relationships
310
+ */
311
+ async analyzeDependencyRelationships(component, options = {}) {
312
+ const dependencies = [];
313
+
314
+ // This would analyze manifest files, import statements, etc.
315
+ // For now, return empty array as placeholder
316
+
317
+ return dependencies;
318
+ }
319
+
320
+ /**
321
+ * Scan for external references (config files, documentation, etc.)
322
+ */
323
+ async scanForExternalReferences(component, options = {}) {
324
+ const externalRefs = [];
325
+
326
+ // Check configuration files
327
+ const configRefs = await this.scanConfigurationFiles(component);
328
+ externalRefs.push(...configRefs);
329
+
330
+ // Check documentation
331
+ const docRefs = await this.scanDocumentationFiles(component);
332
+ externalRefs.push(...docRefs);
333
+
334
+ return externalRefs;
335
+ }
336
+
337
+ /**
338
+ * Analyze usage patterns
339
+ */
340
+ async analyzeUsagePatterns(component, references) {
341
+ const patterns = {
342
+ by_file_type: {},
343
+ by_usage_type: {},
344
+ temporal_distribution: {},
345
+ complexity_indicators: {}
346
+ };
347
+
348
+ for (const ref of references) {
349
+ // Group by file extension
350
+ const ext = path.extname(ref.file);
351
+ patterns.by_file_type[ext] = (patterns.by_file_type[ext] || 0) + 1;
352
+
353
+ // Group by reference type
354
+ patterns.by_usage_type[ref.reference_type] = (patterns.by_usage_type[ref.reference_type] || 0) + 1;
355
+ }
356
+
357
+ return patterns;
358
+ }
359
+
360
+ /**
361
+ * Assess migration risk based on usage analysis
362
+ */
363
+ assessMigrationRisk(analysis) {
364
+ let impactLevel = 'low';
365
+ let migrationComplexity = 'simple';
366
+ const affectedAreas = [];
367
+
368
+ // Assess based on total references
369
+ if (analysis.total_references > 20) {
370
+ impactLevel = 'high';
371
+ migrationComplexity = 'complex';
372
+ } else if (analysis.total_references > 10) {
373
+ impactLevel = 'medium';
374
+ migrationComplexity = 'moderate';
375
+ }
376
+
377
+ // Check for complex usage patterns
378
+ if (analysis.dependent_components.length > 5) {
379
+ migrationComplexity = 'complex';
380
+ affectedAreas.push('component_dependencies');
381
+ }
382
+
383
+ if (analysis.external_references.length > 0) {
384
+ affectedAreas.push('external_configuration');
385
+ }
386
+
387
+ return {
388
+ impact_level: impactLevel,
389
+ affected_areas: affectedAreas,
390
+ migration_complexity: migrationComplexity
391
+ };
392
+ }
393
+
394
+ // Helper methods
395
+
396
+ async getComponentInfo(componentId) {
397
+ // This would typically integrate with the component registry
398
+ // For now, return a basic component structure
399
+ const [type, name] = componentId.split('/');
400
+
401
+ return {
402
+ id: componentId,
403
+ type: type,
404
+ name: name,
405
+ file_path: `aios-core/${type}s/${name}.md`
406
+ };
407
+ }
408
+
409
+ async getScanPaths(_options) {
410
+ const defaultPaths = [
411
+ path.join(this.rootPath, 'aios-core'),
412
+ path.join(this.rootPath, 'src'),
413
+ path.join(this.rootPath, 'lib')
414
+ ];
415
+
416
+ if (options.scanPaths) {
417
+ return options.scanPaths;
418
+ }
419
+
420
+ // Filter paths that exist
421
+ const existingPaths = [];
422
+ for (const scanPath of defaultPaths) {
423
+ try {
424
+ await fs.access(scanPath);
425
+ existingPaths.push(scanPath);
426
+ } catch (_error) {
427
+ // Path doesn't exist, skip
428
+ }
429
+ }
430
+
431
+ return existingPaths;
432
+ }
433
+
434
+ async getFilesToScan(scanPath) {
435
+ const files = [];
436
+
437
+ try {
438
+ const entries = await fs.readdir(scanPath, { withFileTypes: true });
439
+
440
+ for (const entry of entries) {
441
+ const fullPath = path.join(scanPath, entry.name);
442
+
443
+ if (entry.isDirectory()) {
444
+ // Recursively scan subdirectories
445
+ const subFiles = await this.getFilesToScan(fullPath);
446
+ files.push(...subFiles);
447
+ } else if (this.shouldScanFile(entry.name)) {
448
+ files.push(fullPath);
449
+ }
450
+ }
451
+ } catch (_error) {
452
+ // Can't read directory, skip
453
+ }
454
+
455
+ return files;
456
+ }
457
+
458
+ shouldScanFile(filename) {
459
+ const scanExtensions = ['.js', '.ts', '.md', '.yaml', '.yml', '.json'];
460
+ const ext = path.extname(filename);
461
+ return scanExtensions.includes(ext);
462
+ }
463
+
464
+ async scanConfigurationFiles(component) {
465
+ const configRefs = [];
466
+ const configFiles = [
467
+ 'package.json',
468
+ '.aiosrc',
469
+ 'aios.config.js',
470
+ 'manifest.yaml'
471
+ ];
472
+
473
+ for (const configFile of configFiles) {
474
+ const configPath = path.join(this.rootPath, configFile);
475
+
476
+ try {
477
+ const refs = await this.scanFile(configPath, component);
478
+ configRefs.push(...refs.map(ref => ({ ...ref, source: 'configuration' })));
479
+ } catch (_error) {
480
+ // Config file doesn't exist or can't be read
481
+ }
482
+ }
483
+
484
+ return configRefs;
485
+ }
486
+
487
+ async scanDocumentationFiles(component) {
488
+ const docRefs = [];
489
+ const docsPath = path.join(this.rootPath, 'docs');
490
+
491
+ try {
492
+ const files = await this.getFilesToScan(docsPath);
493
+
494
+ for (const file of files) {
495
+ const refs = await this.scanFile(file, component);
496
+ docRefs.push(...refs.map(ref => ({ ...ref, source: 'documentation' })));
497
+ }
498
+ } catch (_error) {
499
+ // Docs directory doesn't exist
500
+ }
501
+
502
+ return docRefs;
503
+ }
504
+
505
+ findNewUsages(oldUsages, newUsages) {
506
+ return newUsages.filter(newUsage =>
507
+ !oldUsages.some(oldUsage =>
508
+ oldUsage.file === newUsage.file && oldUsage.line === newUsage.line
509
+ )
510
+ );
511
+ }
512
+
513
+ findRemovedUsages(oldUsages, newUsages) {
514
+ return oldUsages.filter(oldUsage =>
515
+ !newUsages.some(newUsage =>
516
+ newUsage.file === oldUsage.file && newUsage.line === oldUsage.line
517
+ )
518
+ );
519
+ }
520
+
521
+ calculateUsageTrend(baseline, current) {
522
+ const referenceChange = current.total_references - baseline.total_references;
523
+
524
+ if (referenceChange > 0) return 'increasing';
525
+ if (referenceChange < 0) return 'decreasing';
526
+ return 'stable';
527
+ }
528
+
529
+ calculateMigrationProgress(baseline, current) {
530
+ if (baseline.total_references === 0) return 1.0;
531
+
532
+ const remainingUsages = current.total_references;
533
+ const originalUsages = baseline.total_references;
534
+
535
+ return Math.max(0, (originalUsages - remainingUsages) / originalUsages);
536
+ }
537
+
538
+ generateWarningMessage(componentId, deprecationInfo, usage) {
539
+ let message = `DEPRECATED: ${componentId} is deprecated`;
540
+
541
+ if (deprecationInfo.replacement) {
542
+ message += ` - use ${deprecationInfo.replacement} instead`;
543
+ }
544
+
545
+ if (deprecationInfo.removalVersion) {
546
+ message += ` (will be removed in ${deprecationInfo.removalVersion})`;
547
+ }
548
+
549
+ return message;
550
+ }
551
+
552
+ calculateWarningSeverity(deprecationInfo, usage) {
553
+ if (deprecationInfo.severity === 'critical') return 'error';
554
+ if (deprecationInfo.severity === 'high') return 'warning';
555
+ return 'info';
556
+ }
557
+
558
+ generateSuggestedActions(componentId, deprecationInfo, usage) {
559
+ const actions = [];
560
+
561
+ if (deprecationInfo.replacement) {
562
+ actions.push(`Replace with ${deprecationInfo.replacement}`);
563
+ }
564
+
565
+ if (deprecationInfo.migrationGuide) {
566
+ actions.push(`See migration guide: ${deprecationInfo.migrationGuide}`);
567
+ }
568
+
569
+ actions.push('Update imports and references');
570
+ actions.push('Test functionality after replacement');
571
+
572
+ return actions;
573
+ }
574
+
575
+ categorizeUsageLevel(referenceCount) {
576
+ if (referenceCount === 0) return 'zero';
577
+ if (referenceCount <= 5) return 'low';
578
+ if (referenceCount <= 15) return 'medium';
579
+ if (referenceCount <= 30) return 'high';
580
+ return 'very_high';
581
+ }
582
+
583
+ async getOrAnalyzeUsage(componentId) {
584
+ if (this.usageCache.has(componentId)) {
585
+ return this.usageCache.get(componentId);
586
+ }
587
+
588
+ return await this.analyzeComponentUsage(componentId);
589
+ }
590
+
591
+ async getAllTrackedComponents() {
592
+ // This would typically come from a component registry
593
+ // For now, return empty array
594
+ return [];
595
+ }
596
+
597
+ async saveUsageAnalysis(analysis) {
598
+ const filename = `usage-${analysis.component_id.replace('/', '-')}-${Date.now()}.json`;
599
+ const filePath = path.join(this.usageDir, filename);
600
+
601
+ await fs.writeFile(filePath, JSON.stringify(analysis, null, 2));
602
+ }
603
+
604
+ async saveUsageChanges(changes) {
605
+ const filename = `changes-${changes.component_id.replace('/', '-')}-${Date.now()}.json`;
606
+ const filePath = path.join(this.usageDir, filename);
607
+
608
+ await fs.writeFile(filePath, JSON.stringify(changes, null, 2));
609
+ }
610
+
611
+ async saveUsageWarnings(componentId, warnings) {
612
+ const filename = `warnings-${componentId.replace('/', '-')}-${Date.now()}.json`;
613
+ const filePath = path.join(this.usageDir, filename);
614
+
615
+ await fs.writeFile(filePath, JSON.stringify(warnings, null, 2));
616
+ }
617
+
618
+ initializeScanPatterns() {
619
+ return {
620
+ agent: [
621
+ {
622
+ pattern: 'agent:\\s*{component_name}',
623
+ type: 'yaml_reference',
624
+ confidence: 0.9
625
+ },
626
+ {
627
+ pattern: 'use\\s+{component_name}',
628
+ type: 'usage_statement',
629
+ confidence: 0.8
630
+ }
631
+ ],
632
+ task: [
633
+ {
634
+ pattern: '\\*{component_name}',
635
+ type: 'task_invocation',
636
+ confidence: 0.9
637
+ },
638
+ {
639
+ pattern: 'require\\(.*{component_name}.*\\)',
640
+ type: 'import_statement',
641
+ confidence: 0.8
642
+ }
643
+ ],
644
+ workflow: [
645
+ {
646
+ pattern: 'workflow:\\s*{component_name}',
647
+ type: 'workflow_reference',
648
+ confidence: 0.9
649
+ }
650
+ ],
651
+ util: [
652
+ {
653
+ pattern: 'require\\(.*{component_name}.*\\)',
654
+ type: 'import_statement',
655
+ confidence: 0.9
656
+ },
657
+ {
658
+ pattern: 'import.*{component_name}',
659
+ type: 'import_statement',
660
+ confidence: 0.9
661
+ }
662
+ ],
663
+ default: [
664
+ {
665
+ pattern: '{component_name}',
666
+ type: 'general_reference',
667
+ confidence: 0.6
668
+ }
669
+ ]
670
+ };
671
+ }
672
+ }
673
+
674
674
  module.exports = UsageTracker;