@tonyclaw/agent-inspector 3.0.44 → 3.0.45
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/cli.js +20743 -16945
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DQHjxFO6.js → CompareDrawer-B3_TLTJh.js} +1 -1
- package/.output/public/assets/{InspectorPet-D1A4505B.js → InspectorPet-Cpn6hv4P.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-BhpIgfBi.js → ProxyViewerContainer-BEAhuGOJ.js} +27 -27
- package/.output/public/assets/{ReplayDialog-C5vmbecv.js → ReplayDialog-B3EKVdJk.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CPGNB8lk.js → RequestAnatomy-COOQjyUC.js} +1 -1
- package/.output/public/assets/{ResponseView-DUfrajCm.js → ResponseView-DBCjkwye.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-nbeCQqOz.js → StreamingChunkSequence-CuXhDgMo.js} +1 -1
- package/.output/public/assets/{_sessionId-mw3aA8Bp.js → _sessionId-BJlM3nmt.js} +1 -1
- package/.output/public/assets/{_sessionId-CDhRgzf6.js → _sessionId-zbgYl7ZJ.js} +1 -1
- package/.output/public/assets/{index-B2eoeT-Z.js → index-BIK4bPTv.js} +1 -1
- package/.output/public/assets/{index-C6qZwYlR.js → index-BZo_8koU.js} +15 -15
- package/.output/public/assets/{index-CX7_rf7o.js → index-D2Qw6Ri2.js} +1 -1
- package/.output/public/assets/{index-BWjeqxbk.css → index-ZWschkCh.css} +1 -1
- package/.output/public/assets/{index-BfRhTvOd.js → index-xF_NY8Yb.js} +5 -5
- package/.output/public/assets/{json-viewer-BLmF1sOZ.js → json-viewer-B-Ao6pwW.js} +1 -1
- package/.output/public/assets/{jszip.min-C9rCFoU3.js → jszip.min-B_rfAUCe.js} +1 -1
- package/.output/server/_libs/modelcontextprotocol__core.mjs +25 -25
- package/.output/server/_libs/modelcontextprotocol__server.mjs +2 -2
- package/.output/server/_libs/zod.mjs +6 -6
- package/.output/server/{_sessionId-U54BAqdp.mjs → _sessionId-CJ99gZFV.mjs} +3 -1
- package/.output/server/{_sessionId-E_Dmopc-.mjs → _sessionId-DEjScBpK.mjs} +5 -3
- package/.output/server/_ssr/{CompareDrawer-CksatPed.mjs → CompareDrawer-DtOIMeQB.mjs} +4 -2
- package/.output/server/_ssr/{InspectorPet-DNc4GQ7z.mjs → InspectorPet-CXc4oCBQ.mjs} +3 -1
- package/.output/server/_ssr/{ProxyViewerContainer-B02Ey0p_.mjs → ProxyViewerContainer-DVPlwfkt.mjs} +52 -27
- package/.output/server/_ssr/{ReplayDialog-DdMvHJF1.mjs → ReplayDialog-BQEA95qC.mjs} +6 -4
- package/.output/server/_ssr/{RequestAnatomy--vh2Z8__.mjs → RequestAnatomy-BMyd8B7Q.mjs} +4 -2
- package/.output/server/_ssr/{ResponseView-Dhxc-cKC.mjs → ResponseView-qrTaEIM8.mjs} +4 -2
- package/.output/server/_ssr/{StreamingChunkSequence-BG0EQmaD.mjs → StreamingChunkSequence-BFTL8mIy.mjs} +5 -3
- package/.output/server/_ssr/{index-lcfulIXa.mjs → index-Bcj1Hcy4.mjs} +4 -2
- package/.output/server/_ssr/{index-D0At9nfd.mjs → index-DW-M7XUG.mjs} +3 -1
- package/.output/server/_ssr/index.mjs +4 -3
- package/.output/server/_ssr/{json-viewer-My1J1_5R.mjs → json-viewer-DiI0Yjsn.mjs} +4 -2
- package/.output/server/_ssr/publicBasePathContext-5264L3rX.mjs +148 -0
- package/.output/server/_ssr/{router-DWcUFPR3.mjs → router-BJ_ltLim.mjs} +2432 -475
- package/.output/server/_ssr/start-C6MjPjxp.mjs +57 -0
- package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +4 -0
- package/.output/server/index.mjs +92 -92
- package/.output/workers/logFinalizer.worker.js +4 -0
- package/.output/workers/sessionWorkerEntry.js +4 -0
- package/README.md +221 -25
- package/docs/instance-control.openapi.yaml +306 -0
- package/package.json +4 -1
- package/src/cli/alias.ts +440 -0
- package/src/cli/instance.ts +1037 -0
- package/src/cli/instanceArgs.ts +266 -0
- package/src/cli/instanceControl.ts +183 -0
- package/src/cli/instanceModel.ts +275 -0
- package/src/cli/instanceRegistry.ts +740 -0
- package/src/cli/onboard.ts +123 -35
- package/src/cli/onboardTarget.ts +179 -0
- package/src/cli/templates/codex-skill-onboard.ts +76 -28
- package/src/cli/templates/skill-onboard.ts +93 -59
- package/src/cli.ts +154 -16
- package/src/components/ProxyViewer.tsx +13 -5
- package/src/components/providers/SettingsDialog.tsx +13 -8
- package/src/lib/basePath.ts +8 -2
- package/src/lib/codingAgentEndpoints.ts +16 -0
- package/src/lib/instanceContract.ts +220 -0
- package/src/lib/managedInstance.ts +104 -0
- package/src/lib/publicBasePathContext.ts +107 -0
- package/src/mcp/instanceHandlers.ts +149 -0
- package/src/mcp/loopback.ts +16 -5
- package/src/mcp/mode.ts +25 -0
- package/src/mcp/server.ts +258 -18
- package/src/mcp/toolHandlers.ts +2 -2
- package/src/proxy/identityProxy.ts +655 -36
- package/src/proxy/runtimeShutdown.ts +73 -1
- package/src/proxy/sessionInfo.ts +5 -4
- package/src/routes/api/-instances.ts +109 -0
- package/src/routes/api/instances.$name.connection.ts +12 -0
- package/src/routes/api/instances.$name.restart.ts +23 -0
- package/src/routes/api/instances.$name.start.ts +18 -0
- package/src/routes/api/instances.$name.stop.ts +23 -0
- package/src/routes/api/instances.$name.ts +12 -0
- package/src/routes/api/instances.ts +16 -0
- package/src/start.ts +10 -0
- package/.output/server/_ssr/start-HYkvq4Ni.mjs +0 -4
- package/.output/server/_tanstack-start-manifest_v-B2chR8ef.mjs +0 -4
package/src/cli.ts
CHANGED
|
@@ -6,11 +6,18 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { dirname, join, resolve as resolvePath } from "node:path";
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
import type { Readable, Writable } from "node:stream";
|
|
9
|
+
import packageJson from "../package.json";
|
|
9
10
|
import {
|
|
10
11
|
AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH_ENV,
|
|
11
12
|
appendBasePathToOrigin,
|
|
12
13
|
getConfiguredBasePath,
|
|
13
14
|
} from "./lib/basePath.js";
|
|
15
|
+
import {
|
|
16
|
+
AGENT_INSPECTOR_CLI_ENTRY_ENV,
|
|
17
|
+
managedInstanceShutdownMessage,
|
|
18
|
+
readManagedInstanceLaunch,
|
|
19
|
+
type ManagedInstanceLaunch,
|
|
20
|
+
} from "./lib/managedInstance.js";
|
|
14
21
|
import {
|
|
15
22
|
formatAccessHintLines,
|
|
16
23
|
isLoopbackHost,
|
|
@@ -29,6 +36,7 @@ import {
|
|
|
29
36
|
forceCloseIdentityProxy,
|
|
30
37
|
startIdentityProxy,
|
|
31
38
|
stopIdentityProxyAdmission,
|
|
39
|
+
type ManagedInstanceControlOptions,
|
|
32
40
|
} from "./proxy/identityProxy.js";
|
|
33
41
|
import { findPidsByPort, killPid, openUrlCommand } from "./proxy/platformCommands.js";
|
|
34
42
|
|
|
@@ -61,19 +69,71 @@ process.title = "Agent Inspector";
|
|
|
61
69
|
*/
|
|
62
70
|
const subcommand = process.argv[2];
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
function printGlobalHelp(): void {
|
|
73
|
+
console.log(`agent-inspector ${packageJson.version} - Agent observability and knowledge capture
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
agent-inspector [start] [options]
|
|
77
|
+
agent-inspector instance <start|list|status|connect|stop|restart> ...
|
|
78
|
+
agent-inspector alias <list|add|remove> ...
|
|
79
|
+
agent-inspector onboard [options]
|
|
80
|
+
agent-inspector doctor [options]
|
|
81
|
+
|
|
82
|
+
Global options:
|
|
83
|
+
-h, --help Show this help without starting a runtime
|
|
84
|
+
-v, --version Print the package version
|
|
69
85
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const code = await runDoctor(process.argv.slice(3));
|
|
73
|
-
process.exit(code);
|
|
86
|
+
Run \`agent-inspector instance --help\`, \`agent-inspector onboard --help\`, or
|
|
87
|
+
\`agent-inspector doctor --help\` for command-specific options.`);
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
switch (subcommand) {
|
|
91
|
+
case "--help":
|
|
92
|
+
case "-h":
|
|
93
|
+
printGlobalHelp();
|
|
94
|
+
process.exitCode = 0;
|
|
95
|
+
break;
|
|
96
|
+
case "--version":
|
|
97
|
+
case "-v":
|
|
98
|
+
console.log(packageJson.version);
|
|
99
|
+
process.exitCode = 0;
|
|
100
|
+
break;
|
|
101
|
+
case "onboard": {
|
|
102
|
+
const { runOnboard } = await import("./cli/onboard.js");
|
|
103
|
+
const code = await runOnboard(process.argv.slice(3));
|
|
104
|
+
process.exit(code);
|
|
105
|
+
}
|
|
106
|
+
case "doctor": {
|
|
107
|
+
const { runDoctor } = await import("./cli/doctor.js");
|
|
108
|
+
const code = await runDoctor(process.argv.slice(3));
|
|
109
|
+
process.exit(code);
|
|
110
|
+
}
|
|
111
|
+
case "alias": {
|
|
112
|
+
const { runAlias } = await import("./cli/alias.js");
|
|
113
|
+
const code = await runAlias(process.argv.slice(3));
|
|
114
|
+
process.exit(code);
|
|
115
|
+
}
|
|
116
|
+
case "instance": {
|
|
117
|
+
const { runInstance } = await import("./cli/instance.js");
|
|
118
|
+
const code = await runInstance(process.argv.slice(3));
|
|
119
|
+
process.exitCode = code;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case undefined:
|
|
123
|
+
await runStart(process.argv.slice(2));
|
|
124
|
+
break;
|
|
125
|
+
case "start":
|
|
126
|
+
await runStart(process.argv.slice(3));
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
if (subcommand.startsWith("-")) {
|
|
130
|
+
await runStart(process.argv.slice(2));
|
|
131
|
+
} else {
|
|
132
|
+
console.error(`agent-inspector: unknown command ${subcommand}`);
|
|
133
|
+
console.error("Run `agent-inspector --help` for supported commands.");
|
|
134
|
+
process.exitCode = 2;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
77
137
|
|
|
78
138
|
// -----------------------------------------------------------------------------
|
|
79
139
|
// Legacy `start` behavior — start the proxy on the configured port. Extracted
|
|
@@ -345,6 +405,7 @@ async function tryStartIdentityProxy(
|
|
|
345
405
|
upstreamPort: number,
|
|
346
406
|
listenHost: string,
|
|
347
407
|
upstreamHost: string,
|
|
408
|
+
managedInstance: ManagedInstanceControlOptions | undefined,
|
|
348
409
|
): Promise<import("node:http").Server | null> {
|
|
349
410
|
try {
|
|
350
411
|
const server = await startIdentityProxy({
|
|
@@ -364,6 +425,7 @@ async function tryStartIdentityProxy(
|
|
|
364
425
|
.filter((host) => host.length > 0),
|
|
365
426
|
maxRequestBytes: readPositiveIntegerEnv("AGENT_INSPECTOR_MAX_REQUEST_BYTES"),
|
|
366
427
|
requestTimeoutMs: readPositiveIntegerEnv("AGENT_INSPECTOR_REQUEST_TIMEOUT_MS"),
|
|
428
|
+
managedInstance,
|
|
367
429
|
});
|
|
368
430
|
return server;
|
|
369
431
|
} catch (err) {
|
|
@@ -378,6 +440,14 @@ async function tryStartIdentityProxy(
|
|
|
378
440
|
}
|
|
379
441
|
|
|
380
442
|
async function runStart(args: string[]): Promise<void> {
|
|
443
|
+
const managedLaunchResult = readManagedInstanceLaunch(process.env);
|
|
444
|
+
if (managedLaunchResult.kind === "invalid") {
|
|
445
|
+
console.error(managedLaunchResult.message);
|
|
446
|
+
process.exitCode = 1;
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const managedLaunch: ManagedInstanceLaunch | null =
|
|
450
|
+
managedLaunchResult.kind === "managed" ? managedLaunchResult.launch : null;
|
|
381
451
|
const envPort = process.env["AGENT_INSPECTOR_PORT"] ?? process.env["PORT"];
|
|
382
452
|
const portDefault = envPort !== undefined ? Number(envPort) : DEFAULT_PORT;
|
|
383
453
|
const envHost = process.env["NITRO_HOST"] ?? process.env["HOST"];
|
|
@@ -417,6 +487,10 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
417
487
|
|
|
418
488
|
for (let i = 0; i < args.length; i++) {
|
|
419
489
|
const arg = args[i] ?? "";
|
|
490
|
+
if (arg.startsWith("--port=")) {
|
|
491
|
+
port = Number(arg.slice(arg.indexOf("=") + 1));
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
420
494
|
if (arg.startsWith("--host=")) {
|
|
421
495
|
const value = arg.slice(arg.indexOf("=") + 1).trim();
|
|
422
496
|
if (!isValidBindHost(value)) {
|
|
@@ -515,8 +589,19 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
515
589
|
case "--legacy-port":
|
|
516
590
|
legacyAliasEnabled = true;
|
|
517
591
|
break;
|
|
592
|
+
case "--help":
|
|
593
|
+
case "-h":
|
|
594
|
+
printGlobalHelp();
|
|
595
|
+
return;
|
|
596
|
+
case "--version":
|
|
597
|
+
case "-v":
|
|
598
|
+
console.log(packageJson.version);
|
|
599
|
+
return;
|
|
518
600
|
default:
|
|
519
|
-
|
|
601
|
+
console.error(`agent-inspector start: unknown option ${arg}`);
|
|
602
|
+
console.error("Run `agent-inspector --help` for supported options.");
|
|
603
|
+
process.exitCode = 2;
|
|
604
|
+
return;
|
|
520
605
|
}
|
|
521
606
|
}
|
|
522
607
|
|
|
@@ -551,7 +636,22 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
551
636
|
// TanStack Start listens on the private upstream port; identity proxies own
|
|
552
637
|
// the public-facing port(s). When the identity proxy is disabled we fall
|
|
553
638
|
// back to TanStack listening on the public port directly.
|
|
554
|
-
const upstreamPort =
|
|
639
|
+
const upstreamPort =
|
|
640
|
+
managedLaunch === null
|
|
641
|
+
? enableIdentityProxy
|
|
642
|
+
? pickUpstreamPort(port, legacyAliasPort)
|
|
643
|
+
: port
|
|
644
|
+
: managedLaunch.upstreamPort;
|
|
645
|
+
if (
|
|
646
|
+
upstreamPort < 1 ||
|
|
647
|
+
upstreamPort > 65_535 ||
|
|
648
|
+
(enableIdentityProxy && upstreamPort === port) ||
|
|
649
|
+
upstreamPort === legacyAliasPort
|
|
650
|
+
) {
|
|
651
|
+
console.error(`Invalid managed upstream port: ${String(upstreamPort)}.`);
|
|
652
|
+
process.exitCode = 1;
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
555
655
|
const upstreamHost = enableIdentityProxy ? DEFAULT_BIND_HOST : host;
|
|
556
656
|
process.env["PORT"] = String(upstreamPort);
|
|
557
657
|
|
|
@@ -629,7 +729,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
629
729
|
const supervisorProcess = spawn(process.execPath, [cliEntry, ...supervisorArgs], {
|
|
630
730
|
stdio: "ignore",
|
|
631
731
|
detached: true,
|
|
632
|
-
env: process.env,
|
|
732
|
+
env: { ...process.env, [AGENT_INSPECTOR_CLI_ENTRY_ENV]: cliEntry },
|
|
633
733
|
windowsHide: true,
|
|
634
734
|
});
|
|
635
735
|
supervisorProcess.once("error", (err) => {
|
|
@@ -697,6 +797,10 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
697
797
|
|
|
698
798
|
// Start the server with the branded Windows runtime when postinstall created it.
|
|
699
799
|
const serverEnv = { ...process.env };
|
|
800
|
+
const currentCliEntry = process.env[AGENT_INSPECTOR_CLI_ENTRY_ENV] ?? process.argv[1];
|
|
801
|
+
if (currentCliEntry !== undefined && currentCliEntry.length > 0) {
|
|
802
|
+
serverEnv[AGENT_INSPECTOR_CLI_ENTRY_ENV] = currentCliEntry;
|
|
803
|
+
}
|
|
700
804
|
if (configDir !== undefined) {
|
|
701
805
|
// Normalize MSYS / Git Bash paths to Windows native form.
|
|
702
806
|
// On Windows, `path.join('/c/Users/foo')` becomes `\c\Users\foo`
|
|
@@ -732,7 +836,14 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
732
836
|
serverEnv["AGENT_INSPECTOR_WORKER_DIR"] = workerDir;
|
|
733
837
|
}
|
|
734
838
|
const serverProcess = spawn(serverCommand.command, serverCommand.args, {
|
|
735
|
-
stdio:
|
|
839
|
+
stdio:
|
|
840
|
+
managedLaunch === null
|
|
841
|
+
? background
|
|
842
|
+
? ["ignore", "ignore", "ignore"]
|
|
843
|
+
: ["ignore", "pipe", "pipe"]
|
|
844
|
+
: background
|
|
845
|
+
? ["ignore", "ignore", "ignore", "ipc"]
|
|
846
|
+
: ["ignore", "pipe", "pipe", "ipc"],
|
|
736
847
|
detached: background,
|
|
737
848
|
env: serverEnv,
|
|
738
849
|
windowsHide: background,
|
|
@@ -764,7 +875,13 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
764
875
|
const requestSupervisorShutdown = (signal: "SIGINT" | "SIGTERM"): void => {
|
|
765
876
|
if (supervisorShutdownPromise !== null) return;
|
|
766
877
|
for (const proxy of identityProxies) stopIdentityProxyAdmission(proxy.server);
|
|
767
|
-
serverProcess.
|
|
878
|
+
if (managedLaunch !== null && serverProcess.connected) {
|
|
879
|
+
serverProcess.send(managedInstanceShutdownMessage(managedLaunch.controlToken), (error) => {
|
|
880
|
+
if (error !== null && serverProcess.exitCode === null) serverProcess.kill(signal);
|
|
881
|
+
});
|
|
882
|
+
} else {
|
|
883
|
+
serverProcess.kill(signal);
|
|
884
|
+
}
|
|
768
885
|
|
|
769
886
|
const childDeadline =
|
|
770
887
|
readPositiveIntegerEnv("AGENT_INSPECTOR_SHUTDOWN_TIMEOUT_MS") ?? DEFAULT_SHUTDOWN_DEADLINE_MS;
|
|
@@ -795,8 +912,28 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
795
912
|
const currentSupervisorShutdown = (): Promise<void> | null => supervisorShutdownPromise;
|
|
796
913
|
process.on("SIGINT", handleSigint);
|
|
797
914
|
process.on("SIGTERM", handleSigterm);
|
|
915
|
+
const managedInstanceControl: ManagedInstanceControlOptions | undefined =
|
|
916
|
+
managedLaunch === null
|
|
917
|
+
? undefined
|
|
918
|
+
: {
|
|
919
|
+
name: managedLaunch.name,
|
|
920
|
+
instanceId: managedLaunch.instanceId,
|
|
921
|
+
launchId: managedLaunch.launchId,
|
|
922
|
+
controlToken: managedLaunch.controlToken,
|
|
923
|
+
supervisorPid: process.pid,
|
|
924
|
+
startedAt: managedLaunch.startedAt,
|
|
925
|
+
publicPort: port,
|
|
926
|
+
upstreamPort,
|
|
927
|
+
requestShutdown: () => requestSupervisorShutdown("SIGTERM"),
|
|
928
|
+
};
|
|
798
929
|
if (enableIdentityProxy) {
|
|
799
|
-
const primaryProxy = await tryStartIdentityProxy(
|
|
930
|
+
const primaryProxy = await tryStartIdentityProxy(
|
|
931
|
+
port,
|
|
932
|
+
upstreamPort,
|
|
933
|
+
host,
|
|
934
|
+
upstreamHost,
|
|
935
|
+
managedInstanceControl,
|
|
936
|
+
);
|
|
800
937
|
if (primaryProxy !== null) {
|
|
801
938
|
identityProxies.push({ label: "primary", port, server: primaryProxy });
|
|
802
939
|
}
|
|
@@ -806,6 +943,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
806
943
|
upstreamPort,
|
|
807
944
|
host,
|
|
808
945
|
upstreamHost,
|
|
946
|
+
managedInstanceControl,
|
|
809
947
|
);
|
|
810
948
|
if (legacyProxy !== null) {
|
|
811
949
|
identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
|
|
@@ -43,7 +43,8 @@ import {
|
|
|
43
43
|
|
|
44
44
|
import type { CapturedLog } from "../contracts";
|
|
45
45
|
import { exportLogsAsZip, type ExportMode } from "../lib/export-logs";
|
|
46
|
-
import { withBasePath } from "../lib/basePath";
|
|
46
|
+
import { getConfiguredBasePath, withBasePath } from "../lib/basePath";
|
|
47
|
+
import { deriveCodingAgentEndpoints } from "../lib/codingAgentEndpoints";
|
|
47
48
|
import type { ImportLogsResponse } from "../lib/logImportContract";
|
|
48
49
|
import { copyTextToClipboard } from "../lib/clipboard";
|
|
49
50
|
import type { InspectorGroupEvidence, InspectorGroupMember } from "../lib/groupContract";
|
|
@@ -1384,9 +1385,9 @@ export function ProxyViewer({
|
|
|
1384
1385
|
const exportRequestIdRef = useRef(0);
|
|
1385
1386
|
const detailsPanelResizeRef = useRef<DetailsPanelResizeState | null>(null);
|
|
1386
1387
|
useKeyboardNavigation(logListRef, logListWrapperRef, { pageWide: true });
|
|
1387
|
-
const
|
|
1388
|
+
const connectionEndpoints = useMemo(() => {
|
|
1388
1389
|
const origin = typeof window === "undefined" ? "http://localhost:9527" : window.location.origin;
|
|
1389
|
-
return
|
|
1390
|
+
return deriveCodingAgentEndpoints(origin, getConfiguredBasePath());
|
|
1390
1391
|
}, []);
|
|
1391
1392
|
|
|
1392
1393
|
const cancelTransientTasks = useCallback(() => {
|
|
@@ -2146,11 +2147,18 @@ export function ProxyViewer({
|
|
|
2146
2147
|
<>
|
|
2147
2148
|
<div className="flex flex-col items-center gap-2">
|
|
2148
2149
|
<CopyableCommand
|
|
2149
|
-
command={`ANTHROPIC_BASE_URL=${
|
|
2150
|
+
command={`ANTHROPIC_BASE_URL=${connectionEndpoints.proxy} <your-tool>`}
|
|
2150
2151
|
/>
|
|
2151
2152
|
<CopyableCommand
|
|
2152
|
-
command={`
|
|
2153
|
+
command={`LLM_BASE_URL=${connectionEndpoints.proxy} opencode`}
|
|
2153
2154
|
/>
|
|
2155
|
+
<CopyableCommand
|
|
2156
|
+
command={`OPENAI_BASE_URL=${connectionEndpoints.openAiV1} <your-tool>`}
|
|
2157
|
+
/>
|
|
2158
|
+
<CopyableCommand
|
|
2159
|
+
command={`base_url = "${connectionEndpoints.openAiV1}"`}
|
|
2160
|
+
/>
|
|
2161
|
+
<CopyableCommand command={`MCP_URL=${connectionEndpoints.mcp}`} />
|
|
2154
2162
|
</div>
|
|
2155
2163
|
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2156
2164
|
Container note: if your AI tool runs in a different container or host than
|
|
@@ -10,7 +10,8 @@ import { useProviders } from "../../lib/useProviders";
|
|
|
10
10
|
import { useStripConfig } from "../../lib/useStripConfig";
|
|
11
11
|
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
12
12
|
import { fetchJsonWithTimeout } from "../../lib/apiClient";
|
|
13
|
-
import { withBasePath } from "../../lib/basePath";
|
|
13
|
+
import { getConfiguredBasePath, withBasePath } from "../../lib/basePath";
|
|
14
|
+
import { deriveCodingAgentEndpoints } from "../../lib/codingAgentEndpoints";
|
|
14
15
|
import {
|
|
15
16
|
MAX_PROVIDER_TEST_TIMEOUT_SECONDS,
|
|
16
17
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
@@ -333,6 +334,10 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
333
334
|
if (typeof window === "undefined") return "http://localhost:9527";
|
|
334
335
|
return window.location.origin;
|
|
335
336
|
}, []);
|
|
337
|
+
const endpoints = useMemo(
|
|
338
|
+
() => deriveCodingAgentEndpoints(origin, getConfiguredBasePath()),
|
|
339
|
+
[origin],
|
|
340
|
+
);
|
|
336
341
|
const values = useMemo(
|
|
337
342
|
() => [
|
|
338
343
|
{ id: "status", label: "Check onboarding", value: "agent-inspector onboard --status" },
|
|
@@ -367,7 +372,7 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
367
372
|
{
|
|
368
373
|
id: "opencode-proxy",
|
|
369
374
|
label: "OpenCode proxy",
|
|
370
|
-
value: `LLM_BASE_URL=${
|
|
375
|
+
value: `LLM_BASE_URL=${endpoints.proxy}`,
|
|
371
376
|
},
|
|
372
377
|
{
|
|
373
378
|
id: "mimo-config",
|
|
@@ -383,22 +388,22 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
383
388
|
{
|
|
384
389
|
id: "mimo-proxy",
|
|
385
390
|
label: "MiMo Code proxy",
|
|
386
|
-
value: `OPENAI_BASE_URL=${
|
|
391
|
+
value: `OPENAI_BASE_URL=${endpoints.proxy}`,
|
|
387
392
|
},
|
|
388
|
-
{ id: "mcp", label: "MCP URL", value:
|
|
389
|
-
{ id: "proxy", label: "Proxy URL", value:
|
|
393
|
+
{ id: "mcp", label: "MCP URL", value: endpoints.mcp },
|
|
394
|
+
{ id: "proxy", label: "Proxy URL", value: endpoints.proxy },
|
|
390
395
|
{
|
|
391
396
|
id: "anthropic",
|
|
392
397
|
label: "Anthropic base",
|
|
393
|
-
value: `ANTHROPIC_BASE_URL=${
|
|
398
|
+
value: `ANTHROPIC_BASE_URL=${endpoints.proxy}`,
|
|
394
399
|
},
|
|
395
400
|
{
|
|
396
401
|
id: "openai",
|
|
397
402
|
label: "OpenAI base",
|
|
398
|
-
value: `OPENAI_BASE_URL=${
|
|
403
|
+
value: `OPENAI_BASE_URL=${endpoints.openAiV1}`,
|
|
399
404
|
},
|
|
400
405
|
],
|
|
401
|
-
[
|
|
406
|
+
[endpoints],
|
|
402
407
|
);
|
|
403
408
|
|
|
404
409
|
const handleCopy = useCallback((id: string, value: string) => {
|
package/src/lib/basePath.ts
CHANGED
|
@@ -4,6 +4,8 @@ export const AGENT_INSPECTOR_BASE_PATH_ENV = "AGENT_INSPECTOR_BASE_PATH";
|
|
|
4
4
|
export const AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH_ENV =
|
|
5
5
|
"AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH";
|
|
6
6
|
export const AGENT_INSPECTOR_BASE_PATH_META_NAME = "agent-inspector-base-path";
|
|
7
|
+
export const AGENT_INSPECTOR_PUBLIC_BASE_PATH_HEADER = "x-agent-inspector-public-base-path";
|
|
8
|
+
export const AGENT_INSPECTOR_PUBLIC_PORT_HEADER = "x-agent-inspector-public-port";
|
|
7
9
|
export const DEFAULT_AGENT_INSPECTOR_BASE_PATH = "/inspector";
|
|
8
10
|
|
|
9
11
|
type BasePathEnv = Readonly<Record<string, string | undefined>>;
|
|
@@ -35,9 +37,13 @@ function readProcessBasePath(): string | undefined {
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export function getConfiguredBasePath(env?: BasePathEnv): string {
|
|
40
|
+
if (env !== undefined) {
|
|
41
|
+
return normalizeBasePath(
|
|
42
|
+
env[AGENT_INSPECTOR_BASE_PATH_ENV] ?? DEFAULT_AGENT_INSPECTOR_BASE_PATH,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
38
45
|
return normalizeBasePath(
|
|
39
|
-
|
|
40
|
-
readProcessBasePath() ??
|
|
46
|
+
readProcessBasePath() ??
|
|
41
47
|
readDocumentBasePath() ??
|
|
42
48
|
import.meta.env?.BASE_URL ??
|
|
43
49
|
DEFAULT_AGENT_INSPECTOR_BASE_PATH,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { appendBasePathToOrigin } from "./basePath";
|
|
2
|
+
|
|
3
|
+
export type CodingAgentEndpoints = {
|
|
4
|
+
proxy: string;
|
|
5
|
+
openAiV1: string;
|
|
6
|
+
mcp: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** Derive the public protocol endpoints shown to coding agents from one Inspector origin. */
|
|
10
|
+
export function deriveCodingAgentEndpoints(origin: string, basePath: string): CodingAgentEndpoints {
|
|
11
|
+
return {
|
|
12
|
+
proxy: appendBasePathToOrigin(origin, "/proxy", basePath),
|
|
13
|
+
openAiV1: appendBasePathToOrigin(origin, "/proxy/v1", basePath),
|
|
14
|
+
mcp: appendBasePathToOrigin(origin, "/api/mcp", basePath),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const INSTANCE_API_SCHEMA_VERSION = 1;
|
|
4
|
+
|
|
5
|
+
export const InstanceStateSchema = z.enum(["running", "stopped", "conflict"]);
|
|
6
|
+
export const InstanceStateReasonSchema = z.enum(["identity_mismatch", "port_conflict"]);
|
|
7
|
+
|
|
8
|
+
export const InstanceUrlsSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
ui: z.url(),
|
|
11
|
+
api: z.url(),
|
|
12
|
+
health: z.url(),
|
|
13
|
+
proxy: z.url(),
|
|
14
|
+
openai: z.url(),
|
|
15
|
+
mcp: z.url(),
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
18
|
+
|
|
19
|
+
export const InstanceStatusOutputSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
22
|
+
name: z.string().min(1),
|
|
23
|
+
instanceId: z.string().min(1),
|
|
24
|
+
state: InstanceStateSchema,
|
|
25
|
+
stateReason: InstanceStateReasonSchema.nullable(),
|
|
26
|
+
checkedAt: z.iso.datetime(),
|
|
27
|
+
createdAt: z.iso.datetime(),
|
|
28
|
+
updatedAt: z.iso.datetime(),
|
|
29
|
+
launch: z
|
|
30
|
+
.object({
|
|
31
|
+
launchId: z.string().min(1),
|
|
32
|
+
startedAt: z.iso.datetime(),
|
|
33
|
+
})
|
|
34
|
+
.strict(),
|
|
35
|
+
host: z.string().min(1),
|
|
36
|
+
publicPort: z.number().int().min(1).max(65_535),
|
|
37
|
+
upstreamPort: z.number().int().min(1).max(65_535),
|
|
38
|
+
basePath: z.string().startsWith("/"),
|
|
39
|
+
captureMode: z.enum(["simple", "full"]),
|
|
40
|
+
dataDir: z.string().min(1),
|
|
41
|
+
supervisorPid: z.number().int().positive().nullable(),
|
|
42
|
+
urls: InstanceUrlsSchema,
|
|
43
|
+
})
|
|
44
|
+
.strict();
|
|
45
|
+
|
|
46
|
+
export const InstanceConnectionOutputSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
49
|
+
instance: InstanceStatusOutputSchema,
|
|
50
|
+
baseUrl: z.url(),
|
|
51
|
+
endpoints: InstanceUrlsSchema,
|
|
52
|
+
environment: z
|
|
53
|
+
.object({
|
|
54
|
+
ANTHROPIC_BASE_URL: z.url(),
|
|
55
|
+
LLM_BASE_URL: z.url(),
|
|
56
|
+
OPENAI_BASE_URL: z.url(),
|
|
57
|
+
AGENT_INSPECTOR_MCP_URL: z.url(),
|
|
58
|
+
})
|
|
59
|
+
.strict(),
|
|
60
|
+
mcp: z
|
|
61
|
+
.object({
|
|
62
|
+
serverName: z.string().min(1),
|
|
63
|
+
transport: z.literal("streamable-http"),
|
|
64
|
+
url: z.url(),
|
|
65
|
+
})
|
|
66
|
+
.strict(),
|
|
67
|
+
codex: z
|
|
68
|
+
.object({
|
|
69
|
+
providerName: z.string().min(1),
|
|
70
|
+
baseUrl: z.url(),
|
|
71
|
+
wireApi: z.literal("responses"),
|
|
72
|
+
})
|
|
73
|
+
.strict(),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
|
|
77
|
+
export const InstanceStartRequestSchema = z
|
|
78
|
+
.object({
|
|
79
|
+
port: z.number().int().min(1).max(65_535).optional(),
|
|
80
|
+
basePath: z
|
|
81
|
+
.string()
|
|
82
|
+
.min(1)
|
|
83
|
+
.max(2_048)
|
|
84
|
+
.refine(
|
|
85
|
+
(value) =>
|
|
86
|
+
value.startsWith("/") &&
|
|
87
|
+
!value.includes("?") &&
|
|
88
|
+
!value.includes("#") &&
|
|
89
|
+
!value.includes("\\"),
|
|
90
|
+
"Base Path must be an absolute URL path without query, hash, or backslash",
|
|
91
|
+
)
|
|
92
|
+
.optional(),
|
|
93
|
+
host: z
|
|
94
|
+
.string()
|
|
95
|
+
.min(1)
|
|
96
|
+
.max(253)
|
|
97
|
+
.refine(
|
|
98
|
+
(value) =>
|
|
99
|
+
value.trim() === value &&
|
|
100
|
+
!value.includes("://") &&
|
|
101
|
+
!value.includes("/") &&
|
|
102
|
+
!value.includes("\\") &&
|
|
103
|
+
!/\s/u.test(value),
|
|
104
|
+
"Host must be a hostname or IP address without protocol, path, or whitespace",
|
|
105
|
+
)
|
|
106
|
+
.optional(),
|
|
107
|
+
captureMode: z.enum(["simple", "full"]).optional(),
|
|
108
|
+
dataDir: z.string().trim().min(1).max(32_767).optional(),
|
|
109
|
+
})
|
|
110
|
+
.strict();
|
|
111
|
+
|
|
112
|
+
export const InstanceEmptyRequestSchema = z.object({}).strict();
|
|
113
|
+
|
|
114
|
+
export const InstanceOperationSchema = z.enum(["start", "stop", "restart"]);
|
|
115
|
+
export const InstanceOperationOutcomeSchema = z.enum([
|
|
116
|
+
"created",
|
|
117
|
+
"started",
|
|
118
|
+
"already_running",
|
|
119
|
+
"stopped",
|
|
120
|
+
"already_stopped",
|
|
121
|
+
"restarted",
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
export const InstanceOperationOutputSchema = z
|
|
125
|
+
.object({
|
|
126
|
+
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
127
|
+
operation: InstanceOperationSchema,
|
|
128
|
+
outcome: InstanceOperationOutcomeSchema,
|
|
129
|
+
instance: InstanceStatusOutputSchema,
|
|
130
|
+
})
|
|
131
|
+
.strict();
|
|
132
|
+
|
|
133
|
+
export const InstanceListOutputSchema = z
|
|
134
|
+
.object({
|
|
135
|
+
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
136
|
+
instances: z.array(InstanceStatusOutputSchema),
|
|
137
|
+
})
|
|
138
|
+
.strict();
|
|
139
|
+
|
|
140
|
+
export const InstancePublicErrorCodeSchema = z.enum([
|
|
141
|
+
"argument_invalid",
|
|
142
|
+
"config_mismatch",
|
|
143
|
+
"data_dir_conflict",
|
|
144
|
+
"data_dir_invalid",
|
|
145
|
+
"identity_mismatch",
|
|
146
|
+
"instance_not_found",
|
|
147
|
+
"launch_failed",
|
|
148
|
+
"launch_unavailable",
|
|
149
|
+
"lock_not_owned",
|
|
150
|
+
"lock_timeout",
|
|
151
|
+
"name_invalid",
|
|
152
|
+
"port_conflict",
|
|
153
|
+
"port_exhausted",
|
|
154
|
+
"port_invalid",
|
|
155
|
+
"record_invalid",
|
|
156
|
+
"registry_io",
|
|
157
|
+
"restart_failed_degraded",
|
|
158
|
+
"restart_failed_rolled_back",
|
|
159
|
+
"self_lifecycle_unsupported",
|
|
160
|
+
"shutdown_failed",
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
export const InstancePublicErrorSchema = z
|
|
164
|
+
.object({
|
|
165
|
+
code: InstancePublicErrorCodeSchema,
|
|
166
|
+
message: z.string().min(1),
|
|
167
|
+
retryable: z.boolean(),
|
|
168
|
+
})
|
|
169
|
+
.strict();
|
|
170
|
+
|
|
171
|
+
export const InstanceErrorOutputSchema = z
|
|
172
|
+
.object({
|
|
173
|
+
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
174
|
+
error: InstancePublicErrorSchema,
|
|
175
|
+
})
|
|
176
|
+
.strict();
|
|
177
|
+
|
|
178
|
+
export type InstanceState = z.infer<typeof InstanceStateSchema>;
|
|
179
|
+
export type InstanceStateReason = z.infer<typeof InstanceStateReasonSchema>;
|
|
180
|
+
export type InstanceStatusOutput = z.infer<typeof InstanceStatusOutputSchema>;
|
|
181
|
+
export type InstanceConnectionOutput = z.infer<typeof InstanceConnectionOutputSchema>;
|
|
182
|
+
export type InstanceStartRequest = z.infer<typeof InstanceStartRequestSchema>;
|
|
183
|
+
export type InstanceOperation = z.infer<typeof InstanceOperationSchema>;
|
|
184
|
+
export type InstanceOperationOutcome = z.infer<typeof InstanceOperationOutcomeSchema>;
|
|
185
|
+
export type InstanceOperationOutput = z.infer<typeof InstanceOperationOutputSchema>;
|
|
186
|
+
export type InstanceListOutput = z.infer<typeof InstanceListOutputSchema>;
|
|
187
|
+
export type InstancePublicErrorCode = z.infer<typeof InstancePublicErrorCodeSchema>;
|
|
188
|
+
export type InstancePublicError = z.infer<typeof InstancePublicErrorSchema>;
|
|
189
|
+
export type InstanceErrorOutput = z.infer<typeof InstanceErrorOutputSchema>;
|
|
190
|
+
|
|
191
|
+
export function isRetryableInstanceError(code: InstancePublicErrorCode): boolean {
|
|
192
|
+
switch (code) {
|
|
193
|
+
case "launch_failed":
|
|
194
|
+
case "launch_unavailable":
|
|
195
|
+
case "lock_timeout":
|
|
196
|
+
case "port_exhausted":
|
|
197
|
+
case "registry_io":
|
|
198
|
+
case "restart_failed_degraded":
|
|
199
|
+
case "restart_failed_rolled_back":
|
|
200
|
+
case "shutdown_failed":
|
|
201
|
+
return true;
|
|
202
|
+
case "argument_invalid":
|
|
203
|
+
case "config_mismatch":
|
|
204
|
+
case "data_dir_conflict":
|
|
205
|
+
case "data_dir_invalid":
|
|
206
|
+
case "identity_mismatch":
|
|
207
|
+
case "instance_not_found":
|
|
208
|
+
case "lock_not_owned":
|
|
209
|
+
case "name_invalid":
|
|
210
|
+
case "port_conflict":
|
|
211
|
+
case "port_invalid":
|
|
212
|
+
case "record_invalid":
|
|
213
|
+
case "self_lifecycle_unsupported":
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function instanceErrorOutput(error: InstancePublicError): InstanceErrorOutput {
|
|
219
|
+
return { schemaVersion: INSTANCE_API_SCHEMA_VERSION, error };
|
|
220
|
+
}
|