devharness 0.9.8 → 0.9.10

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.
Files changed (161) hide show
  1. package/README.md +16 -1
  2. package/build/block-events.d.ts +3 -5
  3. package/build/block-events.d.ts.map +1 -1
  4. package/build/block-events.js +6 -24
  5. package/build/block-events.js.map +1 -1
  6. package/build/block-events.test.js +10 -7
  7. package/build/block-events.test.js.map +1 -1
  8. package/build/cdp-manager.d.ts +7 -0
  9. package/build/cdp-manager.d.ts.map +1 -1
  10. package/build/cdp-manager.js +9 -0
  11. package/build/cdp-manager.js.map +1 -1
  12. package/build/cli/index.d.ts +26 -0
  13. package/build/cli/index.d.ts.map +1 -0
  14. package/build/cli/index.js +290 -0
  15. package/build/cli/index.js.map +1 -0
  16. package/build/cli/process-tree.d.ts +21 -0
  17. package/build/cli/process-tree.d.ts.map +1 -0
  18. package/build/cli/process-tree.js +51 -0
  19. package/build/cli/process-tree.js.map +1 -0
  20. package/build/cli/session-match.d.ts +37 -0
  21. package/build/cli/session-match.d.ts.map +1 -0
  22. package/build/cli/session-match.js +55 -0
  23. package/build/cli/session-match.js.map +1 -0
  24. package/build/cli/session-match.test.d.ts +17 -0
  25. package/build/cli/session-match.test.d.ts.map +1 -0
  26. package/build/cli/session-match.test.js +125 -0
  27. package/build/cli/session-match.test.js.map +1 -0
  28. package/build/config.d.ts +2 -2
  29. package/build/config.d.ts.map +1 -1
  30. package/build/config.js +2 -1
  31. package/build/config.js.map +1 -1
  32. package/build/config.test.js +2 -2
  33. package/build/config.test.js.map +1 -1
  34. package/build/connection-manager.d.ts.map +1 -1
  35. package/build/connection-manager.js +6 -1
  36. package/build/connection-manager.js.map +1 -1
  37. package/build/dashboard/dashboard-hub.js +2 -2
  38. package/build/index.js +60 -7
  39. package/build/index.js.map +1 -1
  40. package/build/interaction-recorder.js +2 -2
  41. package/build/interaction-recorder.js.map +1 -1
  42. package/build/issue-tracker.test.js +1 -1
  43. package/build/issue-tracker.test.js.map +1 -1
  44. package/build/mcp-supervisor.js +43 -0
  45. package/build/mcp-supervisor.js.map +1 -1
  46. package/build/network-monitor.d.ts +13 -2
  47. package/build/network-monitor.d.ts.map +1 -1
  48. package/build/network-monitor.js +38 -2
  49. package/build/network-monitor.js.map +1 -1
  50. package/build/network-monitor.test.js +50 -0
  51. package/build/network-monitor.test.js.map +1 -1
  52. package/build/persistent-profiles.test.js +2 -2
  53. package/build/persistent-profiles.test.js.map +1 -1
  54. package/build/plugin-session-start-hook.test.d.ts +10 -0
  55. package/build/plugin-session-start-hook.test.d.ts.map +1 -0
  56. package/build/plugin-session-start-hook.test.js +187 -0
  57. package/build/plugin-session-start-hook.test.js.map +1 -0
  58. package/build/runners/docker-compose-runner.js +1 -1
  59. package/build/runners/docker-compose-runner.js.map +1 -1
  60. package/build/runners/docker-runner.js +1 -1
  61. package/build/runners/docker-runner.js.map +1 -1
  62. package/build/runners/types.d.ts +1 -1
  63. package/build/runners/types.d.ts.map +1 -1
  64. package/build/server-manager.d.ts +1 -1
  65. package/build/server-manager.js +3 -3
  66. package/build/server-manager.js.map +1 -1
  67. package/build/server-manager.test.d.ts +1 -1
  68. package/build/server-manager.test.js +1 -1
  69. package/build/server-ownership.test.js +2 -2
  70. package/build/server-ownership.test.js.map +1 -1
  71. package/build/session-endpoint.d.ts +72 -0
  72. package/build/session-endpoint.d.ts.map +1 -0
  73. package/build/session-endpoint.js +220 -0
  74. package/build/session-endpoint.js.map +1 -0
  75. package/build/session-endpoint.test.d.ts +10 -0
  76. package/build/session-endpoint.test.d.ts.map +1 -0
  77. package/build/session-endpoint.test.js +202 -0
  78. package/build/session-endpoint.test.js.map +1 -0
  79. package/build/session-events.d.ts +28 -0
  80. package/build/session-events.d.ts.map +1 -0
  81. package/build/session-events.js +38 -0
  82. package/build/session-events.js.map +1 -0
  83. package/build/session-events.test.d.ts +8 -0
  84. package/build/session-events.test.d.ts.map +1 -0
  85. package/build/session-events.test.js +56 -0
  86. package/build/session-events.test.js.map +1 -0
  87. package/build/session-identity.d.ts +56 -0
  88. package/build/session-identity.d.ts.map +1 -0
  89. package/build/session-identity.js +96 -0
  90. package/build/session-identity.js.map +1 -0
  91. package/build/session-identity.test.d.ts +9 -0
  92. package/build/session-identity.test.d.ts.map +1 -0
  93. package/build/session-identity.test.js +126 -0
  94. package/build/session-identity.test.js.map +1 -0
  95. package/build/session-messages.d.ts +70 -0
  96. package/build/session-messages.d.ts.map +1 -0
  97. package/build/session-messages.js +139 -0
  98. package/build/session-messages.js.map +1 -0
  99. package/build/supervisor/pidfile.test.js +1 -1
  100. package/build/supervisor/pidfile.test.js.map +1 -1
  101. package/build/tool-response.d.ts +40 -1
  102. package/build/tool-response.d.ts.map +1 -1
  103. package/build/tool-response.js.map +1 -1
  104. package/build/tools/config-tools.d.ts +1 -1
  105. package/build/tools/config-tools.js +4 -4
  106. package/build/tools/config-tools.js.map +1 -1
  107. package/build/tools/console-tools.d.ts +4 -0
  108. package/build/tools/console-tools.d.ts.map +1 -1
  109. package/build/tools/console-tools.js +55 -1
  110. package/build/tools/console-tools.js.map +1 -1
  111. package/build/tools/dashboard-tools.d.ts +1 -1
  112. package/build/tools/dashboard-tools.js +2 -2
  113. package/build/tools/dashboard-tools.js.map +1 -1
  114. package/build/tools/inspect-worker-meta.test.d.ts +9 -0
  115. package/build/tools/inspect-worker-meta.test.d.ts.map +1 -0
  116. package/build/tools/inspect-worker-meta.test.js +122 -0
  117. package/build/tools/inspect-worker-meta.test.js.map +1 -0
  118. package/build/tools/inspection-tools.d.ts +12 -5
  119. package/build/tools/inspection-tools.d.ts.map +1 -1
  120. package/build/tools/inspection-tools.js +86 -5
  121. package/build/tools/inspection-tools.js.map +1 -1
  122. package/build/tools/issues-abort-hygiene.test.js +1 -1
  123. package/build/tools/issues-abort-hygiene.test.js.map +1 -1
  124. package/build/tools/issues-tools.d.ts +3 -3
  125. package/build/tools/issues-tools.test.js +1 -1
  126. package/build/tools/issues-tools.test.js.map +1 -1
  127. package/build/tools/message-tools.d.ts +51 -0
  128. package/build/tools/message-tools.d.ts.map +1 -0
  129. package/build/tools/message-tools.js +251 -0
  130. package/build/tools/message-tools.js.map +1 -0
  131. package/build/tools/message-tools.test.d.ts +9 -0
  132. package/build/tools/message-tools.test.d.ts.map +1 -0
  133. package/build/tools/message-tools.test.js +332 -0
  134. package/build/tools/message-tools.test.js.map +1 -0
  135. package/build/tools/network-tools.js +1 -1
  136. package/build/tools/network-tools.js.map +1 -1
  137. package/build/tools/replay-tools.d.ts +3 -3
  138. package/build/tools/replay-tools.js +3 -3
  139. package/build/tools/replay-tools.js.map +1 -1
  140. package/build/tools/server-tools.d.ts +3 -3
  141. package/build/worker-targets.d.ts +75 -0
  142. package/build/worker-targets.d.ts.map +1 -0
  143. package/build/worker-targets.js +171 -0
  144. package/build/worker-targets.js.map +1 -0
  145. package/build/worker-targets.test.d.ts +8 -0
  146. package/build/worker-targets.test.d.ts.map +1 -0
  147. package/build/worker-targets.test.js +118 -0
  148. package/build/worker-targets.test.js.map +1 -0
  149. package/docs/README.md +2 -2
  150. package/docs/automation.md +1 -1
  151. package/docs/installation.md +4 -4
  152. package/docs/instructions.md +26 -15
  153. package/docs/message-system.md +1 -1
  154. package/docs/messages.md +153 -3
  155. package/docs/parser-plugins.md +1 -1
  156. package/docs/replay.md +1 -1
  157. package/docs/troubleshooting.md +3 -3
  158. package/package.json +2 -1
  159. package/plugin/skills/devharness/SKILL.md +36 -8
  160. package/plugin/skills/devharness/references/sequences.md +2 -2
  161. package/plugin/skills/devharness/references/tool-categories.md +10 -3
