aios-core 3.7.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 (47) 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 +6 -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/next.md +294 -0
  13. package/.aios-core/development/tasks/patterns.md +334 -0
  14. package/.aios-core/development/tasks/squad-creator-analyze.md +315 -0
  15. package/.aios-core/development/tasks/squad-creator-create.md +26 -3
  16. package/.aios-core/development/tasks/squad-creator-extend.md +411 -0
  17. package/.aios-core/development/tasks/squad-creator-validate.md +9 -1
  18. package/.aios-core/development/tasks/waves.md +205 -0
  19. package/.aios-core/development/templates/squad/agent-template.md +69 -0
  20. package/.aios-core/development/templates/squad/checklist-template.md +82 -0
  21. package/.aios-core/development/templates/squad/data-template.yaml +105 -0
  22. package/.aios-core/development/templates/squad/script-template.js +179 -0
  23. package/.aios-core/development/templates/squad/task-template.md +125 -0
  24. package/.aios-core/development/templates/squad/template-template.md +97 -0
  25. package/.aios-core/development/templates/squad/tool-template.js +103 -0
  26. package/.aios-core/development/templates/squad/workflow-template.yaml +108 -0
  27. package/.aios-core/install-manifest.yaml +89 -25
  28. package/.aios-core/quality/metrics-collector.js +27 -0
  29. package/.aios-core/scripts/session-context-loader.js +13 -254
  30. package/.aios-core/utils/aios-validator.js +25 -0
  31. package/.aios-core/workflow-intelligence/__tests__/confidence-scorer.test.js +334 -0
  32. package/.aios-core/workflow-intelligence/__tests__/integration.test.js +337 -0
  33. package/.aios-core/workflow-intelligence/__tests__/suggestion-engine.test.js +431 -0
  34. package/.aios-core/workflow-intelligence/__tests__/wave-analyzer.test.js +458 -0
  35. package/.aios-core/workflow-intelligence/__tests__/workflow-registry.test.js +302 -0
  36. package/.aios-core/workflow-intelligence/engine/confidence-scorer.js +305 -0
  37. package/.aios-core/workflow-intelligence/engine/output-formatter.js +285 -0
  38. package/.aios-core/workflow-intelligence/engine/suggestion-engine.js +603 -0
  39. package/.aios-core/workflow-intelligence/engine/wave-analyzer.js +676 -0
  40. package/.aios-core/workflow-intelligence/index.js +327 -0
  41. package/.aios-core/workflow-intelligence/learning/capture-hook.js +147 -0
  42. package/.aios-core/workflow-intelligence/learning/index.js +230 -0
  43. package/.aios-core/workflow-intelligence/learning/pattern-capture.js +340 -0
  44. package/.aios-core/workflow-intelligence/learning/pattern-store.js +498 -0
  45. package/.aios-core/workflow-intelligence/learning/pattern-validator.js +309 -0
  46. package/.aios-core/workflow-intelligence/registry/workflow-registry.js +358 -0
  47. package/package.json +1 -1
