aios-core 4.2.13 → 4.2.15

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 (95) hide show
  1. package/.aios-core/core/code-intel/helpers/dev-helper.js +206 -0
  2. package/.aios-core/core/registry/registry-schema.json +166 -166
  3. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +3 -3
  4. package/.aios-core/data/entity-registry.yaml +27 -0
  5. package/.aios-core/development/scripts/approval-workflow.js +642 -642
  6. package/.aios-core/development/scripts/backup-manager.js +606 -606
  7. package/.aios-core/development/scripts/branch-manager.js +389 -389
  8. package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
  9. package/.aios-core/development/scripts/commit-message-generator.js +849 -849
  10. package/.aios-core/development/scripts/conflict-resolver.js +674 -674
  11. package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
  12. package/.aios-core/development/scripts/diff-generator.js +351 -351
  13. package/.aios-core/development/scripts/elicitation-engine.js +384 -384
  14. package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
  15. package/.aios-core/development/scripts/git-wrapper.js +461 -461
  16. package/.aios-core/development/scripts/manifest-preview.js +244 -244
  17. package/.aios-core/development/scripts/metrics-tracker.js +775 -775
  18. package/.aios-core/development/scripts/modification-validator.js +554 -554
  19. package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
  20. package/.aios-core/development/scripts/performance-analyzer.js +757 -757
  21. package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
  22. package/.aios-core/development/scripts/rollback-handler.js +530 -530
  23. package/.aios-core/development/scripts/security-checker.js +358 -358
  24. package/.aios-core/development/scripts/template-engine.js +239 -239
  25. package/.aios-core/development/scripts/template-validator.js +278 -278
  26. package/.aios-core/development/scripts/test-generator.js +843 -843
  27. package/.aios-core/development/scripts/transaction-manager.js +589 -589
  28. package/.aios-core/development/scripts/usage-tracker.js +673 -673
  29. package/.aios-core/development/scripts/validate-filenames.js +226 -226
  30. package/.aios-core/development/scripts/version-tracker.js +526 -526
  31. package/.aios-core/development/scripts/yaml-validator.js +396 -396
  32. package/.aios-core/development/tasks/build-autonomous.md +10 -4
  33. package/.aios-core/development/tasks/create-service.md +23 -0
  34. package/.aios-core/development/tasks/dev-develop-story.md +12 -6
  35. package/.aios-core/development/tasks/dev-suggest-refactoring.md +7 -1
  36. package/.aios-core/development/tasks/publish-npm.md +3 -3
  37. package/.aios-core/hooks/unified/README.md +1 -1
  38. package/.aios-core/install-manifest.yaml +65 -61
  39. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  40. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  41. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  42. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  43. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  44. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  45. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  46. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  47. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  48. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  49. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  50. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  51. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  52. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  53. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  54. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  55. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  56. package/README.en.md +747 -0
  57. package/README.md +4 -2
  58. package/bin/aios.js +7 -4
  59. package/package.json +1 -1
  60. package/packages/aios-pro-cli/src/recover.js +1 -1
  61. package/packages/installer/src/wizard/ide-config-generator.js +6 -6
  62. package/packages/installer/src/wizard/pro-setup.js +3 -3
  63. package/pro/license/degradation.js +220 -220
  64. package/pro/license/errors.js +450 -450
  65. package/pro/license/feature-gate.js +354 -354
  66. package/pro/license/index.js +181 -181
  67. package/pro/license/license-cache.js +523 -523
  68. package/pro/license/license-crypto.js +303 -303
  69. package/scripts/package-synapse.js +5 -5
  70. package/scripts/validate-package-completeness.js +3 -3
  71. package/.aios-core/.session/current-session.json +0 -14
  72. package/.aios-core/data/registry-update-log.jsonl +0 -191
  73. package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +0 -335
  74. package/.aios-core/docs/component-creation-guide.md +0 -458
  75. package/.aios-core/docs/session-update-pattern.md +0 -307
  76. package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +0 -1963
  77. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +0 -1190
  78. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +0 -439
  79. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +0 -5398
  80. package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +0 -523
  81. package/.aios-core/docs/template-syntax.md +0 -267
  82. package/.aios-core/docs/troubleshooting-guide.md +0 -625
  83. package/.aios-core/infrastructure/tests/utilities-audit-results.json +0 -501
  84. package/.aios-core/manifests/agents.csv +0 -29
  85. package/.aios-core/manifests/tasks.csv +0 -198
  86. package/.aios-core/manifests/workers.csv +0 -204
  87. package/.claude/rules/agent-authority.md +0 -105
  88. package/.claude/rules/coderabbit-integration.md +0 -93
  89. package/.claude/rules/ids-principles.md +0 -112
  90. package/.claude/rules/story-lifecycle.md +0 -139
  91. package/.claude/rules/workflow-execution.md +0 -150
  92. package/scripts/glue/README.md +0 -355
  93. package/scripts/glue/compose-agent-prompt.cjs +0 -362
  94. /package/.claude/hooks/{precompact-session-digest.js → precompact-session-digest.cjs} +0 -0
  95. /package/.claude/hooks/{synapse-engine.js → synapse-engine.cjs} +0 -0
