@tonyclaw/agent-inspector 2.1.23 → 3.0.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.
Files changed (39) hide show
  1. package/.output/cli.js +78 -29
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-Cvgl_Jmi.js → CompareDrawer-ZL1yvIH6.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-CNLLZq37.js → ProxyViewerContainer-vhfV449d.js} +8 -8
  5. package/.output/public/assets/{ReplayDialog-DeEELx0X.js → ReplayDialog-D-gDSuhe.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-CrLSqdiA.js → RequestAnatomy-CVt2vHih.js} +1 -1
  7. package/.output/public/assets/{ResponseView-CFIqDL5E.js → ResponseView-zVdHc0mv.js} +2 -2
  8. package/.output/public/assets/{StreamingChunkSequence-DSRjbgqb.js → StreamingChunkSequence-DQFhpV_4.js} +1 -1
  9. package/.output/public/assets/{_sessionId-ZuH6-ZX5.js → _sessionId-DeeeQcS9.js} +1 -1
  10. package/.output/public/assets/index-BJvPLWvO.js +1 -0
  11. package/.output/public/assets/index-Tq5s9NV0.css +1 -0
  12. package/.output/public/assets/{index-BZxLBVYd.js → index-_inxJ5Yi.js} +1 -1
  13. package/.output/public/assets/{json-viewer-DERQNZRV.js → json-viewer-B9gYSlz7.js} +1 -1
  14. package/.output/public/assets/{main-BoshTI0W.js → main-Do_fjInc.js} +2 -2
  15. package/.output/server/{_sessionId-BYGtH1pK.mjs → _sessionId-D1XraBbJ.mjs} +2 -2
  16. package/.output/server/_ssr/{CompareDrawer-OchnKiac.mjs → CompareDrawer-Ot4EsLht.mjs} +2 -2
  17. package/.output/server/_ssr/{ProxyViewerContainer-C2lwYwDu.mjs → ProxyViewerContainer-Cb4ZWwFC.mjs} +45 -36
  18. package/.output/server/_ssr/{ReplayDialog-BYwaF14u.mjs → ReplayDialog-B5m_dFdr.mjs} +3 -3
  19. package/.output/server/_ssr/{RequestAnatomy-DTueiqT5.mjs → RequestAnatomy-OUrXKyoI.mjs} +2 -2
  20. package/.output/server/_ssr/{ResponseView-CqB9NKHB.mjs → ResponseView-DV1N1gQ8.mjs} +2 -2
  21. package/.output/server/_ssr/{StreamingChunkSequence-DENB9VUj.mjs → StreamingChunkSequence-CJl70SsF.mjs} +2 -2
  22. package/.output/server/_ssr/{index-BR3ea3Zb.mjs → index-CztmjZ0i.mjs} +2 -2
  23. package/.output/server/_ssr/index.mjs +2 -2
  24. package/.output/server/_ssr/{json-viewer-BU9ZUaHK.mjs → json-viewer-CO0sbce_.mjs} +2 -2
  25. package/.output/server/_ssr/{router-DT6BcrEg.mjs → router-BxWKty_9.mjs} +10 -5
  26. package/.output/server/{_tanstack-start-manifest_v-xQ1BRoZw.mjs → _tanstack-start-manifest_v-BvJ2LKGG.mjs} +1 -1
  27. package/.output/server/index.mjs +66 -66
  28. package/README.md +30 -8
  29. package/package.json +1 -1
  30. package/src/cli/doctor.ts +1 -1
  31. package/src/cli/onboard.ts +15 -9
  32. package/src/cli.ts +87 -33
  33. package/src/components/ProxyViewer.tsx +30 -25
  34. package/src/components/providers/SettingsDialog.tsx +2 -2
  35. package/src/components/ui/icon-trigger.ts +1 -1
  36. package/src/lib/serverPort.ts +9 -3
  37. package/src/proxy/socketTracker.ts +1 -1
  38. package/.output/public/assets/index-B26q0-ch.js +0 -1
  39. package/.output/public/assets/index-CxszCIFm.css +0 -1
