devharness 0.8.0 → 0.9.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 +14 -2
- package/build/cdp-manager.js +1 -1
- package/build/cdp-manager.js.map +1 -1
- package/build/chrome-launcher.d.ts +7 -7
- package/build/chrome-launcher.d.ts.map +1 -1
- package/build/chrome-launcher.js +9 -8
- package/build/chrome-launcher.js.map +1 -1
- package/build/command-recorder.d.ts +1 -1
- package/build/command-recorder.js +1 -1
- package/build/config.d.ts +5 -5
- package/build/config.js +15 -15
- package/build/config.js.map +1 -1
- package/build/config.test.js +4 -4
- package/build/config.test.js.map +1 -1
- package/build/dashboard/dashboard-client.js +2 -2
- package/build/dashboard/dashboard-client.js.map +1 -1
- package/build/dashboard/dashboard-hub.js +3 -2
- package/build/dashboard/dashboard-hub.js.map +1 -1
- package/build/debug-logger.d.ts +1 -1
- package/build/debug-logger.js +1 -1
- package/build/helpers/parser-plugins.d.ts +2 -2
- package/build/helpers/parser-plugins.js +2 -2
- package/build/helpers/paths-migration.test.d.ts +2 -0
- package/build/helpers/paths-migration.test.d.ts.map +1 -0
- package/build/helpers/paths-migration.test.js +65 -0
- package/build/helpers/paths-migration.test.js.map +1 -0
- package/build/helpers/paths.d.ts +28 -9
- package/build/helpers/paths.d.ts.map +1 -1
- package/build/helpers/paths.js +66 -16
- package/build/helpers/paths.js.map +1 -1
- package/build/index.js +46 -46
- package/build/index.js.map +1 -1
- package/build/interaction-recorder.js +4 -4
- package/build/interaction-recorder.js.map +1 -1
- package/build/issue-tracker.js +4 -4
- package/build/issue-tracker.js.map +1 -1
- package/build/issue-tracker.test.js +1 -1
- package/build/issue-tracker.test.js.map +1 -1
- package/build/log-processor/orchestrator.d.ts +2 -2
- package/build/log-processor/orchestrator.d.ts.map +1 -1
- package/build/log-processor/orchestrator.js +1 -1
- package/build/mcp-supervisor.js +2 -3
- package/build/mcp-supervisor.js.map +1 -1
- package/build/messages.d.ts +1 -1
- package/build/messages.js +3 -3
- package/build/messages.js.map +1 -1
- package/build/overlays.d.ts +1 -1
- package/build/overlays.js +2 -2
- package/build/overlays.js.map +1 -1
- package/build/persistent-profiles.test.js +5 -5
- package/build/persistent-profiles.test.js.map +1 -1
- package/build/runners/types.d.ts +1 -1
- package/build/runners/types.d.ts.map +1 -1
- package/build/self-restart.js +1 -1
- package/build/server-claims.js +2 -2
- package/build/server-claims.js.map +1 -1
- package/build/server-claims.test.js +3 -3
- package/build/server-claims.test.js.map +1 -1
- package/build/server-manager.d.ts +4 -4
- package/build/server-manager.d.ts.map +1 -1
- package/build/server-manager.js +7 -7
- package/build/server-manager.js.map +1 -1
- package/build/server-ownership.test.js +2 -2
- package/build/server-ownership.test.js.map +1 -1
- package/build/server-watcher.js +2 -2
- package/build/server-watcher.js.map +1 -1
- package/build/supervisor/idle-config.d.ts +1 -1
- package/build/supervisor/idle-config.d.ts.map +1 -1
- package/build/supervisor/idle-config.js +1 -1
- package/build/tools/breakpoint-tools.js +1 -1
- package/build/tools/breakpoint-tools.js.map +1 -1
- package/build/tools/config-tools.js +2 -2
- package/build/tools/config-tools.js.map +1 -1
- package/build/tools/console-tools.js +1 -1
- package/build/tools/console-tools.js.map +1 -1
- package/build/tools/content-tools.js +5 -5
- package/build/tools/content-tools.js.map +1 -1
- package/build/tools/replay-add-conditional.test.js +2 -2
- package/build/tools/replay-add-conditional.test.js.map +1 -1
- package/build/tools/replay-folder-save.test.js +1 -1
- package/build/tools/replay-folder-save.test.js.map +1 -1
- package/build/tools/replay-formatters.d.ts +1 -1
- package/build/tools/replay-formatters.js +1 -1
- package/build/tools/replay-tools.js +4 -4
- package/build/tools/replay-tools.js.map +1 -1
- package/build/tools/screenshot-tools.js +1 -1
- package/build/tools/screenshot-tools.js.map +1 -1
- package/build/tools/server-tools.js +1 -1
- package/build/tools/server-tools.js.map +1 -1
- package/build/tools/storage-tools.js +1 -1
- package/build/tools/storage-tools.js.map +1 -1
- package/docs/automation.md +3 -3
- package/docs/installation.md +3 -3
- package/docs/instructions.md +7 -7
- package/docs/mcp-instructions.md +3 -3
- package/docs/messages.md +5 -5
- package/docs/parser-plugins.md +4 -4
- package/docs/replay.md +11 -11
- package/docs/troubleshooting.md +2 -2
- package/package.json +2 -2
- package/{skills → plugin/skills}/devharness/SKILL.md +3 -3
- package/build/session-detector.test.d.ts +0 -9
- package/build/session-detector.test.d.ts.map +0 -1
- package/build/session-detector.test.js +0 -45
- package/build/session-detector.test.js.map +0 -1
- /package/{skills → plugin/skills}/devharness/references/sequences.md +0 -0
- /package/{skills → plugin/skills}/devharness/references/tool-categories.md +0 -0
package/docs/replay.md
CHANGED
|
@@ -5,7 +5,7 @@ Record and replay command sequences for testing, automation, and debugging workf
|
|
|
5
5
|
> **Tip:** Use the `replay-agent` (`.claude/agents/replay-agent.md`) to build sequences through investigation - it records your tool calls automatically.
|
|
6
6
|
>
|
|
7
7
|
> For a condensed, agent-facing version of this material see
|
|
8
|
-
> `skills/
|
|
8
|
+
> `skills/devharness/references/sequences.md`. This document is the fuller
|
|
9
9
|
> reference with worked examples.
|
|
10
10
|
|
|
11
11
|
## Actions
|
|
@@ -139,7 +139,7 @@ Export sequences as Playwright or Puppeteer tests:
|
|
|
139
139
|
// Export as Playwright test
|
|
140
140
|
replay({ action: 'export', name: 'my-signup-test', format: 'playwright' })
|
|
141
141
|
// Creates: tests/e2e/my-signup-test.spec.ts
|
|
142
|
-
// Also saves: .
|
|
142
|
+
// Also saves: .devharness/sequences/my-signup-test.json
|
|
143
143
|
|
|
144
144
|
// Export as Puppeteer test
|
|
145
145
|
replay({ action: 'export', name: 'my-signup-test', format: 'puppeteer' })
|
|
@@ -147,7 +147,7 @@ replay({ action: 'export', name: 'my-signup-test', format: 'puppeteer' })
|
|
|
147
147
|
|
|
148
148
|
// Export sequence JSON only (default format)
|
|
149
149
|
replay({ action: 'export', name: 'my-signup-test', format: 'sequence' })
|
|
150
|
-
// Creates: .
|
|
150
|
+
// Creates: .devharness/sequences/my-signup-test.json
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
`export` always writes the sequence JSON first, whatever the format. If a target
|
|
@@ -159,7 +159,7 @@ and are dropped from the generated test.
|
|
|
159
159
|
|
|
160
160
|
### Configure Export Paths
|
|
161
161
|
|
|
162
|
-
In `.
|
|
162
|
+
In `.devharness/config.json`:
|
|
163
163
|
|
|
164
164
|
```json
|
|
165
165
|
{
|
|
@@ -202,7 +202,7 @@ The cursor is only driven for *coordinate* clicks (`input({ action: 'click', x,
|
|
|
202
202
|
y })`) and for `input({ action: 'press' })`. Selector-based clicks execute
|
|
203
203
|
without a cursor effect.
|
|
204
204
|
|
|
205
|
-
Configure in `.
|
|
205
|
+
Configure in `.devharness/config.json`:
|
|
206
206
|
|
|
207
207
|
```json
|
|
208
208
|
{
|
|
@@ -254,7 +254,7 @@ These fields are saved to disk and displayed when listing sequences.
|
|
|
254
254
|
// Execute commands straight from history without making a sequence
|
|
255
255
|
replay({ action: 'repeat', indices: [12, 13] })
|
|
256
256
|
|
|
257
|
-
// Execute lines from .
|
|
257
|
+
// Execute lines from .devharness/history.log (1-indexed, line 1 = most recent)
|
|
258
258
|
replay({ action: 'runFromLog', lines: [3, 4, 5] })
|
|
259
259
|
```
|
|
260
260
|
|
|
@@ -304,11 +304,11 @@ replay({ action: 'delete', sequenceId: 'seq-1234567890' })
|
|
|
304
304
|
```javascript
|
|
305
305
|
// Export sequence to disk (working directory)
|
|
306
306
|
replay({ action: 'export', sequenceId: 'seq-1234567890', format: 'sequence' })
|
|
307
|
-
// Saves to: .
|
|
307
|
+
// Saves to: .devharness/sequences/<name>.json
|
|
308
308
|
|
|
309
309
|
// Export to global location (accessible from any directory)
|
|
310
310
|
replay({ action: 'export', sequenceId: 'seq-1234567890', format: 'sequence', global: true })
|
|
311
|
-
// Saves to: ~/.
|
|
311
|
+
// Saves to: ~/.devharness/sequences/<name>.json
|
|
312
312
|
|
|
313
313
|
// List saved sequences on disk (add showAll: true to include completed issues)
|
|
314
314
|
replay({ action: 'listSaved' })
|
|
@@ -853,7 +853,7 @@ running too. The run says which it closed:
|
|
|
853
853
|
#### Declaring the device, not just the browser
|
|
854
854
|
|
|
855
855
|
`profile` names a persistent Chrome profile (the same ones
|
|
856
|
-
`launchChrome({ profile })` creates, under `~/.
|
|
856
|
+
`launchChrome({ profile })` creates, under `~/.devharness/profiles`):
|
|
857
857
|
|
|
858
858
|
```json
|
|
859
859
|
"requiredConnections": [
|
|
@@ -1100,7 +1100,7 @@ step counts as a success. A condition that cannot be *evaluated* (bad format,
|
|
|
1100
1100
|
unknown type, invalid or over-long regex, tool error) fails the run.
|
|
1101
1101
|
|
|
1102
1102
|
Nesting is capped by `replay.maxConditionalDepth` (default 10) and regexes by
|
|
1103
|
-
`replay.maxRegexLength` (default 500); both are `.
|
|
1103
|
+
`replay.maxRegexLength` (default 500); both are `.devharness/config.json`
|
|
1104
1104
|
settings. Oscillating chains (A→B→A) are allowed up to the depth limit.
|
|
1105
1105
|
|
|
1106
1106
|
## forEach Steps
|
|
@@ -1316,7 +1316,7 @@ parked on.
|
|
|
1316
1316
|
|
|
1317
1317
|
### Configuration
|
|
1318
1318
|
|
|
1319
|
-
Configure in `.
|
|
1319
|
+
Configure in `.devharness/config.json` (values shown are the defaults):
|
|
1320
1320
|
|
|
1321
1321
|
```json
|
|
1322
1322
|
{
|
package/docs/troubleshooting.md
CHANGED
|
@@ -15,7 +15,7 @@ next call.
|
|
|
15
15
|
**Solutions:**
|
|
16
16
|
- Relaunch Chrome (`launchChrome`) and restart the dev server
|
|
17
17
|
(`server({ action: 'start', serverId: '...' })`) - its config is kept.
|
|
18
|
-
- Raise or disable the threshold in `.
|
|
18
|
+
- Raise or disable the threshold in `.devharness/config.json`:
|
|
19
19
|
`{"session": {"idleSuspendMinutes": 0}}`. Read at supervisor startup, so it
|
|
20
20
|
applies from the next reconnect.
|
|
21
21
|
|
|
@@ -238,7 +238,7 @@ running until you reboot.
|
|
|
238
238
|
|
|
239
239
|
```javascript
|
|
240
240
|
setDebugLogging({ enabled: true })
|
|
241
|
-
// Check logs at: .
|
|
241
|
+
// Check logs at: .devharness/logs/debug.log
|
|
242
242
|
```
|
|
243
243
|
|
|
244
244
|
### Check connection status
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devharness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "MCP server that connects AI assistants to Chrome DevTools Protocol for runtime debugging - set breakpoints, inspect variables, monitor network traffic, and automate browser interactions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"files": [
|
|
57
57
|
"build/",
|
|
58
58
|
"docs/",
|
|
59
|
-
"skills/",
|
|
59
|
+
"plugin/skills/",
|
|
60
60
|
"README.md",
|
|
61
61
|
"LICENSE"
|
|
62
62
|
],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: devharness
|
|
3
3
|
description: Drive and debug a running app via the devharness MCP server - launch or attach to Chrome and Node.js, set breakpoints and logpoints, inspect call stacks and variables, watch console and network, manage dev servers, replay any earlier tool call by its history index, and record reproduction sequences that verify a fix. Use whenever a task involves running or debugging a live app, reproducing or verifying a bug, re-driving setup you already did (relaunching, re-logging in, refilling a form), or the user mentions breakpoints, Chrome DevTools, CDP, replay sequences, or devharness tools (launchChrome, navigate, breakpoint, inspect, replay, server, issues, etc.).
|
|
4
4
|
compatibility: Requires the devharness MCP server to be connected (tools such as launchChrome, breakpoint, inspect, replay, server, issues). Previously published as cdp-tools-mcp.
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.9.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# devharness
|
|
@@ -169,8 +169,8 @@ Note this is only one use of `repeat`. The footer hint is on every response, not
|
|
|
169
169
|
|
|
170
170
|
If devharness itself seems stuck or broken (not the target app), restart it yourself rather than asking the user to reconnect - don't wait to be told to.
|
|
171
171
|
|
|
172
|
-
- **Preferred**: `config({ action: 'restart' })`. Under the hood this reads `.
|
|
173
|
-
- If that returns `CONFIG_RESTART_NOT_SUPERVISED` (this server isn't running through the supervisor - e.g. a bare `node build/index.js`), fall back to Bash: `kill -USR2 $(cat .
|
|
172
|
+
- **Preferred**: `config({ action: 'restart' })`. Under the hood this reads `.devharness/mcp-supervisor.pid` and sends the running mcp-supervisor process a `SIGUSR2`, the same signal `npm run build`'s postbuild hook sends automatically after a rebuild. The supervisor replays the original MCP `initialize` handshake to the freshly spawned child, so the host session never needs to reconnect.
|
|
173
|
+
- If that returns `CONFIG_RESTART_NOT_SUPERVISED` (this server isn't running through the supervisor - e.g. a bare `node build/index.js`), fall back to Bash: `kill -USR2 $(cat .devharness/mcp-supervisor.pid)`.
|
|
174
174
|
- If it returns `CONFIG_RESTART_STALE_PID`, the supervisor died without cleaning up its pidfile - ask the user to run `/mcp` to reconnect.
|
|
175
175
|
|
|
176
176
|
**Expect the triggering call itself to come back as an error - that's normal, not a failure.** In practice `config({ action: 'restart' })` almost never returns its own `CONFIG_RESTART_REQUESTED` success message: the old process gets torn down before it can flush that response, so the supervisor's restart-coordinator answers with a synthesized `MCP error -32000: MCP server is restarting; this request will not receive a response from the previous process. Please retry.` instead. Just retry the next call - it'll hit the freshly restarted (and by then ready) process. Two things to expect on that next call: it runs against a new PID (visible in tool response footers), and any acknowledged monitored-port failures (`server({ action: 'acknowledgePort' })`) reset and may need re-acknowledging, since that state lived in the process that just got replaced.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for isAgentSession() - the pure classifier used by bug-003's
|
|
3
|
-
* fix (issues({action:'resolve'}) must refuse autonomous agents). It only
|
|
4
|
-
* operates on the plain SessionState shape returned by
|
|
5
|
-
* SessionDetector.getState(), so it's tested directly without any real
|
|
6
|
-
* fs.watch/transcript-file plumbing.
|
|
7
|
-
*/
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=session-detector.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-detector.test.d.ts","sourceRoot":"","sources":["../src/session-detector.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for isAgentSession() - the pure classifier used by bug-003's
|
|
3
|
-
* fix (issues({action:'resolve'}) must refuse autonomous agents). It only
|
|
4
|
-
* operates on the plain SessionState shape returned by
|
|
5
|
-
* SessionDetector.getState(), so it's tested directly without any real
|
|
6
|
-
* fs.watch/transcript-file plumbing.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect } from 'vitest';
|
|
9
|
-
import { isAgentSession } from './session-detector.js';
|
|
10
|
-
function state(overrides = {}) {
|
|
11
|
-
return {
|
|
12
|
-
mainSession: null,
|
|
13
|
-
activeAgents: [],
|
|
14
|
-
entryCount: 0,
|
|
15
|
-
...overrides,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
describe('isAgentSession', () => {
|
|
19
|
-
it('classifies as agent when only an agent transcript has matched this process\'s PID', () => {
|
|
20
|
-
const s = state({
|
|
21
|
-
mainSession: null,
|
|
22
|
-
activeAgents: [{ agentId: 'a1', shortId: 'a1', agentFile: '/agent-a1.jsonl', startedAt: Date.now() }],
|
|
23
|
-
});
|
|
24
|
-
expect(isAgentSession(s)).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
it('classifies as human when the main session transcript has matched, even with no agents', () => {
|
|
27
|
-
const s = state({
|
|
28
|
-
mainSession: { sessionId: 'm1', shortId: 'm1', sessionFile: '/m1.jsonl', detectedAt: Date.now() },
|
|
29
|
-
activeAgents: [],
|
|
30
|
-
});
|
|
31
|
-
expect(isAgentSession(s)).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
it('prefers human when both a main session and agents are present (main session wins)', () => {
|
|
34
|
-
const s = state({
|
|
35
|
-
mainSession: { sessionId: 'm1', shortId: 'm1', sessionFile: '/m1.jsonl', detectedAt: Date.now() },
|
|
36
|
-
activeAgents: [{ agentId: 'a1', shortId: 'a1', agentFile: '/agent-a1.jsonl', startedAt: Date.now() }],
|
|
37
|
-
});
|
|
38
|
-
expect(isAgentSession(s)).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
it('defaults to human (fails open) when nothing has been classified yet', () => {
|
|
41
|
-
const s = state({ mainSession: null, activeAgents: [] });
|
|
42
|
-
expect(isAgentSession(s)).toBe(false);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
//# sourceMappingURL=session-detector.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-detector.test.js","sourceRoot":"","sources":["../src/session-detector.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAqB,MAAM,uBAAuB,CAAC;AAE1E,SAAS,KAAK,CAAC,YAAmC,EAAE;IAClD,OAAO;QACL,WAAW,EAAE,IAAI;QACjB,YAAY,EAAE,EAAE;QAChB,UAAU,EAAE,CAAC;QACb,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;QAC3F,MAAM,CAAC,GAAG,KAAK,CAAC;YACd,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SACtG,CAAC,CAAC;QACH,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uFAAuF,EAAE,GAAG,EAAE;QAC/F,MAAM,CAAC,GAAG,KAAK,CAAC;YACd,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;YACjG,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;QAC3F,MAAM,CAAC,GAAG,KAAK,CAAC;YACd,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;YACjG,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SACtG,CAAC,CAAC;QACH,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
File without changes
|
|
File without changes
|