@tonyclaw/agent-inspector 2.1.24 → 3.0.1
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 +85 -30
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DsHSCHSx.js → CompareDrawer-BgcAk1te.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-GI3xErl5.js → ProxyViewerContainer-7b_uwvT7.js} +6 -6
- package/.output/public/assets/{ReplayDialog-D0ixqStX.js → ReplayDialog-7Pvhjbjk.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-BG5mb14k.js → RequestAnatomy-BX-UKYQg.js} +1 -1
- package/.output/public/assets/{ResponseView-Bgns6xum.js → ResponseView-zFxGX8xH.js} +2 -2
- package/.output/public/assets/{StreamingChunkSequence-BeqKXAS6.js → StreamingChunkSequence-DzXzVtBF.js} +1 -1
- package/.output/public/assets/{_sessionId-Nme0kuTf.js → _sessionId-CmsUOEIS.js} +1 -1
- package/.output/public/assets/{index-hbDdeKtc.js → index-DXR7RB48.js} +1 -1
- package/.output/public/assets/index-MfTE52Ty.js +1 -0
- package/.output/public/assets/{json-viewer-CWxF2eLV.js → json-viewer-CiMN_9sG.js} +1 -1
- package/.output/public/assets/{main-BDfcCp_1.js → main-Ba9x64uY.js} +2 -2
- package/.output/server/{_sessionId-DOHtZHvJ.mjs → _sessionId-B8GZtC4P.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-HMfALocK.mjs → CompareDrawer-SBDtZDAp.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-DgnyaJPd.mjs → ProxyViewerContainer-B__2O0zh.mjs} +12 -12
- package/.output/server/_ssr/{ReplayDialog-DyIQdJHE.mjs → ReplayDialog-D0u1VHz_.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-8v4e8mYT.mjs → RequestAnatomy-ClvQ3RFh.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-D17WnkXv.mjs → ResponseView-B4UAvUym.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-CALVBf-R.mjs → StreamingChunkSequence-D_aiGGzz.mjs} +2 -2
- package/.output/server/_ssr/{index-D8EDemF-.mjs → index-DuWacKr6.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-BgrtJGqX.mjs → json-viewer-CmNMVinH.mjs} +2 -2
- package/.output/server/_ssr/{router-D3qLyERI.mjs → router-BP46kVrE.mjs} +30 -5
- package/.output/server/{_tanstack-start-manifest_v-6qZpokPP.mjs → _tanstack-start-manifest_v-DltuTRfm.mjs} +1 -1
- package/.output/server/index.mjs +61 -61
- package/README.md +30 -8
- package/package.json +1 -1
- package/src/cli/doctor.ts +1 -1
- package/src/cli/onboard.ts +15 -9
- package/src/cli.ts +96 -34
- package/src/components/ProxyViewer.tsx +2 -2
- package/src/components/providers/SettingsDialog.tsx +2 -2
- package/src/lib/serverPort.ts +9 -3
- package/src/proxy/sessionProcess.ts +22 -1
- package/src/proxy/socketTracker.ts +1 -1
- package/.output/public/assets/index-CUKpd9jb.js +0 -1
package/.output/server/index.mjs
CHANGED
|
@@ -38,114 +38,114 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-07-
|
|
41
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/
|
|
45
|
+
"/assets/CompareDrawer-BgcAk1te.js": {
|
|
46
46
|
"type": "text/javascript; charset=utf-8",
|
|
47
|
-
"etag": '"
|
|
48
|
-
"mtime": "2026-07-
|
|
49
|
-
"size":
|
|
50
|
-
"path": "../public/assets/
|
|
47
|
+
"etag": '"4bbf-gA9nBXsloTEIMhmM3ql/4qNmhOs"',
|
|
48
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
49
|
+
"size": 19391,
|
|
50
|
+
"path": "../public/assets/CompareDrawer-BgcAk1te.js"
|
|
51
51
|
},
|
|
52
|
-
"/assets/
|
|
52
|
+
"/assets/index-DXR7RB48.js": {
|
|
53
53
|
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"
|
|
55
|
-
"mtime": "2026-07-
|
|
56
|
-
"size":
|
|
57
|
-
"path": "../public/assets/
|
|
54
|
+
"etag": '"1cd2c-3SEnnZb993yst8Dzg9UbKuoON3A"',
|
|
55
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
56
|
+
"size": 118060,
|
|
57
|
+
"path": "../public/assets/index-DXR7RB48.js"
|
|
58
58
|
},
|
|
59
|
-
"/assets/
|
|
59
|
+
"/assets/json-viewer-CiMN_9sG.js": {
|
|
60
60
|
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"
|
|
62
|
-
"mtime": "2026-07-
|
|
63
|
-
"size":
|
|
64
|
-
"path": "../public/assets/
|
|
61
|
+
"etag": '"1ae6-uMTpz3tfSXntmUuk5MzHyqBxhWI"',
|
|
62
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
63
|
+
"size": 6886,
|
|
64
|
+
"path": "../public/assets/json-viewer-CiMN_9sG.js"
|
|
65
65
|
},
|
|
66
66
|
"/assets/index-Tq5s9NV0.css": {
|
|
67
67
|
"type": "text/css; charset=utf-8",
|
|
68
68
|
"etag": '"22408-MQKT02eqQudVEj/DozyiEJoTl6E"',
|
|
69
|
-
"mtime": "2026-07-
|
|
69
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
70
70
|
"size": 140296,
|
|
71
71
|
"path": "../public/assets/index-Tq5s9NV0.css"
|
|
72
72
|
},
|
|
73
73
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
74
74
|
"type": "image/jpeg",
|
|
75
75
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
76
|
-
"mtime": "2026-07-
|
|
76
|
+
"mtime": "2026-07-07T00:47:56.084Z",
|
|
77
77
|
"size": 6918,
|
|
78
78
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
79
79
|
},
|
|
80
|
-
"/assets/
|
|
80
|
+
"/assets/index-MfTE52Ty.js": {
|
|
81
81
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-07-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/
|
|
82
|
+
"etag": '"74-xI8cgjppS3YpgGFVqBj/+DUVe/4"',
|
|
83
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
84
|
+
"size": 116,
|
|
85
|
+
"path": "../public/assets/index-MfTE52Ty.js"
|
|
86
|
+
},
|
|
87
|
+
"/assets/ReplayDialog-7Pvhjbjk.js": {
|
|
88
|
+
"type": "text/javascript; charset=utf-8",
|
|
89
|
+
"etag": '"31d6-WfysEtvfuOApCBk5olHqKk8rMfU"',
|
|
90
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
91
|
+
"size": 12758,
|
|
92
|
+
"path": "../public/assets/ReplayDialog-7Pvhjbjk.js"
|
|
86
93
|
},
|
|
87
|
-
"/assets/
|
|
94
|
+
"/assets/main-Ba9x64uY.js": {
|
|
88
95
|
"type": "text/javascript; charset=utf-8",
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-07-
|
|
96
|
+
"etag": '"512fd-xrDcMUYYndBJtS06eXJ9QM25lz4"',
|
|
97
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
98
|
+
"size": 332541,
|
|
99
|
+
"path": "../public/assets/main-Ba9x64uY.js"
|
|
100
|
+
},
|
|
101
|
+
"/assets/StreamingChunkSequence-DzXzVtBF.js": {
|
|
102
|
+
"type": "text/javascript; charset=utf-8",
|
|
103
|
+
"etag": '"dd6-FSNaNigsd1X+gyqALfVxeG2s4fo"',
|
|
104
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
91
105
|
"size": 3542,
|
|
92
|
-
"path": "../public/assets/StreamingChunkSequence-
|
|
106
|
+
"path": "../public/assets/StreamingChunkSequence-DzXzVtBF.js"
|
|
93
107
|
},
|
|
94
108
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
95
109
|
"type": "image/svg+xml",
|
|
96
110
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
97
|
-
"mtime": "2026-07-
|
|
111
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
98
112
|
"size": 11256,
|
|
99
113
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
100
114
|
},
|
|
101
|
-
"/assets/
|
|
102
|
-
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"512fd-wNI+QxyzwhA/0QqJbbcpb3MMxmg"',
|
|
104
|
-
"mtime": "2026-07-06T23:47:30.047Z",
|
|
105
|
-
"size": 332541,
|
|
106
|
-
"path": "../public/assets/main-BDfcCp_1.js"
|
|
107
|
-
},
|
|
108
|
-
"/assets/ReplayDialog-D0ixqStX.js": {
|
|
115
|
+
"/assets/RequestAnatomy-BX-UKYQg.js": {
|
|
109
116
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"
|
|
111
|
-
"mtime": "2026-07-
|
|
112
|
-
"size":
|
|
113
|
-
"path": "../public/assets/
|
|
117
|
+
"etag": '"43f2-Zq3l43VsakNoYmpaf2yidbFacQg"',
|
|
118
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
119
|
+
"size": 17394,
|
|
120
|
+
"path": "../public/assets/RequestAnatomy-BX-UKYQg.js"
|
|
114
121
|
},
|
|
115
|
-
"/assets/ResponseView-
|
|
122
|
+
"/assets/ResponseView-zFxGX8xH.js": {
|
|
116
123
|
"type": "text/javascript; charset=utf-8",
|
|
117
|
-
"etag": '"47fa-
|
|
118
|
-
"mtime": "2026-07-
|
|
124
|
+
"etag": '"47fa-7HB1lxdpkTuo7BEzpS+JAr6zRjM"',
|
|
125
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
119
126
|
"size": 18426,
|
|
120
|
-
"path": "../public/assets/ResponseView-
|
|
127
|
+
"path": "../public/assets/ResponseView-zFxGX8xH.js"
|
|
121
128
|
},
|
|
122
|
-
"/assets/_sessionId-
|
|
129
|
+
"/assets/_sessionId-CmsUOEIS.js": {
|
|
123
130
|
"type": "text/javascript; charset=utf-8",
|
|
124
|
-
"etag": '"36c-
|
|
125
|
-
"mtime": "2026-07-
|
|
131
|
+
"etag": '"36c-oBFmeA36vW57pay3tX7/Tm7ZnGI"',
|
|
132
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
126
133
|
"size": 876,
|
|
127
|
-
"path": "../public/assets/_sessionId-
|
|
134
|
+
"path": "../public/assets/_sessionId-CmsUOEIS.js"
|
|
128
135
|
},
|
|
129
136
|
"/assets/qwen-CONDcHqt.png": {
|
|
130
137
|
"type": "image/png",
|
|
131
138
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
132
|
-
"mtime": "2026-07-
|
|
139
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
133
140
|
"size": 357059,
|
|
134
141
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
135
142
|
},
|
|
136
|
-
"/assets/
|
|
137
|
-
"type": "text/javascript; charset=utf-8",
|
|
138
|
-
"etag": '"1cd2c-o4cSL+ZBVABZPPb9xrCnibEnQQQ"',
|
|
139
|
-
"mtime": "2026-07-06T23:47:30.047Z",
|
|
140
|
-
"size": 118060,
|
|
141
|
-
"path": "../public/assets/index-hbDdeKtc.js"
|
|
142
|
-
},
|
|
143
|
-
"/assets/ProxyViewerContainer-GI3xErl5.js": {
|
|
143
|
+
"/assets/ProxyViewerContainer-7b_uwvT7.js": {
|
|
144
144
|
"type": "text/javascript; charset=utf-8",
|
|
145
|
-
"etag": '"
|
|
146
|
-
"mtime": "2026-07-
|
|
147
|
-
"size":
|
|
148
|
-
"path": "../public/assets/ProxyViewerContainer-
|
|
145
|
+
"etag": '"aef11-9vtbsodrImAt3S4nrgSZgSQRdnc"',
|
|
146
|
+
"mtime": "2026-07-07T00:47:56.086Z",
|
|
147
|
+
"size": 716561,
|
|
148
|
+
"path": "../public/assets/ProxyViewerContainer-7b_uwvT7.js"
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
function readAsset(id) {
|
package/README.md
CHANGED
|
@@ -62,13 +62,13 @@ The onboarding command installs guided setup skills for local agents:
|
|
|
62
62
|
|
|
63
63
|
- Claude Code: `~/.claude/skills/agent-inspector-onboard/SKILL.md` plus a slash command.
|
|
64
64
|
- Codex: `~/.codex/skills/agent-inspector-onboard/SKILL.md`, focused on connecting
|
|
65
|
-
`http://localhost:
|
|
65
|
+
`http://localhost:9527/api/mcp` through Codex `mcp_servers.agent-inspector`.
|
|
66
66
|
- OpenCode: run `agent-inspector onboard --opencode-only` to merge
|
|
67
67
|
`mcp.agent-inspector` into `~/.config/opencode/opencode.json` or `opencode.jsonc`, then verify
|
|
68
68
|
with `opencode mcp list`.
|
|
69
69
|
- MiMo Code: run `agent-inspector onboard --mimo-only` to merge `mcp.agent-inspector` into
|
|
70
70
|
`~/.config/mimocode/mimocode.jsonc` or `mimocode.json`, then route MiMo through the proxy with
|
|
71
|
-
`OPENAI_BASE_URL=http://localhost:
|
|
71
|
+
`OPENAI_BASE_URL=http://localhost:9527/proxy`.
|
|
72
72
|
|
|
73
73
|
During npm global install, Agent Inspector also makes a best-effort onboarding skill install for
|
|
74
74
|
detected local agents. If `~/.claude` exists, it installs the Claude Code skill and slash command.
|
|
@@ -123,20 +123,39 @@ agent-inspector doctor --chrome-extension
|
|
|
123
123
|
Then point an AI coding tool at the proxy:
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
ANTHROPIC_BASE_URL=http://localhost:
|
|
126
|
+
ANTHROPIC_BASE_URL=http://localhost:9527/proxy <tool>
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
The web UI runs at http://localhost:
|
|
130
|
-
`http://localhost:
|
|
129
|
+
The web UI runs at http://localhost:9527. The public proxy endpoint is also
|
|
130
|
+
`http://localhost:9527/proxy`; internally Agent Inspector may run the app on a private helper port,
|
|
131
131
|
but AI tools should use the public URL printed by the CLI.
|
|
132
132
|
|
|
133
|
+
For v3 compatibility, the packaged CLI also keeps `http://localhost:25947` open as a legacy alias
|
|
134
|
+
when it starts on the default port. Existing AI tool and MCP configs that still point at `25947`
|
|
135
|
+
continue to work for now, but new configs should use `9527`.
|
|
136
|
+
|
|
137
|
+
## v3.0 Port Migration
|
|
138
|
+
|
|
139
|
+
Agent Inspector v3.0 changes the default public port from `25947` to `9527`. The packaged CLI keeps
|
|
140
|
+
`25947` as a legacy alias when you run the default `agent-inspector` command, so existing AI coding
|
|
141
|
+
tool and MCP configs do not need to be edited immediately.
|
|
142
|
+
|
|
143
|
+
Use these endpoints for new configs:
|
|
144
|
+
|
|
145
|
+
- Web UI: `http://localhost:9527`
|
|
146
|
+
- Proxy: `http://localhost:9527/proxy`
|
|
147
|
+
- OpenAI-compatible `/v1` proxy: `http://localhost:9527/proxy/v1`
|
|
148
|
+
- MCP: `http://localhost:9527/api/mcp`
|
|
149
|
+
|
|
150
|
+
If you intentionally want only the new port, start with `agent-inspector --no-legacy-port`.
|
|
151
|
+
|
|
133
152
|
For Codex-style OpenAI Responses clients, configure the proxy as an OpenAI-compatible `/v1` base:
|
|
134
153
|
|
|
135
154
|
```toml
|
|
136
155
|
model_provider = "agent-inspector"
|
|
137
156
|
|
|
138
157
|
[model_providers."agent-inspector"]
|
|
139
|
-
base_url = "http://127.0.0.1:
|
|
158
|
+
base_url = "http://127.0.0.1:9527/proxy/v1"
|
|
140
159
|
wire_api = "responses"
|
|
141
160
|
```
|
|
142
161
|
|
|
@@ -226,7 +245,7 @@ upstream URL failed.
|
|
|
226
245
|
Agent Inspector exposes MCP at:
|
|
227
246
|
|
|
228
247
|
```text
|
|
229
|
-
http://localhost:
|
|
248
|
+
http://localhost:9527/api/mcp
|
|
230
249
|
```
|
|
231
250
|
|
|
232
251
|
Coding agents can connect to this MCP surface directly over Streamable HTTP, or through the
|
|
@@ -244,10 +263,13 @@ The MCP HTTP surface is also documented as OpenAPI YAML in
|
|
|
244
263
|
[`docs/mcp-openapi.yaml`](docs/mcp-openapi.yaml).
|
|
245
264
|
|
|
246
265
|
Use only one transport for the same Inspector instance. If the MCP client supports Streamable HTTP,
|
|
247
|
-
configure `http://localhost:
|
|
266
|
+
configure `http://localhost:9527/api/mcp` directly. If it only supports stdio, configure
|
|
248
267
|
`agent-inspector-mcp stdio`; that command is only a bridge to `/api/mcp`, not a second Inspector
|
|
249
268
|
server.
|
|
250
269
|
|
|
270
|
+
Legacy MCP configs that still use `http://localhost:25947/api/mcp` are accepted by the default v3
|
|
271
|
+
CLI alias during the compatibility window.
|
|
272
|
+
|
|
251
273
|
Coding agents can use the MCP surface in three ways:
|
|
252
274
|
|
|
253
275
|
- Tools: perform actions such as listing logs, reading bounded log details, testing providers,
|
package/package.json
CHANGED
package/src/cli/doctor.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
3
3
|
import { createConnection } from "node:net";
|
|
4
4
|
import { migrateLegacyDataDirs, resolveDataDir } from "../proxy/dataDir";
|
|
5
5
|
|
|
6
|
-
const DEFAULT_PORT =
|
|
6
|
+
const DEFAULT_PORT = 9527;
|
|
7
7
|
const PROBE_TIMEOUT_MS = 2000;
|
|
8
8
|
const EXTENSION_REQUIRED_FILES = [
|
|
9
9
|
"manifest.json",
|
package/src/cli/onboard.ts
CHANGED
|
@@ -35,8 +35,9 @@ import { renderSkillOnboard, REQUIRED_PHASE_HEADINGS } from "./templates/skill-o
|
|
|
35
35
|
const __filename = fileURLToPath(import.meta.url);
|
|
36
36
|
const __dirname = dirname(__filename);
|
|
37
37
|
|
|
38
|
-
const DEFAULT_PORT =
|
|
38
|
+
const DEFAULT_PORT = 9527;
|
|
39
39
|
const DEFAULT_MCP_URL = `http://localhost:${DEFAULT_PORT}/api/mcp`;
|
|
40
|
+
const LEGACY_MCP_URL = "http://localhost:25947/api/mcp";
|
|
40
41
|
const SKILL_DIR_NAME = "agent-inspector-onboard";
|
|
41
42
|
const SKILL_FILE_NAME = "SKILL.md";
|
|
42
43
|
// Windows reserves `:` for NTFS alternate data streams, so a file named
|
|
@@ -630,6 +631,10 @@ function stringArrayEquals(value: unknown, expected: readonly string[]): boolean
|
|
|
630
631
|
return value.every((item, index) => item === expected[index]);
|
|
631
632
|
}
|
|
632
633
|
|
|
634
|
+
function knownMcpEndpoints(endpoint: string): readonly string[] {
|
|
635
|
+
return endpoint === DEFAULT_MCP_URL ? [DEFAULT_MCP_URL, LEGACY_MCP_URL] : [endpoint];
|
|
636
|
+
}
|
|
637
|
+
|
|
633
638
|
function isAgentLocalEntry(value: unknown, endpoint: string, ignoreEnabled: boolean): boolean {
|
|
634
639
|
if (!isObject(value)) {
|
|
635
640
|
return false;
|
|
@@ -641,16 +646,14 @@ function isAgentLocalEntry(value: unknown, endpoint: string, ignoreEnabled: bool
|
|
|
641
646
|
}
|
|
642
647
|
|
|
643
648
|
const env = value["environment"];
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
"stdio",
|
|
647
|
-
|
|
648
|
-
endpoint,
|
|
649
|
-
]);
|
|
649
|
+
const endpoints = knownMcpEndpoints(endpoint);
|
|
650
|
+
const usesUrlArg = endpoints.some((candidate) =>
|
|
651
|
+
stringArrayEquals(value["command"], ["agent-inspector-mcp", "stdio", "--url", candidate]),
|
|
652
|
+
);
|
|
650
653
|
const usesEnv =
|
|
651
654
|
stringArrayEquals(value["command"], ["agent-inspector-mcp", "stdio"]) &&
|
|
652
655
|
isObject(env) &&
|
|
653
|
-
env["AGENT_INSPECTOR_MCP_URL"] ===
|
|
656
|
+
endpoints.some((candidate) => env["AGENT_INSPECTOR_MCP_URL"] === candidate);
|
|
654
657
|
|
|
655
658
|
return value["type"] === "local" && (usesUrlArg || usesEnv);
|
|
656
659
|
}
|
|
@@ -665,7 +668,10 @@ function isAgentRemoteEntry(value: unknown, endpoint: string, ignoreEnabled: boo
|
|
|
665
668
|
return false;
|
|
666
669
|
}
|
|
667
670
|
|
|
668
|
-
return
|
|
671
|
+
return (
|
|
672
|
+
value["type"] === "remote" &&
|
|
673
|
+
knownMcpEndpoints(endpoint).some((candidate) => value["url"] === candidate)
|
|
674
|
+
);
|
|
669
675
|
}
|
|
670
676
|
|
|
671
677
|
function isKnownAgentEntry(value: unknown, endpoint: string, ignoreEnabled: boolean): boolean {
|
package/src/cli.ts
CHANGED
|
@@ -23,14 +23,13 @@ import { startIdentityProxy } from "./proxy/identityProxy.js";
|
|
|
23
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
24
|
const __dirname = dirname(__filename);
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const DEFAULT_UPSTREAM_PORT = 25949;
|
|
26
|
+
// v3 defaults the public entrypoint to 9527 while keeping 25947 as a
|
|
27
|
+
// compatibility alias for older AI-tool and MCP configs. The TanStack Start
|
|
28
|
+
// runtime stays on a private upstream port and both public ports reverse-proxy
|
|
29
|
+
// to that same runtime, so logs, sessions, and MCP state remain unified.
|
|
30
|
+
const DEFAULT_PORT = 9527;
|
|
31
|
+
const LEGACY_ALIAS_PORT = 25947;
|
|
32
|
+
const DEFAULT_UPSTREAM_PORT = 9529;
|
|
34
33
|
const LOCAL_PROBE_TIMEOUT_MS = 2000;
|
|
35
34
|
const BRANDED_WINDOWS_RUNTIME_EXE = "agent-inspector.exe";
|
|
36
35
|
const DEFAULT_CAPTURE_MODE = "simple";
|
|
@@ -159,6 +158,10 @@ function openBrowser(targetUrl: string): void {
|
|
|
159
158
|
detached: true,
|
|
160
159
|
windowsHide: true,
|
|
161
160
|
});
|
|
161
|
+
browserProcess.once("error", () => {
|
|
162
|
+
// Opening a browser is best-effort. Minimal Linux/container images may not
|
|
163
|
+
// include xdg-open, and that should not make the CLI look unhealthy.
|
|
164
|
+
});
|
|
162
165
|
browserProcess.unref();
|
|
163
166
|
}
|
|
164
167
|
|
|
@@ -244,6 +247,26 @@ function printAccessHints(port: number, host?: string): void {
|
|
|
244
247
|
}
|
|
245
248
|
}
|
|
246
249
|
|
|
250
|
+
function pickUpstreamPort(publicPort: number, legacyAliasPort: number | null): number {
|
|
251
|
+
const candidates = [
|
|
252
|
+
DEFAULT_UPSTREAM_PORT,
|
|
253
|
+
publicPort + 2 <= 65535 ? publicPort + 2 : publicPort - 2,
|
|
254
|
+
LEGACY_ALIAS_PORT + 2,
|
|
255
|
+
];
|
|
256
|
+
for (const candidate of candidates) {
|
|
257
|
+
if (
|
|
258
|
+
Number.isInteger(candidate) &&
|
|
259
|
+
candidate > 0 &&
|
|
260
|
+
candidate <= 65535 &&
|
|
261
|
+
candidate !== publicPort &&
|
|
262
|
+
candidate !== legacyAliasPort
|
|
263
|
+
) {
|
|
264
|
+
return candidate;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return DEFAULT_UPSTREAM_PORT;
|
|
268
|
+
}
|
|
269
|
+
|
|
247
270
|
/** Try to start the identity proxy. Returns `null` (and prints a warning)
|
|
248
271
|
* if the listen port is already in use by another process — e.g. when
|
|
249
272
|
* restarting a previous instance that didn't shut down cleanly. The
|
|
@@ -273,7 +296,7 @@ async function tryStartIdentityProxy(
|
|
|
273
296
|
}
|
|
274
297
|
|
|
275
298
|
async function runStart(args: string[]): Promise<void> {
|
|
276
|
-
const envPort = process.env["PORT"];
|
|
299
|
+
const envPort = process.env["AGENT_INSPECTOR_PORT"] ?? process.env["PORT"];
|
|
277
300
|
const portDefault = envPort !== undefined ? Number(envPort) : DEFAULT_PORT;
|
|
278
301
|
const envHost = process.env["NITRO_HOST"] ?? process.env["HOST"];
|
|
279
302
|
const envMode =
|
|
@@ -290,10 +313,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
290
313
|
let captureMode = DEFAULT_CAPTURE_MODE;
|
|
291
314
|
let captureModeWasSpecified = false;
|
|
292
315
|
let enableIdentityProxy = true;
|
|
293
|
-
let
|
|
294
|
-
process.env["AGENT_INSPECTOR_PORT"] !== undefined
|
|
295
|
-
? Number(process.env["AGENT_INSPECTOR_PORT"])
|
|
296
|
-
: DEFAULT_PORT;
|
|
316
|
+
let legacyAliasEnabled = true;
|
|
297
317
|
|
|
298
318
|
if (envMode !== undefined && envMode !== "") {
|
|
299
319
|
const parsedMode = parseCaptureMode(envMode);
|
|
@@ -402,10 +422,13 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
402
422
|
process.exitCode = 1;
|
|
403
423
|
return;
|
|
404
424
|
}
|
|
405
|
-
|
|
425
|
+
port = parsed;
|
|
406
426
|
i++;
|
|
407
427
|
break;
|
|
408
428
|
}
|
|
429
|
+
case "--no-legacy-port":
|
|
430
|
+
legacyAliasEnabled = false;
|
|
431
|
+
break;
|
|
409
432
|
default:
|
|
410
433
|
break;
|
|
411
434
|
}
|
|
@@ -489,11 +512,13 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
489
512
|
}
|
|
490
513
|
}
|
|
491
514
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
// the
|
|
496
|
-
|
|
515
|
+
const legacyAliasPort =
|
|
516
|
+
enableIdentityProxy && legacyAliasEnabled && port === DEFAULT_PORT ? LEGACY_ALIAS_PORT : null;
|
|
517
|
+
|
|
518
|
+
// TanStack Start listens on the private upstream port; identity proxies own
|
|
519
|
+
// the public-facing port(s). When the identity proxy is disabled we fall
|
|
520
|
+
// back to TanStack listening on the public port directly.
|
|
521
|
+
const upstreamPort = enableIdentityProxy ? pickUpstreamPort(port, legacyAliasPort) : port;
|
|
497
522
|
process.env["PORT"] = String(upstreamPort);
|
|
498
523
|
|
|
499
524
|
const url = urlForHost(port, host);
|
|
@@ -526,8 +551,8 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
526
551
|
const restartPorts = new Set<number>();
|
|
527
552
|
restartPorts.add(port);
|
|
528
553
|
if (enableIdentityProxy) {
|
|
529
|
-
restartPorts.add(identityProxyPort);
|
|
530
554
|
restartPorts.add(upstreamPort);
|
|
555
|
+
if (legacyAliasPort !== null) restartPorts.add(legacyAliasPort);
|
|
531
556
|
}
|
|
532
557
|
for (const targetPort of restartPorts) {
|
|
533
558
|
killProcessOnPort(targetPort);
|
|
@@ -538,6 +563,11 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
538
563
|
console.log(` Capture mode: ${captureMode}`);
|
|
539
564
|
console.log(` Proxy: ${url}/proxy`);
|
|
540
565
|
printAccessHints(port, host);
|
|
566
|
+
if (legacyAliasPort !== null) {
|
|
567
|
+
console.log(` Legacy UI: http://localhost:${legacyAliasPort}`);
|
|
568
|
+
console.log(` Legacy proxy: http://localhost:${legacyAliasPort}/proxy`);
|
|
569
|
+
console.log(` Legacy MCP: http://localhost:${legacyAliasPort}/api/mcp`);
|
|
570
|
+
}
|
|
541
571
|
console.log(``);
|
|
542
572
|
console.log(`Route AI coding tools through the proxy:`);
|
|
543
573
|
console.log(` Claude Code: ANTHROPIC_BASE_URL=${url}/proxy claude`);
|
|
@@ -594,6 +624,8 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
594
624
|
serverEnv["HOST"] = host;
|
|
595
625
|
serverEnv["NITRO_HOST"] = host;
|
|
596
626
|
}
|
|
627
|
+
serverEnv["AGENT_INSPECTOR_PUBLIC_PORT"] = String(port);
|
|
628
|
+
serverEnv["PROXY_PORT"] = String(port);
|
|
597
629
|
serverEnv["AGENT_INSPECTOR_CAPTURE_MODE"] = captureMode;
|
|
598
630
|
const serverProcess = spawn(serverCommand.command, serverCommand.args, {
|
|
599
631
|
stdio: background ? ["ignore", "ignore", "ignore"] : ["ignore", "pipe", "pipe"],
|
|
@@ -601,6 +633,10 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
601
633
|
env: serverEnv,
|
|
602
634
|
windowsHide: background,
|
|
603
635
|
});
|
|
636
|
+
serverProcess.once("error", (err) => {
|
|
637
|
+
console.error(`Failed to start Agent Inspector runtime: ${err.message}`);
|
|
638
|
+
});
|
|
639
|
+
const serverExit = waitForProcessExit(serverProcess);
|
|
604
640
|
if (!background) {
|
|
605
641
|
pipeServerOutput(serverProcess, {
|
|
606
642
|
enableIdentityProxy,
|
|
@@ -615,9 +651,23 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
615
651
|
// This lets AI tools (which can't easily set those headers themselves)
|
|
616
652
|
// still get accurate session attribution. Started only after TanStack
|
|
617
653
|
// Start is healthy, so the upstream is ready by the time clients connect.
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
:
|
|
654
|
+
const identityProxies: Array<{
|
|
655
|
+
label: "primary" | "legacy";
|
|
656
|
+
port: number;
|
|
657
|
+
server: import("node:http").Server;
|
|
658
|
+
}> = [];
|
|
659
|
+
if (enableIdentityProxy) {
|
|
660
|
+
const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host);
|
|
661
|
+
if (primaryProxy !== null) {
|
|
662
|
+
identityProxies.push({ label: "primary", port, server: primaryProxy });
|
|
663
|
+
}
|
|
664
|
+
if (legacyAliasPort !== null) {
|
|
665
|
+
const legacyProxy = await tryStartIdentityProxy(legacyAliasPort, upstreamPort, host);
|
|
666
|
+
if (legacyProxy !== null) {
|
|
667
|
+
identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
621
671
|
|
|
622
672
|
if (background) {
|
|
623
673
|
serverProcess.unref();
|
|
@@ -625,18 +675,24 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
625
675
|
// not started yet so the public port is not yet accepting traffic.
|
|
626
676
|
if (await waitForInspectorHealthy(upstreamPort, 5000, host)) {
|
|
627
677
|
console.log(`agent-inspector background server is ready at ${url}`);
|
|
628
|
-
if (
|
|
629
|
-
console.log(`Identity proxy ready on port ${
|
|
678
|
+
if (identityProxies.length > 0) {
|
|
679
|
+
console.log(`Identity proxy ready on port ${port} (PID-attributing proxy).`);
|
|
630
680
|
}
|
|
631
681
|
printAccessHints(port, host);
|
|
632
|
-
if (
|
|
682
|
+
if (legacyAliasPort !== null) {
|
|
683
|
+
console.log(` Legacy proxy: http://localhost:${legacyAliasPort}/proxy`);
|
|
684
|
+
console.log(` Legacy MCP: http://localhost:${legacyAliasPort}/api/mcp`);
|
|
685
|
+
}
|
|
686
|
+
if (identityProxies.length > 0) {
|
|
633
687
|
console.log(
|
|
634
688
|
``,
|
|
635
689
|
`Route AI coding tools through the identity proxy for accurate PID attribution:`,
|
|
636
|
-
` Claude Code: ANTHROPIC_BASE_URL=http://localhost:${
|
|
637
|
-
` OpenCode: LLM_BASE_URL=http://localhost:${
|
|
638
|
-
` MiMo Code: OPENAI_BASE_URL=http://localhost:${
|
|
639
|
-
|
|
690
|
+
` Claude Code: ANTHROPIC_BASE_URL=http://localhost:${port}/proxy claude`,
|
|
691
|
+
` OpenCode: LLM_BASE_URL=http://localhost:${port}/proxy opencode`,
|
|
692
|
+
` MiMo Code: OPENAI_BASE_URL=http://localhost:${port}/proxy mimo`,
|
|
693
|
+
legacyAliasPort === null
|
|
694
|
+
? ` Override the port with --port <n> when needed.`
|
|
695
|
+
: ` Legacy configs using http://localhost:${legacyAliasPort}/proxy still work.`,
|
|
640
696
|
);
|
|
641
697
|
}
|
|
642
698
|
return;
|
|
@@ -646,17 +702,23 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
646
702
|
return;
|
|
647
703
|
}
|
|
648
704
|
|
|
649
|
-
if (
|
|
705
|
+
if (identityProxies.length > 0) {
|
|
650
706
|
console.log(``);
|
|
651
707
|
console.log(`Identity proxy ready at ${url} (PID-attributing public entrypoint).`);
|
|
708
|
+
if (legacyAliasPort !== null) {
|
|
709
|
+
const legacyReady = identityProxies.some((proxy) => proxy.label === "legacy");
|
|
710
|
+
if (legacyReady) {
|
|
711
|
+
console.log(` Legacy alias ready at http://localhost:${legacyAliasPort}.`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
652
714
|
if (upstreamPort !== port) {
|
|
653
715
|
console.log(` Internal runtime port ${upstreamPort} is hidden behind the public proxy.`);
|
|
654
716
|
}
|
|
655
717
|
}
|
|
656
718
|
|
|
657
|
-
process.exitCode = await
|
|
719
|
+
process.exitCode = await serverExit;
|
|
658
720
|
|
|
659
|
-
|
|
660
|
-
await new Promise<void>((resolve) =>
|
|
721
|
+
for (const proxy of identityProxies) {
|
|
722
|
+
await new Promise<void>((resolve) => proxy.server.close(() => resolve()));
|
|
661
723
|
}
|
|
662
724
|
}
|
|
@@ -2143,8 +2143,8 @@ export function ProxyViewer({
|
|
|
2143
2143
|
<div className="bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_18px_52px_rgba(0,0,0,0.18)] mx-auto max-w-2xl space-y-4 rounded-[8px] px-4 py-8">
|
|
2144
2144
|
<p className="text-sm">No requests captured yet.</p>
|
|
2145
2145
|
<div className="flex flex-col items-center gap-2">
|
|
2146
|
-
<CopyableCommand command="ANTHROPIC_BASE_URL=http://localhost:
|
|
2147
|
-
<CopyableCommand command="OPENAI_BASE_URL=http://localhost:
|
|
2146
|
+
<CopyableCommand command="ANTHROPIC_BASE_URL=http://localhost:9527/proxy <your-tool>" />
|
|
2147
|
+
<CopyableCommand command="OPENAI_BASE_URL=http://localhost:9527/proxy <your-tool>" />
|
|
2148
2148
|
</div>
|
|
2149
2149
|
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
2150
2150
|
Container note: if your AI tool runs in a different container or host than
|
|
@@ -303,7 +303,7 @@ function CopyableSetupValue({
|
|
|
303
303
|
function OnboardingSettingsTab(): JSX.Element {
|
|
304
304
|
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
305
305
|
const origin = useMemo(() => {
|
|
306
|
-
if (typeof window === "undefined") return "http://localhost:
|
|
306
|
+
if (typeof window === "undefined") return "http://localhost:9527";
|
|
307
307
|
return window.location.origin;
|
|
308
308
|
}, []);
|
|
309
309
|
const values = useMemo(
|
|
@@ -454,7 +454,7 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
454
454
|
function McpSettingsTab(): JSX.Element {
|
|
455
455
|
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
456
456
|
const origin = useMemo(() => {
|
|
457
|
-
if (typeof window === "undefined") return "http://localhost:
|
|
457
|
+
if (typeof window === "undefined") return "http://localhost:9527";
|
|
458
458
|
return window.location.origin;
|
|
459
459
|
}, []);
|
|
460
460
|
const endpoint = `${origin}/api/mcp`;
|
package/src/lib/serverPort.ts
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* Initialization order:
|
|
8
8
|
* 1. `setCurrentPort(port)` — explicit override (used by tests, or any
|
|
9
9
|
* code that has direct knowledge of the bound port).
|
|
10
|
-
* 2. `process.env.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* 2. `process.env.AGENT_INSPECTOR_PUBLIC_PORT` — the public identity-proxy
|
|
11
|
+
* port. The CLI sets this when the runtime is hidden behind a private
|
|
12
|
+
* upstream port.
|
|
13
|
+
* 3. `process.env.PORT` — fallback for direct dev/server runs.
|
|
13
14
|
*
|
|
14
15
|
* `getCurrentPort()` throws if neither source is available.
|
|
15
16
|
*/
|
|
@@ -25,6 +26,11 @@ export function setCurrentPort(port: number): void {
|
|
|
25
26
|
|
|
26
27
|
export function getCurrentPort(): number {
|
|
27
28
|
if (overridePort !== null) return overridePort;
|
|
29
|
+
const publicPort = process.env["AGENT_INSPECTOR_PUBLIC_PORT"];
|
|
30
|
+
if (publicPort !== undefined && publicPort !== "") {
|
|
31
|
+
const n = Number(publicPort);
|
|
32
|
+
if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
|
|
33
|
+
}
|
|
28
34
|
const envPort = process.env["PORT"];
|
|
29
35
|
if (envPort !== undefined && envPort !== "") {
|
|
30
36
|
const n = Number(envPort);
|