@@ -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-06T23:30:24.816Z",
41
+ "mtime": "2026-07-07T00:31:07.940Z",
42
42
  "size": 5915,
43
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
44
44
  },
45
- "/assets/index-B26q0-ch.js": {
45
+ "/assets/CompareDrawer-ZL1yvIH6.js": {
46
46
  "type": "text/javascript; charset=utf-8",
47
- "etag": '"74-AZvnGEhntbiyIDS+wwwbTZjCuCw"',
48
- "mtime": "2026-07-06T23:30:24.817Z",
49
- "size": 116,
50
- "path": "../public/assets/index-B26q0-ch.js"
47
+ "etag": '"4bbf-CIi9MFvNx5XBmXT0nU0DPL42gd8"',
48
+ "mtime": "2026-07-07T00:31:07.942Z",
49
+ "size": 19391,
50
+ "path": "../public/assets/CompareDrawer-ZL1yvIH6.js"
51
51
  },
52
- "/assets/json-viewer-DERQNZRV.js": {
52
+ "/assets/json-viewer-B9gYSlz7.js": {
53
53
  "type": "text/javascript; charset=utf-8",
54
- "etag": '"1ae6-A6B2jiKFX+jryATLfM15t7QIsvM"',
55
- "mtime": "2026-07-06T23:30:24.817Z",
54
+ "etag": '"1ae6-eUFnKJytY27s8aDs8Lo5QbvfXRw"',
55
+ "mtime": "2026-07-07T00:31:07.942Z",
56
56
  "size": 6886,
57
- "path": "../public/assets/json-viewer-DERQNZRV.js"
57
+ "path": "../public/assets/json-viewer-B9gYSlz7.js"
58
58
  },
59
59
  "/assets/minimax-BPMzvuL-.jpeg": {
60
60
  "type": "image/jpeg",
61
61
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
62
- "mtime": "2026-07-06T23:30:24.816Z",
62
+ "mtime": "2026-07-07T00:31:07.942Z",
63
63
  "size": 6918,
64
64
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
65
65
  },
66
- "/assets/index-CxszCIFm.css": {
67
- "type": "text/css; charset=utf-8",
68
- "etag": '"219d3-hGkO4OXmpghyDnxd7KIL9unRxwQ"',
69
- "mtime": "2026-07-06T23:30:24.817Z",
70
- "size": 137683,
71
- "path": "../public/assets/index-CxszCIFm.css"
72
- },
73
- "/assets/CompareDrawer-Cvgl_Jmi.js": {
74
- "type": "text/javascript; charset=utf-8",
75
- "etag": '"4bbf-qdrjZBBOyzn/JHMYJ2UAiNDDbFQ"',
76
- "mtime": "2026-07-06T23:30:24.817Z",
77
- "size": 19391,
78
- "path": "../public/assets/CompareDrawer-Cvgl_Jmi.js"
79
- },
80
- "/assets/index-BZxLBVYd.js": {
66
+ "/assets/index-_inxJ5Yi.js": {
81
67
  "type": "text/javascript; charset=utf-8",
82
- "etag": '"1cd2c-eSvMM8zbdBG02FS4JJNg0vJ028w"',
83
- "mtime": "2026-07-06T23:30:24.817Z",
68
+ "etag": '"1cd2c-oLlmpQRDfuZo5GBb+xP4a/4UY4g"',
69
+ "mtime": "2026-07-07T00:31:07.942Z",
84
70
  "size": 118060,
85
- "path": "../public/assets/index-BZxLBVYd.js"
71
+ "path": "../public/assets/index-_inxJ5Yi.js"
86
72
  },
87
- "/assets/RequestAnatomy-CrLSqdiA.js": {
73
+ "/assets/index-BJvPLWvO.js": {
88
74
  "type": "text/javascript; charset=utf-8",
89
- "etag": '"43f2-YwOCt5e63SibXMhWqzHRxd1nNC8"',
90
- "mtime": "2026-07-06T23:30:24.817Z",
91
- "size": 17394,
92
- "path": "../public/assets/RequestAnatomy-CrLSqdiA.js"
75
+ "etag": '"74-BHSPo95dMXATS9vdlnudttsOua0"',
76
+ "mtime": "2026-07-07T00:31:07.942Z",
77
+ "size": 116,
78
+ "path": "../public/assets/index-BJvPLWvO.js"
93
79
  },
94
- "/assets/ReplayDialog-DeEELx0X.js": {
95
- "type": "text/javascript; charset=utf-8",
96
- "etag": '"31d6-hWOAjkfta2prr+9EmQOXzNOAzTU"',
97
- "mtime": "2026-07-06T23:30:24.817Z",
98
- "size": 12758,
99
- "path": "../public/assets/ReplayDialog-DeEELx0X.js"
80
+ "/assets/index-Tq5s9NV0.css": {
81
+ "type": "text/css; charset=utf-8",
82
+ "etag": '"22408-MQKT02eqQudVEj/DozyiEJoTl6E"',
83
+ "mtime": "2026-07-07T00:31:07.942Z",
84
+ "size": 140296,
85
+ "path": "../public/assets/index-Tq5s9NV0.css"
100
86
  },
101
- "/assets/ResponseView-CFIqDL5E.js": {
87
+ "/assets/RequestAnatomy-CVt2vHih.js": {
102
88
  "type": "text/javascript; charset=utf-8",
103
- "etag": '"47fa-+VN13C6cvB2BYNKPjLEy9ibIswM"',
104
- "mtime": "2026-07-06T23:30:24.817Z",
105
- "size": 18426,
106
- "path": "../public/assets/ResponseView-CFIqDL5E.js"
89
+ "etag": '"43f2-Pb1rRv8VdlgdFtX52V4rCBrFcCo"',
90
+ "mtime": "2026-07-07T00:31:07.942Z",
91
+ "size": 17394,
92
+ "path": "../public/assets/RequestAnatomy-CVt2vHih.js"
107
93
  },
108
- "/assets/main-BoshTI0W.js": {
94
+ "/assets/StreamingChunkSequence-DQFhpV_4.js": {
109
95
  "type": "text/javascript; charset=utf-8",
110
- "etag": '"512fd-NlLbmALn+PuYHWA4Dj6BVyzFIuM"',
111
- "mtime": "2026-07-06T23:30:24.817Z",
112
- "size": 332541,
113
- "path": "../public/assets/main-BoshTI0W.js"
96
+ "etag": '"dd6-SMIn60D5iwf77dJ0W8fWzwFQ+y4"',
97
+ "mtime": "2026-07-07T00:31:07.942Z",
98
+ "size": 3542,
99
+ "path": "../public/assets/StreamingChunkSequence-DQFhpV_4.js"
114
100
  },
115
101
  "/assets/zhipuai-BPNAnxo-.svg": {
116
102
  "type": "image/svg+xml",
117
103
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
118
- "mtime": "2026-07-06T23:30:24.816Z",
104
+ "mtime": "2026-07-07T00:31:07.942Z",
119
105
  "size": 11256,
120
106
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
121
107
  },
122
- "/assets/_sessionId-ZuH6-ZX5.js": {
108
+ "/assets/_sessionId-DeeeQcS9.js": {
123
109
  "type": "text/javascript; charset=utf-8",
124
- "etag": '"36c-yfRDDJm0mM1r+nbDh5oXBDpciWQ"',
125
- "mtime": "2026-07-06T23:30:24.817Z",
110
+ "etag": '"36c-9kxd4A0O2DRX90CFKTSW0gvJg7A"',
111
+ "mtime": "2026-07-07T00:31:07.942Z",
126
112
  "size": 876,
127
- "path": "../public/assets/_sessionId-ZuH6-ZX5.js"
113
+ "path": "../public/assets/_sessionId-DeeeQcS9.js"
128
114
  },
129
- "/assets/StreamingChunkSequence-DSRjbgqb.js": {
115
+ "/assets/ReplayDialog-D-gDSuhe.js": {
130
116
  "type": "text/javascript; charset=utf-8",
131
- "etag": '"dd6-phWzlhQq/JJk54G5Z2rU0kzp2as"',
132
- "mtime": "2026-07-06T23:30:24.817Z",
133
- "size": 3542,
134
- "path": "../public/assets/StreamingChunkSequence-DSRjbgqb.js"
117
+ "etag": '"31d6-7nPX+7CzElY2l3LTEI8tdhGnb9g"',
118
+ "mtime": "2026-07-07T00:31:07.942Z",
119
+ "size": 12758,
120
+ "path": "../public/assets/ReplayDialog-D-gDSuhe.js"
121
+ },
122
+ "/assets/ResponseView-zVdHc0mv.js": {
123
+ "type": "text/javascript; charset=utf-8",
124
+ "etag": '"47fa-My/gIfJNAY80sXwdo3igU0H0hlA"',
125
+ "mtime": "2026-07-07T00:31:07.942Z",
126
+ "size": 18426,
127
+ "path": "../public/assets/ResponseView-zVdHc0mv.js"
128
+ },
129
+ "/assets/main-Do_fjInc.js": {
130
+ "type": "text/javascript; charset=utf-8",
131
+ "etag": '"512fd-fApJrxOu5dijJDTxHvG75pv2C6s"',
132
+ "mtime": "2026-07-07T00:31:07.942Z",
133
+ "size": 332541,
134
+ "path": "../public/assets/main-Do_fjInc.js"
135
135
  },
136
136
  "/assets/qwen-CONDcHqt.png": {
137
137
  "type": "image/png",
138
138
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
139
- "mtime": "2026-07-06T23:30:24.816Z",
139
+ "mtime": "2026-07-07T00:31:07.942Z",
140
140
  "size": 357059,
141
141
  "path": "../public/assets/qwen-CONDcHqt.png"
142
142
  },
143
- "/assets/ProxyViewerContainer-CNLLZq37.js": {
143
+ "/assets/ProxyViewerContainer-vhfV449d.js": {
144
144
  "type": "text/javascript; charset=utf-8",
145
- "etag": '"aece0-rsojOMYS6lexxfh1G0dXZ/InUpE"',
146
- "mtime": "2026-07-06T23:30:24.817Z",
147
- "size": 716e3,
148
- "path": "../public/assets/ProxyViewerContainer-CNLLZq37.js"
145
+ "etag": '"aef11-EMJh1fZUCmNDbpYKv5051UbD1KI"',
146
+ "mtime": "2026-07-07T00:31:07.942Z",
147
+ "size": 716561,
148
+ "path": "../public/assets/ProxyViewerContainer-vhfV449d.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:25947/api/mcp` through Codex `mcp_servers.agent-inspector`.
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:25947/proxy`.
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:25947/proxy <tool>
126
+ ANTHROPIC_BASE_URL=http://localhost:9527/proxy <tool>
127
127
  ```
128
128
 
129
- The web UI runs at http://localhost:25947. The public proxy endpoint is also
130
- `http://localhost:25947/proxy`; internally Agent Inspector may run the app on a private helper port,
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:25947/proxy/v1"
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:25947/api/mcp
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:25947/api/mcp` directly. If it only supports stdio, configure
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/agent-inspector",
3
- "version": "2.1.23",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "description": "Agent observability and knowledge capture layer for AI coding tools.",
6
6
  "license": "MIT",
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 = 25947;
6
+ const DEFAULT_PORT = 9527;
7
7
  const PROBE_TIMEOUT_MS = 2000;
8
8
  const EXTENSION_REQUIRED_FILES = [
9
9
  "manifest.json",
@@ -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 = 25947;
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 usesUrlArg = stringArrayEquals(value["command"], [
645
- "agent-inspector-mcp",
646
- "stdio",
647
- "--url",
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"] === endpoint;
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 value["type"] === "remote" && value["url"] === endpoint;
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
- // External-facing port stays at 25947 so existing tooling / AI clients
27
- // (Claude Code, OpenCode, MiMo Code, etc.) keep working with the
28
- // unchanged `ANTHROPIC_BASE_URL=http://localhost:25947/proxy`. The
29
- // identity-injecting proxy listens on that port; the TanStack Start
30
- // upstream is moved to a private port (25949 by default) and reverse-
31
- // proxied through.
32
- const DEFAULT_PORT = 25947;
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";
@@ -244,6 +243,26 @@ function printAccessHints(port: number, host?: string): void {
244
243
  }
245
244
  }
246
245
 
246
+ function pickUpstreamPort(publicPort: number, legacyAliasPort: number | null): number {
247
+ const candidates = [
248
+ DEFAULT_UPSTREAM_PORT,
249
+ publicPort + 2 <= 65535 ? publicPort + 2 : publicPort - 2,
250
+ LEGACY_ALIAS_PORT + 2,
251
+ ];
252
+ for (const candidate of candidates) {
253
+ if (
254
+ Number.isInteger(candidate) &&
255
+ candidate > 0 &&
256
+ candidate <= 65535 &&
257
+ candidate !== publicPort &&
258
+ candidate !== legacyAliasPort
259
+ ) {
260
+ return candidate;
261
+ }
262
+ }
263
+ return DEFAULT_UPSTREAM_PORT;
264
+ }
265
+
247
266
  /** Try to start the identity proxy. Returns `null` (and prints a warning)
248
267
  * if the listen port is already in use by another process — e.g. when
249
268
  * restarting a previous instance that didn't shut down cleanly. The
@@ -273,7 +292,7 @@ async function tryStartIdentityProxy(
273
292
  }
274
293
 
275
294
  async function runStart(args: string[]): Promise<void> {
276
- const envPort = process.env["PORT"];
295
+ const envPort = process.env["AGENT_INSPECTOR_PORT"] ?? process.env["PORT"];
277
296
  const portDefault = envPort !== undefined ? Number(envPort) : DEFAULT_PORT;
278
297
  const envHost = process.env["NITRO_HOST"] ?? process.env["HOST"];
279
298
  const envMode =
@@ -290,10 +309,7 @@ async function runStart(args: string[]): Promise<void> {
290
309
  let captureMode = DEFAULT_CAPTURE_MODE;
291
310
  let captureModeWasSpecified = false;
292
311
  let enableIdentityProxy = true;
293
- let identityProxyPort =
294
- process.env["AGENT_INSPECTOR_PORT"] !== undefined
295
- ? Number(process.env["AGENT_INSPECTOR_PORT"])
296
- : DEFAULT_PORT;
312
+ let legacyAliasEnabled = true;
297
313
 
298
314
  if (envMode !== undefined && envMode !== "") {
299
315
  const parsedMode = parseCaptureMode(envMode);
@@ -402,10 +418,13 @@ async function runStart(args: string[]): Promise<void> {
402
418
  process.exitCode = 1;
403
419
  return;
404
420
  }
405
- identityProxyPort = parsed;
421
+ port = parsed;
406
422
  i++;
407
423
  break;
408
424
  }
425
+ case "--no-legacy-port":
426
+ legacyAliasEnabled = false;
427
+ break;
409
428
  default:
410
429
  break;
411
430
  }
@@ -489,11 +508,13 @@ async function runStart(args: string[]): Promise<void> {
489
508
  }
490
509
  }
491
510
 
492
- // TanStack Start listens on the private upstream port; the identity
493
- // proxy owns the public-facing `port`. When the identity proxy is
494
- // disabled (or not yet running) we fall back to TanStack listening on
495
- // the public port directly.
496
- const upstreamPort = enableIdentityProxy ? DEFAULT_UPSTREAM_PORT : port;
511
+ const legacyAliasPort =
512
+ enableIdentityProxy && legacyAliasEnabled && port === DEFAULT_PORT ? LEGACY_ALIAS_PORT : null;
513
+
514
+ // TanStack Start listens on the private upstream port; identity proxies own
515
+ // the public-facing port(s). When the identity proxy is disabled we fall
516
+ // back to TanStack listening on the public port directly.
517
+ const upstreamPort = enableIdentityProxy ? pickUpstreamPort(port, legacyAliasPort) : port;
497
518
  process.env["PORT"] = String(upstreamPort);
498
519
 
499
520
  const url = urlForHost(port, host);
@@ -526,8 +547,8 @@ async function runStart(args: string[]): Promise<void> {
526
547
  const restartPorts = new Set<number>();
527
548
  restartPorts.add(port);
528
549
  if (enableIdentityProxy) {
529
- restartPorts.add(identityProxyPort);
530
550
  restartPorts.add(upstreamPort);
551
+ if (legacyAliasPort !== null) restartPorts.add(legacyAliasPort);
531
552
  }
532
553
  for (const targetPort of restartPorts) {
533
554
  killProcessOnPort(targetPort);
@@ -538,6 +559,11 @@ async function runStart(args: string[]): Promise<void> {
538
559
  console.log(` Capture mode: ${captureMode}`);
539
560
  console.log(` Proxy: ${url}/proxy`);
540
561
  printAccessHints(port, host);
562
+ if (legacyAliasPort !== null) {
563
+ console.log(` Legacy UI: http://localhost:${legacyAliasPort}`);
564
+ console.log(` Legacy proxy: http://localhost:${legacyAliasPort}/proxy`);
565
+ console.log(` Legacy MCP: http://localhost:${legacyAliasPort}/api/mcp`);
566
+ }
541
567
  console.log(``);
542
568
  console.log(`Route AI coding tools through the proxy:`);
543
569
  console.log(` Claude Code: ANTHROPIC_BASE_URL=${url}/proxy claude`);
@@ -594,6 +620,8 @@ async function runStart(args: string[]): Promise<void> {
594
620
  serverEnv["HOST"] = host;
595
621
  serverEnv["NITRO_HOST"] = host;
596
622
  }
623
+ serverEnv["AGENT_INSPECTOR_PUBLIC_PORT"] = String(port);
624
+ serverEnv["PROXY_PORT"] = String(port);
597
625
  serverEnv["AGENT_INSPECTOR_CAPTURE_MODE"] = captureMode;
598
626
  const serverProcess = spawn(serverCommand.command, serverCommand.args, {
599
627
  stdio: background ? ["ignore", "ignore", "ignore"] : ["ignore", "pipe", "pipe"],
@@ -615,9 +643,23 @@ async function runStart(args: string[]): Promise<void> {
615
643
  // This lets AI tools (which can't easily set those headers themselves)
616
644
  // still get accurate session attribution. Started only after TanStack
617
645
  // Start is healthy, so the upstream is ready by the time clients connect.
618
- const identityProxy = enableIdentityProxy
619
- ? await tryStartIdentityProxy(identityProxyPort, upstreamPort, host)
620
- : null;
646
+ const identityProxies: Array<{
647
+ label: "primary" | "legacy";
648
+ port: number;
649
+ server: import("node:http").Server;
650
+ }> = [];
651
+ if (enableIdentityProxy) {
652
+ const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host);
653
+ if (primaryProxy !== null) {
654
+ identityProxies.push({ label: "primary", port, server: primaryProxy });
655
+ }
656
+ if (legacyAliasPort !== null) {
657
+ const legacyProxy = await tryStartIdentityProxy(legacyAliasPort, upstreamPort, host);
658
+ if (legacyProxy !== null) {
659
+ identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
660
+ }
661
+ }
662
+ }
621
663
 
622
664
  if (background) {
623
665
  serverProcess.unref();
@@ -625,18 +667,24 @@ async function runStart(args: string[]): Promise<void> {
625
667
  // not started yet so the public port is not yet accepting traffic.
626
668
  if (await waitForInspectorHealthy(upstreamPort, 5000, host)) {
627
669
  console.log(`agent-inspector background server is ready at ${url}`);
628
- if (identityProxy !== null) {
629
- console.log(`Identity proxy ready on port ${identityProxyPort} (PID-attributing proxy).`);
670
+ if (identityProxies.length > 0) {
671
+ console.log(`Identity proxy ready on port ${port} (PID-attributing proxy).`);
630
672
  }
631
673
  printAccessHints(port, host);
632
- if (identityProxy !== null) {
674
+ if (legacyAliasPort !== null) {
675
+ console.log(` Legacy proxy: http://localhost:${legacyAliasPort}/proxy`);
676
+ console.log(` Legacy MCP: http://localhost:${legacyAliasPort}/api/mcp`);
677
+ }
678
+ if (identityProxies.length > 0) {
633
679
  console.log(
634
680
  ``,
635
681
  `Route AI coding tools through the identity proxy for accurate PID attribution:`,
636
- ` Claude Code: ANTHROPIC_BASE_URL=http://localhost:${identityProxyPort}/proxy claude`,
637
- ` OpenCode: LLM_BASE_URL=http://localhost:${identityProxyPort}/proxy opencode`,
638
- ` MiMo Code: OPENAI_BASE_URL=http://localhost:${identityProxyPort}/proxy mimo`,
639
- ` (Direct ${port} still works; it falls back to OS-scan heuristic.)`,
682
+ ` Claude Code: ANTHROPIC_BASE_URL=http://localhost:${port}/proxy claude`,
683
+ ` OpenCode: LLM_BASE_URL=http://localhost:${port}/proxy opencode`,
684
+ ` MiMo Code: OPENAI_BASE_URL=http://localhost:${port}/proxy mimo`,
685
+ legacyAliasPort === null
686
+ ? ` Override the port with --port <n> when needed.`
687
+ : ` Legacy configs using http://localhost:${legacyAliasPort}/proxy still work.`,
640
688
  );
641
689
  }
642
690
  return;
@@ -646,9 +694,15 @@ async function runStart(args: string[]): Promise<void> {
646
694
  return;
647
695
  }
648
696
 
649
- if (identityProxy !== null) {
697
+ if (identityProxies.length > 0) {
650
698
  console.log(``);
651
699
  console.log(`Identity proxy ready at ${url} (PID-attributing public entrypoint).`);
700
+ if (legacyAliasPort !== null) {
701
+ const legacyReady = identityProxies.some((proxy) => proxy.label === "legacy");
702
+ if (legacyReady) {
703
+ console.log(` Legacy alias ready at http://localhost:${legacyAliasPort}.`);
704
+ }
705
+ }
652
706
  if (upstreamPort !== port) {
653
707
  console.log(` Internal runtime port ${upstreamPort} is hidden behind the public proxy.`);
654
708
  }
@@ -656,7 +710,7 @@ async function runStart(args: string[]): Promise<void> {
656
710
 
657
711
  process.exitCode = await waitForProcessExit(serverProcess);
658
712
 
659
- if (identityProxy !== null) {
660
- await new Promise<void>((resolve) => identityProxy.close(() => resolve()));
713
+ for (const proxy of identityProxies) {
714
+ await new Promise<void>((resolve) => proxy.server.close(() => resolve()));
661
715
  }
662
716
  }