fraim-framework 1.0.12 → 2.0.2

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 (93) hide show
  1. package/.ai-agents/agent-guardrails.md +58 -0
  2. package/.ai-agents/mcp-template.jsonc +34 -0
  3. package/.ai-agents/rules/agent-testing-guidelines.md +545 -0
  4. package/.ai-agents/rules/architecture.md +52 -0
  5. package/.ai-agents/rules/communication.md +122 -0
  6. package/.ai-agents/rules/continuous-learning.md +55 -0
  7. package/.ai-agents/rules/git-safe-commands.md +34 -0
  8. package/.ai-agents/rules/integrity-and-test-ethics.md +223 -0
  9. package/.ai-agents/rules/local-development.md +252 -0
  10. package/.ai-agents/rules/merge-requirements.md +231 -0
  11. package/.ai-agents/rules/pr-workflow-completeness.md +191 -0
  12. package/.ai-agents/rules/simplicity.md +112 -0
  13. package/.ai-agents/rules/software-development-lifecycle.md +276 -0
  14. package/.ai-agents/rules/spike-first-development.md +199 -0
  15. package/.ai-agents/rules/successful-debugging-patterns.md +313 -0
  16. package/.ai-agents/scripts/cleanup-branch.ts +278 -0
  17. package/.ai-agents/scripts/exec-with-timeout.ts +122 -0
  18. package/.ai-agents/scripts/prep-issue.sh +162 -0
  19. package/.ai-agents/templates/evidence/Design-Evidence.md +30 -0
  20. package/.ai-agents/templates/evidence/Implementation-BugEvidence.md +48 -0
  21. package/.ai-agents/templates/evidence/Implementation-FeatureEvidence.md +54 -0
  22. package/.ai-agents/templates/evidence/Spec-Evidence.md +19 -0
  23. package/.ai-agents/templates/help/HelpNeeded.md +14 -0
  24. package/.ai-agents/templates/retrospective/RETROSPECTIVE-TEMPLATE.md +55 -0
  25. package/.ai-agents/templates/specs/BUGSPEC-TEMPLATE.md +37 -0
  26. package/.ai-agents/templates/specs/FEATURESPEC-TEMPLATE.md +29 -0
  27. package/.ai-agents/templates/specs/TECHSPEC-TEMPLATE.md +39 -0
  28. package/.ai-agents/workflows/design.md +121 -0
  29. package/.ai-agents/workflows/implement.md +170 -0
  30. package/.ai-agents/workflows/resolve.md +152 -0
  31. package/.ai-agents/workflows/retrospect.md +84 -0
  32. package/.ai-agents/workflows/spec.md +103 -0
  33. package/.ai-agents/workflows/test.md +90 -0
  34. package/.cursor/rules/cursor-rules.mdc +8 -0
  35. package/.cursor/rules/design.mdc +4 -0
  36. package/.cursor/rules/implement.mdc +6 -0
  37. package/.cursor/rules/resolve.mdc +5 -0
  38. package/.cursor/rules/retrospect.mdc +4 -0
  39. package/.cursor/rules/spec.mdc +4 -0
  40. package/.cursor/rules/test.mdc +5 -0
  41. package/.windsurf/rules/windsurf-rules.md +7 -0
  42. package/.windsurf/workflows/resolve-issue.md +6 -0
  43. package/.windsurf/workflows/retrospect.md +6 -0
  44. package/.windsurf/workflows/start-design.md +6 -0
  45. package/.windsurf/workflows/start-impl.md +6 -0
  46. package/.windsurf/workflows/start-spec.md +6 -0
  47. package/.windsurf/workflows/start-tests.md +6 -0
  48. package/CHANGELOG.md +66 -0
  49. package/CODEOWNERS +24 -0
  50. package/DISTRIBUTION.md +6 -6
  51. package/PUBLISH_INSTRUCTIONS.md +93 -0
  52. package/README.md +330 -104
  53. package/bin/fraim.js +49 -3
  54. package/index.js +30 -3
  55. package/install.sh +58 -58
  56. package/labels.json +52 -0
  57. package/linkedin-post.md +23 -0
  58. package/package.json +12 -7
  59. package/sample_package.json +18 -0
  60. package/setup.js +733 -384
  61. package/test-utils.ts +118 -0
  62. package/tsconfig.json +22 -0
  63. package/agents/claude/CLAUDE.md +0 -42
  64. package/agents/cursor/rules/architecture.mdc +0 -49
  65. package/agents/cursor/rules/continuous-learning.mdc +0 -48
  66. package/agents/cursor/rules/cursor-workflow.mdc +0 -29
  67. package/agents/cursor/rules/design.mdc +0 -25
  68. package/agents/cursor/rules/implement.mdc +0 -26
  69. package/agents/cursor/rules/local-development.mdc +0 -104
  70. package/agents/cursor/rules/prep.mdc +0 -15
  71. package/agents/cursor/rules/resolve.mdc +0 -46
  72. package/agents/cursor/rules/simplicity.mdc +0 -18
  73. package/agents/cursor/rules/software-development-lifecycle.mdc +0 -41
  74. package/agents/cursor/rules/test.mdc +0 -25
  75. package/agents/windsurf/rules/architecture.md +0 -49
  76. package/agents/windsurf/rules/continuous-learning.md +0 -47
  77. package/agents/windsurf/rules/local-development.md +0 -103
  78. package/agents/windsurf/rules/remote-development.md +0 -22
  79. package/agents/windsurf/rules/simplicity.md +0 -17
  80. package/agents/windsurf/rules/windsurf-workflow.md +0 -28
  81. package/agents/windsurf/workflows/prep.md +0 -20
  82. package/agents/windsurf/workflows/resolve-issue.md +0 -47
  83. package/agents/windsurf/workflows/start-design.md +0 -26
  84. package/agents/windsurf/workflows/start-impl.md +0 -27
  85. package/agents/windsurf/workflows/start-tests.md +0 -26
  86. package/github/phase-change.yml +0 -218
  87. package/github/status-change.yml +0 -68
  88. package/github/sync-on-pr-review.yml +0 -66
  89. package/scripts/__init__.py +0 -10
  90. package/scripts/cli.py +0 -141
  91. package/setup.py +0 -0
  92. package/test-config.json +0 -32
  93. package/workflows/setup-fraim.yml +0 -147
