aios-core 3.6.0 → 3.8.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 (62) hide show
  1. package/.aios-core/core/session/context-detector.js +3 -0
  2. package/.aios-core/core/session/context-loader.js +154 -0
  3. package/.aios-core/data/learned-patterns.yaml +3 -0
  4. package/.aios-core/data/workflow-patterns.yaml +347 -3
  5. package/.aios-core/development/agents/dev.md +13 -0
  6. package/.aios-core/development/agents/squad-creator.md +30 -0
  7. package/.aios-core/development/scripts/squad/squad-analyzer.js +638 -0
  8. package/.aios-core/development/scripts/squad/squad-extender.js +871 -0
  9. package/.aios-core/development/scripts/squad/squad-generator.js +107 -19
  10. package/.aios-core/development/scripts/squad/squad-migrator.js +3 -5
  11. package/.aios-core/development/scripts/squad/squad-validator.js +98 -0
  12. package/.aios-core/development/tasks/create-service.md +391 -0
  13. package/.aios-core/development/tasks/next.md +294 -0
  14. package/.aios-core/development/tasks/patterns.md +334 -0
  15. package/.aios-core/development/tasks/squad-creator-analyze.md +315 -0
  16. package/.aios-core/development/tasks/squad-creator-create.md +26 -3
  17. package/.aios-core/development/tasks/squad-creator-extend.md +411 -0
  18. package/.aios-core/development/tasks/squad-creator-validate.md +9 -1
  19. package/.aios-core/development/tasks/waves.md +205 -0
  20. package/.aios-core/development/templates/service-template/README.md.hbs +158 -0
  21. package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -0
  22. package/.aios-core/development/templates/service-template/client.ts.hbs +403 -0
  23. package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -0
  24. package/.aios-core/development/templates/service-template/index.ts.hbs +120 -0
  25. package/.aios-core/development/templates/service-template/jest.config.js +89 -0
  26. package/.aios-core/development/templates/service-template/package.json.hbs +87 -0
  27. package/.aios-core/development/templates/service-template/tsconfig.json +45 -0
  28. package/.aios-core/development/templates/service-template/types.ts.hbs +145 -0
  29. package/.aios-core/development/templates/squad/agent-template.md +69 -0
  30. package/.aios-core/development/templates/squad/checklist-template.md +82 -0
  31. package/.aios-core/development/templates/squad/data-template.yaml +105 -0
  32. package/.aios-core/development/templates/squad/script-template.js +179 -0
  33. package/.aios-core/development/templates/squad/task-template.md +125 -0
  34. package/.aios-core/development/templates/squad/template-template.md +97 -0
  35. package/.aios-core/development/templates/squad/tool-template.js +103 -0
  36. package/.aios-core/development/templates/squad/workflow-template.yaml +108 -0
  37. package/.aios-core/infrastructure/scripts/ide-sync/agent-parser.js +45 -1
  38. package/.aios-core/infrastructure/scripts/ide-sync/transformers/antigravity.js +6 -6
  39. package/.aios-core/infrastructure/scripts/ide-sync/transformers/cursor.js +5 -4
  40. package/.aios-core/infrastructure/scripts/ide-sync/transformers/trae.js +3 -3
  41. package/.aios-core/infrastructure/scripts/ide-sync/transformers/windsurf.js +3 -3
  42. package/.aios-core/install-manifest.yaml +139 -35
  43. package/.aios-core/quality/metrics-collector.js +27 -0
  44. package/.aios-core/scripts/session-context-loader.js +13 -254
  45. package/.aios-core/utils/aios-validator.js +25 -0
  46. package/.aios-core/workflow-intelligence/__tests__/confidence-scorer.test.js +334 -0
  47. package/.aios-core/workflow-intelligence/__tests__/integration.test.js +337 -0
  48. package/.aios-core/workflow-intelligence/__tests__/suggestion-engine.test.js +431 -0
  49. package/.aios-core/workflow-intelligence/__tests__/wave-analyzer.test.js +458 -0
  50. package/.aios-core/workflow-intelligence/__tests__/workflow-registry.test.js +302 -0
  51. package/.aios-core/workflow-intelligence/engine/confidence-scorer.js +305 -0
  52. package/.aios-core/workflow-intelligence/engine/output-formatter.js +285 -0
  53. package/.aios-core/workflow-intelligence/engine/suggestion-engine.js +603 -0
  54. package/.aios-core/workflow-intelligence/engine/wave-analyzer.js +676 -0
  55. package/.aios-core/workflow-intelligence/index.js +327 -0
  56. package/.aios-core/workflow-intelligence/learning/capture-hook.js +147 -0
  57. package/.aios-core/workflow-intelligence/learning/index.js +230 -0
  58. package/.aios-core/workflow-intelligence/learning/pattern-capture.js +340 -0
  59. package/.aios-core/workflow-intelligence/learning/pattern-store.js +498 -0
  60. package/.aios-core/workflow-intelligence/learning/pattern-validator.js +309 -0
  61. package/.aios-core/workflow-intelligence/registry/workflow-registry.js +358 -0
  62. package/package.json +1 -1
