mcp-adr-analysis-server 2.7.24 โ†’ 2.7.26

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 (63) hide show
  1. package/README.md +1 -32
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/index.d.ts +0 -4
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +0 -57
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/tools/bootstrap-validation-loop-tool.d.ts +0 -178
  8. package/dist/src/tools/bootstrap-validation-loop-tool.d.ts.map +1 -1
  9. package/dist/src/tools/bootstrap-validation-loop-tool.js +0 -1580
  10. package/dist/src/tools/bootstrap-validation-loop-tool.js.map +1 -1
  11. package/dist/src/tools/tool-catalog.d.ts.map +1 -1
  12. package/dist/src/tools/tool-catalog.js +2 -22
  13. package/dist/src/tools/tool-catalog.js.map +1 -1
  14. package/dist/src/utils/ai-executor.d.ts +1 -1
  15. package/dist/src/utils/ai-executor.js +1 -1
  16. package/dist/src/utils/config.d.ts +0 -3
  17. package/dist/src/utils/config.d.ts.map +1 -1
  18. package/dist/src/utils/config.js +0 -13
  19. package/dist/src/utils/config.js.map +1 -1
  20. package/dist/src/utils/research-orchestrator.d.ts +0 -28
  21. package/dist/src/utils/research-orchestrator.d.ts.map +1 -1
  22. package/dist/src/utils/research-orchestrator.js +15 -252
  23. package/dist/src/utils/research-orchestrator.js.map +1 -1
  24. package/dist/src/utils/server-context-generator.d.ts.map +1 -1
  25. package/dist/src/utils/server-context-generator.js +0 -1
  26. package/dist/src/utils/server-context-generator.js.map +1 -1
  27. package/package.json +1 -3
  28. package/dist/src/tools/llm-web-search-tool.d.ts +0 -59
  29. package/dist/src/tools/llm-web-search-tool.d.ts.map +0 -1
  30. package/dist/src/tools/llm-web-search-tool.js +0 -165
  31. package/dist/src/tools/llm-web-search-tool.js.map +0 -1
  32. package/dist/src/utils/dag-executor.d.ts +0 -106
  33. package/dist/src/utils/dag-executor.d.ts.map +0 -1
  34. package/dist/src/utils/dag-executor.js +0 -453
  35. package/dist/src/utils/dag-executor.js.map +0 -1
  36. package/dist/src/utils/deployment-task-integration.d.ts +0 -260
  37. package/dist/src/utils/deployment-task-integration.d.ts.map +0 -1
  38. package/dist/src/utils/deployment-task-integration.js +0 -393
  39. package/dist/src/utils/deployment-task-integration.js.map +0 -1
  40. package/dist/src/utils/dynamic-deployment-intelligence.d.ts +0 -117
  41. package/dist/src/utils/dynamic-deployment-intelligence.d.ts.map +0 -1
  42. package/dist/src/utils/dynamic-deployment-intelligence.js +0 -445
  43. package/dist/src/utils/dynamic-deployment-intelligence.js.map +0 -1
  44. package/dist/src/utils/pattern-contribution-helper.d.ts +0 -60
  45. package/dist/src/utils/pattern-contribution-helper.d.ts.map +0 -1
  46. package/dist/src/utils/pattern-contribution-helper.js +0 -308
  47. package/dist/src/utils/pattern-contribution-helper.js.map +0 -1
  48. package/dist/src/utils/pattern-loader.d.ts +0 -183
  49. package/dist/src/utils/pattern-loader.d.ts.map +0 -1
  50. package/dist/src/utils/pattern-loader.js +0 -198
  51. package/dist/src/utils/pattern-loader.js.map +0 -1
  52. package/dist/src/utils/pattern-to-dag-converter.d.ts +0 -62
  53. package/dist/src/utils/pattern-to-dag-converter.d.ts.map +0 -1
  54. package/dist/src/utils/pattern-to-dag-converter.js +0 -265
  55. package/dist/src/utils/pattern-to-dag-converter.js.map +0 -1
  56. package/dist/src/utils/resource-extractor.d.ts +0 -57
  57. package/dist/src/utils/resource-extractor.d.ts.map +0 -1
  58. package/dist/src/utils/resource-extractor.js +0 -323
  59. package/dist/src/utils/resource-extractor.js.map +0 -1
  60. package/dist/src/utils/system-card-manager.d.ts +0 -194
  61. package/dist/src/utils/system-card-manager.d.ts.map +0 -1
  62. package/dist/src/utils/system-card-manager.js +0 -336
  63. package/dist/src/utils/system-card-manager.js.map +0 -1
@@ -13,1586 +13,9 @@
13
13
  * This creates a bidirectional feedback loop where ADRs evolve
14
14
  * based on real-world deployment experience.
15
15
  */
16
- import { promises as fs } from 'fs';
17
- import { exec } from 'node:child_process';
18
- import { promisify } from 'util';
19
- import * as path from 'path';
20
- import { createHash } from 'crypto';
21
- import { McpAdrError } from '../types/index.js';
22
- import { EnhancedLogger } from '../utils/enhanced-logging.js';
23
- import { ResearchOrchestrator } from '../utils/research-orchestrator.js';
24
- import { MemoryEntityManager } from '../utils/memory-entity-manager.js';
25
- import { DynamicDeploymentIntelligence, } from '../utils/dynamic-deployment-intelligence.js';
26
- import generateAdrBootstrapScripts from './adr-bootstrap-validation-tool.js';
27
16
  // NEW: Validated Patterns Integration
28
17
  import { detectPlatforms } from '../utils/platform-detector.js';
29
18
  import { getPattern } from '../utils/validated-pattern-definitions.js';
