agent-react-devtools 0.1.0 → 0.2.0-canary-20260210204855
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/CHANGELOG.md +14 -0
- package/README.md +229 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/connect.d.ts +16 -0
- package/dist/connect.js +47 -0
- package/dist/connect.js.map +1 -0
- package/dist/init-7IJ2VXT7.js +202 -0
- package/dist/init-7IJ2VXT7.js.map +1 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +40 -0
- package/dist/vite.js.map +1 -0
- package/package.json +33 -2
- package/src/__tests__/cli-parser.test.ts +0 -76
- package/src/__tests__/component-tree.test.ts +0 -229
- package/src/__tests__/formatters.test.ts +0 -189
- package/src/__tests__/profiler.test.ts +0 -264
- package/src/cli.ts +0 -315
- package/src/component-tree.ts +0 -495
- package/src/daemon-client.ts +0 -144
- package/src/daemon.ts +0 -275
- package/src/devtools-bridge.ts +0 -391
- package/src/formatters.ts +0 -270
- package/src/profiler.ts +0 -356
- package/src/types.ts +0 -126
- package/tsconfig.json +0 -9
- package/tsup.config.ts +0 -17
- package/vitest.config.ts +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# agent-react-devtools
|
|
2
2
|
|
|
3
|
+
## 0.2.0-canary-20260210204855
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0c88c11: Zero-config app integration — connect your React app in one line:
|
|
8
|
+
|
|
9
|
+
- **`agent-react-devtools init`** — CLI command that auto-detects your framework (Vite, Next.js, CRA, React Native) and patches the right config files. Next.js App Router gets a `'use client'` wrapper so the connect code runs in the browser.
|
|
10
|
+
- **`agent-react-devtools/connect`** — add `import 'agent-react-devtools/connect'` as the first line of your entry point to connect to the daemon. Skips SSR and production builds automatically, never blocks your app.
|
|
11
|
+
- **`agent-react-devtools/vite`** — Vite plugin that injects the connect script automatically, no app code changes needed.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 10ac53c: Add comprehensive README with usage examples and MIT LICENSE file
|
|
16
|
+
|
|
3
17
|
## 0.1.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# agent-react-devtools
|
|
2
|
+
|
|
3
|
+
Give your AI agent eyes into your React app. Inspect component trees, read props and state, and profile rendering performance — all from the command line. Inspired by Vercel's [agent-browser](https://github.com/vercel-labs/agent-browser) and Callstack's [agent-device](https://github.com/callstackincubator/agent-device).
|
|
4
|
+
|
|
5
|
+
The project is in early development and considered experimental. Pull requests are welcome!
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Walk the full component tree with props, state, and hooks
|
|
10
|
+
- Search for components by display name
|
|
11
|
+
- Profile renders: find slow components, excessive re-renders, and commit timelines
|
|
12
|
+
- Persistent background daemon that survives across CLI calls
|
|
13
|
+
- Token-efficient output built for LLM consumption
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install -g agent-react-devtools
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or run it directly:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npx agent-react-devtools start
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
agent-react-devtools start
|
|
31
|
+
agent-react-devtools status
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Daemon: running (port 8097)
|
|
36
|
+
Apps: 1 connected, 24 components
|
|
37
|
+
Uptime: 12s
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Browse the component tree:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
agent-react-devtools get tree --depth 3
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
@c1 [fn] "App"
|
|
48
|
+
├─ @c2 [fn] "Header"
|
|
49
|
+
│ ├─ @c3 [fn] "Nav"
|
|
50
|
+
│ └─ @c4 [fn] "SearchBar"
|
|
51
|
+
├─ @c5 [fn] "TodoList"
|
|
52
|
+
│ ├─ @c6 [fn] "TodoItem" key="1"
|
|
53
|
+
│ ├─ @c7 [fn] "TodoItem" key="2"
|
|
54
|
+
│ └─ @c8 [fn] "TodoItem" key="3"
|
|
55
|
+
└─ @c9 [fn] "Footer"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Inspect a component's props, state, and hooks:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
agent-react-devtools get component @c6
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
@c6 [fn] "TodoItem" key="1"
|
|
66
|
+
props:
|
|
67
|
+
id: 1
|
|
68
|
+
text: "Buy groceries"
|
|
69
|
+
done: false
|
|
70
|
+
onToggle: ƒ
|
|
71
|
+
hooks:
|
|
72
|
+
State: false
|
|
73
|
+
Callback: ƒ
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Find components by name:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
agent-react-devtools find TodoItem
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
@c6 [fn] "TodoItem" key="1"
|
|
84
|
+
@c7 [fn] "TodoItem" key="2"
|
|
85
|
+
@c8 [fn] "TodoItem" key="3"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Profile rendering performance:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
agent-react-devtools profile start
|
|
92
|
+
# ... interact with the app ...
|
|
93
|
+
agent-react-devtools profile stop
|
|
94
|
+
agent-react-devtools profile slow
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Slowest (by avg render time):
|
|
99
|
+
TodoList avg:4.2ms max:8.1ms renders:6 cause:props
|
|
100
|
+
SearchBar avg:2.1ms max:3.4ms renders:12 cause:hooks
|
|
101
|
+
Header avg:0.8ms max:1.2ms renders:3 cause:parent
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Commands
|
|
105
|
+
|
|
106
|
+
### Daemon
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
agent-react-devtools start [--port 8097] # Start daemon
|
|
110
|
+
agent-react-devtools stop # Stop daemon
|
|
111
|
+
agent-react-devtools status # Connection status
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Components
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
agent-react-devtools get tree [--depth N] # Component hierarchy
|
|
118
|
+
agent-react-devtools get component <@c1 | id> # Props, state, hooks
|
|
119
|
+
agent-react-devtools find <name> [--exact] # Search by display name
|
|
120
|
+
agent-react-devtools count # Component count by type
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Components are labeled `@c1`, `@c2`, etc. You can use these labels or numeric IDs interchangeably.
|
|
124
|
+
|
|
125
|
+
### Profiling
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
agent-react-devtools profile start [name] # Begin a profiling session
|
|
129
|
+
agent-react-devtools profile stop # Stop and collect data
|
|
130
|
+
agent-react-devtools profile report <@c1 | id> # Render report for a component
|
|
131
|
+
agent-react-devtools profile slow [--limit N] # Slowest components by avg duration
|
|
132
|
+
agent-react-devtools profile rerenders [--limit N] # Most re-rendered components
|
|
133
|
+
agent-react-devtools profile timeline [--limit N] # Commit timeline
|
|
134
|
+
agent-react-devtools profile commit <N | #N> [--limit N] # Single commit detail
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Connecting Your App
|
|
138
|
+
|
|
139
|
+
### Quick setup
|
|
140
|
+
|
|
141
|
+
Run the init command in your project root to auto-configure your framework:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
npx agent-react-devtools init
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This detects your framework (Vite, Next.js, CRA) and patches the appropriate config file.
|
|
148
|
+
|
|
149
|
+
### One-line import
|
|
150
|
+
|
|
151
|
+
Add a single import as the first line of your entry point (e.g. `src/main.tsx`):
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import "agent-react-devtools/connect";
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This handles everything: deleting the Vite hook stub, initializing react-devtools-core, and connecting via WebSocket. Your app is never blocked — if the daemon isn't running, it times out after 2 seconds.
|
|
158
|
+
|
|
159
|
+
### Vite plugin
|
|
160
|
+
|
|
161
|
+
For Vite apps, use the plugin instead — no changes to your app code needed:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// vite.config.ts
|
|
165
|
+
import { defineConfig } from "vite";
|
|
166
|
+
import react from "@vitejs/plugin-react";
|
|
167
|
+
import { reactDevtools } from "agent-react-devtools/vite";
|
|
168
|
+
|
|
169
|
+
export default defineConfig({
|
|
170
|
+
plugins: [reactDevtools(), react()],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The plugin only runs in dev mode (`vite dev`), not in production builds.
|
|
175
|
+
|
|
176
|
+
Options:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
reactDevtools({ port: 8097, host: "localhost" });
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### React Native
|
|
183
|
+
|
|
184
|
+
React Native apps connect to DevTools automatically — no code changes needed:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
agent-react-devtools start
|
|
188
|
+
npx react-native start
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For physical devices, forward the port:
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
adb reverse tcp:8097 tcp:8097
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
For Expo, the connection works automatically with the Expo dev client.
|
|
198
|
+
|
|
199
|
+
To use a custom port, set the `REACT_DEVTOOLS_PORT` environment variable.
|
|
200
|
+
|
|
201
|
+
## Using with AI Agents
|
|
202
|
+
|
|
203
|
+
Add something like this to your project's `CLAUDE.md` (or equivalent agent instructions):
|
|
204
|
+
|
|
205
|
+
```markdown
|
|
206
|
+
## React Debugging
|
|
207
|
+
|
|
208
|
+
This project uses agent-react-devtools to inspect the running React app.
|
|
209
|
+
|
|
210
|
+
- `agent-react-devtools start` — start the daemon
|
|
211
|
+
- `agent-react-devtools status` — check if the app is connected
|
|
212
|
+
- `agent-react-devtools get tree` — see the component hierarchy
|
|
213
|
+
- `agent-react-devtools get component @c1` — inspect a specific component
|
|
214
|
+
- `agent-react-devtools find <Name>` — search for components
|
|
215
|
+
- `agent-react-devtools profile start` / `profile stop` / `profile slow` — diagnose render performance
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Development
|
|
219
|
+
|
|
220
|
+
```sh
|
|
221
|
+
bun install # Install dependencies
|
|
222
|
+
bun run build # Build
|
|
223
|
+
bun run test # Run tests
|
|
224
|
+
bun run typecheck # Type check
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT
|
package/dist/cli.js
CHANGED
|
@@ -325,6 +325,9 @@ function pad(s, len) {
|
|
|
325
325
|
function usage() {
|
|
326
326
|
return `Usage: devtools <command> [options]
|
|
327
327
|
|
|
328
|
+
Setup:
|
|
329
|
+
init [--dry-run] Auto-configure your React app
|
|
330
|
+
|
|
328
331
|
Daemon:
|
|
329
332
|
start [--port 8097] Start daemon
|
|
330
333
|
stop Stop daemon
|
|
@@ -382,6 +385,11 @@ async function main() {
|
|
|
382
385
|
const cmd0 = command[0];
|
|
383
386
|
const cmd1 = command[1];
|
|
384
387
|
try {
|
|
388
|
+
if (cmd0 === "init") {
|
|
389
|
+
const { runInit } = await import("./init-7IJ2VXT7.js");
|
|
390
|
+
await runInit(process.cwd(), flags["dry-run"] === true);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
385
393
|
if (cmd0 === "start") {
|
|
386
394
|
const port = flags["port"] ? parseInt(flags["port"], 10) : void 0;
|
|
387
395
|
await ensureDaemon(port);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/daemon-client.ts","../src/formatters.ts","../src/cli.ts"],"sourcesContent":["import net from 'node:net';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { IpcCommand, IpcResponse, DaemonInfo } from './types.js';\n\nconst DEFAULT_STATE_DIR = path.join(\n process.env.HOME || process.env.USERPROFILE || '/tmp',\n '.agent-react-devtools',\n);\n\nlet stateDir = DEFAULT_STATE_DIR;\n\nexport function setStateDir(dir: string): void {\n stateDir = dir;\n}\n\nfunction getDaemonInfoPath(): string {\n return path.join(stateDir, 'daemon.json');\n}\n\nfunction getSocketPath(): string {\n return path.join(stateDir, 'daemon.sock');\n}\n\nexport function readDaemonInfo(): DaemonInfo | null {\n try {\n const raw = fs.readFileSync(getDaemonInfoPath(), 'utf-8');\n return JSON.parse(raw) as DaemonInfo;\n } catch {\n return null;\n }\n}\n\nfunction isDaemonAlive(info: DaemonInfo): boolean {\n try {\n // Signal 0 doesn't kill, just checks if process exists\n process.kill(info.pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDaemon(port?: number): Promise<void> {\n const info = readDaemonInfo();\n if (info && isDaemonAlive(info)) {\n return; // Already running\n }\n\n // Clean up stale files\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n try {\n fs.unlinkSync(getSocketPath());\n } catch {\n // ignore\n }\n\n // Start daemon as detached child process\n const daemonScript = path.join(\n path.dirname(new URL(import.meta.url).pathname),\n 'daemon.js',\n );\n\n const args = [];\n if (port) args.push(`--port=${port}`);\n if (stateDir !== DEFAULT_STATE_DIR) args.push(`--state-dir=${stateDir}`);\n\n const child = spawn(process.execPath, [daemonScript, ...args], {\n detached: true,\n stdio: 'ignore',\n });\n child.unref();\n\n // Wait for daemon to be ready (up to 5 seconds)\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 100));\n try {\n await sendCommand({ type: 'ping' });\n return;\n } catch {\n // not ready yet\n }\n }\n throw new Error('Daemon failed to start within 5 seconds');\n}\n\nexport function stopDaemon(): boolean {\n const info = readDaemonInfo();\n if (!info) return false;\n\n try {\n process.kill(info.pid, 'SIGTERM');\n // Clean up files\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n return true;\n } catch {\n return false;\n }\n}\n\nexport function sendCommand(cmd: IpcCommand): Promise<IpcResponse> {\n return new Promise((resolve, reject) => {\n const socketPath = getSocketPath();\n\n const conn = net.createConnection(socketPath, () => {\n conn.write(JSON.stringify(cmd) + '\\n');\n });\n\n let buffer = '';\n conn.on('data', (chunk) => {\n buffer += chunk.toString();\n const newlineIdx = buffer.indexOf('\\n');\n if (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx);\n conn.end();\n try {\n resolve(JSON.parse(line) as IpcResponse);\n } catch {\n reject(new Error('Invalid response from daemon'));\n }\n }\n });\n\n conn.on('error', (err) => {\n reject(new Error(`Cannot connect to daemon: ${err.message}`));\n });\n\n // Timeout after 30 seconds\n conn.setTimeout(30_000, () => {\n conn.destroy();\n reject(new Error('Command timed out'));\n });\n });\n}\n","import type {\n StatusInfo,\n InspectedElement,\n ComponentRenderReport,\n} from './types.js';\nimport type { TreeNode } from './component-tree.js';\nimport type { ProfileSummary, TimelineEntry, CommitDetail } from './profiler.js';\n\n// ── Abbreviations for component types ──\nconst TYPE_ABBREV: Record<string, string> = {\n function: 'fn',\n class: 'cls',\n host: 'host',\n memo: 'memo',\n forwardRef: 'fRef',\n profiler: 'prof',\n suspense: 'susp',\n context: 'ctx',\n other: '?',\n};\n\nfunction typeTag(type: string): string {\n return TYPE_ABBREV[type] || type;\n}\n\n// ── Tree connector characters ──\nconst PIPE = '│ ';\nconst TEE = '├─ ';\nconst ELBOW = '└─ ';\nconst SPACE = ' ';\n\nexport function formatTree(nodes: TreeNode[]): string {\n if (nodes.length === 0) return 'No components (is a React app connected?)';\n\n // Build tree structure from the flat list\n const childrenMap = new Map<number | null, TreeNode[]>();\n for (const node of nodes) {\n const parentId = node.parentId;\n let siblings = childrenMap.get(parentId);\n if (!siblings) {\n siblings = [];\n childrenMap.set(parentId, siblings);\n }\n siblings.push(node);\n }\n\n const lines: string[] = [];\n\n function walk(nodeId: number, prefix: string, isLast: boolean, isRoot: boolean): void {\n const node = nodes.find((n) => n.id === nodeId);\n if (!node) return;\n\n const connector = isRoot ? '' : isLast ? ELBOW : TEE;\n let line = `${node.label} [${typeTag(node.type)}] \"${node.displayName}\"`;\n if (node.key) line += ` key=\"${node.key}\"`;\n\n lines.push(`${prefix}${connector}${line}`);\n\n const children = childrenMap.get(node.id) || [];\n const childPrefix = isRoot ? '' : prefix + (isLast ? SPACE : PIPE);\n\n for (let i = 0; i < children.length; i++) {\n walk(children[i].id, childPrefix, i === children.length - 1, false);\n }\n }\n\n // Find root nodes\n const roots = childrenMap.get(null) || [];\n for (let i = 0; i < roots.length; i++) {\n walk(roots[i].id, '', i === roots.length - 1, true);\n }\n\n return lines.join('\\n');\n}\n\nexport function formatComponent(element: InspectedElement, label?: string): string {\n const lines: string[] = [];\n\n const ref = label || `#${element.id}`;\n let header = `${ref} [${typeTag(element.type)}] \"${element.displayName}\"`;\n if (element.key) header += ` key=\"${element.key}\"`;\n lines.push(header);\n\n // Props\n if (element.props && Object.keys(element.props).length > 0) {\n lines.push('props:');\n for (const [key, value] of Object.entries(element.props)) {\n lines.push(` ${key}: ${formatCompactValue(value) ?? 'undefined'}`);\n }\n }\n\n // State\n if (element.state && Object.keys(element.state).length > 0) {\n lines.push('state:');\n for (const [key, value] of Object.entries(element.state)) {\n lines.push(` ${key}: ${formatCompactValue(value) ?? 'undefined'}`);\n }\n }\n\n // Hooks\n if (element.hooks && element.hooks.length > 0) {\n lines.push('hooks:');\n for (const h of element.hooks) {\n const val = formatCompactValue(h.value);\n lines.push(val !== undefined ? ` ${h.name}: ${val}` : ` ${h.name}`);\n if (h.subHooks && h.subHooks.length > 0) {\n for (const sh of h.subHooks) {\n const sval = formatCompactValue(sh.value);\n lines.push(sval !== undefined ? ` ${sh.name}: ${sval}` : ` ${sh.name}`);\n }\n }\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function formatSearchResults(results: TreeNode[]): string {\n if (results.length === 0) return 'No components found';\n\n return results\n .map((n) => {\n let line = `${n.label} [${typeTag(n.type)}] \"${n.displayName}\"`;\n if (n.key) line += ` key=\"${n.key}\"`;\n return line;\n })\n .join('\\n');\n}\n\nexport function formatCount(counts: Record<string, number>): string {\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const parts = Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .map(([type, count]) => `${typeTag(type)}:${count}`)\n .join(' ');\n return `${total} components (${parts})`;\n}\n\nexport function formatStatus(status: StatusInfo): string {\n const lines: string[] = [];\n lines.push(`Daemon: running (port ${status.port})`);\n lines.push(\n `Apps: ${status.connectedApps} connected, ${status.componentCount} components`,\n );\n if (status.profilingActive) {\n lines.push('Profiling: active');\n }\n const upSec = Math.round(status.uptime / 1000);\n lines.push(`Uptime: ${upSec}s`);\n return lines.join('\\n');\n}\n\nexport function formatProfileSummary(summary: ProfileSummary): string {\n const lines: string[] = [];\n const durSec = (summary.duration / 1000).toFixed(1);\n lines.push(\n `Profile \"${summary.name}\" (${durSec}s, ${summary.commitCount} commits)`,\n );\n\n if (summary.componentRenderCounts.length > 0) {\n lines.push('');\n lines.push('Top renders:');\n for (const c of summary.componentRenderCounts.slice(0, 10)) {\n const name = c.displayName || `#${c.id}`;\n lines.push(` ${name} ${c.count} renders`);\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function formatProfileReport(report: ComponentRenderReport, label?: string): string {\n const lines: string[] = [];\n const ref = label || `#${report.id}`;\n lines.push(`${ref} \"${report.displayName}\"`);\n lines.push(\n `renders:${report.renderCount} avg:${report.avgDuration.toFixed(1)}ms max:${report.maxDuration.toFixed(1)}ms total:${report.totalDuration.toFixed(1)}ms`,\n );\n if (report.causes.length > 0) {\n lines.push(`causes: ${report.causes.join(', ')}`);\n }\n return lines.join('\\n');\n}\n\nexport function formatSlowest(reports: ComponentRenderReport[]): string {\n if (reports.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Slowest (by avg render time):'];\n for (const r of reports) {\n const cause = r.causes[0] || '?';\n lines.push(\n ` ${pad(r.displayName, 20)} avg:${r.avgDuration.toFixed(1)}ms max:${r.maxDuration.toFixed(1)}ms renders:${r.renderCount} cause:${cause}`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatRerenders(reports: ComponentRenderReport[]): string {\n if (reports.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Most re-renders:'];\n for (const r of reports) {\n const cause = r.causes[0] || '?';\n lines.push(\n ` ${pad(r.displayName, 20)} ${r.renderCount} renders — ${cause}`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatTimeline(entries: TimelineEntry[]): string {\n if (entries.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Commit timeline:'];\n for (const e of entries) {\n lines.push(\n ` #${e.index} ${e.duration.toFixed(1)}ms ${e.componentCount} components`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatCommitDetail(detail: CommitDetail): string {\n const lines: string[] = [];\n lines.push(`Commit #${detail.index} ${detail.duration.toFixed(1)}ms ${detail.totalComponents} components`);\n lines.push('');\n for (const c of detail.components) {\n const causes = c.causes.length > 0 ? c.causes.join(', ') : '?';\n lines.push(` ${pad(c.displayName, 24)} self:${c.selfDuration.toFixed(1)}ms total:${c.actualDuration.toFixed(1)}ms ${causes}`);\n }\n const hidden = detail.totalComponents - detail.components.length;\n if (hidden > 0) {\n lines.push(` ... ${hidden} more (use --limit to show more)`);\n }\n return lines.join('\\n');\n}\n\n// ── Helpers ──\n\nfunction formatValue(obj: unknown): string {\n try {\n return JSON.stringify(obj, replacer, 0) || 'undefined';\n } catch {\n return String(obj);\n }\n}\n\nfunction formatCompactValue(val: unknown): string | undefined {\n if (val === undefined) return undefined;\n if (val === null) return 'null';\n if (typeof val === 'function') return 'ƒ';\n if (typeof val === 'string') return `\"${val}\"`;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n try {\n const s = JSON.stringify(val, replacer, 0);\n if (s && s.length > 60) return s.slice(0, 57) + '...';\n return s || String(val);\n } catch {\n return String(val);\n }\n}\n\nfunction replacer(_key: string, value: unknown): unknown {\n if (typeof value === 'function') return 'ƒ';\n return value;\n}\n\nfunction pad(s: string, len: number): string {\n return s.length >= len ? s : s + ' '.repeat(len - s.length);\n}\n","import {\n ensureDaemon,\n sendCommand,\n stopDaemon,\n readDaemonInfo,\n setStateDir,\n} from './daemon-client.js';\nimport {\n formatTree,\n formatComponent,\n formatSearchResults,\n formatCount,\n formatStatus,\n formatProfileSummary,\n formatProfileReport,\n formatSlowest,\n formatRerenders,\n formatTimeline,\n formatCommitDetail,\n} from './formatters.js';\nimport type { IpcCommand } from './types.js';\n\nfunction usage(): string {\n return `Usage: devtools <command> [options]\n\nDaemon:\n start [--port 8097] Start daemon\n stop Stop daemon\n status Show daemon status\n\nComponents:\n get tree [--depth N] Component hierarchy\n get component <@c1 | id> Props, state, hooks\n find <name> [--exact] Search by display name\n count Component count by type\n\nProfiling:\n profile start [name] Start profiling session\n profile stop Stop profiling, collect data\n profile report <@c1 | id> Render report for component\n profile slow [--limit N] Slowest components (by avg)\n profile rerenders [--limit N] Most re-rendered components\n profile timeline [--limit N] Commit timeline\n profile commit <N | #N> [--limit N] Detail for specific commit`;\n}\n\nfunction parseArgs(argv: string[]): {\n command: string[];\n flags: Record<string, string | boolean>;\n} {\n const command: string[] = [];\n const flags: Record<string, string | boolean> = {};\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg.startsWith('--')) {\n const key = arg.slice(2);\n const eqIdx = key.indexOf('=');\n if (eqIdx !== -1) {\n flags[key.slice(0, eqIdx)] = key.slice(eqIdx + 1);\n } else {\n // Check if next arg is a value\n const next = argv[i + 1];\n if (next && !next.startsWith('--')) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n } else {\n command.push(arg);\n }\n }\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv.slice(2));\n\n if (command.length === 0 || flags['help']) {\n console.log(usage());\n process.exit(0);\n }\n\n // Configure custom state directory (for test isolation)\n if (typeof flags['state-dir'] === 'string') {\n setStateDir(flags['state-dir']);\n }\n\n const cmd0 = command[0];\n const cmd1 = command[1];\n\n try {\n // ── Daemon management ──\n if (cmd0 === 'start') {\n const port = flags['port'] ? parseInt(flags['port'] as string, 10) : undefined;\n await ensureDaemon(port);\n const resp = await sendCommand({ type: 'status' });\n if (resp.ok) {\n console.log(formatStatus(resp.data as any));\n }\n return;\n }\n\n if (cmd0 === 'stop') {\n const stopped = stopDaemon();\n console.log(stopped ? 'Daemon stopped' : 'Daemon is not running');\n return;\n }\n\n if (cmd0 === 'status') {\n const info = readDaemonInfo();\n if (!info) {\n console.log('Daemon is not running');\n process.exit(1);\n }\n try {\n const resp = await sendCommand({ type: 'status' });\n if (resp.ok) {\n console.log(formatStatus(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n } catch {\n console.log('Daemon is not running (stale info)');\n process.exit(1);\n }\n return;\n }\n\n // ── All other commands require the daemon ──\n await ensureDaemon();\n\n // ── Component inspection ──\n if (cmd0 === 'get' && cmd1 === 'tree') {\n const depth = flags['depth']\n ? parseInt(flags['depth'] as string, 10)\n : undefined;\n const ipcCmd: IpcCommand = { type: 'get-tree', depth };\n const resp = await sendCommand(ipcCmd);\n if (resp.ok) {\n console.log(formatTree(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'get' && cmd1 === 'component') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools get component <@c1 | id>');\n process.exit(1);\n }\n const id: number | string = raw.startsWith('@') ? raw : parseInt(raw, 10);\n if (typeof id === 'number' && isNaN(id)) {\n console.error('Usage: devtools get component <@c1 | id>');\n process.exit(1);\n }\n const resp = await sendCommand({ type: 'get-component', id });\n if (resp.ok) {\n console.log(formatComponent(resp.data as any, resp.label));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'find') {\n const name = command[1];\n if (!name) {\n console.error('Usage: devtools find <name> [--exact]');\n process.exit(1);\n }\n const exact = flags['exact'] === true;\n const resp = await sendCommand({ type: 'find', name, exact });\n if (resp.ok) {\n console.log(formatSearchResults(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'count') {\n const resp = await sendCommand({ type: 'count' });\n if (resp.ok) {\n console.log(formatCount(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n // ── Profiling ──\n if (cmd0 === 'profile' && cmd1 === 'start') {\n const name = command[2];\n const resp = await sendCommand({ type: 'profile-start', name });\n if (resp.ok) {\n console.log(resp.data);\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'stop') {\n const resp = await sendCommand({ type: 'profile-stop' });\n if (resp.ok) {\n console.log(formatProfileSummary(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'report') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools profile report <@c1 | id>');\n process.exit(1);\n }\n const componentId: number | string = raw.startsWith('@') ? raw : parseInt(raw, 10);\n if (typeof componentId === 'number' && isNaN(componentId)) {\n console.error('Usage: devtools profile report <@c1 | id>');\n process.exit(1);\n }\n const resp = await sendCommand({ type: 'profile-report', componentId });\n if (resp.ok) {\n console.log(formatProfileReport(resp.data as any, resp.label));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'slow') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-slow', limit });\n if (resp.ok) {\n console.log(formatSlowest(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'rerenders') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-rerenders', limit });\n if (resp.ok) {\n console.log(formatRerenders(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'commit') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools profile commit <N | #N>');\n process.exit(1);\n }\n const index = parseInt(raw.replace(/^#/, ''), 10);\n if (isNaN(index)) {\n console.error('Usage: devtools profile commit <N | #N>');\n process.exit(1);\n }\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-commit', index, limit });\n if (resp.ok) {\n console.log(formatCommitDetail(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'timeline') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-timeline', limit });\n if (resp.ok) {\n console.log(formatTimeline(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n console.error(`Unknown command: ${command.join(' ')}`);\n console.log(usage());\n process.exit(1);\n } catch (err) {\n console.error(\n err instanceof Error ? err.message : String(err),\n );\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/daemon-client.ts","../src/formatters.ts","../src/cli.ts"],"sourcesContent":["import net from 'node:net';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { IpcCommand, IpcResponse, DaemonInfo } from './types.js';\n\nconst DEFAULT_STATE_DIR = path.join(\n process.env.HOME || process.env.USERPROFILE || '/tmp',\n '.agent-react-devtools',\n);\n\nlet stateDir = DEFAULT_STATE_DIR;\n\nexport function setStateDir(dir: string): void {\n stateDir = dir;\n}\n\nfunction getDaemonInfoPath(): string {\n return path.join(stateDir, 'daemon.json');\n}\n\nfunction getSocketPath(): string {\n return path.join(stateDir, 'daemon.sock');\n}\n\nexport function readDaemonInfo(): DaemonInfo | null {\n try {\n const raw = fs.readFileSync(getDaemonInfoPath(), 'utf-8');\n return JSON.parse(raw) as DaemonInfo;\n } catch {\n return null;\n }\n}\n\nfunction isDaemonAlive(info: DaemonInfo): boolean {\n try {\n // Signal 0 doesn't kill, just checks if process exists\n process.kill(info.pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDaemon(port?: number): Promise<void> {\n const info = readDaemonInfo();\n if (info && isDaemonAlive(info)) {\n return; // Already running\n }\n\n // Clean up stale files\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n try {\n fs.unlinkSync(getSocketPath());\n } catch {\n // ignore\n }\n\n // Start daemon as detached child process\n const daemonScript = path.join(\n path.dirname(new URL(import.meta.url).pathname),\n 'daemon.js',\n );\n\n const args = [];\n if (port) args.push(`--port=${port}`);\n if (stateDir !== DEFAULT_STATE_DIR) args.push(`--state-dir=${stateDir}`);\n\n const child = spawn(process.execPath, [daemonScript, ...args], {\n detached: true,\n stdio: 'ignore',\n });\n child.unref();\n\n // Wait for daemon to be ready (up to 5 seconds)\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 100));\n try {\n await sendCommand({ type: 'ping' });\n return;\n } catch {\n // not ready yet\n }\n }\n throw new Error('Daemon failed to start within 5 seconds');\n}\n\nexport function stopDaemon(): boolean {\n const info = readDaemonInfo();\n if (!info) return false;\n\n try {\n process.kill(info.pid, 'SIGTERM');\n // Clean up files\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n return true;\n } catch {\n return false;\n }\n}\n\nexport function sendCommand(cmd: IpcCommand): Promise<IpcResponse> {\n return new Promise((resolve, reject) => {\n const socketPath = getSocketPath();\n\n const conn = net.createConnection(socketPath, () => {\n conn.write(JSON.stringify(cmd) + '\\n');\n });\n\n let buffer = '';\n conn.on('data', (chunk) => {\n buffer += chunk.toString();\n const newlineIdx = buffer.indexOf('\\n');\n if (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx);\n conn.end();\n try {\n resolve(JSON.parse(line) as IpcResponse);\n } catch {\n reject(new Error('Invalid response from daemon'));\n }\n }\n });\n\n conn.on('error', (err) => {\n reject(new Error(`Cannot connect to daemon: ${err.message}`));\n });\n\n // Timeout after 30 seconds\n conn.setTimeout(30_000, () => {\n conn.destroy();\n reject(new Error('Command timed out'));\n });\n });\n}\n","import type {\n StatusInfo,\n InspectedElement,\n ComponentRenderReport,\n} from './types.js';\nimport type { TreeNode } from './component-tree.js';\nimport type { ProfileSummary, TimelineEntry, CommitDetail } from './profiler.js';\n\n// ── Abbreviations for component types ──\nconst TYPE_ABBREV: Record<string, string> = {\n function: 'fn',\n class: 'cls',\n host: 'host',\n memo: 'memo',\n forwardRef: 'fRef',\n profiler: 'prof',\n suspense: 'susp',\n context: 'ctx',\n other: '?',\n};\n\nfunction typeTag(type: string): string {\n return TYPE_ABBREV[type] || type;\n}\n\n// ── Tree connector characters ──\nconst PIPE = '│ ';\nconst TEE = '├─ ';\nconst ELBOW = '└─ ';\nconst SPACE = ' ';\n\nexport function formatTree(nodes: TreeNode[]): string {\n if (nodes.length === 0) return 'No components (is a React app connected?)';\n\n // Build tree structure from the flat list\n const childrenMap = new Map<number | null, TreeNode[]>();\n for (const node of nodes) {\n const parentId = node.parentId;\n let siblings = childrenMap.get(parentId);\n if (!siblings) {\n siblings = [];\n childrenMap.set(parentId, siblings);\n }\n siblings.push(node);\n }\n\n const lines: string[] = [];\n\n function walk(nodeId: number, prefix: string, isLast: boolean, isRoot: boolean): void {\n const node = nodes.find((n) => n.id === nodeId);\n if (!node) return;\n\n const connector = isRoot ? '' : isLast ? ELBOW : TEE;\n let line = `${node.label} [${typeTag(node.type)}] \"${node.displayName}\"`;\n if (node.key) line += ` key=\"${node.key}\"`;\n\n lines.push(`${prefix}${connector}${line}`);\n\n const children = childrenMap.get(node.id) || [];\n const childPrefix = isRoot ? '' : prefix + (isLast ? SPACE : PIPE);\n\n for (let i = 0; i < children.length; i++) {\n walk(children[i].id, childPrefix, i === children.length - 1, false);\n }\n }\n\n // Find root nodes\n const roots = childrenMap.get(null) || [];\n for (let i = 0; i < roots.length; i++) {\n walk(roots[i].id, '', i === roots.length - 1, true);\n }\n\n return lines.join('\\n');\n}\n\nexport function formatComponent(element: InspectedElement, label?: string): string {\n const lines: string[] = [];\n\n const ref = label || `#${element.id}`;\n let header = `${ref} [${typeTag(element.type)}] \"${element.displayName}\"`;\n if (element.key) header += ` key=\"${element.key}\"`;\n lines.push(header);\n\n // Props\n if (element.props && Object.keys(element.props).length > 0) {\n lines.push('props:');\n for (const [key, value] of Object.entries(element.props)) {\n lines.push(` ${key}: ${formatCompactValue(value) ?? 'undefined'}`);\n }\n }\n\n // State\n if (element.state && Object.keys(element.state).length > 0) {\n lines.push('state:');\n for (const [key, value] of Object.entries(element.state)) {\n lines.push(` ${key}: ${formatCompactValue(value) ?? 'undefined'}`);\n }\n }\n\n // Hooks\n if (element.hooks && element.hooks.length > 0) {\n lines.push('hooks:');\n for (const h of element.hooks) {\n const val = formatCompactValue(h.value);\n lines.push(val !== undefined ? ` ${h.name}: ${val}` : ` ${h.name}`);\n if (h.subHooks && h.subHooks.length > 0) {\n for (const sh of h.subHooks) {\n const sval = formatCompactValue(sh.value);\n lines.push(sval !== undefined ? ` ${sh.name}: ${sval}` : ` ${sh.name}`);\n }\n }\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function formatSearchResults(results: TreeNode[]): string {\n if (results.length === 0) return 'No components found';\n\n return results\n .map((n) => {\n let line = `${n.label} [${typeTag(n.type)}] \"${n.displayName}\"`;\n if (n.key) line += ` key=\"${n.key}\"`;\n return line;\n })\n .join('\\n');\n}\n\nexport function formatCount(counts: Record<string, number>): string {\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const parts = Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .map(([type, count]) => `${typeTag(type)}:${count}`)\n .join(' ');\n return `${total} components (${parts})`;\n}\n\nexport function formatStatus(status: StatusInfo): string {\n const lines: string[] = [];\n lines.push(`Daemon: running (port ${status.port})`);\n lines.push(\n `Apps: ${status.connectedApps} connected, ${status.componentCount} components`,\n );\n if (status.profilingActive) {\n lines.push('Profiling: active');\n }\n const upSec = Math.round(status.uptime / 1000);\n lines.push(`Uptime: ${upSec}s`);\n return lines.join('\\n');\n}\n\nexport function formatProfileSummary(summary: ProfileSummary): string {\n const lines: string[] = [];\n const durSec = (summary.duration / 1000).toFixed(1);\n lines.push(\n `Profile \"${summary.name}\" (${durSec}s, ${summary.commitCount} commits)`,\n );\n\n if (summary.componentRenderCounts.length > 0) {\n lines.push('');\n lines.push('Top renders:');\n for (const c of summary.componentRenderCounts.slice(0, 10)) {\n const name = c.displayName || `#${c.id}`;\n lines.push(` ${name} ${c.count} renders`);\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function formatProfileReport(report: ComponentRenderReport, label?: string): string {\n const lines: string[] = [];\n const ref = label || `#${report.id}`;\n lines.push(`${ref} \"${report.displayName}\"`);\n lines.push(\n `renders:${report.renderCount} avg:${report.avgDuration.toFixed(1)}ms max:${report.maxDuration.toFixed(1)}ms total:${report.totalDuration.toFixed(1)}ms`,\n );\n if (report.causes.length > 0) {\n lines.push(`causes: ${report.causes.join(', ')}`);\n }\n return lines.join('\\n');\n}\n\nexport function formatSlowest(reports: ComponentRenderReport[]): string {\n if (reports.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Slowest (by avg render time):'];\n for (const r of reports) {\n const cause = r.causes[0] || '?';\n lines.push(\n ` ${pad(r.displayName, 20)} avg:${r.avgDuration.toFixed(1)}ms max:${r.maxDuration.toFixed(1)}ms renders:${r.renderCount} cause:${cause}`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatRerenders(reports: ComponentRenderReport[]): string {\n if (reports.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Most re-renders:'];\n for (const r of reports) {\n const cause = r.causes[0] || '?';\n lines.push(\n ` ${pad(r.displayName, 20)} ${r.renderCount} renders — ${cause}`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatTimeline(entries: TimelineEntry[]): string {\n if (entries.length === 0) return 'No profiling data';\n\n const lines: string[] = ['Commit timeline:'];\n for (const e of entries) {\n lines.push(\n ` #${e.index} ${e.duration.toFixed(1)}ms ${e.componentCount} components`,\n );\n }\n return lines.join('\\n');\n}\n\nexport function formatCommitDetail(detail: CommitDetail): string {\n const lines: string[] = [];\n lines.push(`Commit #${detail.index} ${detail.duration.toFixed(1)}ms ${detail.totalComponents} components`);\n lines.push('');\n for (const c of detail.components) {\n const causes = c.causes.length > 0 ? c.causes.join(', ') : '?';\n lines.push(` ${pad(c.displayName, 24)} self:${c.selfDuration.toFixed(1)}ms total:${c.actualDuration.toFixed(1)}ms ${causes}`);\n }\n const hidden = detail.totalComponents - detail.components.length;\n if (hidden > 0) {\n lines.push(` ... ${hidden} more (use --limit to show more)`);\n }\n return lines.join('\\n');\n}\n\n// ── Helpers ──\n\nfunction formatValue(obj: unknown): string {\n try {\n return JSON.stringify(obj, replacer, 0) || 'undefined';\n } catch {\n return String(obj);\n }\n}\n\nfunction formatCompactValue(val: unknown): string | undefined {\n if (val === undefined) return undefined;\n if (val === null) return 'null';\n if (typeof val === 'function') return 'ƒ';\n if (typeof val === 'string') return `\"${val}\"`;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n try {\n const s = JSON.stringify(val, replacer, 0);\n if (s && s.length > 60) return s.slice(0, 57) + '...';\n return s || String(val);\n } catch {\n return String(val);\n }\n}\n\nfunction replacer(_key: string, value: unknown): unknown {\n if (typeof value === 'function') return 'ƒ';\n return value;\n}\n\nfunction pad(s: string, len: number): string {\n return s.length >= len ? s : s + ' '.repeat(len - s.length);\n}\n","import {\n ensureDaemon,\n sendCommand,\n stopDaemon,\n readDaemonInfo,\n setStateDir,\n} from './daemon-client.js';\nimport {\n formatTree,\n formatComponent,\n formatSearchResults,\n formatCount,\n formatStatus,\n formatProfileSummary,\n formatProfileReport,\n formatSlowest,\n formatRerenders,\n formatTimeline,\n formatCommitDetail,\n} from './formatters.js';\nimport type { IpcCommand } from './types.js';\n\nfunction usage(): string {\n return `Usage: devtools <command> [options]\n\nSetup:\n init [--dry-run] Auto-configure your React app\n\nDaemon:\n start [--port 8097] Start daemon\n stop Stop daemon\n status Show daemon status\n\nComponents:\n get tree [--depth N] Component hierarchy\n get component <@c1 | id> Props, state, hooks\n find <name> [--exact] Search by display name\n count Component count by type\n\nProfiling:\n profile start [name] Start profiling session\n profile stop Stop profiling, collect data\n profile report <@c1 | id> Render report for component\n profile slow [--limit N] Slowest components (by avg)\n profile rerenders [--limit N] Most re-rendered components\n profile timeline [--limit N] Commit timeline\n profile commit <N | #N> [--limit N] Detail for specific commit`;\n}\n\nfunction parseArgs(argv: string[]): {\n command: string[];\n flags: Record<string, string | boolean>;\n} {\n const command: string[] = [];\n const flags: Record<string, string | boolean> = {};\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg.startsWith('--')) {\n const key = arg.slice(2);\n const eqIdx = key.indexOf('=');\n if (eqIdx !== -1) {\n flags[key.slice(0, eqIdx)] = key.slice(eqIdx + 1);\n } else {\n // Check if next arg is a value\n const next = argv[i + 1];\n if (next && !next.startsWith('--')) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n } else {\n command.push(arg);\n }\n }\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv.slice(2));\n\n if (command.length === 0 || flags['help']) {\n console.log(usage());\n process.exit(0);\n }\n\n // Configure custom state directory (for test isolation)\n if (typeof flags['state-dir'] === 'string') {\n setStateDir(flags['state-dir']);\n }\n\n const cmd0 = command[0];\n const cmd1 = command[1];\n\n try {\n // ── Init ──\n if (cmd0 === 'init') {\n const { runInit } = await import('./init.js');\n await runInit(process.cwd(), flags['dry-run'] === true);\n return;\n }\n\n // ── Daemon management ──\n if (cmd0 === 'start') {\n const port = flags['port'] ? parseInt(flags['port'] as string, 10) : undefined;\n await ensureDaemon(port);\n const resp = await sendCommand({ type: 'status' });\n if (resp.ok) {\n console.log(formatStatus(resp.data as any));\n }\n return;\n }\n\n if (cmd0 === 'stop') {\n const stopped = stopDaemon();\n console.log(stopped ? 'Daemon stopped' : 'Daemon is not running');\n return;\n }\n\n if (cmd0 === 'status') {\n const info = readDaemonInfo();\n if (!info) {\n console.log('Daemon is not running');\n process.exit(1);\n }\n try {\n const resp = await sendCommand({ type: 'status' });\n if (resp.ok) {\n console.log(formatStatus(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n } catch {\n console.log('Daemon is not running (stale info)');\n process.exit(1);\n }\n return;\n }\n\n // ── All other commands require the daemon ──\n await ensureDaemon();\n\n // ── Component inspection ──\n if (cmd0 === 'get' && cmd1 === 'tree') {\n const depth = flags['depth']\n ? parseInt(flags['depth'] as string, 10)\n : undefined;\n const ipcCmd: IpcCommand = { type: 'get-tree', depth };\n const resp = await sendCommand(ipcCmd);\n if (resp.ok) {\n console.log(formatTree(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'get' && cmd1 === 'component') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools get component <@c1 | id>');\n process.exit(1);\n }\n const id: number | string = raw.startsWith('@') ? raw : parseInt(raw, 10);\n if (typeof id === 'number' && isNaN(id)) {\n console.error('Usage: devtools get component <@c1 | id>');\n process.exit(1);\n }\n const resp = await sendCommand({ type: 'get-component', id });\n if (resp.ok) {\n console.log(formatComponent(resp.data as any, resp.label));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'find') {\n const name = command[1];\n if (!name) {\n console.error('Usage: devtools find <name> [--exact]');\n process.exit(1);\n }\n const exact = flags['exact'] === true;\n const resp = await sendCommand({ type: 'find', name, exact });\n if (resp.ok) {\n console.log(formatSearchResults(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'count') {\n const resp = await sendCommand({ type: 'count' });\n if (resp.ok) {\n console.log(formatCount(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n // ── Profiling ──\n if (cmd0 === 'profile' && cmd1 === 'start') {\n const name = command[2];\n const resp = await sendCommand({ type: 'profile-start', name });\n if (resp.ok) {\n console.log(resp.data);\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'stop') {\n const resp = await sendCommand({ type: 'profile-stop' });\n if (resp.ok) {\n console.log(formatProfileSummary(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'report') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools profile report <@c1 | id>');\n process.exit(1);\n }\n const componentId: number | string = raw.startsWith('@') ? raw : parseInt(raw, 10);\n if (typeof componentId === 'number' && isNaN(componentId)) {\n console.error('Usage: devtools profile report <@c1 | id>');\n process.exit(1);\n }\n const resp = await sendCommand({ type: 'profile-report', componentId });\n if (resp.ok) {\n console.log(formatProfileReport(resp.data as any, resp.label));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'slow') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-slow', limit });\n if (resp.ok) {\n console.log(formatSlowest(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'rerenders') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-rerenders', limit });\n if (resp.ok) {\n console.log(formatRerenders(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'commit') {\n const raw = command[2];\n if (!raw) {\n console.error('Usage: devtools profile commit <N | #N>');\n process.exit(1);\n }\n const index = parseInt(raw.replace(/^#/, ''), 10);\n if (isNaN(index)) {\n console.error('Usage: devtools profile commit <N | #N>');\n process.exit(1);\n }\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-commit', index, limit });\n if (resp.ok) {\n console.log(formatCommitDetail(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n if (cmd0 === 'profile' && cmd1 === 'timeline') {\n const limit = flags['limit'] ? parseInt(flags['limit'] as string, 10) : undefined;\n const resp = await sendCommand({ type: 'profile-timeline', limit });\n if (resp.ok) {\n console.log(formatTimeline(resp.data as any));\n } else {\n console.error(resp.error);\n process.exit(1);\n }\n return;\n }\n\n console.error(`Unknown command: ${command.join(' ')}`);\n console.log(usage());\n process.exit(1);\n } catch (err) {\n console.error(\n err instanceof Error ? err.message : String(err),\n );\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side connection module for agent-react-devtools.
|
|
3
|
+
*
|
|
4
|
+
* Usage: `import 'agent-react-devtools/connect'`
|
|
5
|
+
*
|
|
6
|
+
* This must be imported before React loads. It:
|
|
7
|
+
* 1. Removes the Vite plugin-react hook stub
|
|
8
|
+
* 2. Initializes react-devtools-core
|
|
9
|
+
* 3. Connects via WebSocket to the agent-react-devtools daemon
|
|
10
|
+
*
|
|
11
|
+
* Export `ready` — a promise that resolves once the WebSocket opens
|
|
12
|
+
* (or after a 2s timeout / error, so the app is never blocked).
|
|
13
|
+
*/
|
|
14
|
+
declare const ready: Promise<void>;
|
|
15
|
+
|
|
16
|
+
export { ready };
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/connect.ts
|
|
2
|
+
function getMeta(name) {
|
|
3
|
+
if (typeof document === "undefined") return null;
|
|
4
|
+
const meta = document.querySelector(`meta[name="${name}"]`);
|
|
5
|
+
return meta?.getAttribute("content") || null;
|
|
6
|
+
}
|
|
7
|
+
function getPort() {
|
|
8
|
+
const val = parseInt(getMeta("agent-react-devtools-port") || "", 10);
|
|
9
|
+
return isNaN(val) ? 8097 : val;
|
|
10
|
+
}
|
|
11
|
+
function getHost() {
|
|
12
|
+
return getMeta("agent-react-devtools-host") || "localhost";
|
|
13
|
+
}
|
|
14
|
+
function noop() {
|
|
15
|
+
return Promise.resolve();
|
|
16
|
+
}
|
|
17
|
+
var isSSR = typeof window === "undefined";
|
|
18
|
+
var isProd = typeof import.meta !== "undefined" && import.meta.env?.PROD === true || typeof process !== "undefined" && false;
|
|
19
|
+
var ready = isSSR || isProd ? noop() : connect();
|
|
20
|
+
async function connect() {
|
|
21
|
+
try {
|
|
22
|
+
const port = getPort();
|
|
23
|
+
const host = getHost();
|
|
24
|
+
try {
|
|
25
|
+
delete window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
const { initialize, connectToDevTools } = await import("react-devtools-core");
|
|
29
|
+
initialize();
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
try {
|
|
32
|
+
const ws = new WebSocket(`ws://${host}:${port}`);
|
|
33
|
+
connectToDevTools({ port, websocket: ws });
|
|
34
|
+
ws.addEventListener("open", () => resolve());
|
|
35
|
+
ws.addEventListener("error", () => resolve());
|
|
36
|
+
setTimeout(resolve, 2e3);
|
|
37
|
+
} catch {
|
|
38
|
+
resolve();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
ready
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connect.ts"],"sourcesContent":["/**\n * Browser-side connection module for agent-react-devtools.\n *\n * Usage: `import 'agent-react-devtools/connect'`\n *\n * This must be imported before React loads. It:\n * 1. Removes the Vite plugin-react hook stub\n * 2. Initializes react-devtools-core\n * 3. Connects via WebSocket to the agent-react-devtools daemon\n *\n * Export `ready` — a promise that resolves once the WebSocket opens\n * (or after a 2s timeout / error, so the app is never blocked).\n */\n\nfunction getMeta(name: string): string | null {\n if (typeof document === 'undefined') return null;\n const meta = document.querySelector(`meta[name=\"${name}\"]`);\n return meta?.getAttribute('content') || null;\n}\n\nfunction getPort(): number {\n const val = parseInt(getMeta('agent-react-devtools-port') || '', 10);\n return isNaN(val) ? 8097 : val;\n}\n\nfunction getHost(): string {\n return getMeta('agent-react-devtools-host') || 'localhost';\n}\n\nfunction noop(): Promise<void> {\n return Promise.resolve();\n}\n\n// SSR guard\nconst isSSR = typeof window === 'undefined';\n\n// Production guard — check bundler-injected signals first, then Node.js process.env\nconst isProd =\n (typeof import.meta !== 'undefined' &&\n (import.meta as any).env?.PROD === true) ||\n (typeof process !== 'undefined' &&\n process.env?.NODE_ENV === 'production');\n\nexport const ready: Promise<void> = isSSR || isProd ? noop() : connect();\n\nasync function connect(): Promise<void> {\n try {\n const port = getPort();\n const host = getHost();\n\n // Remove Vite's plugin-react hook stub so react-devtools-core can install the full hook\n try {\n delete (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__;\n } catch {\n // Property may be non-configurable (browser extension) — ignore\n }\n\n const { initialize, connectToDevTools } = await import('react-devtools-core');\n initialize();\n\n return new Promise<void>((resolve) => {\n try {\n const ws = new WebSocket(`ws://${host}:${port}`);\n connectToDevTools({ port, websocket: ws });\n ws.addEventListener('open', () => resolve());\n ws.addEventListener('error', () => resolve());\n setTimeout(resolve, 2000);\n } catch {\n resolve();\n }\n });\n } catch {\n // react-devtools-core not installed or other error — silently skip\n }\n}\n"],"mappings":";AAcA,SAAS,QAAQ,MAA6B;AAC5C,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,OAAO,SAAS,cAAc,cAAc,IAAI,IAAI;AAC1D,SAAO,MAAM,aAAa,SAAS,KAAK;AAC1C;AAEA,SAAS,UAAkB;AACzB,QAAM,MAAM,SAAS,QAAQ,2BAA2B,KAAK,IAAI,EAAE;AACnE,SAAO,MAAM,GAAG,IAAI,OAAO;AAC7B;AAEA,SAAS,UAAkB;AACzB,SAAO,QAAQ,2BAA2B,KAAK;AACjD;AAEA,SAAS,OAAsB;AAC7B,SAAO,QAAQ,QAAQ;AACzB;AAGA,IAAM,QAAQ,OAAO,WAAW;AAGhC,IAAM,SACH,OAAO,gBAAgB,eACrB,YAAoB,KAAK,SAAS,QACpC,OAAO,YAAY,eAClB;AAEG,IAAM,QAAuB,SAAS,SAAS,KAAK,IAAI,QAAQ;AAEvE,eAAe,UAAyB;AACtC,MAAI;AACF,UAAM,OAAO,QAAQ;AACrB,UAAM,OAAO,QAAQ;AAGrB,QAAI;AACF,aAAQ,OAAe;AAAA,IACzB,QAAQ;AAAA,IAER;AAEA,UAAM,EAAE,YAAY,kBAAkB,IAAI,MAAM,OAAO,qBAAqB;AAC5E,eAAW;AAEX,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,UAAI;AACF,cAAM,KAAK,IAAI,UAAU,QAAQ,IAAI,IAAI,IAAI,EAAE;AAC/C,0BAAkB,EAAE,MAAM,WAAW,GAAG,CAAC;AACzC,WAAG,iBAAiB,QAAQ,MAAM,QAAQ,CAAC;AAC3C,WAAG,iBAAiB,SAAS,MAAM,QAAQ,CAAC;AAC5C,mBAAW,SAAS,GAAI;AAAA,MAC1B,QAAQ;AACN,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;","names":[]}
|