package/docs/messages.md CHANGED
@@ -1,6 +1,6 @@
1
- # cdp-tools Message Templates
1
+ # devharness Message Templates
2
2
 
3
- This file contains all user-facing messages for the cdp-tools debugger. Messages use markdown formatting and support variable interpolation using `{{variable}}` syntax.
3
+ This file contains all user-facing messages for the devharness debugger. Messages use markdown formatting and support variable interpolation using `{{variable}}` syntax.
4
4
 
5
5
  ## Template Usage Status
6
6
 
@@ -3631,7 +3631,7 @@ Note: `tools.enabled`/`tools.disabled` changes still require an MCP server resta
3631
3631
  **Type:** success
3632
3632
  **Summary:** Restart requested
3633
3633
 
3634
- Sent a restart signal to the cdp-tools supervisor (PID {{pid}}). The server restarts shortly - no reconnect needed.
3634
+ Sent a restart signal to the devharness supervisor (PID {{pid}}). The server restarts shortly - no reconnect needed.
3635
3635
 
3636
3636
  Note: any Chrome instances this session launched will be killed (call `launchChrome` again). Managed dev servers (the `server` tool) survive and reattach automatically.
3637
3637
 
@@ -3881,6 +3881,97 @@ Cannot wait for {{condition}}: the debugger on "{{connectionReason}}" is paused
3881
3881
 
