pipecraft 0.0.0-releaseit

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 (176) hide show
  1. package/.claude/settings.local.json +35 -0
  2. package/.github/actions/calculate-version/action.yml +106 -0
  3. package/.github/actions/create-pr/action.yml +122 -0
  4. package/.github/actions/create-release/action.yml +74 -0
  5. package/.github/actions/create-tag/action.yml +94 -0
  6. package/.github/actions/detect-changes/action.yml +62 -0
  7. package/.github/actions/manage-branch/action.yml +113 -0
  8. package/.github/actions/promote-branch/action.yml +352 -0
  9. package/.github/example/workflows/job.analyze.code.yml +26 -0
  10. package/.github/example/workflows/job.analyze.docker.yml +32 -0
  11. package/.github/example/workflows/job.app.api.deploy.yml +127 -0
  12. package/.github/example/workflows/job.app.api.test.yml +102 -0
  13. package/.github/example/workflows/job.app.docs.deploy.yml +40 -0
  14. package/.github/example/workflows/job.app.docs.test.yml +50 -0
  15. package/.github/example/workflows/job.app.web.deploy.yml +96 -0
  16. package/.github/example/workflows/job.app.web.test.yml +49 -0
  17. package/.github/example/workflows/job.changes.yml +82 -0
  18. package/.github/example/workflows/job.create-pr.yml +96 -0
  19. package/.github/example/workflows/job.env-check.yml +43 -0
  20. package/.github/example/workflows/job.fast-forward.yml +103 -0
  21. package/.github/example/workflows/job.lint.yml +64 -0
  22. package/.github/example/workflows/job.pr-name.yml +70 -0
  23. package/.github/example/workflows/job.pr-squash-name.yml +27 -0
  24. package/.github/example/workflows/job.tag.yml +38 -0
  25. package/.github/example/workflows/job.version.yml +99 -0
  26. package/.github/example/workflows/lib.plugin-base.publish.yml +59 -0
  27. package/.github/example/workflows/pipe.yml +178 -0
  28. package/.github/example/workflows/scripts/fastforward.sh +51 -0
  29. package/.github/example/workflows/scripts/pipe-cleaner.sh +70 -0
  30. package/.github/scripts/fastforward.sh +51 -0
  31. package/.github/scripts/pipe-cleaner.sh +70 -0
  32. package/.github/workflows/pipeline.yml +220 -0
  33. package/.github/workflows/pr-title-check.yml +70 -0
  34. package/.github/workflows/publish.yml +39 -0
  35. package/.pipecraftrc.json +78 -0
  36. package/.release-it.cjs +71 -0
  37. package/PIPELINE_TESTING_PLAN.md +499 -0
  38. package/README.md +1101 -0
  39. package/TRUNK_FLOW_PLAN.md +401 -0
  40. package/assets/logo_banner.png +0 -0
  41. package/assets/logo_banner.webp +0 -0
  42. package/dist/cli/index.d.ts +3 -0
  43. package/dist/cli/index.d.ts.map +1 -0
  44. package/dist/cli/index.js +364 -0
  45. package/dist/cli/index.js.map +1 -0
  46. package/dist/generators/init.tpl.d.ts +3 -0
  47. package/dist/generators/init.tpl.d.ts.map +1 -0
  48. package/dist/generators/init.tpl.js +117 -0
  49. package/dist/generators/init.tpl.js.map +1 -0
  50. package/dist/generators/workflows.tpl.d.ts +7 -0
  51. package/dist/generators/workflows.tpl.d.ts.map +1 -0
  52. package/dist/generators/workflows.tpl.js +73 -0
  53. package/dist/generators/workflows.tpl.js.map +1 -0
  54. package/dist/templates/actions/calculate-version.yml.tpl.d.ts +3 -0
  55. package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -0
  56. package/dist/templates/actions/calculate-version.yml.tpl.js +122 -0
  57. package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -0
  58. package/dist/templates/actions/create-pr.yml.tpl.d.ts +3 -0
  59. package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -0
  60. package/dist/templates/actions/create-pr.yml.tpl.js +145 -0
  61. package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -0
  62. package/dist/templates/actions/create-tag.yml.tpl.d.ts +3 -0
  63. package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -0
  64. package/dist/templates/actions/create-tag.yml.tpl.js +111 -0
  65. package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -0
  66. package/dist/templates/actions/detect-changes.yml.tpl.d.ts +3 -0
  67. package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -0
  68. package/dist/templates/actions/detect-changes.yml.tpl.js +79 -0
  69. package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -0
  70. package/dist/templates/actions/manage-branch.yml.tpl.d.ts +3 -0
  71. package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -0
  72. package/dist/templates/actions/manage-branch.yml.tpl.js +130 -0
  73. package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -0
  74. package/dist/templates/actions/promote-branch.yml.tpl.d.ts +3 -0
  75. package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -0
  76. package/dist/templates/actions/promote-branch.yml.tpl.js +362 -0
  77. package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -0
  78. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts +16 -0
  79. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts.map +1 -0
  80. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js +652 -0
  81. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js.map +1 -0
  82. package/dist/types/index.d.ts +63 -0
  83. package/dist/types/index.d.ts.map +1 -0
  84. package/dist/types/index.js +2 -0
  85. package/dist/types/index.js.map +1 -0
  86. package/dist/utils/ast-path-operations.d.ts +287 -0
  87. package/dist/utils/ast-path-operations.d.ts.map +1 -0
  88. package/dist/utils/ast-path-operations.js +419 -0
  89. package/dist/utils/ast-path-operations.js.map +1 -0
  90. package/dist/utils/config.d.ts +3 -0
  91. package/dist/utils/config.d.ts.map +1 -0
  92. package/dist/utils/config.js +49 -0
  93. package/dist/utils/config.js.map +1 -0
  94. package/dist/utils/github-setup.d.ts +74 -0
  95. package/dist/utils/github-setup.d.ts.map +1 -0
  96. package/dist/utils/github-setup.js +418 -0
  97. package/dist/utils/github-setup.js.map +1 -0
  98. package/dist/utils/idempotency.d.ts +47 -0
  99. package/dist/utils/idempotency.d.ts.map +1 -0
  100. package/dist/utils/idempotency.js +176 -0
  101. package/dist/utils/idempotency.js.map +1 -0
  102. package/dist/utils/preflight.d.ts +55 -0
  103. package/dist/utils/preflight.d.ts.map +1 -0
  104. package/dist/utils/preflight.js +261 -0
  105. package/dist/utils/preflight.js.map +1 -0
  106. package/dist/utils/versioning.d.ts +41 -0
  107. package/dist/utils/versioning.d.ts.map +1 -0
  108. package/dist/utils/versioning.js +219 -0
  109. package/dist/utils/versioning.js.map +1 -0
  110. package/docs/USER_JOURNEY_ERRORS.md +352 -0
  111. package/eslint.config.js +77 -0
  112. package/examples/basic-config.json +41 -0
  113. package/examples/monorepo-config.json +49 -0
  114. package/examples/usage.md +289 -0
  115. package/package.json +58 -0
  116. package/scripts/debug-workflows.sh +339 -0
  117. package/scripts/parse-pipeline.js +29 -0
  118. package/scripts/test-job-order.cjs +140 -0
  119. package/scripts/validate-pipeline.cjs +379 -0
  120. package/scripts/verify-job-order.sh +30 -0
  121. package/src/cli/index.ts +414 -0
  122. package/src/generators/init.tpl.ts +126 -0
  123. package/src/generators/workflows.tpl.ts +80 -0
  124. package/src/templates/actions/calculate-version.yml.tpl.ts +124 -0
  125. package/src/templates/actions/create-pr.yml.tpl.ts +147 -0
  126. package/src/templates/actions/create-tag.yml.tpl.ts +112 -0
  127. package/src/templates/actions/detect-changes.yml.tpl.ts +87 -0
  128. package/src/templates/actions/manage-branch.yml.tpl.ts +132 -0
  129. package/src/templates/actions/promote-branch.yml.tpl.ts +364 -0
  130. package/src/templates/workflows/pipeline-path-based.yml.tpl.ts +706 -0
  131. package/src/types/index.ts +64 -0
  132. package/src/utils/README-ast-path-operations.md +390 -0
  133. package/src/utils/ast-path-operations.ts +581 -0
  134. package/src/utils/config.ts +64 -0
  135. package/src/utils/github-setup.ts +558 -0
  136. package/src/utils/idempotency.ts +215 -0
  137. package/src/utils/preflight.ts +306 -0
  138. package/src/utils/versioning.ts +244 -0
  139. package/tests/README.md +229 -0
  140. package/tests/TEST_STRUCTURE.md +256 -0
  141. package/tests/act/run-act-tests.sh +345 -0
  142. package/tests/debugging/debug-utils.ts +538 -0
  143. package/tests/debugging/debug-workflow.test.ts +339 -0
  144. package/tests/debugging/debug-workflows.sh +339 -0
  145. package/tests/debugging/iterative-debug.ts +652 -0
  146. package/tests/debugging/run-debug-tests.sh +431 -0
  147. package/tests/fixtures/basic-config.json +51 -0
  148. package/tests/fixtures/invalid-config.json +9 -0
  149. package/tests/fixtures/pipeline-generated.yml +235 -0
  150. package/tests/fixtures/pipeline-preserve-comments.yml +245 -0
  151. package/tests/fixtures/pipeline-user-modified.yml +245 -0
  152. package/tests/fixtures/test-config.json +58 -0
  153. package/tests/github-live/README.md +250 -0
  154. package/tests/github-local/JOB_WORKFLOW_TESTS.md +296 -0
  155. package/tests/github-local/README.md +240 -0
  156. package/tests/github-local/run-all-tests.sh +422 -0
  157. package/tests/github-local/test-job-workflows.sh +631 -0
  158. package/tests/github-local/test-pipeline-workflow.sh +440 -0
  159. package/tests/integration/generators.test.ts +578 -0
  160. package/tests/integration/path-based-template.test.ts +510 -0
  161. package/tests/integration/simple-path-based.test.ts +415 -0
  162. package/tests/setup.ts +56 -0
  163. package/tests/unit/ast-path-operations-extended.test.ts +302 -0
  164. package/tests/unit/cli.test.ts +541 -0
  165. package/tests/unit/config-extended.test.ts +412 -0
  166. package/tests/unit/config.test.ts +152 -0
  167. package/tests/unit/github-setup.test.ts +189 -0
  168. package/tests/unit/idempotency-isolated.test.ts +297 -0
  169. package/tests/unit/job-order.test.ts +157 -0
  170. package/tests/unit/pipeline-path-based.test.ts +511 -0
  171. package/tests/unit/validate-pipeline.test.ts +384 -0
  172. package/tests/unit/versioning-extended.test.ts +279 -0
  173. package/tests/unit/versioning.test.ts +241 -0
  174. package/tsconfig.debug.json +17 -0
  175. package/tsconfig.json +28 -0
  176. package/vitest.config.ts +51 -0
