watchfix 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -64,12 +64,28 @@ watchfix watch
64
64
  watchfix fix <error-id>
65
65
  ```
66
66
 
67
+ ## Autonomous Mode
68
+
69
+ For fully automated error fixing without manual approval:
70
+
71
+ ```bash
72
+ watchfix watch --autonomous
73
+ ```
74
+
75
+ In autonomous mode, watchfix automatically dispatches AI agents to fix detected errors. Combine with daemon mode for background operation (Linux/macOS):
76
+
77
+ ```bash
78
+ watchfix watch --daemon --autonomous
79
+ ```
80
+
81
+ **Note:** Manual `watchfix fix` commands are blocked while running in autonomous mode.
82
+
67
83
  ## CLI Commands
68
84
 
69
85
  | Command | Description |
70
86
  |---------|-------------|
71
87
  | `watchfix init` | Create `watchfix.yaml` in current directory |
72
- | `watchfix watch` | Watch logs in foreground (use `--daemon` for background) |
88
+ | `watchfix watch` | Watch logs in foreground (use `--daemon` for background, `--autonomous` for auto-fix) |
73
89
  | `watchfix fix [id]` | Analyze and fix a specific error (or `--all` for all pending) |
74
90
  | `watchfix show <id>` | Show full error details and analysis |
75
91
  | `watchfix status` | Show watcher state and pending errors |
@@ -175,6 +175,14 @@ const formatFixOutcome = (result, verbosity, maxAttempts) => {
175
175
  }
176
176
  else if (!result.fix?.success) {
177
177
  lines.push(`Error #${result.errorId}: Agent could not apply fix`);
178
+ if (result.diagnostic) {
179
+ // Extract key info from diagnostic
180
+ const diagLines = result.diagnostic.split('\n');
181
+ const reason = diagLines.find(l => l.includes('timed out') || l.includes('Exit code'));
182
+ if (reason) {
183
+ lines.push(` Reason: ${reason.trim()}`);
184
+ }
185
+ }
178
186
  }
179
187
  else {
180
188
  lines.push(`Error #${result.errorId}: Fix attempt completed`);
@@ -18,6 +18,7 @@ export type FixResult = {
18
18
  fix?: FixOutput;
19
19
  verification?: VerificationResult;
20
20
  message?: string;
21
+ diagnostic?: string;
21
22
  };
22
23
  type FixOrchestratorOptions = {
23
24
  agent?: Agent;
@@ -246,6 +246,7 @@ export class FixOrchestrator {
246
246
  lockAcquired: true,
247
247
  attempts,
248
248
  message: 'Analysis failed',
249
+ diagnostic: analysisResult.diagnostic,
249
250
  };
250
251
  }
251
252
  }
@@ -348,6 +349,7 @@ export class FixOrchestrator {
348
349
  attempts,
349
350
  analysis: analysisOutput,
350
351
  message: 'Fix failed',
352
+ diagnostic: fixResult.diagnostic,
351
353
  };
352
354
  }
353
355
  logActivity(this.db, 'verification_start', errorId, JSON.stringify({ attempt: attempts }));
@@ -11,6 +11,14 @@ const CONTINUATION_PATTERNS = [
11
11
  /^\s+\.\.\./,
12
12
  ];
13
13
  const isContinuationLine = (line) => CONTINUATION_PATTERNS.some((pattern) => pattern.test(line));
14
+ const extractCoreMessage = (line) => {
15
+ // "TypeError: Cannot read..." → "Cannot read..."
16
+ const colonIndex = line.indexOf(': ');
17
+ if (colonIndex > 0 && colonIndex < 30) {
18
+ return line.slice(colonIndex + 2).trim();
19
+ }
20
+ return line.trim();
21
+ };
14
22
  const truncateLine = (line) => {
15
23
  if (line.length <= MAX_LINE_LENGTH) {
16
24
  return line;
@@ -58,6 +66,21 @@ export class ErrorParser {
58
66
  return;
59
67
  }
60
68
  if (isError) {
69
+ // Check if this is the same error with a more specific type
70
+ if (this.current && this.current.stackLines.length === 0) {
71
+ const currentCore = extractCoreMessage(this.current.message);
72
+ const newCore = extractCoreMessage(line);
73
+ if (currentCore === newCore) {
74
+ // Same error - discard shallow entry, use the more detailed one
75
+ if (this.flushTimer) {
76
+ clearTimeout(this.flushTimer);
77
+ this.flushTimer = undefined;
78
+ }
79
+ this.current = undefined;
80
+ this.startError(event, line);
81
+ return;
82
+ }
83
+ }
61
84
  await this.flushCurrent('new_error');
62
85
  this.startError(event, line);
63
86
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watchfix",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI tool that watches logs, detects errors, and dispatches AI agents to fix them",
5
5
  "type": "module",
6
6
  "bin": {