3882
3882
  ---
3883
3883
 
3884
+ ## MESSAGE_SESSIONS
3885
+
3886
+ **Type:** success
3887
+ **Summary:** {{count}} session(s) reachable
3888
+
3889
+ This session is `{{self}}`. Its mailbox: `{{mailboxPath}}`
3890
+
3891
+ {{sessionList}}
3892
+
3893
+ **Note:** An arriving message announces itself on this session's event stream, `{{eventStreamPath}}`, which is also where guard blocks land - one watch covers both. The plugin's SessionStart hook prints that path and the `Monitor` call at the start of every session. Without a watch, messages surface only when `message({ action: 'read' })` runs. Nothing watches the mailbox file; it holds the conversation and the read cursor.
3894
+
3895
+ ---
3896
+
3897
+ ## MESSAGE_SENT
3898
+
3899
+ **Type:** success
3900
+ **Summary:** Sent to {{to}}
3901
+
3902
+ Message `{{shortId}}` appended to `{{mailboxPath}}`. The recipient sees it on `message({ action: 'read' })`, or immediately if it has a Monitor armed on its event stream.{{deliveryNote}}
3903
+
3904
+ **Suggestions:**
3905
+ - To hold this call open until the other session answers: `message({ action: 'send', to: '{{to}}', text: '...', waitForReplyMs: 120000 })`
3906
+
3907
+ ---
3908
+
3909
+ ## MESSAGE_REPLY_RECEIVED
3910
+
3911
+ **Type:** success
3912
+ **Summary:** {{count}} message(s) after {{elapsedMs}}ms
3913
+
3914
+ {{messageList}}{{repeatNote}}
3915
+
3916
+ **Suggestions:**
3917
+ - Answer with `message({ action: 'reply', replyTo: '<id>', text: '...' })`
3918
+
3919
+ ---
3920
+
3921
+ ## MESSAGE_INBOX
3922
+
3923
+ **Type:** success
3924
+ **Summary:** {{count}} new of {{total}} in {{self}}
3925
+
3926
+ {{messageList}}
3927
+
3928
+ **Note:** Read advances a cursor, so the same message is returned once. The full history stays in `{{mailboxPath}}`.
3929
+
3930
+ ---
3931
+
3932
+ ## MESSAGE_REPLY_TIMEOUT
3933
+
3934
+ **Type:** error
3935
+ **Code:** MESSAGE_REPLY_TIMEOUT
3936
+
3937
+ Message `{{id}}` reached {{to}}, and nothing arrived in `{{self}}`'s mailbox within {{timeoutMs}}ms.
3938
+
3939
+ **Suggestions:**
3940
+ - The other session is alive but was not calling devharness - it sees the message on its next `message({ action: 'read' })`
3941
+ - Check it is running: `message({ action: 'sessions' })`
3942
+ - Wait again without resending: `message({ action: 'read' })`, or send a follow-up with a longer `waitForReplyMs` (max 300000)
3943
+ - Its mailbox is `{{mailboxPath}}` - a Monitor on that file removes the need to poll
3944
+
3945
+ ---
3946
+
3947
+ ## MESSAGE_TARGET_UNKNOWN
3948
+
3949
+ **Type:** error
3950
+ **Code:** MESSAGE_TARGET_UNKNOWN
3951
+
3952
+ Cannot address "{{target}}": {{reason}}. This session is `{{self}}`.
3953
+
3954
+ **Suggestions:**
3955
+ - List who is reachable: `message({ action: 'sessions' })`
3956
+ - A reply needs the id of a message in this session's own mailbox: `message({ action: 'read' })`
3957
+
3958
+ ---
3959
+
3960
+ ## MESSAGE_INVALID_ARGS
3961
+
3962
+ **Type:** error
3963
+ **Code:** MESSAGE_INVALID_ARGS
3964
+
3965
+ {{message}}
3966
+
3967
+ **Suggestions:**
3968
+ - `message({ action: 'sessions' })` - who is reachable, and this session's mailbox path
3969
+ - `message({ action: 'send', to, text })` - write to another session
3970
+ - `message({ action: 'read' })` - take new messages
3971
+ - `message({ action: 'reply', replyTo, text })` - answer a message by id
3972
+
3973
+ ---
3974
+
3884
3975
  ## CONFIG_USE_LOCAL_FAILED