30
- import { generatePatternResearchReport } from '../utils/pattern-research-utility.js';
31
- // NEW: Tool Context Documentation System
32
- import { ToolContextManager } from '../utils/context-document-manager.js';
33
- // NEW: Hybrid DAG Architecture
34
- import { DAGExecutor } from '../utils/dag-executor.js';
35
- import { PatternToDAGConverter } from '../utils/pattern-to-dag-converter.js';
36
- import { PatternContributionHelper } from '../utils/pattern-contribution-helper.js';
37
- import { PatternLoader } from '../utils/pattern-loader.js';
38
- // NEW: SystemCard for Resource Tracking
39
- import { SystemCardManager } from '../utils/system-card-manager.js';
40
- const execAsync = promisify(exec);
41
- /**
42
- * Bootstrap Validation Loop orchestrator
43
- * Supports dependency injection for improved testability
44
- * @see Issue #310 - Dependency injection for improved testability
45
- */
46
- export class BootstrapValidationLoop {
47
- logger;
48
- projectPath;
49
- adrDirectory;
50
- researchOrchestrator;
51
- memoryManager;
52
- deploymentIntelligence;
53
- executionHistory = [];
54
- maxIterations;
55
- currentIteration = 0;
56
- deploymentPlan = null;
57
- // NEW: Validated Patterns fields
58
- platformDetection = null;
59
- validatedPattern = null;
60
- patternResearchReport = null;
61
- // NEW: Tool Context Documentation
62
- contextManager;
63
- // NEW: Hybrid DAG Architecture
64
- dagExecutor;
65
- patternLoader;
66
- patternConverter;
67
- contributionHelper;
68
- // NEW: SystemCard Resource Tracking
69
- systemCardManager;
70
- /**
71
- * Constructor with optional dependency injection
72
- * @param projectPath - Path to the project
73
- * @param adrDirectory - Path to ADR directory
74
- * @param maxIterations - Maximum validation iterations
75
- * @param deps - Optional dependencies for testing (defaults create real instances)
76
- */
77
- constructor(projectPath, adrDirectory, maxIterations = 5, deps = {}) {
78
- this.logger = deps.logger ?? new EnhancedLogger();
79
- this.projectPath = projectPath;
80
- this.adrDirectory = adrDirectory;
81
- this.maxIterations = maxIterations;
82
- this.researchOrchestrator =
83
- deps.researchOrchestrator ?? new ResearchOrchestrator(projectPath, adrDirectory);
84
- this.memoryManager = deps.memoryManager ?? new MemoryEntityManager();
85
- this.deploymentIntelligence = new DynamicDeploymentIntelligence(projectPath, adrDirectory);
86
- this.contextManager = new ToolContextManager(projectPath);
87
- // Initialize SystemCard for resource tracking (must be before DAGExecutor)
88
- this.systemCardManager = new SystemCardManager(projectPath);
89
- // Initialize DAG architecture components
90
- this.dagExecutor = new DAGExecutor(5, this.systemCardManager); // Max 5 parallel tasks, with resource tracking
91
- this.patternLoader = new PatternLoader();
92
- this.patternConverter = new PatternToDAGConverter();
93
- this.contributionHelper = new PatternContributionHelper();
94
- }
95
- /**
96
- * Initialize the validation loop
97
- */
98
- async initialize() {
99
- await this.memoryManager.initialize();
100
- await this.contextManager.initialize();
101
- this.logger.info('Bootstrap Validation Loop initialized', 'BootstrapValidationLoop', {
102
- projectPath: this.projectPath,
103
- adrDirectory: this.adrDirectory,
104
- maxIterations: this.maxIterations,
105
- });
106
- }
107
- /**
108
- * Execute the complete validation loop
109
- */
110
- async executeLoop(args) {
111
- const { targetEnvironment, autoFix, captureEnvironmentSnapshot, updateAdrsWithLearnings } = args;
112
- this.logger.info('Starting Bootstrap Validation Loop', 'BootstrapValidationLoop', {
113
- targetEnvironment,
114
- autoFix,
115
- maxIterations: this.maxIterations,
116
- });
117
- // STEP 0: Detect platform using Validated Patterns framework
118
- this.logger.info('๐Ÿ” Detecting platform type using Validated Patterns...', 'BootstrapValidationLoop');
119
- this.platformDetection = await detectPlatforms(this.projectPath);
120
- this.logger.info(`๐Ÿ“‹ Platform detection complete (confidence: ${(this.platformDetection.confidence * 100).toFixed(0)}%)`, 'BootstrapValidationLoop', {
121
- primaryPlatform: this.platformDetection.primaryPlatform,
122
- detectedPlatforms: this.platformDetection.detectedPlatforms.map(p => p.type),
123
- evidence: this.platformDetection.evidence.length,
124
- });
125
- // STEP 0.1: Get validated pattern for detected platform
126
- if (this.platformDetection.primaryPlatform) {
127
- this.validatedPattern = getPattern(this.platformDetection.primaryPlatform);
128
- if (this.validatedPattern) {
129
- this.logger.info(`โœ… Loaded validated pattern: ${this.validatedPattern.name}`, 'BootstrapValidationLoop', {
130
- version: this.validatedPattern.version,
131
- lastUpdated: this.validatedPattern.metadata.lastUpdated,
132
- authoritativeSources: this.validatedPattern.authoritativeSources.length,
133
- requiredSources: this.validatedPattern.authoritativeSources.filter(s => s.requiredForDeployment).length,
134
- });
135
- // STEP 0.2: Generate research report for authoritative sources
136
- this.patternResearchReport = generatePatternResearchReport(this.platformDetection.primaryPlatform);
137
- this.logger.info('๐Ÿ“š Generated research report with authoritative source instructions', 'BootstrapValidationLoop');
138
- this.logger.info(`โš ๏ธ IMPORTANT: LLM should query ${this.validatedPattern.authoritativeSources.filter(s => s.requiredForDeployment).length} REQUIRED authoritative sources before deployment`, 'BootstrapValidationLoop');
139
- // Log the research report for LLM to see
140
- this.logger.info('๐Ÿ“– Research Report:\n' + this.patternResearchReport, 'BootstrapValidationLoop');
141
- }
142
- else {
143
- this.logger.warn(`No validated pattern found for ${this.platformDetection.primaryPlatform}, falling back to dynamic intelligence`, 'BootstrapValidationLoop');
144
- }
145
- }
146
- // STEP 0.3: Generate AI-powered deployment plan (fallback or hybrid approach)
147
- this.logger.info('๐Ÿค– Generating dynamic deployment plan with AI + research...', 'BootstrapValidationLoop');
148
- this.deploymentPlan = await this.deploymentIntelligence.generateDeploymentPlan();
149
- this.logger.info(`๐Ÿ“Š Deployment plan generated (confidence: ${this.deploymentPlan.confidence})`, 'BootstrapValidationLoop', {
150
- platforms: this.deploymentPlan.detectedPlatforms,
151
- recommended: this.deploymentPlan.recommendedPlatform,
152
- source: this.deploymentPlan.source,
153
- requiredFiles: this.deploymentPlan.requiredFiles.length,
154
- });
155
- // STEP 0.5: Create Bootstrap ADR for human review
156
- const bootstrapAdrPath = await this.createBootstrapAdr(this.deploymentPlan);
157
- this.logger.info(`๐Ÿ“ Bootstrap ADR created: ${bootstrapAdrPath}`, 'BootstrapValidationLoop');
158
- // STEP 0.6: Save context document for future sessions
159
- const contextDocumentPath = await this.saveBootstrapContext(this.platformDetection, this.validatedPattern, this.deploymentPlan, bootstrapAdrPath);
160
- this.logger.info(`๐Ÿ“„ Context document saved: ${contextDocumentPath}`, 'BootstrapValidationLoop');
161
- this.logger.info('โธ๏ธ WAITING FOR HUMAN APPROVAL - Review the bootstrap ADR before proceeding', 'BootstrapValidationLoop');
162
- // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
163
- // INFRASTRUCTURE LAYER (Hybrid DAG Architecture)
164
- // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
165
- // Execute infrastructure DAG before application deployment iterations
166
- // This runs ONCE and sets up the platform infrastructure
167
- this.logger.info('๐Ÿ—๏ธ Starting Infrastructure Layer (DAG-based execution)...', 'BootstrapValidationLoop');
168
- const infrastructureResult = await this.executeInfrastructureDAG(this.platformDetection);
169
- if (!infrastructureResult.success) {
170
- const failedTasksList = infrastructureResult.failedTasks.join(', ');
171
- this.logger.error(`โŒ Infrastructure Layer failed: ${infrastructureResult.failedTasks.length} tasks failed`, 'BootstrapValidationLoop', undefined, {
172
- failedTasks: infrastructureResult.failedTasks,
173
- skippedTasks: infrastructureResult.skippedTasks,
174
- });
175
- // Infrastructure failure is critical - cannot proceed to application layer
176
- throw new McpAdrError(`Infrastructure deployment failed. Failed tasks: ${failedTasksList}`, 'INFRASTRUCTURE_DEPLOYMENT_ERROR');
177
- }
178
- this.logger.info(`โœ… Infrastructure Layer complete (${infrastructureResult.duration}ms)`, 'BootstrapValidationLoop', {
179
- executedTasks: infrastructureResult.executedTasks.length,
180
- duration: infrastructureResult.duration,
181
- });
182
- // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
183
- // APPLICATION LAYER (Phase-based iteration with auto-fix)
184
- // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
185
- this.logger.info('๐Ÿš€ Starting Application Layer (iterative deployment with auto-fix)...', 'BootstrapValidationLoop');
186
- let success = false;
187
- let finalResult = null;
188
- const adrUpdates = [];
189
- for (let i = 0; i < this.maxIterations; i++) {
190
- this.currentIteration = i + 1;
191
- this.logger.info(`Iteration ${this.currentIteration}/${this.maxIterations}`, 'BootstrapValidationLoop');
192
- // Step 1: Generate bootstrap scripts from current ADRs
193
- const scriptsGenerated = await this.generateBootstrapScripts();
194
- if (!scriptsGenerated) {
195
- throw new McpAdrError('Failed to generate bootstrap scripts', 'SCRIPT_GENERATION_ERROR');
196
- }
197
- // Step 1.5: Detect and handle missing files
198
- this.logger.info('Detecting missing files referenced in ADRs...', 'BootstrapValidationLoop');
199
- const missingFiles = await this.detectMissingFiles();
200
- if (missingFiles.length > 0) {
201
- this.logger.warn(`Found ${missingFiles.length} missing files`, 'BootstrapValidationLoop', {
202
- critical: missingFiles.filter(f => f.severity === 'critical').length,
203
- errors: missingFiles.filter(f => f.severity === 'error').length,
204
- });
205
- // Handle missing files (create templates, add prerequisites)
206
- const missingFileLearnings = await this.handleMissingFiles(missingFiles);
207
- // Log missing file handling results
208
- this.logger.info(`Handled ${missingFileLearnings.length} missing file issues`, 'BootstrapValidationLoop', {
209
- created: missingFileLearnings.filter(l => l.type === 'success').length,
210
- prerequisites: missingFileLearnings.filter(l => l.type === 'prerequisite').length,
211
- });
212
- }
213
- // Step 2: Execute bootstrap.sh with monitoring
214
- const executionResult = await this.executeBootstrapWithMonitoring(targetEnvironment, captureEnvironmentSnapshot);
215
- this.executionHistory.push(executionResult);
216
- // Step 3: Run validation script and capture results
217
- const validationResult = await this.executeValidationScript(executionResult.executionId);
218
- executionResult.validationResults = validationResult.validationResults;
219
- // Step 4: Analyze results and extract learnings
220
- const learnings = await this.extractLearnings(executionResult, validationResult);
221
- executionResult.learnings = learnings;
222
- // Step 5: Store execution in memory system
223
- await this.storeExecutionInMemory(executionResult);
224
- // Check if validation passed
225
- if (validationResult.allPassed) {
226
- this.logger.info('โœ… Validation passed!', 'BootstrapValidationLoop');
227
- success = true;
228
- finalResult = executionResult;
229
- // Update ADRs with successful learnings
230
- if (updateAdrsWithLearnings) {
231
- const updates = await this.generateAdrUpdates(learnings, 'success');
232
- adrUpdates.push(...updates);
233
- }
234
- break;
235
- }
236
- // Step 6: If auto-fix enabled, update scripts based on learnings
237
- if (autoFix) {
238
- this.logger.info('Auto-fixing bootstrap scripts based on failures', 'BootstrapValidationLoop');
239
- const scriptsUpdated = await this.updateBootstrapScriptsFromLearnings(learnings, executionResult);
240
- if (!scriptsUpdated) {
241
- this.logger.warn('Failed to auto-fix scripts, stopping loop', 'BootstrapValidationLoop');
242
- finalResult = executionResult;
243
- break;
244
- }
245
- }
246
- else {
247
- // No auto-fix, stop after first iteration
248
- finalResult = executionResult;
249
- break;
250
- }
251
- finalResult = executionResult;
252
- }
253
- // Generate final ADR update proposals
254
- if (updateAdrsWithLearnings && finalResult) {
255
- const updates = await this.generateAdrUpdates(finalResult.learnings, success ? 'success' : 'failure');
256
- adrUpdates.push(...updates);
257
- }
258
- // Ensure finalResult exists before proceeding
259
- if (!finalResult) {
260
- throw new McpAdrError('No execution result available - bootstrap validation loop failed to execute', 'EXECUTION_ERROR');
261
- }
262
- const result = {
263
- success,
264
- iterations: this.currentIteration,
265
- finalResult,
266
- adrUpdates,
267
- executionHistory: this.executionHistory,
268
- requiresHumanApproval: true,
269
- };
270
- // Only add optional properties if they have values
271
- if (this.deploymentPlan) {
272
- result.deploymentPlan = this.deploymentPlan;
273
- }
274
- if (bootstrapAdrPath) {
275
- result.bootstrapAdrPath = bootstrapAdrPath;
276
- }
277
- if (contextDocumentPath) {
278
- result.contextDocumentPath = contextDocumentPath;
279
- }
280
- return result;
281
- }
282
- /**
283
- * Create Bootstrap ADR with deployment plan and architecture diagrams
284
- */
285
- async createBootstrapAdr(plan) {
286
- try {
287
- const adrContent = `# Bootstrap Deployment Plan
288
-
289
- ## Status
290
- PROPOSED - Awaiting human approval
291
-
292
- ## Context
293
- This ADR documents the automated deployment plan generated for this project.
294
-
295
- **Detected Platforms**: ${plan.detectedPlatforms.join(', ')}
296
- **Recommended Platform**: ${plan.recommendedPlatform}
297
- **Confidence**: ${(plan.confidence * 100).toFixed(1)}%
298
- **Source**: ${plan.source}
299
- **Generated**: ${plan.timestamp}
300
-
301
- ## Architecture Diagram
302
-
303
- ${plan.architectureDiagram}
304
-
305
- ## Required Files
306
-
307
- ${plan.requiredFiles
308
- .map(f => `
309
- ### ${f.path}
310
- - **Purpose**: ${f.purpose}
311
- - **Required**: ${f.required ? 'Yes' : 'No'}
312
- - **Secret**: ${f.isSecret ? 'Yes' : 'No'}
313
- - **Can Auto-Generate**: ${f.canAutoGenerate ? 'Yes' : 'No'}
314
- - **Best Practice**: ${f.currentBestPractice}
315
- ${f.validationCommand ? `- **Validation**: \`${f.validationCommand}\`` : ''}
316
- `)
317
- .join('\n')}
318
-
319
- ## Environment Variables
320
-
321
- ${plan.environmentVariables
322
- .map(e => `
323
- - **${e.name}** (${e.required ? 'Required' : 'Optional'})${e.isSecret ? ' ๐Ÿ”’' : ''}
324
- - ${e.purpose}
325
- ${e.defaultValue ? `- Default: \`${e.defaultValue}\`` : ''}
326
- `)
327
- .join('\n')}
328
-
329
- ## Deployment Steps
330
-
331
- ${plan.deploymentSteps
332
- .map(s => `
333
- ### Step ${s.order}: ${s.title}
334
- **Command**: \`${s.command}\`
335
- **Description**: ${s.description}
336
- **Expected Output**: ${s.expectedOutput}
337
- **Estimated Time**: ${s.estimatedTime}
338
-
339
- **Troubleshooting**:
340
- ${s.troubleshooting.map(t => `- ${t}`).join('\n')}
341
- `)
342
- .join('\n')}
343
-
344
- ## Validation Checks
345
-
346
- ${plan.validationChecks
347
- .map(c => `
348
- - **${c.name}** (${c.severity})
349
- - Command: \`${c.command}\`
350
- - Expected: ${c.expectedResult}
351
- `)
352
- .join('\n')}
353
-
354
- ## Risks
355
-
356
- ${plan.risks
357
- .map(r => `
358
- ### ${r.risk} (${r.severity})
359
- - **Likelihood**: ${r.likelihood}
360
- - **Mitigation**: ${r.mitigation}
361
- `)
362
- .join('\n')}
363
-
364
- ## Prerequisites
365
-
366
- ${plan.prerequisites.map(p => `- ${p}`).join('\n')}
367
-
368
- ## Estimated Duration
369
- ${plan.estimatedDuration}
370
-
371
- ## Research Sources
372
-
373
- ${plan.researchSources.map(s => `- ${s}`).join('\n')}
374
-
375
- ## Decision
376
-
377
- **Status**: โธ๏ธ **AWAITING HUMAN APPROVAL**
378
-
379
- Please review this deployment plan and:
380
- 1. Verify the recommended platform is appropriate
381
- 2. Check that all required files are identified
382
- 3. Review security considerations (environment variables, secrets)
383
- 4. Validate deployment steps make sense for your environment
384
- 5. Approve or provide feedback for modifications
385
-
386
- ## Consequences
387
-
388
- ### Positive
389
- - Automated deployment infrastructure
390
- - Environment-aware configuration
391
- - Validated deployment process
392
-
393
- ### Negative
394
- - Initial setup overhead
395
- - Platform-specific complexity
396
- - Maintenance requirements
397
-
398
- ---
399
- *This ADR was auto-generated by the Bootstrap Validation Loop system using AI-powered deployment intelligence.*
400
- `;
401
- // Ensure ADR directory exists
402
- const adrDir = path.isAbsolute(this.adrDirectory)
403
- ? this.adrDirectory
404
- : path.join(this.projectPath, this.adrDirectory);
405
- await fs.mkdir(adrDir, { recursive: true });
406
- // Create absolute path for ADR file
407
- const adrPath = path.join(adrDir, `bootstrap-deployment-${Date.now()}.md`);
408
- await fs.writeFile(adrPath, adrContent, 'utf-8');
409
- return adrPath;
410
- }
411
- catch (error) {
412
- this.logger.error('Failed to create bootstrap ADR', 'BootstrapValidationLoop', error);
413
- throw error;
414
- }
415
- }
416
- /**
417
- * Save bootstrap context document for future sessions
418
- */
419
- async saveBootstrapContext(platformDetection, validatedPattern, deploymentPlan, bootstrapAdrPath) {
420
- try {
421
- const contextDoc = {
422
- metadata: {
423
- toolName: 'bootstrap_validation_loop',
424
- toolVersion: '1.0.0',
425
- generated: new Date().toISOString(),
426
- projectPath: this.projectPath,
427
- projectName: path.basename(this.projectPath),
428
- status: 'success',
429
- confidence: platformDetection.confidence * 100,
430
- },
431
- quickReference: `
432
- Detected ${platformDetection.primaryPlatform} (${(platformDetection.confidence * 100).toFixed(0)}% confidence).
433
- ${validatedPattern ? `Using validated pattern: ${validatedPattern.name} v${validatedPattern.version}.` : 'Using dynamic AI analysis.'}
434
- Bootstrap ADR: ${bootstrapAdrPath}
435
- `.trim(),
436
- executionSummary: {
437
- status: 'Platform detected and deployment plan generated',
438
- confidence: platformDetection.confidence * 100,
439
- keyFindings: [
440
- `Primary platform: ${platformDetection.primaryPlatform}`,
441
- validatedPattern
442
- ? `Validated pattern: ${validatedPattern.name}`
443
- : 'Dynamic AI deployment plan',
444
- `Required files: ${deploymentPlan.requiredFiles.length}`,
445
- `Deployment steps: ${deploymentPlan.deploymentSteps.length}`,
446
- `Environment variables: ${deploymentPlan.environmentVariables.length}`,
447
- ],
448
- },
449
- detectedContext: {
450
- platform: {
451
- primary: platformDetection.primaryPlatform,
452
- all: platformDetection.detectedPlatforms.map(p => p.type),
453
- confidence: platformDetection.confidence,
454
- evidence: platformDetection.evidence.slice(0, 10).map(e => ({
455
- file: e.file,
456
- indicator: e.indicator,
457
- weight: e.weight,
458
- })),
459
- },
460
- validatedPattern: validatedPattern
461
- ? {
462
- name: validatedPattern.name,
463
- version: validatedPattern.version,
464
- platformType: validatedPattern.platformType,
465
- source: 'typescript-builtin', // Could be enhanced to detect YAML vs TS
466
- sourceHash: this.computePatternHash(validatedPattern),
467
- loadedAt: new Date().toISOString(),
468
- baseRepository: validatedPattern.baseCodeRepository.url,
469
- authoritativeSources: validatedPattern.authoritativeSources.map(s => ({
470
- type: s.type,
471
- url: s.url,
472
- required: s.requiredForDeployment,
473
- purpose: s.purpose,
474
- })),
475
- deploymentPhases: validatedPattern.deploymentPhases.length,
476
- validationChecks: validatedPattern.validationChecks.length,
477
- }
478
- : null,
479
- deploymentPlan: {
480
- recommendedPlatform: deploymentPlan.recommendedPlatform,
481
- confidence: deploymentPlan.confidence,
482
- source: deploymentPlan.source,
483
- requiredFiles: deploymentPlan.requiredFiles.map(f => ({
484
- path: f.path,
485
- purpose: f.purpose,
486
- required: f.required,
487
- })),
488
- environmentVariables: deploymentPlan.environmentVariables.map(e => ({
489
- name: e.name,
490
- required: e.required,
491
- isSecret: e.isSecret,
492
- })),
493
- deploymentSteps: deploymentPlan.deploymentSteps.length,
494
- estimatedDuration: deploymentPlan.estimatedDuration,
495
- },
496
- },
497
- generatedArtifacts: [bootstrapAdrPath, 'bootstrap.sh', 'validate_bootstrap.sh'],
498
- keyDecisions: [
499
- {
500
- decision: `Use ${platformDetection.primaryPlatform} as deployment platform`,
501
- rationale: `Detected with ${(platformDetection.confidence * 100).toFixed(0)}% confidence based on project structure and configuration files`,
502
- alternatives: platformDetection.detectedPlatforms
503
- .filter(p => p.type !== platformDetection.primaryPlatform)
504
- .map(p => `${p.type} (${(p.confidence * 100).toFixed(0)}% confidence)`)
505
- .slice(0, 3),
506
- },
507
- ],
508
- learnings: {
509
- successes: ['Platform detection completed successfully'],
510
- failures: [],
511
- recommendations: [
512
- 'Review bootstrap ADR before proceeding with deployment',
513
- validatedPattern
514
- ? `Consult authoritative sources for ${validatedPattern.name}`
515
- : 'Validate deployment plan with team',
516
- ],
517
- environmentSpecific: [],
518
- },
519
- relatedDocuments: {
520
- adrs: [bootstrapAdrPath],
521
- configs: deploymentPlan.requiredFiles.map(f => f.path),
522
- otherContexts: [],
523
- },
524
- rawData: {
525
- // Full validated pattern snapshot for reproducibility
526
- validatedPatternSnapshot: validatedPattern
527
- ? {
528
- source: 'typescript-builtin', // Could be enhanced to detect YAML vs TS
529
- hash: this.computePatternHash(validatedPattern),
530
- timestamp: new Date().toISOString(),
531
- definition: validatedPattern, // FULL pattern object with all commands, checks, templates
532
- }
533
- : null,
534
- // Deployment plan details
535
- deploymentPlan: {
536
- recommendedPlatform: deploymentPlan.recommendedPlatform,
537
- confidence: deploymentPlan.confidence,
538
- source: deploymentPlan.source,
539
- requiredFiles: deploymentPlan.requiredFiles,
540
- environmentVariables: deploymentPlan.environmentVariables,
541
- deploymentSteps: deploymentPlan.deploymentSteps,
542
- estimatedDuration: deploymentPlan.estimatedDuration,
543
- },
544
- },
545
- };
546
- // Add validated pattern details if available
547
- if (validatedPattern) {
548
- contextDoc.keyDecisions.push({
549
- decision: `Use ${validatedPattern.name} validated pattern`,
550
- rationale: `Best practice pattern for ${platformDetection.primaryPlatform} deployments. Provides proven deployment workflow and authoritative sources.`,
551
- alternatives: ['Custom deployment plan', 'Dynamic AI-generated plan'],
552
- });
553
- }
554
- const contextPath = await this.contextManager.saveContext('bootstrap', contextDoc);
555
- return contextPath;
556
- }
557
- catch (error) {
558
- this.logger.error('Failed to save bootstrap context', 'BootstrapValidationLoop', error);
559
- throw error;
560
- }
561
- }
562
- /**
563
- * Generate bootstrap scripts from validated pattern (NEW)
564
- */
565
- async generateBootstrapScriptsFromPattern() {
566
- if (!this.validatedPattern) {
567
- return false;
568
- }
569
- try {
570
- this.logger.info(`Generating bootstrap scripts from validated pattern: ${this.validatedPattern.name}`, 'BootstrapValidationLoop');
571
- // Generate bootstrap.sh from pattern's deployment phases
572
- let bootstrapScript = `#!/bin/bash
573
- # Bootstrap script generated from ${this.validatedPattern.name} v${this.validatedPattern.version}
574
- # Pattern source: ${this.validatedPattern.metadata.source}
575
- # Last updated: ${this.validatedPattern.metadata.lastUpdated}
576
- # Generated: ${new Date().toISOString()}
577
-
578
- set -e # Exit on error
579
- set -u # Exit on undefined variable
580
-
581
- echo "========================================"
582
- echo "Bootstrap Deployment - ${this.validatedPattern.platformType}"
583
- echo "Pattern: ${this.validatedPattern.name}"
584
- echo "========================================"
585
- echo ""
586
-
587
- `;
588
- // Add each deployment phase
589
- for (const phase of this.validatedPattern.deploymentPhases) {
590
- bootstrapScript += `
591
- # ============================================================================
592
- # Phase ${phase.order}: ${phase.name}
593
- # ${phase.description}
594
- # Estimated duration: ${phase.estimatedDuration}
595
- # ============================================================================
596
-
597
- echo "Starting Phase ${phase.order}: ${phase.name}"
598
-
599
- `;
600
- // Add commands for this phase
601
- for (const command of phase.commands) {
602
- bootstrapScript += `# ${command.description}\n`;
603
- bootstrapScript += `echo " โ†’ ${command.description}"\n`;
604
- bootstrapScript += `${command.command}\n\n`;
605
- }
606
- bootstrapScript += `echo "โœ“ Phase ${phase.order} complete"\necho ""\n`;
607
- }
608
- bootstrapScript += `
609
- echo "========================================"
610
- echo "โœ… Bootstrap deployment complete!"
611
- echo "========================================"
612
- `;
613
- // Generate validate_bootstrap.sh from pattern's validation checks
614
- let validationScript = `#!/bin/bash
615
- # Validation script generated from ${this.validatedPattern.name}
616
- # Generated: ${new Date().toISOString()}
617
-
618
- set -e
619
-
620
- echo "========================================"
621
- echo "Bootstrap Validation"
622
- echo "========================================"
623
- echo ""
624
-
625
- FAILED_CHECKS=0
626
-
627
- `;
628
- for (const check of this.validatedPattern.validationChecks) {
629
- validationScript += `
630
- # ${check.name} (${check.severity})
631
- echo "Checking: ${check.name}"
632
- if ${check.command}; then
633
- echo " โœ… PASSED: ${check.name}"
634
- else
635
- echo " โŒ FAILED: ${check.name}"
636
- echo " ${check.failureMessage}"
637
- echo " Remediation steps:"
638
- ${check.remediationSteps.map(step => ` echo " - ${step}"`).join('\n')}
639
- FAILED_CHECKS=$((FAILED_CHECKS + 1))
640
- fi
641
- echo ""
642
-
643
- `;
644
- }
645
- validationScript += `
646
- if [ $FAILED_CHECKS -eq 0 ]; then
647
- echo "========================================"
648
- echo "โœ… All validation checks passed!"
649
- echo "========================================"
650
- exit 0
651
- else
652
- echo "========================================"
653
- echo "โŒ $FAILED_CHECKS validation check(s) failed"
654
- echo "========================================"
655
- exit 1
656
- fi
657
- `;
658
- // Write scripts
659
- const bootstrapPath = path.join(this.projectPath, 'bootstrap.sh');
660
- await fs.writeFile(bootstrapPath, bootstrapScript, { mode: 0o755 });
661
- const validationPath = path.join(this.projectPath, 'validate_bootstrap.sh');
662
- await fs.writeFile(validationPath, validationScript, { mode: 0o755 });
663
- this.logger.info('Bootstrap scripts generated from validated pattern', 'BootstrapValidationLoop', {
664
- bootstrapPath,
665
- validationPath,
666
- phases: this.validatedPattern.deploymentPhases.length,
667
- validationChecks: this.validatedPattern.validationChecks.length,
668
- });
669
- return true;
670
- }
671
- catch (error) {
672
- this.logger.error('Failed to generate scripts from validated pattern', 'BootstrapValidationLoop', error);
673
- return false;
674
- }
675
- }
676
- /**
677
- * Generate bootstrap scripts from current ADRs (FALLBACK)
678
- */
679
- async generateBootstrapScripts() {
680
- // NEW: Try validated pattern first if available
681
- if (this.validatedPattern) {
682
- this.logger.info('๐ŸŽฏ Using validated pattern to generate bootstrap scripts', 'BootstrapValidationLoop');
683
- const patternSuccess = await this.generateBootstrapScriptsFromPattern();
684
- if (patternSuccess) {
685
- return true;
686
- }
687
- this.logger.warn('Failed to generate from validated pattern, falling back to ADR-based generation', 'BootstrapValidationLoop');
688
- }
689
- try {
690
- this.logger.info('Generating bootstrap scripts from ADRs', 'BootstrapValidationLoop');
691
- const result = await generateAdrBootstrapScripts({
692
- projectPath: this.projectPath,
693
- adrDirectory: this.adrDirectory,
694
- outputPath: this.projectPath,
695
- scriptType: 'both',
696
- includeTests: true,
697
- includeDeployment: true,
698
- enableTreeSitterAnalysis: true,
699
- });
700
- // Validate result structure
701
- if (!result?.content?.[0]?.text) {
702
- throw new McpAdrError('Invalid response from bootstrap script generator - missing content', 'INVALID_RESPONSE');
703
- }
704
- // Extract and validate scripts from result
705
- let response;
706
- try {
707
- response = JSON.parse(result.content[0].text);
708
- }
709
- catch (parseError) {
710
- this.logger.error('Failed to parse bootstrap script response as JSON', 'BootstrapValidationLoop', parseError);
711
- throw new McpAdrError('Malformed JSON response from script generator', 'PARSE_ERROR');
712
- }
713
- // Validate response structure and required properties
714
- if (!response?.scripts) {
715
- throw new McpAdrError('Invalid response structure - missing scripts property', 'INVALID_RESPONSE');
716
- }
717
- if (typeof response.scripts.bootstrap !== 'string' || !response.scripts.bootstrap.trim()) {
718
- throw new McpAdrError('Invalid or empty bootstrap script in response', 'INVALID_SCRIPT');
719
- }
720
- if (typeof response.scripts.validation !== 'string' || !response.scripts.validation.trim()) {
721
- throw new McpAdrError('Invalid or empty validation script in response', 'INVALID_SCRIPT');
722
- }
723
- // Write bootstrap.sh
724
- const bootstrapPath = path.join(this.projectPath, 'bootstrap.sh');
725
- await fs.writeFile(bootstrapPath, response.scripts.bootstrap, { mode: 0o755 });
726
- // Write validate_bootstrap.sh
727
- const validationPath = path.join(this.projectPath, 'validate_bootstrap.sh');
728
- await fs.writeFile(validationPath, response.scripts.validation, { mode: 0o755 });
729
- this.logger.info('Bootstrap scripts generated successfully', 'BootstrapValidationLoop', {
730
- bootstrapPath,
731
- validationPath,
732
- });
733
- return true;
734
- }
735
- catch (error) {
736
- this.logger.error('Failed to generate bootstrap scripts', 'BootstrapValidationLoop', error);
737
- return false;
738
- }
739
- }
740
- /**
741
- * Execute bootstrap.sh with environment monitoring
742
- */
743
- async executeBootstrapWithMonitoring(targetEnvironment, captureSnapshot) {
744
- const executionId = `bootstrap_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
745
- const timestamp = new Date().toISOString();
746
- const startTime = Date.now();
747
- this.logger.info('Executing bootstrap.sh with monitoring', 'BootstrapValidationLoop', {
748
- executionId,
749
- targetEnvironment,
750
- });
751
- let environmentSnapshot = {};
752
- // Capture pre-execution environment snapshot
753
- if (captureSnapshot) {
754
- environmentSnapshot = await this.captureEnvironmentSnapshot();
755
- }
756
- // Execute bootstrap.sh
757
- const bootstrapPath = path.join(this.projectPath, 'bootstrap.sh');
758
- let exitCode = 0;
759
- let stdout = '';
760
- let stderr = '';
761
- try {
762
- const result = await execAsync(`bash "${bootstrapPath}"`, {
763
- cwd: this.projectPath,
764
- timeout: 300000, // 5 minute timeout
765
- maxBuffer: 10 * 1024 * 1024, // 10MB buffer
766
- });
767
- stdout = result.stdout;
768
- stderr = result.stderr;
769
- }
770
- catch (error) {
771
- exitCode = error.code || 1;
772
- stdout = error.stdout || '';
773
- stderr = error.stderr || error.message || '';
774
- this.logger.warn('Bootstrap execution failed', 'BootstrapValidationLoop', {
775
- exitCode,
776
- stderr: stderr.substring(0, 500),
777
- });
778
- }
779
- const duration = Date.now() - startTime;
780
- return {
781
- executionId,
782
- timestamp,
783
- success: exitCode === 0,
784
- duration,
785
- exitCode,
786
- stdout,
787
- stderr,
788
- environmentSnapshot,
789
- learnings: [], // Will be populated later
790
- };
791
- }
792
- /**
793
- * Execute validate_bootstrap.sh and analyze results
794
- */
795
- async executeValidationScript(executionId) {
796
- this.logger.info('Executing validate_bootstrap.sh', 'BootstrapValidationLoop', { executionId });
797
- const validationPath = path.join(this.projectPath, 'validate_bootstrap.sh');
798
- const validationResults = [];
799
- let allPassed = true;
800
- try {
801
- const result = await execAsync(`bash "${validationPath}"`, {
802
- cwd: this.projectPath,
803
- timeout: 180000, // 3 minute timeout
804
- });
805
- // Parse validation output
806
- // This is a simplified parser - actual implementation would be more sophisticated
807
- const lines = result.stdout.split('\n');
808
- for (const line of lines) {
809
- if (line.includes('PASSED') || line.includes('FAILED')) {
810
- const passed = line.includes('PASSED');
811
- if (!passed)
812
- allPassed = false;
813
- validationResults.push({
814
- checkId: `validation_${validationResults.length}`,
815
- adrId: 'unknown', // Would be parsed from output
816
- requirement: line.trim(),
817
- passed,
818
- actualState: passed ? 'compliant' : 'non-compliant',
819
- expectedState: 'compliant',
820
- confidence: 0.9,
821
- evidence: [line],
822
- });
823
- }
824
- }
825
- }
826
- catch (error) {
827
- allPassed = false;
828
- this.logger.error('Validation script failed', 'BootstrapValidationLoop', error);
829
- // Record the failure
830
- validationResults.push({
831
- checkId: 'validation_execution',
832
- adrId: 'system',
833
- requirement: 'Execute validation script',
834
- passed: false,
835
- actualState: 'failed',
836
- expectedState: 'success',
837
- confidence: 1.0,
838
- evidence: [error.message],
839
- });
840
- }
841
- return { allPassed, validationResults };
842
- }
843
- /**
844
- * Extract learnings from execution results
845
- */
846
- async extractLearnings(executionResult, validationResult) {
847
- const learnings = [];
848
- // Analyze failures
849
- for (const validation of validationResult.validationResults) {
850
- if (!validation.passed) {
851
- learnings.push({
852
- type: 'failure',
853
- category: 'infrastructure',
854
- description: `Validation failed: ${validation.requirement}`,
855
- adrReference: validation.adrId,
856
- severity: 'error',
857
- recommendation: await this.generateRecommendation(validation, executionResult),
858
- evidence: validation.evidence,
859
- environmentSpecific: true,
860
- timestamp: new Date().toISOString(),
861
- });
862
- }
863
- }
864
- // Analyze stderr for issues
865
- if (executionResult.stderr) {
866
- const errorLines = executionResult.stderr.split('\n').filter(line => line.trim());
867
- for (const errorLine of errorLines) {
868
- if (errorLine.toLowerCase().includes('error') ||
869
- errorLine.toLowerCase().includes('failed')) {
870
- learnings.push({
871
- type: 'failure',
872
- category: 'configuration',
873
- description: errorLine.substring(0, 200),
874
- severity: 'error',
875
- recommendation: 'Review error message and adjust bootstrap script',
876
- evidence: [errorLine],
877
- environmentSpecific: true,
878
- timestamp: new Date().toISOString(),
879
- });
880
- }
881
- }
882
- }
883
- // Use ResearchOrchestrator to understand environment state
884
- try {
885
- const envCheck = await this.researchOrchestrator.answerResearchQuestion('What is the current state of the deployment environment? List all running services.');
886
- if (envCheck.confidence > 0.7) {
887
- learnings.push({
888
- type: 'success',
889
- category: 'infrastructure',
890
- description: `Environment state verified: ${envCheck.answer?.substring(0, 200)}`,
891
- severity: 'info',
892
- recommendation: 'Document current environment state in ADRs',
893
- evidence: [envCheck.answer || 'Environment check completed'],
894
- environmentSpecific: true,
895
- timestamp: new Date().toISOString(),
896
- });
897
- }
898
- }
899
- catch (error) {
900
- this.logger.warn('Failed to check environment state', 'BootstrapValidationLoop', error);
901
- }
902
- return learnings;
903
- }
904
- /**
905
- * Generate recommendation for a failed validation
906
- */
907
- async generateRecommendation(validation, _executionResult) {
908
- // Use ResearchOrchestrator to generate context-aware recommendation
909
- try {
910
- const question = `How can we fix this deployment issue: ${validation.requirement}?
911
- Current state: ${validation.actualState}
912
- Expected state: ${validation.expectedState}
913
- Evidence: ${validation.evidence.join(', ')}`;
914
- const answer = await this.researchOrchestrator.answerResearchQuestion(question);
915
- if (answer.confidence > 0.6 && answer.answer) {
916
- return answer.answer.substring(0, 500);
917
- }
918
- }
919
- catch (error) {
920
- this.logger.warn('Failed to generate AI recommendation', 'BootstrapValidationLoop', error);
921
- }
922
- return 'Review validation failure and adjust bootstrap script accordingly';
923
- }
924
- /**
925
- * Update bootstrap scripts based on learnings
926
- */
927
- async updateBootstrapScriptsFromLearnings(learnings, _executionResult) {
928
- try {
929
- const bootstrapPath = path.join(this.projectPath, 'bootstrap.sh');
930
- let bootstrapContent = await fs.readFile(bootstrapPath, 'utf-8');
931
- // Apply fixes based on learnings
932
- for (const learning of learnings) {
933
- if (learning.type === 'failure' && learning.category === 'infrastructure') {
934
- // Add prerequisite checks
935
- if (learning.description.toLowerCase().includes('postgres')) {
936
- const postgresCheck = `
937
- # Auto-fix: Added PostgreSQL startup check
938
- if ! pgrep -x "postgres" > /dev/null; then
939
- echo "Starting PostgreSQL..."
940
- systemctl start postgresql || brew services start postgresql
941
- sleep 3
942
- fi
943
- `;
944
- bootstrapContent = bootstrapContent.replace('# Phase 2: Build and Prepare', postgresCheck + '\n# Phase 2: Build and Prepare');
945
- }
946
- // Add Docker checks
947
- if (learning.description.toLowerCase().includes('docker')) {
948
- const dockerCheck = `
949
- # Auto-fix: Added Docker check
950
- if ! docker ps > /dev/null 2>&1; then
951
- echo "Docker is not running. Please start Docker and retry."
952
- exit 1
953
- fi
954
- `;
955
- bootstrapContent = dockerCheck + '\n' + bootstrapContent;
956
- }
957
- }
958
- }
959
- // Write updated script
960
- await fs.writeFile(bootstrapPath, bootstrapContent, { mode: 0o755 });
961
- this.logger.info('Bootstrap script updated with auto-fixes', 'BootstrapValidationLoop', {
962
- fixesApplied: learnings.filter(l => l.type === 'failure').length,
963
- });
964
- return true;
965
- }
966
- catch (error) {
967
- this.logger.error('Failed to update bootstrap scripts', 'BootstrapValidationLoop', error);
968
- return false;
969
- }
970
- }
971
- /**
972
- * Generate ADR update proposals based on learnings
973
- */
974
- async generateAdrUpdates(learnings, outcome) {
975
- const proposals = [];
976
- const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js');
977
- const adrs = await discoverAdrsInDirectory(this.adrDirectory, this.projectPath, {
978
- includeContent: true,
979
- includeTimeline: false,
980
- });
981
- for (const adr of adrs.adrs) {
982
- // Find learnings related to this ADR
983
- const relatedLearnings = learnings.filter(l => l.adrReference === adr.filename || adr.content?.includes(l.description.substring(0, 50)));
984
- if (relatedLearnings.length === 0)
985
- continue;
986
- // Generate update content
987
- const updateContent = this.generateDeploymentExperienceSection(relatedLearnings, outcome);
988
- proposals.push({
989
- adrPath: path.join(this.adrDirectory, adr.filename || 'unknown.md'),
990
- adrTitle: adr.title || 'Unknown ADR',
991
- updateType: 'append',
992
- sectionToUpdate: 'Deployment Experience',
993
- proposedContent: updateContent,
994
- learnings: relatedLearnings,
995
- confidence: 0.85,
996
- requiresReview: outcome === 'failure' && relatedLearnings.some(l => l.severity === 'critical'),
997
- });
998
- }
999
- return proposals;
1000
- }
1001
- /**
1002
- * Generate deployment experience section content
1003
- */
1004
- generateDeploymentExperienceSection(learnings, outcome) {
1005
- const timestamp = new Date().toISOString().split('T')[0];
1006
- let content = `\n## Deployment Experience\n\n`;
1007
- content += `**Last Updated**: ${timestamp}\n`;
1008
- content += `**Deployment Outcome**: ${outcome === 'success' ? 'โœ… Successful' : 'โš ๏ธ Issues Encountered'}\n\n`;
1009
- // Group learnings by category
1010
- const byCategory = {};
1011
- for (const learning of learnings) {
1012
- if (!byCategory[learning.category]) {
1013
- byCategory[learning.category] = [];
1014
- }
1015
- byCategory[learning.category].push(learning);
1016
- }
1017
- for (const [category, categoryLearnings] of Object.entries(byCategory)) {
1018
- content += `### ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
1019
- for (const learning of categoryLearnings) {
1020
- const icon = learning.type === 'success' ? 'โœ…' : learning.type === 'failure' ? 'โŒ' : 'โ„น๏ธ';
1021
- content += `${icon} **${learning.description}**\n`;
1022
- content += ` - Severity: ${learning.severity}\n`;
1023
- content += ` - Recommendation: ${learning.recommendation}\n`;
1024
- if (learning.environmentSpecific) {
1025
- content += ` - *Environment-specific consideration*\n`;
1026
- }
1027
- content += `\n`;
1028
- }
1029
- }
1030
- return content;
1031
- }
1032
- /**
1033
- * Detect missing files that might break bootstrap
1034
- */
1035
- async detectMissingFiles() {
1036
- const missingFiles = [];
1037
- try {
1038
- // Parse .gitignore patterns
1039
- const gitignorePatterns = await this.parseGitignore();
1040
- // Extract file references from ADRs
1041
- const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js');
1042
- const adrs = await discoverAdrsInDirectory(this.adrDirectory, this.projectPath, {
1043
- includeContent: true,
1044
- includeTimeline: false,
1045
- });
1046
- const fileReferences = await this.extractFileReferencesFromAdrs(adrs.adrs);
1047
- // Check each referenced file
1048
- for (const [filePath, referencedBy] of fileReferences.entries()) {
1049
- const fullPath = path.join(this.projectPath, filePath);
1050
- try {
1051
- await fs.access(fullPath);
1052
- // File exists, continue
1053
- }
1054
- catch (error) {
1055
- // Only treat as missing if it's a "file not found" error
1056
- // Other errors (permissions, etc.) should be logged but not treated as missing
1057
- if (error.code === 'ENOENT') {
1058
- const isIgnored = this.isFileIgnored(filePath, gitignorePatterns);
1059
- const fileInfo = this.analyzeMissingFile(filePath, referencedBy, isIgnored);
1060
- missingFiles.push(fileInfo);
1061
- }
1062
- else {
1063
- this.logger.warn(`Error accessing file ${filePath}: ${error.message}`, 'BootstrapValidationLoop');
1064
- }
1065
- }
1066
- }
1067
- // Check for common missing files
1068
- const commonFiles = [
1069
- { path: '.env', type: 'env', critical: true },
1070
- { path: '.env.example', type: 'env', critical: false },
1071
- { path: 'config/database.yml', type: 'config', critical: true },
1072
- { path: 'config/secrets.yml', type: 'secret', critical: true },
1073
- { path: '.npmrc', type: 'config', critical: false },
1074
- { path: 'tsconfig.json', type: 'build', critical: false },
1075
- ];
1076
- for (const common of commonFiles) {
1077
- const fullPath = path.join(this.projectPath, common.path);
1078
- try {
1079
- await fs.access(fullPath);
1080
- }
1081
- catch (error) {
1082
- // Only treat as missing if it's a "file not found" error
1083
- if (error.code === 'ENOENT') {
1084
- const isIgnored = this.isFileIgnored(common.path, gitignorePatterns);
1085
- if (isIgnored || common.critical) {
1086
- missingFiles.push({
1087
- filePath: common.path,
1088
- fileType: common.type,
1089
- isIgnored,
1090
- requiredBy: ['bootstrap-process'],
1091
- severity: common.critical ? 'critical' : 'warning',
1092
- canCreateTemplate: true,
1093
- templateContent: this.generateTemplateContent(common.path, common.type),
1094
- recommendation: isIgnored
1095
- ? `Create ${common.path} from template (file is gitignored)`
1096
- : `Consider creating ${common.path} for better configuration`,
1097
- });
1098
- }
1099
- }
1100
- else {
1101
- this.logger.warn(`Error accessing common file ${common.path}: ${error.message}`, 'BootstrapValidationLoop');
1102
- }
1103
- }
1104
- }
1105
- }
1106
- catch (error) {
1107
- this.logger.warn('Failed to detect missing files', 'BootstrapValidationLoop', error);
1108
- }
1109
- return missingFiles;
1110
- }
1111
- /**
1112
- * Parse .gitignore file patterns
1113
- */
1114
- async parseGitignore() {
1115
- const gitignorePath = path.join(this.projectPath, '.gitignore');
1116
- const patterns = [];
1117
- try {
1118
- const content = await fs.readFile(gitignorePath, 'utf-8');
1119
- const lines = content.split('\n');
1120
- for (const line of lines) {
1121
- const trimmed = line.trim();
1122
- // Skip comments and empty lines
1123
- if (trimmed && !trimmed.startsWith('#')) {
1124
- patterns.push(trimmed);
1125
- }
1126
- }
1127
- }
1128
- catch {
1129
- // .gitignore doesn't exist or can't be read
1130
- this.logger.info('No .gitignore file found', 'BootstrapValidationLoop');
1131
- }
1132
- return patterns;
1133
- }
1134
- /**
1135
- * Check if a file path matches gitignore patterns
1136
- */
1137
- isFileIgnored(filePath, patterns) {
1138
- for (const pattern of patterns) {
1139
- // Simple pattern matching (could be enhanced with minimatch)
1140
- if (pattern.includes('*')) {
1141
- // Wildcard pattern
1142
- const regex = new RegExp(pattern.replace(/\*/g, '.*').replace(/\?/g, '.'));
1143
- if (regex.test(filePath))
1144
- return true;
1145
- }
1146
- else {
1147
- // Exact match or directory match
1148
- if (filePath === pattern || filePath.startsWith(pattern + '/')) {
1149
- return true;
1150
- }
1151
- }
1152
- }
1153
- return false;
1154
- }
1155
- /**
1156
- * Extract file references from ADR content
1157
- */
1158
- async extractFileReferencesFromAdrs(adrs) {
1159
- const references = new Map();
1160
- // Common file path patterns
1161
- const filePatterns = [
1162
- /(?:config|src|lib|dist)\/[a-zA-Z0-9_\-/.]+\.[a-zA-Z0-9]+/g,
1163
- /\.[a-zA-Z0-9_-]+(?:\.example)?\.(?:json|yml|yaml|env|conf|config)/g,
1164
- /`([^`]+\.[a-zA-Z0-9]+)`/g, // Files in backticks
1165
- ];
1166
- for (const adr of adrs) {
1167
- if (!adr.content)
1168
- continue;
1169
- for (const pattern of filePatterns) {
1170
- const matches = adr.content.matchAll(pattern);
1171
- for (const match of matches) {
1172
- const filePath = match[1] || match[0];
1173
- if (!references.has(filePath)) {
1174
- references.set(filePath, []);
1175
- }
1176
- references.get(filePath).push(adr.title || adr.filename || 'Unknown ADR');
1177
- }
1178
- }
1179
- }
1180
- return references;
1181
- }
1182
- /**
1183
- * Analyze a missing file and provide recommendations
1184
- */
1185
- analyzeMissingFile(filePath, referencedBy, isIgnored) {
1186
- const ext = path.extname(filePath).toLowerCase();
1187
- let fileType = 'unknown';
1188
- let severity = 'warning';
1189
- let canCreateTemplate = false;
1190
- // Determine file type and severity
1191
- if (filePath.includes('.env') || ext === '.env') {
1192
- fileType = 'env';
1193
- severity = isIgnored ? 'critical' : 'error';
1194
- canCreateTemplate = true;
1195
- }
1196
- else if (['.json', '.yml', '.yaml', '.conf'].includes(ext)) {
1197
- fileType = 'config';
1198
- severity = 'error';
1199
- canCreateTemplate = true;
1200
- }
1201
- else if (['tsconfig.json', 'webpack.config.js', 'vite.config.ts'].includes(path.basename(filePath))) {
1202
- fileType = 'build';
1203
- severity = 'warning';
1204
- canCreateTemplate = true;
1205
- }
1206
- else if (filePath.includes('secret') || filePath.includes('credential')) {
1207
- fileType = 'secret';
1208
- severity = 'critical';
1209
- canCreateTemplate = false; // Never create secrets automatically
1210
- }
1211
- const templateContent = canCreateTemplate
1212
- ? this.generateTemplateContent(filePath, fileType)
1213
- : undefined;
1214
- return {
1215
- filePath,
1216
- fileType,
1217
- isIgnored,
1218
- requiredBy: referencedBy,
1219
- severity,
1220
- canCreateTemplate,
1221
- templateContent,
1222
- recommendation: this.generateMissingFileRecommendation(filePath, fileType, isIgnored, referencedBy),
1223
- };
1224
- }
1225
- /**
1226
- * Generate template content for missing files
1227
- */
1228
- generateTemplateContent(filePath, _fileType) {
1229
- const fileName = path.basename(filePath);
1230
- if (fileName === '.env' || fileName === '.env.example') {
1231
- return `# Environment Configuration
1232
- # Generated by Bootstrap Validation Loop
1233
- # IMPORTANT: Update these values before deployment
1234
-
1235
- # Application
1236
- NODE_ENV=development
1237
- PORT=3000
1238
-
1239
- # Database
1240
- DATABASE_URL=postgresql://localhost:5432/myapp
1241
- DATABASE_POOL_SIZE=10
1242
-
1243
- # Security
1244
- JWT_SECRET=CHANGE_ME_IN_PRODUCTION
1245
- SESSION_SECRET=CHANGE_ME_IN_PRODUCTION
1246
-
1247
- # External Services
1248
- API_KEY=your_api_key_here
1249
-
1250
- # Logging
1251
- LOG_LEVEL=info
1252
- `;
1253
- }
1254
- if (fileName.endsWith('.json')) {
1255
- return `{
1256
- "// NOTE": "Generated template - customize for your project",
1257
- "name": "project-config",
1258
- "version": "1.0.0",
1259
- "description": "Generated configuration file"
1260
- }
1261
- `;
1262
- }
1263
- if (fileName.endsWith('.yml') || fileName.endsWith('.yaml')) {
1264
- return `# Generated template - customize for your project
1265
- # YAML Configuration
1266
-
1267
- default:
1268
- setting: value
1269
- enabled: false
1270
-
1271
- development:
1272
- debug: true
1273
-
1274
- production:
1275
- debug: false
1276
- `;
1277
- }
1278
- return `# Generated template for ${fileName}
1279
- # Please customize this file for your project
1280
- `;
1281
- }
1282
- /**
1283
- * Generate recommendation for missing file
1284
- */
1285
- generateMissingFileRecommendation(filePath, fileType, isIgnored, referencedBy) {
1286
- let recommendation = `Missing file: ${filePath}\n`;
1287
- recommendation += `Referenced by: ${referencedBy.join(', ')}\n`;
1288
- if (isIgnored) {
1289
- recommendation += `โš ๏ธ File is gitignored - this is intentional for security\n`;
1290
- }
1291
- switch (fileType) {
1292
- case 'env':
1293
- recommendation += isIgnored
1294
- ? `ACTION: Create ${filePath} from template or .env.example\n`
1295
- : `ACTION: Add ${filePath} to .gitignore and create from template\n`;
1296
- break;
1297
- case 'secret':
1298
- recommendation += `โ›” CRITICAL: Never commit secrets to version control\n`;
1299
- recommendation += `ACTION: Create ${filePath} manually with secure values\n`;
1300
- break;
1301
- case 'config':
1302
- recommendation += `ACTION: Create configuration file from template\n`;
1303
- break;
1304
- case 'build':
1305
- recommendation += `ACTION: Generate build configuration or copy from similar project\n`;
1306
- break;
1307
- default:
1308
- recommendation += `ACTION: Create file or update ADRs to remove reference\n`;
1309
- }
1310
- return recommendation;
1311
- }
1312
- /**
1313
- * Handle missing files - create templates or add to bootstrap prerequisites
1314
- */
1315
- async handleMissingFiles(missingFiles) {
1316
- const learnings = [];
1317
- for (const missing of missingFiles) {
1318
- // Create template files if safe to do so
1319
- if (missing.canCreateTemplate && missing.templateContent && missing.fileType !== 'secret') {
1320
- try {
1321
- const fullPath = path.join(this.projectPath, missing.filePath);
1322
- const dir = path.dirname(fullPath);
1323
- // Ensure directory exists
1324
- await fs.mkdir(dir, { recursive: true });
1325
- // Create template file
1326
- await fs.writeFile(fullPath, missing.templateContent, 'utf-8');
1327
- learnings.push({
1328
- type: 'success',
1329
- category: 'configuration',
1330
- description: `Created template file: ${missing.filePath}`,
1331
- severity: 'info',
1332
- recommendation: `Review and customize ${missing.filePath} before deployment`,
1333
- evidence: [`File created with template content`],
1334
- environmentSpecific: false,
1335
- timestamp: new Date().toISOString(),
1336
- });
1337
- this.logger.info(`Created template file: ${missing.filePath}`, 'BootstrapValidationLoop');
1338
- }
1339
- catch (error) {
1340
- learnings.push({
1341
- type: 'failure',
1342
- category: 'configuration',
1343
- description: `Failed to create template: ${missing.filePath}`,
1344
- severity: missing.severity,
1345
- recommendation: missing.recommendation,
1346
- evidence: [error.message],
1347
- environmentSpecific: true,
1348
- timestamp: new Date().toISOString(),
1349
- });
1350
- }
1351
- }
1352
- else {
1353
- // File cannot be auto-created, add as prerequisite
1354
- learnings.push({
1355
- type: 'prerequisite',
1356
- category: missing.fileType === 'secret' ? 'security' : 'configuration',
1357
- description: `Missing required file: ${missing.filePath}`,
1358
- severity: missing.severity,
1359
- recommendation: missing.recommendation,
1360
- evidence: missing.requiredBy,
1361
- environmentSpecific: missing.isIgnored,
1362
- timestamp: new Date().toISOString(),
1363
- });
1364
- }
1365
- }
1366
- return learnings;
1367
- }
1368
- /**
1369
- * Capture environment snapshot
1370
- */
1371
- async captureEnvironmentSnapshot() {
1372
- const snapshot = {};
1373
- try {
1374
- // Docker check
1375
- try {
1376
- const docker = await execAsync('docker ps --format "{{json .}}"', { timeout: 5000 });
1377
- snapshot.docker = {
1378
- available: true,
1379
- containers: docker.stdout.split('\n').filter(Boolean),
1380
- };
1381
- }
1382
- catch {
1383
- snapshot.docker = { available: false };
1384
- }
1385
- // Kubernetes check
1386
- try {
1387
- const k8s = await execAsync('kubectl get all --all-namespaces -o json', { timeout: 10000 });
1388
- snapshot.kubernetes = { available: true, resources: JSON.parse(k8s.stdout) };
1389
- }
1390
- catch {
1391
- snapshot.kubernetes = { available: false };
1392
- }
1393
- // OpenShift check
1394
- try {
1395
- const oc = await execAsync('oc status', { timeout: 5000 });
1396
- snapshot.openshift = { available: true, status: oc.stdout };
1397
- }
1398
- catch {
1399
- snapshot.openshift = { available: false };
1400
- }
1401
- // System info
1402
- snapshot.systemInfo = {
1403
- platform: process.platform,
1404
- arch: process.arch,
1405
- nodeVersion: process.version,
1406
- timestamp: new Date().toISOString(),
1407
- };
1408
- }
1409
- catch (error) {
1410
- this.logger.warn('Failed to capture complete environment snapshot', 'BootstrapValidationLoop', error);
1411
- }
1412
- return snapshot;
1413
- }
1414
- /**
1415
- * Store execution result in memory system
1416
- */
1417
- async storeExecutionInMemory(result) {
1418
- try {
1419
- await this.memoryManager.upsertEntity({
1420
- type: 'bootstrap_execution',
1421
- title: `Bootstrap Execution ${result.executionId} - ${result.success ? 'Success' : 'Failed'}`,
1422
- description: `Bootstrap execution on ${result.timestamp} with ${result.learnings.length} learnings captured`,
1423
- tags: [
1424
- 'bootstrap',
1425
- 'deployment',
1426
- result.success ? 'success' : 'failure',
1427
- `iteration-${this.currentIteration}`,
1428
- `learnings-${result.learnings.length}`,
1429
- `execution-${result.executionId}`,
1430
- ],
1431
- relationships: [],
1432
- context: {
1433
- projectPhase: 'deployment',
1434
- technicalStack: ['bootstrap', 'validation'],
1435
- environmentalFactors: [result.success ? 'success' : 'failure'],
1436
- stakeholders: ['deployment-team', 'infrastructure-team'],
1437
- },
1438
- });
1439
- }
1440
- catch (error) {
1441
- this.logger.warn('Failed to store execution in memory', 'BootstrapValidationLoop', error);
1442
- }
1443
- }
1444
- /**
1445
- * Compute SHA-256 hash of validated pattern for change detection
1446
- * @param pattern - Validated pattern to hash
1447
- * @returns Hex-encoded SHA-256 hash
1448
- */
1449
- /**
1450
- * Execute Infrastructure Layer using DAG with validated pattern
1451
- *
1452
- * This method:
1453
- * 1. Attempts to load validated pattern from YAML
1454
- * 2. If pattern exists: Auto-generates DAG tasks from pattern definition
1455
- * 3. If pattern doesn't exist: Works with user to create GitHub issue
1456
- * 4. Executes infrastructure DAG with parallel execution where possible
1457
- */
1458
- async executeInfrastructureDAG(platformDetection) {
1459
- const platform = platformDetection.primaryPlatform || 'unknown';
1460
- this.logger.info(`๐Ÿ—๏ธ Starting Infrastructure Layer DAG execution for ${platform}`, 'BootstrapValidationLoop');
1461
- // Try to load validated pattern from YAML
1462
- let dynamicPattern = await this.patternLoader.loadPattern(platform);
1463
- // If no pattern exists, work with user to create GitHub issue
1464
- if (!dynamicPattern) {
1465
- this.logger.warn(`โš ๏ธ No validated pattern found for platform: ${platform}`, 'BootstrapValidationLoop');
1466
- // Prompt user for contribution
1467
- const prompt = this.contributionHelper.promptUserForContribution(platform, platformDetection);
1468
- this.logger.info(prompt, 'BootstrapValidationLoop');
1469
- // Create GitHub issue (in production, this would use GitHub API)
1470
- const issueResult = await this.contributionHelper.createGitHubIssue(platform, platformDetection);
1471
- const successMessage = this.contributionHelper.generateSuccessMessage(issueResult, platform);
1472
- this.logger.info(successMessage, 'BootstrapValidationLoop');
1473
- // Fall back to AI-generated pattern
1474
- this.logger.info('๐Ÿค– Generating fallback pattern using AI...', 'BootstrapValidationLoop');
1475
- dynamicPattern = await this.generateFallbackPattern(platformDetection);
1476
- }
1477
- // Auto-generate infrastructure DAG tasks from validated pattern
1478
- const tasks = this.patternConverter.buildInfrastructureTasksFromPattern(dynamicPattern, platform);
1479
- this.logger.info(`๐Ÿ“Š Generated ${tasks.length} infrastructure DAG tasks`, 'BootstrapValidationLoop');
1480
- // Initialize SystemCard before execution
1481
- const bootstrapId = `${platform}-bootstrap-${Date.now()}`;
1482
- const detectedPlatform = platformDetection.detectedPlatforms.find(p => p.type === platform);
1483
- await this.systemCardManager.initialize({
1484
- systemId: bootstrapId,
1485
- created: new Date().toISOString(),
1486
- platform: {
1487
- type: platform,
1488
- ...(detectedPlatform?.version && { version: detectedPlatform.version }),
1489
- detectionConfidence: platformDetection.confidence,
1490
- },
1491
- bootstrapContext: {
1492
- bootstrapId,
1493
- validatedPatternId: dynamicPattern.id,
1494
- // These will be updated after bootstrap completion
1495
- },
1496
- metadata: {
1497
- tags: ['bootstrap', platform, 'infrastructure'],
1498
- description: `Bootstrap deployment for ${platform}`,
1499
- },
1500
- });
1501
- this.logger.info('๐Ÿ“ SystemCard initialized for resource tracking', 'BootstrapValidationLoop');
1502
- // Execute infrastructure DAG
1503
- const result = await this.dagExecutor.execute(tasks);
1504
- // Log results
1505
- if (result.success) {
1506
- this.logger.info(`โœ… Infrastructure Layer complete: ${result.executedTasks.length} tasks executed in ${result.duration}ms`, 'BootstrapValidationLoop');
1507
- // Extract resources from task results and update SystemCard
1508
- // Note: Resource extraction will be implemented in next phase
1509
- // For now, we'll generate cleanup phases based on what was executed
1510
- const cleanupPhases = await this.systemCardManager.generateCleanupPhases();
1511
- this.logger.info(`๐Ÿงน Generated ${cleanupPhases.length} cleanup phases with ${this.systemCardManager.getResourceCount()} tracked resources`, 'BootstrapValidationLoop');
1512
- }
1513
- else {
1514
- this.logger.error(`โŒ Infrastructure Layer failed: ${result.failedTasks.length} tasks failed, ${result.skippedTasks.length} skipped`, 'BootstrapValidationLoop');
1515
- // Log failed tasks
1516
- for (const taskId of result.failedTasks) {
1517
- const taskResult = result.taskResults.get(taskId);
1518
- if (taskResult) {
1519
- this.logger.error(` โŒ ${taskId}: ${taskResult.stderr || taskResult.error?.message}`, 'BootstrapValidationLoop');
1520
- }
1521
- }
1522
- }
1523
- return result;
1524
- }
1525
- /**
1526
- * Generate fallback pattern using AI when validated pattern doesn't exist
1527
- */
1528
- async generateFallbackPattern(detection) {
1529
- this.logger.warn('โš ๏ธ Generating fallback pattern using AI - less tested than validated patterns', 'BootstrapValidationLoop');
1530
- // Use existing dynamic deployment intelligence as fallback
1531
- const plan = await this.deploymentIntelligence.generateDeploymentPlan();
1532
- // Convert to DynamicPattern format
1533
- return {
1534
- version: '1.0-fallback',
1535
- id: `${detection.primaryPlatform}-ai-generated`,
1536
- name: `${detection.primaryPlatform} (AI-Generated)`,
1537
- description: 'Auto-generated deployment pattern - not validated by community',
1538
- authoritativeSources: [],
1539
- deploymentPhases: plan.deploymentSteps.map((step, i) => {
1540
- const prevStep = i > 0 ? plan.deploymentSteps[i - 1] : undefined;
1541
- return {
1542
- order: i + 1,
1543
- name: step.title,
1544
- description: step.description,
1545
- estimatedDuration: step.estimatedTime,
1546
- canParallelize: false,
1547
- prerequisites: prevStep ? [prevStep.title] : [],
1548
- commands: [
1549
- {
1550
- description: step.description,
1551
- command: step.command,
1552
- expectedExitCode: 0,
1553
- },
1554
- ],
1555
- };
1556
- }),
1557
- validationChecks: plan.validationChecks.map((check, i) => ({
1558
- id: `check-${i}`,
1559
- name: check.name,
1560
- description: check.name,
1561
- command: check.command,
1562
- expectedExitCode: 0,
1563
- severity: check.severity,
1564
- failureMessage: `Validation failed: ${check.name}`,
1565
- remediationSteps: [],
1566
- })),
1567
- metadata: {
1568
- source: 'AI-Generated (Fallback)',
1569
- lastUpdated: new Date().toISOString(),
1570
- tags: [detection.primaryPlatform || 'unknown', 'ai-generated', 'unvalidated'],
1571
- },
1572
- };
1573
- }
1574
- computePatternHash(pattern) {
1575
- try {
1576
- // Create a deterministic string representation of the pattern
1577
- const patternString = JSON.stringify({
1578
- id: pattern.id,
1579
- name: pattern.name,
1580
- version: pattern.version,
1581
- platformType: pattern.platformType,
1582
- deploymentPhases: pattern.deploymentPhases,
1583
- validationChecks: pattern.validationChecks,
1584
- authoritativeSources: pattern.authoritativeSources,
1585
- baseCodeRepository: pattern.baseCodeRepository,
1586
- }, null, 2);
1587
- // Compute SHA-256 hash
1588
- return createHash('sha256').update(patternString).digest('hex');
1589
- }
1590
- catch (error) {
1591
- this.logger.warn('Failed to compute pattern hash', 'BootstrapValidationLoop', error);
1592
- return 'hash-computation-failed';
1593
- }
1594
- }
1595
- }
1596
19
  /**
1597
20
  * Generate guided execution instructions for LLM
1598
21
  * This function returns step-by-step commands for the LLM to execute
@@ -1952,12 +375,9 @@ ${previousExecutionSuccess ? 'โœ… Deployment validation complete!\n\nReview the
1952
375
  */
1953
376
  export async function bootstrapValidationLoop(args) {
1954
377
  const { projectPath = process.cwd(), adrDirectory = 'docs/adrs', targetEnvironment = 'development', maxIterations = 5, autoFix = true, updateAdrsWithLearnings = true, currentIteration = 0, previousExecutionOutput = '', previousExecutionSuccess = false, deploymentCleanupRequested = false, appSelector, } = args;
1955
- const loop = new BootstrapValidationLoop(projectPath, adrDirectory, maxIterations);
1956
- await loop.initialize();
1957
378
  // GUIDED MODE: Return instructions for LLM to execute commands
1958
379
  // This mode tells the LLM what to run and processes the output iteratively
1959
380
  return await generateGuidedExecutionInstructions({
1960
- loop,
1961
381
  projectPath,
1962
382
  adrDirectory,
1963
383
  targetEnvironment,