@@ -0,0 +1,313 @@
1
+ # Successful Debugging Patterns
2
+
3
+ ## INTENT
4
+ Establish systematic debugging approaches that convert challenges into learning opportunities and prevent recurring issues through comprehensive testing and documentation.
5
+
6
+ ## PRINCIPLES
7
+ - **Systematic Approach**: Follow structured debugging methodology
8
+ - **Evidence-Based**: Document findings with concrete evidence
9
+ - **Learning Focus**: Convert every debug session into reusable knowledge
10
+ - **Test-Driven**: Create tests that prevent regression
11
+ - **Pattern Recognition**: Identify and document common failure modes
12
+
13
+ ## SYSTEMATIC DEBUGGING METHODOLOGY
14
+
15
+ ### 1. Issue Reproduction
16
+ **Goal**: Create reliable, repeatable failure conditions
17
+
18
+ **Steps**:
19
+ 1. Document exact steps to reproduce
20
+ 2. Identify minimum conditions for failure
21
+ 3. Create automated reproduction script
22
+ 4. Verify reproduction works consistently
23
+ 5. Document environment and dependencies
24
+
25
+ ### 2. Evidence Collection
26
+ **Goal**: Gather comprehensive data about the failure
27
+
28
+ **Steps**:
29
+ 1. Collect error messages and stack traces
30
+ 2. Review relevant logs with timestamps
31
+ 3. Document system state at failure time
32
+ 4. Capture network requests/responses
33
+ 5. Record configuration and environment details
34
+
35
+ ### 3. Root Cause Analysis
36
+ **Goal**: Identify the underlying cause, not just symptoms
37
+
38
+ **Steps**:
39
+ 1. Trace execution flow to failure point
40
+ 2. Examine code logic and data flow
41
+ 3. Identify assumptions that may be incorrect
42
+ 4. Check for race conditions or timing issues
43
+ 5. Validate external dependencies
44
+
45
+ ### 4. Solution Development
46
+ **Goal**: Create targeted fix that addresses root cause
47
+
48
+ **Steps**:
49
+ 1. Design minimal fix for root cause
50
+ 2. Consider impact on other system components
51
+ 3. Plan rollback strategy if needed
52
+ 4. Implement fix with proper error handling
53
+ 5. Add monitoring/logging for future detection
54
+
55
+ ### 5. Validation and Testing
56
+ **Goal**: Ensure fix works and doesn't break anything else
57
+
58
+ **Steps**:
59
+ 1. Verify original issue is resolved
60
+ 2. Run comprehensive test suite
61
+ 3. Test edge cases and error conditions
62
+ 4. Validate performance impact
63
+ 5. Confirm no new issues introduced
64
+
65
+ ## SPECIFIC DEBUGGING TECHNIQUES
66
+
67
+ ### Code Analysis and Understanding
68
+
69
+ **CRITICAL: Always Analyze Before Implementing**
70
+ Before making any changes, use tools to understand the current codebase:
71
+
72
+ ```bash
73
+ # Find all files that import a specific module
74
+ grep_search --SearchPath src --Query \"import.*ApiService\" --IsRegex true --MatchPerLine true
75
+
76
+ # Find files by pattern
77
+ find_by_name --SearchDirectory src --Pattern \"*service*\" --Type file
78
+
79
+ # Read specific files to understand implementation
80
+ Read --file_path src/services/api-service.ts
81
+ ```
82
+
83
+ **Pattern Analysis Requirements:**
84
+ 1. **Examine existing patterns** in the codebase (e.g., ServiceBase pattern)
85
+ 2. **Use grep_search** to find all dependencies and usage
86
+ 3. **Read actual implementations** to understand current architecture
87
+ 4. **Document findings** with real code examples and line numbers
88
+
89
+ ### Database Validation Scripts
90
+
91
+ **Database State Validation:**
92
+ ```typescript
93
+ const { DatabaseService } = require('./src/services/database-service');
94
+
95
+ async function checkDatabaseState() {
96
+ console.log('🔍 Checking database state...');
97
+ const dbService = new DatabaseService();
98
+ await dbService.initialize();
99
+
100
+ try {
101
+ // Check for tokens
102
+ const tokens = await dbService.getTokens('primary');
103
+ console.log('📋 Tokens found:', !!tokens);
104
+
105
+ // Check for data
106
+ const records = await dbService.getAllRecords();
107
+ console.log('📊 Records found:', records.length);
108
+
109
+ // Check for specific data
110
+ const config = await dbService.getConfig('APP_CLIENT_ID');
111
+ console.log('🔑 Config found:', !!config);
112
+
113
+ } catch (error) {
114
+ console.error('❌ Database check failed:', error);
115
+ } finally {
116
+ await dbService.close();
117
+ }
118
+ }
119
+ ```
120
+
121
+ **API Endpoint Testing:**
122
+ ```typescript
123
+ async function testAPIEndpoints() {
124
+ const baseUrl = 'http://localhost:3000';
125
+
126
+ // Test main API
127
+ try {
128
+ const response = await fetch(`${baseUrl}/api/data?start=2024-01-01&end=2024-01-02`);
129
+ const data = await response.json();
130
+ console.log('📊 Data API:', response.status, data);
131
+ } catch (error) {
132
+ console.error('❌ Data API failed:', error);
133
+ }
134
+
135
+ // Test status API
136
+ try {
137
+ const response = await fetch(`${baseUrl}/api/status`);
138
+ const data = await response.json();
139
+ console.log('💬 Status API:', response.status, data);
140
+ } catch (error) {
141
+ console.error('❌ Status API failed:', error);
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## COMMON DEBUGGING SCENARIOS
147
+
148
+ ### Authentication Issues
149
+ **Symptoms**: 401 errors, token validation failures
150
+ **Common Causes**:
151
+ - Expired tokens not being refreshed
152
+ - Missing authentication headers
153
+ - Incorrect token format or encoding
154
+ - Clock skew between systems
155
+
156
+ **Debugging Steps**:
157
+ 1. Verify token expiration times
158
+ 2. Check token refresh logic
159
+ 3. Validate authentication headers
160
+ 4. Test with known-good tokens
161
+
162
+ ### API Integration Issues
163
+ **Symptoms**: Network errors, unexpected responses
164
+ **Common Causes**:
165
+ - Rate limiting
166
+ - API version mismatches
167
+ - Incorrect request formatting
168
+ - Network connectivity issues
169
+
170
+ **Debugging Steps**:
171
+ 1. Check API documentation for changes
172
+ 2. Verify request format and headers
173
+ 3. Test with API debugging tools
174
+ 4. Monitor rate limits and quotas
175
+
176
+ ### Database Connection Issues
177
+ **Symptoms**: Connection timeouts, query failures
178
+ **Common Causes**:
179
+ - Connection pool exhaustion
180
+ - Database server issues
181
+ - Network connectivity problems
182
+ - Query performance issues
183
+
184
+ **Debugging Steps**:
185
+ 1. Check connection pool status
186
+ 2. Verify database server health
187
+ 3. Analyze slow query logs
188
+ 4. Test connection from different environments
189
+
190
+ ## LEARNING AND DOCUMENTATION
191
+
192
+ ### Issue Documentation Template
193
+ ```markdown
194
+ # Debug Session: [Issue Title]
195
+
196
+ ## Problem Description
197
+ [Clear description of the issue]
198
+
199
+ ## Reproduction Steps
200
+ 1. [Step 1]
201
+ 2. [Step 2]
202
+ 3. [Expected vs Actual behavior]
203
+
204
+ ## Investigation Process
205
+ - **Hypothesis 1**: [What you thought might be wrong]
206
+ - **Test**: [How you tested it]
207
+ - **Result**: [What you found]
208
+ - **Hypothesis 2**: [Next theory]
209
+ - **Test**: [How you tested it]
210
+ - **Result**: [What you found]
211
+
212
+ ## Root Cause
213
+ [The actual underlying cause]
214
+
215
+ ## Solution
216
+ [What you changed to fix it]
217
+
218
+ ## Prevention
219
+ - **Tests Added**: [New tests to prevent regression]
220
+ - **Monitoring Added**: [New alerts or logging]
221
+ - **Documentation Updated**: [What docs were improved]
222
+
223
+ ## Lessons Learned
224
+ [Key insights for future debugging]
225
+ ```
226
+
227
+ ### Creating Regression Tests
228
+ **Always create tests that would have caught the bug:**
229
+
230
+ ```typescript
231
+ describe('Bug Fix: [Issue Description]', () => {
232
+ it('should handle [specific failure condition]', async () => {
233
+ // Arrange: Set up the exact conditions that caused the bug
234
+ const testData = createTestConditions();
235
+
236
+ // Act: Perform the action that previously failed
237
+ const result = await performAction(testData);
238
+
239
+ // Assert: Verify the fix works
240
+ expect(result).toBeDefined();
241
+ expect(result.status).toBe('success');
242
+ });
243
+
244
+ it('should not break existing functionality', async () => {
245
+ // Regression test to ensure fix doesn't break other features
246
+ const existingFlow = await testExistingWorkflow();
247
+ expect(existingFlow).toMatchSnapshot();
248
+ });
249
+ });
250
+ ```
251
+
252
+ ## ESCALATION PATTERNS
253
+
254
+ ### When to Escalate
255
+ - Issue persists after 2+ hours of systematic debugging
256
+ - Root cause requires architectural changes
257
+ - Issue affects production systems
258
+ - Solution requires expertise outside your domain
259
+
260
+ ### How to Escalate
261
+ 1. **Document everything**: Provide complete investigation history
262
+ 2. **Be specific**: Include exact error messages and reproduction steps
263
+ 3. **Show your work**: Explain what you've tried and why
264
+ 4. **Suggest options**: Propose potential solutions if you have ideas
265
+ 5. **Set context**: Explain business impact and urgency
266
+
267
+ ### Escalation Template
268
+ ```markdown
269
+ # Escalation: [Issue Title]
270
+
271
+ ## Summary
272
+ [Brief description of the problem]
273
+
274
+ ## Business Impact
275
+ - **Affected Users**: [Who is impacted]
276
+ - **Severity**: [Critical/High/Medium/Low]
277
+ - **Timeline**: [When this needs to be resolved]
278
+
279
+ ## Investigation Summary
280
+ - **Time Spent**: [Hours invested]
281
+ - **Approaches Tried**: [List of debugging attempts]
282
+ - **Current Status**: [Where you're stuck]
283
+
284
+ ## Technical Details
285
+ - **Error Messages**: [Exact error text]
286
+ - **Reproduction Steps**: [How to reproduce]
287
+ - **Environment**: [System details]
288
+
289
+ ## Requested Help
290
+ - **Specific Question**: [What you need help with]
291
+ - **Suggested Approach**: [Your ideas, if any]
292
+ - **Resources Needed**: [Additional access, tools, etc.]
293
+ ```
294
+
295
+ ## CONTINUOUS IMPROVEMENT
296
+
297
+ ### Post-Debug Review
298
+ After resolving any significant issue:
299
+ 1. **Document the solution** in team knowledge base
300
+ 2. **Update debugging runbooks** with new patterns
301
+ 3. **Improve monitoring** to catch similar issues earlier
302
+ 4. **Share learnings** with team in retrospectives
303
+ 5. **Update automated tests** to prevent regression
304
+
305
+ ### Pattern Recognition
306
+ Keep track of:
307
+ - **Common failure modes** in your system
308
+ - **Effective debugging techniques** for different issue types
309
+ - **Tools and commands** that consistently help
310
+ - **Environmental factors** that contribute to issues
311
+ - **Time patterns** when issues typically occur
312
+
313
+ This systematic approach ensures that every debugging session contributes to the overall system reliability and team knowledge.
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ import { execSync } from 'child_process';
4
+ import dotenv from 'dotenv';
5
+
6
+ // Load environment variables
7
+ dotenv.config({ override: true });
8
+
9
+ interface CleanupOptions {
10
+ branchName?: string;
11
+ force?: boolean;
12
+ skipProjectCleanup?: boolean;
13
+ skipGit?: boolean;
14
+ }
15
+
16
+ class BranchCleanup {
17
+ private options: CleanupOptions;
18
+
19
+ constructor(options: CleanupOptions = {}) {
20
+ this.options = {
21
+ branchName: options.branchName,
22
+ force: options.force || false,
23
+ skipProjectCleanup: options.skipProjectCleanup || false,
24
+ skipGit: options.skipGit || false,
25
+ };
26
+ }
27
+
28
+ private async insertYourCodeHere(branchName: string): Promise<void> {
29
+ // add project specific cleanup code here
30
+ }
31
+
32
+
33
+ private log(message: string, level: 'info' | 'warn' | 'error' | 'success' = 'info') {
34
+ const timestamp = new Date().toISOString();
35
+ const prefix = {
36
+ info: 'ℹ️ ',
37
+ warn: '⚠️ ',
38
+ error: '❌',
39
+ success: '✅'
40
+ }[level];
41
+
42
+ console.log(`${prefix} [${timestamp}] ${message}`);
43
+ }
44
+
45
+ private async executeCommand(command: string, description: string): Promise<string> {
46
+ this.log(`Executing: ${description}`);
47
+
48
+ try {
49
+ const result = execSync(command, {
50
+ encoding: 'utf8',
51
+ stdio: 'pipe',
52
+ cwd: process.cwd()
53
+ });
54
+ this.log(`Success: ${description}`, 'success');
55
+ return result;
56
+ } catch (error: any) {
57
+ this.log(`Failed: ${description} - ${error.message}`, 'error');
58
+ throw error;
59
+ }
60
+ }
61
+
62
+ private async getCurrentBranch(): Promise<string> {
63
+ try {
64
+ const result = await this.executeCommand('git branch --show-current', 'Get current branch');
65
+ return result.trim();
66
+ } catch (error) {
67
+ this.log('Could not determine current branch', 'warn');
68
+ return 'unknown';
69
+ }
70
+ }
71
+
72
+ private async getBranchName(): Promise<string> {
73
+ if (this.options.branchName) {
74
+ return this.options.branchName;
75
+ }
76
+
77
+ const currentBranch = await this.getCurrentBranch();
78
+ if (currentBranch === 'master' || currentBranch === 'main') {
79
+ throw new Error('Cannot cleanup master/main branch. Please specify a feature branch name.');
80
+ }
81
+
82
+ return currentBranch;
83
+ }
84
+
85
+ private async checkBranchExists(branchName: string, remote: boolean = false): Promise<boolean> {
86
+ try {
87
+ const command = remote
88
+ ? `git ls-remote --heads origin ${branchName}`
89
+ : `git branch --list ${branchName}`;
90
+
91
+ const result = await this.executeCommand(command, `Check if ${remote ? 'remote' : 'local'} branch exists`);
92
+ return result.trim().length > 0;
93
+ } catch (error) {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ private async doProjectSpecificCleanup(branchName: string): Promise<void> {
99
+ try {
100
+ if (this.options.skipProjectCleanup) {
101
+ this.log('Skipping project-specific cleanup', 'warn');
102
+ return;
103
+ }
104
+
105
+ this.log('Starting project-specific cleanup...');
106
+
107
+ await this.insertYourCodeHere(branchName);
108
+
109
+ this.log('Project-specific cleanup completed successfully', 'success');
110
+ } catch (error: any) {
111
+ this.log(`Project-specific cleanup failed: ${error.message}`, 'error');
112
+ if (!this.options.force) {
113
+ throw error;
114
+ }
115
+ }
116
+ }
117
+
118
+ private async cleanupGitBranches(branchName: string): Promise<void> {
119
+ if (this.options.skipGit) {
120
+ this.log('Skipping Git cleanup', 'warn');
121
+ return;
122
+ }
123
+
124
+ this.log(`Starting Git branch cleanup for: ${branchName}`);
125
+
126
+ // Check if we're on the branch we want to delete
127
+ const currentBranch = await this.getCurrentBranch();
128
+ if (currentBranch === branchName) {
129
+ this.log(`Currently on branch ${branchName}, switching to master first`, 'warn');
130
+ await this.executeCommand('git checkout master', 'Switch to master branch');
131
+ }
132
+
133
+ // Delete remote branch
134
+ const remoteExists = await this.checkBranchExists(branchName, true);
135
+ if (remoteExists) {
136
+ this.log(`Deleting remote branch: origin/${branchName}`);
137
+ await this.executeCommand(`git push origin --delete ${branchName}`, `Delete remote branch ${branchName}`);
138
+ } else {
139
+ this.log(`Remote branch origin/${branchName} does not exist`, 'info');
140
+ }
141
+
142
+ // Delete local branch
143
+ const localExists = await this.checkBranchExists(branchName, false);
144
+ if (localExists) {
145
+ this.log(`Deleting local branch: ${branchName}`);
146
+ await this.executeCommand(`git branch -D ${branchName}`, `Delete local branch ${branchName}`);
147
+ } else {
148
+ this.log(`Local branch ${branchName} does not exist`, 'info');
149
+ }
150
+
151
+ // Clean up any untracked files
152
+ this.log('Cleaning up untracked files...');
153
+ await this.executeCommand('git clean -fd', 'Remove untracked files and directories');
154
+
155
+ // Reset any uncommitted changes
156
+ this.log('Resetting uncommitted changes...');
157
+ await this.executeCommand('git reset --hard HEAD', 'Reset to HEAD');
158
+
159
+ this.log('Git branch cleanup completed', 'success');
160
+ }
161
+
162
+
163
+ private async verifyCleanup(branchName: string): Promise<void> {
164
+ this.log('Verifying cleanup...');
165
+
166
+ // Verify branch deletion
167
+ const remoteExists = await this.checkBranchExists(branchName, true);
168
+ const localExists = await this.checkBranchExists(branchName, false);
169
+
170
+ if (remoteExists || localExists) {
171
+ this.log(`Warning: Branch ${branchName} still exists (remote: ${remoteExists}, local: ${localExists})`, 'warn');
172
+ } else {
173
+ this.log(`Branch ${branchName} successfully deleted`, 'success');
174
+ }
175
+
176
+ // Verify we're on master
177
+ const currentBranch = await this.getCurrentBranch();
178
+ if (currentBranch === 'master' || currentBranch === 'main') {
179
+ this.log('Currently on master/main branch', 'success');
180
+ } else {
181
+ this.log(`Warning: Not on master branch, currently on ${currentBranch}`, 'warn');
182
+ }
183
+
184
+ this.log('Cleanup verification completed', 'success');
185
+ }
186
+
187
+ async cleanup(): Promise<void> {
188
+ try {
189
+ this.log('🚀 Starting branch cleanup process...');
190
+
191
+ const branchName = await this.getBranchName();
192
+ this.log(`Target branch: ${branchName}`);
193
+
194
+ // Step 1: Project-specific cleanup
195
+ await this.doProjectSpecificCleanup(branchName);
196
+
197
+ // Step 2: Git branch cleanup
198
+ await this.cleanupGitBranches(branchName);
199
+
200
+ // Step 3: Verification
201
+ await this.verifyCleanup(branchName);
202
+
203
+ this.log('🎉 Branch cleanup completed successfully!', 'success');
204
+
205
+ } catch (error: any) {
206
+ this.log(`Cleanup failed: ${error.message}`, 'error');
207
+ if (!this.options.force) {
208
+ process.exit(1);
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ // Parse command line arguments
215
+ const args = process.argv.slice(2);
216
+ const options: CleanupOptions = {};
217
+
218
+ // Parse arguments
219
+ for (let i = 0; i < args.length; i++) {
220
+ const arg = args[i];
221
+
222
+ switch (arg) {
223
+ case '--branch':
224
+ case '-b':
225
+ options.branchName = args[++i];
226
+ break;
227
+ case '--force':
228
+ case '-f':
229
+ options.force = true;
230
+ break;
231
+ case '--skip-project-cleanup':
232
+ options.skipProjectCleanup = true;
233
+ break;
234
+ case '--skip-git':
235
+ options.skipGit = true;
236
+ break;
237
+ case '--help':
238
+ case '-h':
239
+ console.log(`
240
+ 🧹 Branch Cleanup Script
241
+
242
+ Usage:
243
+ npx tsx .ai-agents/scripts/cleanup-branch.ts [options]
244
+
245
+ Options:
246
+ --branch, -b <name> Specific branch name to cleanup (default: current branch)
247
+ --force, -f Continue even if some operations fail
248
+ --skip-project-cleanup Skip project-specific cleanup
249
+ --skip-git Skip Git branch deletion
250
+ --help, -h Show this help message
251
+
252
+ Examples:
253
+ # Cleanup current branch with default settings
254
+ npx tsx .ai-agents/scripts/cleanup-branch.ts
255
+
256
+ # Cleanup specific branch
257
+ npx tsx .ai-agents/scripts/cleanup-branch.ts --branch feature/123
258
+
259
+ # Force cleanup even if some operations fail
260
+ npx tsx .ai-agents/scripts/cleanup-branch.ts --force
261
+
262
+ # Skip project-specific cleanup (only do Git cleanup)
263
+ npx tsx .ai-agents/scripts/cleanup-branch.ts --skip-project-cleanup
264
+
265
+ This script performs the following cleanup operations:
266
+ 1. 🗄️ Project-specific cleanup (calls existing cleanup-mongo-schemas.ts with branch-based pattern)
267
+ 2. 🌿 Git branch deletion (remote and local)
268
+ 3. ✅ Verification of cleanup completion
269
+
270
+ ⚠️ WARNING: This script will permanently delete branches and data!
271
+ `);
272
+ process.exit(0);
273
+ }
274
+ }
275
+
276
+ // Run the cleanup
277
+ const cleanup = new BranchCleanup(options);
278
+ cleanup.cleanup();
@@ -0,0 +1,122 @@
1
+ import { spawn } from "child_process";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import fg from "fast-glob";
5
+ import kill from "tree-kill";
6
+ import os from "os";
7
+
8
+ function parseArgs(argv: string[]) {
9
+ const out: any = { cmd: [], timeout: 120, logfile: "run.log" };
10
+ let parsingCmd = false;
11
+
12
+ for (let i = 0; i < argv.length; i++) {
13
+ const a = argv[i];
14
+
15
+ if (!parsingCmd) {
16
+ if (a === "--timeout" && argv[i + 1]) {
17
+ out.timeout = parseInt(argv[++i], 10);
18
+ } else if (a.startsWith("--timeout=")) {
19
+ out.timeout = parseInt(a.split("=")[1], 10);
20
+ } else if (a === "--logfile" && argv[i + 1]) {
21
+ out.logfile = argv[++i];
22
+ } else if (a.startsWith("--logfile=")) {
23
+ out.logfile = a.split("=")[1];
24
+ } else if (a === "--") {
25
+ parsingCmd = true; // everything after this is command
26
+ } else {
27
+ parsingCmd = true;
28
+ out.cmd.push(a);
29
+ }
30
+ } else {
31
+ out.cmd.push(a);
32
+ }
33
+ }
34
+
35
+ return out;
36
+ }
37
+
38
+ async function main() {
39
+ const args = parseArgs(process.argv.slice(2));
40
+ if (!args.cmd.length) {
41
+ console.error(
42
+ "Usage: exec-with-timeout <cmd> [args...] [--timeout 120] [--logfile run.log]"
43
+ );
44
+ process.exit(2);
45
+ }
46
+
47
+ const logPath = path.resolve(process.cwd(), args.logfile);
48
+ const out = fs.createWriteStream(logPath, { flags: "a" });
49
+ out.write(
50
+ `\n--- RUN: ${args.cmd.join(" ")} @ ${new Date().toISOString()} (timeout ${
51
+ args.timeout
52
+ }s) ---\n`
53
+ );
54
+
55
+ // Expand globs (e.g. test*.ts)
56
+ let [cmd, ...argv] = args.cmd;
57
+ let expanded: string[] = [];
58
+ for (const a of argv) {
59
+ if (a.includes("*")) {
60
+ const matches = await fg(a);
61
+ expanded.push(...matches);
62
+ } else {
63
+ expanded.push(a);
64
+ }
65
+ }
66
+
67
+ let child;
68
+ if (os.platform() === "win32" && (cmd === "npm" || cmd === "npx")) {
69
+ // On Windows, run the full command line with shell
70
+ const fullCommand = [cmd, ...expanded].join(" ");
71
+ child = spawn(fullCommand, { stdio: ["ignore", "pipe", "pipe"], shell: true });
72
+ } else {
73
+ // On Linux/Mac, do it the normal way
74
+ child = spawn(cmd, expanded, { stdio: ["ignore", "pipe", "pipe"] });
75
+ }
76
+
77
+
78
+
79
+ child.stdout.on("data", (d) => {
80
+ process.stdout.write(d);
81
+ out.write(d);
82
+ });
83
+
84
+ child.stderr.on("data", (d) => {
85
+ process.stderr.write(d);
86
+ out.write(d);
87
+ });
88
+
89
+ let timedOut = false;
90
+ const timer = setTimeout(() => {
91
+ timedOut = true;
92
+ out.write(
93
+ `\n[exec-with-timeout] TIMEOUT after ${args.timeout}s → killing process tree\n`
94
+ );
95
+ kill(child.pid!, "SIGTERM");
96
+
97
+ setTimeout(() => {
98
+ try {
99
+ kill(child.pid!, "SIGKILL");
100
+ } catch {}
101
+ }, 2000);
102
+ }, args.timeout * 1000);
103
+
104
+ child.on("exit", (code, signal) => {
105
+ clearTimeout(timer);
106
+ out.write(
107
+ `\n--- EXIT: code=${code} signal=${signal} timedOut=${timedOut} ---\n`
108
+ );
109
+ out.end();
110
+
111
+ if (timedOut) {
112
+ console.error(`[guard] Command timed out: ${args.cmd.join(" ")}`);
113
+ process.exit(124);
114
+ }
115
+ process.exit(code === null ? 1 : code);
116
+ });
117
+ }
118
+
119
+ main().catch((err) => {
120
+ console.error(err);
121
+ process.exit(1);
122
+ });