@tonyclaw/llm-inspector 1.6.1 → 1.6.2

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 ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { spawn } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+ import { dirname, join } from "node:path";
7
+ import { existsSync } from "node:fs";
8
+ var __filename = fileURLToPath(import.meta.url);
9
+ var __dirname = dirname(__filename);
10
+ var DEFAULT_PORT = 25947;
11
+ var findBun = () => {
12
+ const pathEnv = process.env.PATH ?? "";
13
+ const pathDirs = pathEnv.split(process.platform === "win32" ? ";" : ":");
14
+ for (const dir of pathDirs) {
15
+ const bunPath2 = join(dir, process.platform === "win32" ? "bun.exe" : "bun");
16
+ if (existsSync(bunPath2)) {
17
+ if (process.platform === "win32" && !bunPath2.endsWith(".exe")) {
18
+ const actualPath = join(dir, "node_modules", "bun", "bin", "bun.exe");
19
+ if (existsSync(actualPath)) {
20
+ return actualPath;
21
+ }
22
+ }
23
+ return bunPath2;
24
+ }
25
+ }
26
+ if (process.platform === "win32") {
27
+ const localAppData = process.env.LOCALAPPDATA ?? "";
28
+ const appData = process.env.APPDATA ?? "";
29
+ const userProfile = process.env.USERPROFILE ?? "";
30
+ const commonPaths = [
31
+ join(localAppData, "bun", "bin", "bun.exe"),
32
+ join(appData, "bun", "bin", "bun.exe"),
33
+ join(userProfile, "AppData", "Local", "bun", "bin", "bun.exe"),
34
+ join(userProfile, "AppData", "Roaming", "npm", "node_modules", "bun", "bin", "bun.exe"),
35
+ join(userProfile, "AppData", "Roaming", "npm", "bun")
36
+ ];
37
+ for (const bunPath2 of commonPaths) {
38
+ if (existsSync(bunPath2)) {
39
+ return bunPath2;
40
+ }
41
+ }
42
+ }
43
+ return null;
44
+ };
45
+ var envPort = process.env["PORT"];
46
+ var portDefault = envPort !== void 0 ? Number(envPort) : DEFAULT_PORT;
47
+ var args = process.argv.slice(2);
48
+ var port = portDefault;
49
+ var open = true;
50
+ for (let i = 0; i < args.length; i++) {
51
+ const arg = args[i] ?? "";
52
+ switch (arg) {
53
+ case "--port":
54
+ case "-p":
55
+ port = Number(args[i + 1]);
56
+ i++;
57
+ break;
58
+ case "--no-open":
59
+ open = false;
60
+ break;
61
+ case "--open":
62
+ open = true;
63
+ break;
64
+ default:
65
+ break;
66
+ }
67
+ }
68
+ process.env["PORT"] = String(port);
69
+ var url = `http://localhost:${port}`;
70
+ console.log(`Server running at ${url}`);
71
+ console.log(` Proxy: ${url}/proxy`);
72
+ console.log(``);
73
+ console.log(`Route AI coding tools through the proxy:`);
74
+ console.log(` Claude Code: ANTHROPIC_BASE_URL=${url}/proxy claude`);
75
+ console.log(` OpenCode: LLM_BASE_URL=${url}/proxy opencode`);
76
+ console.log(` Direct HTTP: curl ${url}/proxy/v1/messages -d '{"model":"...","messages":[...]}'`);
77
+ console.log(``);
78
+ console.log(`Routing environment variables:`);
79
+ console.log(` ROUTES JSON map of model prefix -> upstream URL`);
80
+ console.log(` DEFAULT_UPSTREAM Fallback upstream for unmatched models`);
81
+ console.log(
82
+ ` Example: ROUTES='{"claude-":"https://api.anthropic.com","MiniMax":"https://api.minimaxi.com/anthropic"}'`
83
+ );
84
+ var openBrowser = (targetUrl) => {
85
+ let command;
86
+ switch (process.platform) {
87
+ case "darwin":
88
+ command = ["open", targetUrl];
89
+ break;
90
+ case "linux":
91
+ command = ["xdg-open", targetUrl];
92
+ break;
93
+ case "win32":
94
+ command = ["cmd", "/c", "start", targetUrl];
95
+ break;
96
+ default:
97
+ break;
98
+ }
99
+ if (command === void 0) return;
100
+ const [bin, ...cmdArgs] = command;
101
+ if (bin === void 0) return;
102
+ spawn(bin, cmdArgs, { stdio: "ignore", detached: true });
103
+ };
104
+ if (open) {
105
+ openBrowser(url);
106
+ }
107
+ var bunPath = findBun();
108
+ if (bunPath === null) {
109
+ console.error("\nError: bun is not installed or not in PATH.");
110
+ console.error("Please install bun from https://bun.sh");
111
+ process.exit(1);
112
+ }
113
+ var outputDir = __dirname;
114
+ var serverPath = join(outputDir, "../.output/server/index.mjs");
115
+ var serverProcess = spawn(bunPath, [serverPath], {
116
+ stdio: ["ignore", "inherit", "inherit"],
117
+ detached: true
118
+ });
119
+ serverProcess.unref();
@@ -1,5 +1,5 @@
1
1
  {
2
- "date": "2026-06-03T06:16:03.122Z",
2
+ "date": "2026-06-03T07:56:05.905Z",
3
3
  "preset": "bun",
4
4
  "framework": {
5
5
  "name": "nitro",
@@ -93,52 +93,52 @@ const headers = ((m) => function headersRouteRule(event) {
93
93
  }
94
94
  });
95
95
  const assets = {
96
- "/assets/minimax-BPMzvuL-.jpeg": {
97
- "type": "image/jpeg",
98
- "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
99
- "mtime": "2026-06-03T06:15:56.954Z",
100
- "size": 6918,
101
- "path": "../public/assets/minimax-BPMzvuL-.jpeg"
102
- },
103
- "/assets/zhipuai-BPNAnxo-.svg": {
104
- "type": "image/svg+xml",
105
- "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
106
- "mtime": "2026-06-03T06:15:56.954Z",
107
- "size": 11256,
108
- "path": "../public/assets/zhipuai-BPNAnxo-.svg"
109
- },
110
96
  "/assets/alibaba-TTwafVwX.svg": {
111
97
  "type": "image/svg+xml",
112
98
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
113
- "mtime": "2026-06-03T06:15:56.951Z",
99
+ "mtime": "2026-06-03T07:55:59.581Z",
114
100
  "size": 5915,
115
101
  "path": "../public/assets/alibaba-TTwafVwX.svg"
116
102
  },
117
103
  "/assets/index-B3RwBPLW.css": {
118
104
  "type": "text/css; charset=utf-8",
119
105
  "etag": '"10c74-aXacU4DRFVsUwcC5jHnjoPRSlTA"',
120
- "mtime": "2026-06-03T06:15:56.954Z",
106
+ "mtime": "2026-06-03T07:55:59.583Z",
121
107
  "size": 68724,
122
108
  "path": "../public/assets/index-B3RwBPLW.css"
123
109
  },
124
110
  "/assets/main-Cp8AM0Pa.js": {
125
111
  "type": "text/javascript; charset=utf-8",
126
112
  "etag": '"4db57-FpqlPRLq9OHoaAFCL2NIXtZbW5c"',
127
- "mtime": "2026-06-03T06:15:56.954Z",
113
+ "mtime": "2026-06-03T07:55:59.583Z",
128
114
  "size": 318295,
129
115
  "path": "../public/assets/main-Cp8AM0Pa.js"
130
116
  },
131
117
  "/assets/qwen-CONDcHqt.png": {
132
118
  "type": "image/png",
133
119
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
134
- "mtime": "2026-06-03T06:15:56.954Z",
120
+ "mtime": "2026-06-03T07:55:59.581Z",
135
121
  "size": 357059,
136
122
  "path": "../public/assets/qwen-CONDcHqt.png"
137
123
  },
124
+ "/assets/minimax-BPMzvuL-.jpeg": {
125
+ "type": "image/jpeg",
126
+ "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
127
+ "mtime": "2026-06-03T07:55:59.580Z",
128
+ "size": 6918,
129
+ "path": "../public/assets/minimax-BPMzvuL-.jpeg"
130
+ },
131
+ "/assets/zhipuai-BPNAnxo-.svg": {
132
+ "type": "image/svg+xml",
133
+ "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
134
+ "mtime": "2026-06-03T07:55:59.581Z",
135
+ "size": 11256,
136
+ "path": "../public/assets/zhipuai-BPNAnxo-.svg"
137
+ },
138
138
  "/assets/index-s4lwsWvq.js": {
139
139
  "type": "text/javascript; charset=utf-8",
140
140
  "etag": '"828c8-LEW/XL92J2/5lU4VKALlH7aVpaA"',
141
- "mtime": "2026-06-03T06:15:56.954Z",
141
+ "mtime": "2026-06-03T07:55:59.583Z",
142
142
  "size": 534728,
143
143
  "path": "../public/assets/index-s4lwsWvq.js"
144
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/llm-inspector",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "type": "module",
5
5
  "description": "LLM API proxy inspector — captures and displays requests/responses from AI coding tools in a web UI",
6
6
  "license": "MIT",
@@ -18,7 +18,7 @@
18
18
  "ai-coding-tools"
19
19
  ],
20
20
  "bin": {
21
- "llm-inspector": "src/cli.ts"
21
+ "llm-inspector": ".output/cli.js"
22
22
  },
23
23
  "files": [
24
24
  "src",
@@ -31,9 +31,10 @@
31
31
  ],
32
32
  "scripts": {
33
33
  "dev": "vite dev",
34
- "start": "bun src/cli.ts",
35
- "build": "vite build",
36
- "prepublishOnly": "bun run build",
34
+ "start": "node .output/cli.js",
35
+ "build": "vite build && bun build:cli",
36
+ "build:cli": "npx esbuild src/cli.ts --bundle --platform=node --target=node18 --format=esm --outfile=.output/cli.js",
37
+ "prepublishOnly": "npm run build",
37
38
  "typecheck": "tsc --noEmit",
38
39
  "lint": "eslint .",
39
40
  "format": "biome format --write .",
@@ -52,7 +53,6 @@
52
53
  "@tanstack/react-start": "^1.161.0",
53
54
  "@tanstack/react-virtual": "^3.13.26",
54
55
  "class-variance-authority": "^0.7.1",
55
- "cleye": "^2.2.1",
56
56
  "clsx": "^2.1.1",
57
57
  "conf": "^15.1.0",
58
58
  "jszip": "^3.10.1",
@@ -76,6 +76,7 @@
76
76
  "@typescript-eslint/eslint-plugin": "^8.55.0",
77
77
  "@typescript-eslint/parser": "^8.55.0",
78
78
  "@vitejs/plugin-react": "^5.1.4",
79
+ "esbuild": "^0.25.0",
79
80
  "eslint": "^9.32.0",
80
81
  "eslint-plugin-eslint-comments": "^3.2.0",
81
82
  "eslint-plugin-functional": "^9.0.2",
package/src/cli.ts CHANGED
@@ -1,31 +1,88 @@
1
- #!/usr/bin/env bun
2
- import { cli } from "cleye";
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ import { existsSync } from "node:fs";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
3
9
 
4
10
  const DEFAULT_PORT = 25947;
5
11
 
12
+ // Find bun executable
13
+ const findBun = (): string | null => {
14
+ // Check if bun is in PATH
15
+ const pathEnv = process.env.PATH ?? "";
16
+ const pathDirs = pathEnv.split(process.platform === "win32" ? ";" : ":");
17
+
18
+ for (const dir of pathDirs) {
19
+ const bunPath = join(dir, process.platform === "win32" ? "bun.exe" : "bun");
20
+ if (existsSync(bunPath)) {
21
+ // On Windows, npm shim is a script, not the actual exe
22
+ if (process.platform === "win32" && !bunPath.endsWith(".exe")) {
23
+ // Check if it's the npm shim and find the actual exe
24
+ const actualPath = join(dir, "node_modules", "bun", "bin", "bun.exe");
25
+ if (existsSync(actualPath)) {
26
+ return actualPath;
27
+ }
28
+ }
29
+ return bunPath;
30
+ }
31
+ }
32
+
33
+ // Common Windows paths
34
+ if (process.platform === "win32") {
35
+ const localAppData = process.env.LOCALAPPDATA ?? "";
36
+ const appData = process.env.APPDATA ?? "";
37
+ const userProfile = process.env.USERPROFILE ?? "";
38
+
39
+ const commonPaths = [
40
+ join(localAppData, "bun", "bin", "bun.exe"),
41
+ join(appData, "bun", "bin", "bun.exe"),
42
+ join(userProfile, "AppData", "Local", "bun", "bin", "bun.exe"),
43
+ join(userProfile, "AppData", "Roaming", "npm", "node_modules", "bun", "bin", "bun.exe"),
44
+ join(userProfile, "AppData", "Roaming", "npm", "bun"),
45
+ ];
46
+ for (const bunPath of commonPaths) {
47
+ if (existsSync(bunPath)) {
48
+ return bunPath;
49
+ }
50
+ }
51
+ }
52
+
53
+ return null;
54
+ };
55
+
6
56
  const envPort = process.env["PORT"];
7
57
  const portDefault = envPort !== undefined ? Number(envPort) : DEFAULT_PORT;
8
58
 
9
- const argv = cli({
10
- name: "llm-inspector",
11
- flags: {
12
- port: {
13
- type: Number,
14
- alias: "p",
15
- default: portDefault,
16
- description: "Port to listen on (env: PORT)",
17
- },
18
- open: {
19
- type: Boolean,
20
- default: true,
21
- description: "Open the browser on start (use --no-open to disable)",
22
- },
23
- },
24
- });
59
+ // Simple argument parsing
60
+ const args = process.argv.slice(2);
61
+ let port = portDefault;
62
+ let open = true;
25
63
 
26
- process.env["PORT"] = String(argv.flags.port);
64
+ for (let i = 0; i < args.length; i++) {
65
+ const arg = args[i] ?? "";
66
+ switch (arg) {
67
+ case "--port":
68
+ case "-p":
69
+ port = Number(args[i + 1]);
70
+ i++;
71
+ break;
72
+ case "--no-open":
73
+ open = false;
74
+ break;
75
+ case "--open":
76
+ open = true;
77
+ break;
78
+ default:
79
+ break;
80
+ }
81
+ }
82
+
83
+ process.env["PORT"] = String(port);
27
84
 
28
- const url = `http://localhost:${argv.flags.port}`;
85
+ const url = `http://localhost:${port}`;
29
86
 
30
87
  console.log(`Server running at ${url}`);
31
88
  console.log(` Proxy: ${url}/proxy`);
@@ -43,26 +100,48 @@ console.log(
43
100
  );
44
101
 
45
102
  const openBrowser = (targetUrl: string): void => {
46
- const commandByPlatform: Record<string, string[]> = {
47
- darwin: ["open", targetUrl],
48
- linux: ["xdg-open", targetUrl],
49
- win32: ["cmd", "/c", "start", targetUrl],
50
- };
51
- const command = commandByPlatform[process.platform];
103
+ let command: string[] | undefined;
104
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
105
+ switch (process.platform) {
106
+ case "darwin":
107
+ command = ["open", targetUrl];
108
+ break;
109
+ case "linux":
110
+ command = ["xdg-open", targetUrl];
111
+ break;
112
+ case "win32":
113
+ command = ["cmd", "/c", "start", targetUrl];
114
+ break;
115
+ default:
116
+ // Unsupported platform - do nothing
117
+ break;
118
+ }
52
119
  if (command === undefined) return;
53
- const [bin, ...args] = command;
120
+ const [bin, ...cmdArgs] = command;
54
121
  if (bin === undefined) return;
55
- Bun.spawn([bin, ...args], { stdio: ["ignore", "ignore", "ignore"] });
122
+ spawn(bin, cmdArgs, { stdio: "ignore", detached: true });
56
123
  };
57
124
 
58
- if (argv.flags.open) {
125
+ if (open) {
59
126
  openBrowser(url);
60
127
  }
61
128
 
62
- const { initLogger } = await import("./proxy/logger.js");
63
- await initLogger();
64
- const { rebuildIndex } = await import("./proxy/logIndex.js");
65
- await rebuildIndex();
66
- const { loadLogsIntoMemory } = await import("./proxy/store.js");
67
- await loadLogsIntoMemory();
68
- await import("../.output/server/index.mjs");
129
+ // Find bun and start server
130
+ const bunPath = findBun();
131
+ if (bunPath === null) {
132
+ console.error("\nError: bun is not installed or not in PATH.");
133
+ console.error("Please install bun from https://bun.sh");
134
+ process.exit(1);
135
+ }
136
+
137
+ // Compute server path
138
+ const outputDir = __dirname;
139
+ const serverPath = join(outputDir, "../.output/server/index.mjs");
140
+
141
+ // Start server with bun
142
+ const serverProcess = spawn(bunPath, [serverPath], {
143
+ stdio: ["ignore", "inherit", "inherit"],
144
+ detached: true,
145
+ });
146
+
147
+ serverProcess.unref();