Skip to content

Commit 5c19cdf

Browse files
committed
refactor: replace wait --components N with wait --component <name>
Wait for a specific component by display name instead of an arbitrary count. More useful for agents that need to wait for a particular part of the UI to render after a reload.
1 parent 20a9044 commit 5c19cdf

File tree

8 files changed

+30
-24
lines changed

8 files changed

+30
-24
lines changed

.changeset/connection-health.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@
22
"agent-react-devtools": minor
33
---
44

5-
Add connection health tracking and `wait` command
5+
Add `wait` command and connection health tracking
6+
7+
**`wait` command**
8+
9+
Block until a condition is met, with `--timeout` (default 30s) and non-zero exit on timeout:
10+
11+
- `wait --connected` — block until a React app connects via WebSocket
12+
- `wait --component <name>` — block until a component with the given name appears in the tree
13+
14+
**Connection health in `status`**
615

716
- Track connect, disconnect, and reconnect events with timestamps
817
- Show last connection event in `status` output (e.g. "app reconnected 3s ago")
918
- Show contextual hint when `get tree` returns empty after a disconnect
10-
- Add `wait --connected` to block until a React app connects
11-
- Add `wait --components N` to block until N components are mounted
12-
- Both wait variants support `--timeout` (default 30s) and exit non-zero on timeout

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ Components are labeled `@c1`, `@c2`, etc. You can use these labels or numeric ID
125125

126126
### Wait
127127

128-
Block until a React app is connected or a component count threshold is met. Useful in scripts or agent workflows where the daemon starts before the app:
128+
Block until a condition is met. Useful in scripts or agent workflows where the daemon starts before the app:
129129

130130
```sh
131-
agent-react-devtools wait --connected [--timeout 30] # Block until an app connects
132-
agent-react-devtools wait --components 5 [--timeout 30] # Block until 5+ components exist
131+
agent-react-devtools wait --connected [--timeout 30] # Block until an app connects
132+
agent-react-devtools wait --component App [--timeout 30] # Block until a component appears
133133
```
134134

135135
Exits with code 0 when the condition is met, or code 1 on timeout.

packages/agent-react-devtools/skills/react-devtools/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ agent-react-devtools start # Start daemon (auto-starts on first com
2424
agent-react-devtools stop # Stop daemon
2525
agent-react-devtools status # Check connection, component count, last event
2626
agent-react-devtools wait --connected # Block until a React app connects
27-
agent-react-devtools wait --components 5 # Block until ≥5 components are mounted
27+
agent-react-devtools wait --component App # Block until a component appears
2828
```
2929

3030
### Component Inspection

packages/agent-react-devtools/skills/react-devtools/references/commands.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ If profiling is active, shows `Profiling: active`.
2424
### `agent-react-devtools wait --connected [--timeout S]`
2525
Block until at least one React app connects via WebSocket. Resolves immediately if already connected. Default timeout: 30s. Exits non-zero on timeout.
2626

27-
### `agent-react-devtools wait --components N [--timeout S]`
28-
Block until at least N components are present in the tree. Useful after a reload to wait for the app to fully render. Default timeout: 30s. Exits non-zero on timeout.
27+
### `agent-react-devtools wait --component <name> [--timeout S]`
28+
Block until a component with the given display name appears in the tree. Uses case-insensitive substring matching (same as `find`). Useful after a reload to wait for a specific part of the UI to render. Default timeout: 30s. Exits non-zero on timeout.
2929

3030
## Component Inspection
3131

packages/agent-react-devtools/src/cli.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Components:
3939
4040
Wait:
4141
wait --connected [--timeout S] Block until an app connects
42-
wait --components N [--timeout S] Block until N components exist
42+
wait --component <name> [--timeout S] Block until a component appears
4343
4444
Profiling:
4545
profile start [name] Start profiling session
@@ -221,15 +221,15 @@ async function main(): Promise<void> {
221221
let ipcCmd: IpcCommand;
222222
if (flags['connected'] !== undefined) {
223223
ipcCmd = { type: 'wait', condition: 'connected', timeout: timeoutMs };
224-
} else if (flags['components'] !== undefined) {
225-
const count = parseInt(flags['components'] as string, 10);
226-
if (isNaN(count) || count < 1) {
227-
console.error('Usage: devtools wait --components N [--timeout S]');
224+
} else if (flags['component'] !== undefined) {
225+
const name = flags['component'] as string;
226+
if (!name || name === 'true') {
227+
console.error('Usage: devtools wait --component <name> [--timeout S]');
228228
process.exit(1);
229229
}
230-
ipcCmd = { type: 'wait', condition: 'components', count, timeout: timeoutMs };
230+
ipcCmd = { type: 'wait', condition: 'component', name, timeout: timeoutMs };
231231
} else {
232-
console.error('Usage: devtools wait --connected|--components N [--timeout S]');
232+
console.error('Usage: devtools wait --connected|--component <name> [--timeout S]');
233233
process.exit(1);
234234
}
235235

packages/agent-react-devtools/src/daemon.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class Daemon {
312312
switch (cmd.condition) {
313313
case 'connected':
314314
return this.bridge.getConnectedAppCount() > 0;
315-
case 'components':
316-
return this.tree.getComponentCount() >= cmd.count;
315+
case 'component':
316+
return this.tree.findByName(cmd.name, false).length > 0;
317317
default:
318318
return false;
319319
}

packages/agent-react-devtools/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export type IpcCommand =
117117
| { type: 'profile-timeline'; limit?: number }
118118
| { type: 'profile-commit'; index: number; limit?: number }
119119
| { type: 'wait'; condition: 'connected'; timeout?: number }
120-
| { type: 'wait'; condition: 'components'; count: number; timeout?: number };
120+
| { type: 'wait'; condition: 'component'; name: string; timeout?: number };
121121

122122
export interface IpcResponse {
123123
ok: boolean;

packages/e2e-tests/src/connection-health.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ describe('Connection health (e2e)', () => {
164164
expect(data.timeout).toBe(true);
165165
});
166166

167-
it('wait --components should resolve when enough components arrive', async () => {
167+
it('wait --component should resolve when the named component appears', async () => {
168168
const ws = await connectMockApp(port);
169169
await sleep(300);
170170

171-
// Start waiting for 3 components (root + 2)
171+
// Start waiting for Counter to appear
172172
const waitPromise = sendIpcCommand(
173173
socketPath,
174-
{ type: 'wait', condition: 'components', count: 3, timeout: 5000 },
174+
{ type: 'wait', condition: 'component', name: 'Counter', timeout: 5000 },
175175
10_000,
176176
);
177177

@@ -188,7 +188,7 @@ describe('Connection health (e2e)', () => {
188188
expect(resp.ok).toBe(true);
189189
const data = resp.data as { met: boolean; condition: string };
190190
expect(data.met).toBe(true);
191-
expect(data.condition).toBe('components');
191+
expect(data.condition).toBe('component');
192192

193193
ws.close();
194194
await sleep(300);

0 commit comments

Comments
 (0)