agent-react-devtools 0.3.0 → 0.4.0-canary-20260317173115
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/dist/cli.js +39 -4
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +178 -6
- package/dist/daemon.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# agent-react-devtools
|
|
2
2
|
|
|
3
|
+
## 0.4.0-canary-20260317173115
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5c5ace6: Add `profile export <file>` command
|
|
8
|
+
|
|
9
|
+
- Exports profiling session as a JSON file compatible with the React DevTools Profiler
|
|
10
|
+
- Import the file in the browser extension's Profiler tab to visualize flame graphs, ranked charts, and commit timelines
|
|
11
|
+
- Includes commit data, fiber durations, change descriptions, effect durations, and component snapshots
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 68bd0fc: Auto-restart daemon when CLI detects the binary has been rebuilt since the daemon started. Previously, rebuilding the package required manually stopping and restarting the daemon for changes to take effect.
|
|
16
|
+
|
|
3
17
|
## 0.3.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/dist/cli.js
CHANGED
|
@@ -38,7 +38,22 @@ function isDaemonAlive(info) {
|
|
|
38
38
|
async function ensureDaemon(port) {
|
|
39
39
|
const info = readDaemonInfo();
|
|
40
40
|
if (info && isDaemonAlive(info)) {
|
|
41
|
-
|
|
41
|
+
const daemonScript2 = path.join(
|
|
42
|
+
path.dirname(new URL(import.meta.url).pathname),
|
|
43
|
+
"daemon.js"
|
|
44
|
+
);
|
|
45
|
+
try {
|
|
46
|
+
const stat = fs.statSync(daemonScript2);
|
|
47
|
+
const stale = info.buildMtime !== void 0 ? stat.mtimeMs !== info.buildMtime : stat.mtimeMs > info.startedAt;
|
|
48
|
+
if (stale) {
|
|
49
|
+
port = port ?? info.port;
|
|
50
|
+
stopDaemon();
|
|
51
|
+
} else {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
42
57
|
}
|
|
43
58
|
try {
|
|
44
59
|
fs.unlinkSync(getDaemonInfoPath());
|
|
@@ -86,7 +101,7 @@ function stopDaemon() {
|
|
|
86
101
|
}
|
|
87
102
|
}
|
|
88
103
|
function sendCommand(cmd, socketTimeout = 3e4) {
|
|
89
|
-
return new Promise((
|
|
104
|
+
return new Promise((resolve2, reject) => {
|
|
90
105
|
const socketPath = getSocketPath();
|
|
91
106
|
const conn = net.createConnection(socketPath, () => {
|
|
92
107
|
conn.write(JSON.stringify(cmd) + "\n");
|
|
@@ -99,7 +114,7 @@ function sendCommand(cmd, socketTimeout = 3e4) {
|
|
|
99
114
|
const line = buffer.slice(0, newlineIdx);
|
|
100
115
|
conn.end();
|
|
101
116
|
try {
|
|
102
|
-
|
|
117
|
+
resolve2(JSON.parse(line));
|
|
103
118
|
} catch {
|
|
104
119
|
reject(new Error("Invalid response from daemon"));
|
|
105
120
|
}
|
|
@@ -352,6 +367,8 @@ function replacer(_key, value) {
|
|
|
352
367
|
}
|
|
353
368
|
|
|
354
369
|
// src/cli.ts
|
|
370
|
+
import { writeFileSync } from "fs";
|
|
371
|
+
import { resolve } from "path";
|
|
355
372
|
function usage() {
|
|
356
373
|
return `Usage: devtools <command> [options]
|
|
357
374
|
|
|
@@ -380,7 +397,8 @@ Profiling:
|
|
|
380
397
|
profile slow [--limit N] Slowest components (by avg)
|
|
381
398
|
profile rerenders [--limit N] Most re-rendered components
|
|
382
399
|
profile timeline [--limit N] Commit timeline
|
|
383
|
-
profile commit <N | #N> [--limit N] Detail for specific commit
|
|
400
|
+
profile commit <N | #N> [--limit N] Detail for specific commit
|
|
401
|
+
profile export <file> Export as React DevTools JSON`;
|
|
384
402
|
}
|
|
385
403
|
function parseArgs(argv) {
|
|
386
404
|
const command = [];
|
|
@@ -654,6 +672,23 @@ async function main() {
|
|
|
654
672
|
}
|
|
655
673
|
return;
|
|
656
674
|
}
|
|
675
|
+
if (cmd0 === "profile" && cmd1 === "export") {
|
|
676
|
+
const file = command[2];
|
|
677
|
+
if (!file) {
|
|
678
|
+
console.error("Usage: devtools profile export <file>");
|
|
679
|
+
process.exit(1);
|
|
680
|
+
}
|
|
681
|
+
const resp = await sendCommand({ type: "profile-export" });
|
|
682
|
+
if (resp.ok) {
|
|
683
|
+
const outPath = resolve(file);
|
|
684
|
+
writeFileSync(outPath, JSON.stringify(resp.data), "utf-8");
|
|
685
|
+
console.log(`Exported to ${outPath}`);
|
|
686
|
+
} else {
|
|
687
|
+
console.error(resp.error);
|
|
688
|
+
process.exit(1);
|
|
689
|
+
}
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
657
692
|
console.error(`Unknown command: ${command.join(" ")}`);
|
|
658
693
|
console.log(usage());
|
|
659
694
|
process.exit(1);
|
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, socketTimeout = 30_000): 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 conn.setTimeout(socketTimeout, () => {\n conn.destroy();\n reject(new Error('Command timed out'));\n });\n });\n}\n","import type {\n StatusInfo,\n InspectedElement,\n ComponentRenderReport,\n ChangedKeys,\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/**\n * Format a consistent component reference: `@c1 [fn] Name` or `@c1 [fn] Name key=x`\n */\nfunction formatRef(opts: { label?: string; type?: string; name: string; key?: string | null }): string {\n const ref = opts.label || '?';\n const tag = typeTag(opts.type || 'other');\n let s = `${ref} [${tag}] ${opts.name}`;\n if (opts.key) s += ` key=${opts.key}`;\n return s;\n}\n\n// ── Tree connector characters ──\nconst PIPE = '│ ';\nconst TEE = '├─ ';\nconst ELBOW = '└─ ';\nconst SPACE = ' ';\n\nexport function formatTree(nodes: TreeNode[], hint?: string): string {\n if (nodes.length === 0) {\n return hint ? `No components (${hint})` : 'No components (is a React app connected?)';\n }\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 const line = formatRef({ label: node.label, type: node.type, name: node.displayName, 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 lines.push(formatRef({ label: label || `#${element.id}`, type: element.type, name: element.displayName, key: element.key }));\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) => formatRef({ label: n.label, type: n.type, name: n.displayName, key: n.key }))\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 if (status.connection?.recentEvents?.length > 0) {\n const last = status.connection.recentEvents[status.connection.recentEvents.length - 1];\n const ago = formatAgo(Date.now() - last.timestamp);\n lines.push(`Last event: app ${last.type} ${ago}`);\n }\n return lines.join('\\n');\n}\n\nexport function formatAgo(ms: number): string {\n const sec = Math.round(ms / 1000);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n return `${hr}h ago`;\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 ref = formatRef({ label: c.label, type: c.type, name: c.displayName || `#${c.id}` });\n lines.push(` ${ref} ${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 lines.push(formatRef({ label: label || report.label || `#${report.id}`, type: report.type, name: 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 const keys = formatChangedKeys(report.changedKeys);\n if (keys) {\n lines.push(`changed: ${keys}`);\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 ref = formatRef({ label: r.label, type: r.type, name: r.displayName });\n const causes = r.causes.length > 0 ? r.causes.join(', ') : '?';\n let line = ` ${ref} avg:${r.avgDuration.toFixed(1)}ms max:${r.maxDuration.toFixed(1)}ms renders:${r.renderCount} causes:${causes}`;\n const keys = formatChangedKeys(r.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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 ref = formatRef({ label: r.label, type: r.type, name: r.displayName });\n const causes = r.causes.length > 0 ? r.causes.join(', ') : '?';\n let line = ` ${ref} ${r.renderCount} renders causes:${causes}`;\n const keys = formatChangedKeys(r.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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 ref = formatRef({ label: c.label, type: c.type, name: c.displayName });\n const causes = c.causes.length > 0 ? c.causes.join(', ') : '?';\n let line = ` ${ref} self:${c.selfDuration.toFixed(1)}ms total:${c.actualDuration.toFixed(1)}ms causes:${causes}`;\n const keys = formatChangedKeys(c.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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// ── Changed-keys helper ──\n\nexport function formatChangedKeys(keys: ChangedKeys | undefined): string {\n if (!keys) return '';\n const parts: string[] = [];\n if (keys.props.length > 0) parts.push(`props: ${keys.props.join(', ')}`);\n if (keys.state.length > 0) parts.push(`state: ${keys.state.join(', ')}`);\n if (keys.hooks.length > 0) parts.push(`hooks: ${keys.hooks.map((h) => `#${h}`).join(', ')}`);\n return parts.join(' ');\n}\n\n// ── Helpers ──\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","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\nWait:\n wait --connected [--timeout S] Block until an app connects\n wait --component <name> [--timeout S] Block until a component appears\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\nfunction parseNumericFlag(\n flags: Record<string, string | boolean>,\n name: string,\n defaultValue?: number,\n): number | undefined {\n const raw = flags[name];\n if (raw === undefined || raw === true) return defaultValue;\n const n = parseInt(raw as string, 10);\n if (isNaN(n)) {\n console.error(`Invalid value for --${name}: expected a number`);\n process.exit(1);\n }\n return n;\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 = parseNumericFlag(flags, 'port');\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 = parseNumericFlag(flags, 'depth');\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, resp.hint));\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 // ── Wait ──\n if (cmd0 === 'wait') {\n const timeoutSec = parseNumericFlag(flags, 'timeout', 30)!;\n const timeoutMs = timeoutSec * 1000;\n const socketTimeout = timeoutMs + 5000;\n\n let ipcCmd: IpcCommand;\n if (flags['connected'] !== undefined) {\n ipcCmd = { type: 'wait', condition: 'connected', timeout: timeoutMs };\n } else if (flags['component'] !== undefined) {\n if (typeof flags['component'] !== 'string') {\n console.error('Usage: devtools wait --component <name> [--timeout S]');\n process.exit(1);\n }\n ipcCmd = { type: 'wait', condition: 'component', name: flags['component'], timeout: timeoutMs };\n } else {\n console.error('Usage: devtools wait --connected|--component <name> [--timeout S]');\n process.exit(1);\n }\n\n const resp = await sendCommand(ipcCmd, socketTimeout);\n if (resp.ok) {\n const result = resp.data as { met: boolean; condition: string; timeout?: boolean };\n if (result.met) {\n console.log(`Condition met: ${result.condition}`);\n } else {\n console.error(`Timed out waiting for: ${result.condition}`);\n process.exit(1);\n }\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 const daemonScript = path.join(\n path.dirname(new URL(import.meta.url).pathname),\n 'daemon.js',\n );\n try {\n const stat = fs.statSync(daemonScript);\n const stale = info.buildMtime !== undefined\n ? stat.mtimeMs !== info.buildMtime\n : stat.mtimeMs > info.startedAt;\n if (stale) {\n port = port ?? info.port;\n stopDaemon();\n } else {\n return;\n }\n } catch {\n return;\n }\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, socketTimeout = 30_000): 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 conn.setTimeout(socketTimeout, () => {\n conn.destroy();\n reject(new Error('Command timed out'));\n });\n });\n}\n","import type {\n StatusInfo,\n InspectedElement,\n ComponentRenderReport,\n ChangedKeys,\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/**\n * Format a consistent component reference: `@c1 [fn] Name` or `@c1 [fn] Name key=x`\n */\nfunction formatRef(opts: { label?: string; type?: string; name: string; key?: string | null }): string {\n const ref = opts.label || '?';\n const tag = typeTag(opts.type || 'other');\n let s = `${ref} [${tag}] ${opts.name}`;\n if (opts.key) s += ` key=${opts.key}`;\n return s;\n}\n\n// ── Tree connector characters ──\nconst PIPE = '│ ';\nconst TEE = '├─ ';\nconst ELBOW = '└─ ';\nconst SPACE = ' ';\n\nexport function formatTree(nodes: TreeNode[], hint?: string): string {\n if (nodes.length === 0) {\n return hint ? `No components (${hint})` : 'No components (is a React app connected?)';\n }\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 const line = formatRef({ label: node.label, type: node.type, name: node.displayName, 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 lines.push(formatRef({ label: label || `#${element.id}`, type: element.type, name: element.displayName, key: element.key }));\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) => formatRef({ label: n.label, type: n.type, name: n.displayName, key: n.key }))\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 if (status.connection?.recentEvents?.length > 0) {\n const last = status.connection.recentEvents[status.connection.recentEvents.length - 1];\n const ago = formatAgo(Date.now() - last.timestamp);\n lines.push(`Last event: app ${last.type} ${ago}`);\n }\n return lines.join('\\n');\n}\n\nexport function formatAgo(ms: number): string {\n const sec = Math.round(ms / 1000);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n return `${hr}h ago`;\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 ref = formatRef({ label: c.label, type: c.type, name: c.displayName || `#${c.id}` });\n lines.push(` ${ref} ${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 lines.push(formatRef({ label: label || report.label || `#${report.id}`, type: report.type, name: 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 const keys = formatChangedKeys(report.changedKeys);\n if (keys) {\n lines.push(`changed: ${keys}`);\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 ref = formatRef({ label: r.label, type: r.type, name: r.displayName });\n const causes = r.causes.length > 0 ? r.causes.join(', ') : '?';\n let line = ` ${ref} avg:${r.avgDuration.toFixed(1)}ms max:${r.maxDuration.toFixed(1)}ms renders:${r.renderCount} causes:${causes}`;\n const keys = formatChangedKeys(r.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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 ref = formatRef({ label: r.label, type: r.type, name: r.displayName });\n const causes = r.causes.length > 0 ? r.causes.join(', ') : '?';\n let line = ` ${ref} ${r.renderCount} renders causes:${causes}`;\n const keys = formatChangedKeys(r.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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 ref = formatRef({ label: c.label, type: c.type, name: c.displayName });\n const causes = c.causes.length > 0 ? c.causes.join(', ') : '?';\n let line = ` ${ref} self:${c.selfDuration.toFixed(1)}ms total:${c.actualDuration.toFixed(1)}ms causes:${causes}`;\n const keys = formatChangedKeys(c.changedKeys);\n if (keys) line += ` changed: ${keys}`;\n lines.push(line);\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// ── Changed-keys helper ──\n\nexport function formatChangedKeys(keys: ChangedKeys | undefined): string {\n if (!keys) return '';\n const parts: string[] = [];\n if (keys.props.length > 0) parts.push(`props: ${keys.props.join(', ')}`);\n if (keys.state.length > 0) parts.push(`state: ${keys.state.join(', ')}`);\n if (keys.hooks.length > 0) parts.push(`hooks: ${keys.hooks.map((h) => `#${h}`).join(', ')}`);\n return parts.join(' ');\n}\n\n// ── Helpers ──\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","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 { writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\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\nWait:\n wait --connected [--timeout S] Block until an app connects\n wait --component <name> [--timeout S] Block until a component appears\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 profile export <file> Export as React DevTools JSON`;\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\nfunction parseNumericFlag(\n flags: Record<string, string | boolean>,\n name: string,\n defaultValue?: number,\n): number | undefined {\n const raw = flags[name];\n if (raw === undefined || raw === true) return defaultValue;\n const n = parseInt(raw as string, 10);\n if (isNaN(n)) {\n console.error(`Invalid value for --${name}: expected a number`);\n process.exit(1);\n }\n return n;\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 = parseNumericFlag(flags, 'port');\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 = parseNumericFlag(flags, 'depth');\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, resp.hint));\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 // ── Wait ──\n if (cmd0 === 'wait') {\n const timeoutSec = parseNumericFlag(flags, 'timeout', 30)!;\n const timeoutMs = timeoutSec * 1000;\n const socketTimeout = timeoutMs + 5000;\n\n let ipcCmd: IpcCommand;\n if (flags['connected'] !== undefined) {\n ipcCmd = { type: 'wait', condition: 'connected', timeout: timeoutMs };\n } else if (flags['component'] !== undefined) {\n if (typeof flags['component'] !== 'string') {\n console.error('Usage: devtools wait --component <name> [--timeout S]');\n process.exit(1);\n }\n ipcCmd = { type: 'wait', condition: 'component', name: flags['component'], timeout: timeoutMs };\n } else {\n console.error('Usage: devtools wait --connected|--component <name> [--timeout S]');\n process.exit(1);\n }\n\n const resp = await sendCommand(ipcCmd, socketTimeout);\n if (resp.ok) {\n const result = resp.data as { met: boolean; condition: string; timeout?: boolean };\n if (result.met) {\n console.log(`Condition met: ${result.condition}`);\n } else {\n console.error(`Timed out waiting for: ${result.condition}`);\n process.exit(1);\n }\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 = parseNumericFlag(flags, 'limit');\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 if (cmd0 === 'profile' && cmd1 === 'export') {\n const file = command[2];\n if (!file) {\n console.error('Usage: devtools profile export <file>');\n process.exit(1);\n }\n const resp = await sendCommand({ type: 'profile-export' });\n if (resp.ok) {\n const outPath = resolve(file);\n writeFileSync(outPath, JSON.stringify(resp.data), 'utf-8');\n console.log(`Exported to ${outPath}`);\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":["daemonScript","resolve"]}
|
package/dist/daemon.js
CHANGED
|
@@ -698,6 +698,147 @@ var ComponentTree = class {
|
|
|
698
698
|
}
|
|
699
699
|
};
|
|
700
700
|
|
|
701
|
+
// src/profile-export.ts
|
|
702
|
+
function buildExportData(session, tree) {
|
|
703
|
+
if (session.commits.length === 0) return null;
|
|
704
|
+
if (session.rawRoots.length > 0) {
|
|
705
|
+
return {
|
|
706
|
+
version: 5,
|
|
707
|
+
dataForRoots: session.rawRoots.map((raw) => {
|
|
708
|
+
const subtreeIds = collectSubtreeIds(raw.rootID, tree);
|
|
709
|
+
const snapshots = buildSnapshots(raw.rootID, subtreeIds, tree);
|
|
710
|
+
const operations = raw.operations.length > 0 ? raw.operations : session.commits.map(() => []);
|
|
711
|
+
return {
|
|
712
|
+
commitData: raw.commitData,
|
|
713
|
+
displayName: raw.displayName,
|
|
714
|
+
initialTreeBaseDurations: raw.initialTreeBaseDurations,
|
|
715
|
+
operations,
|
|
716
|
+
rootID: raw.rootID,
|
|
717
|
+
snapshots
|
|
718
|
+
};
|
|
719
|
+
})
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
return buildFromParsedCommits(session, tree);
|
|
723
|
+
}
|
|
724
|
+
function buildFromParsedCommits(session, tree) {
|
|
725
|
+
let rootIds = tree.getRootIds();
|
|
726
|
+
if (rootIds.length === 0) {
|
|
727
|
+
rootIds = [1];
|
|
728
|
+
}
|
|
729
|
+
const dataForRoots = [];
|
|
730
|
+
for (const rootId of rootIds) {
|
|
731
|
+
const rootNode = tree.getNode(rootId);
|
|
732
|
+
const subtreeIds = collectSubtreeIds(rootId, tree);
|
|
733
|
+
const snapshots = buildSnapshots(rootId, subtreeIds, tree);
|
|
734
|
+
const baseDurationMap = /* @__PURE__ */ new Map();
|
|
735
|
+
for (const nodeId of subtreeIds) {
|
|
736
|
+
baseDurationMap.set(nodeId, 0);
|
|
737
|
+
}
|
|
738
|
+
for (const commit of session.commits) {
|
|
739
|
+
for (const [id, duration] of commit.fiberSelfDurations) {
|
|
740
|
+
if (baseDurationMap.has(id)) {
|
|
741
|
+
baseDurationMap.set(id, duration);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const commitData = session.commits.map(
|
|
746
|
+
(commit) => convertCommit(commit)
|
|
747
|
+
);
|
|
748
|
+
dataForRoots.push({
|
|
749
|
+
commitData,
|
|
750
|
+
displayName: rootNode?.displayName || "Root",
|
|
751
|
+
initialTreeBaseDurations: Array.from(baseDurationMap.entries()),
|
|
752
|
+
operations: session.commits.map(() => []),
|
|
753
|
+
rootID: rootId,
|
|
754
|
+
snapshots
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
return {
|
|
758
|
+
version: 5,
|
|
759
|
+
dataForRoots
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function convertCommit(commit) {
|
|
763
|
+
const changeDescriptions = [];
|
|
764
|
+
for (const [id, desc] of commit.changeDescriptions) {
|
|
765
|
+
changeDescriptions.push([id, {
|
|
766
|
+
context: null,
|
|
767
|
+
didHooksChange: desc.didHooksChange,
|
|
768
|
+
isFirstMount: desc.isFirstMount,
|
|
769
|
+
props: desc.props,
|
|
770
|
+
state: desc.state,
|
|
771
|
+
hooks: desc.hooks
|
|
772
|
+
}]);
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
changeDescriptions: changeDescriptions.length > 0 ? changeDescriptions : null,
|
|
776
|
+
duration: commit.duration,
|
|
777
|
+
effectDuration: commit.effectDuration ?? 0,
|
|
778
|
+
fiberActualDurations: Array.from(commit.fiberActualDurations.entries()),
|
|
779
|
+
fiberSelfDurations: Array.from(commit.fiberSelfDurations.entries()),
|
|
780
|
+
passiveEffectDuration: commit.passiveEffectDuration ?? 0,
|
|
781
|
+
priorityLevel: commit.priorityLevel ?? null,
|
|
782
|
+
timestamp: commit.timestamp,
|
|
783
|
+
updaters: commit.updaters
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function buildSnapshots(rootId, subtreeIds, tree) {
|
|
787
|
+
const snapshots = [];
|
|
788
|
+
for (const nodeId of subtreeIds) {
|
|
789
|
+
const node = tree.getNode(nodeId);
|
|
790
|
+
if (!node) continue;
|
|
791
|
+
const elementType = nodeId === rootId && node.type === "other" ? 11 : componentTypeToElementType(node.type);
|
|
792
|
+
snapshots.push([nodeId, {
|
|
793
|
+
id: nodeId,
|
|
794
|
+
children: node.children,
|
|
795
|
+
displayName: node.displayName || null,
|
|
796
|
+
hocDisplayNames: null,
|
|
797
|
+
key: node.key,
|
|
798
|
+
type: elementType,
|
|
799
|
+
compiledWithForget: false
|
|
800
|
+
}]);
|
|
801
|
+
}
|
|
802
|
+
return snapshots;
|
|
803
|
+
}
|
|
804
|
+
function collectSubtreeIds(rootId, tree) {
|
|
805
|
+
const ids = [];
|
|
806
|
+
const visit = (id) => {
|
|
807
|
+
const node = tree.getNode(id);
|
|
808
|
+
if (!node) return;
|
|
809
|
+
ids.push(id);
|
|
810
|
+
for (const childId of node.children) {
|
|
811
|
+
visit(childId);
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
visit(rootId);
|
|
815
|
+
return ids;
|
|
816
|
+
}
|
|
817
|
+
function componentTypeToElementType(type) {
|
|
818
|
+
switch (type) {
|
|
819
|
+
case "class":
|
|
820
|
+
return 1;
|
|
821
|
+
case "context":
|
|
822
|
+
return 2;
|
|
823
|
+
case "function":
|
|
824
|
+
return 5;
|
|
825
|
+
case "forwardRef":
|
|
826
|
+
return 6;
|
|
827
|
+
case "host":
|
|
828
|
+
return 7;
|
|
829
|
+
case "memo":
|
|
830
|
+
return 8;
|
|
831
|
+
case "profiler":
|
|
832
|
+
return 10;
|
|
833
|
+
case "suspense":
|
|
834
|
+
return 12;
|
|
835
|
+
case "other":
|
|
836
|
+
return 9;
|
|
837
|
+
default:
|
|
838
|
+
return 9;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
701
842
|
// src/profiler.ts
|
|
702
843
|
var Profiler = class {
|
|
703
844
|
session = null;
|
|
@@ -712,7 +853,8 @@ var Profiler = class {
|
|
|
712
853
|
name: name || `session-${Date.now()}`,
|
|
713
854
|
startedAt: Date.now(),
|
|
714
855
|
stoppedAt: null,
|
|
715
|
-
commits: []
|
|
856
|
+
commits: [],
|
|
857
|
+
rawRoots: []
|
|
716
858
|
};
|
|
717
859
|
}
|
|
718
860
|
/** Cache a component's display name (call during profiling to survive unmounts) */
|
|
@@ -753,11 +895,19 @@ var Profiler = class {
|
|
|
753
895
|
* - changeDescriptions: Map<id, description>
|
|
754
896
|
*/
|
|
755
897
|
processProfilingData(payload) {
|
|
756
|
-
if (!this.session
|
|
898
|
+
if (!this.session) return;
|
|
757
899
|
const data = payload;
|
|
758
900
|
const roots = data?.dataForRoots;
|
|
759
901
|
if (roots) {
|
|
760
902
|
for (const root of roots) {
|
|
903
|
+
this.session.rawRoots.push({
|
|
904
|
+
rootID: root.rootID ?? 1,
|
|
905
|
+
commitData: root.commitData ?? [],
|
|
906
|
+
initialTreeBaseDurations: root.initialTreeBaseDurations ?? [],
|
|
907
|
+
operations: root.operations ?? [],
|
|
908
|
+
snapshots: root.snapshots ?? [],
|
|
909
|
+
displayName: root.displayName ?? "Root"
|
|
910
|
+
});
|
|
761
911
|
if (root.commitData) {
|
|
762
912
|
for (const commitData of root.commitData) {
|
|
763
913
|
this.processCommitData(commitData);
|
|
@@ -778,7 +928,11 @@ var Profiler = class {
|
|
|
778
928
|
duration: commitData.duration || 0,
|
|
779
929
|
fiberActualDurations: /* @__PURE__ */ new Map(),
|
|
780
930
|
fiberSelfDurations: /* @__PURE__ */ new Map(),
|
|
781
|
-
changeDescriptions: /* @__PURE__ */ new Map()
|
|
931
|
+
changeDescriptions: /* @__PURE__ */ new Map(),
|
|
932
|
+
effectDuration: commitData.effectDuration ?? null,
|
|
933
|
+
passiveEffectDuration: commitData.passiveEffectDuration ?? null,
|
|
934
|
+
priorityLevel: commitData.priorityLevel ?? null,
|
|
935
|
+
updaters: commitData.updaters ?? null
|
|
782
936
|
};
|
|
783
937
|
if (commitData.fiberActualDurations) {
|
|
784
938
|
parseDurations(commitData.fiberActualDurations, commit.fiberActualDurations);
|
|
@@ -786,8 +940,9 @@ var Profiler = class {
|
|
|
786
940
|
if (commitData.fiberSelfDurations) {
|
|
787
941
|
parseDurations(commitData.fiberSelfDurations, commit.fiberSelfDurations);
|
|
788
942
|
}
|
|
789
|
-
|
|
790
|
-
|
|
943
|
+
const rawDescs = commitData.changeDescriptions;
|
|
944
|
+
if (rawDescs) {
|
|
945
|
+
const entries = rawDescs instanceof Map ? rawDescs.entries() : rawDescs[Symbol.iterator]();
|
|
791
946
|
for (const [id, desc] of entries) {
|
|
792
947
|
const d = desc;
|
|
793
948
|
commit.changeDescriptions.set(id, {
|
|
@@ -889,6 +1044,10 @@ var Profiler = class {
|
|
|
889
1044
|
if (limit) return entries.slice(0, limit);
|
|
890
1045
|
return entries;
|
|
891
1046
|
}
|
|
1047
|
+
getExportData(tree) {
|
|
1048
|
+
if (!this.session) return null;
|
|
1049
|
+
return buildExportData(this.session, tree);
|
|
1050
|
+
}
|
|
892
1051
|
getAllReports(tree) {
|
|
893
1052
|
if (!this.session) return [];
|
|
894
1053
|
const componentIds = /* @__PURE__ */ new Set();
|
|
@@ -983,11 +1142,17 @@ var Daemon = class {
|
|
|
983
1142
|
}
|
|
984
1143
|
await this.bridge.start();
|
|
985
1144
|
await this.startIpc(socketPath);
|
|
1145
|
+
let buildMtime;
|
|
1146
|
+
try {
|
|
1147
|
+
buildMtime = fs.statSync(new URL(import.meta.url).pathname).mtimeMs;
|
|
1148
|
+
} catch {
|
|
1149
|
+
}
|
|
986
1150
|
const info = {
|
|
987
1151
|
pid: process.pid,
|
|
988
1152
|
port: this.port,
|
|
989
1153
|
socketPath,
|
|
990
|
-
startedAt: this.startedAt
|
|
1154
|
+
startedAt: this.startedAt,
|
|
1155
|
+
buildMtime
|
|
991
1156
|
};
|
|
992
1157
|
fs.writeFileSync(getDaemonInfoPath(), JSON.stringify(info, null, 2));
|
|
993
1158
|
console.log(`Daemon started (pid=${process.pid}, port=${this.port})`);
|
|
@@ -1139,6 +1304,13 @@ var Daemon = class {
|
|
|
1139
1304
|
enrichWithLabels(detail.components, this.tree);
|
|
1140
1305
|
return { ok: true, data: detail };
|
|
1141
1306
|
}
|
|
1307
|
+
case "profile-export": {
|
|
1308
|
+
const exportData = this.profiler.getExportData(this.tree);
|
|
1309
|
+
if (!exportData) {
|
|
1310
|
+
return { ok: false, error: "No profiling data to export (run profile start/stop first)" };
|
|
1311
|
+
}
|
|
1312
|
+
return { ok: true, data: exportData };
|
|
1313
|
+
}
|
|
1142
1314
|
case "wait":
|
|
1143
1315
|
return this.handleWait(cmd, conn);
|
|
1144
1316
|
default:
|
package/dist/daemon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/daemon.ts","../src/devtools-bridge.ts","../src/component-tree.ts","../src/profiler.ts"],"sourcesContent":["import net from 'node:net';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { DevToolsBridge } from './devtools-bridge.js';\nimport { ComponentTree } from './component-tree.js';\nimport { Profiler } from './profiler.js';\nimport type { IpcCommand, IpcResponse, DaemonInfo, StatusInfo } 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 STATE_DIR = DEFAULT_STATE_DIR;\n\nfunction getSocketPath(): string {\n return path.join(STATE_DIR, 'daemon.sock');\n}\n\nfunction getDaemonInfoPath(): string {\n return path.join(STATE_DIR, 'daemon.json');\n}\n\n/**\n * Enrich profiling result items with label + type from the component tree.\n */\nfunction enrichWithLabels(\n items: Array<{ id: number; label?: string; type?: string }>,\n tree: ComponentTree,\n): void {\n for (const item of items) {\n if (!item.label) item.label = tree.getLabel(item.id);\n if (!item.type) {\n const node = tree.getNode(item.id);\n if (node) item.type = node.type;\n }\n }\n}\n\nclass Daemon {\n private ipcServer: net.Server | null = null;\n private bridge: DevToolsBridge;\n private tree: ComponentTree;\n private profiler: Profiler;\n private port: number;\n private startedAt = Date.now();\n\n constructor(port: number) {\n this.port = port;\n this.tree = new ComponentTree();\n this.profiler = new Profiler();\n this.bridge = new DevToolsBridge(port, this.tree, this.profiler);\n }\n\n async start(): Promise<void> {\n // Ensure state directory exists\n fs.mkdirSync(STATE_DIR, { recursive: true });\n\n // Clean up stale socket\n const socketPath = getSocketPath();\n if (fs.existsSync(socketPath)) {\n try {\n fs.unlinkSync(socketPath);\n } catch {\n // ignore\n }\n }\n\n // Start WebSocket bridge\n await this.bridge.start();\n\n // Start IPC server\n await this.startIpc(socketPath);\n\n // Write daemon info\n const info: DaemonInfo = {\n pid: process.pid,\n port: this.port,\n socketPath,\n startedAt: this.startedAt,\n };\n fs.writeFileSync(getDaemonInfoPath(), JSON.stringify(info, null, 2));\n\n console.log(`Daemon started (pid=${process.pid}, port=${this.port})`);\n\n // Handle shutdown\n const shutdown = () => {\n this.stop();\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n }\n\n private startIpc(socketPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.ipcServer = net.createServer((conn) => {\n let buffer = '';\n\n conn.on('data', (chunk) => {\n buffer += chunk.toString();\n\n // Process complete messages (newline-delimited JSON)\n let newlineIdx: number;\n while ((newlineIdx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n\n try {\n const cmd: IpcCommand = JSON.parse(line);\n this.handleCommand(cmd, conn).then((response) => {\n if (!conn.destroyed) {\n conn.write(JSON.stringify(response) + '\\n');\n }\n });\n } catch {\n const response: IpcResponse = {\n ok: false,\n error: 'Invalid JSON',\n };\n conn.write(JSON.stringify(response) + '\\n');\n }\n }\n });\n });\n\n this.ipcServer.on('error', reject);\n\n this.ipcServer.listen(socketPath, () => {\n resolve();\n });\n });\n }\n\n private async handleCommand(cmd: IpcCommand, conn: net.Socket): Promise<IpcResponse> {\n try {\n switch (cmd.type) {\n case 'ping':\n return { ok: true, data: 'pong' };\n\n case 'status':\n return {\n ok: true,\n data: {\n daemonRunning: true,\n port: this.port,\n connectedApps: this.bridge.getConnectedAppCount(),\n componentCount: this.tree.getComponentCount(),\n profilingActive: this.profiler.isActive(),\n uptime: Date.now() - this.startedAt,\n connection: this.bridge.getConnectionHealth(),\n } satisfies StatusInfo,\n };\n\n case 'get-tree': {\n const treeData = this.tree.getTree(cmd.depth);\n const response: IpcResponse = { ok: true, data: treeData };\n if (treeData.length === 0) {\n const health = this.bridge.getConnectionHealth();\n if (health.hasEverConnected && health.connectedApps === 0 && health.lastDisconnectAt !== null) {\n const ago = Math.round((Date.now() - health.lastDisconnectAt) / 1000);\n response.hint = `app disconnected ${ago}s ago, waiting for reconnect...`;\n }\n }\n return response;\n }\n\n case 'get-component': {\n const resolvedId = this.tree.resolveId(cmd.id);\n if (resolvedId === undefined) {\n return { ok: false, error: `Component ${cmd.id} not found` };\n }\n const element = await this.bridge.inspectElement(resolvedId);\n if (!element) {\n return { ok: false, error: `Component ${cmd.id} not found` };\n }\n // Include the label if the request used one\n const label = typeof cmd.id === 'string' ? cmd.id : undefined;\n return { ok: true, data: element, label };\n }\n\n case 'find':\n return {\n ok: true,\n data: this.tree.findByName(cmd.name, cmd.exact),\n };\n\n case 'count':\n return {\n ok: true,\n data: this.tree.getCountByType(),\n };\n\n case 'profile-start':\n this.profiler.start(cmd.name);\n // Snapshot existing component names so they survive unmounts\n for (const id of this.tree.getAllNodeIds()) {\n const node = this.tree.getNode(id);\n if (node) this.profiler.trackComponent(id, node.displayName);\n }\n this.bridge.startProfiling();\n return { ok: true, data: 'Profiling started' };\n\n case 'profile-stop': {\n await this.bridge.stopProfilingAndCollect();\n const session = this.profiler.stop(this.tree);\n if (!session) {\n return { ok: false, error: 'No active profiling session' };\n }\n enrichWithLabels(session.componentRenderCounts, this.tree);\n return { ok: true, data: session };\n }\n\n case 'profile-report': {\n const resolvedCompId = this.tree.resolveId(cmd.componentId);\n if (resolvedCompId === undefined) {\n return { ok: false, error: `Component ${cmd.componentId} not found` };\n }\n const report = this.profiler.getReport(resolvedCompId, this.tree);\n if (!report) {\n return {\n ok: false,\n error: `No profiling data for component ${cmd.componentId}`,\n };\n }\n enrichWithLabels([report], this.tree);\n const compLabel = typeof cmd.componentId === 'string' ? cmd.componentId : undefined;\n return { ok: true, data: report, label: compLabel };\n }\n\n case 'profile-slow': {\n const slowest = this.profiler.getSlowest(this.tree, cmd.limit);\n enrichWithLabels(slowest, this.tree);\n return { ok: true, data: slowest };\n }\n\n case 'profile-rerenders': {\n const rerenders = this.profiler.getMostRerenders(this.tree, cmd.limit);\n enrichWithLabels(rerenders, this.tree);\n return { ok: true, data: rerenders };\n }\n\n case 'profile-timeline':\n return {\n ok: true,\n data: this.profiler.getTimeline(cmd.limit),\n };\n\n case 'profile-commit': {\n const detail = this.profiler.getCommitDetails(cmd.index, this.tree, cmd.limit);\n if (!detail) {\n return { ok: false, error: `Commit #${cmd.index} not found` };\n }\n enrichWithLabels(detail.components, this.tree);\n return { ok: true, data: detail };\n }\n\n case 'wait':\n return this.handleWait(cmd, conn);\n\n default:\n return { ok: false, error: `Unknown command: ${(cmd as any).type}` };\n }\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n private handleWait(\n cmd: Extract<IpcCommand, { type: 'wait' }>,\n conn: net.Socket,\n ): Promise<IpcResponse> {\n const timeout = cmd.timeout ?? 30_000;\n\n // Check if condition is already met\n if (this.isWaitConditionMet(cmd)) {\n return Promise.resolve({ ok: true, data: { met: true, condition: cmd.condition } });\n }\n\n return new Promise((resolve) => {\n let settled = false;\n const settle = (response: IpcResponse) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n unsubscribe();\n conn.removeListener('close', onClose);\n resolve(response);\n };\n\n const unsubscribe = this.bridge.onStateChange(() => {\n if (this.isWaitConditionMet(cmd)) {\n settle({ ok: true, data: { met: true, condition: cmd.condition } });\n }\n });\n\n const timer = setTimeout(() => {\n settle({ ok: true, data: { met: false, condition: cmd.condition, timeout: true } });\n }, timeout);\n\n const onClose = () => {\n settle({ ok: false, error: 'Client disconnected' });\n };\n conn.on('close', onClose);\n });\n }\n\n private isWaitConditionMet(cmd: Extract<IpcCommand, { type: 'wait' }>): boolean {\n switch (cmd.condition) {\n case 'connected':\n return this.bridge.getConnectedAppCount() > 0;\n case 'component':\n return this.tree.findByName(cmd.name, true).length > 0;\n default:\n return false;\n }\n }\n\n stop(): void {\n this.bridge.stop();\n if (this.ipcServer) {\n this.ipcServer.close();\n this.ipcServer = null;\n }\n // Clean up files\n try {\n fs.unlinkSync(getSocketPath());\n } catch {\n // ignore\n }\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n console.log('Daemon stopped');\n }\n}\n\n// ── Main ──\n\nconst portArg = process.argv.find((a) => a.startsWith('--port='));\nconst port = portArg ? parseInt(portArg.split('=')[1], 10) : 8097;\n\nconst stateDirArg = process.argv.find((a) => a.startsWith('--state-dir='));\nif (stateDirArg) {\n STATE_DIR = stateDirArg.split('=')[1];\n}\n\nconst daemon = new Daemon(port);\ndaemon.start().catch((err) => {\n console.error('Failed to start daemon:', err);\n process.exit(1);\n});\n","import { WebSocketServer, WebSocket } from 'ws';\nimport type { ComponentTree } from './component-tree.js';\nimport type { Profiler } from './profiler.js';\nimport type { InspectedElement, ConnectionHealth, ConnectionEvent } from './types.js';\n\n/**\n * React DevTools protocol bridge.\n *\n * Implements the \"Wall\" messaging pattern that React DevTools uses:\n * - The backend (inside React app) sends operations, profiling data, etc.\n * - The frontend (us) can request element inspection, start/stop profiling, etc.\n *\n * Message format over WebSocket:\n * { event: string, payload: any }\n */\n\ninterface DevToolsMessage {\n event: string;\n payload: unknown;\n}\n\ninterface PendingInspection {\n resolve: (value: InspectedElement | null) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface PendingProfilingCollect {\n resolve: () => void;\n timer: ReturnType<typeof setTimeout>;\n remaining: number;\n}\n\nexport class DevToolsBridge {\n private wss: WebSocketServer | null = null;\n private connections = new Set<WebSocket>();\n private port: number;\n private tree: ComponentTree;\n private profiler: Profiler;\n private pendingInspections = new Map<number, PendingInspection>();\n private pendingProfilingCollect: PendingProfilingCollect | null = null;\n private rendererIds = new Set<number>();\n /** Track which root fiber IDs belong to each WebSocket connection */\n private connectionRoots = new Map<WebSocket, Set<number>>();\n private hasEverConnected = false;\n private lastDisconnectAt: number | null = null;\n private recentEvents: ConnectionEvent[] = [];\n private reconnectWindowMs = 5000;\n private stateChangeListeners = new Set<() => void>();\n\n constructor(port: number, tree: ComponentTree, profiler: Profiler) {\n this.port = port;\n this.tree = tree;\n this.profiler = profiler;\n }\n\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.wss = new WebSocketServer({ port: this.port }, () => {\n resolve();\n });\n\n this.wss.on('error', (err) => {\n reject(err);\n });\n\n this.wss.on('connection', (ws) => {\n this.connections.add(ws);\n\n // Reconnect = going from 0 to 1 connected app shortly after a disconnect\n const wasDisconnected = this.connections.size === 1 &&\n this.lastDisconnectAt !== null &&\n (Date.now() - this.lastDisconnectAt) < this.reconnectWindowMs;\n const eventType = wasDisconnected ? 'reconnected' as const : 'connected' as const;\n this.hasEverConnected = true;\n this.lastDisconnectAt = null;\n this.pushEvent({ type: eventType, timestamp: Date.now() });\n this.notifyStateChange();\n\n ws.on('message', (data) => {\n try {\n const msg: DevToolsMessage = JSON.parse(data.toString());\n this.handleMessage(ws, msg);\n } catch {\n // ignore parse errors\n }\n });\n\n ws.on('close', () => {\n this.cleanupConnection(ws);\n });\n\n ws.on('error', () => {\n this.cleanupConnection(ws);\n });\n });\n });\n }\n\n stop(): void {\n for (const conn of this.connections) {\n conn.close();\n }\n this.connections.clear();\n if (this.wss) {\n this.wss.close();\n this.wss = null;\n }\n }\n\n getConnectedAppCount(): number {\n return this.connections.size;\n }\n\n /**\n * Request detailed inspection of a specific element.\n * Sends a request to the React app and waits for the response.\n */\n inspectElement(id: number): Promise<InspectedElement | null> {\n const node = this.tree.getNode(id);\n if (!node) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n this.pendingInspections.delete(id);\n resolve(null);\n }, 5000);\n\n this.pendingInspections.set(id, { resolve, timer });\n\n this.sendToAll({\n event: 'inspectElement',\n payload: {\n id,\n rendererID: node.rendererId,\n forceFullData: true,\n requestID: id,\n path: null,\n },\n });\n });\n }\n\n startProfiling(): void {\n this.sendToAll({\n event: 'startProfiling',\n payload: { recordChangeDescriptions: true },\n });\n }\n\n /**\n * Stop profiling and request data from each renderer.\n * Returns a promise that resolves when profilingData arrives (or 5s timeout).\n */\n stopProfilingAndCollect(): Promise<void> {\n this.sendToAll({\n event: 'stopProfiling',\n payload: undefined,\n });\n\n // If no renderers known, resolve immediately\n if (this.rendererIds.size === 0) {\n return Promise.resolve();\n }\n\n // Request profiling data from each renderer\n for (const rendererID of this.rendererIds) {\n this.sendToAll({\n event: 'getProfilingData',\n payload: { rendererID },\n });\n }\n\n const expected = this.rendererIds.size;\n return new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n this.pendingProfilingCollect = null;\n resolve();\n }, 5000);\n\n this.pendingProfilingCollect = { resolve, timer, remaining: expected };\n });\n }\n\n private handleMessage(ws: WebSocket, msg: DevToolsMessage): void {\n switch (msg.event) {\n case 'backendInitialized':\n // Send the full frontend handshake sequence\n this.sendTo(ws, { event: 'getBridgeProtocol', payload: undefined });\n this.sendTo(ws, { event: 'getBackendVersion', payload: undefined });\n this.sendTo(ws, { event: 'getIfHasUnsupportedRendererVersion', payload: undefined });\n this.sendTo(ws, { event: 'getHookSettings', payload: undefined });\n this.sendTo(ws, { event: 'getProfilingStatus', payload: undefined });\n break;\n\n case 'bridgeProtocol':\n case 'backendVersion':\n case 'profilingStatus':\n case 'overrideComponentFilters':\n break;\n\n case 'operations':\n this.handleOperations(ws, msg.payload as number[]);\n break;\n\n case 'inspectedElement':\n this.handleInspectedElement(msg.payload);\n break;\n\n case 'profilingData':\n this.handleProfilingData(msg.payload);\n break;\n\n case 'renderer': {\n const payload = msg.payload as { id: number };\n this.rendererIds.add(payload.id);\n break;\n }\n\n case 'rendererAttached': {\n const payload = msg.payload as { id: number };\n this.rendererIds.add(payload.id);\n break;\n }\n\n case 'shutdown':\n ws.close();\n break;\n\n // Silently ignore known but unhandled events\n case 'hookSettings':\n case 'isBackendStorageAPISupported':\n case 'isReactNativeEnvironment':\n case 'isReloadAndProfileSupportedByBackend':\n case 'isSynchronousXHRSupported':\n case 'syncSelectionFromNativeElementsPanel':\n case 'unsupportedRendererVersion':\n break;\n\n default:\n break;\n }\n }\n\n private handleOperations(ws: WebSocket, operations: number[]): void {\n if (operations.length >= 2) {\n // Track renderer ID (first element of every operations array)\n this.rendererIds.add(operations[0]);\n\n // Track which root fiber IDs belong to this connection\n const rootFiberId = operations[1];\n let roots = this.connectionRoots.get(ws);\n if (!roots) {\n roots = new Set();\n this.connectionRoots.set(ws, roots);\n }\n roots.add(rootFiberId);\n }\n const added = this.tree.applyOperations(operations);\n\n // Cache display names during profiling so unmounted components are still identifiable\n if (this.profiler.isActive()) {\n for (const node of added) {\n this.profiler.trackComponent(node.id, node.displayName);\n }\n }\n\n this.notifyStateChange();\n }\n\n private cleanupConnection(ws: WebSocket): void {\n this.connections.delete(ws);\n // Remove all root trees that belonged to this connection\n const roots = this.connectionRoots.get(ws);\n if (roots) {\n for (const rootId of roots) {\n this.tree.removeRoot(rootId);\n }\n this.connectionRoots.delete(ws);\n }\n this.lastDisconnectAt = Date.now();\n this.pushEvent({ type: 'disconnected', timestamp: Date.now() });\n this.notifyStateChange();\n }\n\n private handleInspectedElement(payload: unknown): void {\n const data = payload as {\n type: string;\n id: number;\n value?: {\n id: number;\n displayName: string;\n type: number;\n key: string | null;\n props: Record<string, unknown>;\n state: Record<string, unknown> | null;\n hooks: unknown[] | null;\n };\n };\n\n if (data.type !== 'full-data' && data.type !== 'hydrated-path') {\n // No data available\n const pending = this.pendingInspections.get(data.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingInspections.delete(data.id);\n pending.resolve(null);\n }\n return;\n }\n\n const pending = this.pendingInspections.get(data.id);\n if (!pending || !data.value) return;\n\n clearTimeout(pending.timer);\n this.pendingInspections.delete(data.id);\n\n const node = this.tree.getNode(data.id);\n const inspected: InspectedElement = {\n id: data.id,\n displayName: data.value.displayName || node?.displayName || 'Unknown',\n type: node?.type || 'other',\n key: data.value.key,\n props: cleanDehydrated(data.value.props) as Record<string, unknown>,\n state: data.value.state\n ? (cleanDehydrated(data.value.state) as Record<string, unknown>)\n : null,\n hooks: data.value.hooks\n ? parseHooks(data.value.hooks)\n : null,\n renderedAt: null,\n };\n\n pending.resolve(inspected);\n }\n\n private handleProfilingData(payload: unknown): void {\n // React DevTools sends profiling data as a complex nested structure.\n // We forward it to the profiler for processing.\n this.profiler.processProfilingData(payload);\n\n // Resolve once all expected renderer responses have arrived\n if (this.pendingProfilingCollect) {\n this.pendingProfilingCollect.remaining--;\n if (this.pendingProfilingCollect.remaining <= 0) {\n clearTimeout(this.pendingProfilingCollect.timer);\n const pending = this.pendingProfilingCollect;\n this.pendingProfilingCollect = null;\n pending.resolve();\n }\n }\n }\n\n getConnectionHealth(): ConnectionHealth {\n return {\n connectedApps: this.connections.size,\n hasEverConnected: this.hasEverConnected,\n lastDisconnectAt: this.lastDisconnectAt,\n recentEvents: [...this.recentEvents],\n };\n }\n\n onStateChange(listener: () => void): () => void {\n this.stateChangeListeners.add(listener);\n return () => { this.stateChangeListeners.delete(listener); };\n }\n\n private pushEvent(event: ConnectionEvent): void {\n this.recentEvents.push(event);\n if (this.recentEvents.length > 20) {\n this.recentEvents = this.recentEvents.slice(-20);\n }\n }\n\n private notifyStateChange(): void {\n for (const listener of this.stateChangeListeners) {\n listener();\n }\n }\n\n private sendTo(ws: WebSocket, msg: DevToolsMessage): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n }\n\n private sendToAll(msg: DevToolsMessage): void {\n const raw = JSON.stringify(msg);\n for (const conn of this.connections) {\n if (conn.readyState === WebSocket.OPEN) {\n conn.send(raw);\n }\n }\n }\n}\n\n/**\n * React DevTools uses \"dehydrated\" values for complex objects.\n * These appear as objects with `type: 'string'` and other metadata.\n * We simplify them for display.\n */\nfunction cleanDehydrated(obj: unknown): unknown {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(cleanDehydrated);\n\n const record = obj as Record<string, unknown>;\n\n // Dehydrated value markers from React DevTools\n if ('type' in record && 'preview_short' in record) {\n return record['preview_short'];\n }\n\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n cleaned[key] = cleanDehydrated(value);\n }\n return cleaned;\n}\n\nfunction parseHooks(hooks: unknown[]): { name: string; value: unknown; subHooks?: { name: string; value: unknown }[] }[] {\n return hooks.map((hook) => {\n const h = hook as {\n id: number | null;\n isStateEditable: boolean;\n name: string;\n value: unknown;\n subHooks?: unknown[];\n };\n const result: { name: string; value: unknown; subHooks?: { name: string; value: unknown }[] } = {\n name: h.name,\n value: cleanDehydrated(h.value),\n };\n if (h.subHooks && h.subHooks.length > 0) {\n result.subHooks = parseHooks(h.subHooks) as { name: string; value: unknown }[];\n }\n return result;\n });\n}\n","import type { ComponentNode, ComponentType } from './types.js';\n\n/**\n * React DevTools operations encoding (protocol v2):\n * Operations is a flat array of numbers representing tree mutations.\n *\n * Format: [rendererID, rootFiberID, stringTableSize, ...stringTable, ...ops]\n *\n * The string table encodes display names and keys. Each entry is:\n * [length, ...charCodes]\n * String ID 0 = null. String ID 1 = first entry, etc.\n *\n * Operation types (from React DevTools source):\n */\nconst TREE_OPERATION_ADD = 1;\nconst TREE_OPERATION_REMOVE = 2;\nconst TREE_OPERATION_REORDER_CHILDREN = 3;\nconst TREE_OPERATION_UPDATE_TREE_BASE_DURATION = 4;\nconst TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS = 5;\nconst TREE_OPERATION_REMOVE_ROOT = 6;\nconst TREE_OPERATION_SET_SUBTREE_MODE = 7;\n\n/**\n * Suspense tree operations (newer React DevTools backends, e.g. browser extension):\n */\nconst SUSPENSE_TREE_OPERATION_ADD = 8;\nconst SUSPENSE_TREE_OPERATION_REMOVE = 9;\nconst SUSPENSE_TREE_OPERATION_REORDER_CHILDREN = 10;\nconst SUSPENSE_TREE_OPERATION_RESIZE = 11;\nconst SUSPENSE_TREE_OPERATION_SUSPENDERS = 12;\nconst TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE = 13;\n\n/**\n * Element types from React DevTools (react-devtools-shared/src/frontend/types.js)\n */\nconst ELEMENT_TYPE_CLASS = 1;\n// const ELEMENT_TYPE_CONTEXT = 2;\nconst ELEMENT_TYPE_FUNCTION = 5;\nconst ELEMENT_TYPE_FORWARD_REF = 6;\nconst ELEMENT_TYPE_HOST = 7;\nconst ELEMENT_TYPE_MEMO = 8;\n// const ELEMENT_TYPE_OTHER = 9;\nconst ELEMENT_TYPE_PROFILER = 10;\nconst ELEMENT_TYPE_ROOT = 11;\nconst ELEMENT_TYPE_SUSPENSE = 12;\n\nfunction toComponentType(elementType: number): ComponentType {\n switch (elementType) {\n case ELEMENT_TYPE_CLASS:\n return 'class';\n case ELEMENT_TYPE_FUNCTION:\n return 'function';\n case ELEMENT_TYPE_FORWARD_REF:\n return 'forwardRef';\n case ELEMENT_TYPE_HOST:\n return 'host';\n case ELEMENT_TYPE_MEMO:\n return 'memo';\n case ELEMENT_TYPE_PROFILER:\n return 'profiler';\n case ELEMENT_TYPE_SUSPENSE:\n return 'suspense';\n case ELEMENT_TYPE_ROOT:\n return 'other'; // roots are internal, map to 'other'\n default:\n return 'other';\n }\n}\n\n/**\n * Skip a variable-length rect encoding in the operations array.\n * Rects are encoded as: count, then count * 4 values (x, y, w, h each × 1000).\n * A count of -1 means null (no rects).\n * Returns the new index after skipping.\n */\nfunction skipRects(operations: number[], i: number): number {\n const count = operations[i++];\n if (count === -1) return i;\n return i + count * 4;\n}\n\nexport interface TreeNode {\n id: number;\n label: string;\n displayName: string;\n type: ComponentType;\n key: string | null;\n parentId: number | null;\n children: number[];\n depth: number;\n}\n\nexport class ComponentTree {\n private nodes = new Map<number, ComponentNode>();\n private roots: number[] = [];\n /** Index: lowercase display name → set of node ids */\n private nameIndex = new Map<string, Set<number>>();\n /** Label → real node ID (e.g., \"@c1\" → 10) */\n private labelToId = new Map<string, number>();\n /** Real node ID → label */\n private idToLabel = new Map<number, string>();\n /**\n * Whether the backend uses the extended ADD format (8 fields with namePropStringID).\n * Auto-detected from the presence of SUSPENSE_TREE_OPERATION opcodes.\n */\n private extendedAddFormat = false;\n\n applyOperations(operations: number[]): Array<{ id: number; displayName: string }> {\n if (operations.length < 2) return [];\n\n const added: Array<{ id: number; displayName: string }> = [];\n const rendererId = operations[0];\n // operations[1] is the root fiber ID\n let i = 2;\n\n // Parse the string table (protocol v2)\n const stringTable: Array<string | null> = [null]; // ID 0 = null\n const stringTableSize = operations[i++];\n const stringTableEnd = i + stringTableSize;\n while (i < stringTableEnd) {\n const strLen = operations[i++];\n let str = '';\n for (let j = 0; j < strLen; j++) {\n str += String.fromCodePoint(operations[i++]);\n }\n stringTable.push(str);\n }\n\n // Parse operations\n while (i < operations.length) {\n const op = operations[i];\n\n switch (op) {\n case TREE_OPERATION_ADD: {\n const id = operations[i + 1];\n const elementType = operations[i + 2];\n i += 3;\n\n if (elementType === ELEMENT_TYPE_ROOT) {\n // Root node: isStrictModeCompliant, supportsProfiling,\n // supportsStrictMode, hasOwnerMetadata\n i += 4;\n\n const node: ComponentNode = {\n id,\n displayName: 'Root',\n type: 'other',\n key: null,\n parentId: null,\n children: [],\n rendererId,\n };\n this.nodes.set(id, node);\n added.push({ id, displayName: node.displayName });\n if (!this.roots.includes(id)) {\n this.roots.push(id);\n }\n } else {\n const parentId = operations[i++];\n i++; // ownerID\n const displayNameStringId = operations[i++];\n const keyStringId = operations[i++];\n if (this.extendedAddFormat) {\n i++; // namePropStringID (added in newer backends)\n }\n\n const displayName =\n (displayNameStringId > 0 ? stringTable[displayNameStringId] : null) ||\n (elementType === ELEMENT_TYPE_HOST ? 'HostComponent' : 'Anonymous');\n const key = keyStringId > 0 ? stringTable[keyStringId] || null : null;\n\n const node: ComponentNode = {\n id,\n displayName,\n type: toComponentType(elementType),\n key,\n parentId: parentId === 0 ? null : parentId,\n children: [],\n rendererId,\n };\n\n this.nodes.set(id, node);\n added.push({ id, displayName });\n\n // Add to parent's children\n if (parentId === 0) {\n if (!this.roots.includes(id)) {\n this.roots.push(id);\n }\n } else {\n const parent = this.nodes.get(parentId);\n if (parent) {\n parent.children.push(id);\n }\n }\n\n // Update name index\n if (displayName) {\n const lower = displayName.toLowerCase();\n let set = this.nameIndex.get(lower);\n if (!set) {\n set = new Set();\n this.nameIndex.set(lower, set);\n }\n set.add(id);\n }\n }\n break;\n }\n\n case TREE_OPERATION_REMOVE: {\n const numRemoved = operations[i + 1];\n for (let j = 0; j < numRemoved; j++) {\n const id = operations[i + 2 + j];\n this.removeNode(id);\n }\n i += 2 + numRemoved;\n break;\n }\n\n case TREE_OPERATION_REORDER_CHILDREN: {\n const id = operations[i + 1];\n const numChildren = operations[i + 2];\n const newChildren: number[] = [];\n for (let j = 0; j < numChildren; j++) {\n newChildren.push(operations[i + 3 + j]);\n }\n const node = this.nodes.get(id);\n if (node) {\n node.children = newChildren;\n }\n i += 3 + numChildren;\n break;\n }\n\n case TREE_OPERATION_UPDATE_TREE_BASE_DURATION: {\n // id, baseDuration — skip\n i += 3;\n break;\n }\n\n case TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS: {\n // id, numErrors, numWarnings\n i += 4;\n break;\n }\n\n case TREE_OPERATION_REMOVE_ROOT: {\n const rootId = operations[i + 1];\n this.removeNode(rootId);\n i += 2;\n break;\n }\n\n case TREE_OPERATION_SET_SUBTREE_MODE: {\n // id, mode\n i += 3;\n break;\n }\n\n // ── Suspense tree operations (newer backends) ──\n\n case SUSPENSE_TREE_OPERATION_ADD: {\n // Presence of suspense ops means the backend also uses 8-field ADD\n this.extendedAddFormat = true;\n // fiberID, parentID, nameStringID, isSuspended, rects\n i += 5; // opcode + 4 fields\n i = skipRects(operations, i);\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_REMOVE: {\n this.extendedAddFormat = true;\n // numIDs, then that many IDs\n const numIds = operations[i + 1];\n i += 2 + numIds;\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_REORDER_CHILDREN: {\n this.extendedAddFormat = true;\n // parentID, numChildren, then that many child IDs\n const numSuspenseChildren = operations[i + 2];\n i += 3 + numSuspenseChildren;\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_RESIZE: {\n this.extendedAddFormat = true;\n // fiberID, rects\n i += 2; // opcode + fiberID\n i = skipRects(operations, i);\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_SUSPENDERS: {\n this.extendedAddFormat = true;\n // numChanges, then numChanges * 4 values\n const numChanges = operations[i + 1];\n i += 2 + numChanges * 4;\n break;\n }\n\n case TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE: {\n this.extendedAddFormat = true;\n // id\n i += 2;\n break;\n }\n\n default:\n // Unknown operation — skip one value and try to continue.\n // Future protocol additions may cause brief misalignment but\n // subsequent operations batches will self-correct.\n i++;\n break;\n }\n }\n\n return added;\n }\n\n private removeNode(id: number): void {\n const node = this.nodes.get(id);\n if (!node) return;\n\n // Remove from parent's children\n if (node.parentId !== null) {\n const parent = this.nodes.get(node.parentId);\n if (parent) {\n parent.children = parent.children.filter((c) => c !== id);\n }\n }\n\n // Remove from roots\n this.roots = this.roots.filter((r) => r !== id);\n\n // Remove from name index\n if (node.displayName) {\n const lower = node.displayName.toLowerCase();\n const set = this.nameIndex.get(lower);\n if (set) {\n set.delete(id);\n if (set.size === 0) this.nameIndex.delete(lower);\n }\n }\n\n // Recursively remove children\n for (const childId of node.children) {\n this.removeNode(childId);\n }\n\n this.nodes.delete(id);\n }\n\n getNode(id: number): ComponentNode | undefined {\n return this.nodes.get(id);\n }\n\n getTree(maxDepth?: number): TreeNode[] {\n const result: TreeNode[] = [];\n\n // Rebuild label maps on every getTree() call\n this.labelToId.clear();\n this.idToLabel.clear();\n let labelCounter = 1;\n\n const walk = (id: number, depth: number) => {\n const node = this.nodes.get(id);\n if (!node) return;\n if (maxDepth !== undefined && depth > maxDepth) return;\n\n const label = `@c${labelCounter++}`;\n this.labelToId.set(label, node.id);\n this.idToLabel.set(node.id, label);\n\n result.push({\n id: node.id,\n label,\n displayName: node.displayName,\n type: node.type,\n key: node.key,\n parentId: node.parentId,\n children: node.children,\n depth,\n });\n\n for (const childId of node.children) {\n walk(childId, depth + 1);\n }\n };\n\n for (const rootId of this.roots) {\n walk(rootId, 0);\n }\n return result;\n }\n\n findByName(name: string, exact?: boolean): TreeNode[] {\n const results: TreeNode[] = [];\n\n if (exact) {\n const lower = name.toLowerCase();\n const ids = this.nameIndex.get(lower);\n if (ids) {\n for (const id of ids) {\n const node = this.nodes.get(id);\n if (node && node.displayName.toLowerCase() === lower) {\n results.push(this.toTreeNode(node));\n }\n }\n }\n } else {\n const lower = name.toLowerCase();\n for (const [indexName, ids] of this.nameIndex) {\n if (indexName.includes(lower)) {\n for (const id of ids) {\n const node = this.nodes.get(id);\n if (node) {\n results.push(this.toTreeNode(node));\n }\n }\n }\n }\n }\n\n return results;\n }\n\n getComponentCount(): number {\n return this.nodes.size;\n }\n\n getCountByType(): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const node of this.nodes.values()) {\n counts[node.type] = (counts[node.type] || 0) + 1;\n }\n return counts;\n }\n\n getAllNodeIds(): number[] {\n return Array.from(this.nodes.keys());\n }\n\n getRootIds(): number[] {\n return [...this.roots];\n }\n\n removeRoot(rootId: number): void {\n this.removeNode(rootId);\n }\n\n /**\n * Look up the @cN label for a given component ID.\n * Returns undefined if the ID has no label assigned.\n */\n getLabel(id: number): string | undefined {\n return this.idToLabel.get(id);\n }\n\n /**\n * Resolve a label like \"@c3\" to a real node ID.\n * Returns undefined if label not found.\n */\n resolveLabel(label: string): number | undefined {\n return this.labelToId.get(label);\n }\n\n /**\n * Resolve either a label string (\"@c3\") or a numeric ID to a real node ID.\n */\n resolveId(id: number | string): number | undefined {\n if (typeof id === 'number') return id;\n if (id.startsWith('@c')) return this.labelToId.get(id);\n // Try parsing as number\n const num = parseInt(id, 10);\n return isNaN(num) ? undefined : num;\n }\n\n private toTreeNode(node: ComponentNode): TreeNode {\n // Calculate depth by walking up the tree\n let depth = 0;\n let current = node;\n while (current.parentId !== null) {\n depth++;\n const parent = this.nodes.get(current.parentId);\n if (!parent) break;\n current = parent;\n }\n\n return {\n id: node.id,\n label: this.idToLabel.get(node.id) || `@c?`,\n displayName: node.displayName,\n type: node.type,\n key: node.key,\n parentId: node.parentId,\n children: node.children,\n depth,\n };\n }\n}\n","import type {\n ProfilingSession,\n ProfilingCommit,\n ChangeDescription,\n ComponentRenderReport,\n RenderCause,\n ChangedKeys,\n} from './types.js';\nimport type { ComponentTree } from './component-tree.js';\n\nexport interface ProfileSummary {\n name: string;\n duration: number;\n commitCount: number;\n componentRenderCounts: { id: number; displayName: string; label?: string; type?: string; count: number }[];\n}\n\nexport interface TimelineEntry {\n index: number;\n timestamp: number;\n duration: number;\n componentCount: number;\n}\n\nexport interface CommitDetail {\n index: number;\n timestamp: number;\n duration: number;\n components: Array<{\n id: number;\n displayName: string;\n label?: string;\n type?: string;\n actualDuration: number;\n selfDuration: number;\n causes: RenderCause[];\n changedKeys?: ChangedKeys;\n }>;\n totalComponents: number;\n}\n\nexport class Profiler {\n private session: ProfilingSession | null = null;\n /** Display names captured during profiling (survives unmounts) */\n private displayNames = new Map<number, string>();\n\n isActive(): boolean {\n return this.session !== null && this.session.stoppedAt === null;\n }\n\n start(name?: string): void {\n this.displayNames.clear();\n this.session = {\n name: name || `session-${Date.now()}`,\n startedAt: Date.now(),\n stoppedAt: null,\n commits: [],\n };\n }\n\n /** Cache a component's display name (call during profiling to survive unmounts) */\n trackComponent(id: number, displayName: string): void {\n this.displayNames.set(id, displayName);\n }\n\n stop(tree?: ComponentTree): ProfileSummary | null {\n if (!this.session) return null;\n this.session.stoppedAt = Date.now();\n\n const duration = this.session.stoppedAt - this.session.startedAt;\n\n // Count renders per component\n const renderCounts = new Map<number, number>();\n for (const commit of this.session.commits) {\n for (const [id] of commit.fiberActualDurations) {\n renderCounts.set(id, (renderCounts.get(id) || 0) + 1);\n }\n }\n\n const componentRenderCounts = Array.from(renderCounts.entries())\n .map(([id, count]) => ({\n id,\n displayName: tree?.getNode(id)?.displayName || this.displayNames.get(id) || '',\n count,\n }))\n .sort((a, b) => b.count - a.count);\n\n return {\n name: this.session.name,\n duration,\n commitCount: this.session.commits.length,\n componentRenderCounts,\n };\n }\n\n /**\n * Process profiling data sent from React DevTools.\n *\n * The data format varies between React versions. We handle the common\n * format where each commit contains:\n * - commitTime\n * - duration\n * - fiberActualDurations: [id, duration, ...]\n * - fiberSelfDurations: [id, duration, ...]\n * - changeDescriptions: Map<id, description>\n */\n processProfilingData(payload: unknown): void {\n if (!this.session || this.session.stoppedAt !== null) return;\n\n const data = payload as {\n dataForRoots?: Array<{\n commitData?: Array<{\n changeDescriptions?: Array<[number, unknown]> | Map<number, unknown>;\n duration?: number;\n fiberActualDurations?: Array<[number, number]> | number[];\n fiberSelfDurations?: Array<[number, number]> | number[];\n timestamp?: number;\n }>;\n operations?: unknown[];\n }>;\n // Alternative flat format\n commitData?: Array<{\n changeDescriptions?: Array<[number, unknown]> | Map<number, unknown>;\n duration?: number;\n fiberActualDurations?: Array<[number, number]> | number[];\n fiberSelfDurations?: Array<[number, number]> | number[];\n timestamp?: number;\n }>;\n };\n\n // Handle nested format (dataForRoots)\n const roots = data?.dataForRoots;\n if (roots) {\n for (const root of roots) {\n if (root.commitData) {\n for (const commitData of root.commitData) {\n this.processCommitData(commitData);\n }\n }\n }\n return;\n }\n\n // Handle flat format\n if (data?.commitData) {\n for (const commitData of data.commitData) {\n this.processCommitData(commitData);\n }\n }\n }\n\n private processCommitData(commitData: {\n changeDescriptions?: Array<[number, unknown]> | Map<number, unknown>;\n duration?: number;\n fiberActualDurations?: Array<[number, number]> | number[];\n fiberSelfDurations?: Array<[number, number]> | number[];\n timestamp?: number;\n }): void {\n const commit: ProfilingCommit = {\n timestamp: commitData.timestamp || Date.now(),\n duration: commitData.duration || 0,\n fiberActualDurations: new Map(),\n fiberSelfDurations: new Map(),\n changeDescriptions: new Map(),\n };\n\n // Parse fiber durations (can be [id, duration, id, duration, ...] or [[id, duration], ...])\n if (commitData.fiberActualDurations) {\n parseDurations(commitData.fiberActualDurations, commit.fiberActualDurations);\n }\n if (commitData.fiberSelfDurations) {\n parseDurations(commitData.fiberSelfDurations, commit.fiberSelfDurations);\n }\n\n // Parse change descriptions\n if (commitData.changeDescriptions) {\n const entries =\n commitData.changeDescriptions instanceof Map\n ? commitData.changeDescriptions.entries()\n : commitData.changeDescriptions[Symbol.iterator]();\n for (const [id, desc] of entries) {\n const d = desc as {\n didHooksChange?: boolean;\n isFirstMount?: boolean;\n props?: string[] | null;\n state?: string[] | null;\n hooks?: number[] | null;\n };\n commit.changeDescriptions.set(id as number, {\n didHooksChange: d.didHooksChange || false,\n isFirstMount: d.isFirstMount || false,\n props: d.props || null,\n state: d.state || null,\n hooks: d.hooks || null,\n });\n }\n }\n\n this.session!.commits.push(commit);\n }\n\n getReport(\n componentId: number,\n tree: ComponentTree,\n ): ComponentRenderReport | null {\n if (!this.session) return null;\n\n const node = tree.getNode(componentId);\n let renderCount = 0;\n let totalDuration = 0;\n let maxDuration = 0;\n const causeSet = new Set<RenderCause>();\n const propsSet = new Set<string>();\n const stateSet = new Set<string>();\n const hooksSet = new Set<number>();\n\n for (const commit of this.session.commits) {\n const duration = commit.fiberActualDurations.get(componentId);\n if (duration !== undefined) {\n renderCount++;\n totalDuration += duration;\n if (duration > maxDuration) maxDuration = duration;\n\n const desc = commit.changeDescriptions.get(componentId);\n if (desc) {\n for (const cause of describeCauses(desc)) {\n causeSet.add(cause);\n }\n const keys = extractChangedKeys(desc);\n for (const p of keys.props) propsSet.add(p);\n for (const s of keys.state) stateSet.add(s);\n for (const h of keys.hooks) hooksSet.add(h);\n }\n }\n }\n\n if (renderCount === 0) return null;\n\n return {\n id: componentId,\n displayName: node?.displayName || this.displayNames.get(componentId) || `Component#${componentId}`,\n renderCount,\n totalDuration,\n avgDuration: totalDuration / renderCount,\n maxDuration,\n causes: Array.from(causeSet),\n changedKeys: {\n props: Array.from(propsSet),\n state: Array.from(stateSet),\n hooks: Array.from(hooksSet),\n },\n };\n }\n\n getSlowest(\n tree: ComponentTree,\n limit = 10,\n ): ComponentRenderReport[] {\n return this.getAllReports(tree)\n .sort((a, b) => b.avgDuration - a.avgDuration)\n .slice(0, limit);\n }\n\n getMostRerenders(\n tree: ComponentTree,\n limit = 10,\n ): ComponentRenderReport[] {\n return this.getAllReports(tree)\n .sort((a, b) => b.renderCount - a.renderCount)\n .slice(0, limit);\n }\n\n getCommitDetails(index: number, tree: ComponentTree, limit = 10): CommitDetail | null {\n if (!this.session) return null;\n if (index < 0 || index >= this.session.commits.length) return null;\n\n const commit = this.session.commits[index];\n const components: CommitDetail['components'] = [];\n\n for (const [id, actualDuration] of commit.fiberActualDurations) {\n const selfDuration = commit.fiberSelfDurations.get(id) || 0;\n const desc = commit.changeDescriptions.get(id);\n components.push({\n id,\n displayName: tree.getNode(id)?.displayName || this.displayNames.get(id) || `Component#${id}`,\n actualDuration,\n selfDuration,\n causes: desc ? describeCauses(desc) : [],\n changedKeys: desc ? extractChangedKeys(desc) : { props: [], state: [], hooks: [] },\n });\n }\n\n components.sort((a, b) => b.selfDuration - a.selfDuration);\n\n const totalCount = components.length;\n\n return {\n index,\n timestamp: commit.timestamp,\n duration: commit.duration,\n components: limit > 0 ? components.slice(0, limit) : components,\n totalComponents: totalCount,\n };\n }\n\n getTimeline(limit?: number): TimelineEntry[] {\n if (!this.session) return [];\n\n const entries = this.session.commits.map((commit, index) => ({\n index,\n timestamp: commit.timestamp,\n duration: commit.duration,\n componentCount: commit.fiberActualDurations.size,\n }));\n\n if (limit) return entries.slice(0, limit);\n return entries;\n }\n\n private getAllReports(tree: ComponentTree): ComponentRenderReport[] {\n if (!this.session) return [];\n\n // Collect all component IDs that appear in profiling data\n const componentIds = new Set<number>();\n for (const commit of this.session.commits) {\n for (const id of commit.fiberActualDurations.keys()) {\n componentIds.add(id);\n }\n }\n\n const reports: ComponentRenderReport[] = [];\n for (const id of componentIds) {\n const report = this.getReport(id, tree);\n if (report) reports.push(report);\n }\n return reports;\n }\n}\n\nfunction parseDurations(\n raw: Array<[number, number]> | number[],\n target: Map<number, number>,\n): void {\n if (raw.length === 0) return;\n\n // Check if it's array of tuples or flat array\n if (Array.isArray(raw[0])) {\n // [[id, duration], ...]\n for (const [id, duration] of raw as Array<[number, number]>) {\n target.set(id, duration);\n }\n } else {\n // [id, duration, id, duration, ...]\n const flat = raw as number[];\n for (let i = 0; i < flat.length; i += 2) {\n target.set(flat[i], flat[i + 1]);\n }\n }\n}\n\nfunction describeCauses(desc: ChangeDescription): RenderCause[] {\n const causes: RenderCause[] = [];\n if (desc.isFirstMount) {\n causes.push('first-mount');\n return causes;\n }\n if (desc.props && desc.props.length > 0) causes.push('props-changed');\n if (desc.state && desc.state.length > 0) causes.push('state-changed');\n if (desc.didHooksChange) causes.push('hooks-changed');\n // If no specific cause found, it was likely parent-triggered\n if (causes.length === 0) causes.push('parent-rendered');\n return causes;\n}\n\nfunction extractChangedKeys(desc: ChangeDescription): ChangedKeys {\n return {\n props: desc.props ?? [],\n state: desc.state ?? [],\n hooks: desc.hooks ?? [],\n };\n}\n"],"mappings":"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","names":["port","pending","port"]}
|
|
1
|
+
{"version":3,"sources":["../src/daemon.ts","../src/devtools-bridge.ts","../src/component-tree.ts","../src/profile-export.ts","../src/profiler.ts"],"sourcesContent":["import net from 'node:net';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { DevToolsBridge } from './devtools-bridge.js';\nimport { ComponentTree } from './component-tree.js';\nimport { Profiler } from './profiler.js';\nimport type { IpcCommand, IpcResponse, DaemonInfo, StatusInfo } 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 STATE_DIR = DEFAULT_STATE_DIR;\n\nfunction getSocketPath(): string {\n return path.join(STATE_DIR, 'daemon.sock');\n}\n\nfunction getDaemonInfoPath(): string {\n return path.join(STATE_DIR, 'daemon.json');\n}\n\n/**\n * Enrich profiling result items with label + type from the component tree.\n */\nfunction enrichWithLabels(\n items: Array<{ id: number; label?: string; type?: string }>,\n tree: ComponentTree,\n): void {\n for (const item of items) {\n if (!item.label) item.label = tree.getLabel(item.id);\n if (!item.type) {\n const node = tree.getNode(item.id);\n if (node) item.type = node.type;\n }\n }\n}\n\nclass Daemon {\n private ipcServer: net.Server | null = null;\n private bridge: DevToolsBridge;\n private tree: ComponentTree;\n private profiler: Profiler;\n private port: number;\n private startedAt = Date.now();\n\n constructor(port: number) {\n this.port = port;\n this.tree = new ComponentTree();\n this.profiler = new Profiler();\n this.bridge = new DevToolsBridge(port, this.tree, this.profiler);\n }\n\n async start(): Promise<void> {\n // Ensure state directory exists\n fs.mkdirSync(STATE_DIR, { recursive: true });\n\n // Clean up stale socket\n const socketPath = getSocketPath();\n if (fs.existsSync(socketPath)) {\n try {\n fs.unlinkSync(socketPath);\n } catch {\n // ignore\n }\n }\n\n // Start WebSocket bridge\n await this.bridge.start();\n\n // Start IPC server\n await this.startIpc(socketPath);\n\n // Write daemon info\n let buildMtime: number | undefined;\n try {\n buildMtime = fs.statSync(new URL(import.meta.url).pathname).mtimeMs;\n } catch {\n // ignore\n }\n const info: DaemonInfo = {\n pid: process.pid,\n port: this.port,\n socketPath,\n startedAt: this.startedAt,\n buildMtime,\n };\n fs.writeFileSync(getDaemonInfoPath(), JSON.stringify(info, null, 2));\n\n console.log(`Daemon started (pid=${process.pid}, port=${this.port})`);\n\n // Handle shutdown\n const shutdown = () => {\n this.stop();\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n }\n\n private startIpc(socketPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.ipcServer = net.createServer((conn) => {\n let buffer = '';\n\n conn.on('data', (chunk) => {\n buffer += chunk.toString();\n\n // Process complete messages (newline-delimited JSON)\n let newlineIdx: number;\n while ((newlineIdx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n\n try {\n const cmd: IpcCommand = JSON.parse(line);\n this.handleCommand(cmd, conn).then((response) => {\n if (!conn.destroyed) {\n conn.write(JSON.stringify(response) + '\\n');\n }\n });\n } catch {\n const response: IpcResponse = {\n ok: false,\n error: 'Invalid JSON',\n };\n conn.write(JSON.stringify(response) + '\\n');\n }\n }\n });\n });\n\n this.ipcServer.on('error', reject);\n\n this.ipcServer.listen(socketPath, () => {\n resolve();\n });\n });\n }\n\n private async handleCommand(cmd: IpcCommand, conn: net.Socket): Promise<IpcResponse> {\n try {\n switch (cmd.type) {\n case 'ping':\n return { ok: true, data: 'pong' };\n\n case 'status':\n return {\n ok: true,\n data: {\n daemonRunning: true,\n port: this.port,\n connectedApps: this.bridge.getConnectedAppCount(),\n componentCount: this.tree.getComponentCount(),\n profilingActive: this.profiler.isActive(),\n uptime: Date.now() - this.startedAt,\n connection: this.bridge.getConnectionHealth(),\n } satisfies StatusInfo,\n };\n\n case 'get-tree': {\n const treeData = this.tree.getTree(cmd.depth);\n const response: IpcResponse = { ok: true, data: treeData };\n if (treeData.length === 0) {\n const health = this.bridge.getConnectionHealth();\n if (health.hasEverConnected && health.connectedApps === 0 && health.lastDisconnectAt !== null) {\n const ago = Math.round((Date.now() - health.lastDisconnectAt) / 1000);\n response.hint = `app disconnected ${ago}s ago, waiting for reconnect...`;\n }\n }\n return response;\n }\n\n case 'get-component': {\n const resolvedId = this.tree.resolveId(cmd.id);\n if (resolvedId === undefined) {\n return { ok: false, error: `Component ${cmd.id} not found` };\n }\n const element = await this.bridge.inspectElement(resolvedId);\n if (!element) {\n return { ok: false, error: `Component ${cmd.id} not found` };\n }\n // Include the label if the request used one\n const label = typeof cmd.id === 'string' ? cmd.id : undefined;\n return { ok: true, data: element, label };\n }\n\n case 'find':\n return {\n ok: true,\n data: this.tree.findByName(cmd.name, cmd.exact),\n };\n\n case 'count':\n return {\n ok: true,\n data: this.tree.getCountByType(),\n };\n\n case 'profile-start':\n this.profiler.start(cmd.name);\n // Snapshot existing component names so they survive unmounts\n for (const id of this.tree.getAllNodeIds()) {\n const node = this.tree.getNode(id);\n if (node) this.profiler.trackComponent(id, node.displayName);\n }\n this.bridge.startProfiling();\n return { ok: true, data: 'Profiling started' };\n\n case 'profile-stop': {\n await this.bridge.stopProfilingAndCollect();\n const session = this.profiler.stop(this.tree);\n if (!session) {\n return { ok: false, error: 'No active profiling session' };\n }\n enrichWithLabels(session.componentRenderCounts, this.tree);\n return { ok: true, data: session };\n }\n\n case 'profile-report': {\n const resolvedCompId = this.tree.resolveId(cmd.componentId);\n if (resolvedCompId === undefined) {\n return { ok: false, error: `Component ${cmd.componentId} not found` };\n }\n const report = this.profiler.getReport(resolvedCompId, this.tree);\n if (!report) {\n return {\n ok: false,\n error: `No profiling data for component ${cmd.componentId}`,\n };\n }\n enrichWithLabels([report], this.tree);\n const compLabel = typeof cmd.componentId === 'string' ? cmd.componentId : undefined;\n return { ok: true, data: report, label: compLabel };\n }\n\n case 'profile-slow': {\n const slowest = this.profiler.getSlowest(this.tree, cmd.limit);\n enrichWithLabels(slowest, this.tree);\n return { ok: true, data: slowest };\n }\n\n case 'profile-rerenders': {\n const rerenders = this.profiler.getMostRerenders(this.tree, cmd.limit);\n enrichWithLabels(rerenders, this.tree);\n return { ok: true, data: rerenders };\n }\n\n case 'profile-timeline':\n return {\n ok: true,\n data: this.profiler.getTimeline(cmd.limit),\n };\n\n case 'profile-commit': {\n const detail = this.profiler.getCommitDetails(cmd.index, this.tree, cmd.limit);\n if (!detail) {\n return { ok: false, error: `Commit #${cmd.index} not found` };\n }\n enrichWithLabels(detail.components, this.tree);\n return { ok: true, data: detail };\n }\n\n case 'profile-export': {\n const exportData = this.profiler.getExportData(this.tree);\n if (!exportData) {\n return { ok: false, error: 'No profiling data to export (run profile start/stop first)' };\n }\n return { ok: true, data: exportData };\n }\n\n case 'wait':\n return this.handleWait(cmd, conn);\n\n default:\n return { ok: false, error: `Unknown command: ${(cmd as any).type}` };\n }\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n private handleWait(\n cmd: Extract<IpcCommand, { type: 'wait' }>,\n conn: net.Socket,\n ): Promise<IpcResponse> {\n const timeout = cmd.timeout ?? 30_000;\n\n // Check if condition is already met\n if (this.isWaitConditionMet(cmd)) {\n return Promise.resolve({ ok: true, data: { met: true, condition: cmd.condition } });\n }\n\n return new Promise((resolve) => {\n let settled = false;\n const settle = (response: IpcResponse) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n unsubscribe();\n conn.removeListener('close', onClose);\n resolve(response);\n };\n\n const unsubscribe = this.bridge.onStateChange(() => {\n if (this.isWaitConditionMet(cmd)) {\n settle({ ok: true, data: { met: true, condition: cmd.condition } });\n }\n });\n\n const timer = setTimeout(() => {\n settle({ ok: true, data: { met: false, condition: cmd.condition, timeout: true } });\n }, timeout);\n\n const onClose = () => {\n settle({ ok: false, error: 'Client disconnected' });\n };\n conn.on('close', onClose);\n });\n }\n\n private isWaitConditionMet(cmd: Extract<IpcCommand, { type: 'wait' }>): boolean {\n switch (cmd.condition) {\n case 'connected':\n return this.bridge.getConnectedAppCount() > 0;\n case 'component':\n return this.tree.findByName(cmd.name, true).length > 0;\n default:\n return false;\n }\n }\n\n stop(): void {\n this.bridge.stop();\n if (this.ipcServer) {\n this.ipcServer.close();\n this.ipcServer = null;\n }\n // Clean up files\n try {\n fs.unlinkSync(getSocketPath());\n } catch {\n // ignore\n }\n try {\n fs.unlinkSync(getDaemonInfoPath());\n } catch {\n // ignore\n }\n console.log('Daemon stopped');\n }\n}\n\n// ── Main ──\n\nconst portArg = process.argv.find((a) => a.startsWith('--port='));\nconst port = portArg ? parseInt(portArg.split('=')[1], 10) : 8097;\n\nconst stateDirArg = process.argv.find((a) => a.startsWith('--state-dir='));\nif (stateDirArg) {\n STATE_DIR = stateDirArg.split('=')[1];\n}\n\nconst daemon = new Daemon(port);\ndaemon.start().catch((err) => {\n console.error('Failed to start daemon:', err);\n process.exit(1);\n});\n","import { WebSocketServer, WebSocket } from 'ws';\nimport type { ComponentTree } from './component-tree.js';\nimport type { Profiler } from './profiler.js';\nimport type { InspectedElement, ConnectionHealth, ConnectionEvent } from './types.js';\n\n/**\n * React DevTools protocol bridge.\n *\n * Implements the \"Wall\" messaging pattern that React DevTools uses:\n * - The backend (inside React app) sends operations, profiling data, etc.\n * - The frontend (us) can request element inspection, start/stop profiling, etc.\n *\n * Message format over WebSocket:\n * { event: string, payload: any }\n */\n\ninterface DevToolsMessage {\n event: string;\n payload: unknown;\n}\n\ninterface PendingInspection {\n resolve: (value: InspectedElement | null) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface PendingProfilingCollect {\n resolve: () => void;\n timer: ReturnType<typeof setTimeout>;\n remaining: number;\n}\n\nexport class DevToolsBridge {\n private wss: WebSocketServer | null = null;\n private connections = new Set<WebSocket>();\n private port: number;\n private tree: ComponentTree;\n private profiler: Profiler;\n private pendingInspections = new Map<number, PendingInspection>();\n private pendingProfilingCollect: PendingProfilingCollect | null = null;\n private rendererIds = new Set<number>();\n /** Track which root fiber IDs belong to each WebSocket connection */\n private connectionRoots = new Map<WebSocket, Set<number>>();\n private hasEverConnected = false;\n private lastDisconnectAt: number | null = null;\n private recentEvents: ConnectionEvent[] = [];\n private reconnectWindowMs = 5000;\n private stateChangeListeners = new Set<() => void>();\n\n constructor(port: number, tree: ComponentTree, profiler: Profiler) {\n this.port = port;\n this.tree = tree;\n this.profiler = profiler;\n }\n\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.wss = new WebSocketServer({ port: this.port }, () => {\n resolve();\n });\n\n this.wss.on('error', (err) => {\n reject(err);\n });\n\n this.wss.on('connection', (ws) => {\n this.connections.add(ws);\n\n // Reconnect = going from 0 to 1 connected app shortly after a disconnect\n const wasDisconnected = this.connections.size === 1 &&\n this.lastDisconnectAt !== null &&\n (Date.now() - this.lastDisconnectAt) < this.reconnectWindowMs;\n const eventType = wasDisconnected ? 'reconnected' as const : 'connected' as const;\n this.hasEverConnected = true;\n this.lastDisconnectAt = null;\n this.pushEvent({ type: eventType, timestamp: Date.now() });\n this.notifyStateChange();\n\n ws.on('message', (data) => {\n try {\n const msg: DevToolsMessage = JSON.parse(data.toString());\n this.handleMessage(ws, msg);\n } catch {\n // ignore parse errors\n }\n });\n\n ws.on('close', () => {\n this.cleanupConnection(ws);\n });\n\n ws.on('error', () => {\n this.cleanupConnection(ws);\n });\n });\n });\n }\n\n stop(): void {\n for (const conn of this.connections) {\n conn.close();\n }\n this.connections.clear();\n if (this.wss) {\n this.wss.close();\n this.wss = null;\n }\n }\n\n getConnectedAppCount(): number {\n return this.connections.size;\n }\n\n /**\n * Request detailed inspection of a specific element.\n * Sends a request to the React app and waits for the response.\n */\n inspectElement(id: number): Promise<InspectedElement | null> {\n const node = this.tree.getNode(id);\n if (!node) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n this.pendingInspections.delete(id);\n resolve(null);\n }, 5000);\n\n this.pendingInspections.set(id, { resolve, timer });\n\n this.sendToAll({\n event: 'inspectElement',\n payload: {\n id,\n rendererID: node.rendererId,\n forceFullData: true,\n requestID: id,\n path: null,\n },\n });\n });\n }\n\n startProfiling(): void {\n this.sendToAll({\n event: 'startProfiling',\n payload: { recordChangeDescriptions: true },\n });\n }\n\n /**\n * Stop profiling and request data from each renderer.\n * Returns a promise that resolves when profilingData arrives (or 5s timeout).\n */\n stopProfilingAndCollect(): Promise<void> {\n this.sendToAll({\n event: 'stopProfiling',\n payload: undefined,\n });\n\n // If no renderers known, resolve immediately\n if (this.rendererIds.size === 0) {\n return Promise.resolve();\n }\n\n // Request profiling data from each renderer\n for (const rendererID of this.rendererIds) {\n this.sendToAll({\n event: 'getProfilingData',\n payload: { rendererID },\n });\n }\n\n const expected = this.rendererIds.size;\n return new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n this.pendingProfilingCollect = null;\n resolve();\n }, 5000);\n\n this.pendingProfilingCollect = { resolve, timer, remaining: expected };\n });\n }\n\n private handleMessage(ws: WebSocket, msg: DevToolsMessage): void {\n switch (msg.event) {\n case 'backendInitialized':\n // Send the full frontend handshake sequence\n this.sendTo(ws, { event: 'getBridgeProtocol', payload: undefined });\n this.sendTo(ws, { event: 'getBackendVersion', payload: undefined });\n this.sendTo(ws, { event: 'getIfHasUnsupportedRendererVersion', payload: undefined });\n this.sendTo(ws, { event: 'getHookSettings', payload: undefined });\n this.sendTo(ws, { event: 'getProfilingStatus', payload: undefined });\n break;\n\n case 'bridgeProtocol':\n case 'backendVersion':\n case 'profilingStatus':\n case 'overrideComponentFilters':\n break;\n\n case 'operations':\n this.handleOperations(ws, msg.payload as number[]);\n break;\n\n case 'inspectedElement':\n this.handleInspectedElement(msg.payload);\n break;\n\n case 'profilingData':\n this.handleProfilingData(msg.payload);\n break;\n\n case 'renderer': {\n const payload = msg.payload as { id: number };\n this.rendererIds.add(payload.id);\n break;\n }\n\n case 'rendererAttached': {\n const payload = msg.payload as { id: number };\n this.rendererIds.add(payload.id);\n break;\n }\n\n case 'shutdown':\n ws.close();\n break;\n\n // Silently ignore known but unhandled events\n case 'hookSettings':\n case 'isBackendStorageAPISupported':\n case 'isReactNativeEnvironment':\n case 'isReloadAndProfileSupportedByBackend':\n case 'isSynchronousXHRSupported':\n case 'syncSelectionFromNativeElementsPanel':\n case 'unsupportedRendererVersion':\n break;\n\n default:\n break;\n }\n }\n\n private handleOperations(ws: WebSocket, operations: number[]): void {\n if (operations.length >= 2) {\n // Track renderer ID (first element of every operations array)\n this.rendererIds.add(operations[0]);\n\n // Track which root fiber IDs belong to this connection\n const rootFiberId = operations[1];\n let roots = this.connectionRoots.get(ws);\n if (!roots) {\n roots = new Set();\n this.connectionRoots.set(ws, roots);\n }\n roots.add(rootFiberId);\n }\n const added = this.tree.applyOperations(operations);\n\n // Cache display names during profiling so unmounted components are still identifiable\n if (this.profiler.isActive()) {\n for (const node of added) {\n this.profiler.trackComponent(node.id, node.displayName);\n }\n }\n\n this.notifyStateChange();\n }\n\n private cleanupConnection(ws: WebSocket): void {\n this.connections.delete(ws);\n // Remove all root trees that belonged to this connection\n const roots = this.connectionRoots.get(ws);\n if (roots) {\n for (const rootId of roots) {\n this.tree.removeRoot(rootId);\n }\n this.connectionRoots.delete(ws);\n }\n this.lastDisconnectAt = Date.now();\n this.pushEvent({ type: 'disconnected', timestamp: Date.now() });\n this.notifyStateChange();\n }\n\n private handleInspectedElement(payload: unknown): void {\n const data = payload as {\n type: string;\n id: number;\n value?: {\n id: number;\n displayName: string;\n type: number;\n key: string | null;\n props: Record<string, unknown>;\n state: Record<string, unknown> | null;\n hooks: unknown[] | null;\n };\n };\n\n if (data.type !== 'full-data' && data.type !== 'hydrated-path') {\n // No data available\n const pending = this.pendingInspections.get(data.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingInspections.delete(data.id);\n pending.resolve(null);\n }\n return;\n }\n\n const pending = this.pendingInspections.get(data.id);\n if (!pending || !data.value) return;\n\n clearTimeout(pending.timer);\n this.pendingInspections.delete(data.id);\n\n const node = this.tree.getNode(data.id);\n const inspected: InspectedElement = {\n id: data.id,\n displayName: data.value.displayName || node?.displayName || 'Unknown',\n type: node?.type || 'other',\n key: data.value.key,\n props: cleanDehydrated(data.value.props) as Record<string, unknown>,\n state: data.value.state\n ? (cleanDehydrated(data.value.state) as Record<string, unknown>)\n : null,\n hooks: data.value.hooks\n ? parseHooks(data.value.hooks)\n : null,\n renderedAt: null,\n };\n\n pending.resolve(inspected);\n }\n\n private handleProfilingData(payload: unknown): void {\n // React DevTools sends profiling data as a complex nested structure.\n // We forward it to the profiler for processing.\n this.profiler.processProfilingData(payload);\n\n // Resolve once all expected renderer responses have arrived\n if (this.pendingProfilingCollect) {\n this.pendingProfilingCollect.remaining--;\n if (this.pendingProfilingCollect.remaining <= 0) {\n clearTimeout(this.pendingProfilingCollect.timer);\n const pending = this.pendingProfilingCollect;\n this.pendingProfilingCollect = null;\n pending.resolve();\n }\n }\n }\n\n getConnectionHealth(): ConnectionHealth {\n return {\n connectedApps: this.connections.size,\n hasEverConnected: this.hasEverConnected,\n lastDisconnectAt: this.lastDisconnectAt,\n recentEvents: [...this.recentEvents],\n };\n }\n\n onStateChange(listener: () => void): () => void {\n this.stateChangeListeners.add(listener);\n return () => { this.stateChangeListeners.delete(listener); };\n }\n\n private pushEvent(event: ConnectionEvent): void {\n this.recentEvents.push(event);\n if (this.recentEvents.length > 20) {\n this.recentEvents = this.recentEvents.slice(-20);\n }\n }\n\n private notifyStateChange(): void {\n for (const listener of this.stateChangeListeners) {\n listener();\n }\n }\n\n private sendTo(ws: WebSocket, msg: DevToolsMessage): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n }\n\n private sendToAll(msg: DevToolsMessage): void {\n const raw = JSON.stringify(msg);\n for (const conn of this.connections) {\n if (conn.readyState === WebSocket.OPEN) {\n conn.send(raw);\n }\n }\n }\n}\n\n/**\n * React DevTools uses \"dehydrated\" values for complex objects.\n * These appear as objects with `type: 'string'` and other metadata.\n * We simplify them for display.\n */\nfunction cleanDehydrated(obj: unknown): unknown {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(cleanDehydrated);\n\n const record = obj as Record<string, unknown>;\n\n // Dehydrated value markers from React DevTools\n if ('type' in record && 'preview_short' in record) {\n return record['preview_short'];\n }\n\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n cleaned[key] = cleanDehydrated(value);\n }\n return cleaned;\n}\n\nfunction parseHooks(hooks: unknown[]): { name: string; value: unknown; subHooks?: { name: string; value: unknown }[] }[] {\n return hooks.map((hook) => {\n const h = hook as {\n id: number | null;\n isStateEditable: boolean;\n name: string;\n value: unknown;\n subHooks?: unknown[];\n };\n const result: { name: string; value: unknown; subHooks?: { name: string; value: unknown }[] } = {\n name: h.name,\n value: cleanDehydrated(h.value),\n };\n if (h.subHooks && h.subHooks.length > 0) {\n result.subHooks = parseHooks(h.subHooks) as { name: string; value: unknown }[];\n }\n return result;\n });\n}\n","import type { ComponentNode, ComponentType } from './types.js';\n\n/**\n * React DevTools operations encoding (protocol v2):\n * Operations is a flat array of numbers representing tree mutations.\n *\n * Format: [rendererID, rootFiberID, stringTableSize, ...stringTable, ...ops]\n *\n * The string table encodes display names and keys. Each entry is:\n * [length, ...charCodes]\n * String ID 0 = null. String ID 1 = first entry, etc.\n *\n * Operation types (from React DevTools source):\n */\nconst TREE_OPERATION_ADD = 1;\nconst TREE_OPERATION_REMOVE = 2;\nconst TREE_OPERATION_REORDER_CHILDREN = 3;\nconst TREE_OPERATION_UPDATE_TREE_BASE_DURATION = 4;\nconst TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS = 5;\nconst TREE_OPERATION_REMOVE_ROOT = 6;\nconst TREE_OPERATION_SET_SUBTREE_MODE = 7;\n\n/**\n * Suspense tree operations (newer React DevTools backends, e.g. browser extension):\n */\nconst SUSPENSE_TREE_OPERATION_ADD = 8;\nconst SUSPENSE_TREE_OPERATION_REMOVE = 9;\nconst SUSPENSE_TREE_OPERATION_REORDER_CHILDREN = 10;\nconst SUSPENSE_TREE_OPERATION_RESIZE = 11;\nconst SUSPENSE_TREE_OPERATION_SUSPENDERS = 12;\nconst TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE = 13;\n\n/**\n * Element types from React DevTools (react-devtools-shared/src/frontend/types.js)\n */\nconst ELEMENT_TYPE_CLASS = 1;\n// const ELEMENT_TYPE_CONTEXT = 2;\nconst ELEMENT_TYPE_FUNCTION = 5;\nconst ELEMENT_TYPE_FORWARD_REF = 6;\nconst ELEMENT_TYPE_HOST = 7;\nconst ELEMENT_TYPE_MEMO = 8;\n// const ELEMENT_TYPE_OTHER = 9;\nconst ELEMENT_TYPE_PROFILER = 10;\nconst ELEMENT_TYPE_ROOT = 11;\nconst ELEMENT_TYPE_SUSPENSE = 12;\n\nfunction toComponentType(elementType: number): ComponentType {\n switch (elementType) {\n case ELEMENT_TYPE_CLASS:\n return 'class';\n case ELEMENT_TYPE_FUNCTION:\n return 'function';\n case ELEMENT_TYPE_FORWARD_REF:\n return 'forwardRef';\n case ELEMENT_TYPE_HOST:\n return 'host';\n case ELEMENT_TYPE_MEMO:\n return 'memo';\n case ELEMENT_TYPE_PROFILER:\n return 'profiler';\n case ELEMENT_TYPE_SUSPENSE:\n return 'suspense';\n case ELEMENT_TYPE_ROOT:\n return 'other'; // roots are internal, map to 'other'\n default:\n return 'other';\n }\n}\n\n/**\n * Skip a variable-length rect encoding in the operations array.\n * Rects are encoded as: count, then count * 4 values (x, y, w, h each × 1000).\n * A count of -1 means null (no rects).\n * Returns the new index after skipping.\n */\nfunction skipRects(operations: number[], i: number): number {\n const count = operations[i++];\n if (count === -1) return i;\n return i + count * 4;\n}\n\nexport interface TreeNode {\n id: number;\n label: string;\n displayName: string;\n type: ComponentType;\n key: string | null;\n parentId: number | null;\n children: number[];\n depth: number;\n}\n\nexport class ComponentTree {\n private nodes = new Map<number, ComponentNode>();\n private roots: number[] = [];\n /** Index: lowercase display name → set of node ids */\n private nameIndex = new Map<string, Set<number>>();\n /** Label → real node ID (e.g., \"@c1\" → 10) */\n private labelToId = new Map<string, number>();\n /** Real node ID → label */\n private idToLabel = new Map<number, string>();\n /**\n * Whether the backend uses the extended ADD format (8 fields with namePropStringID).\n * Auto-detected from the presence of SUSPENSE_TREE_OPERATION opcodes.\n */\n private extendedAddFormat = false;\n\n applyOperations(operations: number[]): Array<{ id: number; displayName: string }> {\n if (operations.length < 2) return [];\n\n const added: Array<{ id: number; displayName: string }> = [];\n const rendererId = operations[0];\n // operations[1] is the root fiber ID\n let i = 2;\n\n // Parse the string table (protocol v2)\n const stringTable: Array<string | null> = [null]; // ID 0 = null\n const stringTableSize = operations[i++];\n const stringTableEnd = i + stringTableSize;\n while (i < stringTableEnd) {\n const strLen = operations[i++];\n let str = '';\n for (let j = 0; j < strLen; j++) {\n str += String.fromCodePoint(operations[i++]);\n }\n stringTable.push(str);\n }\n\n // Parse operations\n while (i < operations.length) {\n const op = operations[i];\n\n switch (op) {\n case TREE_OPERATION_ADD: {\n const id = operations[i + 1];\n const elementType = operations[i + 2];\n i += 3;\n\n if (elementType === ELEMENT_TYPE_ROOT) {\n // Root node: isStrictModeCompliant, supportsProfiling,\n // supportsStrictMode, hasOwnerMetadata\n i += 4;\n\n const node: ComponentNode = {\n id,\n displayName: 'Root',\n type: 'other',\n key: null,\n parentId: null,\n children: [],\n rendererId,\n };\n this.nodes.set(id, node);\n added.push({ id, displayName: node.displayName });\n if (!this.roots.includes(id)) {\n this.roots.push(id);\n }\n } else {\n const parentId = operations[i++];\n i++; // ownerID\n const displayNameStringId = operations[i++];\n const keyStringId = operations[i++];\n if (this.extendedAddFormat) {\n i++; // namePropStringID (added in newer backends)\n }\n\n const displayName =\n (displayNameStringId > 0 ? stringTable[displayNameStringId] : null) ||\n (elementType === ELEMENT_TYPE_HOST ? 'HostComponent' : 'Anonymous');\n const key = keyStringId > 0 ? stringTable[keyStringId] || null : null;\n\n const node: ComponentNode = {\n id,\n displayName,\n type: toComponentType(elementType),\n key,\n parentId: parentId === 0 ? null : parentId,\n children: [],\n rendererId,\n };\n\n this.nodes.set(id, node);\n added.push({ id, displayName });\n\n // Add to parent's children\n if (parentId === 0) {\n if (!this.roots.includes(id)) {\n this.roots.push(id);\n }\n } else {\n const parent = this.nodes.get(parentId);\n if (parent) {\n parent.children.push(id);\n }\n }\n\n // Update name index\n if (displayName) {\n const lower = displayName.toLowerCase();\n let set = this.nameIndex.get(lower);\n if (!set) {\n set = new Set();\n this.nameIndex.set(lower, set);\n }\n set.add(id);\n }\n }\n break;\n }\n\n case TREE_OPERATION_REMOVE: {\n const numRemoved = operations[i + 1];\n for (let j = 0; j < numRemoved; j++) {\n const id = operations[i + 2 + j];\n this.removeNode(id);\n }\n i += 2 + numRemoved;\n break;\n }\n\n case TREE_OPERATION_REORDER_CHILDREN: {\n const id = operations[i + 1];\n const numChildren = operations[i + 2];\n const newChildren: number[] = [];\n for (let j = 0; j < numChildren; j++) {\n newChildren.push(operations[i + 3 + j]);\n }\n const node = this.nodes.get(id);\n if (node) {\n node.children = newChildren;\n }\n i += 3 + numChildren;\n break;\n }\n\n case TREE_OPERATION_UPDATE_TREE_BASE_DURATION: {\n // id, baseDuration — skip\n i += 3;\n break;\n }\n\n case TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS: {\n // id, numErrors, numWarnings\n i += 4;\n break;\n }\n\n case TREE_OPERATION_REMOVE_ROOT: {\n const rootId = operations[i + 1];\n this.removeNode(rootId);\n i += 2;\n break;\n }\n\n case TREE_OPERATION_SET_SUBTREE_MODE: {\n // id, mode\n i += 3;\n break;\n }\n\n // ── Suspense tree operations (newer backends) ──\n\n case SUSPENSE_TREE_OPERATION_ADD: {\n // Presence of suspense ops means the backend also uses 8-field ADD\n this.extendedAddFormat = true;\n // fiberID, parentID, nameStringID, isSuspended, rects\n i += 5; // opcode + 4 fields\n i = skipRects(operations, i);\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_REMOVE: {\n this.extendedAddFormat = true;\n // numIDs, then that many IDs\n const numIds = operations[i + 1];\n i += 2 + numIds;\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_REORDER_CHILDREN: {\n this.extendedAddFormat = true;\n // parentID, numChildren, then that many child IDs\n const numSuspenseChildren = operations[i + 2];\n i += 3 + numSuspenseChildren;\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_RESIZE: {\n this.extendedAddFormat = true;\n // fiberID, rects\n i += 2; // opcode + fiberID\n i = skipRects(operations, i);\n break;\n }\n\n case SUSPENSE_TREE_OPERATION_SUSPENDERS: {\n this.extendedAddFormat = true;\n // numChanges, then numChanges * 4 values\n const numChanges = operations[i + 1];\n i += 2 + numChanges * 4;\n break;\n }\n\n case TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE: {\n this.extendedAddFormat = true;\n // id\n i += 2;\n break;\n }\n\n default:\n // Unknown operation — skip one value and try to continue.\n // Future protocol additions may cause brief misalignment but\n // subsequent operations batches will self-correct.\n i++;\n break;\n }\n }\n\n return added;\n }\n\n private removeNode(id: number): void {\n const node = this.nodes.get(id);\n if (!node) return;\n\n // Remove from parent's children\n if (node.parentId !== null) {\n const parent = this.nodes.get(node.parentId);\n if (parent) {\n parent.children = parent.children.filter((c) => c !== id);\n }\n }\n\n // Remove from roots\n this.roots = this.roots.filter((r) => r !== id);\n\n // Remove from name index\n if (node.displayName) {\n const lower = node.displayName.toLowerCase();\n const set = this.nameIndex.get(lower);\n if (set) {\n set.delete(id);\n if (set.size === 0) this.nameIndex.delete(lower);\n }\n }\n\n // Recursively remove children\n for (const childId of node.children) {\n this.removeNode(childId);\n }\n\n this.nodes.delete(id);\n }\n\n getNode(id: number): ComponentNode | undefined {\n return this.nodes.get(id);\n }\n\n getTree(maxDepth?: number): TreeNode[] {\n const result: TreeNode[] = [];\n\n // Rebuild label maps on every getTree() call\n this.labelToId.clear();\n this.idToLabel.clear();\n let labelCounter = 1;\n\n const walk = (id: number, depth: number) => {\n const node = this.nodes.get(id);\n if (!node) return;\n if (maxDepth !== undefined && depth > maxDepth) return;\n\n const label = `@c${labelCounter++}`;\n this.labelToId.set(label, node.id);\n this.idToLabel.set(node.id, label);\n\n result.push({\n id: node.id,\n label,\n displayName: node.displayName,\n type: node.type,\n key: node.key,\n parentId: node.parentId,\n children: node.children,\n depth,\n });\n\n for (const childId of node.children) {\n walk(childId, depth + 1);\n }\n };\n\n for (const rootId of this.roots) {\n walk(rootId, 0);\n }\n return result;\n }\n\n findByName(name: string, exact?: boolean): TreeNode[] {\n const results: TreeNode[] = [];\n\n if (exact) {\n const lower = name.toLowerCase();\n const ids = this.nameIndex.get(lower);\n if (ids) {\n for (const id of ids) {\n const node = this.nodes.get(id);\n if (node && node.displayName.toLowerCase() === lower) {\n results.push(this.toTreeNode(node));\n }\n }\n }\n } else {\n const lower = name.toLowerCase();\n for (const [indexName, ids] of this.nameIndex) {\n if (indexName.includes(lower)) {\n for (const id of ids) {\n const node = this.nodes.get(id);\n if (node) {\n results.push(this.toTreeNode(node));\n }\n }\n }\n }\n }\n\n return results;\n }\n\n getComponentCount(): number {\n return this.nodes.size;\n }\n\n getCountByType(): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const node of this.nodes.values()) {\n counts[node.type] = (counts[node.type] || 0) + 1;\n }\n return counts;\n }\n\n getAllNodeIds(): number[] {\n return Array.from(this.nodes.keys());\n }\n\n getRootIds(): number[] {\n return [...this.roots];\n }\n\n removeRoot(rootId: number): void {\n this.removeNode(rootId);\n }\n\n /**\n * Look up the @cN label for a given component ID.\n * Returns undefined if the ID has no label assigned.\n */\n getLabel(id: number): string | undefined {\n return this.idToLabel.get(id);\n }\n\n /**\n * Resolve a label like \"@c3\" to a real node ID.\n * Returns undefined if label not found.\n */\n resolveLabel(label: string): number | undefined {\n return this.labelToId.get(label);\n }\n\n /**\n * Resolve either a label string (\"@c3\") or a numeric ID to a real node ID.\n */\n resolveId(id: number | string): number | undefined {\n if (typeof id === 'number') return id;\n if (id.startsWith('@c')) return this.labelToId.get(id);\n // Try parsing as number\n const num = parseInt(id, 10);\n return isNaN(num) ? undefined : num;\n }\n\n private toTreeNode(node: ComponentNode): TreeNode {\n // Calculate depth by walking up the tree\n let depth = 0;\n let current = node;\n while (current.parentId !== null) {\n depth++;\n const parent = this.nodes.get(current.parentId);\n if (!parent) break;\n current = parent;\n }\n\n return {\n id: node.id,\n label: this.idToLabel.get(node.id) || `@c?`,\n displayName: node.displayName,\n type: node.type,\n key: node.key,\n parentId: node.parentId,\n children: node.children,\n depth,\n };\n }\n}\n","import type {\n ProfilingSession,\n ProfilingCommit,\n ComponentType,\n ProfilingDataExport,\n ProfilingDataForRootExport,\n CommitDataExport,\n SnapshotNodeExport,\n} from './types.js';\nimport type { ComponentTree } from './component-tree.js';\n\n/**\n * Build a React DevTools Profiler export (version 5) from a profiling session.\n *\n * When raw data from React DevTools is available (collected via\n * processProfilingData), it is passed through to ensure full fidelity —\n * including initialTreeBaseDurations that DevTools needs for correct\n * flame graph rendering. Snapshots are always built from the ComponentTree\n * since the protocol sends them empty.\n */\nexport function buildExportData(\n session: ProfilingSession,\n tree: ComponentTree,\n): ProfilingDataExport | null {\n if (session.commits.length === 0) return null;\n\n if (session.rawRoots.length > 0) {\n return {\n version: 5,\n dataForRoots: session.rawRoots.map((raw) => {\n const subtreeIds = collectSubtreeIds(raw.rootID, tree);\n const snapshots = buildSnapshots(raw.rootID, subtreeIds, tree);\n const operations = raw.operations.length > 0\n ? raw.operations\n : session.commits.map(() => []);\n\n return {\n commitData: raw.commitData as CommitDataExport[],\n displayName: raw.displayName,\n initialTreeBaseDurations: raw.initialTreeBaseDurations,\n operations,\n rootID: raw.rootID,\n snapshots,\n };\n }),\n };\n }\n\n // Fallback: reconstruct from parsed commits (e.g. if data came via flat format)\n return buildFromParsedCommits(session, tree);\n}\n\nfunction buildFromParsedCommits(\n session: ProfilingSession,\n tree: ComponentTree,\n): ProfilingDataExport {\n let rootIds = tree.getRootIds();\n if (rootIds.length === 0) {\n rootIds = [1];\n }\n\n const dataForRoots: ProfilingDataForRootExport[] = [];\n\n for (const rootId of rootIds) {\n const rootNode = tree.getNode(rootId);\n const subtreeIds = collectSubtreeIds(rootId, tree);\n const snapshots = buildSnapshots(rootId, subtreeIds, tree);\n\n const baseDurationMap = new Map<number, number>();\n for (const nodeId of subtreeIds) {\n baseDurationMap.set(nodeId, 0);\n }\n for (const commit of session.commits) {\n for (const [id, duration] of commit.fiberSelfDurations) {\n if (baseDurationMap.has(id)) {\n baseDurationMap.set(id, duration);\n }\n }\n }\n\n const commitData: CommitDataExport[] = session.commits.map(\n (commit) => convertCommit(commit),\n );\n\n dataForRoots.push({\n commitData,\n displayName: rootNode?.displayName || 'Root',\n initialTreeBaseDurations: Array.from(baseDurationMap.entries()),\n operations: session.commits.map(() => []),\n rootID: rootId,\n snapshots,\n });\n }\n\n return {\n version: 5,\n dataForRoots,\n };\n}\n\nfunction convertCommit(commit: ProfilingCommit): CommitDataExport {\n const changeDescriptions: Array<[number, {\n context: null;\n didHooksChange: boolean;\n isFirstMount: boolean;\n props: string[] | null;\n state: string[] | null;\n hooks: number[] | null;\n }]> = [];\n\n for (const [id, desc] of commit.changeDescriptions) {\n changeDescriptions.push([id, {\n context: null,\n didHooksChange: desc.didHooksChange,\n isFirstMount: desc.isFirstMount,\n props: desc.props,\n state: desc.state,\n hooks: desc.hooks,\n }]);\n }\n\n return {\n changeDescriptions: changeDescriptions.length > 0 ? changeDescriptions : null,\n duration: commit.duration,\n effectDuration: commit.effectDuration ?? 0,\n fiberActualDurations: Array.from(commit.fiberActualDurations.entries()),\n fiberSelfDurations: Array.from(commit.fiberSelfDurations.entries()),\n passiveEffectDuration: commit.passiveEffectDuration ?? 0,\n priorityLevel: commit.priorityLevel ?? null,\n timestamp: commit.timestamp,\n updaters: commit.updaters as CommitDataExport['updaters'],\n };\n}\n\nfunction buildSnapshots(\n rootId: number,\n subtreeIds: number[],\n tree: ComponentTree,\n): Array<[number, SnapshotNodeExport]> {\n const snapshots: Array<[number, SnapshotNodeExport]> = [];\n for (const nodeId of subtreeIds) {\n const node = tree.getNode(nodeId);\n if (!node) continue;\n const elementType =\n nodeId === rootId && node.type === 'other'\n ? 11\n : componentTypeToElementType(node.type);\n snapshots.push([nodeId, {\n id: nodeId,\n children: node.children,\n displayName: node.displayName || null,\n hocDisplayNames: null,\n key: node.key,\n type: elementType,\n compiledWithForget: false,\n }]);\n }\n return snapshots;\n}\n\nfunction collectSubtreeIds(rootId: number, tree: ComponentTree): number[] {\n const ids: number[] = [];\n const visit = (id: number) => {\n const node = tree.getNode(id);\n if (!node) return;\n ids.push(id);\n for (const childId of node.children) {\n visit(childId);\n }\n };\n visit(rootId);\n return ids;\n}\n\nfunction componentTypeToElementType(type: ComponentType): number {\n switch (type) {\n case 'class': return 1;\n case 'context': return 2;\n case 'function': return 5;\n case 'forwardRef': return 6;\n case 'host': return 7;\n case 'memo': return 8;\n case 'profiler': return 10;\n case 'suspense': return 12;\n case 'other': return 9;\n default: return 9;\n }\n}\n","import type {\n ProfilingSession,\n ProfilingCommit,\n ChangeDescription,\n ComponentRenderReport,\n RenderCause,\n ChangedKeys,\n ProfilingDataExport,\n} from './types.js';\nimport type { ComponentTree } from './component-tree.js';\nimport { buildExportData } from './profile-export.js';\n\nexport interface ProfileSummary {\n name: string;\n duration: number;\n commitCount: number;\n componentRenderCounts: { id: number; displayName: string; label?: string; type?: string; count: number }[];\n}\n\nexport interface TimelineEntry {\n index: number;\n timestamp: number;\n duration: number;\n componentCount: number;\n}\n\nexport interface CommitDetail {\n index: number;\n timestamp: number;\n duration: number;\n components: Array<{\n id: number;\n displayName: string;\n label?: string;\n type?: string;\n actualDuration: number;\n selfDuration: number;\n causes: RenderCause[];\n changedKeys?: ChangedKeys;\n }>;\n totalComponents: number;\n}\n\nexport class Profiler {\n private session: ProfilingSession | null = null;\n /** Display names captured during profiling (survives unmounts) */\n private displayNames = new Map<number, string>();\n\n isActive(): boolean {\n return this.session !== null && this.session.stoppedAt === null;\n }\n\n start(name?: string): void {\n this.displayNames.clear();\n this.session = {\n name: name || `session-${Date.now()}`,\n startedAt: Date.now(),\n stoppedAt: null,\n commits: [],\n rawRoots: [],\n };\n }\n\n /** Cache a component's display name (call during profiling to survive unmounts) */\n trackComponent(id: number, displayName: string): void {\n this.displayNames.set(id, displayName);\n }\n\n stop(tree?: ComponentTree): ProfileSummary | null {\n if (!this.session) return null;\n this.session.stoppedAt = Date.now();\n\n const duration = this.session.stoppedAt - this.session.startedAt;\n\n // Count renders per component\n const renderCounts = new Map<number, number>();\n for (const commit of this.session.commits) {\n for (const [id] of commit.fiberActualDurations) {\n renderCounts.set(id, (renderCounts.get(id) || 0) + 1);\n }\n }\n\n const componentRenderCounts = Array.from(renderCounts.entries())\n .map(([id, count]) => ({\n id,\n displayName: tree?.getNode(id)?.displayName || this.displayNames.get(id) || '',\n count,\n }))\n .sort((a, b) => b.count - a.count);\n\n return {\n name: this.session.name,\n duration,\n commitCount: this.session.commits.length,\n componentRenderCounts,\n };\n }\n\n /**\n * Process profiling data sent from React DevTools.\n *\n * The data format varies between React versions. We handle the common\n * format where each commit contains:\n * - commitTime\n * - duration\n * - fiberActualDurations: [id, duration, ...]\n * - fiberSelfDurations: [id, duration, ...]\n * - changeDescriptions: Map<id, description>\n */\n processProfilingData(payload: unknown): void {\n if (!this.session) return;\n\n const data = payload as {\n dataForRoots?: Array<{\n rootID?: number;\n commitData?: unknown[];\n operations?: Array<number[]>;\n initialTreeBaseDurations?: Array<[number, number]>;\n snapshots?: Array<[number, unknown]>;\n displayName?: string;\n }>;\n // Alternative flat format\n commitData?: unknown[];\n };\n\n // Handle nested format (dataForRoots)\n const roots = data?.dataForRoots;\n if (roots) {\n for (const root of roots) {\n // Store raw root data for export passthrough\n this.session.rawRoots.push({\n rootID: root.rootID ?? 1,\n commitData: root.commitData ?? [],\n initialTreeBaseDurations: root.initialTreeBaseDurations ?? [],\n operations: root.operations ?? [],\n snapshots: root.snapshots ?? [],\n displayName: root.displayName ?? 'Root',\n });\n\n if (root.commitData) {\n for (const commitData of root.commitData) {\n this.processCommitData(commitData as Record<string, unknown>);\n }\n }\n }\n return;\n }\n\n // Handle flat format\n if (data?.commitData) {\n for (const commitData of data.commitData) {\n this.processCommitData(commitData as Record<string, unknown>);\n }\n }\n }\n\n private processCommitData(commitData: Record<string, unknown>): void {\n const commit: ProfilingCommit = {\n timestamp: (commitData.timestamp as number) || Date.now(),\n duration: (commitData.duration as number) || 0,\n fiberActualDurations: new Map(),\n fiberSelfDurations: new Map(),\n changeDescriptions: new Map(),\n effectDuration: (commitData.effectDuration as number) ?? null,\n passiveEffectDuration: (commitData.passiveEffectDuration as number) ?? null,\n priorityLevel: (commitData.priorityLevel as string) ?? null,\n updaters: (commitData.updaters as unknown[]) ?? null,\n };\n\n // Parse fiber durations (can be [id, duration, id, duration, ...] or [[id, duration], ...])\n if (commitData.fiberActualDurations) {\n parseDurations(commitData.fiberActualDurations as Array<[number, number]> | number[], commit.fiberActualDurations);\n }\n if (commitData.fiberSelfDurations) {\n parseDurations(commitData.fiberSelfDurations as Array<[number, number]> | number[], commit.fiberSelfDurations);\n }\n\n // Parse change descriptions\n const rawDescs = commitData.changeDescriptions as Array<[number, unknown]> | Map<number, unknown> | undefined;\n if (rawDescs) {\n const entries =\n rawDescs instanceof Map\n ? rawDescs.entries()\n : rawDescs[Symbol.iterator]();\n for (const [id, desc] of entries) {\n const d = desc as {\n didHooksChange?: boolean;\n isFirstMount?: boolean;\n props?: string[] | null;\n state?: string[] | null;\n hooks?: number[] | null;\n };\n commit.changeDescriptions.set(id as number, {\n didHooksChange: d.didHooksChange || false,\n isFirstMount: d.isFirstMount || false,\n props: d.props || null,\n state: d.state || null,\n hooks: d.hooks || null,\n });\n }\n }\n\n this.session!.commits.push(commit);\n }\n\n getReport(\n componentId: number,\n tree: ComponentTree,\n ): ComponentRenderReport | null {\n if (!this.session) return null;\n\n const node = tree.getNode(componentId);\n let renderCount = 0;\n let totalDuration = 0;\n let maxDuration = 0;\n const causeSet = new Set<RenderCause>();\n const propsSet = new Set<string>();\n const stateSet = new Set<string>();\n const hooksSet = new Set<number>();\n\n for (const commit of this.session.commits) {\n const duration = commit.fiberActualDurations.get(componentId);\n if (duration !== undefined) {\n renderCount++;\n totalDuration += duration;\n if (duration > maxDuration) maxDuration = duration;\n\n const desc = commit.changeDescriptions.get(componentId);\n if (desc) {\n for (const cause of describeCauses(desc)) {\n causeSet.add(cause);\n }\n const keys = extractChangedKeys(desc);\n for (const p of keys.props) propsSet.add(p);\n for (const s of keys.state) stateSet.add(s);\n for (const h of keys.hooks) hooksSet.add(h);\n }\n }\n }\n\n if (renderCount === 0) return null;\n\n return {\n id: componentId,\n displayName: node?.displayName || this.displayNames.get(componentId) || `Component#${componentId}`,\n renderCount,\n totalDuration,\n avgDuration: totalDuration / renderCount,\n maxDuration,\n causes: Array.from(causeSet),\n changedKeys: {\n props: Array.from(propsSet),\n state: Array.from(stateSet),\n hooks: Array.from(hooksSet),\n },\n };\n }\n\n getSlowest(\n tree: ComponentTree,\n limit = 10,\n ): ComponentRenderReport[] {\n return this.getAllReports(tree)\n .sort((a, b) => b.avgDuration - a.avgDuration)\n .slice(0, limit);\n }\n\n getMostRerenders(\n tree: ComponentTree,\n limit = 10,\n ): ComponentRenderReport[] {\n return this.getAllReports(tree)\n .sort((a, b) => b.renderCount - a.renderCount)\n .slice(0, limit);\n }\n\n getCommitDetails(index: number, tree: ComponentTree, limit = 10): CommitDetail | null {\n if (!this.session) return null;\n if (index < 0 || index >= this.session.commits.length) return null;\n\n const commit = this.session.commits[index];\n const components: CommitDetail['components'] = [];\n\n for (const [id, actualDuration] of commit.fiberActualDurations) {\n const selfDuration = commit.fiberSelfDurations.get(id) || 0;\n const desc = commit.changeDescriptions.get(id);\n components.push({\n id,\n displayName: tree.getNode(id)?.displayName || this.displayNames.get(id) || `Component#${id}`,\n actualDuration,\n selfDuration,\n causes: desc ? describeCauses(desc) : [],\n changedKeys: desc ? extractChangedKeys(desc) : { props: [], state: [], hooks: [] },\n });\n }\n\n components.sort((a, b) => b.selfDuration - a.selfDuration);\n\n const totalCount = components.length;\n\n return {\n index,\n timestamp: commit.timestamp,\n duration: commit.duration,\n components: limit > 0 ? components.slice(0, limit) : components,\n totalComponents: totalCount,\n };\n }\n\n getTimeline(limit?: number): TimelineEntry[] {\n if (!this.session) return [];\n\n const entries = this.session.commits.map((commit, index) => ({\n index,\n timestamp: commit.timestamp,\n duration: commit.duration,\n componentCount: commit.fiberActualDurations.size,\n }));\n\n if (limit) return entries.slice(0, limit);\n return entries;\n }\n\n getExportData(tree: ComponentTree): ProfilingDataExport | null {\n if (!this.session) return null;\n return buildExportData(this.session, tree);\n }\n\n private getAllReports(tree: ComponentTree): ComponentRenderReport[] {\n if (!this.session) return [];\n\n // Collect all component IDs that appear in profiling data\n const componentIds = new Set<number>();\n for (const commit of this.session.commits) {\n for (const id of commit.fiberActualDurations.keys()) {\n componentIds.add(id);\n }\n }\n\n const reports: ComponentRenderReport[] = [];\n for (const id of componentIds) {\n const report = this.getReport(id, tree);\n if (report) reports.push(report);\n }\n return reports;\n }\n}\n\nfunction parseDurations(\n raw: Array<[number, number]> | number[],\n target: Map<number, number>,\n): void {\n if (raw.length === 0) return;\n\n // Check if it's array of tuples or flat array\n if (Array.isArray(raw[0])) {\n // [[id, duration], ...]\n for (const [id, duration] of raw as Array<[number, number]>) {\n target.set(id, duration);\n }\n } else {\n // [id, duration, id, duration, ...]\n const flat = raw as number[];\n for (let i = 0; i < flat.length; i += 2) {\n target.set(flat[i], flat[i + 1]);\n }\n }\n}\n\nfunction describeCauses(desc: ChangeDescription): RenderCause[] {\n const causes: RenderCause[] = [];\n if (desc.isFirstMount) {\n causes.push('first-mount');\n return causes;\n }\n if (desc.props && desc.props.length > 0) causes.push('props-changed');\n if (desc.state && desc.state.length > 0) causes.push('state-changed');\n if (desc.didHooksChange) causes.push('hooks-changed');\n // If no specific cause found, it was likely parent-triggered\n if (causes.length === 0) causes.push('parent-rendered');\n return causes;\n}\n\nfunction extractChangedKeys(desc: ChangeDescription): ChangedKeys {\n return {\n props: desc.props ?? [],\n state: desc.state ?? [],\n hooks: desc.hooks ?? [],\n };\n}\n"],"mappings":";;;AAAA,OAAO,SAAS;AAChB,OAAO,QAAQ;AACf,OAAO,UAAU;;;ACFjB,SAAS,iBAAiB,iBAAiB;AAgCpC,IAAM,iBAAN,MAAqB;AAAA,EAClB,MAA8B;AAAA,EAC9B,cAAc,oBAAI,IAAe;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB,oBAAI,IAA+B;AAAA,EACxD,0BAA0D;AAAA,EAC1D,cAAc,oBAAI,IAAY;AAAA;AAAA,EAE9B,kBAAkB,oBAAI,IAA4B;AAAA,EAClD,mBAAmB;AAAA,EACnB,mBAAkC;AAAA,EAClC,eAAkC,CAAC;AAAA,EACnC,oBAAoB;AAAA,EACpB,uBAAuB,oBAAI,IAAgB;AAAA,EAEnD,YAAYA,OAAc,MAAqB,UAAoB;AACjE,SAAK,OAAOA;AACZ,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,QAAuB;AAC3B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,MAAM,IAAI,gBAAgB,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM;AACxD,gBAAQ;AAAA,MACV,CAAC;AAED,WAAK,IAAI,GAAG,SAAS,CAAC,QAAQ;AAC5B,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,WAAK,IAAI,GAAG,cAAc,CAAC,OAAO;AAChC,aAAK,YAAY,IAAI,EAAE;AAGvB,cAAM,kBAAkB,KAAK,YAAY,SAAS,KAChD,KAAK,qBAAqB,QACzB,KAAK,IAAI,IAAI,KAAK,mBAAoB,KAAK;AAC9C,cAAM,YAAY,kBAAkB,gBAAyB;AAC7D,aAAK,mBAAmB;AACxB,aAAK,mBAAmB;AACxB,aAAK,UAAU,EAAE,MAAM,WAAW,WAAW,KAAK,IAAI,EAAE,CAAC;AACzD,aAAK,kBAAkB;AAEvB,WAAG,GAAG,WAAW,CAAC,SAAS;AACzB,cAAI;AACF,kBAAM,MAAuB,KAAK,MAAM,KAAK,SAAS,CAAC;AACvD,iBAAK,cAAc,IAAI,GAAG;AAAA,UAC5B,QAAQ;AAAA,UAER;AAAA,QACF,CAAC;AAED,WAAG,GAAG,SAAS,MAAM;AACnB,eAAK,kBAAkB,EAAE;AAAA,QAC3B,CAAC;AAED,WAAG,GAAG,SAAS,MAAM;AACnB,eAAK,kBAAkB,EAAE;AAAA,QAC3B,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,OAAa;AACX,eAAW,QAAQ,KAAK,aAAa;AACnC,WAAK,MAAM;AAAA,IACb;AACA,SAAK,YAAY,MAAM;AACvB,QAAI,KAAK,KAAK;AACZ,WAAK,IAAI,MAAM;AACf,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,uBAA+B;AAC7B,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,IAA8C;AAC3D,UAAM,OAAO,KAAK,KAAK,QAAQ,EAAE;AACjC,QAAI,CAAC,KAAM,QAAO,QAAQ,QAAQ,IAAI;AAEtC,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,mBAAmB,OAAO,EAAE;AACjC,gBAAQ,IAAI;AAAA,MACd,GAAG,GAAI;AAEP,WAAK,mBAAmB,IAAI,IAAI,EAAE,SAAS,MAAM,CAAC;AAElD,WAAK,UAAU;AAAA,QACb,OAAO;AAAA,QACP,SAAS;AAAA,UACP;AAAA,UACA,YAAY,KAAK;AAAA,UACjB,eAAe;AAAA,UACf,WAAW;AAAA,UACX,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,iBAAuB;AACrB,SAAK,UAAU;AAAA,MACb,OAAO;AAAA,MACP,SAAS,EAAE,0BAA0B,KAAK;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,0BAAyC;AACvC,SAAK,UAAU;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAGD,QAAI,KAAK,YAAY,SAAS,GAAG;AAC/B,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAGA,eAAW,cAAc,KAAK,aAAa;AACzC,WAAK,UAAU;AAAA,QACb,OAAO;AAAA,QACP,SAAS,EAAE,WAAW;AAAA,MACxB,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,KAAK,YAAY;AAClC,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,0BAA0B;AAC/B,gBAAQ;AAAA,MACV,GAAG,GAAI;AAEP,WAAK,0BAA0B,EAAE,SAAS,OAAO,WAAW,SAAS;AAAA,IACvE,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,IAAe,KAA4B;AAC/D,YAAQ,IAAI,OAAO;AAAA,MACjB,KAAK;AAEH,aAAK,OAAO,IAAI,EAAE,OAAO,qBAAqB,SAAS,OAAU,CAAC;AAClE,aAAK,OAAO,IAAI,EAAE,OAAO,qBAAqB,SAAS,OAAU,CAAC;AAClE,aAAK,OAAO,IAAI,EAAE,OAAO,sCAAsC,SAAS,OAAU,CAAC;AACnF,aAAK,OAAO,IAAI,EAAE,OAAO,mBAAmB,SAAS,OAAU,CAAC;AAChE,aAAK,OAAO,IAAI,EAAE,OAAO,sBAAsB,SAAS,OAAU,CAAC;AACnE;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH;AAAA,MAEF,KAAK;AACH,aAAK,iBAAiB,IAAI,IAAI,OAAmB;AACjD;AAAA,MAEF,KAAK;AACH,aAAK,uBAAuB,IAAI,OAAO;AACvC;AAAA,MAEF,KAAK;AACH,aAAK,oBAAoB,IAAI,OAAO;AACpC;AAAA,MAEF,KAAK,YAAY;AACf,cAAM,UAAU,IAAI;AACpB,aAAK,YAAY,IAAI,QAAQ,EAAE;AAC/B;AAAA,MACF;AAAA,MAEA,KAAK,oBAAoB;AACvB,cAAM,UAAU,IAAI;AACpB,aAAK,YAAY,IAAI,QAAQ,EAAE;AAC/B;AAAA,MACF;AAAA,MAEA,KAAK;AACH,WAAG,MAAM;AACT;AAAA;AAAA,MAGF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH;AAAA,MAEF;AACE;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,iBAAiB,IAAe,YAA4B;AAClE,QAAI,WAAW,UAAU,GAAG;AAE1B,WAAK,YAAY,IAAI,WAAW,CAAC,CAAC;AAGlC,YAAM,cAAc,WAAW,CAAC;AAChC,UAAI,QAAQ,KAAK,gBAAgB,IAAI,EAAE;AACvC,UAAI,CAAC,OAAO;AACV,gBAAQ,oBAAI,IAAI;AAChB,aAAK,gBAAgB,IAAI,IAAI,KAAK;AAAA,MACpC;AACA,YAAM,IAAI,WAAW;AAAA,IACvB;AACA,UAAM,QAAQ,KAAK,KAAK,gBAAgB,UAAU;AAGlD,QAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,iBAAW,QAAQ,OAAO;AACxB,aAAK,SAAS,eAAe,KAAK,IAAI,KAAK,WAAW;AAAA,MACxD;AAAA,IACF;AAEA,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,kBAAkB,IAAqB;AAC7C,SAAK,YAAY,OAAO,EAAE;AAE1B,UAAM,QAAQ,KAAK,gBAAgB,IAAI,EAAE;AACzC,QAAI,OAAO;AACT,iBAAW,UAAU,OAAO;AAC1B,aAAK,KAAK,WAAW,MAAM;AAAA,MAC7B;AACA,WAAK,gBAAgB,OAAO,EAAE;AAAA,IAChC;AACA,SAAK,mBAAmB,KAAK,IAAI;AACjC,SAAK,UAAU,EAAE,MAAM,gBAAgB,WAAW,KAAK,IAAI,EAAE,CAAC;AAC9D,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,uBAAuB,SAAwB;AACrD,UAAM,OAAO;AAcb,QAAI,KAAK,SAAS,eAAe,KAAK,SAAS,iBAAiB;AAE9D,YAAMC,WAAU,KAAK,mBAAmB,IAAI,KAAK,EAAE;AACnD,UAAIA,UAAS;AACX,qBAAaA,SAAQ,KAAK;AAC1B,aAAK,mBAAmB,OAAO,KAAK,EAAE;AACtC,QAAAA,SAAQ,QAAQ,IAAI;AAAA,MACtB;AACA;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,mBAAmB,IAAI,KAAK,EAAE;AACnD,QAAI,CAAC,WAAW,CAAC,KAAK,MAAO;AAE7B,iBAAa,QAAQ,KAAK;AAC1B,SAAK,mBAAmB,OAAO,KAAK,EAAE;AAEtC,UAAM,OAAO,KAAK,KAAK,QAAQ,KAAK,EAAE;AACtC,UAAM,YAA8B;AAAA,MAClC,IAAI,KAAK;AAAA,MACT,aAAa,KAAK,MAAM,eAAe,MAAM,eAAe;AAAA,MAC5D,MAAM,MAAM,QAAQ;AAAA,MACpB,KAAK,KAAK,MAAM;AAAA,MAChB,OAAO,gBAAgB,KAAK,MAAM,KAAK;AAAA,MACvC,OAAO,KAAK,MAAM,QACb,gBAAgB,KAAK,MAAM,KAAK,IACjC;AAAA,MACJ,OAAO,KAAK,MAAM,QACd,WAAW,KAAK,MAAM,KAAK,IAC3B;AAAA,MACJ,YAAY;AAAA,IACd;AAEA,YAAQ,QAAQ,SAAS;AAAA,EAC3B;AAAA,EAEQ,oBAAoB,SAAwB;AAGlD,SAAK,SAAS,qBAAqB,OAAO;AAG1C,QAAI,KAAK,yBAAyB;AAChC,WAAK,wBAAwB;AAC7B,UAAI,KAAK,wBAAwB,aAAa,GAAG;AAC/C,qBAAa,KAAK,wBAAwB,KAAK;AAC/C,cAAM,UAAU,KAAK;AACrB,aAAK,0BAA0B;AAC/B,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,sBAAwC;AACtC,WAAO;AAAA,MACL,eAAe,KAAK,YAAY;AAAA,MAChC,kBAAkB,KAAK;AAAA,MACvB,kBAAkB,KAAK;AAAA,MACvB,cAAc,CAAC,GAAG,KAAK,YAAY;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,cAAc,UAAkC;AAC9C,SAAK,qBAAqB,IAAI,QAAQ;AACtC,WAAO,MAAM;AAAE,WAAK,qBAAqB,OAAO,QAAQ;AAAA,IAAG;AAAA,EAC7D;AAAA,EAEQ,UAAU,OAA8B;AAC9C,SAAK,aAAa,KAAK,KAAK;AAC5B,QAAI,KAAK,aAAa,SAAS,IAAI;AACjC,WAAK,eAAe,KAAK,aAAa,MAAM,GAAG;AAAA,IACjD;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,eAAW,YAAY,KAAK,sBAAsB;AAChD,eAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,OAAO,IAAe,KAA4B;AACxD,QAAI,GAAG,eAAe,UAAU,MAAM;AACpC,SAAG,KAAK,KAAK,UAAU,GAAG,CAAC;AAAA,IAC7B;AAAA,EACF;AAAA,EAEQ,UAAU,KAA4B;AAC5C,UAAM,MAAM,KAAK,UAAU,GAAG;AAC9B,eAAW,QAAQ,KAAK,aAAa;AACnC,UAAI,KAAK,eAAe,UAAU,MAAM;AACtC,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;AAOA,SAAS,gBAAgB,KAAuB;AAC9C,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO;AAC9C,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,eAAe;AAEtD,QAAM,SAAS;AAGf,MAAI,UAAU,UAAU,mBAAmB,QAAQ;AACjD,WAAO,OAAO,eAAe;AAAA,EAC/B;AAEA,QAAM,UAAmC,CAAC;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAQ,GAAG,IAAI,gBAAgB,KAAK;AAAA,EACtC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAqG;AACvH,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,UAAM,IAAI;AAOV,UAAM,SAA0F;AAAA,MAC9F,MAAM,EAAE;AAAA,MACR,OAAO,gBAAgB,EAAE,KAAK;AAAA,IAChC;AACA,QAAI,EAAE,YAAY,EAAE,SAAS,SAAS,GAAG;AACvC,aAAO,WAAW,WAAW,EAAE,QAAQ;AAAA,IACzC;AACA,WAAO;AAAA,EACT,CAAC;AACH;;;ACvaA,IAAM,qBAAqB;AAC3B,IAAM,wBAAwB;AAC9B,IAAM,kCAAkC;AACxC,IAAM,2CAA2C;AACjD,IAAM,2CAA2C;AACjD,IAAM,6BAA6B;AACnC,IAAM,kCAAkC;AAKxC,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,2CAA2C;AACjD,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,+CAA+C;AAKrD,IAAM,qBAAqB;AAE3B,IAAM,wBAAwB;AAC9B,IAAM,2BAA2B;AACjC,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAE1B,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAE9B,SAAS,gBAAgB,aAAoC;AAC3D,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAQA,SAAS,UAAU,YAAsB,GAAmB;AAC1D,QAAM,QAAQ,WAAW,GAAG;AAC5B,MAAI,UAAU,GAAI,QAAO;AACzB,SAAO,IAAI,QAAQ;AACrB;AAaO,IAAM,gBAAN,MAAoB;AAAA,EACjB,QAAQ,oBAAI,IAA2B;AAAA,EACvC,QAAkB,CAAC;AAAA;AAAA,EAEnB,YAAY,oBAAI,IAAyB;AAAA;AAAA,EAEzC,YAAY,oBAAI,IAAoB;AAAA;AAAA,EAEpC,YAAY,oBAAI,IAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpC,oBAAoB;AAAA,EAE5B,gBAAgB,YAAkE;AAChF,QAAI,WAAW,SAAS,EAAG,QAAO,CAAC;AAEnC,UAAM,QAAoD,CAAC;AAC3D,UAAM,aAAa,WAAW,CAAC;AAE/B,QAAI,IAAI;AAGR,UAAM,cAAoC,CAAC,IAAI;AAC/C,UAAM,kBAAkB,WAAW,GAAG;AACtC,UAAM,iBAAiB,IAAI;AAC3B,WAAO,IAAI,gBAAgB;AACzB,YAAM,SAAS,WAAW,GAAG;AAC7B,UAAI,MAAM;AACV,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,eAAO,OAAO,cAAc,WAAW,GAAG,CAAC;AAAA,MAC7C;AACA,kBAAY,KAAK,GAAG;AAAA,IACtB;AAGA,WAAO,IAAI,WAAW,QAAQ;AAC5B,YAAM,KAAK,WAAW,CAAC;AAEvB,cAAQ,IAAI;AAAA,QACV,KAAK,oBAAoB;AACvB,gBAAM,KAAK,WAAW,IAAI,CAAC;AAC3B,gBAAM,cAAc,WAAW,IAAI,CAAC;AACpC,eAAK;AAEL,cAAI,gBAAgB,mBAAmB;AAGrC,iBAAK;AAEL,kBAAM,OAAsB;AAAA,cAC1B;AAAA,cACA,aAAa;AAAA,cACb,MAAM;AAAA,cACN,KAAK;AAAA,cACL,UAAU;AAAA,cACV,UAAU,CAAC;AAAA,cACX;AAAA,YACF;AACA,iBAAK,MAAM,IAAI,IAAI,IAAI;AACvB,kBAAM,KAAK,EAAE,IAAI,aAAa,KAAK,YAAY,CAAC;AAChD,gBAAI,CAAC,KAAK,MAAM,SAAS,EAAE,GAAG;AAC5B,mBAAK,MAAM,KAAK,EAAE;AAAA,YACpB;AAAA,UACF,OAAO;AACL,kBAAM,WAAW,WAAW,GAAG;AAC/B;AACA,kBAAM,sBAAsB,WAAW,GAAG;AAC1C,kBAAM,cAAc,WAAW,GAAG;AAClC,gBAAI,KAAK,mBAAmB;AAC1B;AAAA,YACF;AAEA,kBAAM,eACH,sBAAsB,IAAI,YAAY,mBAAmB,IAAI,UAC7D,gBAAgB,oBAAoB,kBAAkB;AACzD,kBAAM,MAAM,cAAc,IAAI,YAAY,WAAW,KAAK,OAAO;AAEjE,kBAAM,OAAsB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA,MAAM,gBAAgB,WAAW;AAAA,cACjC;AAAA,cACA,UAAU,aAAa,IAAI,OAAO;AAAA,cAClC,UAAU,CAAC;AAAA,cACX;AAAA,YACF;AAEA,iBAAK,MAAM,IAAI,IAAI,IAAI;AACvB,kBAAM,KAAK,EAAE,IAAI,YAAY,CAAC;AAG9B,gBAAI,aAAa,GAAG;AAClB,kBAAI,CAAC,KAAK,MAAM,SAAS,EAAE,GAAG;AAC5B,qBAAK,MAAM,KAAK,EAAE;AAAA,cACpB;AAAA,YACF,OAAO;AACL,oBAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,kBAAI,QAAQ;AACV,uBAAO,SAAS,KAAK,EAAE;AAAA,cACzB;AAAA,YACF;AAGA,gBAAI,aAAa;AACf,oBAAM,QAAQ,YAAY,YAAY;AACtC,kBAAI,MAAM,KAAK,UAAU,IAAI,KAAK;AAClC,kBAAI,CAAC,KAAK;AACR,sBAAM,oBAAI,IAAI;AACd,qBAAK,UAAU,IAAI,OAAO,GAAG;AAAA,cAC/B;AACA,kBAAI,IAAI,EAAE;AAAA,YACZ;AAAA,UACF;AACA;AAAA,QACF;AAAA,QAEA,KAAK,uBAAuB;AAC1B,gBAAM,aAAa,WAAW,IAAI,CAAC;AACnC,mBAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,kBAAM,KAAK,WAAW,IAAI,IAAI,CAAC;AAC/B,iBAAK,WAAW,EAAE;AAAA,UACpB;AACA,eAAK,IAAI;AACT;AAAA,QACF;AAAA,QAEA,KAAK,iCAAiC;AACpC,gBAAM,KAAK,WAAW,IAAI,CAAC;AAC3B,gBAAM,cAAc,WAAW,IAAI,CAAC;AACpC,gBAAM,cAAwB,CAAC;AAC/B,mBAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,wBAAY,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC;AAAA,UACxC;AACA,gBAAM,OAAO,KAAK,MAAM,IAAI,EAAE;AAC9B,cAAI,MAAM;AACR,iBAAK,WAAW;AAAA,UAClB;AACA,eAAK,IAAI;AACT;AAAA,QACF;AAAA,QAEA,KAAK,0CAA0C;AAE7C,eAAK;AACL;AAAA,QACF;AAAA,QAEA,KAAK,0CAA0C;AAE7C,eAAK;AACL;AAAA,QACF;AAAA,QAEA,KAAK,4BAA4B;AAC/B,gBAAM,SAAS,WAAW,IAAI,CAAC;AAC/B,eAAK,WAAW,MAAM;AACtB,eAAK;AACL;AAAA,QACF;AAAA,QAEA,KAAK,iCAAiC;AAEpC,eAAK;AACL;AAAA,QACF;AAAA;AAAA,QAIA,KAAK,6BAA6B;AAEhC,eAAK,oBAAoB;AAEzB,eAAK;AACL,cAAI,UAAU,YAAY,CAAC;AAC3B;AAAA,QACF;AAAA,QAEA,KAAK,gCAAgC;AACnC,eAAK,oBAAoB;AAEzB,gBAAM,SAAS,WAAW,IAAI,CAAC;AAC/B,eAAK,IAAI;AACT;AAAA,QACF;AAAA,QAEA,KAAK,0CAA0C;AAC7C,eAAK,oBAAoB;AAEzB,gBAAM,sBAAsB,WAAW,IAAI,CAAC;AAC5C,eAAK,IAAI;AACT;AAAA,QACF;AAAA,QAEA,KAAK,gCAAgC;AACnC,eAAK,oBAAoB;AAEzB,eAAK;AACL,cAAI,UAAU,YAAY,CAAC;AAC3B;AAAA,QACF;AAAA,QAEA,KAAK,oCAAoC;AACvC,eAAK,oBAAoB;AAEzB,gBAAM,aAAa,WAAW,IAAI,CAAC;AACnC,eAAK,IAAI,aAAa;AACtB;AAAA,QACF;AAAA,QAEA,KAAK,8CAA8C;AACjD,eAAK,oBAAoB;AAEzB,eAAK;AACL;AAAA,QACF;AAAA,QAEA;AAIE;AACA;AAAA,MACJ;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,IAAkB;AACnC,UAAM,OAAO,KAAK,MAAM,IAAI,EAAE;AAC9B,QAAI,CAAC,KAAM;AAGX,QAAI,KAAK,aAAa,MAAM;AAC1B,YAAM,SAAS,KAAK,MAAM,IAAI,KAAK,QAAQ;AAC3C,UAAI,QAAQ;AACV,eAAO,WAAW,OAAO,SAAS,OAAO,CAAC,MAAM,MAAM,EAAE;AAAA,MAC1D;AAAA,IACF;AAGA,SAAK,QAAQ,KAAK,MAAM,OAAO,CAAC,MAAM,MAAM,EAAE;AAG9C,QAAI,KAAK,aAAa;AACpB,YAAM,QAAQ,KAAK,YAAY,YAAY;AAC3C,YAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,UAAI,KAAK;AACP,YAAI,OAAO,EAAE;AACb,YAAI,IAAI,SAAS,EAAG,MAAK,UAAU,OAAO,KAAK;AAAA,MACjD;AAAA,IACF;AAGA,eAAW,WAAW,KAAK,UAAU;AACnC,WAAK,WAAW,OAAO;AAAA,IACzB;AAEA,SAAK,MAAM,OAAO,EAAE;AAAA,EACtB;AAAA,EAEA,QAAQ,IAAuC;AAC7C,WAAO,KAAK,MAAM,IAAI,EAAE;AAAA,EAC1B;AAAA,EAEA,QAAQ,UAA+B;AACrC,UAAM,SAAqB,CAAC;AAG5B,SAAK,UAAU,MAAM;AACrB,SAAK,UAAU,MAAM;AACrB,QAAI,eAAe;AAEnB,UAAM,OAAO,CAAC,IAAY,UAAkB;AAC1C,YAAM,OAAO,KAAK,MAAM,IAAI,EAAE;AAC9B,UAAI,CAAC,KAAM;AACX,UAAI,aAAa,UAAa,QAAQ,SAAU;AAEhD,YAAM,QAAQ,KAAK,cAAc;AACjC,WAAK,UAAU,IAAI,OAAO,KAAK,EAAE;AACjC,WAAK,UAAU,IAAI,KAAK,IAAI,KAAK;AAEjC,aAAO,KAAK;AAAA,QACV,IAAI,KAAK;AAAA,QACT;AAAA,QACA,aAAa,KAAK;AAAA,QAClB,MAAM,KAAK;AAAA,QACX,KAAK,KAAK;AAAA,QACV,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AAED,iBAAW,WAAW,KAAK,UAAU;AACnC,aAAK,SAAS,QAAQ,CAAC;AAAA,MACzB;AAAA,IACF;AAEA,eAAW,UAAU,KAAK,OAAO;AAC/B,WAAK,QAAQ,CAAC;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,MAAc,OAA6B;AACpD,UAAM,UAAsB,CAAC;AAE7B,QAAI,OAAO;AACT,YAAM,QAAQ,KAAK,YAAY;AAC/B,YAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,UAAI,KAAK;AACP,mBAAW,MAAM,KAAK;AACpB,gBAAM,OAAO,KAAK,MAAM,IAAI,EAAE;AAC9B,cAAI,QAAQ,KAAK,YAAY,YAAY,MAAM,OAAO;AACpD,oBAAQ,KAAK,KAAK,WAAW,IAAI,CAAC;AAAA,UACpC;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,KAAK,YAAY;AAC/B,iBAAW,CAAC,WAAW,GAAG,KAAK,KAAK,WAAW;AAC7C,YAAI,UAAU,SAAS,KAAK,GAAG;AAC7B,qBAAW,MAAM,KAAK;AACpB,kBAAM,OAAO,KAAK,MAAM,IAAI,EAAE;AAC9B,gBAAI,MAAM;AACR,sBAAQ,KAAK,KAAK,WAAW,IAAI,CAAC;AAAA,YACpC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,oBAA4B;AAC1B,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,iBAAyC;AACvC,UAAM,SAAiC,CAAC;AACxC,eAAW,QAAQ,KAAK,MAAM,OAAO,GAAG;AACtC,aAAO,KAAK,IAAI,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK;AAAA,IACjD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gBAA0B;AACxB,WAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAAA,EACrC;AAAA,EAEA,aAAuB;AACrB,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACvB;AAAA,EAEA,WAAW,QAAsB;AAC/B,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,IAAgC;AACvC,WAAO,KAAK,UAAU,IAAI,EAAE;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAmC;AAC9C,WAAO,KAAK,UAAU,IAAI,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,IAAyC;AACjD,QAAI,OAAO,OAAO,SAAU,QAAO;AACnC,QAAI,GAAG,WAAW,IAAI,EAAG,QAAO,KAAK,UAAU,IAAI,EAAE;AAErD,UAAM,MAAM,SAAS,IAAI,EAAE;AAC3B,WAAO,MAAM,GAAG,IAAI,SAAY;AAAA,EAClC;AAAA,EAEQ,WAAW,MAA+B;AAEhD,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,WAAO,QAAQ,aAAa,MAAM;AAChC;AACA,YAAM,SAAS,KAAK,MAAM,IAAI,QAAQ,QAAQ;AAC9C,UAAI,CAAC,OAAQ;AACb,gBAAU;AAAA,IACZ;AAEA,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,OAAO,KAAK,UAAU,IAAI,KAAK,EAAE,KAAK;AAAA,MACtC,aAAa,KAAK;AAAA,MAClB,MAAM,KAAK;AAAA,MACX,KAAK,KAAK;AAAA,MACV,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;;;ACleO,SAAS,gBACd,SACA,MAC4B;AAC5B,MAAI,QAAQ,QAAQ,WAAW,EAAG,QAAO;AAEzC,MAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,cAAc,QAAQ,SAAS,IAAI,CAAC,QAAQ;AAC1C,cAAM,aAAa,kBAAkB,IAAI,QAAQ,IAAI;AACrD,cAAM,YAAY,eAAe,IAAI,QAAQ,YAAY,IAAI;AAC7D,cAAM,aAAa,IAAI,WAAW,SAAS,IACvC,IAAI,aACJ,QAAQ,QAAQ,IAAI,MAAM,CAAC,CAAC;AAEhC,eAAO;AAAA,UACL,YAAY,IAAI;AAAA,UAChB,aAAa,IAAI;AAAA,UACjB,0BAA0B,IAAI;AAAA,UAC9B;AAAA,UACA,QAAQ,IAAI;AAAA,UACZ;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO,uBAAuB,SAAS,IAAI;AAC7C;AAEA,SAAS,uBACP,SACA,MACqB;AACrB,MAAI,UAAU,KAAK,WAAW;AAC9B,MAAI,QAAQ,WAAW,GAAG;AACxB,cAAU,CAAC,CAAC;AAAA,EACd;AAEA,QAAM,eAA6C,CAAC;AAEpD,aAAW,UAAU,SAAS;AAC5B,UAAM,WAAW,KAAK,QAAQ,MAAM;AACpC,UAAM,aAAa,kBAAkB,QAAQ,IAAI;AACjD,UAAM,YAAY,eAAe,QAAQ,YAAY,IAAI;AAEzD,UAAM,kBAAkB,oBAAI,IAAoB;AAChD,eAAW,UAAU,YAAY;AAC/B,sBAAgB,IAAI,QAAQ,CAAC;AAAA,IAC/B;AACA,eAAW,UAAU,QAAQ,SAAS;AACpC,iBAAW,CAAC,IAAI,QAAQ,KAAK,OAAO,oBAAoB;AACtD,YAAI,gBAAgB,IAAI,EAAE,GAAG;AAC3B,0BAAgB,IAAI,IAAI,QAAQ;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAiC,QAAQ,QAAQ;AAAA,MACrD,CAAC,WAAW,cAAc,MAAM;AAAA,IAClC;AAEA,iBAAa,KAAK;AAAA,MAChB;AAAA,MACA,aAAa,UAAU,eAAe;AAAA,MACtC,0BAA0B,MAAM,KAAK,gBAAgB,QAAQ,CAAC;AAAA,MAC9D,YAAY,QAAQ,QAAQ,IAAI,MAAM,CAAC,CAAC;AAAA,MACxC,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,cAAc,QAA2C;AAChE,QAAM,qBAOA,CAAC;AAEP,aAAW,CAAC,IAAI,IAAI,KAAK,OAAO,oBAAoB;AAClD,uBAAmB,KAAK,CAAC,IAAI;AAAA,MAC3B,SAAS;AAAA,MACT,gBAAgB,KAAK;AAAA,MACrB,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,IACd,CAAC,CAAC;AAAA,EACJ;AAEA,SAAO;AAAA,IACL,oBAAoB,mBAAmB,SAAS,IAAI,qBAAqB;AAAA,IACzE,UAAU,OAAO;AAAA,IACjB,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,sBAAsB,MAAM,KAAK,OAAO,qBAAqB,QAAQ,CAAC;AAAA,IACtE,oBAAoB,MAAM,KAAK,OAAO,mBAAmB,QAAQ,CAAC;AAAA,IAClE,uBAAuB,OAAO,yBAAyB;AAAA,IACvD,eAAe,OAAO,iBAAiB;AAAA,IACvC,WAAW,OAAO;AAAA,IAClB,UAAU,OAAO;AAAA,EACnB;AACF;AAEA,SAAS,eACP,QACA,YACA,MACqC;AACrC,QAAM,YAAiD,CAAC;AACxD,aAAW,UAAU,YAAY;AAC/B,UAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,QAAI,CAAC,KAAM;AACX,UAAM,cACJ,WAAW,UAAU,KAAK,SAAS,UAC/B,KACA,2BAA2B,KAAK,IAAI;AAC1C,cAAU,KAAK,CAAC,QAAQ;AAAA,MACtB,IAAI;AAAA,MACJ,UAAU,KAAK;AAAA,MACf,aAAa,KAAK,eAAe;AAAA,MACjC,iBAAiB;AAAA,MACjB,KAAK,KAAK;AAAA,MACV,MAAM;AAAA,MACN,oBAAoB;AAAA,IACtB,CAAC,CAAC;AAAA,EACJ;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,QAAgB,MAA+B;AACxE,QAAM,MAAgB,CAAC;AACvB,QAAM,QAAQ,CAAC,OAAe;AAC5B,UAAM,OAAO,KAAK,QAAQ,EAAE;AAC5B,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,EAAE;AACX,eAAW,WAAW,KAAK,UAAU;AACnC,YAAM,OAAO;AAAA,IACf;AAAA,EACF;AACA,QAAM,MAAM;AACZ,SAAO;AACT;AAEA,SAAS,2BAA2B,MAA6B;AAC/D,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAS,aAAO;AAAA,IACrB,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAc,aAAO;AAAA,IAC1B,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAS,aAAO;AAAA,IACrB;AAAS,aAAO;AAAA,EAClB;AACF;;;AChJO,IAAM,WAAN,MAAe;AAAA,EACZ,UAAmC;AAAA;AAAA,EAEnC,eAAe,oBAAI,IAAoB;AAAA,EAE/C,WAAoB;AAClB,WAAO,KAAK,YAAY,QAAQ,KAAK,QAAQ,cAAc;AAAA,EAC7D;AAAA,EAEA,MAAM,MAAqB;AACzB,SAAK,aAAa,MAAM;AACxB,SAAK,UAAU;AAAA,MACb,MAAM,QAAQ,WAAW,KAAK,IAAI,CAAC;AAAA,MACnC,WAAW,KAAK,IAAI;AAAA,MACpB,WAAW;AAAA,MACX,SAAS,CAAC;AAAA,MACV,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAAA;AAAA,EAGA,eAAe,IAAY,aAA2B;AACpD,SAAK,aAAa,IAAI,IAAI,WAAW;AAAA,EACvC;AAAA,EAEA,KAAK,MAA6C;AAChD,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,SAAK,QAAQ,YAAY,KAAK,IAAI;AAElC,UAAM,WAAW,KAAK,QAAQ,YAAY,KAAK,QAAQ;AAGvD,UAAM,eAAe,oBAAI,IAAoB;AAC7C,eAAW,UAAU,KAAK,QAAQ,SAAS;AACzC,iBAAW,CAAC,EAAE,KAAK,OAAO,sBAAsB;AAC9C,qBAAa,IAAI,KAAK,aAAa,IAAI,EAAE,KAAK,KAAK,CAAC;AAAA,MACtD;AAAA,IACF;AAEA,UAAM,wBAAwB,MAAM,KAAK,aAAa,QAAQ,CAAC,EAC5D,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;AAAA,MACrB;AAAA,MACA,aAAa,MAAM,QAAQ,EAAE,GAAG,eAAe,KAAK,aAAa,IAAI,EAAE,KAAK;AAAA,MAC5E;AAAA,IACF,EAAE,EACD,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAEnC,WAAO;AAAA,MACL,MAAM,KAAK,QAAQ;AAAA,MACnB;AAAA,MACA,aAAa,KAAK,QAAQ,QAAQ;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,qBAAqB,SAAwB;AAC3C,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,OAAO;AAcb,UAAM,QAAQ,MAAM;AACpB,QAAI,OAAO;AACT,iBAAW,QAAQ,OAAO;AAExB,aAAK,QAAQ,SAAS,KAAK;AAAA,UACzB,QAAQ,KAAK,UAAU;AAAA,UACvB,YAAY,KAAK,cAAc,CAAC;AAAA,UAChC,0BAA0B,KAAK,4BAA4B,CAAC;AAAA,UAC5D,YAAY,KAAK,cAAc,CAAC;AAAA,UAChC,WAAW,KAAK,aAAa,CAAC;AAAA,UAC9B,aAAa,KAAK,eAAe;AAAA,QACnC,CAAC;AAED,YAAI,KAAK,YAAY;AACnB,qBAAW,cAAc,KAAK,YAAY;AACxC,iBAAK,kBAAkB,UAAqC;AAAA,UAC9D;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,MAAM,YAAY;AACpB,iBAAW,cAAc,KAAK,YAAY;AACxC,aAAK,kBAAkB,UAAqC;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,kBAAkB,YAA2C;AACnE,UAAM,SAA0B;AAAA,MAC9B,WAAY,WAAW,aAAwB,KAAK,IAAI;AAAA,MACxD,UAAW,WAAW,YAAuB;AAAA,MAC7C,sBAAsB,oBAAI,IAAI;AAAA,MAC9B,oBAAoB,oBAAI,IAAI;AAAA,MAC5B,oBAAoB,oBAAI,IAAI;AAAA,MAC5B,gBAAiB,WAAW,kBAA6B;AAAA,MACzD,uBAAwB,WAAW,yBAAoC;AAAA,MACvE,eAAgB,WAAW,iBAA4B;AAAA,MACvD,UAAW,WAAW,YAA0B;AAAA,IAClD;AAGA,QAAI,WAAW,sBAAsB;AACnC,qBAAe,WAAW,sBAA4D,OAAO,oBAAoB;AAAA,IACnH;AACA,QAAI,WAAW,oBAAoB;AACjC,qBAAe,WAAW,oBAA0D,OAAO,kBAAkB;AAAA,IAC/G;AAGA,UAAM,WAAW,WAAW;AAC5B,QAAI,UAAU;AACZ,YAAM,UACJ,oBAAoB,MAChB,SAAS,QAAQ,IACjB,SAAS,OAAO,QAAQ,EAAE;AAChC,iBAAW,CAAC,IAAI,IAAI,KAAK,SAAS;AAChC,cAAM,IAAI;AAOV,eAAO,mBAAmB,IAAI,IAAc;AAAA,UAC1C,gBAAgB,EAAE,kBAAkB;AAAA,UACpC,cAAc,EAAE,gBAAgB;AAAA,UAChC,OAAO,EAAE,SAAS;AAAA,UAClB,OAAO,EAAE,SAAS;AAAA,UAClB,OAAO,EAAE,SAAS;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,SAAK,QAAS,QAAQ,KAAK,MAAM;AAAA,EACnC;AAAA,EAEA,UACE,aACA,MAC8B;AAC9B,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,UAAM,OAAO,KAAK,QAAQ,WAAW;AACrC,QAAI,cAAc;AAClB,QAAI,gBAAgB;AACpB,QAAI,cAAc;AAClB,UAAM,WAAW,oBAAI,IAAiB;AACtC,UAAM,WAAW,oBAAI,IAAY;AACjC,UAAM,WAAW,oBAAI,IAAY;AACjC,UAAM,WAAW,oBAAI,IAAY;AAEjC,eAAW,UAAU,KAAK,QAAQ,SAAS;AACzC,YAAM,WAAW,OAAO,qBAAqB,IAAI,WAAW;AAC5D,UAAI,aAAa,QAAW;AAC1B;AACA,yBAAiB;AACjB,YAAI,WAAW,YAAa,eAAc;AAE1C,cAAM,OAAO,OAAO,mBAAmB,IAAI,WAAW;AACtD,YAAI,MAAM;AACR,qBAAW,SAAS,eAAe,IAAI,GAAG;AACxC,qBAAS,IAAI,KAAK;AAAA,UACpB;AACA,gBAAM,OAAO,mBAAmB,IAAI;AACpC,qBAAW,KAAK,KAAK,MAAO,UAAS,IAAI,CAAC;AAC1C,qBAAW,KAAK,KAAK,MAAO,UAAS,IAAI,CAAC;AAC1C,qBAAW,KAAK,KAAK,MAAO,UAAS,IAAI,CAAC;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAEA,QAAI,gBAAgB,EAAG,QAAO;AAE9B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,aAAa,MAAM,eAAe,KAAK,aAAa,IAAI,WAAW,KAAK,aAAa,WAAW;AAAA,MAChG;AAAA,MACA;AAAA,MACA,aAAa,gBAAgB;AAAA,MAC7B;AAAA,MACA,QAAQ,MAAM,KAAK,QAAQ;AAAA,MAC3B,aAAa;AAAA,QACX,OAAO,MAAM,KAAK,QAAQ;AAAA,QAC1B,OAAO,MAAM,KAAK,QAAQ;AAAA,QAC1B,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WACE,MACA,QAAQ,IACiB;AACzB,WAAO,KAAK,cAAc,IAAI,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW,EAC5C,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,iBACE,MACA,QAAQ,IACiB;AACzB,WAAO,KAAK,cAAc,IAAI,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW,EAC5C,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,iBAAiB,OAAe,MAAqB,QAAQ,IAAyB;AACpF,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,QAAI,QAAQ,KAAK,SAAS,KAAK,QAAQ,QAAQ,OAAQ,QAAO;AAE9D,UAAM,SAAS,KAAK,QAAQ,QAAQ,KAAK;AACzC,UAAM,aAAyC,CAAC;AAEhD,eAAW,CAAC,IAAI,cAAc,KAAK,OAAO,sBAAsB;AAC9D,YAAM,eAAe,OAAO,mBAAmB,IAAI,EAAE,KAAK;AAC1D,YAAM,OAAO,OAAO,mBAAmB,IAAI,EAAE;AAC7C,iBAAW,KAAK;AAAA,QACd;AAAA,QACA,aAAa,KAAK,QAAQ,EAAE,GAAG,eAAe,KAAK,aAAa,IAAI,EAAE,KAAK,aAAa,EAAE;AAAA,QAC1F;AAAA,QACA;AAAA,QACA,QAAQ,OAAO,eAAe,IAAI,IAAI,CAAC;AAAA,QACvC,aAAa,OAAO,mBAAmB,IAAI,IAAI,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AAAA,MACnF,CAAC;AAAA,IACH;AAEA,eAAW,KAAK,CAAC,GAAG,MAAM,EAAE,eAAe,EAAE,YAAY;AAEzD,UAAM,aAAa,WAAW;AAE9B,WAAO;AAAA,MACL;AAAA,MACA,WAAW,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,YAAY,QAAQ,IAAI,WAAW,MAAM,GAAG,KAAK,IAAI;AAAA,MACrD,iBAAiB;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,YAAY,OAAiC;AAC3C,QAAI,CAAC,KAAK,QAAS,QAAO,CAAC;AAE3B,UAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,CAAC,QAAQ,WAAW;AAAA,MAC3D;AAAA,MACA,WAAW,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO,qBAAqB;AAAA,IAC9C,EAAE;AAEF,QAAI,MAAO,QAAO,QAAQ,MAAM,GAAG,KAAK;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,MAAiD;AAC7D,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,WAAO,gBAAgB,KAAK,SAAS,IAAI;AAAA,EAC3C;AAAA,EAEQ,cAAc,MAA8C;AAClE,QAAI,CAAC,KAAK,QAAS,QAAO,CAAC;AAG3B,UAAM,eAAe,oBAAI,IAAY;AACrC,eAAW,UAAU,KAAK,QAAQ,SAAS;AACzC,iBAAW,MAAM,OAAO,qBAAqB,KAAK,GAAG;AACnD,qBAAa,IAAI,EAAE;AAAA,MACrB;AAAA,IACF;AAEA,UAAM,UAAmC,CAAC;AAC1C,eAAW,MAAM,cAAc;AAC7B,YAAM,SAAS,KAAK,UAAU,IAAI,IAAI;AACtC,UAAI,OAAQ,SAAQ,KAAK,MAAM;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eACP,KACA,QACM;AACN,MAAI,IAAI,WAAW,EAAG;AAGtB,MAAI,MAAM,QAAQ,IAAI,CAAC,CAAC,GAAG;AAEzB,eAAW,CAAC,IAAI,QAAQ,KAAK,KAAgC;AAC3D,aAAO,IAAI,IAAI,QAAQ;AAAA,IACzB;AAAA,EACF,OAAO;AAEL,UAAM,OAAO;AACb,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,aAAO,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AAAA,IACjC;AAAA,EACF;AACF;AAEA,SAAS,eAAe,MAAwC;AAC9D,QAAM,SAAwB,CAAC;AAC/B,MAAI,KAAK,cAAc;AACrB,WAAO,KAAK,aAAa;AACzB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,KAAK,MAAM,SAAS,EAAG,QAAO,KAAK,eAAe;AACpE,MAAI,KAAK,SAAS,KAAK,MAAM,SAAS,EAAG,QAAO,KAAK,eAAe;AACpE,MAAI,KAAK,eAAgB,QAAO,KAAK,eAAe;AAEpD,MAAI,OAAO,WAAW,EAAG,QAAO,KAAK,iBAAiB;AACtD,SAAO;AACT;AAEA,SAAS,mBAAmB,MAAsC;AAChE,SAAO;AAAA,IACL,OAAO,KAAK,SAAS,CAAC;AAAA,IACtB,OAAO,KAAK,SAAS,CAAC;AAAA,IACtB,OAAO,KAAK,SAAS,CAAC;AAAA,EACxB;AACF;;;AJ7XA,IAAM,oBAAoB,KAAK;AAAA,EAC7B,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAAA,EAC/C;AACF;AAEA,IAAI,YAAY;AAEhB,SAAS,gBAAwB;AAC/B,SAAO,KAAK,KAAK,WAAW,aAAa;AAC3C;AAEA,SAAS,oBAA4B;AACnC,SAAO,KAAK,KAAK,WAAW,aAAa;AAC3C;AAKA,SAAS,iBACP,OACA,MACM;AACN,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,MAAO,MAAK,QAAQ,KAAK,SAAS,KAAK,EAAE;AACnD,QAAI,CAAC,KAAK,MAAM;AACd,YAAM,OAAO,KAAK,QAAQ,KAAK,EAAE;AACjC,UAAI,KAAM,MAAK,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;AAEA,IAAM,SAAN,MAAa;AAAA,EACH,YAA+B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,KAAK,IAAI;AAAA,EAE7B,YAAYC,OAAc;AACxB,SAAK,OAAOA;AACZ,SAAK,OAAO,IAAI,cAAc;AAC9B,SAAK,WAAW,IAAI,SAAS;AAC7B,SAAK,SAAS,IAAI,eAAeA,OAAM,KAAK,MAAM,KAAK,QAAQ;AAAA,EACjE;AAAA,EAEA,MAAM,QAAuB;AAE3B,OAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAG3C,UAAM,aAAa,cAAc;AACjC,QAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,UAAI;AACF,WAAG,WAAW,UAAU;AAAA,MAC1B,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,KAAK,OAAO,MAAM;AAGxB,UAAM,KAAK,SAAS,UAAU;AAG9B,QAAI;AACJ,QAAI;AACF,mBAAa,GAAG,SAAS,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ,EAAE;AAAA,IAC9D,QAAQ;AAAA,IAER;AACA,UAAM,OAAmB;AAAA,MACvB,KAAK,QAAQ;AAAA,MACb,MAAM,KAAK;AAAA,MACX;AAAA,MACA,WAAW,KAAK;AAAA,MAChB;AAAA,IACF;AACA,OAAG,cAAc,kBAAkB,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAEnE,YAAQ,IAAI,uBAAuB,QAAQ,GAAG,UAAU,KAAK,IAAI,GAAG;AAGpE,UAAM,WAAW,MAAM;AACrB,WAAK,KAAK;AACV,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,GAAG,WAAW,QAAQ;AAC9B,YAAQ,GAAG,UAAU,QAAQ;AAAA,EAC/B;AAAA,EAEQ,SAAS,YAAmC;AAClD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,YAAY,IAAI,aAAa,CAAC,SAAS;AAC1C,YAAI,SAAS;AAEb,aAAK,GAAG,QAAQ,CAAC,UAAU;AACzB,oBAAU,MAAM,SAAS;AAGzB,cAAI;AACJ,kBAAQ,aAAa,OAAO,QAAQ,IAAI,OAAO,IAAI;AACjD,kBAAM,OAAO,OAAO,MAAM,GAAG,UAAU;AACvC,qBAAS,OAAO,MAAM,aAAa,CAAC;AAEpC,gBAAI;AACF,oBAAM,MAAkB,KAAK,MAAM,IAAI;AACvC,mBAAK,cAAc,KAAK,IAAI,EAAE,KAAK,CAAC,aAAa;AAC/C,oBAAI,CAAC,KAAK,WAAW;AACnB,uBAAK,MAAM,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,gBAC5C;AAAA,cACF,CAAC;AAAA,YACH,QAAQ;AACN,oBAAM,WAAwB;AAAA,gBAC5B,IAAI;AAAA,gBACJ,OAAO;AAAA,cACT;AACA,mBAAK,MAAM,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,YAC5C;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,WAAK,UAAU,GAAG,SAAS,MAAM;AAEjC,WAAK,UAAU,OAAO,YAAY,MAAM;AACtC,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,cAAc,KAAiB,MAAwC;AACnF,QAAI;AACF,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,iBAAO,EAAE,IAAI,MAAM,MAAM,OAAO;AAAA,QAElC,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM;AAAA,cACJ,eAAe;AAAA,cACf,MAAM,KAAK;AAAA,cACX,eAAe,KAAK,OAAO,qBAAqB;AAAA,cAChD,gBAAgB,KAAK,KAAK,kBAAkB;AAAA,cAC5C,iBAAiB,KAAK,SAAS,SAAS;AAAA,cACxC,QAAQ,KAAK,IAAI,IAAI,KAAK;AAAA,cAC1B,YAAY,KAAK,OAAO,oBAAoB;AAAA,YAC9C;AAAA,UACF;AAAA,QAEF,KAAK,YAAY;AACf,gBAAM,WAAW,KAAK,KAAK,QAAQ,IAAI,KAAK;AAC5C,gBAAM,WAAwB,EAAE,IAAI,MAAM,MAAM,SAAS;AACzD,cAAI,SAAS,WAAW,GAAG;AACzB,kBAAM,SAAS,KAAK,OAAO,oBAAoB;AAC/C,gBAAI,OAAO,oBAAoB,OAAO,kBAAkB,KAAK,OAAO,qBAAqB,MAAM;AAC7F,oBAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,OAAO,oBAAoB,GAAI;AACpE,uBAAS,OAAO,oBAAoB,GAAG;AAAA,YACzC;AAAA,UACF;AACA,iBAAO;AAAA,QACT;AAAA,QAEA,KAAK,iBAAiB;AACpB,gBAAM,aAAa,KAAK,KAAK,UAAU,IAAI,EAAE;AAC7C,cAAI,eAAe,QAAW;AAC5B,mBAAO,EAAE,IAAI,OAAO,OAAO,aAAa,IAAI,EAAE,aAAa;AAAA,UAC7D;AACA,gBAAM,UAAU,MAAM,KAAK,OAAO,eAAe,UAAU;AAC3D,cAAI,CAAC,SAAS;AACZ,mBAAO,EAAE,IAAI,OAAO,OAAO,aAAa,IAAI,EAAE,aAAa;AAAA,UAC7D;AAEA,gBAAM,QAAQ,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK;AACpD,iBAAO,EAAE,IAAI,MAAM,MAAM,SAAS,MAAM;AAAA,QAC1C;AAAA,QAEA,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM,KAAK,KAAK,WAAW,IAAI,MAAM,IAAI,KAAK;AAAA,UAChD;AAAA,QAEF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM,KAAK,KAAK,eAAe;AAAA,UACjC;AAAA,QAEF,KAAK;AACH,eAAK,SAAS,MAAM,IAAI,IAAI;AAE5B,qBAAW,MAAM,KAAK,KAAK,cAAc,GAAG;AAC1C,kBAAM,OAAO,KAAK,KAAK,QAAQ,EAAE;AACjC,gBAAI,KAAM,MAAK,SAAS,eAAe,IAAI,KAAK,WAAW;AAAA,UAC7D;AACA,eAAK,OAAO,eAAe;AAC3B,iBAAO,EAAE,IAAI,MAAM,MAAM,oBAAoB;AAAA,QAE/C,KAAK,gBAAgB;AACnB,gBAAM,KAAK,OAAO,wBAAwB;AAC1C,gBAAM,UAAU,KAAK,SAAS,KAAK,KAAK,IAAI;AAC5C,cAAI,CAAC,SAAS;AACZ,mBAAO,EAAE,IAAI,OAAO,OAAO,8BAA8B;AAAA,UAC3D;AACA,2BAAiB,QAAQ,uBAAuB,KAAK,IAAI;AACzD,iBAAO,EAAE,IAAI,MAAM,MAAM,QAAQ;AAAA,QACnC;AAAA,QAEA,KAAK,kBAAkB;AACrB,gBAAM,iBAAiB,KAAK,KAAK,UAAU,IAAI,WAAW;AAC1D,cAAI,mBAAmB,QAAW;AAChC,mBAAO,EAAE,IAAI,OAAO,OAAO,aAAa,IAAI,WAAW,aAAa;AAAA,UACtE;AACA,gBAAM,SAAS,KAAK,SAAS,UAAU,gBAAgB,KAAK,IAAI;AAChE,cAAI,CAAC,QAAQ;AACX,mBAAO;AAAA,cACL,IAAI;AAAA,cACJ,OAAO,mCAAmC,IAAI,WAAW;AAAA,YAC3D;AAAA,UACF;AACA,2BAAiB,CAAC,MAAM,GAAG,KAAK,IAAI;AACpC,gBAAM,YAAY,OAAO,IAAI,gBAAgB,WAAW,IAAI,cAAc;AAC1E,iBAAO,EAAE,IAAI,MAAM,MAAM,QAAQ,OAAO,UAAU;AAAA,QACpD;AAAA,QAEA,KAAK,gBAAgB;AACnB,gBAAM,UAAU,KAAK,SAAS,WAAW,KAAK,MAAM,IAAI,KAAK;AAC7D,2BAAiB,SAAS,KAAK,IAAI;AACnC,iBAAO,EAAE,IAAI,MAAM,MAAM,QAAQ;AAAA,QACnC;AAAA,QAEA,KAAK,qBAAqB;AACxB,gBAAM,YAAY,KAAK,SAAS,iBAAiB,KAAK,MAAM,IAAI,KAAK;AACrE,2BAAiB,WAAW,KAAK,IAAI;AACrC,iBAAO,EAAE,IAAI,MAAM,MAAM,UAAU;AAAA,QACrC;AAAA,QAEA,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM,KAAK,SAAS,YAAY,IAAI,KAAK;AAAA,UAC3C;AAAA,QAEF,KAAK,kBAAkB;AACrB,gBAAM,SAAS,KAAK,SAAS,iBAAiB,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK;AAC7E,cAAI,CAAC,QAAQ;AACX,mBAAO,EAAE,IAAI,OAAO,OAAO,WAAW,IAAI,KAAK,aAAa;AAAA,UAC9D;AACA,2BAAiB,OAAO,YAAY,KAAK,IAAI;AAC7C,iBAAO,EAAE,IAAI,MAAM,MAAM,OAAO;AAAA,QAClC;AAAA,QAEA,KAAK,kBAAkB;AACrB,gBAAM,aAAa,KAAK,SAAS,cAAc,KAAK,IAAI;AACxD,cAAI,CAAC,YAAY;AACf,mBAAO,EAAE,IAAI,OAAO,OAAO,6DAA6D;AAAA,UAC1F;AACA,iBAAO,EAAE,IAAI,MAAM,MAAM,WAAW;AAAA,QACtC;AAAA,QAEA,KAAK;AACH,iBAAO,KAAK,WAAW,KAAK,IAAI;AAAA,QAElC;AACE,iBAAO,EAAE,IAAI,OAAO,OAAO,oBAAqB,IAAY,IAAI,GAAG;AAAA,MACvE;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,WACN,KACA,MACsB;AACtB,UAAM,UAAU,IAAI,WAAW;AAG/B,QAAI,KAAK,mBAAmB,GAAG,GAAG;AAChC,aAAO,QAAQ,QAAQ,EAAE,IAAI,MAAM,MAAM,EAAE,KAAK,MAAM,WAAW,IAAI,UAAU,EAAE,CAAC;AAAA,IACpF;AAEA,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAI,UAAU;AACd,YAAM,SAAS,CAAC,aAA0B;AACxC,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAClB,oBAAY;AACZ,aAAK,eAAe,SAAS,OAAO;AACpC,gBAAQ,QAAQ;AAAA,MAClB;AAEA,YAAM,cAAc,KAAK,OAAO,cAAc,MAAM;AAClD,YAAI,KAAK,mBAAmB,GAAG,GAAG;AAChC,iBAAO,EAAE,IAAI,MAAM,MAAM,EAAE,KAAK,MAAM,WAAW,IAAI,UAAU,EAAE,CAAC;AAAA,QACpE;AAAA,MACF,CAAC;AAED,YAAM,QAAQ,WAAW,MAAM;AAC7B,eAAO,EAAE,IAAI,MAAM,MAAM,EAAE,KAAK,OAAO,WAAW,IAAI,WAAW,SAAS,KAAK,EAAE,CAAC;AAAA,MACpF,GAAG,OAAO;AAEV,YAAM,UAAU,MAAM;AACpB,eAAO,EAAE,IAAI,OAAO,OAAO,sBAAsB,CAAC;AAAA,MACpD;AACA,WAAK,GAAG,SAAS,OAAO;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB,KAAqD;AAC9E,YAAQ,IAAI,WAAW;AAAA,MACrB,KAAK;AACH,eAAO,KAAK,OAAO,qBAAqB,IAAI;AAAA,MAC9C,KAAK;AACH,eAAO,KAAK,KAAK,WAAW,IAAI,MAAM,IAAI,EAAE,SAAS;AAAA,MACvD;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEA,OAAa;AACX,SAAK,OAAO,KAAK;AACjB,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AAAA,IACnB;AAEA,QAAI;AACF,SAAG,WAAW,cAAc,CAAC;AAAA,IAC/B,QAAQ;AAAA,IAER;AACA,QAAI;AACF,SAAG,WAAW,kBAAkB,CAAC;AAAA,IACnC,QAAQ;AAAA,IAER;AACA,YAAQ,IAAI,gBAAgB;AAAA,EAC9B;AACF;AAIA,IAAM,UAAU,QAAQ,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC;AAChE,IAAM,OAAO,UAAU,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI;AAE7D,IAAM,cAAc,QAAQ,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,cAAc,CAAC;AACzE,IAAI,aAAa;AACf,cAAY,YAAY,MAAM,GAAG,EAAE,CAAC;AACtC;AAEA,IAAM,SAAS,IAAI,OAAO,IAAI;AAC9B,OAAO,MAAM,EAAE,MAAM,CAAC,QAAQ;AAC5B,UAAQ,MAAM,2BAA2B,GAAG;AAC5C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["port","pending","port"]}
|