agent-react-devtools 0.1.1-canary-20260210005551 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # agent-react-devtools
2
2
 
3
- ## 0.1.1-canary-20260210005551
3
+ ## 0.2.0
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.
4
12
 
5
13
  ### Patch Changes
6
14
 
package/README.md CHANGED
@@ -136,19 +136,68 @@ agent-react-devtools profile commit <N | #N> [--limit N] # Single commit detail
136
136
 
137
137
  ## Connecting Your App
138
138
 
139
- Install `react-devtools-core` in your app and connect before React renders (e.g. in `src/main.tsx`):
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`):
140
152
 
141
153
  ```ts
142
- import { initialize, connectToDevTools } from 'react-devtools-core';
143
- import { createRoot } from 'react-dom/client';
144
- import App from './App';
154
+ import "agent-react-devtools/connect";
155
+ ```
145
156
 
146
- initialize();
147
- connectToDevTools({ port: 8097 });
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.
148
158
 
149
- createRoot(document.getElementById('root')!).render(<App />);
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
+ });
150
172
  ```
151
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
+
152
201
  ## Using with AI Agents
153
202
 
154
203
  Add something like this to your project's `CLAUDE.md` (or equivalent agent instructions):
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":";;;AAAA,OAAO,SAAS;AAChB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,aAAa;AAGtB,IAAM,oBAAoB,KAAK;AAAA,EAC7B,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAAA,EAC/C;AACF;AAEA,IAAI,WAAW;AAER,SAAS,YAAY,KAAmB;AAC7C,aAAW;AACb;AAEA,SAAS,oBAA4B;AACnC,SAAO,KAAK,KAAK,UAAU,aAAa;AAC1C;AAEA,SAAS,gBAAwB;AAC/B,SAAO,KAAK,KAAK,UAAU,aAAa;AAC1C;AAEO,SAAS,iBAAoC;AAClD,MAAI;AACF,UAAM,MAAM,GAAG,aAAa,kBAAkB,GAAG,OAAO;AACxD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,MAA2B;AAChD,MAAI;AAEF,YAAQ,KAAK,KAAK,KAAK,CAAC;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,aAAa,MAA8B;AAC/D,QAAM,OAAO,eAAe;AAC5B,MAAI,QAAQ,cAAc,IAAI,GAAG;AAC/B;AAAA,EACF;AAGA,MAAI;AACF,OAAG,WAAW,kBAAkB,CAAC;AAAA,EACnC,QAAQ;AAAA,EAER;AACA,MAAI;AACF,OAAG,WAAW,cAAc,CAAC;AAAA,EAC/B,QAAQ;AAAA,EAER;AAGA,QAAM,eAAe,KAAK;AAAA,IACxB,KAAK,QAAQ,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ;AAAA,IAC9C;AAAA,EACF;AAEA,QAAM,OAAO,CAAC;AACd,MAAI,KAAM,MAAK,KAAK,UAAU,IAAI,EAAE;AACpC,MAAI,aAAa,kBAAmB,MAAK,KAAK,eAAe,QAAQ,EAAE;AAEvE,QAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,cAAc,GAAG,IAAI,GAAG;AAAA,IAC7D,UAAU;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AACD,QAAM,MAAM;AAGZ,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC3C,QAAI;AACF,YAAM,YAAY,EAAE,MAAM,OAAO,CAAC;AAClC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,IAAI,MAAM,yCAAyC;AAC3D;AAEO,SAAS,aAAsB;AACpC,QAAM,OAAO,eAAe;AAC5B,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,YAAQ,KAAK,KAAK,KAAK,SAAS;AAEhC,QAAI;AACF,SAAG,WAAW,kBAAkB,CAAC;AAAA,IACnC,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YAAY,KAAuC;AACjE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,aAAa,cAAc;AAEjC,UAAM,OAAO,IAAI,iBAAiB,YAAY,MAAM;AAClD,WAAK,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,IACvC,CAAC;AAED,QAAI,SAAS;AACb,SAAK,GAAG,QAAQ,CAAC,UAAU;AACzB,gBAAU,MAAM,SAAS;AACzB,YAAM,aAAa,OAAO,QAAQ,IAAI;AACtC,UAAI,eAAe,IAAI;AACrB,cAAM,OAAO,OAAO,MAAM,GAAG,UAAU;AACvC,aAAK,IAAI;AACT,YAAI;AACF,kBAAQ,KAAK,MAAM,IAAI,CAAgB;AAAA,QACzC,QAAQ;AACN,iBAAO,IAAI,MAAM,8BAA8B,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,aAAO,IAAI,MAAM,6BAA6B,IAAI,OAAO,EAAE,CAAC;AAAA,IAC9D,CAAC;AAGD,SAAK,WAAW,KAAQ,MAAM;AAC5B,WAAK,QAAQ;AACb,aAAO,IAAI,MAAM,mBAAmB,CAAC;AAAA,IACvC,CAAC;AAAA,EACH,CAAC;AACH;;;ACtIA,IAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAS;AAAA,EACT,OAAO;AACT;AAEA,SAAS,QAAQ,MAAsB;AACrC,SAAO,YAAY,IAAI,KAAK;AAC9B;AAGA,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,QAAQ;AACd,IAAM,QAAQ;AAEP,SAAS,WAAW,OAA2B;AACpD,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,QAAM,cAAc,oBAAI,IAA+B;AACvD,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,KAAK;AACtB,QAAI,WAAW,YAAY,IAAI,QAAQ;AACvC,QAAI,CAAC,UAAU;AACb,iBAAW,CAAC;AACZ,kBAAY,IAAI,UAAU,QAAQ;AAAA,IACpC;AACA,aAAS,KAAK,IAAI;AAAA,EACpB;AAEA,QAAM,QAAkB,CAAC;AAEzB,WAAS,KAAK,QAAgB,QAAgB,QAAiB,QAAuB;AACpF,UAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AAC9C,QAAI,CAAC,KAAM;AAEX,UAAM,YAAY,SAAS,KAAK,SAAS,QAAQ;AACjD,QAAI,OAAO,GAAG,KAAK,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC,MAAM,KAAK,WAAW;AACrE,QAAI,KAAK,IAAK,SAAQ,SAAS,KAAK,GAAG;AAEvC,UAAM,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE;AAEzC,UAAM,WAAW,YAAY,IAAI,KAAK,EAAE,KAAK,CAAC;AAC9C,UAAM,cAAc,SAAS,KAAK,UAAU,SAAS,QAAQ;AAE7D,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,WAAK,SAAS,CAAC,EAAE,IAAI,aAAa,MAAM,SAAS,SAAS,GAAG,KAAK;AAAA,IACpE;AAAA,EACF;AAGA,QAAM,QAAQ,YAAY,IAAI,IAAI,KAAK,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,SAAK,MAAM,CAAC,EAAE,IAAI,IAAI,MAAM,MAAM,SAAS,GAAG,IAAI;AAAA,EACpD;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,gBAAgB,SAA2B,OAAwB;AACjF,QAAM,QAAkB,CAAC;AAEzB,QAAM,MAAM,SAAS,IAAI,QAAQ,EAAE;AACnC,MAAI,SAAS,GAAG,GAAG,KAAK,QAAQ,QAAQ,IAAI,CAAC,MAAM,QAAQ,WAAW;AACtE,MAAI,QAAQ,IAAK,WAAU,SAAS,QAAQ,GAAG;AAC/C,QAAM,KAAK,MAAM;AAGjB,MAAI,QAAQ,SAAS,OAAO,KAAK,QAAQ,KAAK,EAAE,SAAS,GAAG;AAC1D,UAAM,KAAK,QAAQ;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,KAAK,GAAG;AACxD,YAAM,KAAK,KAAK,GAAG,KAAK,mBAAmB,KAAK,KAAK,WAAW,EAAE;AAAA,IACpE;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS,OAAO,KAAK,QAAQ,KAAK,EAAE,SAAS,GAAG;AAC1D,UAAM,KAAK,QAAQ;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,KAAK,GAAG;AACxD,YAAM,KAAK,KAAK,GAAG,KAAK,mBAAmB,KAAK,KAAK,WAAW,EAAE;AAAA,IACpE;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC7C,UAAM,KAAK,QAAQ;AACnB,eAAW,KAAK,QAAQ,OAAO;AAC7B,YAAM,MAAM,mBAAmB,EAAE,KAAK;AACtC,YAAM,KAAK,QAAQ,SAAY,KAAK,EAAE,IAAI,KAAK,GAAG,KAAK,KAAK,EAAE,IAAI,EAAE;AACpE,UAAI,EAAE,YAAY,EAAE,SAAS,SAAS,GAAG;AACvC,mBAAW,MAAM,EAAE,UAAU;AAC3B,gBAAM,OAAO,mBAAmB,GAAG,KAAK;AACxC,gBAAM,KAAK,SAAS,SAAY,OAAO,GAAG,IAAI,KAAK,IAAI,KAAK,OAAO,GAAG,IAAI,EAAE;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,oBAAoB,SAA6B;AAC/D,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO,QACJ,IAAI,CAAC,MAAM;AACV,QAAI,OAAO,GAAG,EAAE,KAAK,KAAK,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW;AAC5D,QAAI,EAAE,IAAK,SAAQ,SAAS,EAAE,GAAG;AACjC,WAAO;AAAA,EACT,CAAC,EACA,KAAK,IAAI;AACd;AAEO,SAAS,YAAY,QAAwC;AAClE,QAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAC7D,QAAM,QAAQ,OAAO,QAAQ,MAAM,EAChC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,GAAG,QAAQ,IAAI,CAAC,IAAI,KAAK,EAAE,EAClD,KAAK,GAAG;AACX,SAAO,GAAG,KAAK,gBAAgB,KAAK;AACtC;AAEO,SAAS,aAAa,QAA4B;AACvD,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,yBAAyB,OAAO,IAAI,GAAG;AAClD,QAAM;AAAA,IACJ,SAAS,OAAO,aAAa,eAAe,OAAO,cAAc;AAAA,EACnE;AACA,MAAI,OAAO,iBAAiB;AAC1B,UAAM,KAAK,mBAAmB;AAAA,EAChC;AACA,QAAM,QAAQ,KAAK,MAAM,OAAO,SAAS,GAAI;AAC7C,QAAM,KAAK,WAAW,KAAK,GAAG;AAC9B,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,qBAAqB,SAAiC;AACpE,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAU,QAAQ,WAAW,KAAM,QAAQ,CAAC;AAClD,QAAM;AAAA,IACJ,YAAY,QAAQ,IAAI,MAAM,MAAM,MAAM,QAAQ,WAAW;AAAA,EAC/D;AAEA,MAAI,QAAQ,sBAAsB,SAAS,GAAG;AAC5C,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,cAAc;AACzB,eAAW,KAAK,QAAQ,sBAAsB,MAAM,GAAG,EAAE,GAAG;AAC1D,YAAM,OAAO,EAAE,eAAe,IAAI,EAAE,EAAE;AACtC,YAAM,KAAK,KAAK,IAAI,KAAK,EAAE,KAAK,UAAU;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,oBAAoB,QAA+B,OAAwB;AACzF,QAAM,QAAkB,CAAC;AACzB,QAAM,MAAM,SAAS,IAAI,OAAO,EAAE;AAClC,QAAM,KAAK,GAAG,GAAG,KAAK,OAAO,WAAW,GAAG;AAC3C,QAAM;AAAA,IACJ,WAAW,OAAO,WAAW,SAAS,OAAO,YAAY,QAAQ,CAAC,CAAC,WAAW,OAAO,YAAY,QAAQ,CAAC,CAAC,aAAa,OAAO,cAAc,QAAQ,CAAC,CAAC;AAAA,EACzJ;AACA,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,UAAM,KAAK,WAAW,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,EAClD;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,cAAc,SAA0C;AACtE,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAkB,CAAC,+BAA+B;AACxD,aAAW,KAAK,SAAS;AACvB,UAAM,QAAQ,EAAE,OAAO,CAAC,KAAK;AAC7B,UAAM;AAAA,MACJ,KAAK,IAAI,EAAE,aAAa,EAAE,CAAC,QAAQ,EAAE,YAAY,QAAQ,CAAC,CAAC,WAAW,EAAE,YAAY,QAAQ,CAAC,CAAC,eAAe,EAAE,WAAW,WAAW,KAAK;AAAA,IAC5I;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,gBAAgB,SAA0C;AACxE,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAkB,CAAC,kBAAkB;AAC3C,aAAW,KAAK,SAAS;AACvB,UAAM,QAAQ,EAAE,OAAO,CAAC,KAAK;AAC7B,UAAM;AAAA,MACJ,KAAK,IAAI,EAAE,aAAa,EAAE,CAAC,IAAI,EAAE,WAAW,mBAAc,KAAK;AAAA,IACjE;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,eAAe,SAAkC;AAC/D,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAkB,CAAC,kBAAkB;AAC3C,aAAW,KAAK,SAAS;AACvB,UAAM;AAAA,MACJ,MAAM,EAAE,KAAK,KAAK,EAAE,SAAS,QAAQ,CAAC,CAAC,OAAO,EAAE,cAAc;AAAA,IAChE;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,mBAAmB,QAA8B;AAC/D,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,WAAW,OAAO,KAAK,KAAK,OAAO,SAAS,QAAQ,CAAC,CAAC,OAAO,OAAO,eAAe,aAAa;AAC3G,QAAM,KAAK,EAAE;AACb,aAAW,KAAK,OAAO,YAAY;AACjC,UAAM,SAAS,EAAE,OAAO,SAAS,IAAI,EAAE,OAAO,KAAK,IAAI,IAAI;AAC3D,UAAM,KAAK,KAAK,IAAI,EAAE,aAAa,EAAE,CAAC,SAAS,EAAE,aAAa,QAAQ,CAAC,CAAC,aAAa,EAAE,eAAe,QAAQ,CAAC,CAAC,OAAO,MAAM,EAAE;AAAA,EACjI;AACA,QAAM,SAAS,OAAO,kBAAkB,OAAO,WAAW;AAC1D,MAAI,SAAS,GAAG;AACd,UAAM,KAAK,SAAS,MAAM,kCAAkC;AAAA,EAC9D;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAYA,SAAS,mBAAmB,KAAkC;AAC5D,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI,QAAQ,KAAM,QAAO;AACzB,MAAI,OAAO,QAAQ,WAAY,QAAO;AACtC,MAAI,OAAO,QAAQ,SAAU,QAAO,IAAI,GAAG;AAC3C,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAW,QAAO,OAAO,GAAG;AAC1E,MAAI;AACF,UAAM,IAAI,KAAK,UAAU,KAAK,UAAU,CAAC;AACzC,QAAI,KAAK,EAAE,SAAS,GAAI,QAAO,EAAE,MAAM,GAAG,EAAE,IAAI;AAChD,WAAO,KAAK,OAAO,GAAG;AAAA,EACxB,QAAQ;AACN,WAAO,OAAO,GAAG;AAAA,EACnB;AACF;AAEA,SAAS,SAAS,MAAc,OAAyB;AACvD,MAAI,OAAO,UAAU,WAAY,QAAO;AACxC,SAAO;AACT;AAEA,SAAS,IAAI,GAAW,KAAqB;AAC3C,SAAO,EAAE,UAAU,MAAM,IAAI,IAAI,IAAI,OAAO,MAAM,EAAE,MAAM;AAC5D;;;ACvPA,SAAS,QAAgB;AACvB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBT;AAEA,SAAS,UAAU,MAGjB;AACA,QAAM,UAAoB,CAAC;AAC3B,QAAM,QAA0C,CAAC;AAEjD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,IAAI,WAAW,IAAI,GAAG;AACxB,YAAM,MAAM,IAAI,MAAM,CAAC;AACvB,YAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,UAAI,UAAU,IAAI;AAChB,cAAM,IAAI,MAAM,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,QAAQ,CAAC;AAAA,MAClD,OAAO;AAEL,cAAM,OAAO,KAAK,IAAI,CAAC;AACvB,YAAI,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG;AAClC,gBAAM,GAAG,IAAI;AACb;AAAA,QACF,OAAO;AACL,gBAAM,GAAG,IAAI;AAAA,QACf;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AACA,SAAO,EAAE,SAAS,MAAM;AAC1B;AAEA,eAAe,OAAsB;AACnC,QAAM,EAAE,SAAS,MAAM,IAAI,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE1D,MAAI,QAAQ,WAAW,KAAK,MAAM,MAAM,GAAG;AACzC,YAAQ,IAAI,MAAM,CAAC;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,OAAO,MAAM,WAAW,MAAM,UAAU;AAC1C,gBAAY,MAAM,WAAW,CAAC;AAAA,EAChC;AAEA,QAAM,OAAO,QAAQ,CAAC;AACtB,QAAM,OAAO,QAAQ,CAAC;AAEtB,MAAI;AAEF,QAAI,SAAS,QAAQ;AACnB,YAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAW;AAC5C,YAAM,QAAQ,QAAQ,IAAI,GAAG,MAAM,SAAS,MAAM,IAAI;AACtD;AAAA,IACF;AAGA,QAAI,SAAS,SAAS;AACpB,YAAM,OAAO,MAAM,MAAM,IAAI,SAAS,MAAM,MAAM,GAAa,EAAE,IAAI;AACrE,YAAM,aAAa,IAAI;AACvB,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,SAAS,CAAC;AACjD,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,aAAa,KAAK,IAAW,CAAC;AAAA,MAC5C;AACA;AAAA,IACF;AAEA,QAAI,SAAS,QAAQ;AACnB,YAAM,UAAU,WAAW;AAC3B,cAAQ,IAAI,UAAU,mBAAmB,uBAAuB;AAChE;AAAA,IACF;AAEA,QAAI,SAAS,UAAU;AACrB,YAAM,OAAO,eAAe;AAC5B,UAAI,CAAC,MAAM;AACT,gBAAQ,IAAI,uBAAuB;AACnC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,UAAI;AACF,cAAM,OAAO,MAAM,YAAY,EAAE,MAAM,SAAS,CAAC;AACjD,YAAI,KAAK,IAAI;AACX,kBAAQ,IAAI,aAAa,KAAK,IAAW,CAAC;AAAA,QAC5C,OAAO;AACL,kBAAQ,MAAM,KAAK,KAAK;AACxB,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF,QAAQ;AACN,gBAAQ,IAAI,oCAAoC;AAChD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAGA,UAAM,aAAa;AAGnB,QAAI,SAAS,SAAS,SAAS,QAAQ;AACrC,YAAM,QAAQ,MAAM,OAAO,IACvB,SAAS,MAAM,OAAO,GAAa,EAAE,IACrC;AACJ,YAAM,SAAqB,EAAE,MAAM,YAAY,MAAM;AACrD,YAAM,OAAO,MAAM,YAAY,MAAM;AACrC,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,WAAW,KAAK,IAAW,CAAC;AAAA,MAC1C,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,SAAS,aAAa;AAC1C,YAAM,MAAM,QAAQ,CAAC;AACrB,UAAI,CAAC,KAAK;AACR,gBAAQ,MAAM,0CAA0C;AACxD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,KAAsB,IAAI,WAAW,GAAG,IAAI,MAAM,SAAS,KAAK,EAAE;AACxE,UAAI,OAAO,OAAO,YAAY,MAAM,EAAE,GAAG;AACvC,gBAAQ,MAAM,0CAA0C;AACxD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,iBAAiB,GAAG,CAAC;AAC5D,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,gBAAgB,KAAK,MAAa,KAAK,KAAK,CAAC;AAAA,MAC3D,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,QAAQ;AACnB,YAAM,OAAO,QAAQ,CAAC;AACtB,UAAI,CAAC,MAAM;AACT,gBAAQ,MAAM,uCAAuC;AACrD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,QAAQ,MAAM,OAAO,MAAM;AACjC,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,QAAQ,MAAM,MAAM,CAAC;AAC5D,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,oBAAoB,KAAK,IAAW,CAAC;AAAA,MACnD,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,SAAS;AACpB,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,QAAQ,CAAC;AAChD,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,YAAY,KAAK,IAAW,CAAC;AAAA,MAC3C,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAGA,QAAI,SAAS,aAAa,SAAS,SAAS;AAC1C,YAAM,OAAO,QAAQ,CAAC;AACtB,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,iBAAiB,KAAK,CAAC;AAC9D,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,KAAK,IAAI;AAAA,MACvB,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,QAAQ;AACzC,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,eAAe,CAAC;AACvD,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,qBAAqB,KAAK,IAAW,CAAC;AAAA,MACpD,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,UAAU;AAC3C,YAAM,MAAM,QAAQ,CAAC;AACrB,UAAI,CAAC,KAAK;AACR,gBAAQ,MAAM,2CAA2C;AACzD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,cAA+B,IAAI,WAAW,GAAG,IAAI,MAAM,SAAS,KAAK,EAAE;AACjF,UAAI,OAAO,gBAAgB,YAAY,MAAM,WAAW,GAAG;AACzD,gBAAQ,MAAM,2CAA2C;AACzD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,kBAAkB,YAAY,CAAC;AACtE,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,oBAAoB,KAAK,MAAa,KAAK,KAAK,CAAC;AAAA,MAC/D,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,QAAQ;AACzC,YAAM,QAAQ,MAAM,OAAO,IAAI,SAAS,MAAM,OAAO,GAAa,EAAE,IAAI;AACxE,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,gBAAgB,MAAM,CAAC;AAC9D,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,cAAc,KAAK,IAAW,CAAC;AAAA,MAC7C,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,aAAa;AAC9C,YAAM,QAAQ,MAAM,OAAO,IAAI,SAAS,MAAM,OAAO,GAAa,EAAE,IAAI;AACxE,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,qBAAqB,MAAM,CAAC;AACnE,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,gBAAgB,KAAK,IAAW,CAAC;AAAA,MAC/C,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,UAAU;AAC3C,YAAM,MAAM,QAAQ,CAAC;AACrB,UAAI,CAAC,KAAK;AACR,gBAAQ,MAAM,yCAAyC;AACvD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,QAAQ,SAAS,IAAI,QAAQ,MAAM,EAAE,GAAG,EAAE;AAChD,UAAI,MAAM,KAAK,GAAG;AAChB,gBAAQ,MAAM,yCAAyC;AACvD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,QAAQ,MAAM,OAAO,IAAI,SAAS,MAAM,OAAO,GAAa,EAAE,IAAI;AACxE,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,kBAAkB,OAAO,MAAM,CAAC;AACvE,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,mBAAmB,KAAK,IAAW,CAAC;AAAA,MAClD,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,SAAS,YAAY;AAC7C,YAAM,QAAQ,MAAM,OAAO,IAAI,SAAS,MAAM,OAAO,GAAa,EAAE,IAAI;AACxE,YAAM,OAAO,MAAM,YAAY,EAAE,MAAM,oBAAoB,MAAM,CAAC;AAClE,UAAI,KAAK,IAAI;AACX,gBAAQ,IAAI,eAAe,KAAK,IAAW,CAAC;AAAA,MAC9C,OAAO;AACL,gBAAQ,MAAM,KAAK,KAAK;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF;AAEA,YAAQ,MAAM,oBAAoB,QAAQ,KAAK,GAAG,CAAC,EAAE;AACrD,YAAQ,IAAI,MAAM,CAAC;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACjD;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;","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 };
@@ -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":[]}
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/init.ts
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ import { join, dirname } from "path";
6
+ function detectFramework(cwd) {
7
+ const pkgPath = join(cwd, "package.json");
8
+ if (!existsSync(pkgPath)) return "unknown";
9
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
10
+ const allDeps = {
11
+ ...pkg.dependencies,
12
+ ...pkg.devDependencies
13
+ };
14
+ if (allDeps["@vitejs/plugin-react"]) return "vite";
15
+ if (allDeps["next"]) return "nextjs";
16
+ if (allDeps["react-scripts"]) return "cra";
17
+ if (allDeps["react-native"]) return "react-native";
18
+ return "unknown";
19
+ }
20
+ function findFile(cwd, ...candidates) {
21
+ for (const c of candidates) {
22
+ const p = join(cwd, c);
23
+ if (existsSync(p)) return p;
24
+ }
25
+ return null;
26
+ }
27
+ function prependImport(filePath, importLine, dryRun) {
28
+ const content = readFileSync(filePath, "utf-8");
29
+ if (content.includes(importLine) || content.includes("agent-react-devtools")) {
30
+ return null;
31
+ }
32
+ const newContent = importLine + "\n" + content;
33
+ if (!dryRun) {
34
+ writeFileSync(filePath, newContent, "utf-8");
35
+ }
36
+ return filePath;
37
+ }
38
+ function patchViteConfig(cwd, dryRun) {
39
+ const configPath = findFile(
40
+ cwd,
41
+ "vite.config.ts",
42
+ "vite.config.js",
43
+ "vite.config.mts",
44
+ "vite.config.mjs"
45
+ );
46
+ if (!configPath) {
47
+ console.error(" Could not find vite.config.{ts,js}");
48
+ return [];
49
+ }
50
+ const content = readFileSync(configPath, "utf-8");
51
+ if (content.includes("agent-react-devtools")) {
52
+ console.log(" Already configured");
53
+ return [];
54
+ }
55
+ const importLine = "import { reactDevtools } from 'agent-react-devtools/vite';";
56
+ let newContent;
57
+ const lastImportIdx = content.lastIndexOf("\nimport ");
58
+ if (lastImportIdx !== -1) {
59
+ const endOfLine = content.indexOf("\n", lastImportIdx + 1);
60
+ newContent = content.slice(0, endOfLine + 1) + importLine + "\n" + content.slice(endOfLine + 1);
61
+ } else {
62
+ newContent = importLine + "\n" + content;
63
+ }
64
+ const pluginsMatch = newContent.match(/plugins\s*:\s*\[/);
65
+ if (pluginsMatch && pluginsMatch.index != null) {
66
+ const insertPos = pluginsMatch.index + pluginsMatch[0].length;
67
+ newContent = newContent.slice(0, insertPos) + "\n reactDevtools()," + newContent.slice(insertPos);
68
+ } else {
69
+ console.error(" Could not find plugins array in vite config");
70
+ return [];
71
+ }
72
+ if (!dryRun) {
73
+ writeFileSync(configPath, newContent, "utf-8");
74
+ }
75
+ return [configPath];
76
+ }
77
+ function patchNextJs(cwd, dryRun) {
78
+ const pagesEntry = findFile(
79
+ cwd,
80
+ "pages/_app.tsx",
81
+ "pages/_app.jsx",
82
+ "pages/_app.js",
83
+ "src/pages/_app.tsx",
84
+ "src/pages/_app.jsx",
85
+ "src/pages/_app.js"
86
+ );
87
+ if (pagesEntry) {
88
+ const result2 = prependImport(
89
+ pagesEntry,
90
+ "import 'agent-react-devtools/connect';",
91
+ dryRun
92
+ );
93
+ return result2 ? [result2] : [];
94
+ }
95
+ const layoutPath = findFile(
96
+ cwd,
97
+ "app/layout.tsx",
98
+ "app/layout.jsx",
99
+ "app/layout.js",
100
+ "src/app/layout.tsx",
101
+ "src/app/layout.jsx",
102
+ "src/app/layout.js"
103
+ );
104
+ if (!layoutPath) {
105
+ console.error(" Could not find app/layout.tsx or pages/_app.tsx");
106
+ return [];
107
+ }
108
+ const devtoolsPath = join(dirname(layoutPath), "devtools.ts");
109
+ const modified = [];
110
+ if (existsSync(devtoolsPath)) {
111
+ const existing = readFileSync(devtoolsPath, "utf-8");
112
+ if (!existing.includes("agent-react-devtools")) {
113
+ console.error(` ${devtoolsPath} already exists with different content`);
114
+ return [];
115
+ }
116
+ } else {
117
+ const wrapper = "'use client';\nimport 'agent-react-devtools/connect';\n";
118
+ if (!dryRun) {
119
+ writeFileSync(devtoolsPath, wrapper, "utf-8");
120
+ }
121
+ modified.push(devtoolsPath);
122
+ }
123
+ const result = prependImport(layoutPath, "import './devtools';", dryRun);
124
+ if (result) {
125
+ modified.push(result);
126
+ }
127
+ return modified;
128
+ }
129
+ function patchCRA(cwd, dryRun) {
130
+ const entryPath = findFile(
131
+ cwd,
132
+ "src/index.tsx",
133
+ "src/index.jsx",
134
+ "src/index.js"
135
+ );
136
+ if (!entryPath) {
137
+ console.error(" Could not find src/index.tsx");
138
+ return [];
139
+ }
140
+ const result = prependImport(
141
+ entryPath,
142
+ "import 'agent-react-devtools/connect';",
143
+ dryRun
144
+ );
145
+ return result ? [result] : [];
146
+ }
147
+ async function runInit(cwd, dryRun) {
148
+ const framework = detectFramework(cwd);
149
+ console.log(`Detected framework: ${framework}`);
150
+ if (framework === "unknown") {
151
+ console.log("\nCould not detect framework. Manual setup required:");
152
+ console.log(" import 'agent-react-devtools/connect';");
153
+ console.log(" // Must be imported before React loads");
154
+ return;
155
+ }
156
+ if (framework === "react-native") {
157
+ console.log("\nReact Native detected \u2014 no code changes needed!");
158
+ console.log("React Native apps connect to DevTools automatically.\n");
159
+ console.log("Next steps:");
160
+ console.log(" 1. Start the daemon: agent-react-devtools start");
161
+ console.log(" 2. Start your app: npx react-native start");
162
+ console.log("\nFor physical devices:");
163
+ console.log(" adb reverse tcp:8097 tcp:8097");
164
+ console.log("\nFor Expo:");
165
+ console.log(" The connection works automatically with Expo dev client.");
166
+ console.log("\nCustom port:");
167
+ console.log(" Set REACT_DEVTOOLS_PORT=<port> environment variable");
168
+ return;
169
+ }
170
+ let modified = [];
171
+ if (dryRun) {
172
+ console.log("\n[dry-run] Would modify:");
173
+ }
174
+ switch (framework) {
175
+ case "vite":
176
+ modified = patchViteConfig(cwd, dryRun);
177
+ break;
178
+ case "nextjs":
179
+ modified = patchNextJs(cwd, dryRun);
180
+ break;
181
+ case "cra":
182
+ modified = patchCRA(cwd, dryRun);
183
+ break;
184
+ }
185
+ if (modified.length === 0) {
186
+ console.log(" No changes needed (already configured or could not find entry files)");
187
+ return;
188
+ }
189
+ for (const f of modified) {
190
+ console.log(` ${dryRun ? "[dry-run] " : ""}Modified: ${f}`);
191
+ }
192
+ console.log("\nNext steps:");
193
+ console.log(" 1. Install: npm install -D agent-react-devtools react-devtools-core");
194
+ console.log(" 2. Start daemon: agent-react-devtools start");
195
+ console.log(" 3. Start dev server and open your app");
196
+ console.log(" 4. Inspect: agent-react-devtools get tree");
197
+ }
198
+ export {
199
+ detectFramework,
200
+ runInit
201
+ };
202
+ //# sourceMappingURL=init-7IJ2VXT7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\ntype Framework = 'vite' | 'nextjs' | 'cra' | 'react-native' | 'unknown';\n\nexport function detectFramework(cwd: string): Framework {\n const pkgPath = join(cwd, 'package.json');\n if (!existsSync(pkgPath)) return 'unknown';\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n if (allDeps['@vitejs/plugin-react']) return 'vite';\n if (allDeps['next']) return 'nextjs';\n if (allDeps['react-scripts']) return 'cra';\n if (allDeps['react-native']) return 'react-native';\n return 'unknown';\n}\n\nfunction findFile(cwd: string, ...candidates: string[]): string | null {\n for (const c of candidates) {\n const p = join(cwd, c);\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction prependImport(filePath: string, importLine: string, dryRun: boolean): string | null {\n const content = readFileSync(filePath, 'utf-8');\n if (content.includes(importLine) || content.includes('agent-react-devtools')) {\n return null; // already configured\n }\n const newContent = importLine + '\\n' + content;\n if (!dryRun) {\n writeFileSync(filePath, newContent, 'utf-8');\n }\n return filePath;\n}\n\nfunction patchViteConfig(cwd: string, dryRun: boolean): string[] {\n const configPath = findFile(\n cwd,\n 'vite.config.ts',\n 'vite.config.js',\n 'vite.config.mts',\n 'vite.config.mjs',\n );\n if (!configPath) {\n console.error(' Could not find vite.config.{ts,js}');\n return [];\n }\n\n const content = readFileSync(configPath, 'utf-8');\n if (content.includes('agent-react-devtools')) {\n console.log(' Already configured');\n return [];\n }\n\n const importLine = \"import { reactDevtools } from 'agent-react-devtools/vite';\";\n let newContent: string;\n\n // Add import after the last existing import\n const lastImportIdx = content.lastIndexOf('\\nimport ');\n if (lastImportIdx !== -1) {\n const endOfLine = content.indexOf('\\n', lastImportIdx + 1);\n newContent =\n content.slice(0, endOfLine + 1) +\n importLine +\n '\\n' +\n content.slice(endOfLine + 1);\n } else {\n newContent = importLine + '\\n' + content;\n }\n\n // Add reactDevtools() to plugins array\n const pluginsMatch = newContent.match(/plugins\\s*:\\s*\\[/);\n if (pluginsMatch && pluginsMatch.index != null) {\n const insertPos = pluginsMatch.index + pluginsMatch[0].length;\n newContent =\n newContent.slice(0, insertPos) +\n '\\n reactDevtools(),' +\n newContent.slice(insertPos);\n } else {\n console.error(' Could not find plugins array in vite config');\n return [];\n }\n\n if (!dryRun) {\n writeFileSync(configPath, newContent, 'utf-8');\n }\n\n return [configPath];\n}\n\nfunction patchNextJs(cwd: string, dryRun: boolean): string[] {\n // Try Pages Router first — _app is always client-side\n const pagesEntry = findFile(\n cwd,\n 'pages/_app.tsx',\n 'pages/_app.jsx',\n 'pages/_app.js',\n 'src/pages/_app.tsx',\n 'src/pages/_app.jsx',\n 'src/pages/_app.js',\n );\n if (pagesEntry) {\n const result = prependImport(\n pagesEntry,\n \"import 'agent-react-devtools/connect';\",\n dryRun,\n );\n return result ? [result] : [];\n }\n\n // App Router — layout is a Server Component, so we need a 'use client' wrapper\n const layoutPath = findFile(\n cwd,\n 'app/layout.tsx',\n 'app/layout.jsx',\n 'app/layout.js',\n 'src/app/layout.tsx',\n 'src/app/layout.jsx',\n 'src/app/layout.js',\n );\n if (!layoutPath) {\n console.error(' Could not find app/layout.tsx or pages/_app.tsx');\n return [];\n }\n\n const devtoolsPath = join(dirname(layoutPath), 'devtools.ts');\n const modified: string[] = [];\n\n // Create the 'use client' wrapper file\n if (existsSync(devtoolsPath)) {\n const existing = readFileSync(devtoolsPath, 'utf-8');\n if (!existing.includes('agent-react-devtools')) {\n console.error(` ${devtoolsPath} already exists with different content`);\n return [];\n }\n } else {\n const wrapper = \"'use client';\\nimport 'agent-react-devtools/connect';\\n\";\n if (!dryRun) {\n writeFileSync(devtoolsPath, wrapper, 'utf-8');\n }\n modified.push(devtoolsPath);\n }\n\n // Prepend import of the wrapper to the layout\n const result = prependImport(layoutPath, \"import './devtools';\", dryRun);\n if (result) {\n modified.push(result);\n }\n\n return modified;\n}\n\nfunction patchCRA(cwd: string, dryRun: boolean): string[] {\n const entryPath = findFile(\n cwd,\n 'src/index.tsx',\n 'src/index.jsx',\n 'src/index.js',\n );\n if (!entryPath) {\n console.error(' Could not find src/index.tsx');\n return [];\n }\n\n const result = prependImport(\n entryPath,\n \"import 'agent-react-devtools/connect';\",\n dryRun,\n );\n return result ? [result] : [];\n}\n\nexport async function runInit(\n cwd: string,\n dryRun: boolean,\n): Promise<void> {\n const framework = detectFramework(cwd);\n\n console.log(`Detected framework: ${framework}`);\n\n if (framework === 'unknown') {\n console.log('\\nCould not detect framework. Manual setup required:');\n console.log(\" import 'agent-react-devtools/connect';\");\n console.log(' // Must be imported before React loads');\n return;\n }\n\n if (framework === 'react-native') {\n console.log('\\nReact Native detected — no code changes needed!');\n console.log('React Native apps connect to DevTools automatically.\\n');\n console.log('Next steps:');\n console.log(' 1. Start the daemon: agent-react-devtools start');\n console.log(' 2. Start your app: npx react-native start');\n console.log('\\nFor physical devices:');\n console.log(' adb reverse tcp:8097 tcp:8097');\n console.log('\\nFor Expo:');\n console.log(' The connection works automatically with Expo dev client.');\n console.log('\\nCustom port:');\n console.log(' Set REACT_DEVTOOLS_PORT=<port> environment variable');\n return;\n }\n\n let modified: string[] = [];\n\n if (dryRun) {\n console.log('\\n[dry-run] Would modify:');\n }\n\n switch (framework) {\n case 'vite':\n modified = patchViteConfig(cwd, dryRun);\n break;\n case 'nextjs':\n modified = patchNextJs(cwd, dryRun);\n break;\n case 'cra':\n modified = patchCRA(cwd, dryRun);\n break;\n }\n\n if (modified.length === 0) {\n console.log(' No changes needed (already configured or could not find entry files)');\n return;\n }\n\n for (const f of modified) {\n console.log(` ${dryRun ? '[dry-run] ' : ''}Modified: ${f}`);\n }\n\n console.log('\\nNext steps:');\n console.log(' 1. Install: npm install -D agent-react-devtools react-devtools-core');\n console.log(' 2. Start daemon: agent-react-devtools start');\n console.log(' 3. Start dev server and open your app');\n console.log(' 4. Inspect: agent-react-devtools get tree');\n}\n"],"mappings":"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","names":["result"]}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface ReactDevtoolsOptions {
4
+ /** WebSocket port the daemon listens on. Default: 8097 */
5
+ port?: number;
6
+ /** WebSocket host. Default: 'localhost' */
7
+ host?: string;
8
+ }
9
+ declare function reactDevtools(options?: ReactDevtoolsOptions): Plugin;
10
+
11
+ export { type ReactDevtoolsOptions, reactDevtools };
package/dist/vite.js ADDED
@@ -0,0 +1,40 @@
1
+ // src/vite-plugin.ts
2
+ function reactDevtools(options) {
3
+ const port = options?.port ?? 8097;
4
+ const host = options?.host ?? "localhost";
5
+ return {
6
+ name: "agent-react-devtools",
7
+ apply: "serve",
8
+ transformIndexHtml: {
9
+ order: "pre",
10
+ handler() {
11
+ const tags = [];
12
+ if (host !== "localhost") {
13
+ tags.push({
14
+ tag: "meta",
15
+ attrs: { name: "agent-react-devtools-host", content: host },
16
+ injectTo: "head-prepend"
17
+ });
18
+ }
19
+ if (port !== 8097) {
20
+ tags.push({
21
+ tag: "meta",
22
+ attrs: { name: "agent-react-devtools-port", content: String(port) },
23
+ injectTo: "head-prepend"
24
+ });
25
+ }
26
+ tags.push({
27
+ tag: "script",
28
+ attrs: { type: "module" },
29
+ children: `import 'agent-react-devtools/connect';`,
30
+ injectTo: "head-prepend"
31
+ });
32
+ return tags;
33
+ }
34
+ }
35
+ };
36
+ }
37
+ export {
38
+ reactDevtools
39
+ };
40
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite-plugin.ts"],"sourcesContent":["import type { Plugin, HtmlTagDescriptor } from 'vite';\n\nexport interface ReactDevtoolsOptions {\n /** WebSocket port the daemon listens on. Default: 8097 */\n port?: number;\n /** WebSocket host. Default: 'localhost' */\n host?: string;\n}\n\nexport function reactDevtools(options?: ReactDevtoolsOptions): Plugin {\n const port = options?.port ?? 8097;\n const host = options?.host ?? 'localhost';\n\n return {\n name: 'agent-react-devtools',\n apply: 'serve',\n transformIndexHtml: {\n order: 'pre',\n handler() {\n const tags: HtmlTagDescriptor[] = [];\n\n if (host !== 'localhost') {\n tags.push({\n tag: 'meta',\n attrs: { name: 'agent-react-devtools-host', content: host },\n injectTo: 'head-prepend',\n });\n }\n\n if (port !== 8097) {\n tags.push({\n tag: 'meta',\n attrs: { name: 'agent-react-devtools-port', content: String(port) },\n injectTo: 'head-prepend',\n });\n }\n\n tags.push({\n tag: 'script',\n attrs: { type: 'module' },\n children: `import 'agent-react-devtools/connect';`,\n injectTo: 'head-prepend',\n });\n\n return tags;\n },\n },\n };\n}\n"],"mappings":";AASO,SAAS,cAAc,SAAwC;AACpE,QAAM,OAAO,SAAS,QAAQ;AAC9B,QAAM,OAAO,SAAS,QAAQ;AAE9B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,oBAAoB;AAAA,MAClB,OAAO;AAAA,MACP,UAAU;AACR,cAAM,OAA4B,CAAC;AAEnC,YAAI,SAAS,aAAa;AACxB,eAAK,KAAK;AAAA,YACR,KAAK;AAAA,YACL,OAAO,EAAE,MAAM,6BAA6B,SAAS,KAAK;AAAA,YAC1D,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAEA,YAAI,SAAS,MAAM;AACjB,eAAK,KAAK;AAAA,YACR,KAAK;AAAA,YACL,OAAO,EAAE,MAAM,6BAA6B,SAAS,OAAO,IAAI,EAAE;AAAA,YAClE,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAEA,aAAK,KAAK;AAAA,UACR,KAAK;AAAA,UACL,OAAO,EAAE,MAAM,SAAS;AAAA,UACxB,UAAU;AAAA,UACV,UAAU;AAAA,QACZ,CAAC;AAED,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,11 +1,22 @@
1
1
  {
2
2
  "name": "agent-react-devtools",
3
- "version": "0.1.1-canary-20260210005551",
3
+ "version": "0.2.0",
4
4
  "description": "CLI tool for AI agents to inspect React component trees and profile performance",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "agent-react-devtools": "./dist/cli.js"
8
8
  },