3885
3976
 
3886
3977
  **Type:** error
@@ -3940,3 +4031,62 @@ Section "{{section}}" was not found in the page content.
3940
4031
 
3941
4032
  ---
3942
4033
 
4034
+ ## WORKER_TARGETS_LISTED
4035
+
4036
+ **Type:** success
4037
+ **Code:** WORKER_TARGETS_LISTED
4038
+
4039
+ {{count}} worker target(s). Pass a target id, or a substring of its URL, as `target`.
4040
+
4041
+ {{targets}}
4042
+
4043
+ ---
4044
+
4045
+ ## WORKER_EVALUATED
4046
+
4047
+ **Type:** success
4048
+ **Code:** WORKER_EVALUATED
4049
+
4050
+ Evaluated inside worker target "{{target}}".
4051
+
4052
+ {{result}}
4053
+
4054
+ ---
4055
+
4056
+ ## WORKER_TARGET_NOT_FOUND
4057
+
4058
+ **Type:** error
4059
+ **Code:** WORKER_TARGET_NOT_FOUND
4060
+
4061
+ No worker target matches "{{target}}". Available: {{available}}
4062
+
4063
+ ---
4064
+
4065
+ ## WORKER_TARGET_AMBIGUOUS
4066
+
4067
+ **Type:** error
4068
+ **Code:** WORKER_TARGET_AMBIGUOUS
4069
+
4070
+ "{{target}}" matches more than one worker target: {{matches}}. Pass a target id instead.
4071
+
4072
+ ---
4073
+
4074
+ ## WORKER_EVALUATE_FAILED
4075
+
4076
+ **Type:** error
4077
+ **Code:** WORKER_EVALUATE_FAILED
4078
+
4079
+ Evaluating inside worker target "{{target}}" failed: {{error}}
4080
+
4081
+ ---
4082
+
4083
+ ## WORKER_CONSOLE_LISTED
4084
+
4085
+ **Type:** success
4086
+ **Code:** WORKER_CONSOLE_LISTED
4087
+
4088
+ {{count}} console message(s) from worker target "{{target}}".
4089
+
4090
+ {{messages}}
4091
+
4092
+ ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  `content({ action: 'parse' })` runs small, user-written parser plugins against
4
4
  the current page and returns their JSON output. Plugins are **not** shipped with
