vibecodingmachine-core 2025.12.25-1541 → 2026.1.3-2209
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/ERROR_REPORTING_API.md +212 -0
- package/ERROR_REPORTING_USAGE.md +380 -0
- package/__tests__/utils/git-branch-manager.test.js +61 -0
- package/package.json +1 -1
- package/src/database/user-database-client.js +26 -0
- package/src/database/user-schema.js +7 -0
- package/src/ide-integration/applescript-manager.cjs +26 -6
- package/src/ide-integration/applescript-manager.js +6 -5
- package/src/ide-integration/applescript-utils.js +26 -18
- package/src/index.cjs +4 -0
- package/src/index.js +4 -0
- package/src/localization/translations/en.js +2 -0
- package/src/localization/translations/es.js +2 -0
- package/src/requirement-numbering.js +164 -0
- package/src/utils/error-reporter.js +109 -0
- package/src/utils/git-branch-manager.js +278 -0
- package/src/utils/requirement-helpers.js +10 -1
- package/src/utils/requirements-parser.js +25 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Error Reporting API Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The error reporting system automatically sends error information to the admin database when the CLI or GUI encounters errors. This allows the admin to track issues and use VibeCodingMachine to fix itself.
|
|
6
|
+
|
|
7
|
+
## Client Implementation
|
|
8
|
+
|
|
9
|
+
The client-side error reporting is implemented in:
|
|
10
|
+
- `packages/core/src/utils/error-reporter.js` - Error reporter utility
|
|
11
|
+
- `packages/core/src/database/user-database-client.js` - API client with `reportError()` method
|
|
12
|
+
- `packages/cli/bin/vibecodingmachine.js` - Global error handlers
|
|
13
|
+
|
|
14
|
+
## API Endpoint Required
|
|
15
|
+
|
|
16
|
+
### POST /api/errors/report
|
|
17
|
+
|
|
18
|
+
Reports an error to the admin database for tracking and fixing.
|
|
19
|
+
|
|
20
|
+
**Authentication**: Required (Bearer token)
|
|
21
|
+
|
|
22
|
+
**Request Body**:
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"message": "The \"path\" argument must be of type string. Received null",
|
|
26
|
+
"stack": "TypeError: The \"path\" argument must be of type string...",
|
|
27
|
+
"name": "TypeError",
|
|
28
|
+
"code": "ERR_INVALID_ARG_TYPE",
|
|
29
|
+
"timestamp": 1704326400000,
|
|
30
|
+
"hostname": "Jesses-MacBook-Pro.local",
|
|
31
|
+
"platform": "darwin",
|
|
32
|
+
"arch": "arm64",
|
|
33
|
+
"nodeVersion": "v18.17.0",
|
|
34
|
+
"context": {
|
|
35
|
+
"command": "addRemoteRequirement",
|
|
36
|
+
"computerId": "OLSEN2018PC",
|
|
37
|
+
"requirementText": "Fix the login bug",
|
|
38
|
+
"cwd": "/Users/jesseolsen/repos/mediawink/allnightai",
|
|
39
|
+
"argv": ["computer:add-requirement", "OLSEN2018PC", "Fix the login bug"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Response**:
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"success": true,
|
|
48
|
+
"errorId": "err_abc123xyz"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Error Response**:
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"error": "Failed to report error",
|
|
56
|
+
"details": "Database connection failed"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Database Schema
|
|
61
|
+
|
|
62
|
+
The error reports should be stored in a DynamoDB table with the following structure:
|
|
63
|
+
|
|
64
|
+
**Table Name**: `vibecodingmachine-errors`
|
|
65
|
+
|
|
66
|
+
**Primary Key**:
|
|
67
|
+
- `errorId` (String) - Unique error identifier (generated server-side)
|
|
68
|
+
|
|
69
|
+
**Attributes**:
|
|
70
|
+
- `userId` (String) - User ID from auth token
|
|
71
|
+
- `email` (String) - User email
|
|
72
|
+
- `timestamp` (Number) - Unix timestamp when error occurred
|
|
73
|
+
- `message` (String) - Error message
|
|
74
|
+
- `stack` (String) - Error stack trace
|
|
75
|
+
- `name` (String) - Error name/type
|
|
76
|
+
- `code` (String) - Error code (if available)
|
|
77
|
+
- `hostname` (String) - Computer hostname
|
|
78
|
+
- `platform` (String) - OS platform (darwin, win32, linux)
|
|
79
|
+
- `arch` (String) - CPU architecture
|
|
80
|
+
- `nodeVersion` (String) - Node.js version
|
|
81
|
+
- `context` (Map) - Additional context about the error
|
|
82
|
+
- `status` (String) - Error status: "NEW", "INVESTIGATING", "FIXED", "IGNORED"
|
|
83
|
+
- `reportedAt` (Number) - Server timestamp when error was reported
|
|
84
|
+
|
|
85
|
+
**GSI (Global Secondary Index)**:
|
|
86
|
+
- `userId-timestamp-index` - For querying errors by user and time
|
|
87
|
+
- `status-timestamp-index` - For querying errors by status
|
|
88
|
+
|
|
89
|
+
## Server Implementation Required
|
|
90
|
+
|
|
91
|
+
The API server needs to implement the `/api/errors/report` endpoint:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
// Example implementation (pseudo-code)
|
|
95
|
+
app.post('/api/errors/report', authenticateToken, async (req, res) => {
|
|
96
|
+
try {
|
|
97
|
+
const userId = req.user.userId;
|
|
98
|
+
const email = req.user.email;
|
|
99
|
+
|
|
100
|
+
const errorId = generateErrorId(); // e.g., 'err_' + crypto.randomBytes(8).toString('hex')
|
|
101
|
+
|
|
102
|
+
const errorReport = {
|
|
103
|
+
errorId,
|
|
104
|
+
userId,
|
|
105
|
+
email,
|
|
106
|
+
...req.body,
|
|
107
|
+
status: 'NEW',
|
|
108
|
+
reportedAt: Date.now()
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Save to DynamoDB
|
|
112
|
+
await dynamodb.put({
|
|
113
|
+
TableName: 'vibecodingmachine-errors',
|
|
114
|
+
Item: errorReport
|
|
115
|
+
}).promise();
|
|
116
|
+
|
|
117
|
+
res.json({ success: true, errorId });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
res.status(500).json({
|
|
120
|
+
error: 'Failed to report error',
|
|
121
|
+
details: error.message
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Usage Examples
|
|
128
|
+
|
|
129
|
+
### Automatic Error Reporting (Global Handlers)
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
// In CLI entry point
|
|
133
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
134
|
+
|
|
135
|
+
// Initialize with auth token
|
|
136
|
+
const token = await auth.getAuthToken();
|
|
137
|
+
errorReporter.setAuthToken(token);
|
|
138
|
+
|
|
139
|
+
// Global handlers automatically report errors
|
|
140
|
+
process.on('uncaughtException', async (error) => {
|
|
141
|
+
await errorReporter.reportError(error, { type: 'uncaughtException' });
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Manual Error Reporting
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
// Some operation that might fail
|
|
152
|
+
await addRemoteRequirement(computerId, requirementText);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
// Report error with context
|
|
155
|
+
await errorReporter.reportError(error, {
|
|
156
|
+
command: 'addRemoteRequirement',
|
|
157
|
+
computerId,
|
|
158
|
+
requirementText
|
|
159
|
+
});
|
|
160
|
+
throw error; // Re-throw to show user
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Wrapping Functions
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
168
|
+
|
|
169
|
+
// Wrap a function to automatically report errors
|
|
170
|
+
const safeFunction = errorReporter.wrapFunction(
|
|
171
|
+
async (arg1, arg2) => {
|
|
172
|
+
// Function implementation
|
|
173
|
+
},
|
|
174
|
+
{ functionName: 'myFunction' }
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Admin Dashboard Integration
|
|
179
|
+
|
|
180
|
+
The admin dashboard should display error reports with:
|
|
181
|
+
- List of all errors (filterable by status, user, date)
|
|
182
|
+
- Error details view (message, stack, context)
|
|
183
|
+
- Ability to change error status
|
|
184
|
+
- Statistics (errors per day, most common errors)
|
|
185
|
+
- Link to create a requirement/issue from an error
|
|
186
|
+
|
|
187
|
+
## Privacy Considerations
|
|
188
|
+
|
|
189
|
+
The error reporter automatically filters sensitive information:
|
|
190
|
+
- Passwords, tokens, and secrets are removed from arguments
|
|
191
|
+
- Only non-sensitive context is included
|
|
192
|
+
- Stack traces may contain file paths but not file contents
|
|
193
|
+
|
|
194
|
+
## Testing
|
|
195
|
+
|
|
196
|
+
To test error reporting:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Trigger an error in the CLI
|
|
200
|
+
vcm computer:add-requirement TESTPC null
|
|
201
|
+
|
|
202
|
+
# Check that error was reported
|
|
203
|
+
# (Admin dashboard should show the error)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Future Enhancements
|
|
207
|
+
|
|
208
|
+
- Automatic error grouping (similar errors grouped together)
|
|
209
|
+
- Error frequency tracking
|
|
210
|
+
- Automatic issue creation in GitHub
|
|
211
|
+
- Email notifications for critical errors
|
|
212
|
+
- Error trend analysis
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Error Reporting Usage Guide
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
### 1. Import the Error Reporter
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### 2. Initialize with Auth Token
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const auth = require('./utils/auth');
|
|
15
|
+
const token = await auth.getAuthToken();
|
|
16
|
+
if (token) {
|
|
17
|
+
errorReporter.setAuthToken(token);
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 3. Report Errors
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
try {
|
|
25
|
+
// Your code here
|
|
26
|
+
await someOperation();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// Report error with context
|
|
29
|
+
await errorReporter.reportError(error, {
|
|
30
|
+
command: 'someOperation',
|
|
31
|
+
additionalContext: 'value'
|
|
32
|
+
});
|
|
33
|
+
throw error; // Re-throw to show user
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage Patterns
|
|
38
|
+
|
|
39
|
+
### Pattern 1: Try-Catch with Error Reporting
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
async function addRemoteRequirement(computerId, requirementText) {
|
|
43
|
+
try {
|
|
44
|
+
// Operation that might fail
|
|
45
|
+
const result = await performOperation(computerId, requirementText);
|
|
46
|
+
return result;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error(chalk.red('✗ Operation failed:'), error.message);
|
|
49
|
+
|
|
50
|
+
// Report error with context
|
|
51
|
+
await errorReporter.reportError(error, {
|
|
52
|
+
command: 'addRemoteRequirement',
|
|
53
|
+
computerId,
|
|
54
|
+
requirementText
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
throw error; // Re-throw to maintain error flow
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Pattern 2: Global Error Handlers
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// In your main entry point
|
|
66
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
67
|
+
|
|
68
|
+
// Initialize with auth token
|
|
69
|
+
const token = await auth.getAuthToken();
|
|
70
|
+
if (token) {
|
|
71
|
+
errorReporter.setAuthToken(token);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Setup global handlers
|
|
75
|
+
process.on('uncaughtException', async (error) => {
|
|
76
|
+
console.error('Uncaught Exception:', error);
|
|
77
|
+
await errorReporter.reportError(error, {
|
|
78
|
+
type: 'uncaughtException'
|
|
79
|
+
});
|
|
80
|
+
process.exit(1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
process.on('unhandledRejection', async (error) => {
|
|
84
|
+
console.error('Unhandled Rejection:', error);
|
|
85
|
+
await errorReporter.reportError(error, {
|
|
86
|
+
type: 'unhandledRejection'
|
|
87
|
+
});
|
|
88
|
+
process.exit(1);
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Pattern 3: Function Wrapping
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
96
|
+
|
|
97
|
+
// Wrap a function to automatically report errors
|
|
98
|
+
const safeOperation = errorReporter.wrapFunction(
|
|
99
|
+
async (arg1, arg2) => {
|
|
100
|
+
// Your function implementation
|
|
101
|
+
return await performOperation(arg1, arg2);
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
functionName: 'performOperation',
|
|
105
|
+
module: 'operations'
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Use the wrapped function
|
|
110
|
+
try {
|
|
111
|
+
await safeOperation('value1', 'value2');
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// Error was already reported automatically
|
|
114
|
+
console.error('Operation failed:', error.message);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Pattern 4: Conditional Error Reporting
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
122
|
+
|
|
123
|
+
// Enable/disable error reporting
|
|
124
|
+
errorReporter.setEnabled(true); // Enable
|
|
125
|
+
errorReporter.setEnabled(false); // Disable
|
|
126
|
+
|
|
127
|
+
// Example: Disable in development
|
|
128
|
+
if (process.env.NODE_ENV === 'development') {
|
|
129
|
+
errorReporter.setEnabled(false);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Context Best Practices
|
|
134
|
+
|
|
135
|
+
### Good Context Examples
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
// ✅ GOOD - Includes relevant context
|
|
139
|
+
await errorReporter.reportError(error, {
|
|
140
|
+
command: 'addRemoteRequirement',
|
|
141
|
+
computerId: 'OLSEN2018PC',
|
|
142
|
+
requirementText: 'Fix the login bug',
|
|
143
|
+
operation: 'file_write'
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ✅ GOOD - Includes user action context
|
|
147
|
+
await errorReporter.reportError(error, {
|
|
148
|
+
action: 'sync',
|
|
149
|
+
syncDirection: 'upload',
|
|
150
|
+
fileCount: 5,
|
|
151
|
+
retryAttempt: 2
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Bad Context Examples
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// ❌ BAD - Includes sensitive information
|
|
159
|
+
await errorReporter.reportError(error, {
|
|
160
|
+
password: 'secret123', // Don't include passwords!
|
|
161
|
+
apiKey: 'abc123xyz' // Don't include API keys!
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// ❌ BAD - Too much unnecessary data
|
|
165
|
+
await errorReporter.reportError(error, {
|
|
166
|
+
entireFileContents: fs.readFileSync('large-file.txt'),
|
|
167
|
+
allEnvironmentVariables: process.env
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// ❌ BAD - No context at all
|
|
171
|
+
await errorReporter.reportError(error);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## What Gets Reported Automatically
|
|
175
|
+
|
|
176
|
+
The error reporter automatically includes:
|
|
177
|
+
|
|
178
|
+
- **Error Information**:
|
|
179
|
+
- `message` - Error message
|
|
180
|
+
- `stack` - Stack trace
|
|
181
|
+
- `name` - Error type (TypeError, ReferenceError, etc.)
|
|
182
|
+
- `code` - Error code (if available)
|
|
183
|
+
|
|
184
|
+
- **System Information**:
|
|
185
|
+
- `timestamp` - When error occurred
|
|
186
|
+
- `hostname` - Computer hostname
|
|
187
|
+
- `platform` - OS platform (darwin, win32, linux)
|
|
188
|
+
- `arch` - CPU architecture (x64, arm64)
|
|
189
|
+
- `nodeVersion` - Node.js version
|
|
190
|
+
|
|
191
|
+
- **Context Information**:
|
|
192
|
+
- `cwd` - Current working directory
|
|
193
|
+
- `argv` - Command line arguments (filtered for sensitive data)
|
|
194
|
+
- Any custom context you provide
|
|
195
|
+
|
|
196
|
+
## Privacy & Security
|
|
197
|
+
|
|
198
|
+
The error reporter automatically filters sensitive information:
|
|
199
|
+
|
|
200
|
+
- Passwords
|
|
201
|
+
- Tokens
|
|
202
|
+
- Secrets
|
|
203
|
+
- API keys
|
|
204
|
+
- Authentication credentials
|
|
205
|
+
|
|
206
|
+
**Example**:
|
|
207
|
+
```javascript
|
|
208
|
+
// These will be filtered out automatically
|
|
209
|
+
const args = ['--password=secret', '--token=abc123'];
|
|
210
|
+
await errorReporter.reportError(error, { args });
|
|
211
|
+
// Reported args will be filtered
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Testing Error Reporting
|
|
215
|
+
|
|
216
|
+
### Test 1: Manual Error
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
220
|
+
|
|
221
|
+
// Initialize
|
|
222
|
+
const token = await auth.getAuthToken();
|
|
223
|
+
errorReporter.setAuthToken(token);
|
|
224
|
+
|
|
225
|
+
// Create and report a test error
|
|
226
|
+
const testError = new Error('Test error for reporting');
|
|
227
|
+
testError.code = 'TEST_ERROR';
|
|
228
|
+
|
|
229
|
+
await errorReporter.reportError(testError, {
|
|
230
|
+
test: true,
|
|
231
|
+
purpose: 'testing error reporting system'
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log('Test error reported successfully');
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Test 2: Trigger Real Error
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Trigger an error in the CLI
|
|
241
|
+
vcm computer:add-requirement TESTPC null
|
|
242
|
+
|
|
243
|
+
# Check console output for error reporting
|
|
244
|
+
# Check admin dashboard for error report
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Troubleshooting
|
|
248
|
+
|
|
249
|
+
### Error Not Being Reported
|
|
250
|
+
|
|
251
|
+
1. **Check Authentication**:
|
|
252
|
+
```javascript
|
|
253
|
+
const token = await auth.getAuthToken();
|
|
254
|
+
console.log('Auth token:', token ? 'Present' : 'Missing');
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
2. **Check Error Reporter Status**:
|
|
258
|
+
```javascript
|
|
259
|
+
console.log('Error reporter enabled:', errorReporter.enabled);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
3. **Check Network**:
|
|
263
|
+
- Verify API server is running
|
|
264
|
+
- Check API endpoint URL
|
|
265
|
+
- Verify authentication token is valid
|
|
266
|
+
|
|
267
|
+
### Silent Failures
|
|
268
|
+
|
|
269
|
+
Error reporting is designed to fail silently to avoid disrupting the user experience. Check console warnings:
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
// Look for warnings like:
|
|
273
|
+
// "Failed to report error: Network error"
|
|
274
|
+
// "UserDatabase: reportError failed: ..."
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Integration with Other Systems
|
|
278
|
+
|
|
279
|
+
### Electron App
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
// In main process
|
|
283
|
+
const { errorReporter } = require('vibecodingmachine-core');
|
|
284
|
+
|
|
285
|
+
// Initialize with user's auth token
|
|
286
|
+
const token = await getUserAuthToken();
|
|
287
|
+
errorReporter.setAuthToken(token);
|
|
288
|
+
|
|
289
|
+
// Report renderer process errors
|
|
290
|
+
ipcMain.on('renderer-error', async (event, error) => {
|
|
291
|
+
await errorReporter.reportError(error, {
|
|
292
|
+
source: 'renderer',
|
|
293
|
+
window: event.sender.id
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Web Application
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
// In your React/Vue app
|
|
302
|
+
import { errorReporter } from 'vibecodingmachine-core';
|
|
303
|
+
|
|
304
|
+
// Initialize with user's auth token
|
|
305
|
+
const token = await getAuthToken();
|
|
306
|
+
errorReporter.setAuthToken(token);
|
|
307
|
+
|
|
308
|
+
// Report errors in error boundary
|
|
309
|
+
class ErrorBoundary extends React.Component {
|
|
310
|
+
componentDidCatch(error, errorInfo) {
|
|
311
|
+
errorReporter.reportError(error, {
|
|
312
|
+
source: 'react',
|
|
313
|
+
componentStack: errorInfo.componentStack
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## API Reference
|
|
320
|
+
|
|
321
|
+
### `errorReporter.setAuthToken(token)`
|
|
322
|
+
|
|
323
|
+
Set the authentication token for error reporting.
|
|
324
|
+
|
|
325
|
+
**Parameters**:
|
|
326
|
+
- `token` (string) - JWT authentication token
|
|
327
|
+
|
|
328
|
+
**Example**:
|
|
329
|
+
```javascript
|
|
330
|
+
const token = await auth.getAuthToken();
|
|
331
|
+
errorReporter.setAuthToken(token);
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### `errorReporter.setEnabled(enabled)`
|
|
335
|
+
|
|
336
|
+
Enable or disable error reporting.
|
|
337
|
+
|
|
338
|
+
**Parameters**:
|
|
339
|
+
- `enabled` (boolean) - True to enable, false to disable
|
|
340
|
+
|
|
341
|
+
**Example**:
|
|
342
|
+
```javascript
|
|
343
|
+
errorReporter.setEnabled(false); // Disable in development
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### `errorReporter.reportError(error, context)`
|
|
347
|
+
|
|
348
|
+
Report an error to the admin database.
|
|
349
|
+
|
|
350
|
+
**Parameters**:
|
|
351
|
+
- `error` (Error) - Error object to report
|
|
352
|
+
- `context` (Object) - Additional context about the error
|
|
353
|
+
|
|
354
|
+
**Returns**: Promise<boolean> - True if reported successfully
|
|
355
|
+
|
|
356
|
+
**Example**:
|
|
357
|
+
```javascript
|
|
358
|
+
await errorReporter.reportError(error, {
|
|
359
|
+
command: 'sync',
|
|
360
|
+
operation: 'upload'
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### `errorReporter.wrapFunction(fn, context)`
|
|
365
|
+
|
|
366
|
+
Wrap a function to automatically report errors.
|
|
367
|
+
|
|
368
|
+
**Parameters**:
|
|
369
|
+
- `fn` (Function) - Function to wrap
|
|
370
|
+
- `context` (Object) - Context to include in error reports
|
|
371
|
+
|
|
372
|
+
**Returns**: Function - Wrapped function
|
|
373
|
+
|
|
374
|
+
**Example**:
|
|
375
|
+
```javascript
|
|
376
|
+
const safeFunction = errorReporter.wrapFunction(
|
|
377
|
+
async (arg) => { /* ... */ },
|
|
378
|
+
{ functionName: 'myFunction' }
|
|
379
|
+
);
|
|
380
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { isGitRepo, getCurrentBranch, hasUncommittedChanges } = require('../../src/utils/git-branch-manager');
|
|
6
|
+
|
|
7
|
+
describe('git-branch-manager', () => {
|
|
8
|
+
let tempRepoPath;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
tempRepoPath = path.join(os.tmpdir(), `vcm-test-repo-${Date.now()}`);
|
|
12
|
+
await fs.ensureDir(tempRepoPath);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(async () => {
|
|
16
|
+
await fs.remove(tempRepoPath);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const initRepo = () => {
|
|
20
|
+
execSync('git init', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
21
|
+
execSync('git config user.email "test@example.com"', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
22
|
+
execSync('git config user.name "Test User"', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
test('isGitRepo identifies git repositories', () => {
|
|
26
|
+
expect(isGitRepo(tempRepoPath)).toBe(false);
|
|
27
|
+
initRepo();
|
|
28
|
+
expect(isGitRepo(tempRepoPath)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('getCurrentBranch returns the current branch name', async () => {
|
|
32
|
+
initRepo();
|
|
33
|
+
// Must commit something for HEAD to exist
|
|
34
|
+
await fs.writeFile(path.join(tempRepoPath, 'initial.txt'), 'init');
|
|
35
|
+
execSync('git add .', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
36
|
+
execSync('git commit -m "initial commit"', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
37
|
+
|
|
38
|
+
const branch = getCurrentBranch(tempRepoPath);
|
|
39
|
+
expect(branch).toMatch(/^(main|master)$/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('hasUncommittedChanges detects dirty repository', async () => {
|
|
43
|
+
initRepo();
|
|
44
|
+
// Should be false initially (even if empty)
|
|
45
|
+
expect(hasUncommittedChanges(tempRepoPath)).toBe(false);
|
|
46
|
+
|
|
47
|
+
// Create a file
|
|
48
|
+
await fs.writeFile(path.join(tempRepoPath, 'test.txt'), 'hello');
|
|
49
|
+
// Untracked file counts as uncommitted change
|
|
50
|
+
expect(hasUncommittedChanges(tempRepoPath)).toBe(true);
|
|
51
|
+
|
|
52
|
+
// Commit it
|
|
53
|
+
execSync('git add .', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
54
|
+
execSync('git commit -m "initial commit"', { cwd: tempRepoPath, stdio: 'ignore' });
|
|
55
|
+
expect(hasUncommittedChanges(tempRepoPath)).toBe(false);
|
|
56
|
+
|
|
57
|
+
// Modify it
|
|
58
|
+
await fs.appendFile(path.join(tempRepoPath, 'test.txt'), ' world');
|
|
59
|
+
expect(hasUncommittedChanges(tempRepoPath)).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
package/package.json
CHANGED
|
@@ -273,6 +273,32 @@ class UserDatabaseClient {
|
|
|
273
273
|
async isAdmin(userId) {
|
|
274
274
|
return false; // Client-side can't check admin status
|
|
275
275
|
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Report an error to the admin database for tracking and fixing
|
|
279
|
+
*/
|
|
280
|
+
async reportError(errorData) {
|
|
281
|
+
try {
|
|
282
|
+
const errorReport = {
|
|
283
|
+
timestamp: Date.now(),
|
|
284
|
+
hostname: os.hostname(),
|
|
285
|
+
platform: os.platform(),
|
|
286
|
+
arch: os.arch(),
|
|
287
|
+
nodeVersion: process.version,
|
|
288
|
+
...errorData
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
await this.apiRequest('/api/errors/report', {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
body: JSON.stringify(errorReport)
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return true;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.warn('UserDatabase: reportError failed:', error.message);
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
276
302
|
// Helper methods (same as server-side)
|
|
277
303
|
generateUserId(email) {
|
|
278
304
|
return crypto.createHash('sha256').update(email.toLowerCase()).digest('hex').substring(0, 16);
|
|
@@ -115,6 +115,13 @@ class UserDatabase {
|
|
|
115
115
|
return this.apiClient.isAdmin(userId)
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Report an error to the admin database for tracking and fixing
|
|
120
|
+
*/
|
|
121
|
+
async reportError(errorData) {
|
|
122
|
+
return this.apiClient.reportError(errorData)
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
// Helper methods - delegate to API client
|
|
119
126
|
generateUserId(email) {
|
|
120
127
|
return this.apiClient.generateUserId(email)
|