watchfix 0.4.0 → 0.5.0

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/HELP.md ADDED
@@ -0,0 +1,416 @@
1
+ # watchfix - Agent Reference
2
+
3
+ > Run `watchfix manual` to display this document.
4
+
5
+ ## Quick Context
6
+
7
+ watchfix is a CLI tool that watches log files, detects errors via configurable patterns, and dispatches AI agents (Claude, Gemini, or Codex) to analyze and fix them automatically. Prerequisites: a `watchfix.yaml` config file in your project root, one of the supported AI CLIs installed and in PATH, and at least one log source configured. All state is stored locally in `.watchfix/errors.db` (SQLite).
8
+
9
+ ## Commands
10
+
11
+ ### Setup Commands
12
+
13
+ #### `watchfix init`
14
+
15
+ Create a `watchfix.yaml` config file in the current directory.
16
+
17
+ ```
18
+ watchfix init [--agent <provider>] [--force]
19
+ ```
20
+
21
+ | Flag | Description |
22
+ |------|-------------|
23
+ | `--agent <provider>` | Set agent provider: `claude`, `gemini`, or `codex` (default: `claude`) |
24
+ | `--force` | Overwrite existing `watchfix.yaml` |
25
+
26
+ Output: writes `watchfix.yaml` and adds `.watchfix/` to `.gitignore`.
27
+
28
+ #### `watchfix config validate`
29
+
30
+ Validate the configuration file.
31
+
32
+ ```
33
+ watchfix config validate [-c <path>]
34
+ ```
35
+
36
+ Exit code 0 if valid, 1 if invalid (error message on stderr).
37
+
38
+ ### Watching Commands
39
+
40
+ #### `watchfix watch`
41
+
42
+ Start watching configured log sources for errors.
43
+
44
+ ```
45
+ watchfix watch [--daemon] [--autonomous]
46
+ ```
47
+
48
+ | Flags | Mode | Behavior |
49
+ |-------|------|----------|
50
+ | _(none)_ | Foreground, manual | Detects errors, queues for manual `fix` |
51
+ | `--autonomous` | Foreground, autonomous | Detects and auto-fixes without approval |
52
+ | `--daemon` | Background, manual | Runs detached; logs to activity log only |
53
+ | `--daemon --autonomous` | Background, autonomous | Runs detached; auto-fixes in background |
54
+
55
+ Exit code 2 if a watcher is already running.
56
+
57
+ #### `watchfix stop`
58
+
59
+ Stop a running background watcher.
60
+
61
+ ```
62
+ watchfix stop
63
+ ```
64
+
65
+ Exit code 2 if no watcher is running.
66
+
67
+ #### `watchfix status`
68
+
69
+ Show watcher state and pending errors.
70
+
71
+ ```
72
+ watchfix status
73
+ ```
74
+
75
+ Output format (plain text, one error per line):
76
+
77
+ ```
78
+ Watcher: running (pid 12345, mode: autonomous)
79
+ Uptime: 2h 15m
80
+
81
+ Errors:
82
+ #1 [pending] TypeError: Cannot read property 'x' of null (app)
83
+ #3 [suggested] ReferenceError: foo is not defined (api)
84
+ #7 [fixing] FATAL: connection refused (db)
85
+ ```
86
+
87
+ When no errors exist: `No errors recorded.`
88
+ When watcher is not running: `Watcher: not running`
89
+
90
+ ### Error Management Commands
91
+
92
+ #### `watchfix show <id>`
93
+
94
+ Show full error details and analysis.
95
+
96
+ ```
97
+ watchfix show <id> [--json]
98
+ ```
99
+
100
+ | Flag | Description |
101
+ |------|-------------|
102
+ | `--json` | Output machine-readable JSON (see JSON Output Format below) |
103
+
104
+ Without `--json`, outputs human-readable text with error metadata, stack trace, analysis, fix result, and activity log.
105
+
106
+ #### `watchfix fix [id]`
107
+
108
+ Analyze and fix an error. Without an id, requires `--all`.
109
+
110
+ ```
111
+ watchfix fix <id> [-y] [--analyze-only] [--reanalyze]
112
+ watchfix fix --all [--confirm-each] [--analyze-only] [--reanalyze]
113
+ ```
114
+
115
+ | Flag | Description |
116
+ |------|-------------|
117
+ | `-y, --yes` | Skip confirmation prompt |
118
+ | `--all` | Fix all pending/suggested errors sequentially |
119
+ | `--confirm-each` | With `--all`: prompt before each fix |
120
+ | `--analyze-only` | Stop after analysis, don't apply the fix |
121
+ | `--reanalyze` | Force re-analysis even if already in `suggested` status |
122
+
123
+ Exit code 3 if the error is not in an actionable status or not found.
124
+
125
+ #### `watchfix ignore <id>`
126
+
127
+ Mark an error as ignored. It will not be processed further.
128
+
129
+ ```
130
+ watchfix ignore <id>
131
+ ```
132
+
133
+ ### Utility Commands
134
+
135
+ #### `watchfix logs`
136
+
137
+ Show the activity log.
138
+
139
+ ```
140
+ watchfix logs [--tail] [-n <count>]
141
+ ```
142
+
143
+ | Flag | Description |
144
+ |------|-------------|
145
+ | `--tail` | Follow the log (stream new entries) |
146
+ | `-n, --lines <count>` | Number of lines to show (default: 50) |
147
+
148
+ #### `watchfix clean`
149
+
150
+ Remove old context files from `.watchfix/context/`.
151
+
152
+ ```
153
+ watchfix clean [--dry-run] [--force]
154
+ ```
155
+
156
+ | Flag | Description |
157
+ |------|-------------|
158
+ | `--dry-run` | Show what would be removed without deleting |
159
+ | `--force` | Skip confirmation prompt |
160
+
161
+ #### `watchfix version`
162
+
163
+ Show version, Node.js version, config status, and agent provider.
164
+
165
+ ```
166
+ watchfix version
167
+ ```
168
+
169
+ #### `watchfix manual`
170
+
171
+ Output this reference document to stdout.
172
+
173
+ ```
174
+ watchfix manual
175
+ ```
176
+
177
+ ### Global Options
178
+
179
+ These flags work with all commands:
180
+
181
+ | Flag | Description |
182
+ |------|-------------|
183
+ | `-c, --config <path>` | Use alternate config file (default: `./watchfix.yaml`) |
184
+ | `--verbose` | Increase output verbosity |
185
+ | `-q, --quiet` | Suppress non-essential output |
186
+ | `-h, --help` | Show help for command |
187
+ | `-v, --version` | Show version and exit |
188
+
189
+ ## Common Workflows
190
+
191
+ ### Check if watchfix is set up
192
+
193
+ ```bash
194
+ # Look for config file
195
+ ls watchfix.yaml
196
+
197
+ # Validate it
198
+ watchfix config validate
199
+ ```
200
+
201
+ ### Start watching and monitor
202
+
203
+ ```bash
204
+ # Start watcher in foreground
205
+ watchfix watch
206
+
207
+ # Or in background (Linux/macOS)
208
+ watchfix watch --daemon
209
+
210
+ # Poll for errors
211
+ watchfix status
212
+
213
+ # Stream activity log
214
+ watchfix logs --tail
215
+ ```
216
+
217
+ ### Investigate and fix one error
218
+
219
+ ```bash
220
+ # See what errors exist
221
+ watchfix status
222
+
223
+ # Get full details (machine-readable)
224
+ watchfix show 3 --json
225
+
226
+ # Fix it (with confirmation)
227
+ watchfix fix 3
228
+
229
+ # Or skip confirmation
230
+ watchfix fix 3 -y
231
+ ```
232
+
233
+ ### Fix all pending errors
234
+
235
+ ```bash
236
+ watchfix fix --all
237
+ ```
238
+
239
+ ### Fully automated operation
240
+
241
+ ```bash
242
+ # Start autonomous daemon
243
+ watchfix watch --daemon --autonomous
244
+
245
+ # Monitor progress
246
+ watchfix status
247
+ watchfix logs --tail
248
+
249
+ # Stop when done
250
+ watchfix stop
251
+ ```
252
+
253
+ ### Analyze without fixing
254
+
255
+ ```bash
256
+ # Get analysis only (no code changes)
257
+ watchfix fix 3 --analyze-only
258
+
259
+ # View the analysis
260
+ watchfix show 3
261
+ ```
262
+
263
+ ## Exit Codes
264
+
265
+ | Code | Constant | Meaning |
266
+ |------|----------|---------|
267
+ | 0 | `SUCCESS` | Command completed successfully |
268
+ | 1 | `GENERAL_ERROR` | General error (invalid config, agent failure, etc.) |
269
+ | 2 | `WATCHER_CONFLICT` | Watcher state conflict (already running / not running) |
270
+ | 3 | `NOT_ACTIONABLE` | Target not actionable (error not found, wrong status, locked) |
271
+ | 4 | `SCHEMA_MISMATCH` | Database schema version mismatch (requires migration) |
272
+ | 130 | `INTERRUPTED` | Interrupted by user (SIGINT / Ctrl+C) |
273
+
274
+ ## Error Statuses
275
+
276
+ ### Status Lifecycle
277
+
278
+ ```
279
+ pending → analyzing → suggested → fixing → fixed
280
+ → failed (after max attempts)
281
+ Any status → ignored (via watchfix ignore)
282
+ ```
283
+
284
+ ### Status Reference
285
+
286
+ | Status | Description | Actionable? |
287
+ |--------|-------------|-------------|
288
+ | `pending` | Detected, awaiting analysis | Yes — `fix` will start analysis |
289
+ | `analyzing` | Agent is currently analyzing | No — locked |
290
+ | `suggested` | Analysis complete, awaiting fix | Yes — `fix` will apply the suggestion |
291
+ | `fixing` | Agent is currently applying fix | No — locked |
292
+ | `fixed` | Fix applied and verified | No — terminal |
293
+ | `failed` | Max attempts exceeded | Manual retry only (`fix <id>`, excluded from `--all`) |
294
+ | `ignored` | User chose to ignore | No — terminal |
295
+ | `resolved` | Fixed by a previous fix to another error | No — terminal |
296
+ | `deferred` | Non-code issue (infrastructure/config) | No — shows remediation guidance |
297
+
298
+ ### Deduplication
299
+
300
+ When a new error matches an existing one (by hash):
301
+ - If existing is `pending`, `analyzing`, `suggested`, or `fixing`: new error is dropped
302
+ - If existing is `fixed`, `failed`, or `ignored`: a new entry is created (error recurred)
303
+
304
+ ## JSON Output Format
305
+
306
+ `watchfix show <id> --json` returns a JSON object with this shape:
307
+
308
+ ```json
309
+ {
310
+ "error": {
311
+ "id": 1,
312
+ "hash": "abc123...",
313
+ "source": "app",
314
+ "timestamp": "2026-01-29T12:00:00.000Z",
315
+ "errorType": "TypeError",
316
+ "message": "Cannot read property 'x' of null",
317
+ "stackTrace": "TypeError: Cannot read property...\n at foo (src/app.ts:10:5)\n ...",
318
+ "rawLog": "[2026-01-29 12:00:00] ERROR TypeError: Cannot read property...",
319
+ "status": "suggested",
320
+ "suggestion": "{\"summary\":\"...\",\"root_cause\":\"...\",\"suggested_fix\":\"...\"}",
321
+ "fixResult": null,
322
+ "fixAttempts": 0,
323
+ "lockedBy": null,
324
+ "lockedAt": null,
325
+ "createdAt": "2026-01-29T12:00:01.000Z",
326
+ "updatedAt": "2026-01-29T12:00:05.000Z"
327
+ },
328
+ "analysis": {
329
+ "summary": "Null pointer access in foo()",
330
+ "root_cause": "Variable 'x' is not initialized before access",
331
+ "suggested_fix": "Add null check before accessing property",
332
+ "files_to_modify": ["src/app.ts"],
333
+ "confidence": "high",
334
+ "category": "code"
335
+ },
336
+ "fixResult": null,
337
+ "activityLog": [
338
+ {
339
+ "id": 1,
340
+ "timestamp": "2026-01-29T12:00:01.000Z",
341
+ "action": "error_detected",
342
+ "error_id": 1,
343
+ "details": "TypeError: Cannot read property 'x' of null"
344
+ }
345
+ ]
346
+ }
347
+ ```
348
+
349
+ ### Key Fields
350
+
351
+ - `error.status` — current lifecycle status (see Error Statuses above)
352
+ - `error.suggestion` — raw JSON string of agent analysis (parse it to get the `analysis` object)
353
+ - `error.fixResult` — raw JSON string of fix result (null if not yet fixed)
354
+ - `analysis` — parsed suggestion object; `null` if not yet analyzed
355
+ - `analysis.category` — `"code"`, `"infrastructure"`, or `"configuration"`
356
+ - `analysis.confidence` — `"high"`, `"medium"`, or `"low"`
357
+ - `analysis.remediation_guidance` — present for `deferred` (non-code) errors
358
+ - `fixResult` — parsed fix result object; `null` if not yet fixed
359
+ - `fixResult.success` — boolean indicating if verification passed
360
+ - `fixResult.files_changed` — array of `{ "path": "...", "change": "..." }`
361
+ - `activityLog` — chronological list of actions taken on this error
362
+
363
+ ## Configuration Quick Reference
364
+
365
+ watchfix uses a `watchfix.yaml` file in the project root. Run `watchfix init` to generate a template.
366
+
367
+ ### Key Sections
368
+
369
+ ```yaml
370
+ project:
371
+ name: my-app # Project identifier
372
+ root: . # Project root (paths resolve relative to this)
373
+
374
+ agent:
375
+ provider: claude # Required: claude | gemini | codex
376
+ timeout: 5m # Max agent execution time (default: 5m)
377
+ retries: 2 # Retries on agent timeout/crash (default: 2)
378
+
379
+ logs:
380
+ sources: # At least one source required
381
+ - name: app # Source identifier
382
+ type: file # file | docker | command
383
+ path: ./logs/app.log
384
+ context_lines_before: 10
385
+ context_lines_after: 5
386
+
387
+ verification:
388
+ test_commands: # Run after fix, in order; stop on first failure
389
+ - npm run lint
390
+ - npm test
391
+ health_checks: # HTTP GET, expect 2xx
392
+ - http://localhost:3000/health
393
+
394
+ patterns:
395
+ match: # Additional error patterns
396
+ - "FATAL:"
397
+ - "regex:OOM.*killed"
398
+ ignore: # Patterns to skip
399
+ - "DeprecationWarning"
400
+
401
+ limits:
402
+ max_attempts_per_error: 3
403
+
404
+ cleanup:
405
+ context_max_age_days: 7
406
+ ```
407
+
408
+ ### Source Types
409
+
410
+ | Type | Required Fields | Description |
411
+ |------|----------------|-------------|
412
+ | `file` | `path` | Watch a log file (supports `format: ndjson` for structured JSON logs) |
413
+ | `docker` | `container` | Watch Docker container logs |
414
+ | `command` | `run`, `interval` | Run a command periodically and scan output |
415
+
416
+ For full configuration details and NDJSON options, run `watchfix init` to see the annotated template.
@@ -0,0 +1 @@
1
+ export declare const manualCommand: () => Promise<void>;
@@ -0,0 +1,14 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { UserError } from '../../utils/errors.js';
5
+ export const manualCommand = async () => {
6
+ const helpPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'HELP.md');
7
+ try {
8
+ const content = await fs.readFile(helpPath, 'utf8');
9
+ process.stdout.write(content);
10
+ }
11
+ catch {
12
+ throw new UserError('HELP.md not found. This file should be included in the watchfix package.');
13
+ }
14
+ };
package/dist/cli/index.js CHANGED
@@ -12,6 +12,7 @@ import { logsCommand } from './commands/logs.js';
12
12
  import { configValidateCommand } from './commands/config.js';