5
- cdp-tools — you write the ones you need.
5
+ devharness — you write the ones you need.
6
6
 
7
7
  ## Usage
8
8
 
package/docs/replay.md CHANGED
@@ -1183,7 +1183,7 @@ rendered in their own section — never merged into `results` or the
1183
1183
  successful/failed counts. A broken cleanup must not turn a passing run red, nor
1184
1184
  make a failing one look like it failed somewhere it did not.
1185
1185
 
1186
- Teardown is best-effort by construction: a killed cdp-tools process takes any
1186
+ Teardown is best-effort by construction: a killed devharness process takes any
1187
1187
  pending teardown with it. It reduces accumulation; it cannot guarantee a clean
1188
1188
  world, so assertions that depend on absence remain order-dependent regardless.
1189
1189
 
@@ -8,7 +8,7 @@
8
8
  dev server has stopped - but the MCP connection still works.
9
9
 
10
10
  **Cause:** The session was suspended. With no request from the client for
11
- `session.idleSuspendMinutes` (default 120), cdp-tools releases what it holds
11
+ `session.idleSuspendMinutes` (default 120), devharness releases what it holds
12
12
  and exits; the supervisor stays connected and started a fresh server for your
13
13
  next call.
14
14
 
@@ -24,7 +24,7 @@ released when no other live session claims it or is working in its directory.
24
24
 
25
25
  ### A dev server stopped when I opened a new session
26
26
 
27
- **Problem:** Starting cdp-tools in a project stopped a dev server that was
27
+ **Problem:** Starting devharness in a project stopped a dev server that was
28
28
  already running.
29
29
 
30
30
  **Cause:** Every session that had claimed it was gone, so it was collected as
@@ -34,7 +34,7 @@ running until you reboot.
34
34
  **Solutions:**
35
35
  - Restart it (`server({ action: 'start', serverId: '...' })`).
36
36
  - To keep a server outside this lifecycle, run it yourself rather than through
37
- the `server` tool; cdp-tools only collects servers it manages, and only ones
37
+ the `server` tool; devharness only collects servers it manages, and only ones
38
38
  it can prove nobody is left to use.
39
39
 
40
40
  ## Chrome Connection Issues
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devharness",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
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",
@@ -22,6 +22,7 @@
22
22
  "test:coverage": "vitest run --coverage",
23
23
  "stress:suspend": "node scripts/stress-suspend.mjs",
24
24
  "check:targets": "node scripts/check-target-resume.mjs",
25
+ "check:workers": "node scripts/check-worker-eval.mjs",
25
26
  "prepublishOnly": "npm run test:run && npm run build:verify",
26
27
  "version": "node scripts/sync-skill-version.mjs",
27
28
  "postversion": "git push && git push --tags"
@@ -1,8 +1,8 @@
1
1
  ---
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
- 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.9.8
4
+ compatibility: Requires the devharness MCP server to be connected (tools such as launchChrome, breakpoint, inspect, replay, server, issues). The shell commands need `devharness` on PATH (`npm i -g devharness`); without it use `npx -y devharness@<version> <command>`. Previously published as cdp-tools-mcp.
5
+ version: 0.9.10
6
6
  ---