@@ -0,0 +1,652 @@
1
+ /**
2
+ * Iterative GitHub Actions Debugging System
3
+ *
4
+ * This module provides an interactive debugging system that can be run repeatedly
5
+ * to iteratively fix workflow issues. It maintains state between runs and provides
6
+ * intelligent suggestions for the next debugging steps.
7
+ */
8
+
9
+ import { execSync } from 'child_process';
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
11
+ import { join } from 'path';
12
+ import {
13
+ WorkflowDebugOrchestrator,
14
+ GitHubWorkflowDebugger,
15
+ type DebugAnalysis,
16
+ type LogAnalysis
17
+ } from './debug-utils';
18
+
19
+ export interface DebugSession {
20
+ sessionId: string;
21
+ workflowName: string;
22
+ branch?: string;
23
+ startTime: string;
24
+ lastRunId?: number;
25
+ totalRuns: number;
26
+ fixedIssues: string[];
27
+ remainingIssues: string[];
28
+ nextSteps: string[];
29
+ history: DebugHistoryEntry[];
30
+ }
31
+
32
+ export interface DebugHistoryEntry {
33
+ timestamp: string;
34
+ runId: number;
35
+ issues: string[];
36
+ actions: string[];
37
+ outcome: 'success' | 'failure' | 'partial';
38
+ }
39
+
40
+ export interface DebuggingPlan {
41
+ priority: 'high' | 'medium' | 'low';
42
+ issue: string;
43
+ suggestedActions: string[];
44
+ estimatedTime: string;
45
+ dependencies: string[];
46
+ }
47
+
48
+ /**
49
+ * Interactive debugging orchestrator that maintains state between runs
50
+ */
51
+ export class IterativeDebugger {
52
+ private session: DebugSession;
53
+ private debugger: GitHubWorkflowDebugger;
54
+ private sessionFile: string;
55
+ private outputDir: string;
56
+
57
+ constructor(
58
+ token: string,
59
+ owner: string,
60
+ repo: string,
61
+ workflowName: string,
62
+ branch?: string,
63
+ outputDir: string = './debug-sessions'
64
+ ) {
65
+ this.debugger = new GitHubWorkflowDebugger(token, owner, repo);
66
+ this.outputDir = outputDir;
67
+ this.sessionFile = join(outputDir, `session-${workflowName}-${Date.now()}.json`);
68
+
69
+ // Initialize or load session
70
+ this.session = this.initializeSession(workflowName, branch);
71
+ }
72
+
73
+ /**
74
+ * Initialize or load existing debug session
75
+ */
76
+ private initializeSession(workflowName: string, branch?: string): DebugSession {
77
+ if (existsSync(this.sessionFile)) {
78
+ try {
79
+ const sessionData = JSON.parse(readFileSync(this.sessionFile, 'utf-8'));
80
+ console.log(`๐Ÿ“‚ Loaded existing session: ${sessionData.sessionId}`);
81
+ return sessionData;
82
+ } catch (error) {
83
+ console.warn('โš ๏ธ Could not load existing session, starting fresh');
84
+ }
85
+ }
86
+
87
+ return {
88
+ sessionId: `debug-${Date.now()}`,
89
+ workflowName,
90
+ branch,
91
+ startTime: new Date().toISOString(),
92
+ totalRuns: 0,
93
+ fixedIssues: [],
94
+ remainingIssues: [],
95
+ nextSteps: [],
96
+ history: []
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Save session state
102
+ */
103
+ private saveSession(): void {
104
+ if (!existsSync(this.outputDir)) {
105
+ mkdirSync(this.outputDir, { recursive: true });
106
+ }
107
+
108
+ writeFileSync(this.sessionFile, JSON.stringify(this.session, null, 2));
109
+ }
110
+
111
+ /**
112
+ * Run a complete debugging iteration
113
+ */
114
+ async runDebugIteration(): Promise<DebugAnalysis | null> {
115
+ console.log(`๐Ÿ”„ Starting debug iteration ${this.session.totalRuns + 1}`);
116
+
117
+ try {
118
+ // Get recent workflow runs
119
+ const runs = await this.debugger.getWorkflowRuns(
120
+ this.session.workflowName,
121
+ this.session.branch,
122
+ 5
123
+ );
124
+
125
+ if (runs.length === 0) {
126
+ console.log('โŒ No workflow runs found');
127
+ return null;
128
+ }
129
+
130
+ // Find the most recent run
131
+ const latestRun = runs[0];
132
+ this.session.lastRunId = latestRun.id;
133
+ this.session.totalRuns++;
134
+
135
+ console.log(`๐Ÿ“Š Analyzing run ${latestRun.id} (${latestRun.status})`);
136
+
137
+ // Get jobs for this run
138
+ const jobs = await this.debugger.getWorkflowJobs(latestRun.id);
139
+
140
+ // Analyze the run
141
+ const analysis = this.analyzeWorkflowRun(latestRun, jobs);
142
+
143
+ // Update session with findings
144
+ this.updateSessionWithAnalysis(analysis);
145
+
146
+ // Generate next steps
147
+ this.generateNextSteps(analysis);
148
+
149
+ // Save session
150
+ this.saveSession();
151
+
152
+ // Generate report
153
+ await this.generateIterationReport(analysis);
154
+
155
+ return analysis;
156
+
157
+ } catch (error) {
158
+ console.error(`โŒ Debug iteration failed: ${error}`);
159
+ return null;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Analyze a workflow run and extract issues
165
+ */
166
+ private analyzeWorkflowRun(run: any, jobs: any[]): DebugAnalysis {
167
+ const failedJobs = jobs.filter(job =>
168
+ job.conclusion === 'failure' || job.conclusion === 'cancelled'
169
+ );
170
+
171
+ const successRate = jobs.length > 0 ?
172
+ ((jobs.length - failedJobs.length) / jobs.length) * 100 : 0;
173
+
174
+ // Extract issues from failed jobs
175
+ const issues: string[] = [];
176
+ failedJobs.forEach(job => {
177
+ job.steps.forEach((step: any) => {
178
+ if (step.conclusion === 'failure') {
179
+ const issue = this.categorizeIssue(step.name, job.name);
180
+ if (!issues.includes(issue)) {
181
+ issues.push(issue);
182
+ }
183
+ }
184
+ });
185
+ });
186
+
187
+ return {
188
+ runId: run.id,
189
+ status: run.status,
190
+ conclusion: run.conclusion,
191
+ failedJobs,
192
+ totalJobs: jobs.length,
193
+ successRate,
194
+ commonFailurePatterns: issues,
195
+ recommendations: this.generateRecommendations(issues)
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Categorize issues based on step and job names
201
+ */
202
+ private categorizeIssue(stepName: string, jobName: string): string {
203
+ const step = stepName.toLowerCase();
204
+ const job = jobName.toLowerCase();
205
+
206
+ if (step.includes('test') || job.includes('test')) {
207
+ return 'Test Failures';
208
+ }
209
+ if (step.includes('build') || job.includes('build')) {
210
+ return 'Build Failures';
211
+ }
212
+ if (step.includes('lint') || job.includes('lint')) {
213
+ return 'Linting Issues';
214
+ }
215
+ if (step.includes('deploy') || job.includes('deploy')) {
216
+ return 'Deployment Issues';
217
+ }
218
+ if (step.includes('install') || step.includes('dependencies')) {
219
+ return 'Dependency Issues';
220
+ }
221
+ if (step.includes('docker') || job.includes('docker')) {
222
+ return 'Docker Issues';
223
+ }
224
+ if (step.includes('security') || job.includes('security')) {
225
+ return 'Security Issues';
226
+ }
227
+
228
+ return 'Unknown Issues';
229
+ }
230
+
231
+ /**
232
+ * Generate specific recommendations based on issues
233
+ */
234
+ private generateRecommendations(issues: string[]): string[] {
235
+ const recommendations: string[] = [];
236
+
237
+ if (issues.includes('Test Failures')) {
238
+ recommendations.push('Run tests locally to reproduce failures');
239
+ recommendations.push('Check for flaky tests and add retry mechanisms');
240
+ recommendations.push('Update test dependencies and configurations');
241
+ }
242
+
243
+ if (issues.includes('Build Failures')) {
244
+ recommendations.push('Verify build environment and dependencies');
245
+ recommendations.push('Check for breaking changes in dependencies');
246
+ recommendations.push('Review build configuration files');
247
+ }
248
+
249
+ if (issues.includes('Linting Issues')) {
250
+ recommendations.push('Run linting locally and fix issues');
251
+ recommendations.push('Configure pre-commit hooks for automatic linting');
252
+ recommendations.push('Update linting rules and configurations');
253
+ }
254
+
255
+ if (issues.includes('Dependency Issues')) {
256
+ recommendations.push('Update package-lock.json or yarn.lock');
257
+ recommendations.push('Check for version conflicts in dependencies');
258
+ recommendations.push('Clear node_modules and reinstall dependencies');
259
+ }
260
+
261
+ if (issues.includes('Docker Issues')) {
262
+ recommendations.push('Test Docker build locally');
263
+ recommendations.push('Check Dockerfile syntax and base images');
264
+ recommendations.push('Verify resource constraints in CI environment');
265
+ }
266
+
267
+ return recommendations;
268
+ }
269
+
270
+ /**
271
+ * Update session with analysis results
272
+ */
273
+ private updateSessionWithAnalysis(analysis: DebugAnalysis): void {
274
+ // Track new issues
275
+ const newIssues = analysis.commonFailurePatterns.filter(issue =>
276
+ !this.session.remainingIssues.includes(issue)
277
+ );
278
+
279
+ this.session.remainingIssues = [
280
+ ...this.session.remainingIssues,
281
+ ...newIssues
282
+ ];
283
+
284
+ // Remove fixed issues (issues that are no longer present)
285
+ const currentIssues = analysis.commonFailurePatterns;
286
+ const fixedIssues = this.session.remainingIssues.filter(issue =>
287
+ !currentIssues.includes(issue)
288
+ );
289
+
290
+ this.session.fixedIssues = [...this.session.fixedIssues, ...fixedIssues];
291
+ this.session.remainingIssues = this.session.remainingIssues.filter(issue =>
292
+ currentIssues.includes(issue)
293
+ );
294
+
295
+ // Add to history
296
+ this.session.history.push({
297
+ timestamp: new Date().toISOString(),
298
+ runId: analysis.runId,
299
+ issues: analysis.commonFailurePatterns,
300
+ actions: [],
301
+ outcome: analysis.successRate > 80 ? 'success' :
302
+ analysis.successRate > 50 ? 'partial' : 'failure'
303
+ });
304
+ }
305
+
306
+ /**
307
+ * Generate next steps based on current state
308
+ */
309
+ private generateNextSteps(analysis: DebugAnalysis): void {
310
+ const nextSteps: string[] = [];
311
+
312
+ if (analysis.successRate === 100) {
313
+ nextSteps.push('๐ŸŽ‰ All issues resolved! Workflow is now passing.');
314
+ nextSteps.push('Consider adding monitoring to prevent regressions.');
315
+ } else if (analysis.successRate > 80) {
316
+ nextSteps.push('โœ… Significant progress made! Focus on remaining issues.');
317
+ nextSteps.push('Review the remaining failed jobs and their logs.');
318
+ } else {
319
+ nextSteps.push('๐Ÿ”ง Focus on the most critical issues first.');
320
+ nextSteps.push('Consider breaking down large jobs into smaller ones.');
321
+ }
322
+
323
+ // Add specific recommendations
324
+ analysis.recommendations.forEach(rec => {
325
+ nextSteps.push(`๐Ÿ’ก ${rec}`);
326
+ });
327
+
328
+ this.session.nextSteps = nextSteps;
329
+ }
330
+
331
+ /**
332
+ * Generate iteration report
333
+ */
334
+ private async generateIterationReport(analysis: DebugAnalysis): Promise<void> {
335
+ const reportPath = join(this.outputDir, `iteration-${this.session.totalRuns}.md`);
336
+
337
+ const report = `# Debug Iteration ${this.session.totalRuns}
338
+
339
+ **Session ID**: ${this.session.sessionId}
340
+ **Timestamp**: ${new Date().toISOString()}
341
+ **Workflow**: ${this.session.workflowName}
342
+ **Run ID**: ${analysis.runId}
343
+
344
+ ## Current Status
345
+
346
+ - **Success Rate**: ${analysis.successRate.toFixed(1)}%
347
+ - **Total Jobs**: ${analysis.totalJobs}
348
+ - **Failed Jobs**: ${analysis.failedJobs.length}
349
+
350
+ ## Issues Found
351
+
352
+ ${analysis.commonFailurePatterns.map(issue => `- ${issue}`).join('\n')}
353
+
354
+ ## Recommendations
355
+
356
+ ${analysis.recommendations.map(rec => `- ${rec}`).join('\n')}
357
+
358
+ ## Session Progress
359
+
360
+ - **Total Iterations**: ${this.session.totalRuns}
361
+ - **Issues Fixed**: ${this.session.fixedIssues.length}
362
+ - **Remaining Issues**: ${this.session.remainingIssues.length}
363
+
364
+ ### Fixed Issues
365
+ ${this.session.fixedIssues.map(issue => `- โœ… ${issue}`).join('\n')}
366
+
367
+ ### Remaining Issues
368
+ ${this.session.remainingIssues.map(issue => `- ๐Ÿ”ง ${issue}`).join('\n')}
369
+
370
+ ## Next Steps
371
+
372
+ ${this.session.nextSteps.map(step => `- ${step}`).join('\n')}
373
+
374
+ ## History
375
+
376
+ ${this.session.history.map(entry => `
377
+ ### ${entry.timestamp}
378
+ - **Run ID**: ${entry.runId}
379
+ - **Outcome**: ${entry.outcome}
380
+ - **Issues**: ${entry.issues.join(', ')}
381
+ `).join('\n')}
382
+
383
+ ---
384
+ *Generated by Pipecraft Iterative Debugger*
385
+ `;
386
+
387
+ writeFileSync(reportPath, report);
388
+ console.log(`๐Ÿ“„ Iteration report saved: ${reportPath}`);
389
+ }
390
+
391
+ /**
392
+ * Get current session status
393
+ */
394
+ getSessionStatus(): DebugSession {
395
+ return { ...this.session };
396
+ }
397
+
398
+ /**
399
+ * Get debugging plan with priorities
400
+ */
401
+ getDebuggingPlan(): DebuggingPlan[] {
402
+ const plans: DebuggingPlan[] = [];
403
+
404
+ this.session.remainingIssues.forEach(issue => {
405
+ const priority = this.determinePriority(issue);
406
+ const actions = this.getActionsForIssue(issue);
407
+
408
+ plans.push({
409
+ priority,
410
+ issue,
411
+ suggestedActions: actions,
412
+ estimatedTime: this.estimateTime(issue),
413
+ dependencies: this.getDependencies(issue)
414
+ });
415
+ });
416
+
417
+ return plans.sort((a, b) => {
418
+ const priorityOrder = { high: 3, medium: 2, low: 1 };
419
+ return priorityOrder[b.priority] - priorityOrder[a.priority];
420
+ });
421
+ }
422
+
423
+ /**
424
+ * Determine priority for an issue
425
+ */
426
+ private determinePriority(issue: string): 'high' | 'medium' | 'low' {
427
+ const highPriorityIssues = ['Build Failures', 'Dependency Issues'];
428
+ const mediumPriorityIssues = ['Test Failures', 'Linting Issues'];
429
+
430
+ if (highPriorityIssues.includes(issue)) return 'high';
431
+ if (mediumPriorityIssues.includes(issue)) return 'medium';
432
+ return 'low';
433
+ }
434
+
435
+ /**
436
+ * Get specific actions for an issue
437
+ */
438
+ private getActionsForIssue(issue: string): string[] {
439
+ const actionMap: Record<string, string[]> = {
440
+ 'Test Failures': [
441
+ 'Run tests locally with same environment',
442
+ 'Check for flaky tests and add retries',
443
+ 'Update test dependencies',
444
+ 'Review test configuration'
445
+ ],
446
+ 'Build Failures': [
447
+ 'Test build locally',
448
+ 'Check dependency versions',
449
+ 'Review build configuration',
450
+ 'Check for breaking changes'
451
+ ],
452
+ 'Linting Issues': [
453
+ 'Run linting locally',
454
+ 'Fix linting errors',
455
+ 'Update linting configuration',
456
+ 'Add pre-commit hooks'
457
+ ],
458
+ 'Dependency Issues': [
459
+ 'Update package-lock.json',
460
+ 'Clear node_modules and reinstall',
461
+ 'Check for version conflicts',
462
+ 'Update dependency versions'
463
+ ],
464
+ 'Docker Issues': [
465
+ 'Test Docker build locally',
466
+ 'Check Dockerfile syntax',
467
+ 'Verify base image versions',
468
+ 'Check resource constraints'
469
+ ]
470
+ };
471
+
472
+ return actionMap[issue] || ['Investigate the issue further'];
473
+ }
474
+
475
+ /**
476
+ * Estimate time to fix an issue
477
+ */
478
+ private estimateTime(issue: string): string {
479
+ const timeMap: Record<string, string> = {
480
+ 'Test Failures': '30-60 minutes',
481
+ 'Build Failures': '15-45 minutes',
482
+ 'Linting Issues': '10-30 minutes',
483
+ 'Dependency Issues': '20-40 minutes',
484
+ 'Docker Issues': '30-60 minutes'
485
+ };
486
+
487
+ return timeMap[issue] || 'Unknown';
488
+ }
489
+
490
+ /**
491
+ * Get dependencies for an issue
492
+ */
493
+ private getDependencies(issue: string): string[] {
494
+ const dependencyMap: Record<string, string[]> = {
495
+ 'Test Failures': ['Build Failures'],
496
+ 'Build Failures': ['Dependency Issues'],
497
+ 'Linting Issues': [],
498
+ 'Dependency Issues': [],
499
+ 'Docker Issues': ['Build Failures']
500
+ };
501
+
502
+ return dependencyMap[issue] || [];
503
+ }
504
+
505
+ /**
506
+ * Run a quick health check
507
+ */
508
+ async runHealthCheck(): Promise<boolean> {
509
+ try {
510
+ const runs = await this.debugger.getWorkflowRuns(this.session.workflowName, this.session.branch, 1);
511
+ return runs.length > 0;
512
+ } catch (error) {
513
+ console.error(`โŒ Health check failed: ${error}`);
514
+ return false;
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Clean up old sessions
520
+ */
521
+ static cleanupOldSessions(outputDir: string, maxAge: number = 7 * 24 * 60 * 60 * 1000): void {
522
+ // Implementation for cleaning up old session files
523
+ console.log(`๐Ÿงน Cleaning up sessions older than ${maxAge}ms`);
524
+ }
525
+ }
526
+
527
+ /**
528
+ * CLI interface for iterative debugging
529
+ */
530
+ export class IterativeDebugCLI {
531
+ private debugger: IterativeDebugger;
532
+
533
+ constructor(debugger: IterativeDebugger) {
534
+ this.debugger = debugger;
535
+ }
536
+
537
+ /**
538
+ * Run interactive debugging session
539
+ */
540
+ async runInteractiveSession(): Promise<void> {
541
+ console.log('๐Ÿš€ Starting interactive debugging session');
542
+ console.log(`๐Ÿ“‹ Session ID: ${this.debugger.getSessionStatus().sessionId}`);
543
+
544
+ let continueDebugging = true;
545
+ let iteration = 0;
546
+
547
+ while (continueDebugging && iteration < 10) { // Limit to 10 iterations
548
+ iteration++;
549
+
550
+ console.log(`\n๐Ÿ”„ Iteration ${iteration}`);
551
+ console.log('=' * 50);
552
+
553
+ // Run debug iteration
554
+ const analysis = await this.debugger.runDebugIteration();
555
+
556
+ if (!analysis) {
557
+ console.log('โŒ No analysis available, stopping');
558
+ break;
559
+ }
560
+
561
+ // Show current status
562
+ this.showCurrentStatus();
563
+
564
+ // Show debugging plan
565
+ this.showDebuggingPlan();
566
+
567
+ // Ask user if they want to continue
568
+ console.log('\nโ“ Continue debugging? (y/n)');
569
+ // In a real implementation, you'd read from stdin
570
+ // For now, we'll just continue automatically
571
+ continueDebugging = iteration < 3; // Auto-stop after 3 iterations for demo
572
+ }
573
+
574
+ console.log('\n๐Ÿ Debugging session complete');
575
+ this.showFinalSummary();
576
+ }
577
+
578
+ /**
579
+ * Show current debugging status
580
+ */
581
+ private showCurrentStatus(): void {
582
+ const status = this.debugger.getSessionStatus();
583
+
584
+ console.log('\n๐Ÿ“Š Current Status:');
585
+ console.log(` Total Iterations: ${status.totalRuns}`);
586
+ console.log(` Issues Fixed: ${status.fixedIssues.length}`);
587
+ console.log(` Remaining Issues: ${status.remainingIssues.length}`);
588
+
589
+ if (status.remainingIssues.length > 0) {
590
+ console.log('\n๐Ÿ”ง Remaining Issues:');
591
+ status.remainingIssues.forEach(issue => {
592
+ console.log(` - ${issue}`);
593
+ });
594
+ }
595
+ }
596
+
597
+ /**
598
+ * Show debugging plan
599
+ */
600
+ private showDebuggingPlan(): void {
601
+ const plans = this.debugger.getDebuggingPlan();
602
+
603
+ if (plans.length === 0) {
604
+ console.log('\n๐ŸŽ‰ No remaining issues to fix!');
605
+ return;
606
+ }
607
+
608
+ console.log('\n๐Ÿ“‹ Debugging Plan:');
609
+ plans.forEach((plan, index) => {
610
+ console.log(`\n${index + 1}. ${plan.issue} (${plan.priority} priority)`);
611
+ console.log(` Estimated Time: ${plan.estimatedTime}`);
612
+ console.log(` Actions:`);
613
+ plan.suggestedActions.forEach(action => {
614
+ console.log(` - ${action}`);
615
+ });
616
+ });
617
+ }
618
+
619
+ /**
620
+ * Show final summary
621
+ */
622
+ private showFinalSummary(): void {
623
+ const status = this.debugger.getSessionStatus();
624
+
625
+ console.log('\n๐Ÿ“ˆ Final Summary:');
626
+ console.log(` Session Duration: ${this.calculateSessionDuration()}`);
627
+ console.log(` Total Iterations: ${status.totalRuns}`);
628
+ console.log(` Issues Fixed: ${status.fixedIssues.length}`);
629
+ console.log(` Remaining Issues: ${status.remainingIssues.length}`);
630
+
631
+ if (status.fixedIssues.length > 0) {
632
+ console.log('\nโœ… Fixed Issues:');
633
+ status.fixedIssues.forEach(issue => {
634
+ console.log(` - ${issue}`);
635
+ });
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Calculate session duration
641
+ */
642
+ private calculateSessionDuration(): string {
643
+ const status = this.debugger.getSessionStatus();
644
+ const startTime = new Date(status.startTime);
645
+ const duration = Date.now() - startTime.getTime();
646
+
647
+ const minutes = Math.floor(duration / 60000);
648
+ const seconds = Math.floor((duration % 60000) / 1000);
649
+
650
+ return `${minutes}m ${seconds}s`;
651
+ }
652
+ }