@tonyclaw/agent-inspector 3.0.47 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/backend/nitro.json +1 -1
- package/.output/cli.js +1855 -1758
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-BwZEsYfS.mjs → router-CPZp1dgy.mjs} +304 -2
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-V-8lPASC.js → CompareDrawer-CkABWY5h.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D4CVnfdf.js → InspectorPet-BvsFl3jv.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-CO3ZVHLX.js → ProxyViewerContainer-D6O6tY5h.js} +23 -23
- package/.output/ui/assets/{ReplayDialog-CpGyTLtt.js → ReplayDialog-uJnW9FgF.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-BLuJL9dZ.js → RequestAnatomy-CJ1IFwXf.js} +1 -1
- package/.output/ui/assets/{ResponseView-BuSC-CH7.js → ResponseView-Da8fKfh6.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-DeA-JJKa.js → StreamingChunkSequence-zIZ1fbEj.js} +1 -1
- package/.output/ui/assets/{_sessionId-Chp67th6.js → _sessionId-CY9mZjlC.js} +1 -1
- package/.output/ui/assets/{_sessionId-8HuHFhjo.js → _sessionId-WYeJ04Ke.js} +1 -1
- package/.output/ui/assets/{index-atoQrlb8.js → index-Bzm_5L4l.js} +1 -1
- package/.output/ui/assets/{index-nY3E1vxV.js → index-C2AvphEC.js} +2 -2
- package/.output/ui/assets/{index-DPmKK_5d.js → index-CwOAPU17.js} +1 -1
- package/.output/ui/assets/{index-nl9-dpZn.js → index-DWI-2j8i.js} +1 -1
- package/.output/ui/assets/{json-viewer-B9kIzqeX.js → json-viewer-C9EpwpoT.js} +1 -1
- package/.output/ui/assets/{jszip.min-B7tfyE-I.js → jszip.min-CEk40IyV.js} +1 -1
- package/.output/ui/index.html +1 -1
- package/README.md +46 -0
- package/package.json +4 -4
- package/src/cli/instance.ts +12 -1
- package/src/cli/instanceArgs.ts +1 -1
- package/src/cli/rustBackendPackage.ts +8 -0
- package/src/cli.ts +108 -9
- package/src/components/ProxyViewer.tsx +4 -13
- package/src/components/proxy-viewer/proxyViewerLogic.ts +9 -0
package/src/cli.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn, type ChildProcess } from "node:child_process";
|
|
|
4
4
|
import { createConnection } from "node:net";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { dirname, join, resolve as resolvePath } from "node:path";
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
7
|
+
import { appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
8
8
|
import type { Readable, Writable } from "node:stream";
|
|
9
9
|
import packageJson from "../package.json";
|
|
10
10
|
import {
|
|
@@ -40,7 +40,10 @@ import {
|
|
|
40
40
|
shouldSuppressServerOutputLine,
|
|
41
41
|
type ServerOutputFilterContext,
|
|
42
42
|
} from "./cli/startupOutput.js";
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
resolvePreferredBackendImplementation,
|
|
45
|
+
resolveRustBackendPackage,
|
|
46
|
+
} from "./cli/rustBackendPackage.js";
|
|
44
47
|
import { handleNamedInstanceApi } from "./cli/instanceApi.js";
|
|
45
48
|
import {
|
|
46
49
|
closeIdentityProxyGracefully,
|
|
@@ -51,6 +54,7 @@ import {
|
|
|
51
54
|
type ManagedInstanceControlOptions,
|
|
52
55
|
} from "./proxy/identityProxy.js";
|
|
53
56
|
import { findPidsByPort, killPid, openUrlCommand } from "./proxy/platformCommands.js";
|
|
57
|
+
import { resolveDataDir } from "./proxy/dataDir.js";
|
|
54
58
|
|
|
55
59
|
const __filename = fileURLToPath(import.meta.url);
|
|
56
60
|
const __dirname = dirname(__filename);
|
|
@@ -68,6 +72,7 @@ const BRANDED_WINDOWS_RUNTIME_EXE = "agent-inspector.exe";
|
|
|
68
72
|
const DEFAULT_CAPTURE_MODE = "simple";
|
|
69
73
|
const DEFAULT_SHUTDOWN_DEADLINE_MS = 15_000;
|
|
70
74
|
const SUPERVISOR_SHUTDOWN_GRACE_MS = 2_000;
|
|
75
|
+
const AGENT_INSPECTOR_BACKGROUND_SUPERVISOR_ENV = "AGENT_INSPECTOR_BACKGROUND_SUPERVISOR";
|
|
71
76
|
|
|
72
77
|
type CaptureMode = "simple" | "full";
|
|
73
78
|
|
|
@@ -96,7 +101,7 @@ Global options:
|
|
|
96
101
|
-v, --version Print the package version
|
|
97
102
|
|
|
98
103
|
Start options:
|
|
99
|
-
--backend <typescript|rust> Select the backend implementation (default:
|
|
104
|
+
--backend <typescript|rust> Select the backend implementation (default: rust when native package is available)
|
|
100
105
|
--backend-only, --headless Start the API, proxy, and MCP runtime without serving the UI
|
|
101
106
|
--with-ui Serve the independently built UI through the protected ingress
|
|
102
107
|
--port, -p <port> Public ingress port (default: 9527)
|
|
@@ -298,6 +303,30 @@ function pipeServerOutput(child: ChildProcess, context: ServerOutputFilterContex
|
|
|
298
303
|
pipeServerOutputStream(child.stderr, process.stderr, context);
|
|
299
304
|
}
|
|
300
305
|
|
|
306
|
+
type BackgroundSupervisorLogs = {
|
|
307
|
+
stdoutPath: string;
|
|
308
|
+
stderrPath: string;
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
function createBackgroundSupervisorLogs(
|
|
312
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
313
|
+
): BackgroundSupervisorLogs | null {
|
|
314
|
+
try {
|
|
315
|
+
const logsDir = join(resolveDataDir(existsSync, env), "logs");
|
|
316
|
+
mkdirSync(logsDir, { recursive: true });
|
|
317
|
+
const stdoutPath = join(logsDir, "backend.stdout.log");
|
|
318
|
+
const stderrPath = join(logsDir, "backend.stderr.log");
|
|
319
|
+
const header = `\n[${new Date().toISOString()}] Agent Inspector backend process started\n`;
|
|
320
|
+
appendFileSync(stdoutPath, header, { encoding: "utf8" });
|
|
321
|
+
appendFileSync(stderrPath, header, { encoding: "utf8" });
|
|
322
|
+
return { stdoutPath, stderrPath };
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
325
|
+
process.stderr.write(`Failed to open Agent Inspector background logs: ${message}\n`);
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
301
330
|
function pipeServerOutputStream(
|
|
302
331
|
stream: Readable | null,
|
|
303
332
|
target: Writable,
|
|
@@ -325,6 +354,42 @@ function pipeServerOutputStream(
|
|
|
325
354
|
});
|
|
326
355
|
}
|
|
327
356
|
|
|
357
|
+
function appendBackgroundLog(path: string, text: string): void {
|
|
358
|
+
try {
|
|
359
|
+
appendFileSync(path, text, { encoding: "utf8" });
|
|
360
|
+
} catch {
|
|
361
|
+
// Background supervisor output is best-effort: startup must not fail just
|
|
362
|
+
// because a diagnostic log file is temporarily unavailable.
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function pipeServerOutputStreamToFile(
|
|
367
|
+
stream: Readable | null,
|
|
368
|
+
targetPath: string,
|
|
369
|
+
context: ServerOutputFilterContext,
|
|
370
|
+
): void {
|
|
371
|
+
if (stream === null) return;
|
|
372
|
+
|
|
373
|
+
let buffered = "";
|
|
374
|
+
stream.on("data", (chunk: unknown) => {
|
|
375
|
+
const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
376
|
+
const lines = `${buffered}${text}`.split(/\r?\n/);
|
|
377
|
+
buffered = lines.pop() ?? "";
|
|
378
|
+
for (const line of lines) {
|
|
379
|
+
if (!shouldSuppressServerOutputLine(line, context)) {
|
|
380
|
+
appendBackgroundLog(targetPath, `${line}\n`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
stream.on("end", () => {
|
|
385
|
+
if (buffered.length === 0) return;
|
|
386
|
+
if (!shouldSuppressServerOutputLine(buffered, context)) {
|
|
387
|
+
appendBackgroundLog(targetPath, buffered);
|
|
388
|
+
}
|
|
389
|
+
buffered = "";
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
328
393
|
type ServerCommand = {
|
|
329
394
|
command: string;
|
|
330
395
|
args: string[];
|
|
@@ -568,7 +633,9 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
568
633
|
const envHost = process.env["NITRO_HOST"] ?? process.env["HOST"];
|
|
569
634
|
const envMode =
|
|
570
635
|
process.env["AGENT_INSPECTOR_CAPTURE_MODE"] ?? process.env["AGENT_INSPECTOR_MODE"];
|
|
571
|
-
const
|
|
636
|
+
const rawEnvBackend = process.env[AGENT_INSPECTOR_BACKEND_ENV];
|
|
637
|
+
const envBackend =
|
|
638
|
+
rawEnvBackend === undefined ? undefined : parseBackendImplementation(rawEnvBackend);
|
|
572
639
|
if (envBackend === null) {
|
|
573
640
|
console.error(
|
|
574
641
|
`Invalid ${AGENT_INSPECTOR_BACKEND_ENV}. Use typescript or rust; no backend was started.`,
|
|
@@ -591,7 +658,8 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
591
658
|
let enableIdentityProxy = true;
|
|
592
659
|
let legacyAliasEnabled = false;
|
|
593
660
|
let serveUi = process.env["AGENT_INSPECTOR_BACKEND_ONLY"] !== "1";
|
|
594
|
-
let backend: BackendImplementation = envBackend;
|
|
661
|
+
let backend: BackendImplementation = envBackend ?? "typescript";
|
|
662
|
+
let backendWasSpecified = envBackend !== undefined;
|
|
595
663
|
|
|
596
664
|
if (envMode !== undefined && envMode !== "") {
|
|
597
665
|
const parsedMode = parseCaptureMode(envMode);
|
|
@@ -651,6 +719,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
651
719
|
return;
|
|
652
720
|
}
|
|
653
721
|
backend = parsedBackend.data;
|
|
722
|
+
backendWasSpecified = true;
|
|
654
723
|
continue;
|
|
655
724
|
}
|
|
656
725
|
switch (arg) {
|
|
@@ -681,6 +750,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
681
750
|
return;
|
|
682
751
|
}
|
|
683
752
|
backend = parsedBackend.data;
|
|
753
|
+
backendWasSpecified = true;
|
|
684
754
|
i++;
|
|
685
755
|
break;
|
|
686
756
|
}
|
|
@@ -772,6 +842,12 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
772
842
|
return;
|
|
773
843
|
}
|
|
774
844
|
|
|
845
|
+
if (!backendWasSpecified) {
|
|
846
|
+
backend =
|
|
847
|
+
managedLaunch?.backend ??
|
|
848
|
+
resolvePreferredBackendImplementation({ rootVersion: packageJson.version });
|
|
849
|
+
}
|
|
850
|
+
|
|
775
851
|
if (managedLaunch !== null && managedLaunch.backend !== backend) {
|
|
776
852
|
console.error(
|
|
777
853
|
`Managed instance backend mismatch: launch identity requires ${managedLaunch.backend}, but ${backend} was selected.`,
|
|
@@ -967,7 +1043,11 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
967
1043
|
const supervisorProcess = spawn(process.execPath, [cliEntry, ...supervisorArgs], {
|
|
968
1044
|
stdio: "ignore",
|
|
969
1045
|
detached: true,
|
|
970
|
-
env: {
|
|
1046
|
+
env: {
|
|
1047
|
+
...process.env,
|
|
1048
|
+
[AGENT_INSPECTOR_CLI_ENTRY_ENV]: cliEntry,
|
|
1049
|
+
[AGENT_INSPECTOR_BACKGROUND_SUPERVISOR_ENV]: "1",
|
|
1050
|
+
},
|
|
971
1051
|
windowsHide: true,
|
|
972
1052
|
});
|
|
973
1053
|
supervisorProcess.once("error", (err) => {
|
|
@@ -1042,6 +1122,11 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
1042
1122
|
if (existsSync(workerDir)) {
|
|
1043
1123
|
serverEnv["AGENT_INSPECTOR_WORKER_DIR"] = workerDir;
|
|
1044
1124
|
}
|
|
1125
|
+
const runningInBackgroundSupervisor =
|
|
1126
|
+
process.env[AGENT_INSPECTOR_BACKGROUND_SUPERVISOR_ENV] === "1";
|
|
1127
|
+
const backgroundSupervisorLogs = runningInBackgroundSupervisor
|
|
1128
|
+
? createBackgroundSupervisorLogs(serverEnv)
|
|
1129
|
+
: null;
|
|
1045
1130
|
const serverProcess = spawn(serverCommand.command, serverCommand.args, {
|
|
1046
1131
|
stdio:
|
|
1047
1132
|
managedLaunch === null
|
|
@@ -1057,18 +1142,32 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
1057
1142
|
: ["ignore", "pipe", "pipe"],
|
|
1058
1143
|
detached: background,
|
|
1059
1144
|
env: serverEnv,
|
|
1060
|
-
windowsHide: background,
|
|
1145
|
+
windowsHide: background || runningInBackgroundSupervisor,
|
|
1061
1146
|
});
|
|
1062
1147
|
serverProcess.once("error", (err) => {
|
|
1063
1148
|
console.error(`Failed to start Agent Inspector runtime: ${err.message}`);
|
|
1064
1149
|
});
|
|
1065
1150
|
const serverExit = waitForProcessExit(serverProcess);
|
|
1066
1151
|
if (!background) {
|
|
1067
|
-
|
|
1152
|
+
const outputContext = {
|
|
1068
1153
|
enableIdentityProxy,
|
|
1069
1154
|
publicPort: port,
|
|
1070
1155
|
upstreamPort,
|
|
1071
|
-
}
|
|
1156
|
+
};
|
|
1157
|
+
if (backgroundSupervisorLogs === null) {
|
|
1158
|
+
pipeServerOutput(serverProcess, outputContext);
|
|
1159
|
+
} else {
|
|
1160
|
+
pipeServerOutputStreamToFile(
|
|
1161
|
+
serverProcess.stdout,
|
|
1162
|
+
backgroundSupervisorLogs.stdoutPath,
|
|
1163
|
+
outputContext,
|
|
1164
|
+
);
|
|
1165
|
+
pipeServerOutputStreamToFile(
|
|
1166
|
+
serverProcess.stderr,
|
|
1167
|
+
backgroundSupervisorLogs.stderrPath,
|
|
1168
|
+
outputContext,
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1072
1171
|
}
|
|
1073
1172
|
|
|
1074
1173
|
// Identity proxy — a native Node HTTP server that sits in front of
|
|
@@ -61,6 +61,7 @@ import { useProviders } from "../lib/useProviders";
|
|
|
61
61
|
import { groupLogsByConversation, type ConversationGroupData } from "./proxy-viewer";
|
|
62
62
|
import {
|
|
63
63
|
buildSessionSlateStats,
|
|
64
|
+
buildHomeConnectionCommands,
|
|
64
65
|
COPYABLE_COMMAND_CONTAINER_CLASS_NAME,
|
|
65
66
|
COPYABLE_COMMAND_TEXT_CLASS_NAME,
|
|
66
67
|
exportRequiresConfirmation,
|
|
@@ -2148,19 +2149,9 @@ export function ProxyViewer({
|
|
|
2148
2149
|
{liveEmptyStateCopy.showConnectionCommands && connectionEndpoints !== null && (
|
|
2149
2150
|
<>
|
|
2150
2151
|
<div className="flex flex-col items-center gap-2">
|
|
2151
|
-
|
|
2152
|
-
command={
|
|
2153
|
-
|
|
2154
|
-
<CopyableCommand
|
|
2155
|
-
command={`LLM_BASE_URL=${connectionEndpoints.proxy} opencode`}
|
|
2156
|
-
/>
|
|
2157
|
-
<CopyableCommand
|
|
2158
|
-
command={`OPENAI_BASE_URL=${connectionEndpoints.openAiV1} <your-tool>`}
|
|
2159
|
-
/>
|
|
2160
|
-
<CopyableCommand
|
|
2161
|
-
command={`base_url = "${connectionEndpoints.openAiV1}"`}
|
|
2162
|
-
/>
|
|
2163
|
-
<CopyableCommand command={`MCP_URL=${connectionEndpoints.mcp}`} />
|
|
2152
|
+
{buildHomeConnectionCommands(connectionEndpoints).map((command) => (
|
|
2153
|
+
<CopyableCommand key={command} command={command} />
|
|
2154
|
+
))}
|
|
2164
2155
|
</div>
|
|
2165
2156
|
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2166
2157
|
Container note: if your AI tool runs in a different container or host than
|
|
@@ -24,11 +24,20 @@ export type ConversationLogs = {
|
|
|
24
24
|
logs: CapturedLog[];
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export type HomeConnectionEndpoints = {
|
|
28
|
+
proxy: string;
|
|
29
|
+
mcp: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
27
32
|
export const COPYABLE_COMMAND_CONTAINER_CLASS_NAME =
|
|
28
33
|
"flex w-full min-w-0 items-center gap-2 rounded-md border border-border/70 bg-muted/35 px-3 py-2 sm:w-auto sm:max-w-full";
|
|
29
34
|
export const COPYABLE_COMMAND_TEXT_CLASS_NAME =
|
|
30
35
|
"m-0 min-w-0 flex-1 overflow-x-auto font-mono text-xs text-foreground sm:text-sm";
|
|
31
36
|
|
|
37
|
+
export function buildHomeConnectionCommands(endpoints: HomeConnectionEndpoints): readonly string[] {
|
|
38
|
+
return [`PROXY_BASE_URL=${endpoints.proxy}`, `MCP_URL=${endpoints.mcp}`];
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
export type SessionSlateStats = {
|
|
33
42
|
status: SessionSlateStatus;
|
|
34
43
|
statusLabel: string;
|