7
7
 
8
8
  # devharness
@@ -27,6 +27,7 @@ Launched without a reference? `tab({ action: 'rename', reference: "unnamed-conne
27
27
 
28
28
  Paused: `inspect({ action: 'getCallStack' })` → `getVariables` → `evaluateExpression`.
29
29
  Watch: `console({ action: 'list' })`, `network({ action: 'list' })` (needs `network({ action: 'enable' })` first).
30
+ Inside a worker: `inspect({ action: 'listTargets' })` → `evaluateExpression({ target, expression })`, and `console({ action: 'list', target })` — a service worker's console reaches no page listener.
30
31
 
31
32
  ## `.devharness/` must be git-ignored
32
33
 
@@ -63,22 +64,49 @@ Server merges and re-validates. Same token, repeat until it passes. Expires in 5
63
64
 
64
65
  **Guard blocked a valid call** (dead port, breakpoint pause) → it was already recorded. Acknowledge (`server({ action: 'acknowledgePort' })`, `acknowledgeStartup`), then use the footer's `replay` hint. Don't rebuild the arguments; don't use a `continuationToken` here.
65
66
 
66
- ## Get told the moment a guard blocks
67
+ ## The event stream
67
68
 
68
- Guards only surface on your *next* devharness call, so a server that dies while you're editing files stays invisible until you happen to call back. Every new block also appends one JSON line to `.devharness/logs/blocks.jsonl` `{ts, guard, tool, detail, resolve}`, one of `port`, `breakpoint`, `pendingStartup`, `bug`, `duplicateSession`.
69
+ Everything devharness pushes at you - a guard block, a message from another session - appends one JSON line to `~/.devharness/events/<sessionId>.jsonl`. One file, one watch, and any kind added later arrives on the same watch.
69
70
 
70
- Arm a Claude Code Monitor once, right after `launchChrome`/`server start`:
71
+ Installed as a plugin, a `SessionStart` hook prints that path and the `Monitor` call at the top of every session. Arm it when you see it:
71
72
 
72
73
  ```
73
74
  Monitor({
74
- command: "mkdir -p .devharness/logs && touch .devharness/logs/blocks.jsonl && tail -f -n0 .devharness/logs/blocks.jsonl",
75
- description: "devharness guard blocks",
75
+ command: "mkdir -p ~/.devharness/events && touch <streamPath> && tail -f -n0 <streamPath>",
76
+ description: "devharness events",
76
77
  persistent: true,
77
78
  timeout_ms: 3600000
78
79
  })