13
13
  import { cleanCommand } from './commands/clean.js';
14
14
  import { versionCommand } from './commands/version.js';
15
+ import { manualCommand } from './commands/manual.js';
15
16
  import { EXIT_CODES, InternalError, UserError } from '../utils/errors.js';
16
17
  const require = createRequire(import.meta.url);
17
18
  const pkg = require('../../package.json');
@@ -105,6 +106,12 @@ const registerCommands = (program) => {
105
106
  .action(async (options) => {
106
107
  await versionCommand(options);
107
108
  }));
109
+ program
110
+ .command('manual')
111
+ .description('Show detailed reference documentation')
112
+ .action(async () => {
113
+ await manualCommand();
114
+ });
108
115
  };
109
116
  const program = new Command();
110
117
  program
@@ -114,6 +121,7 @@ addGlobalOptions(program);
114
121
  program
115
122
  .helpOption('-h, --help', 'Show help for command')
116
123
  .version(pkg.version ?? '0.0.0', '-v, --version', 'Show version and exit');
124
+ program.addHelpText('after', '\nRun "watchfix manual" for detailed reference documentation.');
117
125
  registerCommands(program);
118
126
  const handleError = (error) => {
119
127
  if (error instanceof UserError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watchfix",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI tool that watches logs, detects errors, and dispatches AI agents to fix them",
5
5
  "keywords": [
6
6
  "cli",
@@ -30,6 +30,7 @@
30
30
  "dist",
31
31
  "LICENSE",
32
32
  "README.md",
33
+ "HELP.md",
33
34
  "package.json"
34
35
  ],
35
36
  "dependencies": {