mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
Revert "feat: enhance React profiler session handling with device ID support"
This reverts commit 1efa4c001e.
This commit is contained in:
@@ -108,13 +108,10 @@ export const jsRuntimeDebuggerBlueprint: ServiceBlueprint<JsRuntimeDebuggerApi,
|
||||
},
|
||||
|
||||
async factory(_deps, payload, options?) {
|
||||
// payload is either "port" or "port:deviceId"
|
||||
const colonIdx = payload.indexOf(":");
|
||||
const port = colonIdx >= 0 ? parseInt(payload.slice(0, colonIdx), 10) : parseInt(payload, 10);
|
||||
const deviceId = colonIdx >= 0 ? payload.slice(colonIdx + 1) : undefined;
|
||||
const port = parseInt(payload, 10);
|
||||
|
||||
const metro = await discoverMetro(port);
|
||||
const selected = selectTarget(metro.targets, port, { ...options, ...(deviceId && { deviceId }) });
|
||||
const selected = selectTarget(metro.targets, port, options);
|
||||
|
||||
const cdp = new CDPClient(selected.webSocketUrl);
|
||||
await cdp.connect();
|
||||
|
||||
@@ -38,15 +38,10 @@ export interface ProfilerSessionPaths {
|
||||
anyCompilerOptimized: boolean | null;
|
||||
hotCommitIndices: number[] | null;
|
||||
totalReactCommits: number | null;
|
||||
deviceId: string | null;
|
||||
deviceName: string | null;
|
||||
appName: string | null;
|
||||
projectRoot: string | null;
|
||||
}
|
||||
|
||||
export interface ReactProfilerSessionApi {
|
||||
port: number;
|
||||
deviceId: string | null;
|
||||
cdp: CDPClient;
|
||||
projectRoot: string;
|
||||
hermesVersion: string;
|
||||
@@ -64,17 +59,12 @@ export interface ReactProfilerSessionApi {
|
||||
export const reactProfilerSessionBlueprint: ServiceBlueprint<ReactProfilerSessionApi, string> = {
|
||||
namespace: REACT_PROFILER_SESSION_NAMESPACE,
|
||||
|
||||
// payload is either "port" or "port:deviceId"
|
||||
getURN(payload: string) {
|
||||
return `${REACT_PROFILER_SESSION_NAMESPACE}:${payload}`;
|
||||
getURN(port: string) {
|
||||
return `${REACT_PROFILER_SESSION_NAMESPACE}:${port}`;
|
||||
},
|
||||
|
||||
getDependencies(payload: string) {
|
||||
const colonIdx = payload.indexOf(":");
|
||||
const portStr = colonIdx >= 0 ? payload.slice(0, colonIdx) : payload;
|
||||
const deviceId = colonIdx >= 0 ? payload.slice(colonIdx + 1) : undefined;
|
||||
const depPayload = deviceId ? `${portStr}:${deviceId}` : portStr;
|
||||
return { debugger: `JsRuntimeDebugger:${depPayload}` };
|
||||
getDependencies(port: string) {
|
||||
return { debugger: `JsRuntimeDebugger:${port}` };
|
||||
},
|
||||
|
||||
async factory(deps, _payload) {
|
||||
@@ -91,7 +81,6 @@ export const reactProfilerSessionBlueprint: ServiceBlueprint<ReactProfilerSessio
|
||||
|
||||
const state: ReactProfilerSessionApi = {
|
||||
port: debuggerApi.port,
|
||||
deviceId: debuggerApi.logicalDeviceId ?? null,
|
||||
cdp,
|
||||
projectRoot: debuggerApi.projectRoot,
|
||||
hermesVersion: "unknown",
|
||||
@@ -167,11 +156,6 @@ export const reactProfilerSessionBlueprint: ServiceBlueprint<ReactProfilerSessio
|
||||
}
|
||||
|
||||
cdp.events.on("disconnected", (error) => {
|
||||
// Only clear cache if profiling was in progress — preserves data from a completed session
|
||||
// that survived app restart, while preventing stale in-flight data from being returned.
|
||||
if (state.profilingActive) {
|
||||
clearCachedProfilerPaths(state.port, state.deviceId ?? undefined);
|
||||
}
|
||||
events.emit("terminated", error ?? new Error("CDP disconnected"));
|
||||
});
|
||||
|
||||
@@ -186,27 +170,16 @@ export const reactProfilerSessionBlueprint: ServiceBlueprint<ReactProfilerSessio
|
||||
},
|
||||
};
|
||||
|
||||
const profilerPathsCache = new Map<string, ProfilerSessionPaths>();
|
||||
const profilerPathsCache = new Map<number, ProfilerSessionPaths>();
|
||||
|
||||
function cacheKey(port: number, deviceId?: string): string {
|
||||
return deviceId ? `${port}:${deviceId}` : `${port}`;
|
||||
export function cacheProfilerPaths(port: number, paths: ProfilerSessionPaths): void {
|
||||
profilerPathsCache.set(port, paths);
|
||||
}
|
||||
|
||||
export function cacheProfilerPaths(
|
||||
port: number,
|
||||
paths: ProfilerSessionPaths,
|
||||
deviceId?: string
|
||||
): void {
|
||||
profilerPathsCache.set(cacheKey(port, deviceId), paths);
|
||||
export function getCachedProfilerPaths(port: number): ProfilerSessionPaths | undefined {
|
||||
return profilerPathsCache.get(port);
|
||||
}
|
||||
|
||||
export function getCachedProfilerPaths(
|
||||
port: number,
|
||||
deviceId?: string
|
||||
): ProfilerSessionPaths | undefined {
|
||||
return profilerPathsCache.get(cacheKey(port, deviceId));
|
||||
}
|
||||
|
||||
export function clearCachedProfilerPaths(port: number, deviceId?: string): void {
|
||||
profilerPathsCache.delete(cacheKey(port, deviceId));
|
||||
export function clearCachedProfilerPaths(port: number): void {
|
||||
profilerPathsCache.delete(port);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import { getCachedProfilerPaths } from "../../../blueprints/react-profiler-session";
|
||||
import {
|
||||
REACT_PROFILER_SESSION_NAMESPACE,
|
||||
type ReactProfilerSessionApi,
|
||||
getCachedProfilerPaths,
|
||||
} from "../../../blueprints/react-profiler-session";
|
||||
import {
|
||||
IOS_PROFILER_SESSION_NAMESPACE,
|
||||
type IosProfilerSessionApi,
|
||||
@@ -44,9 +48,11 @@ Returns a markdown report correlating hangs with React commits, memory leaks, an
|
||||
Fails if either react-profiler-analyze or ios-profiler-analyze has not been called first.`,
|
||||
zodSchema,
|
||||
services: (params) => ({
|
||||
reactSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
iosSession: `${IOS_PROFILER_SESSION_NAMESPACE}:${params.device_id}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
async execute(services) {
|
||||
const reactApi = services.reactSession as ReactProfilerSessionApi;
|
||||
const iosApi = services.iosSession as IosProfilerSessionApi;
|
||||
|
||||
// Validate prerequisites
|
||||
@@ -54,8 +60,7 @@ Fails if either react-profiler-analyze or ios-profiler-analyze has not been call
|
||||
throw new Error("No iOS Instruments data. Run ios-profiler-analyze first.");
|
||||
}
|
||||
|
||||
// Read-only: resolve react paths from cache only — no live CDP connection needed.
|
||||
const sessionPaths = getCachedProfilerPaths(params.port, params.device_id);
|
||||
const sessionPaths = reactApi.sessionPaths ?? getCachedProfilerPaths(reactApi.port);
|
||||
if (!sessionPaths?.commitsPath) {
|
||||
throw new Error("No React commit data. Run react-profiler-analyze first.");
|
||||
}
|
||||
@@ -71,7 +76,7 @@ Fails if either react-profiler-analyze or ios-profiler-analyze has not been call
|
||||
cpuProfile = await readCpuProfile(sessionPaths.cpuProfilePath);
|
||||
}
|
||||
|
||||
const reactWallStart = onDisk.meta?.profileStartWallMs ?? null;
|
||||
const reactWallStart = reactApi.profileStartWallMs ?? onDisk.meta?.profileStartWallMs ?? null;
|
||||
const iosWallStart = iosApi.wallClockStartMs;
|
||||
|
||||
if (!reactWallStart && !iosWallStart) {
|
||||
@@ -98,7 +103,7 @@ Fails if either react-profiler-analyze or ios-profiler-analyze has not been call
|
||||
|
||||
// Build hot commit summaries from raw data
|
||||
const preprocessed = preprocess(commitTree.commits);
|
||||
const hotIndices = sessionPaths.hotCommitIndices ?? [];
|
||||
const hotIndices = sessionPaths.hotCommitIndices ?? reactApi.hotCommitIndices ?? [];
|
||||
const hotCommits = buildHotCommitSummaries(preprocessed, hotIndices);
|
||||
const nonMarginCommits = hotCommits.filter((c) => !c.isMargin);
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import { getCachedProfilerPaths } from "../../../blueprints/react-profiler-session";
|
||||
import {
|
||||
REACT_PROFILER_SESSION_NAMESPACE,
|
||||
type ReactProfilerSessionApi,
|
||||
getCachedProfilerPaths,
|
||||
} from "../../../blueprints/react-profiler-session";
|
||||
import type {
|
||||
DevToolsFiberCommit,
|
||||
DevToolsCommitTree,
|
||||
@@ -15,12 +19,6 @@ const timeRangeSchema = z.object({
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Must match the value passed to react-profiler-start/stop."
|
||||
),
|
||||
mode: z
|
||||
.enum(["by_component", "by_time_range", "by_index", "cascade_tree"])
|
||||
.describe(
|
||||
@@ -42,11 +40,8 @@ const zodSchema = z.object({
|
||||
.describe("Max results to return (default 20)"),
|
||||
});
|
||||
|
||||
async function getCommitTree(
|
||||
port: number,
|
||||
deviceId: string | undefined
|
||||
): Promise<DevToolsCommitTree> {
|
||||
const sessionPaths = getCachedProfilerPaths(port, deviceId);
|
||||
async function getCommitTree(api: ReactProfilerSessionApi): Promise<DevToolsCommitTree> {
|
||||
const sessionPaths = api.sessionPaths ?? getCachedProfilerPaths(api.port);
|
||||
if (!sessionPaths?.commitsPath) {
|
||||
throw new Error(
|
||||
"No commit data stored. Run react-profiler-start → exercise app → react-profiler-stop first."
|
||||
@@ -331,9 +326,12 @@ Use when drilling into specific components or time windows after react-profiler-
|
||||
Returns a markdown table or tree of commit data matching the requested mode.
|
||||
Fails if react-profiler-stop has not been called or no commit data is stored.`,
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
const commitTree = await getCommitTree(params.port, params.device_id);
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
const commitTree = await getCommitTree(api);
|
||||
|
||||
switch (params.mode) {
|
||||
case "by_component": {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import {
|
||||
REACT_PROFILER_SESSION_NAMESPACE,
|
||||
type ReactProfilerSessionApi,
|
||||
type ProfilerSessionPaths,
|
||||
getCachedProfilerPaths,
|
||||
} from "../../../blueprints/react-profiler-session";
|
||||
@@ -22,12 +24,6 @@ const timeWindowSchema = z.object({
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Must match the value passed to react-profiler-start/stop."
|
||||
),
|
||||
mode: z
|
||||
.enum(["top_functions", "time_window", "call_tree", "component_cpu"])
|
||||
.describe(
|
||||
@@ -51,7 +47,7 @@ const zodSchema = z.object({
|
||||
.describe("For call_tree mode: also show callers of the function"),
|
||||
});
|
||||
|
||||
async function getIndex(sessionPaths: ProfilerSessionPaths): Promise<{
|
||||
async function getIndex(api: ReactProfilerSessionApi): Promise<{
|
||||
index: CpuSampleIndex;
|
||||
commitTree: {
|
||||
commits: {
|
||||
@@ -62,6 +58,9 @@ async function getIndex(sessionPaths: ProfilerSessionPaths): Promise<{
|
||||
}[];
|
||||
} | null;
|
||||
}> {
|
||||
const sessionPaths: ProfilerSessionPaths | undefined =
|
||||
api.sessionPaths ?? getCachedProfilerPaths(api.port) ?? undefined;
|
||||
|
||||
if (!sessionPaths?.cpuProfilePath) {
|
||||
throw new Error(
|
||||
"No CPU profile stored. Run react-profiler-start → exercise the app → react-profiler-stop → react-profiler-analyze first."
|
||||
@@ -349,15 +348,12 @@ Use when investigating JS CPU hotspots or correlating CPU cost with specific com
|
||||
Returns a markdown table of CPU hotspots, call tree, or per-component CPU breakdown.
|
||||
Fails if no CPU profile is stored — run react-profiler-stop first.`,
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
const sessionPaths = getCachedProfilerPaths(params.port, params.device_id);
|
||||
if (!sessionPaths) {
|
||||
throw new Error(
|
||||
"No profiling data stored. Run react-profiler-start → exercise the app → react-profiler-stop → react-profiler-analyze first."
|
||||
);
|
||||
}
|
||||
const { index, commitTree } = await getIndex(sessionPaths);
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
const { index, commitTree } = await getIndex(api);
|
||||
|
||||
switch (params.mode) {
|
||||
case "top_functions":
|
||||
|
||||
@@ -38,10 +38,7 @@ const zodSchema = z.object({
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Required for load_instruments. " +
|
||||
"For load_react: caches the session under this device ID so query tools can look it up by port+device."
|
||||
),
|
||||
.describe("iOS Simulator UDID — required for load_instruments to populate the iOS session"),
|
||||
});
|
||||
|
||||
async function listSessions(debugDir: string): Promise<string> {
|
||||
@@ -122,8 +119,7 @@ async function listSessions(debugDir: string): Promise<string> {
|
||||
async function loadReactSession(
|
||||
debugDir: string,
|
||||
sessionId: string,
|
||||
port: number,
|
||||
deviceId?: string
|
||||
port: number
|
||||
): Promise<string> {
|
||||
const cpuPath = path.join(debugDir, `react-profiler-${sessionId}_cpu.json`);
|
||||
const commitsPath = path.join(debugDir, `react-profiler-${sessionId}_commits.json`);
|
||||
@@ -203,13 +199,9 @@ async function loadReactSession(
|
||||
anyCompilerOptimized,
|
||||
hotCommitIndices,
|
||||
totalReactCommits,
|
||||
deviceId: deviceId ?? null,
|
||||
deviceName: null,
|
||||
appName: null,
|
||||
projectRoot: null,
|
||||
};
|
||||
|
||||
cacheProfilerPaths(port, sessionPaths, deviceId);
|
||||
cacheProfilerPaths(port, sessionPaths);
|
||||
|
||||
const lines: string[] = [
|
||||
`Loaded React profiler session \`${sessionId}\` into port ${port}.`,
|
||||
@@ -319,7 +311,7 @@ Fails if the session_id is not found or required XML files are missing from disk
|
||||
"load_react mode requires the session_id parameter. Use list mode first."
|
||||
);
|
||||
}
|
||||
return loadReactSession(debugDir, params.session_id, params.port, params.device_id);
|
||||
return loadReactSession(debugDir, params.session_id, params.port);
|
||||
}
|
||||
|
||||
case "load_instruments": {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { z } from "zod";
|
||||
import { promises as fsPromises } from "fs";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import {
|
||||
REACT_PROFILER_SESSION_NAMESPACE,
|
||||
type ReactProfilerSessionApi,
|
||||
type ProfilerSessionPaths,
|
||||
getCachedProfilerPaths,
|
||||
} from "../../../blueprints/react-profiler-session";
|
||||
@@ -31,12 +33,6 @@ const annotationSchema = z.object({
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Must match the value passed to react-profiler-start/stop."
|
||||
),
|
||||
project_root: z
|
||||
.string()
|
||||
.describe("Absolute path to the RN project root for session context detection"),
|
||||
@@ -71,13 +67,15 @@ is returned by react-profiler-start.
|
||||
Use when the profiling session is complete and you need to interpret the collected data.
|
||||
Fails if react-profiler-stop has not been called or no profiling data is stored.`,
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
// Read-only: resolve paths from cache only — no live CDP connection needed.
|
||||
const sessionPaths: ProfilerSessionPaths | undefined = getCachedProfilerPaths(
|
||||
params.port,
|
||||
params.device_id
|
||||
);
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
|
||||
// Resolve session paths from session or cache
|
||||
const sessionPaths: ProfilerSessionPaths | undefined =
|
||||
api.sessionPaths ?? getCachedProfilerPaths(api.port) ?? undefined;
|
||||
|
||||
if (!sessionPaths) {
|
||||
throw new Error(
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { z } from "zod";
|
||||
import { promises as fs } from "fs";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import { REACT_PROFILER_SESSION_NAMESPACE } from "../../../blueprints/react-profiler-session";
|
||||
import { buildAstIndexWithDiagnostics } from "../../../utils/react-profiler/pipeline/06-resolve/ast-index";
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
component_name: z.string().describe("Name of the React component to look up"),
|
||||
project_root: z.string().describe("Absolute path to the RN project root"),
|
||||
});
|
||||
@@ -17,7 +19,9 @@ export const reactProfilerComponentSourceTool: ToolDefinition<
|
||||
Call this per-finding after react-profiler-analyze to inspect source before proposing a fix.
|
||||
Returns found: false if the component is not found in user-owned code (e.g. lives in node_modules).`,
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(_services, params) {
|
||||
const astIndex = await buildAstIndexWithDiagnostics(params.project_root);
|
||||
const entry = astIndex.index.get(params.component_name);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import type { ToolDefinition } from "@argent/registry";
|
||||
import { getCachedProfilerPaths } from "../../../blueprints/react-profiler-session";
|
||||
import {
|
||||
REACT_PROFILER_SESSION_NAMESPACE,
|
||||
type ReactProfilerSessionApi,
|
||||
getCachedProfilerPaths,
|
||||
} from "../../../blueprints/react-profiler-session";
|
||||
import type {
|
||||
HermesProfileNode,
|
||||
HermesCpuProfile,
|
||||
@@ -10,12 +14,6 @@ import { isArgentProfilerFunction } from "../../../utils/react-profiler/pipeline
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Must match the value passed to react-profiler-start/stop."
|
||||
),
|
||||
top_n: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
@@ -125,9 +123,13 @@ Call react-profiler-stop first. Reads directly from the stored cpuProfile.
|
||||
Returns a markdown table of the top hotspot functions with self-time, total-time, and location.
|
||||
Fails if react-profiler-stop has not been called or no CPU profile is stored.`,
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
const sessionPaths = getCachedProfilerPaths(params.port, params.device_id);
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
|
||||
const sessionPaths = api.sessionPaths ?? getCachedProfilerPaths(api.port);
|
||||
if (!sessionPaths?.cpuProfilePath) {
|
||||
throw new Error(
|
||||
"No CPU profile stored. Call react-profiler-start, exercise the app, then react-profiler-stop."
|
||||
|
||||
@@ -90,12 +90,6 @@ function buildFiberTreeScript(maxDepth: number, filter: string): string {
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Required when multiple simulators are connected to the same Metro port."
|
||||
),
|
||||
max_depth: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
@@ -113,7 +107,7 @@ Returns a nested JSON tree of fiber nodes with name, tag, actualDuration, selfBa
|
||||
Fails if the React DevTools hook is not present or no fiber roots have been committed yet.`,
|
||||
zodSchema,
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}${params.device_id ? `:${params.device_id}` : ""}`,
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
|
||||
@@ -91,12 +91,6 @@ function renderMarkdownTable(entries: RenderEntry[]): string {
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Required when multiple simulators are connected to the same Metro port."
|
||||
),
|
||||
top_n: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
@@ -113,7 +107,7 @@ Use when you want a quick snapshot of render counts without a full profiling ses
|
||||
Fails if the React DevTools hook is not present in the runtime or the app is not connected.`,
|
||||
zodSchema,
|
||||
services: (params) => ({
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}${params.device_id ? `:${params.device_id}` : ""}`,
|
||||
profilerSession: `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`,
|
||||
}),
|
||||
async execute(services, params) {
|
||||
const api = services.profilerSession as ReactProfilerSessionApi;
|
||||
|
||||
@@ -9,17 +9,12 @@ import { JS_RUNTIME_DEBUGGER_NAMESPACE } from "../../../blueprints/js-runtime-de
|
||||
|
||||
const COMMIT_CAPTURE_SCRIPT = `
|
||||
(function __argent_commitCaptureInit() {
|
||||
// Always reset the data array and commit index so each start() begins fresh.
|
||||
globalThis.__ARGENT_DEVTOOLS_COMMITS__ = [];
|
||||
globalThis.__ARGENT_DEVTOOLS_COMMIT_INDEX__ = 0;
|
||||
var hook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
if (!hook) return;
|
||||
// Idempotency guard: only wrap onCommitFiberRoot once per JS runtime lifetime.
|
||||
// Subsequent start() calls reset the arrays above but skip re-wrapping the hook,
|
||||
// preventing N nested wrappers (and N duplicate entries per commit) on re-use.
|
||||
if (hook.__argent_commit_capture__) return;
|
||||
hook.__argent_commit_capture__ = true;
|
||||
var origOnCommit = hook.onCommitFiberRoot;
|
||||
var commitIndex = 0;
|
||||
|
||||
function __argent_getChangedHookIndices(fiber) {
|
||||
if (!fiber.alternate) return null;
|
||||
@@ -51,7 +46,7 @@ const COMMIT_CAPTURE_SCRIPT = `
|
||||
|
||||
hook.onCommitFiberRoot = function __argent_onCommitFiberRoot(rendererID, root, priorityLevel) {
|
||||
var ts = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
|
||||
var idx = globalThis.__ARGENT_DEVTOOLS_COMMIT_INDEX__++;
|
||||
var idx = commitIndex++;
|
||||
var commitDur = (root && root.current && typeof root.current.actualDuration === 'number')
|
||||
? root.current.actualDuration : 0;
|
||||
var stack = root && root.current ? [root.current] : [];
|
||||
@@ -131,12 +126,6 @@ const COMMIT_CAPTURE_SCRIPT = `
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Required when multiple simulators are connected to the same Metro port. Omit to auto-select the first available target."
|
||||
),
|
||||
sample_interval_us: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
@@ -174,9 +163,8 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
const deviceSuffix = params.device_id ? `:${params.device_id}` : "";
|
||||
const jsdUrn = `${JS_RUNTIME_DEBUGGER_NAMESPACE}:${params.port}${deviceSuffix}`;
|
||||
const psUrn = `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}${deviceSuffix}`;
|
||||
const jsdUrn = `${JS_RUNTIME_DEBUGGER_NAMESPACE}:${params.port}`;
|
||||
const psUrn = `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`;
|
||||
const ignore = () => {};
|
||||
|
||||
async function disposeAndWait() {
|
||||
@@ -280,7 +268,7 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
|
||||
)
|
||||
.catch(ignore);
|
||||
|
||||
clearCachedProfilerPaths(api.port, api.deviceId ?? undefined);
|
||||
clearCachedProfilerPaths(api.port);
|
||||
api.sessionPaths = null;
|
||||
api.profilingActive = true;
|
||||
api.anyCompilerOptimized = null;
|
||||
|
||||
@@ -15,12 +15,6 @@ import { getDebugDir, writeDumpCompact } from "../../../utils/react-profiler/deb
|
||||
|
||||
const zodSchema = z.object({
|
||||
port: z.coerce.number().default(8081).describe("Metro server port"),
|
||||
device_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"iOS Simulator UDID (logicalDeviceId). Must match the value passed to react-profiler-start."
|
||||
),
|
||||
});
|
||||
|
||||
export function createReactProfilerStopTool(
|
||||
@@ -37,8 +31,7 @@ Fails if no active profiling session exists or the CDP connection was lost durin
|
||||
zodSchema,
|
||||
services: () => ({}),
|
||||
async execute(_services, params) {
|
||||
const deviceSuffix = params.device_id ? `:${params.device_id}` : "";
|
||||
const psUrn = `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}${deviceSuffix}`;
|
||||
const psUrn = `${REACT_PROFILER_SESSION_NAMESPACE}:${params.port}`;
|
||||
const snapshot = registry.getSnapshot();
|
||||
const entry = snapshot.services.get(psUrn);
|
||||
|
||||
@@ -263,10 +256,6 @@ Fails if no active profiling session exists or the CDP connection was lost durin
|
||||
hotCommitIndices: api.hotCommitIndices,
|
||||
totalReactCommits: api.totalReactCommits,
|
||||
profileStartWallMs: api.profileStartWallMs,
|
||||
// Provenance fields — used by profiler-load to display session origin
|
||||
projectRoot: api.projectRoot,
|
||||
deviceId: api.deviceId,
|
||||
port: api.port,
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -281,13 +270,9 @@ Fails if no active profiling session exists or the CDP connection was lost durin
|
||||
anyCompilerOptimized: api.anyCompilerOptimized,
|
||||
hotCommitIndices: api.hotCommitIndices,
|
||||
totalReactCommits: api.totalReactCommits,
|
||||
deviceId: api.deviceId,
|
||||
deviceName: null,
|
||||
appName: null,
|
||||
projectRoot: api.projectRoot,
|
||||
};
|
||||
|
||||
cacheProfilerPaths(api.port, sessionPaths, api.deviceId ?? undefined);
|
||||
cacheProfilerPaths(api.port, sessionPaths);
|
||||
api.sessionPaths = sessionPaths;
|
||||
api.disposeSession();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user