79
80
  ```
80
81
 
81
- `-n0` skips history you only want blocks from now on. One line per *new* block, not per blocked call; the same block re-firing stays quiet until a call gets through all guards and it recurs. Act on the event's `resolve` field.
82
+ Nothing is lost without it: blocks and messages still surface on your next devharness call. The watch is what makes them arrive while you are doing something else, which for a dev server that died an hour ago is the difference that matters.
83
+
84
+ Each line carries `kind` and, where there is one, `resolve` - the call that clears it. `kind: "block"` also carries `guard`, one of `port`, `breakpoint`, `pendingStartup`, `bug`, `duplicateSession`; blocks are deduplicated, one line per *new* block rather than one per blocked call. `kind: "message"` carries `from` and the message id.
85
+
86
+ ## Talking to another devharness session
87
+
88
+ Two devharness sessions on this machine reach each other by mailbox id - the session hitting a devharness bug and the session working on devharness itself, for example.
89
+
90
+ `message({ action: 'sessions' })` lists who is reachable and prints this session's own mailbox path.
91
+
92
+ ```
93
+ message({ action: 'send', to: 'a1b2c3d4', text: 'Repro: ...', waitForReplyMs: 120000 })
94
+ ```
95
+
96
+ That holds the call open until something lands in this session's mailbox, then returns it; answer with `message({ action: 'reply', replyTo: '<id>', text: '...' })`. The wait returns on ANY arrival, not only a tagged reply - two sessions blocking at the same moment both release instead of both timing out.
97
+
98
+ An arriving message announces itself on the event stream, so the watch above covers it and there is no second watch to arm. `message({ action: 'read' })` is what takes them, advancing a cursor so each is returned once; the full history stays in the mailbox file.
99
+
100
+ ## Running a tool from the shell
101
+
102
+ `devharness <command>` typed in a session's shell runs that tool **inside that session**, against the connections it already holds. The plugin does not put `devharness` on PATH - `npm i -g devharness` does, or run it as `npx -y devharness@<version> <command>`. The SessionStart hook reports which of those applies here. The session is found by walking up the process tree, so `! devharness screenshot` uses the browser this session opened, not a new one.
103
+
104
+ - `devharness which` - which session this shell resolves to
105
+ - `devharness call <tool> '<json>'` - any tool: `devharness call config '{"action":"status"}'`
106
+ - `devharness sessions` / `send <id> "text"` / `read` / `reply <id> "text"` - the message tool, with `--wait=<ms>` to hold for an answer
107
+ - `--session=<id>` names a session explicitly, `--json` prints the raw response, `--timeout=<ms>` bounds the call
108
+
109
+ Two differences from an MCP call. Guards do not apply - a dead dev server port, a paused breakpoint or a pending bug blocks a tool call through MCP and does not block this one. And a session the supervisor has suspended is not listening, so the CLI reports that rather than waiting.
82
110
 
83
111
  ## Restarting devharness
84
112
 
@@ -1,6 +1,6 @@
1
1
  # Replay Sequences
2
2
 
3
- A sequence is an ordered list of tool calls you can re-run. It's how cdp-tools
3
+ A sequence is an ordered list of tool calls you can re-run. It's how devharness
4
4
  turns "I clicked around and hit the bug" into something repeatable - a
5
5
  regression test, a repro attached to an issue, or a multi-step automation.
6
6
 
@@ -590,7 +590,7 @@ A failing teardown step never changes the run's verdict; it is reported in its
590
590
  own section. Otherwise a broken cleanup would mask the failure it was cleaning up
591
591
  after.
592
592
 
593
- **Teardown is always best-effort.** A killed cdp-tools process takes any pending
593
+ **Teardown is always best-effort.** A killed devharness process takes any pending
594
594
  teardown with it, so it reduces accumulation and cannot guarantee a clean world.
595
595
  An assertion that depends on nothing being left over ("No assets yet") stays
596
596
  order-dependent whether or not teardown exists - mint your own fixture and assert
@@ -22,13 +22,15 @@ runs against (see the skill's Quick Start).
22
22
 
23
23
  **Execution**: `execution` (actions: pause, resume, stepOver, stepInto, stepOut, acknowledge)
24
24
 
25
- **Inspection**: `inspect` (actions: getCallStack, getVariables, evaluateExpression, searchCode, searchFunctions)
25
+ **Inspection**: `inspect` (actions: getCallStack, getVariables, evaluateExpression, searchCode, searchFunctions, listTargets)
26
+ - `listTargets` lists the service, dedicated and shared worker targets on this browser. `evaluateExpression({ target })` runs the expression inside one of them, addressed by target id or by a substring of its URL - a substring matching two targets is refused with both named. A worker's console reaches no page listener, so `console({ action: 'list' | 'recent', target })` reads it from that target; recording starts at first attach
26
27
  - `evaluateExpression` awaits a returned Promise by default (async IIFEs resolve to their settled value; a rejection is reported as the expression's own error). Pass `awaitPromise: false` to inspect the Promise object itself. While paused at a breakpoint only already-settled promises can be resolved - a pending one fails fast because the event loop is stopped
27
28
 
28
29
  **Source**: `getSourceCode`, `loadSourceMaps`
29
30
  - Individual tools, not actions
30
31
 
31
32
  **Console**: `console` (actions: list, get, recent, search, clear, setObjectDepth)
33
+ - `target` on `list` and `recent` reads a worker's console instead of the page's
32
34
 
33
35
  **Network**: `network` (actions: list, get, search, enable, disable, setConditions)
34
36
 
@@ -75,9 +77,14 @@ runs against (see the skill's Quick Start).
75
77
  - `pullSequence` writes a sequence out of an issue to disk. Nothing is written until you ask, and nothing is ever run automatically: sequence steps are `{tool, params}` for **any** tool, so a sequence in a public issue is a script, not a macro. One authored by a GitHub account other than the one `gh` is logged in as is refused until a **person** has read it and re-run with `confirm: true` - an agent must not confirm on its own. One using `execution`, `saveToDisk`, `server`, `request` or `download` is refused unless you pass `allowPrivilegedSteps: true`. Read the step list in the response before you do
76
78
  - All of these are blocked while any bug is `pending` - `acknowledge` first
77
79
 
80
+ **Messages**: `message` (actions: sessions, send, read, reply)
81
+ - Text between two devharness sessions on this machine - a session hitting a devharness bug talking to the session working on devharness itself. `sessions` lists reachable mailboxes and this session's own mailbox path
82
+ - `send({ to, text, waitForReplyMs })` holds the call open until something lands in this session's mailbox (max 300000ms) and returns it; without `waitForReplyMs` it returns as soon as the line is written. `reply({ replyTo, text })` routes back to the sender of that message. The wait returns on ANY arrival, not only a tagged reply, so two sessions blocking at the same moment both release
83
+ - The mailbox is one append-only JSONL file per session under `~/.devharness/messages/`, holding the conversation and the read cursor; the global directory is what makes it reach across project roots. Nothing watches it. An arrival announces itself on that session's event stream, `~/.devharness/events/<id>.jsonl`, so one watch covers messages and guard blocks alike; without one, messages surface on the next `message({ action: 'read' })`
84
+
78
85
  **Server**: `server` (actions: start, stop, restart, list, logs, stopAll, setAutoRun, clearLogs, remove, monitorPort, unmonitorPort, listMonitored, acknowledgePort, acknowledgeStartup, extendStartup, cancelPendingRestart)
79
86
  - Use `global: true` to access servers started from a different working directory
80
- - `start({ watch: true, watchPaths?: [...] })`: cdp-tools watches the given paths (default: cwd) and auto-restarts the server on file changes, instead of relying on `--watch`/nodemon. Pause-aware: if a breakpoint debugger is paused on that server's inspector port, the restart queues instead of firing immediately - `cancelPendingRestart` discards a queued restart to keep debugging without it firing on resume
87
+ - `start({ watch: true, watchPaths?: [...] })`: devharness watches the given paths (default: cwd) and auto-restarts the server on file changes, instead of relying on `--watch`/nodemon. Pause-aware: if a breakpoint debugger is paused on that server's inspector port, the restart queues instead of firing immediately - `cancelPendingRestart` discards a queued restart to keep debugging without it firing on resume
81
88
 
82
89
  **Replay**: `replay` (actions: history, create, list, get, delete, export, load, listSaved, deleteSaved, run, runAll, step, finish, insert, addConditional, status, cancel, repeat, runFromLog, recordInteraction)
83
90
  - `recordInteraction`: record mouse, keyboard, and navigation events with a visual overlay
@@ -101,6 +108,6 @@ runs against (see the skill's Quick Start).
101
108
  - `show`: Display current configuration
102
109
  - `listTools`: List all toggleable tools with status and dependency conflicts
103
110
  - `reload`: Re-read config.json now (also happens automatically on file edits, ~250ms debounce). Doesn't apply `tools.enabled`/`tools.disabled` - those need `restart`
104
- - `restart`: Restart cdp-tools itself via the mcp-supervisor (see "Restarting cdp-tools" above) - use when the server seems stuck/broken, or to apply `tools.enabled`/`tools.disabled` changes
111
+ - `restart`: Restart devharness itself via the mcp-supervisor (see "Restarting devharness" above) - use when the server seems stuck/broken, or to apply `tools.enabled`/`tools.disabled` changes
105
112
  - `listProfiles`: List named persistent Chrome profiles and the root they live under
106
113
  - `resetProfile`: Wipe and recreate a named profile (`config({ action: 'resetProfile', profile: 'device-a' })`). Refused while a live Chrome holds that profile - nothing is deleted in that case