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.
- package/.ai-agents/agent-guardrails.md +58 -0
- package/.ai-agents/mcp-template.jsonc +34 -0
- package/.ai-agents/rules/agent-testing-guidelines.md +545 -0
- package/.ai-agents/rules/architecture.md +52 -0
- package/.ai-agents/rules/communication.md +122 -0
- package/.ai-agents/rules/continuous-learning.md +55 -0
- package/.ai-agents/rules/git-safe-commands.md +34 -0
- package/.ai-agents/rules/integrity-and-test-ethics.md +223 -0
- package/.ai-agents/rules/local-development.md +252 -0
- package/.ai-agents/rules/merge-requirements.md +231 -0
- package/.ai-agents/rules/pr-workflow-completeness.md +191 -0
- package/.ai-agents/rules/simplicity.md +112 -0
- package/.ai-agents/rules/software-development-lifecycle.md +276 -0
- package/.ai-agents/rules/spike-first-development.md +199 -0
- package/.ai-agents/rules/successful-debugging-patterns.md +313 -0
- package/.ai-agents/scripts/cleanup-branch.ts +278 -0
- package/.ai-agents/scripts/exec-with-timeout.ts +122 -0
- package/.ai-agents/scripts/prep-issue.sh +162 -0
- package/.ai-agents/templates/evidence/Design-Evidence.md +30 -0
- package/.ai-agents/templates/evidence/Implementation-BugEvidence.md +48 -0
- package/.ai-agents/templates/evidence/Implementation-FeatureEvidence.md +54 -0
- package/.ai-agents/templates/evidence/Spec-Evidence.md +19 -0
- package/.ai-agents/templates/help/HelpNeeded.md +14 -0
- package/.ai-agents/templates/retrospective/RETROSPECTIVE-TEMPLATE.md +55 -0
- package/.ai-agents/templates/specs/BUGSPEC-TEMPLATE.md +37 -0
- package/.ai-agents/templates/specs/FEATURESPEC-TEMPLATE.md +29 -0
- package/.ai-agents/templates/specs/TECHSPEC-TEMPLATE.md +39 -0
- package/.ai-agents/workflows/design.md +121 -0
- package/.ai-agents/workflows/implement.md +170 -0
- package/.ai-agents/workflows/resolve.md +152 -0
- package/.ai-agents/workflows/retrospect.md +84 -0
- package/.ai-agents/workflows/spec.md +103 -0
- package/.ai-agents/workflows/test.md +90 -0
- package/.cursor/rules/cursor-rules.mdc +8 -0
- package/.cursor/rules/design.mdc +4 -0
- package/.cursor/rules/implement.mdc +6 -0
- package/.cursor/rules/resolve.mdc +5 -0
- package/.cursor/rules/retrospect.mdc +4 -0
- package/.cursor/rules/spec.mdc +4 -0
- package/.cursor/rules/test.mdc +5 -0
- package/.windsurf/rules/windsurf-rules.md +7 -0
- package/.windsurf/workflows/resolve-issue.md +6 -0
- package/.windsurf/workflows/retrospect.md +6 -0
- package/.windsurf/workflows/start-design.md +6 -0
- package/.windsurf/workflows/start-impl.md +6 -0
- package/.windsurf/workflows/start-spec.md +6 -0
- package/.windsurf/workflows/start-tests.md +6 -0
- package/CHANGELOG.md +66 -0
- package/CODEOWNERS +24 -0
- package/DISTRIBUTION.md +6 -6
- package/PUBLISH_INSTRUCTIONS.md +93 -0
- package/README.md +330 -104
- package/bin/fraim.js +49 -3
- package/index.js +30 -3
- package/install.sh +58 -58
- package/labels.json +52 -0
- package/linkedin-post.md +23 -0
- package/package.json +12 -7
- package/sample_package.json +18 -0
- package/setup.js +733 -384
- package/test-utils.ts +118 -0
- package/tsconfig.json +22 -0
- package/agents/claude/CLAUDE.md +0 -42
- package/agents/cursor/rules/architecture.mdc +0 -49
- package/agents/cursor/rules/continuous-learning.mdc +0 -48
- package/agents/cursor/rules/cursor-workflow.mdc +0 -29
- package/agents/cursor/rules/design.mdc +0 -25
- package/agents/cursor/rules/implement.mdc +0 -26
- package/agents/cursor/rules/local-development.mdc +0 -104
- package/agents/cursor/rules/prep.mdc +0 -15
- package/agents/cursor/rules/resolve.mdc +0 -46
- package/agents/cursor/rules/simplicity.mdc +0 -18
- package/agents/cursor/rules/software-development-lifecycle.mdc +0 -41
- package/agents/cursor/rules/test.mdc +0 -25
- package/agents/windsurf/rules/architecture.md +0 -49
- package/agents/windsurf/rules/continuous-learning.md +0 -47
- package/agents/windsurf/rules/local-development.md +0 -103
- package/agents/windsurf/rules/remote-development.md +0 -22
- package/agents/windsurf/rules/simplicity.md +0 -17
- package/agents/windsurf/rules/windsurf-workflow.md +0 -28
- package/agents/windsurf/workflows/prep.md +0 -20
- package/agents/windsurf/workflows/resolve-issue.md +0 -47
- package/agents/windsurf/workflows/start-design.md +0 -26
- package/agents/windsurf/workflows/start-impl.md +0 -27
- package/agents/windsurf/workflows/start-tests.md +0 -26
- package/github/phase-change.yml +0 -218
- package/github/status-change.yml +0 -68
- package/github/sync-on-pr-review.yml +0 -66
- package/scripts/__init__.py +0 -10
- package/scripts/cli.py +0 -141
- package/setup.py +0 -0
- package/test-config.json +0 -32
- 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
|
+
});
|