@@ -0,0 +1,871 @@
1
+ /**
2
+ * Squad Extender Utility
3
+ *
4
+ * Extends existing squads with new components (agents, tasks, workflows, etc.)
5
+ * with automatic manifest updates and validation.
6
+ *
7
+ * Used by: squad-creator agent (*extend-squad task)
8
+ *
9
+ * @module squad-extender
10
+ * @version 1.0.0
11
+ * @see Story SQS-11: Squad Analyze & Extend
12
+ */
13
+
14
+ const fs = require('fs').promises;
15
+ const path = require('path');
16
+ const yaml = require('js-yaml');
17
+
18
+ /**
19
+ * Default path for squads directory
20
+ * @constant {string}
21
+ */
22
+ const DEFAULT_SQUADS_PATH = './squads';
23
+
24
+ /**
25
+ * Default templates directory path
26
+ * @constant {string}
27
+ */
28
+ const DEFAULT_TEMPLATES_PATH = './.aios-core/development/templates/squad';
29
+
30
+ /**
31
+ * Component types and their configurations
32
+ * @constant {Object}
33
+ */
34
+ const COMPONENT_CONFIG = {
35
+ agent: {
36
+ directory: 'agents',
37
+ extension: '.md',
38
+ template: 'agent-template.md',
39
+ manifestKey: 'agents',
40
+ },
41
+ task: {
42
+ directory: 'tasks',
43
+ extension: '.md',
44
+ template: 'task-template.md',
45
+ manifestKey: 'tasks',
46
+ },
47
+ workflow: {
48
+ directory: 'workflows',
49
+ extension: '.yaml',
50
+ template: 'workflow-template.yaml',
51
+ manifestKey: 'workflows',
52
+ },
53
+ checklist: {
54
+ directory: 'checklists',
55
+ extension: '.md',
56
+ template: 'checklist-template.md',
57
+ manifestKey: 'checklists',
58
+ },
59
+ template: {
60
+ directory: 'templates',
61
+ extension: '.md',
62
+ template: 'template-template.md',
63
+ manifestKey: 'templates',
64
+ },
65
+ tool: {
66
+ directory: 'tools',
67
+ extension: '.js',
68
+ template: 'tool-template.js',
69
+ manifestKey: 'tools',
70
+ },
71
+ script: {
72
+ directory: 'scripts',
73
+ extension: '.js',
74
+ template: 'script-template.js',
75
+ manifestKey: 'scripts',
76
+ },
77
+ data: {
78
+ directory: 'data',
79
+ extension: '.yaml',
80
+ template: 'data-template.yaml',
81
+ manifestKey: 'data',
82
+ },
83
+ };
84
+
85
+ /**
86
+ * Manifest file names in order of preference
87
+ * @constant {string[]}
88
+ */
89
+ const MANIFEST_FILES = ['squad.yaml', 'config.yaml'];
90
+
91
+ /**
92
+ * Error codes for SquadExtenderError
93
+ * @enum {string}
94
+ */
95
+ const ErrorCodes = {
96
+ SQUAD_NOT_FOUND: 'SQUAD_NOT_FOUND',
97
+ MANIFEST_NOT_FOUND: 'MANIFEST_NOT_FOUND',
98
+ MANIFEST_UPDATE_FAILED: 'MANIFEST_UPDATE_FAILED',
99
+ COMPONENT_EXISTS: 'COMPONENT_EXISTS',
100
+ INVALID_COMPONENT_NAME: 'INVALID_COMPONENT_NAME',
101
+ INVALID_COMPONENT_TYPE: 'INVALID_COMPONENT_TYPE',
102
+ AGENT_NOT_FOUND: 'AGENT_NOT_FOUND',
103
+ TEMPLATE_NOT_FOUND: 'TEMPLATE_NOT_FOUND',
104
+ PATH_TRAVERSAL: 'PATH_TRAVERSAL',
105
+ CREATION_FAILED: 'CREATION_FAILED',
106
+ };
107
+
108
+ /**
109
+ * Custom error class for Squad Extender operations
110
+ * @extends Error
111
+ */
112
+ class SquadExtenderError extends Error {
113
+ /**
114
+ * Create a SquadExtenderError
115
+ * @param {string} code - Error code from ErrorCodes enum
116
+ * @param {string} message - Human-readable error message
117
+ * @param {string} [suggestion] - Suggested fix for the error
118
+ */
119
+ constructor(code, message, suggestion) {
120
+ super(message);
121
+ this.name = 'SquadExtenderError';
122
+ this.code = code;
123
+ this.suggestion = suggestion || '';
124
+
125
+ if (Error.captureStackTrace) {
126
+ Error.captureStackTrace(this, SquadExtenderError);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Create error for squad not found
132
+ * @param {string} squadName - Name of the squad
133
+ * @returns {SquadExtenderError}
134
+ */
135
+ static squadNotFound(squadName) {
136
+ return new SquadExtenderError(
137
+ ErrorCodes.SQUAD_NOT_FOUND,
138
+ `Squad "${squadName}" not found`,
139
+ `Use *list-squads to see available squads, or *create-squad ${squadName} to create it`
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Create error for manifest not found
145
+ * @param {string} squadPath - Path to squad directory
146
+ * @returns {SquadExtenderError}
147
+ */
148
+ static manifestNotFound(squadPath) {
149
+ return new SquadExtenderError(
150
+ ErrorCodes.MANIFEST_NOT_FOUND,
151
+ `No squad.yaml or config.yaml found in ${squadPath}`,
152
+ 'Create squad.yaml with squad metadata'
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Create error for component already exists
158
+ * @param {string} filePath - Path to existing component
159
+ * @returns {SquadExtenderError}
160
+ */
161
+ static componentExists(filePath) {
162
+ return new SquadExtenderError(
163
+ ErrorCodes.COMPONENT_EXISTS,
164
+ `Component already exists at ${filePath}`,
165
+ 'Use --force to overwrite, or choose a different name'
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Create error for invalid component name
171
+ * @param {string} name - Invalid component name
172
+ * @returns {SquadExtenderError}
173
+ */
174
+ static invalidComponentName(name) {
175
+ return new SquadExtenderError(
176
+ ErrorCodes.INVALID_COMPONENT_NAME,
177
+ `Invalid component name: "${name}"`,
178
+ 'Use kebab-case (lowercase letters, numbers, and hyphens only)'
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Create error for invalid component type
184
+ * @param {string} type - Invalid component type
185
+ * @returns {SquadExtenderError}
186
+ */
187
+ static invalidComponentType(type) {
188
+ const validTypes = Object.keys(COMPONENT_CONFIG).join(', ');
189
+ return new SquadExtenderError(
190
+ ErrorCodes.INVALID_COMPONENT_TYPE,
191
+ `Invalid component type: "${type}"`,
192
+ `Valid types are: ${validTypes}`
193
+ );
194
+ }
195
+
196
+ /**
197
+ * Create error for agent not found
198
+ * @param {string} agentId - Agent ID not found
199
+ * @param {string[]} availableAgents - List of available agents
200
+ * @returns {SquadExtenderError}
201
+ */
202
+ static agentNotFound(agentId, availableAgents) {
203
+ return new SquadExtenderError(
204
+ ErrorCodes.AGENT_NOT_FOUND,
205
+ `Agent "${agentId}" not found in squad`,
206
+ `Available agents: ${availableAgents.join(', ')}`
207
+ );
208
+ }
209
+
210
+ /**
211
+ * Create error for path traversal attempt
212
+ * @param {string} name - Component name with path characters
213
+ * @returns {SquadExtenderError}
214
+ */
215
+ static pathTraversal(name) {
216
+ return new SquadExtenderError(
217
+ ErrorCodes.PATH_TRAVERSAL,
218
+ `Invalid component name - path traversal not allowed: "${name}"`,
219
+ 'Component names cannot contain path separators or ".."'
220
+ );
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Squad Extender class for adding new components to squads
226
+ */
227
+ class SquadExtender {
228
+ /**
229
+ * Create a SquadExtender instance
230
+ * @param {Object} [options={}] - Configuration options
231
+ * @param {string} [options.squadsPath] - Custom squads directory path
232
+ * @param {string} [options.templatesPath] - Custom templates directory path
233
+ * @param {boolean} [options.verbose=false] - Enable verbose output
234
+ */
235
+ constructor(options = {}) {
236
+ this.squadsPath = options.squadsPath || DEFAULT_SQUADS_PATH;
237
+ this.templatesPath = options.templatesPath || DEFAULT_TEMPLATES_PATH;
238
+ this.verbose = options.verbose || false;
239
+ }
240
+
241
+ /**
242
+ * Add a new component to a squad
243
+ * @param {string} squadName - Name of the squad
244
+ * @param {Object} componentInfo - Component configuration
245
+ * @param {string} componentInfo.type - Component type (agent, task, workflow, etc.)
246
+ * @param {string} componentInfo.name - Component name (kebab-case)
247
+ * @param {string} [componentInfo.agentId] - Agent ID (required for tasks)
248
+ * @param {string} [componentInfo.description] - Component description
249
+ * @param {string} [componentInfo.storyId] - Related story ID for traceability
250
+ * @param {Object} [options={}] - Add options
251
+ * @param {boolean} [options.force=false] - Overwrite existing component
252
+ * @returns {Promise<Object>} Result object with file path and status
253
+ */
254
+ async addComponent(squadName, componentInfo, options = {}) {
255
+ const { type, name, agentId, description, storyId } = componentInfo;
256
+ const { force = false } = options;
257
+
258
+ // Validate inputs
259
+ this._validateComponentType(type);
260
+ this._validateComponentName(name);
261
+
262
+ const squadPath = path.join(this.squadsPath, squadName);
263
+
264
+ // Check squad exists
265
+ const exists = await this._directoryExists(squadPath);
266
+ if (!exists) {
267
+ throw SquadExtenderError.squadNotFound(squadName);
268
+ }
269
+
270
+ // For tasks, validate agent exists
271
+ if (type === 'task' && agentId) {
272
+ await this._validateAgentExists(squadPath, agentId);
273
+ }
274
+
275
+ // Get component config
276
+ const config = COMPONENT_CONFIG[type];
277
+
278
+ // Build file name
279
+ const fileName = this._buildFileName(type, name, agentId, config.extension);
280
+
281
+ // Build target path
282
+ const targetDir = path.join(squadPath, config.directory);
283
+ const targetPath = path.join(targetDir, fileName);
284
+ const relativePath = path.join(config.directory, fileName);
285
+
286
+ // Check if file already exists
287
+ if (await this._fileExists(targetPath)) {
288
+ if (!force) {
289
+ throw SquadExtenderError.componentExists(relativePath);
290
+ }
291
+ // Create backup before overwriting
292
+ await this._createBackup(targetPath);
293
+ }
294
+
295
+ // Ensure target directory exists
296
+ await this._ensureDirectory(targetDir);
297
+
298
+ // Load and render template
299
+ const content = await this._renderTemplate(type, {
300
+ componentName: name,
301
+ agentId,
302
+ description: description || `${type} component: ${name}`,
303
+ storyId: storyId || '',
304
+ squadName,
305
+ createdAt: new Date().toISOString().split('T')[0],
306
+ });
307
+
308
+ // Write component file
309
+ await fs.writeFile(targetPath, content, 'utf8');
310
+
311
+ // Update manifest
312
+ const manifestUpdated = await this.updateManifest(squadPath, {
313
+ type,
314
+ file: fileName,
315
+ });
316
+
317
+ return {
318
+ success: true,
319
+ filePath: targetPath,
320
+ relativePath,
321
+ fileName,
322
+ type,
323
+ templateUsed: config.template,
324
+ manifestUpdated,
325
+ };
326
+ }
327
+
328
+ /**
329
+ * Update squad manifest with new component
330
+ * @param {string} squadPath - Path to squad directory
331
+ * @param {Object} componentInfo - Component information
332
+ * @param {string} componentInfo.type - Component type
333
+ * @param {string} componentInfo.file - Component file name
334
+ * @returns {Promise<boolean>} True if manifest was updated
335
+ */
336
+ async updateManifest(squadPath, componentInfo) {
337
+ const { type, file } = componentInfo;
338
+ const config = COMPONENT_CONFIG[type];
339
+ const manifestKey = config.manifestKey;
340
+
341
+ // Find manifest file
342
+ const { manifestPath, manifest } = await this._loadManifest(squadPath);
343
+
344
+ // Create backup
345
+ await this._createBackup(manifestPath);
346
+
347
+ // Ensure components section exists
348
+ if (!manifest.components) {
349
+ manifest.components = {};
350
+ }
351
+
352
+ // Ensure component type array exists
353
+ if (!manifest.components[manifestKey]) {
354
+ manifest.components[manifestKey] = [];
355
+ }
356
+
357
+ // Add file if not already present
358
+ if (!manifest.components[manifestKey].includes(file)) {
359
+ manifest.components[manifestKey].push(file);
360
+ }
361
+
362
+ // Write updated manifest
363
+ const yamlContent = yaml.dump(manifest, {
364
+ indent: 2,
365
+ lineWidth: -1,
366
+ noRefs: true,
367
+ sortKeys: false,
368
+ });
369
+
370
+ await fs.writeFile(manifestPath, yamlContent, 'utf8');
371
+
372
+ return true;
373
+ }
374
+
375
+ /**
376
+ * List agents in a squad
377
+ * @param {string} squadPath - Path to squad directory
378
+ * @returns {Promise<string[]>} List of agent IDs
379
+ */
380
+ async listAgents(squadPath) {
381
+ const agentsDir = path.join(squadPath, 'agents');
382
+ try {
383
+ const entries = await fs.readdir(agentsDir, { withFileTypes: true });
384
+ return entries
385
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
386
+ .map((entry) => entry.name.replace('.md', ''));
387
+ } catch {
388
+ return [];
389
+ }
390
+ }
391
+
392
+ // ============================================
393
+ // Private Helper Methods
394
+ // ============================================
395
+
396
+ /**
397
+ * Validate component type
398
+ * @private
399
+ */
400
+ _validateComponentType(type) {
401
+ if (!COMPONENT_CONFIG[type]) {
402
+ throw SquadExtenderError.invalidComponentType(type);
403
+ }
404
+ }
405
+
406
+ /**
407
+ * Validate component name (kebab-case)
408
+ * @private
409
+ */
410
+ _validateComponentName(name) {
411
+ // Check for path traversal
412
+ if (name.includes('/') || name.includes('\\') || name.includes('..')) {
413
+ throw SquadExtenderError.pathTraversal(name);
414
+ }
415
+
416
+ // Check kebab-case format
417
+ const kebabCasePattern = /^[a-z][a-z0-9-]*[a-z0-9]$|^[a-z]$/;
418
+ if (!kebabCasePattern.test(name)) {
419
+ throw SquadExtenderError.invalidComponentName(name);
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Validate agent exists in squad
425
+ * @private
426
+ */
427
+ async _validateAgentExists(squadPath, agentId) {
428
+ const agents = await this.listAgents(squadPath);
429
+ if (!agents.includes(agentId)) {
430
+ throw SquadExtenderError.agentNotFound(agentId, agents);
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Build file name for component
436
+ * @private
437
+ */
438
+ _buildFileName(type, name, agentId, extension) {
439
+ // For tasks, prepend agent ID
440
+ if (type === 'task' && agentId) {
441
+ return `${agentId}-${name}${extension}`;
442
+ }
443
+ return `${name}${extension}`;
444
+ }
445
+
446
+ /**
447
+ * Check if directory exists
448
+ * @private
449
+ */
450
+ async _directoryExists(dirPath) {
451
+ try {
452
+ const stats = await fs.stat(dirPath);
453
+ return stats.isDirectory();
454
+ } catch {
455
+ return false;
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Check if file exists
461
+ * @private
462
+ */
463
+ async _fileExists(filePath) {
464
+ try {
465
+ await fs.access(filePath);
466
+ return true;
467
+ } catch {
468
+ return false;
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Ensure directory exists, create if not
474
+ * @private
475
+ */
476
+ async _ensureDirectory(dirPath) {
477
+ await fs.mkdir(dirPath, { recursive: true });
478
+ }
479
+
480
+ /**
481
+ * Create backup of file
482
+ * @private
483
+ */
484
+ async _createBackup(filePath) {
485
+ try {
486
+ const backupPath = `${filePath}.bak`;
487
+ await fs.copyFile(filePath, backupPath);
488
+ if (this.verbose) {
489
+ console.log(`Backup created: ${backupPath}`);
490
+ }
491
+ } catch {
492
+ // File might not exist yet, that's ok
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Load squad manifest
498
+ * @private
499
+ */
500
+ async _loadManifest(squadPath) {
501
+ for (const manifestFile of MANIFEST_FILES) {
502
+ const manifestPath = path.join(squadPath, manifestFile);
503
+ try {
504
+ const content = await fs.readFile(manifestPath, 'utf8');
505
+ const manifest = yaml.load(content);
506
+ return { manifestPath, manifest };
507
+ } catch (error) {
508
+ if (error.code !== 'ENOENT') {
509
+ throw new SquadExtenderError(
510
+ ErrorCodes.MANIFEST_UPDATE_FAILED,
511
+ `Failed to parse ${manifestFile}: ${error.message}`,
512
+ 'Check YAML syntax - use a YAML linter'
513
+ );
514
+ }
515
+ }
516
+ }
517
+
518
+ throw SquadExtenderError.manifestNotFound(squadPath);
519
+ }
520
+
521
+ /**
522
+ * Load and render template
523
+ * @private
524
+ */
525
+ async _renderTemplate(type, context) {
526
+ const config = COMPONENT_CONFIG[type];
527
+ const templatePath = path.join(this.templatesPath, config.template);
528
+
529
+ try {
530
+ // Try to load template from templates path
531
+ const template = await fs.readFile(templatePath, 'utf8');
532
+ return this._interpolateTemplate(template, context);
533
+ } catch (error) {
534
+ if (error.code === 'ENOENT') {
535
+ // Template not found, use default template
536
+ return this._getDefaultTemplate(type, context);
537
+ }
538
+ throw error;
539
+ }
540
+ }
541
+
542
+ /**
543
+ * Interpolate template variables
544
+ * @private
545
+ */
546
+ _interpolateTemplate(template, context) {
547
+ let result = template;
548
+ for (const [key, value] of Object.entries(context)) {
549
+ const placeholder = new RegExp(`\\{\\{${key.toUpperCase()}\\}\\}`, 'g');
550
+ result = result.replace(placeholder, value || '');
551
+ }
552
+ return result;
553
+ }
554
+
555
+ /**
556
+ * Get default template for component type
557
+ * @private
558
+ */
559
+ _getDefaultTemplate(type, context) {
560
+ const templates = {
561
+ agent: `# ${context.componentName}
562
+
563
+ > Agent definition for ${context.squadName}
564
+ > Created: ${context.createdAt}
565
+ ${context.storyId ? `> Story: ${context.storyId}` : ''}
566
+
567
+ ## Description
568
+
569
+ ${context.description}
570
+
571
+ ## Configuration
572
+
573
+ \`\`\`yaml
574
+ agent:
575
+ name: ${context.componentName}
576
+ id: ${context.componentName}
577
+ title: "Agent Title"
578
+ icon: "🤖"
579
+
580
+ persona:
581
+ role: "Describe the agent's role"
582
+ style: "Communication style"
583
+
584
+ commands:
585
+ - help: "Show available commands"
586
+ - exit: "Exit agent mode"
587
+
588
+ dependencies:
589
+ tasks: []
590
+ templates: []
591
+ \`\`\`
592
+ `,
593
+
594
+ task: `---
595
+ task: ${context.componentName}
596
+ responsavel: "@${context.agentId || 'agent'}"
597
+ responsavel_type: Agent
598
+ atomic_layer: Task
599
+ elicit: false
600
+
601
+ Entrada:
602
+ - campo: input_param
603
+ tipo: string
604
+ origem: User Input
605
+ obrigatorio: true
606
+ validacao: "Description of validation"
607
+
608
+ Saida:
609
+ - campo: output_result
610
+ tipo: object
611
+ destino: Return value
612
+ persistido: false
613
+
614
+ Checklist:
615
+ - "[ ] Step 1"
616
+ - "[ ] Step 2"
617
+ - "[ ] Step 3"
618
+ ---
619
+
620
+ # ${context.componentName}
621
+
622
+ ## Description
623
+
624
+ ${context.description}
625
+
626
+ ${context.storyId ? `## Story Reference\n\n- **Story:** ${context.storyId}\n` : ''}
627
+
628
+ ## Execution Steps
629
+
630
+ ### Step 1: Initialize
631
+
632
+ \`\`\`javascript
633
+ // Implementation here
634
+ \`\`\`
635
+
636
+ ### Step 2: Process
637
+
638
+ \`\`\`javascript
639
+ // Implementation here
640
+ \`\`\`
641
+
642
+ ### Step 3: Complete
643
+
644
+ \`\`\`javascript
645
+ // Implementation here
646
+ \`\`\`
647
+
648
+ ## Error Handling
649
+
650
+ \`\`\`yaml
651
+ error: ERROR_CODE
652
+ cause: Description of cause
653
+ resolution: How to resolve
654
+ \`\`\`
655
+
656
+ ## Metadata
657
+
658
+ \`\`\`yaml
659
+ ${context.storyId ? `story: ${context.storyId}` : 'story: N/A'}
660
+ version: 1.0.0
661
+ created: ${context.createdAt}
662
+ author: squad-creator
663
+ \`\`\`
664
+ `,
665
+
666
+ workflow: `# ${context.componentName} Workflow
667
+
668
+ name: ${context.componentName}
669
+ description: ${context.description}
670
+ version: 1.0.0
671
+ ${context.storyId ? `story: ${context.storyId}` : ''}
672
+ created: ${context.createdAt}
673
+
674
+ # Trigger conditions
675
+ triggers:
676
+ - manual
677
+
678
+ # Workflow steps
679
+ steps:
680
+ - id: step-1
681
+ name: "Step 1"
682
+ description: "Description of step 1"
683
+ action: task
684
+ task: task-name
685
+
686
+ - id: step-2
687
+ name: "Step 2"
688
+ description: "Description of step 2"
689
+ action: task
690
+ task: task-name
691
+ depends_on:
692
+ - step-1
693
+
694
+ # Completion criteria
695
+ completion:
696
+ success_message: "Workflow completed successfully"
697
+ failure_message: "Workflow failed"
698
+ `,
699
+
700
+ checklist: `# ${context.componentName} Checklist
701
+
702
+ > ${context.description}
703
+ > Created: ${context.createdAt}
704
+ ${context.storyId ? `> Story: ${context.storyId}` : ''}
705
+
706
+ ## Pre-Conditions
707
+
708
+ - [ ] Pre-condition 1
709
+ - [ ] Pre-condition 2
710
+
711
+ ## Validation Items
712
+
713
+ ### Category 1
714
+
715
+ - [ ] Item 1
716
+ - [ ] Item 2
717
+ - [ ] Item 3
718
+
719
+ ### Category 2
720
+
721
+ - [ ] Item 4
722
+ - [ ] Item 5
723
+
724
+ ## Post-Conditions
725
+
726
+ - [ ] Post-condition 1
727
+ - [ ] Post-condition 2
728
+ `,
729
+
730
+ template: `# ${context.componentName} Template
731
+
732
+ > ${context.description}
733
+ > Created: ${context.createdAt}
734
+ ${context.storyId ? `> Story: ${context.storyId}` : ''}
735
+
736
+ ## Template Content
737
+
738
+ Replace placeholders with actual values:
739
+
740
+ - {{PLACEHOLDER_1}}: Description
741
+ - {{PLACEHOLDER_2}}: Description
742
+
743
+ ---
744
+
745
+ ## Content
746
+
747
+ {{PLACEHOLDER_1}}
748
+
749
+ ### Section 1
750
+
751
+ {{PLACEHOLDER_2}}
752
+
753
+ ---
754
+
755
+ *Template generated by squad-creator*
756
+ `,
757
+
758
+ tool: `/**
759
+ * ${context.componentName} Tool
760
+ *
761
+ * ${context.description}
762
+ *
763
+ * @module ${context.componentName}
764
+ * @version 1.0.0
765
+ ${context.storyId ? `* @see ${context.storyId}` : ''}
766
+ */
767
+
768
+ /**
769
+ * Main function for ${context.componentName}
770
+ * @param {Object} input - Input parameters
771
+ * @returns {Object} Result
772
+ */
773
+ function ${this._toCamelCase(context.componentName)}(input) {
774
+ // Implementation here
775
+ return {
776
+ success: true,
777
+ data: {},
778
+ };
779
+ }
780
+
781
+ module.exports = {
782
+ ${this._toCamelCase(context.componentName)},
783
+ };
784
+ `,
785
+
786
+ script: `#!/usr/bin/env node
787
+
788
+ /**
789
+ * ${context.componentName} Script
790
+ *
791
+ * ${context.description}
792
+ *
793
+ * @module ${context.componentName}
794
+ * @version 1.0.0
795
+ ${context.storyId ? `* @see ${context.storyId}` : ''}
796
+ */
797
+
798
+ const fs = require('fs').promises;
799
+ const path = require('path');
800
+
801
+ /**
802
+ * Main entry point
803
+ * @param {string[]} args - Command line arguments
804
+ */
805
+ async function main(args) {
806
+ console.log('${context.componentName} script started');
807
+
808
+ // Implementation here
809
+
810
+ console.log('${context.componentName} script completed');
811
+ }
812
+
813
+ // Run if called directly
814
+ if (require.main === module) {
815
+ main(process.argv.slice(2))
816
+ .catch((error) => {
817
+ console.error('Error:', error.message);
818
+ process.exit(1);
819
+ });
820
+ }
821
+
822
+ module.exports = { main };
823
+ `,
824
+
825
+ data: `# ${context.componentName} Data
826
+
827
+ name: ${context.componentName}
828
+ description: ${context.description}
829
+ version: 1.0.0
830
+ ${context.storyId ? `story: ${context.storyId}` : ''}
831
+ created: ${context.createdAt}
832
+
833
+ # Data schema
834
+ schema:
835
+ type: object
836
+ properties:
837
+ field1:
838
+ type: string
839
+ description: "Field description"
840
+ field2:
841
+ type: number
842
+ description: "Field description"
843
+
844
+ # Default values
845
+ defaults:
846
+ field1: "default value"
847
+ field2: 0
848
+
849
+ # Data entries
850
+ entries: []
851
+ `,
852
+ };
853
+
854
+ return templates[type] || `# ${context.componentName}\n\n${context.description}`;
855
+ }
856
+
857
+ /**
858
+ * Convert kebab-case to camelCase
859
+ * @private
860
+ */
861
+ _toCamelCase(str) {
862
+ return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
863
+ }
864
+ }
865
+
866
+ module.exports = {
867
+ SquadExtender,
868
+ SquadExtenderError,
869
+ ErrorCodes,
870
+ COMPONENT_CONFIG,
871
+ };