@@ -1,638 +1,638 @@
1
- /**
2
- * Dependency Analyzer for AIOS-FULLSTACK
3
- * Analyzes and resolves dependencies between components
4
- * @module dependency-analyzer
5
- */
6
-
7
- const fs = require('fs-extra');
8
- const path = require('path');
9
- const _yaml = require('js-yaml');
10
- const chalk = require('chalk');
11
-
12
- class DependencyAnalyzer {
13
- constructor(options = {}) {
14
- this.rootPath = options.rootPath || process.cwd();
15
- this.manifestPath = path.join(this.rootPath, 'aios-core', 'team-manifest.yaml');
16
-
17
- // Component paths
18
- this.paths = {
19
- agents: path.join(this.rootPath, 'aios-core', 'agents'),
20
- tasks: path.join(this.rootPath, 'aios-core', 'tasks'),
21
- workflows: path.join(this.rootPath, 'aios-core', 'workflows')
22
- };
23
-
24
- // Dependency cache
25
- this.dependencyCache = new Map();
26
- }
27
-
28
- /**
29
- * Analyze dependencies for a component
30
- * @param {string} componentType - Type of component (agent/task/workflow)
31
- * @param {Object} componentData - Component configuration data
32
- * @returns {Promise<Object>} Dependency analysis result
33
- */
34
- async analyzeDependencies(componentType, componentData) {
35
- const dependencies = {
36
- required: [],
37
- optional: [],
38
- missing: [],
39
- circular: false,
40
- graph: new Map()
41
- };
42
-
43
- switch (componentType) {
44
- case 'agent':
45
- await this.analyzeAgentDependencies(componentData, dependencies);
46
- break;
47
- case 'task':
48
- await this.analyzeTaskDependencies(componentData, dependencies);
49
- break;
50
- case 'workflow':
51
- await this.analyzeWorkflowDependencies(componentData, dependencies);
52
- break;
53
- }
54
-
55
- // Check for circular dependencies
56
- dependencies.circular = this.detectCircularDependencies(dependencies.graph);
57
-
58
- return dependencies;
59
- }
60
-
61
- /**
62
- * Analyze agent dependencies
63
- * @private
64
- */
65
- async analyzeAgentDependencies(agentData, dependencies) {
66
- // Check for task dependencies from commands
67
- if (agentData.commands && Array.isArray(agentData.commands)) {
68
- for (const command of agentData.commands) {
69
- const taskId = this.commandToTaskId(command);
70
- const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
71
-
72
- if (await fs.pathExists(taskPath)) {
73
- dependencies.required.push({
74
- type: 'task',
75
- id: taskId,
76
- path: taskPath,
77
- reason: `Command '${command}' requires task`
78
- });
79
- } else {
80
- dependencies.missing.push({
81
- type: 'task',
82
- id: taskId,
83
- reason: `Command '${command}' requires task file`
84
- });
85
- }
86
- }
87
- }
88
-
89
- // Check for workflow dependencies
90
- if (agentData.workflows && Array.isArray(agentData.workflows)) {
91
- for (const workflowId of agentData.workflows) {
92
- const workflowPath = path.join(this.paths.workflows, `${workflowId}.yaml`);
93
-
94
- if (await fs.pathExists(workflowPath)) {
95
- dependencies.optional.push({
96
- type: 'workflow',
97
- id: workflowId,
98
- path: workflowPath,
99
- reason: 'Agent workflow reference'
100
- });
101
- }
102
- }
103
- }
104
-
105
- // Check for agent dependencies
106
- if (agentData.dependencies?.agents) {
107
- for (const agentId of agentData.dependencies.agents) {
108
- const agentPath = path.join(this.paths.agents, `${agentId}.md`);
109
-
110
- if (await fs.pathExists(agentPath)) {
111
- dependencies.required.push({
112
- type: 'agent',
113
- id: agentId,
114
- path: agentPath,
115
- reason: 'Explicit agent dependency'
116
- });
117
- } else {
118
- dependencies.missing.push({
119
- type: 'agent',
120
- id: agentId,
121
- reason: 'Required agent not found'
122
- });
123
- }
124
- }
125
- }
126
- }
127
-
128
- /**
129
- * Analyze task dependencies
130
- * @private
131
- */
132
- async analyzeTaskDependencies(taskData, dependencies) {
133
- // Check for agent dependency
134
- if (taskData.agentName) {
135
- const agentPath = path.join(this.paths.agents, `${taskData.agentName}.md`);
136
-
137
- if (await fs.pathExists(agentPath)) {
138
- dependencies.required.push({
139
- type: 'agent',
140
- id: taskData.agentName,
141
- path: agentPath,
142
- reason: 'Task belongs to agent'
143
- });
144
- } else {
145
- dependencies.missing.push({
146
- type: 'agent',
147
- id: taskData.agentName,
148
- reason: 'Agent not found for task'
149
- });
150
- }
151
- }
152
-
153
- // Check for other task dependencies
154
- if (taskData.dependencies?.tasks) {
155
- for (const taskId of taskData.dependencies.tasks) {
156
- const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
157
-
158
- if (await fs.pathExists(taskPath)) {
159
- dependencies.required.push({
160
- type: 'task',
161
- id: taskId,
162
- path: taskPath,
163
- reason: 'Task dependency'
164
- });
165
- } else {
166
- dependencies.missing.push({
167
- type: 'task',
168
- id: taskId,
169
- reason: 'Required task not found'
170
- });
171
- }
172
- }
173
- }
174
- }
175
-
176
- /**
177
- * Analyze workflow dependencies
178
- * @private
179
- */
180
- async analyzeWorkflowDependencies(workflowData, dependencies) {
181
- // Extract task references from workflow steps
182
- const taskIds = new Set();
183
-
184
- if (workflowData.steps && Array.isArray(workflowData.steps)) {
185
- for (const step of workflowData.steps) {
186
- if (step.type === 'task' && step.taskId) {
187
- taskIds.add(step.taskId);
188
- } else if (step.action?.includes('task:')) {
189
- const taskMatch = step.action.match(/task:([a-z0-9-]+)/);
190
- if (taskMatch) {
191
- taskIds.add(taskMatch[1]);
192
- }
193
- }
194
- }
195
- }
196
-
197
- // Check each task dependency
198
- for (const taskId of taskIds) {
199
- const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
200
-
201
- if (await fs.pathExists(taskPath)) {
202
- dependencies.required.push({
203
- type: 'task',
204
- id: taskId,
205
- path: taskPath,
206
- reason: 'Workflow step requires task'
207
- });
208
-
209
- // Also check the task's agent dependency
210
- const taskContent = await fs.readFile(taskPath, 'utf8');
211
- const agentMatch = taskContent.match(/\*\*Agent:\*\*\s*([a-z0-9-]+)/);
212
- if (agentMatch) {
213
- const agentId = agentMatch[1];
214
- const agentPath = path.join(this.paths.agents, `${agentId}.md`);
215
-
216
- if (await fs.pathExists(agentPath)) {
217
- dependencies.required.push({
218
- type: 'agent',
219
- id: agentId,
220
- path: agentPath,
221
- reason: 'Task requires agent'
222
- });
223
- }
224
- }
225
- } else {
226
- dependencies.missing.push({
227
- type: 'task',
228
- id: taskId,
229
- reason: 'Workflow step requires task'
230
- });
231
- }
232
- }
233
-
234
- // Check for sub-workflow dependencies
235
- if (workflowData.dependencies?.workflows) {
236
- for (const workflowId of workflowData.dependencies.workflows) {
237
- const workflowPath = path.join(this.paths.workflows, `${workflowId}.yaml`);
238
-
239
- if (await fs.pathExists(workflowPath)) {
240
- dependencies.required.push({
241
- type: 'workflow',
242
- id: workflowId,
243
- path: workflowPath,
244
- reason: 'Sub-workflow dependency'
245
- });
246
- } else {
247
- dependencies.missing.push({
248
- type: 'workflow',
249
- id: workflowId,
250
- reason: 'Required workflow not found'
251
- });
252
- }
253
- }
254
- }
255
- }
256
-
257
- /**
258
- * Convert command name to task ID
259
- * @private
260
- */
261
- commandToTaskId(command) {
262
- // Remove asterisk if present
263
- const cleanCommand = command.replace(/^\*/, '');
264
-
265
- // Handle common patterns
266
- if (cleanCommand.startsWith('create-')) {
267
- return cleanCommand;
268
- }
269
-
270
- // Convert to task ID format
271
- return cleanCommand.replace(/([A-Z])/g, '-$1').toLowerCase();
272
- }
273
-
274
- /**
275
- * Detect circular dependencies
276
- * @private
277
- */
278
- detectCircularDependencies(graph) {
279
- const visited = new Set();
280
- const recursionStack = new Set();
281
-
282
- const hasCycle = (node, path = []) => {
283
- if (recursionStack.has(node)) {
284
- console.log(chalk.red(`\n⚠️ Circular dependency detected: ${[...path, node].join(' → ')}`));
285
- return true;
286
- }
287
-
288
- if (visited.has(node)) {
289
- return false;
290
- }
291
-
292
- visited.add(node);
293
- recursionStack.add(node);
294
-
295
- const neighbors = graph.get(node) || [];
296
- for (const neighbor of neighbors) {
297
- if (hasCycle(neighbor, [...path, node])) {
298
- return true;
299
- }
300
- }
301
-
302
- recursionStack.delete(node);
303
- return false;
304
- };
305
-
306
- for (const node of graph.keys()) {
307
- if (hasCycle(node)) {
308
- return true;
309
- }
310
- }
311
-
312
- return false;
313
- }
314
-
315
- /**
316
- * Validate all dependencies exist
317
- * @param {Array} components - Components to validate
318
- * @returns {Promise<Object>} Validation result
319
- */
320
- async validateDependencies(components) {
321
- const results = {
322
- valid: true,
323
- issues: [],
324
- resolutions: []
325
- };
326
-
327
- for (const component of components) {
328
- const deps = await this.analyzeDependencies(component.type, component.config);
329
-
330
- if (deps.missing.length > 0) {
331
- results.valid = false;
332
- results.issues.push({
333
- component: component.config.name || component.config.id,
334
- missing: deps.missing
335
- });
336
-
337
- // Suggest resolutions
338
- for (const missing of deps.missing) {
339
- results.resolutions.push({
340
- action: 'create',
341
- type: missing.type,
342
- id: missing.id,
343
- reason: missing.reason
344
- });
345
- }
346
- }
347
-
348
- if (deps.circular) {
349
- results.valid = false;
350
- results.issues.push({
351
- component: component.config.name || component.config.id,
352
- issue: 'Circular dependency detected'
353
- });
354
- }
355
- }
356
-
357
- return results;
358
- }
359
-
360
- /**
361
- * Get creation order for components based on dependencies
362
- * @param {Array} components - Components to order
363
- * @returns {Promise<Array>} Ordered components
364
- */
365
- async getCreationOrder(components) {
366
- const graph = new Map();
367
- const inDegree = new Map();
368
-
369
- // Initialize graph
370
- for (const component of components) {
371
- const id = this.getComponentId(component);
372
- graph.set(id, []);
373
- inDegree.set(id, 0);
374
- }
375
-
376
- // Build dependency graph
377
- for (const component of components) {
378
- const id = this.getComponentId(component);
379
- const deps = await this.analyzeDependencies(component.type, component.config);
380
-
381
- for (const dep of deps.required) {
382
- const depId = `${dep.type}:${dep.id}`;
383
-
384
- // Only add edge if dependency is in our component list
385
- if (graph.has(depId)) {
386
- graph.get(depId).push(id);
387
- inDegree.set(id, inDegree.get(id) + 1);
388
- }
389
- }
390
- }
391
-
392
- // Topological sort using Kahn's algorithm
393
- const queue = [];
394
- const ordered = [];
395
-
396
- // Find nodes with no dependencies
397
- for (const [id, degree] of inDegree.entries()) {
398
- if (degree === 0) {
399
- queue.push(id);
400
- }
401
- }
402
-
403
- while (queue.length > 0) {
404
- const current = queue.shift();
405
- ordered.push(current);
406
-
407
- // Process neighbors
408
- for (const neighbor of graph.get(current) || []) {
409
- inDegree.set(neighbor, inDegree.get(neighbor) - 1);
410
-
411
- if (inDegree.get(neighbor) === 0) {
412
- queue.push(neighbor);
413
- }
414
- }
415
- }
416
-
417
- // Check for cycles
418
- if (ordered.length !== components.length) {
419
- throw new Error('Circular dependency detected - cannot determine creation order');
420
- }
421
-
422
- // Map back to components
423
- const componentMap = new Map();
424
- for (const component of components) {
425
- const id = this.getComponentId(component);
426
- componentMap.set(id, component);
427
- }
428
-
429
- return ordered.map(id => componentMap.get(id));
430
- }
431
-
432
- /**
433
- * Get component ID for graph
434
- * @private
435
- */
436
- getComponentId(component) {
437
- const name = component.config.agentName ||
438
- component.config.taskId ||
439
- component.config.workflowId ||
440
- component.config.name ||
441
- component.config.id;
442
- return `${component.type}:${name}`;
443
- }
444
-
445
- /**
446
- * Create missing dependencies interactively
447
- * @param {Array} missing - Missing dependencies
448
- * @returns {Promise<Array>} Components to create
449
- */
450
- async promptForMissingDependencies(missing) {
451
- const inquirer = require('inquirer');
452
- const componentsToCreate = [];
453
-
454
- console.log(chalk.yellow('\n⚠️ Missing dependencies detected:'));
455
-
456
- for (const dep of missing) {
457
- console.log(chalk.gray(` - ${dep.type}: ${dep.id} (${dep.reason})`));
458
- }
459
-
460
- const { action } = await inquirer.prompt([{
461
- type: 'list',
462
- name: 'action',
463
- message: 'How would you like to handle missing dependencies?',
464
- choices: [
465
- { name: 'Create all missing dependencies', value: 'create-all' },
466
- { name: 'Select which to create', value: 'select' },
467
- { name: 'Skip dependency creation', value: 'skip' }
468
- ]
469
- }]);
470
-
471
- if (action === 'skip') {
472
- return [];
473
- }
474
-
475
- if (action === 'create-all') {
476
- for (const dep of missing) {
477
- componentsToCreate.push({
478
- type: dep.type,
479
- config: await this.getMinimalConfig(dep.type, dep.id)
480
- });
481
- }
482
- } else {
483
- // Select which to create
484
- const { selected } = await inquirer.prompt([{
485
- type: 'checkbox',
486
- name: 'selected',
487
- message: 'Select dependencies to create:',
488
- choices: missing.map(dep => ({
489
- name: `${dep.type}: ${dep.id}`,
490
- value: dep,
491
- checked: true
492
- }))
493
- }]);
494
-
495
- for (const dep of selected) {
496
- componentsToCreate.push({
497
- type: dep.type,
498
- config: await this.getMinimalConfig(dep.type, dep.id)
499
- });
500
- }
501
- }
502
-
503
- return componentsToCreate;
504
- }
505
-
506
- /**
507
- * Validate workflow dependencies
508
- * @param {Object} workflowData - Workflow configuration
509
- * @returns {Promise<Object>} Validation result
510
- */
511
- async validateWorkflowDependencies(workflowData) {
512
- const result = {
513
- valid: true,
514
- issues: [],
515
- taskDependencies: [],
516
- missingTasks: []
517
- };
518
-
519
- // Extract all task references
520
- const taskRefs = new Set();
521
-
522
- if (workflowData.steps && Array.isArray(workflowData.steps)) {
523
- for (const step of workflowData.steps) {
524
- if (step.type === 'task' && step.taskId) {
525
- taskRefs.add(step.taskId);
526
- } else if (step.action && typeof step.action === 'string') {
527
- // Extract task references from action strings
528
- const taskMatches = step.action.match(/task:([a-z0-9-]+)/g);
529
- if (taskMatches) {
530
- taskMatches.forEach(match => {
531
- const taskId = match.replace('task:', '');
532
- taskRefs.add(taskId);
533
- });
534
- }
535
- }
536
-
537
- // Check step dependencies
538
- if (step.dependencies && Array.isArray(step.dependencies)) {
539
- for (const depId of step.dependencies) {
540
- if (!workflowData.steps.find(s => s.id === depId)) {
541
- result.valid = false;
542
- result.issues.push({
543
- step: step.id || step.name,
544
- issue: `References non-existent step: ${depId}`
545
- });
546
- }
547
- }
548
- }
549
- }
550
- }
551
-
552
- // Validate each task reference
553
- for (const taskId of taskRefs) {
554
- const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
555
-
556
- if (await fs.pathExists(taskPath)) {
557
- result.taskDependencies.push({
558
- taskId,
559
- path: taskPath,
560
- exists: true
561
- });
562
- } else {
563
- result.valid = false;
564
- result.missingTasks.push(taskId);
565
- }
566
- }
567
-
568
- // Check for circular step dependencies
569
- if (workflowData.steps) {
570
- const stepGraph = new Map();
571
-
572
- for (const step of workflowData.steps) {
573
- const stepId = step.id || step.name;
574
- const deps = step.dependencies || [];
575
- stepGraph.set(stepId, deps);
576
- }
577
-
578
- if (this.detectCircularDependencies(stepGraph)) {
579
- result.valid = false;
580
- result.issues.push({
581
- issue: 'Circular dependency detected in workflow steps'
582
- });
583
- }
584
- }
585
-
586
- return result;
587
- }
588
-
589
- /**
590
- * Get minimal config for dependency creation
591
- * @private
592
- */
593
- async getMinimalConfig(type, id) {
594
- const inquirer = require('inquirer');
595
-
596
- switch (type) {
597
- case 'agent':
598
- const { agentTitle } = await inquirer.prompt([{
599
- type: 'input',
600
- name: 'agentTitle',
601
- message: `Title for agent '${id}':`,
602
- default: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
603
- }]);
604
-
605
- return {
606
- agentName: id,
607
- agentTitle,
608
- whenToUse: `Dependency for ${id}`,
609
- commands: []
610
- };
611
-
612
- case 'task':
613
- const { taskTitle } = await inquirer.prompt([{
614
- type: 'input',
615
- name: 'taskTitle',
616
- message: `Title for task '${id}':`,
617
- default: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
618
- }]);
619
-
620
- return {
621
- taskId: id,
622
- taskTitle,
623
- taskDescription: `Dependency task for ${id}`,
624
- agentName: 'aios-developer'
625
- };
626
-
627
- case 'workflow':
628
- return {
629
- workflowId: id,
630
- workflowName: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
631
- workflowType: 'standard',
632
- steps: []
633
- };
634
- }
635
- }
636
- }
637
-
1
+ /**
2
+ * Dependency Analyzer for AIOS-FULLSTACK
3
+ * Analyzes and resolves dependencies between components
4
+ * @module dependency-analyzer
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const _yaml = require('js-yaml');
10
+ const chalk = require('chalk');
11
+
12
+ class DependencyAnalyzer {
13
+ constructor(options = {}) {
14
+ this.rootPath = options.rootPath || process.cwd();
15
+ this.manifestPath = path.join(this.rootPath, 'aios-core', 'team-manifest.yaml');
16
+
17
+ // Component paths
18
+ this.paths = {
19
+ agents: path.join(this.rootPath, 'aios-core', 'agents'),
20
+ tasks: path.join(this.rootPath, 'aios-core', 'tasks'),
21
+ workflows: path.join(this.rootPath, 'aios-core', 'workflows')
22
+ };
23
+
24
+ // Dependency cache
25
+ this.dependencyCache = new Map();
26
+ }
27
+
28
+ /**
29
+ * Analyze dependencies for a component
30
+ * @param {string} componentType - Type of component (agent/task/workflow)
31
+ * @param {Object} componentData - Component configuration data
32
+ * @returns {Promise<Object>} Dependency analysis result
33
+ */
34
+ async analyzeDependencies(componentType, componentData) {
35
+ const dependencies = {
36
+ required: [],
37
+ optional: [],
38
+ missing: [],
39
+ circular: false,
40
+ graph: new Map()
41
+ };
42
+
43
+ switch (componentType) {
44
+ case 'agent':
45
+ await this.analyzeAgentDependencies(componentData, dependencies);
46
+ break;
47
+ case 'task':
48
+ await this.analyzeTaskDependencies(componentData, dependencies);
49
+ break;
50
+ case 'workflow':
51
+ await this.analyzeWorkflowDependencies(componentData, dependencies);
52
+ break;
53
+ }
54
+
55
+ // Check for circular dependencies
56
+ dependencies.circular = this.detectCircularDependencies(dependencies.graph);
57
+
58
+ return dependencies;
59
+ }
60
+
61
+ /**
62
+ * Analyze agent dependencies
63
+ * @private
64
+ */
65
+ async analyzeAgentDependencies(agentData, dependencies) {
66
+ // Check for task dependencies from commands
67
+ if (agentData.commands && Array.isArray(agentData.commands)) {
68
+ for (const command of agentData.commands) {
69
+ const taskId = this.commandToTaskId(command);
70
+ const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
71
+
72
+ if (await fs.pathExists(taskPath)) {
73
+ dependencies.required.push({
74
+ type: 'task',
75
+ id: taskId,
76
+ path: taskPath,
77
+ reason: `Command '${command}' requires task`
78
+ });
79
+ } else {
80
+ dependencies.missing.push({
81
+ type: 'task',
82
+ id: taskId,
83
+ reason: `Command '${command}' requires task file`
84
+ });
85
+ }
86
+ }
87
+ }
88
+
89
+ // Check for workflow dependencies
90
+ if (agentData.workflows && Array.isArray(agentData.workflows)) {
91
+ for (const workflowId of agentData.workflows) {
92
+ const workflowPath = path.join(this.paths.workflows, `${workflowId}.yaml`);
93
+
94
+ if (await fs.pathExists(workflowPath)) {
95
+ dependencies.optional.push({
96
+ type: 'workflow',
97
+ id: workflowId,
98
+ path: workflowPath,
99
+ reason: 'Agent workflow reference'
100
+ });
101
+ }
102
+ }
103
+ }
104
+
105
+ // Check for agent dependencies
106
+ if (agentData.dependencies?.agents) {
107
+ for (const agentId of agentData.dependencies.agents) {
108
+ const agentPath = path.join(this.paths.agents, `${agentId}.md`);
109
+
110
+ if (await fs.pathExists(agentPath)) {
111
+ dependencies.required.push({
112
+ type: 'agent',
113
+ id: agentId,
114
+ path: agentPath,
115
+ reason: 'Explicit agent dependency'
116
+ });
117
+ } else {
118
+ dependencies.missing.push({
119
+ type: 'agent',
120
+ id: agentId,
121
+ reason: 'Required agent not found'
122
+ });
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Analyze task dependencies
130
+ * @private
131
+ */
132
+ async analyzeTaskDependencies(taskData, dependencies) {
133
+ // Check for agent dependency
134
+ if (taskData.agentName) {
135
+ const agentPath = path.join(this.paths.agents, `${taskData.agentName}.md`);
136
+
137
+ if (await fs.pathExists(agentPath)) {
138
+ dependencies.required.push({
139
+ type: 'agent',
140
+ id: taskData.agentName,
141
+ path: agentPath,
142
+ reason: 'Task belongs to agent'
143
+ });
144
+ } else {
145
+ dependencies.missing.push({
146
+ type: 'agent',
147
+ id: taskData.agentName,
148
+ reason: 'Agent not found for task'
149
+ });
150
+ }
151
+ }
152
+
153
+ // Check for other task dependencies
154
+ if (taskData.dependencies?.tasks) {
155
+ for (const taskId of taskData.dependencies.tasks) {
156
+ const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
157
+
158
+ if (await fs.pathExists(taskPath)) {
159
+ dependencies.required.push({
160
+ type: 'task',
161
+ id: taskId,
162
+ path: taskPath,
163
+ reason: 'Task dependency'
164
+ });
165
+ } else {
166
+ dependencies.missing.push({
167
+ type: 'task',
168
+ id: taskId,
169
+ reason: 'Required task not found'
170
+ });
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Analyze workflow dependencies
178
+ * @private
179
+ */
180
+ async analyzeWorkflowDependencies(workflowData, dependencies) {
181
+ // Extract task references from workflow steps
182
+ const taskIds = new Set();
183
+
184
+ if (workflowData.steps && Array.isArray(workflowData.steps)) {
185
+ for (const step of workflowData.steps) {
186
+ if (step.type === 'task' && step.taskId) {
187
+ taskIds.add(step.taskId);
188
+ } else if (step.action?.includes('task:')) {
189
+ const taskMatch = step.action.match(/task:([a-z0-9-]+)/);
190
+ if (taskMatch) {
191
+ taskIds.add(taskMatch[1]);
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ // Check each task dependency
198
+ for (const taskId of taskIds) {
199
+ const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
200
+
201
+ if (await fs.pathExists(taskPath)) {
202
+ dependencies.required.push({
203
+ type: 'task',
204
+ id: taskId,
205
+ path: taskPath,
206
+ reason: 'Workflow step requires task'
207
+ });
208
+
209
+ // Also check the task's agent dependency
210
+ const taskContent = await fs.readFile(taskPath, 'utf8');
211
+ const agentMatch = taskContent.match(/\*\*Agent:\*\*\s*([a-z0-9-]+)/);
212
+ if (agentMatch) {
213
+ const agentId = agentMatch[1];
214
+ const agentPath = path.join(this.paths.agents, `${agentId}.md`);
215
+
216
+ if (await fs.pathExists(agentPath)) {
217
+ dependencies.required.push({
218
+ type: 'agent',
219
+ id: agentId,
220
+ path: agentPath,
221
+ reason: 'Task requires agent'
222
+ });
223
+ }
224
+ }
225
+ } else {
226
+ dependencies.missing.push({
227
+ type: 'task',
228
+ id: taskId,
229
+ reason: 'Workflow step requires task'
230
+ });
231
+ }
232
+ }
233
+
234
+ // Check for sub-workflow dependencies
235
+ if (workflowData.dependencies?.workflows) {
236
+ for (const workflowId of workflowData.dependencies.workflows) {
237
+ const workflowPath = path.join(this.paths.workflows, `${workflowId}.yaml`);
238
+
239
+ if (await fs.pathExists(workflowPath)) {
240
+ dependencies.required.push({
241
+ type: 'workflow',
242
+ id: workflowId,
243
+ path: workflowPath,
244
+ reason: 'Sub-workflow dependency'
245
+ });
246
+ } else {
247
+ dependencies.missing.push({
248
+ type: 'workflow',
249
+ id: workflowId,
250
+ reason: 'Required workflow not found'
251
+ });
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Convert command name to task ID
259
+ * @private
260
+ */
261
+ commandToTaskId(command) {
262
+ // Remove asterisk if present
263
+ const cleanCommand = command.replace(/^\*/, '');
264
+
265
+ // Handle common patterns
266
+ if (cleanCommand.startsWith('create-')) {
267
+ return cleanCommand;
268
+ }
269
+
270
+ // Convert to task ID format
271
+ return cleanCommand.replace(/([A-Z])/g, '-$1').toLowerCase();
272
+ }
273
+
274
+ /**
275
+ * Detect circular dependencies
276
+ * @private
277
+ */
278
+ detectCircularDependencies(graph) {
279
+ const visited = new Set();
280
+ const recursionStack = new Set();
281
+
282
+ const hasCycle = (node, path = []) => {
283
+ if (recursionStack.has(node)) {
284
+ console.log(chalk.red(`\n⚠️ Circular dependency detected: ${[...path, node].join(' → ')}`));
285
+ return true;
286
+ }
287
+
288
+ if (visited.has(node)) {
289
+ return false;
290
+ }
291
+
292
+ visited.add(node);
293
+ recursionStack.add(node);
294
+
295
+ const neighbors = graph.get(node) || [];
296
+ for (const neighbor of neighbors) {
297
+ if (hasCycle(neighbor, [...path, node])) {
298
+ return true;
299
+ }
300
+ }
301
+
302
+ recursionStack.delete(node);
303
+ return false;
304
+ };
305
+
306
+ for (const node of graph.keys()) {
307
+ if (hasCycle(node)) {
308
+ return true;
309
+ }
310
+ }
311
+
312
+ return false;
313
+ }
314
+
315
+ /**
316
+ * Validate all dependencies exist
317
+ * @param {Array} components - Components to validate
318
+ * @returns {Promise<Object>} Validation result
319
+ */
320
+ async validateDependencies(components) {
321
+ const results = {
322
+ valid: true,
323
+ issues: [],
324
+ resolutions: []
325
+ };
326
+
327
+ for (const component of components) {
328
+ const deps = await this.analyzeDependencies(component.type, component.config);
329
+
330
+ if (deps.missing.length > 0) {
331
+ results.valid = false;
332
+ results.issues.push({
333
+ component: component.config.name || component.config.id,
334
+ missing: deps.missing
335
+ });
336
+
337
+ // Suggest resolutions
338
+ for (const missing of deps.missing) {
339
+ results.resolutions.push({
340
+ action: 'create',
341
+ type: missing.type,
342
+ id: missing.id,
343
+ reason: missing.reason
344
+ });
345
+ }
346
+ }
347
+
348
+ if (deps.circular) {
349
+ results.valid = false;
350
+ results.issues.push({
351
+ component: component.config.name || component.config.id,
352
+ issue: 'Circular dependency detected'
353
+ });
354
+ }
355
+ }
356
+
357
+ return results;
358
+ }
359
+
360
+ /**
361
+ * Get creation order for components based on dependencies
362
+ * @param {Array} components - Components to order
363
+ * @returns {Promise<Array>} Ordered components
364
+ */
365
+ async getCreationOrder(components) {
366
+ const graph = new Map();
367
+ const inDegree = new Map();
368
+
369
+ // Initialize graph
370
+ for (const component of components) {
371
+ const id = this.getComponentId(component);
372
+ graph.set(id, []);
373
+ inDegree.set(id, 0);
374
+ }
375
+
376
+ // Build dependency graph
377
+ for (const component of components) {
378
+ const id = this.getComponentId(component);
379
+ const deps = await this.analyzeDependencies(component.type, component.config);
380
+
381
+ for (const dep of deps.required) {
382
+ const depId = `${dep.type}:${dep.id}`;
383
+
384
+ // Only add edge if dependency is in our component list
385
+ if (graph.has(depId)) {
386
+ graph.get(depId).push(id);
387
+ inDegree.set(id, inDegree.get(id) + 1);
388
+ }
389
+ }
390
+ }
391
+
392
+ // Topological sort using Kahn's algorithm
393
+ const queue = [];
394
+ const ordered = [];
395
+
396
+ // Find nodes with no dependencies
397
+ for (const [id, degree] of inDegree.entries()) {
398
+ if (degree === 0) {
399
+ queue.push(id);
400
+ }
401
+ }
402
+
403
+ while (queue.length > 0) {
404
+ const current = queue.shift();
405
+ ordered.push(current);
406
+
407
+ // Process neighbors
408
+ for (const neighbor of graph.get(current) || []) {
409
+ inDegree.set(neighbor, inDegree.get(neighbor) - 1);
410
+
411
+ if (inDegree.get(neighbor) === 0) {
412
+ queue.push(neighbor);
413
+ }
414
+ }
415
+ }
416
+
417
+ // Check for cycles
418
+ if (ordered.length !== components.length) {
419
+ throw new Error('Circular dependency detected - cannot determine creation order');
420
+ }
421
+
422
+ // Map back to components
423
+ const componentMap = new Map();
424
+ for (const component of components) {
425
+ const id = this.getComponentId(component);
426
+ componentMap.set(id, component);
427
+ }
428
+
429
+ return ordered.map(id => componentMap.get(id));
430
+ }
431
+
432
+ /**
433
+ * Get component ID for graph
434
+ * @private
435
+ */
436
+ getComponentId(component) {
437
+ const name = component.config.agentName ||
438
+ component.config.taskId ||
439
+ component.config.workflowId ||
440
+ component.config.name ||
441
+ component.config.id;
442
+ return `${component.type}:${name}`;
443
+ }
444
+
445
+ /**
446
+ * Create missing dependencies interactively
447
+ * @param {Array} missing - Missing dependencies
448
+ * @returns {Promise<Array>} Components to create
449
+ */
450
+ async promptForMissingDependencies(missing) {
451
+ const inquirer = require('inquirer');
452
+ const componentsToCreate = [];
453
+
454
+ console.log(chalk.yellow('\n⚠️ Missing dependencies detected:'));
455
+
456
+ for (const dep of missing) {
457
+ console.log(chalk.gray(` - ${dep.type}: ${dep.id} (${dep.reason})`));
458
+ }
459
+
460
+ const { action } = await inquirer.prompt([{
461
+ type: 'list',
462
+ name: 'action',
463
+ message: 'How would you like to handle missing dependencies?',
464
+ choices: [
465
+ { name: 'Create all missing dependencies', value: 'create-all' },
466
+ { name: 'Select which to create', value: 'select' },
467
+ { name: 'Skip dependency creation', value: 'skip' }
468
+ ]
469
+ }]);
470
+
471
+ if (action === 'skip') {
472
+ return [];
473
+ }
474
+
475
+ if (action === 'create-all') {
476
+ for (const dep of missing) {
477
+ componentsToCreate.push({
478
+ type: dep.type,
479
+ config: await this.getMinimalConfig(dep.type, dep.id)
480
+ });
481
+ }
482
+ } else {
483
+ // Select which to create
484
+ const { selected } = await inquirer.prompt([{
485
+ type: 'checkbox',
486
+ name: 'selected',
487
+ message: 'Select dependencies to create:',
488
+ choices: missing.map(dep => ({
489
+ name: `${dep.type}: ${dep.id}`,
490
+ value: dep,
491
+ checked: true
492
+ }))
493
+ }]);
494
+
495
+ for (const dep of selected) {
496
+ componentsToCreate.push({
497
+ type: dep.type,
498
+ config: await this.getMinimalConfig(dep.type, dep.id)
499
+ });
500
+ }
501
+ }
502
+
503
+ return componentsToCreate;
504
+ }
505
+
506
+ /**
507
+ * Validate workflow dependencies
508
+ * @param {Object} workflowData - Workflow configuration
509
+ * @returns {Promise<Object>} Validation result
510
+ */
511
+ async validateWorkflowDependencies(workflowData) {
512
+ const result = {
513
+ valid: true,
514
+ issues: [],
515
+ taskDependencies: [],
516
+ missingTasks: []
517
+ };
518
+
519
+ // Extract all task references
520
+ const taskRefs = new Set();
521
+
522
+ if (workflowData.steps && Array.isArray(workflowData.steps)) {
523
+ for (const step of workflowData.steps) {
524
+ if (step.type === 'task' && step.taskId) {
525
+ taskRefs.add(step.taskId);
526
+ } else if (step.action && typeof step.action === 'string') {
527
+ // Extract task references from action strings
528
+ const taskMatches = step.action.match(/task:([a-z0-9-]+)/g);
529
+ if (taskMatches) {
530
+ taskMatches.forEach(match => {
531
+ const taskId = match.replace('task:', '');
532
+ taskRefs.add(taskId);
533
+ });
534
+ }
535
+ }
536
+
537
+ // Check step dependencies
538
+ if (step.dependencies && Array.isArray(step.dependencies)) {
539
+ for (const depId of step.dependencies) {
540
+ if (!workflowData.steps.find(s => s.id === depId)) {
541
+ result.valid = false;
542
+ result.issues.push({
543
+ step: step.id || step.name,
544
+ issue: `References non-existent step: ${depId}`
545
+ });
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+
552
+ // Validate each task reference
553
+ for (const taskId of taskRefs) {
554
+ const taskPath = path.join(this.paths.tasks, `${taskId}.md`);
555
+
556
+ if (await fs.pathExists(taskPath)) {
557
+ result.taskDependencies.push({
558
+ taskId,
559
+ path: taskPath,
560
+ exists: true
561
+ });
562
+ } else {
563
+ result.valid = false;
564
+ result.missingTasks.push(taskId);
565
+ }
566
+ }
567
+
568
+ // Check for circular step dependencies
569
+ if (workflowData.steps) {
570
+ const stepGraph = new Map();
571
+
572
+ for (const step of workflowData.steps) {
573
+ const stepId = step.id || step.name;
574
+ const deps = step.dependencies || [];
575
+ stepGraph.set(stepId, deps);
576
+ }
577
+
578
+ if (this.detectCircularDependencies(stepGraph)) {
579
+ result.valid = false;
580
+ result.issues.push({
581
+ issue: 'Circular dependency detected in workflow steps'
582
+ });
583
+ }
584
+ }
585
+
586
+ return result;
587
+ }
588
+
589
+ /**
590
+ * Get minimal config for dependency creation
591
+ * @private
592
+ */
593
+ async getMinimalConfig(type, id) {
594
+ const inquirer = require('inquirer');
595
+
596
+ switch (type) {
597
+ case 'agent':
598
+ const { agentTitle } = await inquirer.prompt([{
599
+ type: 'input',
600
+ name: 'agentTitle',
601
+ message: `Title for agent '${id}':`,
602
+ default: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
603
+ }]);
604
+
605
+ return {
606
+ agentName: id,
607
+ agentTitle,
608
+ whenToUse: `Dependency for ${id}`,
609
+ commands: []
610
+ };
611
+
612
+ case 'task':
613
+ const { taskTitle } = await inquirer.prompt([{
614
+ type: 'input',
615
+ name: 'taskTitle',
616
+ message: `Title for task '${id}':`,
617
+ default: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
618
+ }]);
619
+
620
+ return {
621
+ taskId: id,
622
+ taskTitle,
623
+ taskDescription: `Dependency task for ${id}`,
624
+ agentName: 'aios-developer'
625
+ };
626
+
627
+ case 'workflow':
628
+ return {
629
+ workflowId: id,
630
+ workflowName: id.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
631
+ workflowType: 'standard',
632
+ steps: []
633
+ };
634
+ }
635
+ }
636
+ }
637
+
638
638
  module.exports = DependencyAnalyzer;