@@ -0,0 +1,309 @@
1
+ /**
2
+ * @module PatternValidator
3
+ * @description Validates workflow patterns before storage
4
+ * @story WIS-5 - Pattern Capture (Internal)
5
+ * @version 1.0.0
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ /**
11
+ * Default validation rules
12
+ * @type {Object}
13
+ */
14
+ const DEFAULT_VALIDATION_RULES = {
15
+ minSequenceLength: 3,
16
+ maxSequenceLength: 10,
17
+ minOccurrences: 2,
18
+ minSuccessRate: 0.8,
19
+ requiredKeyCommands: [
20
+ 'develop',
21
+ 'review-qa',
22
+ 'create-story',
23
+ 'validate-story-draft',
24
+ 'apply-qa-fixes',
25
+ 'run-tests'
26
+ ],
27
+ similarityThreshold: 0.85 // For fuzzy duplicate detection
28
+ };
29
+
30
+ /**
31
+ * Known AIOS task registry commands
32
+ * @type {Set<string>}
33
+ */
34
+ const KNOWN_COMMANDS = new Set([
35
+ 'develop',
36
+ 'develop-yolo',
37
+ 'develop-interactive',
38
+ 'develop-preflight',
39
+ 'review-qa',
40
+ 'apply-qa-fixes',
41
+ 'run-tests',
42
+ 'create-story',
43
+ 'create-next-story',
44
+ 'validate-story-draft',
45
+ 'create-pr',
46
+ 'push',
47
+ 'backlog-debt',
48
+ 'help',
49
+ 'exit',
50
+ 'guide',
51
+ 'explain',
52
+ 'session-info',
53
+ 'load-full',
54
+ 'clear-cache',
55
+ 'patterns',
56
+ 'next'
57
+ ]);
58
+
59
+ /**
60
+ * PatternValidator class for validating pattern quality
61
+ */
62
+ class PatternValidator {
63
+ /**
64
+ * Create a PatternValidator instance
65
+ * @param {Object} options - Configuration options
66
+ * @param {Object} options.rules - Custom validation rules
67
+ */
68
+ constructor(options = {}) {
69
+ this.rules = { ...DEFAULT_VALIDATION_RULES, ...options.rules };
70
+ }
71
+
72
+ /**
73
+ * Validate a pattern against all rules
74
+ * @param {Object} pattern - Pattern to validate
75
+ * @returns {Object} Validation result with valid flag and reasons
76
+ */
77
+ validate(pattern) {
78
+ const errors = [];
79
+ const warnings = [];
80
+
81
+ // Check required fields
82
+ if (!pattern) {
83
+ return { valid: false, errors: ['Pattern is null or undefined'], warnings: [] };
84
+ }
85
+
86
+ if (!pattern.sequence || !Array.isArray(pattern.sequence)) {
87
+ return { valid: false, errors: ['Missing or invalid sequence'], warnings: [] };
88
+ }
89
+
90
+ // Rule 1: Minimum sequence length
91
+ if (pattern.sequence.length < this.rules.minSequenceLength) {
92
+ errors.push(
93
+ `Sequence too short: ${pattern.sequence.length} < minimum ${this.rules.minSequenceLength}`
94
+ );
95
+ }
96
+
97
+ // Rule 2: Maximum sequence length
98
+ if (pattern.sequence.length > this.rules.maxSequenceLength) {
99
+ warnings.push(
100
+ `Sequence unusually long: ${pattern.sequence.length} > ${this.rules.maxSequenceLength}`
101
+ );
102
+ }
103
+
104
+ // Rule 3: Minimum occurrences for promotion
105
+ if (pattern.occurrences !== undefined && pattern.occurrences < this.rules.minOccurrences) {
106
+ warnings.push(
107
+ `Low occurrences: ${pattern.occurrences} < minimum ${this.rules.minOccurrences} for promotion`
108
+ );
109
+ }
110
+
111
+ // Rule 4: Minimum success rate
112
+ if (pattern.successRate !== undefined && pattern.successRate < this.rules.minSuccessRate) {
113
+ errors.push(
114
+ `Success rate too low: ${(pattern.successRate * 100).toFixed(1)}% < ${(this.rules.minSuccessRate * 100).toFixed(1)}%`
115
+ );
116
+ }
117
+
118
+ // Rule 5: Must contain at least one key workflow command
119
+ const hasKeyCommand = pattern.sequence.some(cmd =>
120
+ this.rules.requiredKeyCommands.some(key => cmd.includes(key))
121
+ );
122
+ if (!hasKeyCommand) {
123
+ errors.push('Sequence must contain at least one key workflow command');
124
+ }
125
+
126
+ // Rule 6: All commands should exist in AIOS task registry
127
+ const unknownCommands = pattern.sequence.filter(cmd => !this._isKnownCommand(cmd));
128
+ if (unknownCommands.length > 0) {
129
+ warnings.push(`Unknown commands: ${unknownCommands.join(', ')}`);
130
+ }
131
+
132
+ // Rule 7: No duplicate consecutive commands
133
+ const hasDuplicateConsecutive = pattern.sequence.some(
134
+ (cmd, i) => i > 0 && cmd === pattern.sequence[i - 1]
135
+ );
136
+ if (hasDuplicateConsecutive) {
137
+ warnings.push('Pattern contains duplicate consecutive commands');
138
+ }
139
+
140
+ return {
141
+ valid: errors.length === 0,
142
+ errors: errors,
143
+ warnings: warnings,
144
+ reason: errors.length > 0 ? errors.join('; ') : null
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Check if a pattern is a duplicate of existing patterns
150
+ * @param {Object} pattern - Pattern to check
151
+ * @param {Object[]} existingPatterns - Existing patterns to compare against
152
+ * @returns {Object} Duplicate check result
153
+ */
154
+ isDuplicate(pattern, existingPatterns) {
155
+ if (!existingPatterns || existingPatterns.length === 0) {
156
+ return { isDuplicate: false };
157
+ }
158
+
159
+ for (const existing of existingPatterns) {
160
+ // Exact match check first
161
+ if (this._isExactMatch(pattern.sequence, existing.sequence)) {
162
+ return {
163
+ isDuplicate: true,
164
+ duplicateOf: existing.id,
165
+ similarity: 1.0,
166
+ exact: true
167
+ };
168
+ }
169
+
170
+ // Then similarity check
171
+ const similarity = this._calculateSimilarity(pattern.sequence, existing.sequence);
172
+
173
+ if (similarity >= this.rules.similarityThreshold) {
174
+ return {
175
+ isDuplicate: true,
176
+ duplicateOf: existing.id,
177
+ similarity: similarity
178
+ };
179
+ }
180
+ }
181
+
182
+ return { isDuplicate: false };
183
+ }
184
+
185
+ /**
186
+ * Check if pattern meets minimum threshold for promotion
187
+ * @param {Object} pattern - Pattern to check
188
+ * @returns {Object} Threshold check result
189
+ */
190
+ meetsMinimumThreshold(pattern) {
191
+ const meetsOccurrences = pattern.occurrences >= this.rules.minOccurrences;
192
+ const meetsSuccessRate = pattern.successRate >= this.rules.minSuccessRate;
193
+
194
+ return {
195
+ meetsThreshold: meetsOccurrences && meetsSuccessRate,
196
+ meetsOccurrences: meetsOccurrences,
197
+ meetsSuccessRate: meetsSuccessRate,
198
+ currentOccurrences: pattern.occurrences,
199
+ requiredOccurrences: this.rules.minOccurrences,
200
+ currentSuccessRate: pattern.successRate,
201
+ requiredSuccessRate: this.rules.minSuccessRate
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Get current validation rules
207
+ * @returns {Object} Current validation rules
208
+ */
209
+ getValidationRules() {
210
+ return { ...this.rules };
211
+ }
212
+
213
+ /**
214
+ * Update validation rules
215
+ * @param {Object} newRules - New rules to merge
216
+ */
217
+ updateRules(newRules) {
218
+ this.rules = { ...this.rules, ...newRules };
219
+ }
220
+
221
+ /**
222
+ * Check if a command is known in the AIOS task registry
223
+ * @param {string} command - Command to check
224
+ * @returns {boolean} True if command is known
225
+ * @private
226
+ */
227
+ _isKnownCommand(command) {
228
+ const normalized = command.toLowerCase().replace(/^\*/, '').trim();
229
+
230
+ // Direct match
231
+ if (KNOWN_COMMANDS.has(normalized)) {
232
+ return true;
233
+ }
234
+
235
+ // Prefix match (e.g., "develop-yolo" starts with known "develop")
236
+ for (const known of KNOWN_COMMANDS) {
237
+ if (normalized.startsWith(known) || known.startsWith(normalized)) {
238
+ return true;
239
+ }
240
+ }
241
+
242
+ return false;
243
+ }
244
+
245
+ /**
246
+ * Calculate similarity between two sequences using Jaccard similarity
247
+ * @param {string[]} seq1 - First sequence
248
+ * @param {string[]} seq2 - Second sequence
249
+ * @returns {number} Similarity score (0-1)
250
+ * @private
251
+ */
252
+ _calculateSimilarity(seq1, seq2) {
253
+ if (!seq1 || !seq2 || seq1.length === 0 || seq2.length === 0) {
254
+ return 0;
255
+ }
256
+
257
+ const set1 = new Set(seq1);
258
+ const set2 = new Set(seq2);
259
+
260
+ // Jaccard similarity
261
+ const intersection = new Set([...set1].filter(x => set2.has(x)));
262
+ const union = new Set([...set1, ...set2]);
263
+
264
+ const jaccardSimilarity = intersection.size / union.size;
265
+
266
+ // Order similarity (for sequence patterns, order matters)
267
+ let orderScore = 0;
268
+ const minLen = Math.min(seq1.length, seq2.length);
269
+ for (let i = 0; i < minLen; i++) {
270
+ if (seq1[i] === seq2[i]) {
271
+ orderScore++;
272
+ }
273
+ }
274
+ const orderSimilarity = orderScore / Math.max(seq1.length, seq2.length);
275
+
276
+ // Combined score (weighted average)
277
+ return (jaccardSimilarity * 0.4) + (orderSimilarity * 0.6);
278
+ }
279
+
280
+ /**
281
+ * Check if two sequences are exactly the same
282
+ * @param {string[]} seq1 - First sequence
283
+ * @param {string[]} seq2 - Second sequence
284
+ * @returns {boolean} True if exact match
285
+ * @private
286
+ */
287
+ _isExactMatch(seq1, seq2) {
288
+ if (seq1.length !== seq2.length) {
289
+ return false;
290
+ }
291
+ return seq1.every((cmd, i) => cmd === seq2[i]);
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Create a new PatternValidator instance
297
+ * @param {Object} options - Configuration options
298
+ * @returns {PatternValidator} New instance
299
+ */
300
+ function createPatternValidator(options = {}) {
301
+ return new PatternValidator(options);
302
+ }
303
+
304
+ module.exports = {
305
+ PatternValidator,
306
+ createPatternValidator,
307
+ DEFAULT_VALIDATION_RULES,
308
+ KNOWN_COMMANDS
309
+ };
@@ -0,0 +1,358 @@
1
+ /**
2
+ * @module WorkflowRegistry
3
+ * @description Registry for loading and managing workflow patterns
4
+ * @story WIS-2 - Workflow Registry Enhancement
5
+ * @version 1.0.0
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const yaml = require('js-yaml');
13
+
14
+ /**
15
+ * Default cache TTL in milliseconds (5 minutes)
16
+ * @type {number}
17
+ */
18
+ const DEFAULT_CACHE_TTL = 5 * 60 * 1000;
19
+
20
+ /**
21
+ * Default path to workflow patterns file
22
+ * @type {string}
23
+ */
24
+ const DEFAULT_PATTERNS_PATH = path.join(
25
+ __dirname,
26
+ '../../data/workflow-patterns.yaml'
27
+ );
28
+
29
+ /**
30
+ * WorkflowRegistry class for managing workflow patterns
31
+ */
32
+ class WorkflowRegistry {
33
+ /**
34
+ * Create a WorkflowRegistry instance
35
+ * @param {Object} options - Configuration options
36
+ * @param {string} options.patternsPath - Path to workflow-patterns.yaml
37
+ * @param {number} options.cacheTTL - Cache time-to-live in milliseconds
38
+ */
39
+ constructor(options = {}) {
40
+ this.patternsPath = options.patternsPath || DEFAULT_PATTERNS_PATH;
41
+ this.cacheTTL = options.cacheTTL || DEFAULT_CACHE_TTL;
42
+ this.cache = null;
43
+ this.cacheTimestamp = null;
44
+ }
45
+
46
+ /**
47
+ * Load workflows from YAML file with caching
48
+ * @returns {Object} Loaded workflow patterns
49
+ * @throws {Error} If file cannot be read or parsed
50
+ */
51
+ loadWorkflows() {
52
+ // Check if cache is valid
53
+ if (this.isCacheValid()) {
54
+ return this.cache;
55
+ }
56
+
57
+ try {
58
+ const content = fs.readFileSync(this.patternsPath, 'utf8');
59
+ const parsed = yaml.load(content);
60
+
61
+ if (!parsed || !parsed.workflows) {
62
+ throw new Error('Invalid workflow patterns file: missing workflows key');
63
+ }
64
+
65
+ this.cache = parsed.workflows;
66
+ this.cacheTimestamp = Date.now();
67
+
68
+ return this.cache;
69
+ } catch (error) {
70
+ if (error.code === 'ENOENT') {
71
+ throw new Error(`Workflow patterns file not found: ${this.patternsPath}`);
72
+ }
73
+ throw new Error(`Failed to load workflow patterns: ${error.message}`);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Check if cache is still valid
79
+ * @returns {boolean} True if cache is valid
80
+ */
81
+ isCacheValid() {
82
+ if (!this.cache || !this.cacheTimestamp) {
83
+ return false;
84
+ }
85
+ return (Date.now() - this.cacheTimestamp) < this.cacheTTL;
86
+ }
87
+
88
+ /**
89
+ * Invalidate the cache
90
+ */
91
+ invalidateCache() {
92
+ this.cache = null;
93
+ this.cacheTimestamp = null;
94
+ }
95
+
96
+ /**
97
+ * Get all workflow names
98
+ * @returns {string[]} Array of workflow names
99
+ */
100
+ getWorkflowNames() {
101
+ const workflows = this.loadWorkflows();
102
+ return Object.keys(workflows);
103
+ }
104
+
105
+ /**
106
+ * Get a specific workflow by name
107
+ * @param {string} name - Workflow name
108
+ * @returns {Object|null} Workflow object or null if not found
109
+ */
110
+ getWorkflow(name) {
111
+ const workflows = this.loadWorkflows();
112
+ return workflows[name] || null;
113
+ }
114
+
115
+ /**
116
+ * Match command history to find the best matching workflow
117
+ * @param {string[]} commands - Recent command history
118
+ * @returns {Object|null} Best matching workflow with score, or null
119
+ */
120
+ matchWorkflow(commands) {
121
+ if (!commands || commands.length === 0) {
122
+ return null;
123
+ }
124
+
125
+ const workflows = this.loadWorkflows();
126
+ const normalizedCommands = commands.map(cmd => this.normalizeCommand(cmd));
127
+
128
+ let bestMatch = null;
129
+ let bestScore = 0;
130
+
131
+ for (const [name, workflow] of Object.entries(workflows)) {
132
+ const score = this.calculateWorkflowMatch(workflow, normalizedCommands);
133
+
134
+ if (score > bestScore && score >= (workflow.trigger_threshold ?? 2)) {
135
+ bestScore = score;
136
+ bestMatch = {
137
+ name,
138
+ workflow,
139
+ score,
140
+ matchedCommands: this.getMatchedCommands(workflow, normalizedCommands)
141
+ };
142
+ }
143
+ }
144
+
145
+ return bestMatch;
146
+ }
147
+
148
+ /**
149
+ * Calculate match score between workflow and command history
150
+ * @param {Object} workflow - Workflow definition
151
+ * @param {string[]} commands - Normalized command history
152
+ * @returns {number} Match score
153
+ */
154
+ calculateWorkflowMatch(workflow, commands) {
155
+ if (!workflow.key_commands) {
156
+ return 0;
157
+ }
158
+
159
+ const keyCommands = workflow.key_commands.map(cmd => this.normalizeCommand(cmd));
160
+ let matches = 0;
161
+
162
+ for (const cmd of commands) {
163
+ for (const keyCmd of keyCommands) {
164
+ if (cmd.includes(keyCmd) || keyCmd.includes(cmd)) {
165
+ matches++;
166
+ break;
167
+ }
168
+ }
169
+ }
170
+
171
+ return matches;
172
+ }
173
+
174
+ /**
175
+ * Get commands that matched from history
176
+ * @param {Object} workflow - Workflow definition
177
+ * @param {string[]} commands - Normalized command history
178
+ * @returns {string[]} Matched commands
179
+ */
180
+ getMatchedCommands(workflow, commands) {
181
+ if (!workflow.key_commands) {
182
+ return [];
183
+ }
184
+
185
+ const keyCommands = workflow.key_commands.map(cmd => this.normalizeCommand(cmd));
186
+ const matched = [];
187
+
188
+ for (const cmd of commands) {
189
+ for (const keyCmd of keyCommands) {
190
+ if (cmd.includes(keyCmd) || keyCmd.includes(cmd)) {
191
+ matched.push(cmd);
192
+ break;
193
+ }
194
+ }
195
+ }
196
+
197
+ return matched;
198
+ }
199
+
200
+ /**
201
+ * Get transitions for a workflow state
202
+ * @param {string} workflowName - Name of the workflow
203
+ * @param {string} state - Current state in the workflow
204
+ * @returns {Object|null} Transition object or null if not found
205
+ */
206
+ getTransitions(workflowName, state) {
207
+ const workflow = this.getWorkflow(workflowName);
208
+
209
+ if (!workflow || !workflow.transitions) {
210
+ return null;
211
+ }
212
+
213
+ return workflow.transitions[state] || null;
214
+ }
215
+
216
+ /**
217
+ * Get all available transitions for a workflow
218
+ * @param {string} workflowName - Name of the workflow
219
+ * @returns {Object} All transitions for the workflow
220
+ */
221
+ getAllTransitions(workflowName) {
222
+ const workflow = this.getWorkflow(workflowName);
223
+
224
+ if (!workflow || !workflow.transitions) {
225
+ return {};
226
+ }
227
+
228
+ return workflow.transitions;
229
+ }
230
+
231
+ /**
232
+ * Get next steps for a workflow state
233
+ * @param {string} workflowName - Name of the workflow
234
+ * @param {string} state - Current state
235
+ * @returns {Object[]} Array of next step suggestions
236
+ */
237
+ getNextSteps(workflowName, state) {
238
+ const transition = this.getTransitions(workflowName, state);
239
+
240
+ if (!transition || !transition.next_steps) {
241
+ return [];
242
+ }
243
+
244
+ return transition.next_steps.sort((a, b) => (a.priority || 99) - (b.priority || 99));
245
+ }
246
+
247
+ /**
248
+ * Find current state based on last command
249
+ * @param {string} workflowName - Name of the workflow
250
+ * @param {string} lastCommand - Last executed command
251
+ * @returns {string|null} Current state or null if not found
252
+ */
253
+ findCurrentState(workflowName, lastCommand) {
254
+ const workflow = this.getWorkflow(workflowName);
255
+
256
+ if (!workflow || !workflow.transitions) {
257
+ return null;
258
+ }
259
+
260
+ const normalizedCmd = this.normalizeCommand(lastCommand);
261
+
262
+ for (const [state, transition] of Object.entries(workflow.transitions)) {
263
+ if (transition.trigger) {
264
+ const normalizedTrigger = this.normalizeCommand(transition.trigger);
265
+ if (normalizedCmd.includes(normalizedTrigger) ||
266
+ normalizedTrigger.includes(normalizedCmd)) {
267
+ return state;
268
+ }
269
+ }
270
+ }
271
+
272
+ return null;
273
+ }
274
+
275
+ /**
276
+ * Get workflows by agent
277
+ * @param {string} agentId - Agent identifier
278
+ * @returns {Object[]} Workflows involving this agent
279
+ */
280
+ getWorkflowsByAgent(agentId) {
281
+ const workflows = this.loadWorkflows();
282
+ const normalizedAgent = agentId.replace('@', '').toLowerCase();
283
+ const results = [];
284
+
285
+ for (const [name, workflow] of Object.entries(workflows)) {
286
+ if (workflow.agent_sequence) {
287
+ const hasAgent = workflow.agent_sequence.some(
288
+ agent => agent.toLowerCase() === normalizedAgent
289
+ );
290
+ if (hasAgent) {
291
+ results.push({ name, workflow });
292
+ }
293
+ }
294
+ }
295
+
296
+ return results;
297
+ }
298
+
299
+ /**
300
+ * Normalize a command string for matching
301
+ * @param {string} command - Command to normalize
302
+ * @returns {string} Normalized command
303
+ */
304
+ normalizeCommand(command) {
305
+ if (!command) return '';
306
+
307
+ return command
308
+ .toLowerCase()
309
+ .replace(/\s+completed\s*$/i, '')
310
+ .replace(/\s+successfully\s*$/i, '')
311
+ .replace(/^\*/, '')
312
+ .replace(/['"]/g, '')
313
+ .trim();
314
+ }
315
+
316
+ /**
317
+ * Get registry statistics
318
+ * @returns {Object} Statistics about the registry
319
+ */
320
+ getStats() {
321
+ const workflows = this.loadWorkflows();
322
+ const workflowNames = Object.keys(workflows);
323
+
324
+ let totalTransitions = 0;
325
+ let workflowsWithTransitions = 0;
326
+
327
+ for (const workflow of Object.values(workflows)) {
328
+ if (workflow.transitions) {
329
+ workflowsWithTransitions++;
330
+ totalTransitions += Object.keys(workflow.transitions).length;
331
+ }
332
+ }
333
+
334
+ return {
335
+ totalWorkflows: workflowNames.length,
336
+ workflowsWithTransitions,
337
+ totalTransitions,
338
+ cacheValid: this.isCacheValid(),
339
+ cacheAge: this.cacheTimestamp ? Date.now() - this.cacheTimestamp : null
340
+ };
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Create a new WorkflowRegistry instance
346
+ * @param {Object} options - Configuration options
347
+ * @returns {WorkflowRegistry} New registry instance
348
+ */
349
+ function createWorkflowRegistry(options = {}) {
350
+ return new WorkflowRegistry(options);
351
+ }
352
+
353
+ module.exports = {
354
+ WorkflowRegistry,
355
+ createWorkflowRegistry,
356
+ DEFAULT_CACHE_TTL,
357
+ DEFAULT_PATTERNS_PATH
358
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aios-core",
3
- "version": "3.6.0",
3
+ "version": "3.8.0",
4
4
  "description": "Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework",
5
5
  "main": "index.js",
6
6
  "module": "index.esm.js",