9
+ "exports": {
10
+ ".": "./dist/cli.js",
11
+ "./connect": {
12
+ "types": "./dist/connect.d.ts",
13
+ "import": "./dist/connect.js"
14
+ },
15
+ "./vite": {
16
+ "types": "./dist/vite.d.ts",
17
+ "import": "./dist/vite.js"
18
+ }
19
+ },
9
20
  "files": [
10
21
  "dist",
11
22
  "README.md",
@@ -29,13 +40,27 @@
29
40
  "devDependencies": {
30
41
  "@types/node": "^22.0.0",
31
42
  "@types/ws": "^8.5.0",
43
+ "react-devtools-core": "^6.1.0",
32
44
  "tsup": "^8.0.0",
33
45
  "typescript": "^5.5.0",
46
+ "vite": "^6.0.0",
34
47
  "vitest": "^2.0.0"
35
48
  },
36
49
  "dependencies": {
37
50
  "@modelcontextprotocol/sdk": "^1.12.0",
38
51
  "ws": "^8.18.0",
39
52
  "zod": "^3.24.0"
53
+ },
54
+ "peerDependencies": {
55
+ "react-devtools-core": ">=5.0.0",
56
+ "vite": ">=5.0.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "react-devtools-core": {
60
+ "optional": true
61
+ },
62
+ "vite": {
63
+ "optional": true
64
+ }
40
65
  }
41
66
  }