context-lens 0.2.0 ā 0.2.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/README.md +62 -17
- package/dist/cli-utils.d.ts +1 -1
- package/dist/cli-utils.d.ts.map +1 -1
- package/dist/cli-utils.js +28 -13
- package/dist/cli-utils.js.map +1 -1
- package/dist/cli.js +77 -65
- package/dist/cli.js.map +1 -1
- package/dist/core/conversation.d.ts +54 -0
- package/dist/core/conversation.d.ts.map +1 -0
- package/dist/core/conversation.js +188 -0
- package/dist/core/conversation.js.map +1 -0
- package/dist/core/models.d.ts +30 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +96 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/parse.d.ts +17 -0
- package/dist/core/parse.d.ts.map +1 -0
- package/dist/core/parse.js +349 -0
- package/dist/core/parse.js.map +1 -0
- package/dist/core/routing.d.ts +47 -0
- package/dist/core/routing.d.ts.map +1 -0
- package/dist/core/routing.js +132 -0
- package/dist/core/routing.js.map +1 -0
- package/dist/core/source.d.ts +22 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +56 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/tokens.d.ts +11 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +16 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core.d.ts +12 -22
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +12 -471
- package/dist/core.js.map +1 -1
- package/dist/http/headers.d.ts +25 -0
- package/dist/http/headers.d.ts.map +1 -0
- package/dist/http/headers.js +54 -0
- package/dist/http/headers.js.map +1 -0
- package/dist/lhar-types.generated.d.ts +1 -1
- package/dist/lhar.d.ts +4 -4
- package/dist/lhar.d.ts.map +1 -1
- package/dist/lhar.js +190 -106
- package/dist/lhar.js.map +1 -1
- package/dist/server/config.d.ts +12 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +33 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/projection.d.ts +9 -0
- package/dist/server/projection.d.ts.map +1 -0
- package/dist/server/projection.js +39 -0
- package/dist/server/projection.js.map +1 -0
- package/dist/server/proxy.d.ts +13 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +232 -0
- package/dist/server/proxy.js.map +1 -0
- package/dist/server/store.d.ts +33 -0
- package/dist/server/store.d.ts.map +1 -0
- package/dist/server/store.js +350 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server/webui.d.ts +5 -0
- package/dist/server/webui.d.ts.map +1 -0
- package/dist/server/webui.js +170 -0
- package/dist/server/webui.js.map +1 -0
- package/dist/server-utils.d.ts +2 -2
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +12 -21
- package/dist/server-utils.js.map +1 -1
- package/dist/server.js +30 -697
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +50 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/version.generated.d.ts +2 -0
- package/dist/version.generated.d.ts.map +1 -0
- package/dist/version.generated.js +2 -0
- package/dist/version.generated.js.map +1 -0
- package/package.json +18 -6
- package/public/index.html +39 -12
- package/schema/lhar.schema.json +1 -1
package/README.md
CHANGED
|
@@ -1,37 +1,62 @@
|
|
|
1
1
|
# Context Lens
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+
[](https://github.com/larsderidder/context-lens/actions/workflows/ci.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/context-lens)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Context window visualizer for LLM coding tools. Sits between your tool and the API as a proxy, captures every request, and gives you a web UI to explore what's actually in the context window: composition treemaps, turn-by-turn diffs, cost tracking, and automatic findings.
|
|
6
8
|
|
|
7
|
-
Zero dependencies.
|
|
9
|
+
Zero dependencies. Works with Claude Code, Codex, Gemini CLI, Aider, Kimi, Pi, and anything else that talks to OpenAI/Anthropic/Google APIs.
|
|
8
10
|
|
|
9
11
|

|
|
10
12
|
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g context-lens
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or run directly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx context-lens ...
|
|
23
|
+
```
|
|
24
|
+
|
|
11
25
|
## Quick Start
|
|
12
26
|
|
|
13
27
|
```bash
|
|
14
28
|
npx context-lens claude "your prompt"
|
|
15
29
|
npx context-lens codex "your prompt"
|
|
30
|
+
npx context-lens gemini "your prompt"
|
|
16
31
|
npx context-lens aider --model claude-sonnet-4
|
|
17
32
|
npx context-lens -- python my_agent.py
|
|
18
33
|
```
|
|
19
34
|
|
|
20
|
-
This starts the proxy (port 4040), opens the web UI (http://localhost:4041), sets the right env vars, and runs your command. Multiple tools can share one proxy
|
|
35
|
+
This starts the proxy (port 4040), opens the web UI (http://localhost:4041), sets the right env vars, and runs your command. Multiple tools can share one proxy; just open more terminals.
|
|
36
|
+
|
|
37
|
+
## Supported Providers
|
|
38
|
+
|
|
39
|
+
| Provider | Method | Status | Environment Variable |
|
|
40
|
+
| :--- | :--- | :--- | :--- |
|
|
41
|
+
| **Anthropic** | Reverse Proxy | ā
Stable | `ANTHROPIC_BASE_URL` |
|
|
42
|
+
| **OpenAI** | Reverse Proxy | ā
Stable | `OPENAI_BASE_URL` |
|
|
43
|
+
| **Google Gemini** | Reverse Proxy | š§Ŗ Experimental | `GOOGLE_GEMINI_BASE_URL` |
|
|
44
|
+
| **ChatGPT (Subscription)** | MITM Proxy | ā
Stable | `https_proxy` |
|
|
45
|
+
| **Aider / Generic** | Reverse Proxy | ā
Stable | Detects standard patterns |
|
|
21
46
|
|
|
22
47
|
## What You Get
|
|
23
48
|
|
|
24
|
-
- **Composition treemap
|
|
25
|
-
- **Cost tracking
|
|
26
|
-
- **Conversation threading
|
|
27
|
-
- **Agent breakdown
|
|
28
|
-
- **Timeline
|
|
29
|
-
- **Context diff
|
|
30
|
-
- **Findings
|
|
31
|
-
- **Auto-detection
|
|
32
|
-
- **LHAR export
|
|
33
|
-
- **State persistence
|
|
34
|
-
- **Streaming support
|
|
49
|
+
- **Composition treemap:** visual breakdown of what's filling your context (system prompts, tool definitions, tool results, messages, thinking, images)
|
|
50
|
+
- **Cost tracking:** per-turn and per-session cost estimates across models
|
|
51
|
+
- **Conversation threading:** groups API calls by session, shows main agent vs subagent turns
|
|
52
|
+
- **Agent breakdown:** token usage and cost per agent within a session
|
|
53
|
+
- **Timeline:** bar chart of context size over time, filterable by main/all/cost
|
|
54
|
+
- **Context diff:** turn-to-turn delta showing what grew, shrank, or appeared
|
|
55
|
+
- **Findings:** flags large tool results, unused tool definitions, context overflow risk, compaction events
|
|
56
|
+
- **Auto-detection:** recognizes Claude Code, Codex, aider, Pi, and others by source tag or system prompt
|
|
57
|
+
- **LHAR export:** download session data as LHAR (LLM HTTP Archive) format ([doc](docs/LHAR.md))
|
|
58
|
+
- **State persistence:** data survives restarts; delete individual sessions or reset all from the UI
|
|
59
|
+
- **Streaming support:** passes through SSE chunks in real-time
|
|
35
60
|
|
|
36
61
|
### Screenshots
|
|
37
62
|
|
|
@@ -55,6 +80,7 @@ npm start
|
|
|
55
80
|
|
|
56
81
|
ANTHROPIC_BASE_URL=http://localhost:4040 claude "your prompt"
|
|
57
82
|
OPENAI_BASE_URL=http://localhost:4040 codex "your prompt"
|
|
83
|
+
GOOGLE_GEMINI_BASE_URL=http://localhost:4040 gemini "your prompt" # experimental
|
|
58
84
|
```
|
|
59
85
|
|
|
60
86
|
### Source Tagging
|
|
@@ -66,9 +92,28 @@ ANTHROPIC_BASE_URL=http://localhost:4040/claude claude "prompt"
|
|
|
66
92
|
OPENAI_BASE_URL=http://localhost:4040/aider aider "prompt"
|
|
67
93
|
```
|
|
68
94
|
|
|
95
|
+
### Pi Coding Agent
|
|
96
|
+
|
|
97
|
+
Pi ignores standard base-URL environment variables, so the CLI wrapper can't redirect it automatically. Instead, configure Pi to point at the proxy via `~/.pi/agent/models.json`:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"providers": {
|
|
102
|
+
"anthropic": { "baseUrl": "http://localhost:4040/pi" },
|
|
103
|
+
"openai": { "baseUrl": "http://localhost:4040/pi" },
|
|
104
|
+
"google-gemini-cli": { "baseUrl": "http://localhost:4040/pi" },
|
|
105
|
+
"google-antigravity": { "baseUrl": "http://localhost:4040/pi" }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Start the proxy (`npm start`), then run Pi normally. No CLI wrapper needed. The config hot-reloads when you switch models via `/model`, but adding new provider overrides requires restarting Pi.
|
|
111
|
+
|
|
112
|
+
Tested with: Claude Opus 4.6, Gemini 2.5 Flash (via Gemini CLI subscription), GPT-OSS 120B (via Antigravity). The `openai-codex` provider (ChatGPT subscription) has the same Cloudflare limitation as Codex and is not supported through the reverse proxy.
|
|
113
|
+
|
|
69
114
|
### Codex Subscription Mode
|
|
70
115
|
|
|
71
|
-
Codex with a ChatGPT subscription needs mitmproxy for HTTPS interception (Cloudflare blocks reverse proxies). The CLI handles this automatically
|
|
116
|
+
Codex with a ChatGPT subscription needs mitmproxy for HTTPS interception (Cloudflare blocks reverse proxies). The CLI handles this automatically. Just make sure `mitmdump` is installed:
|
|
72
117
|
|
|
73
118
|
```bash
|
|
74
119
|
pipx install mitmproxy
|
|
@@ -82,7 +127,7 @@ Context Lens sits between your coding tool and the LLM API, capturing requests i
|
|
|
82
127
|
**Reverse proxy (Claude Code, aider, OpenAI API tools)**
|
|
83
128
|
|
|
84
129
|
```
|
|
85
|
-
Tool
|
|
130
|
+
Tool āHTTPāā¶ Context Lens (:4040) āHTTPSāā¶ api.anthropic.com / api.openai.com
|
|
86
131
|
ā
|
|
87
132
|
ā¼
|
|
88
133
|
Web UI (:4041)
|
|
@@ -95,7 +140,7 @@ The CLI sets env vars like `ANTHROPIC_BASE_URL=http://localhost:4040` so the too
|
|
|
95
140
|
Some tools can't be reverse-proxied. Codex with a ChatGPT subscription authenticates against `chatgpt.com`, which is behind Cloudflare. A reverse proxy changes the TLS fingerprint, causing Cloudflare to reject the request with a 403. For these tools, Context Lens uses mitmproxy as a forward HTTPS proxy instead:
|
|
96
141
|
|
|
97
142
|
```
|
|
98
|
-
Tool
|
|
143
|
+
Tool āHTTPS via proxyāā¶ mitmproxy (:8080) āHTTPSāā¶ chatgpt.com
|
|
99
144
|
ā
|
|
100
145
|
mitm_addon.py
|
|
101
146
|
ā
|
package/dist/cli-utils.d.ts
CHANGED
package/dist/cli-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-utils.d.ts","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-utils.d.ts","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAoD7C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAY1D;AAGD,eAAO,MAAM,aAAa;;;;;CAMhB,CAAC"}
|
package/dist/cli-utils.js
CHANGED
|
@@ -1,43 +1,58 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { fileURLToPath } from
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
3
|
const __filename = fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = dirname(__filename);
|
|
5
5
|
// Known tool config: env vars for the child process, extra CLI args, server env vars, and whether mitmproxy is needed
|
|
6
|
-
const PROXY_URL =
|
|
6
|
+
const PROXY_URL = "http://localhost:4040";
|
|
7
7
|
const MITM_PORT = 8080;
|
|
8
8
|
const MITM_PROXY_URL = `http://localhost:${MITM_PORT}`;
|
|
9
9
|
const TOOL_CONFIG = {
|
|
10
|
-
|
|
10
|
+
claude: {
|
|
11
11
|
childEnv: { ANTHROPIC_BASE_URL: `${PROXY_URL}/claude` },
|
|
12
12
|
extraArgs: [],
|
|
13
13
|
serverEnv: {},
|
|
14
14
|
needsMitm: false,
|
|
15
15
|
},
|
|
16
|
-
|
|
17
|
-
// Codex subscription uses chatgpt.com with Cloudflare
|
|
16
|
+
codex: {
|
|
17
|
+
// Codex subscription uses chatgpt.com with Cloudflare, needs forward proxy (mitmproxy)
|
|
18
18
|
// to intercept HTTPS traffic without breaking TLS fingerprinting.
|
|
19
19
|
childEnv: {
|
|
20
20
|
https_proxy: MITM_PROXY_URL,
|
|
21
|
-
SSL_CERT_FILE: join(process.env.HOME ||
|
|
21
|
+
SSL_CERT_FILE: join(process.env.HOME || "", ".mitmproxy", "mitmproxy-ca-cert.pem"),
|
|
22
22
|
},
|
|
23
23
|
extraArgs: [],
|
|
24
24
|
serverEnv: {},
|
|
25
25
|
needsMitm: true,
|
|
26
26
|
},
|
|
27
|
-
|
|
28
|
-
childEnv: {
|
|
27
|
+
aider: {
|
|
28
|
+
childEnv: {
|
|
29
|
+
ANTHROPIC_BASE_URL: `${PROXY_URL}/aider`,
|
|
30
|
+
OPENAI_BASE_URL: `${PROXY_URL}/aider`,
|
|
31
|
+
},
|
|
32
|
+
extraArgs: [],
|
|
33
|
+
serverEnv: {},
|
|
34
|
+
needsMitm: false,
|
|
35
|
+
},
|
|
36
|
+
gemini: {
|
|
37
|
+
childEnv: {
|
|
38
|
+
GOOGLE_GEMINI_BASE_URL: `${PROXY_URL}/gemini/`, // API-key auth path
|
|
39
|
+
CODE_ASSIST_ENDPOINT: `${PROXY_URL}/gemini`, // OAuth/Google login path
|
|
40
|
+
},
|
|
29
41
|
extraArgs: [],
|
|
30
42
|
serverEnv: {},
|
|
31
43
|
needsMitm: false,
|
|
32
44
|
},
|
|
33
45
|
};
|
|
34
46
|
export function getToolConfig(toolName) {
|
|
35
|
-
return TOOL_CONFIG[toolName] || {
|
|
36
|
-
childEnv: {
|
|
47
|
+
return (TOOL_CONFIG[toolName] || {
|
|
48
|
+
childEnv: {
|
|
49
|
+
ANTHROPIC_BASE_URL: `${PROXY_URL}/${toolName}`,
|
|
50
|
+
OPENAI_BASE_URL: `${PROXY_URL}/${toolName}`,
|
|
51
|
+
},
|
|
37
52
|
extraArgs: [],
|
|
38
53
|
serverEnv: {},
|
|
39
54
|
needsMitm: false,
|
|
40
|
-
};
|
|
55
|
+
});
|
|
41
56
|
}
|
|
42
57
|
// Exported for tests (and to keep cli.ts smaller).
|
|
43
58
|
export const CLI_CONSTANTS = {
|
|
@@ -45,6 +60,6 @@ export const CLI_CONSTANTS = {
|
|
|
45
60
|
MITM_PORT,
|
|
46
61
|
MITM_PROXY_URL,
|
|
47
62
|
// Resolved relative to compiled output (dist/ or dist-test/), matching cli.ts behavior.
|
|
48
|
-
MITM_ADDON_PATH: join(__dirname,
|
|
63
|
+
MITM_ADDON_PATH: join(__dirname, "..", "mitm_addon.py"),
|
|
49
64
|
};
|
|
50
65
|
//# sourceMappingURL=cli-utils.js.map
|
package/dist/cli-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-utils.js","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli-utils.js","sourceRoot":"","sources":["../src/cli-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,sHAAsH;AACtH,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAC1C,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,cAAc,GAAG,oBAAoB,SAAS,EAAE,CAAC;AAEvD,MAAM,WAAW,GAA+B;IAC9C,MAAM,EAAE;QACN,QAAQ,EAAE,EAAE,kBAAkB,EAAE,GAAG,SAAS,SAAS,EAAE;QACvD,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,KAAK;KACjB;IACD,KAAK,EAAE;QACL,uFAAuF;QACvF,kEAAkE;QAClE,QAAQ,EAAE;YACR,WAAW,EAAE,cAAc;YAC3B,aAAa,EAAE,IAAI,CACjB,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EACtB,YAAY,EACZ,uBAAuB,CACxB;SACF;QACD,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,IAAI;KAChB;IACD,KAAK,EAAE;QACL,QAAQ,EAAE;YACR,kBAAkB,EAAE,GAAG,SAAS,QAAQ;YACxC,eAAe,EAAE,GAAG,SAAS,QAAQ;SACtC;QACD,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,KAAK;KACjB;IACD,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,sBAAsB,EAAE,GAAG,SAAS,UAAU,EAAE,oBAAoB;YACpE,oBAAoB,EAAE,GAAG,SAAS,SAAS,EAAE,0BAA0B;SACxE;QACD,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,KAAK;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,CACL,WAAW,CAAC,QAAQ,CAAC,IAAI;QACvB,QAAQ,EAAE;YACR,kBAAkB,EAAE,GAAG,SAAS,IAAI,QAAQ,EAAE;YAC9C,eAAe,EAAE,GAAG,SAAS,IAAI,QAAQ,EAAE;SAC5C;QACD,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,KAAK;KACjB,CACF,CAAC;AACJ,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS;IACT,SAAS;IACT,cAAc;IACd,wFAAwF;IACxF,eAAe,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,eAAe,CAAC;CAC/C,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import { fileURLToPath } from
|
|
8
|
-
import {
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import net from "node:net";
|
|
5
|
+
import { platform } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { CLI_CONSTANTS, getToolConfig } from "./cli-utils.js";
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = dirname(__filename);
|
|
11
11
|
// Known tool config: env vars for the child process, extra CLI args, server env vars, and whether mitmproxy is needed
|
|
12
12
|
// Note: actual tool config lives in cli-utils.ts so it can be unit-tested without importing this entrypoint.
|
|
13
|
-
const LOCKFILE =
|
|
13
|
+
const LOCKFILE = "/tmp/context-lens.lock";
|
|
14
14
|
// Parse command line arguments
|
|
15
15
|
const args = process.argv.slice(2);
|
|
16
16
|
if (args.length === 0) {
|
|
17
17
|
// Standalone mode: just start the proxy server
|
|
18
|
-
const serverPath = join(__dirname,
|
|
19
|
-
const server = spawn(
|
|
20
|
-
server.on(
|
|
21
|
-
process.on(
|
|
22
|
-
process.on(
|
|
18
|
+
const serverPath = join(__dirname, "server.js");
|
|
19
|
+
const server = spawn("node", [serverPath], { stdio: "inherit" });
|
|
20
|
+
server.on("exit", (code) => process.exit(code || 0));
|
|
21
|
+
process.on("SIGINT", () => server.kill("SIGINT"));
|
|
22
|
+
process.on("SIGTERM", () => server.kill("SIGTERM"));
|
|
23
23
|
// Prevent early exit
|
|
24
24
|
process.stdin.resume();
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
27
|
// Skip '--' separator if present
|
|
28
28
|
let commandArgs = args;
|
|
29
|
-
if (args[0] ===
|
|
29
|
+
if (args[0] === "--") {
|
|
30
30
|
commandArgs = args.slice(1);
|
|
31
31
|
}
|
|
32
32
|
if (commandArgs.length === 0) {
|
|
33
|
-
console.error(
|
|
33
|
+
console.error("Error: No command specified after --");
|
|
34
34
|
process.exit(1);
|
|
35
35
|
}
|
|
36
36
|
const commandName = commandArgs[0];
|
|
@@ -40,11 +40,11 @@ else {
|
|
|
40
40
|
// Check if proxy is already running
|
|
41
41
|
function isProxyRunning() {
|
|
42
42
|
return new Promise((resolve) => {
|
|
43
|
-
const socket = net.connect({ port: 4040, host:
|
|
43
|
+
const socket = net.connect({ port: 4040, host: "localhost" }, () => {
|
|
44
44
|
socket.end();
|
|
45
45
|
resolve(true);
|
|
46
46
|
});
|
|
47
|
-
socket.on(
|
|
47
|
+
socket.on("error", () => resolve(false));
|
|
48
48
|
socket.setTimeout(1000, () => {
|
|
49
49
|
socket.destroy();
|
|
50
50
|
resolve(false);
|
|
@@ -56,14 +56,14 @@ else {
|
|
|
56
56
|
try {
|
|
57
57
|
let count = 0;
|
|
58
58
|
if (fs.existsSync(LOCKFILE)) {
|
|
59
|
-
const data = fs.readFileSync(LOCKFILE,
|
|
60
|
-
count = parseInt(data) || 0;
|
|
59
|
+
const data = fs.readFileSync(LOCKFILE, "utf8");
|
|
60
|
+
count = parseInt(data, 10) || 0;
|
|
61
61
|
}
|
|
62
62
|
fs.writeFileSync(LOCKFILE, String(count + 1));
|
|
63
63
|
return count + 1;
|
|
64
64
|
}
|
|
65
65
|
catch (err) {
|
|
66
|
-
console.error(
|
|
66
|
+
console.error("Warning: failed to update lockfile:", err instanceof Error ? err.message : String(err));
|
|
67
67
|
return 1;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -74,7 +74,7 @@ else {
|
|
|
74
74
|
fs.unlinkSync(LOCKFILE);
|
|
75
75
|
}
|
|
76
76
|
catch (err) {
|
|
77
|
-
console.error(
|
|
77
|
+
console.error("Warning: failed to clear stale lockfile:", err instanceof Error ? err.message : String(err));
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
// Decrement reference count in lockfile
|
|
@@ -82,8 +82,8 @@ else {
|
|
|
82
82
|
try {
|
|
83
83
|
if (!fs.existsSync(LOCKFILE))
|
|
84
84
|
return 0;
|
|
85
|
-
const data = fs.readFileSync(LOCKFILE,
|
|
86
|
-
const count = Math.max(0, (parseInt(data) || 1) - 1);
|
|
85
|
+
const data = fs.readFileSync(LOCKFILE, "utf8");
|
|
86
|
+
const count = Math.max(0, (parseInt(data, 10) || 1) - 1);
|
|
87
87
|
if (count === 0) {
|
|
88
88
|
fs.unlinkSync(LOCKFILE);
|
|
89
89
|
}
|
|
@@ -93,7 +93,7 @@ else {
|
|
|
93
93
|
return count;
|
|
94
94
|
}
|
|
95
95
|
catch (err) {
|
|
96
|
-
console.error(
|
|
96
|
+
console.error("Warning: failed to update lockfile:", err instanceof Error ? err.message : String(err));
|
|
97
97
|
return 0;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -108,55 +108,55 @@ else {
|
|
|
108
108
|
async function initializeProxy() {
|
|
109
109
|
const alreadyRunning = await isProxyRunning();
|
|
110
110
|
if (alreadyRunning) {
|
|
111
|
-
console.log(
|
|
111
|
+
console.log("š Context Lens proxy already running, attaching to it...");
|
|
112
112
|
incrementRefCount();
|
|
113
113
|
serverReady = true;
|
|
114
114
|
shouldShutdownProxy = false;
|
|
115
115
|
maybeStartMitmThenChild();
|
|
116
116
|
}
|
|
117
117
|
else {
|
|
118
|
-
console.log(
|
|
118
|
+
console.log("š Starting Context Lens proxy and web UI...");
|
|
119
119
|
// No proxy is listening on :4040. Any existing lockfile is stale and would prevent shutdown later.
|
|
120
120
|
clearStaleLockfile();
|
|
121
121
|
incrementRefCount();
|
|
122
122
|
shouldShutdownProxy = true;
|
|
123
|
-
const serverPath = join(__dirname,
|
|
124
|
-
serverProcess = spawn(
|
|
125
|
-
stdio: [
|
|
123
|
+
const serverPath = join(__dirname, "server.js");
|
|
124
|
+
serverProcess = spawn("node", [serverPath], {
|
|
125
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
126
126
|
detached: false,
|
|
127
|
-
env: { ...toolConfig.serverEnv, ...process.env, CONTEXT_LENS_CLI:
|
|
127
|
+
env: { ...toolConfig.serverEnv, ...process.env, CONTEXT_LENS_CLI: "1" },
|
|
128
128
|
});
|
|
129
129
|
// Wait for server to be ready, then suppress output (visible in web UI at :4041)
|
|
130
|
-
serverProcess.stdout
|
|
130
|
+
serverProcess.stdout?.on("data", (data) => {
|
|
131
131
|
const output = data.toString();
|
|
132
132
|
if (!serverReady) {
|
|
133
133
|
process.stderr.write(output);
|
|
134
134
|
}
|
|
135
|
-
if (output.includes(
|
|
135
|
+
if (output.includes("Context Lens Web UI running") && !serverReady) {
|
|
136
136
|
serverReady = true;
|
|
137
137
|
maybeStartMitmThenChild();
|
|
138
138
|
}
|
|
139
139
|
});
|
|
140
|
-
serverProcess.stderr
|
|
140
|
+
serverProcess.stderr?.on("data", (data) => {
|
|
141
141
|
if (!serverReady) {
|
|
142
142
|
process.stderr.write(data);
|
|
143
143
|
}
|
|
144
144
|
});
|
|
145
|
-
serverProcess.on(
|
|
146
|
-
console.error(
|
|
145
|
+
serverProcess.on("error", (err) => {
|
|
146
|
+
console.error("Failed to start server:", err);
|
|
147
147
|
decrementRefCount();
|
|
148
148
|
process.exit(1);
|
|
149
149
|
});
|
|
150
|
-
serverProcess.on(
|
|
150
|
+
serverProcess.on("exit", (code) => {
|
|
151
151
|
if (!serverReady) {
|
|
152
|
-
console.error(
|
|
152
|
+
console.error("Server exited unexpectedly");
|
|
153
153
|
decrementRefCount();
|
|
154
154
|
process.exit(code || 1);
|
|
155
155
|
}
|
|
156
156
|
});
|
|
157
157
|
// Open browser after a short delay (only when starting new server)
|
|
158
158
|
setTimeout(() => {
|
|
159
|
-
openBrowser(
|
|
159
|
+
openBrowser("http://localhost:4041");
|
|
160
160
|
}, 1000);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -164,27 +164,34 @@ else {
|
|
|
164
164
|
// Start mitmproxy if needed, then start the child
|
|
165
165
|
function maybeStartMitmThenChild() {
|
|
166
166
|
if (!toolConfig.needsMitm) {
|
|
167
|
-
|
|
167
|
+
startChild();
|
|
168
|
+
return;
|
|
168
169
|
}
|
|
169
170
|
const addonPath = CLI_CONSTANTS.MITM_ADDON_PATH;
|
|
170
|
-
console.log(
|
|
171
|
-
mitmProcess = spawn(
|
|
172
|
-
|
|
171
|
+
console.log("š Starting mitmproxy (forward proxy for HTTPS interception)...");
|
|
172
|
+
mitmProcess = spawn("mitmdump", [
|
|
173
|
+
"-s",
|
|
174
|
+
addonPath,
|
|
175
|
+
"--quiet",
|
|
176
|
+
"--listen-port",
|
|
177
|
+
String(CLI_CONSTANTS.MITM_PORT),
|
|
178
|
+
], {
|
|
179
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
173
180
|
});
|
|
174
|
-
mitmProcess.on(
|
|
175
|
-
console.error(
|
|
176
|
-
console.error(
|
|
181
|
+
mitmProcess.on("error", (err) => {
|
|
182
|
+
console.error("Failed to start mitmproxy:", err.message);
|
|
183
|
+
console.error("Install it: pipx install mitmproxy");
|
|
177
184
|
cleanup(1);
|
|
178
185
|
});
|
|
179
|
-
mitmProcess.on(
|
|
186
|
+
mitmProcess.on("exit", (code) => {
|
|
180
187
|
if (!mitmReady) {
|
|
181
|
-
console.error(
|
|
188
|
+
console.error("mitmproxy exited unexpectedly");
|
|
182
189
|
cleanup(code || 1);
|
|
183
190
|
}
|
|
184
191
|
});
|
|
185
192
|
// Poll until mitmproxy is accepting connections
|
|
186
193
|
const pollMitm = setInterval(() => {
|
|
187
|
-
const socket = net.connect({ port: CLI_CONSTANTS.MITM_PORT, host:
|
|
194
|
+
const socket = net.connect({ port: CLI_CONSTANTS.MITM_PORT, host: "localhost" }, () => {
|
|
188
195
|
socket.end();
|
|
189
196
|
if (!mitmReady) {
|
|
190
197
|
mitmReady = true;
|
|
@@ -193,7 +200,7 @@ else {
|
|
|
193
200
|
startChild();
|
|
194
201
|
}
|
|
195
202
|
});
|
|
196
|
-
socket.on(
|
|
203
|
+
socket.on("error", () => { }); // not ready yet
|
|
197
204
|
socket.setTimeout(500, () => socket.destroy());
|
|
198
205
|
}, 200);
|
|
199
206
|
}
|
|
@@ -201,33 +208,35 @@ else {
|
|
|
201
208
|
function startChild() {
|
|
202
209
|
// Inject extra args (e.g. codex -c chatgpt_base_url=...) before user args
|
|
203
210
|
const allArgs = [...toolConfig.extraArgs, ...commandArguments];
|
|
204
|
-
console.log(`\nš Launching: ${commandName} ${allArgs.join(
|
|
211
|
+
console.log(`\nš Launching: ${commandName} ${allArgs.join(" ")}\n`);
|
|
205
212
|
const childEnv = {
|
|
206
213
|
...process.env,
|
|
207
214
|
...toolConfig.childEnv,
|
|
208
215
|
};
|
|
209
216
|
// Spawn the child process with inherited stdio (interactive)
|
|
210
|
-
// No shell: true
|
|
217
|
+
// No shell: true. Avoids intermediate process that breaks signal delivery
|
|
211
218
|
childProcess = spawn(commandName, allArgs, {
|
|
212
|
-
stdio:
|
|
219
|
+
stdio: "inherit",
|
|
213
220
|
env: childEnv,
|
|
214
221
|
});
|
|
215
|
-
childProcess.on(
|
|
222
|
+
childProcess.on("error", (err) => {
|
|
216
223
|
console.error(`\nFailed to start ${commandName}:`, err.message);
|
|
217
224
|
cleanup(1);
|
|
218
225
|
});
|
|
219
226
|
// When the child exits (however it happens), clean up and mirror its exit code
|
|
220
|
-
childProcess.on(
|
|
221
|
-
cleanup(signal ? 128 + (signal ===
|
|
227
|
+
childProcess.on("exit", (code, signal) => {
|
|
228
|
+
cleanup(signal ? 128 + (signal === "SIGINT" ? 2 : 15) : code || 0);
|
|
222
229
|
});
|
|
223
230
|
}
|
|
224
231
|
// Open browser (cross-platform)
|
|
225
232
|
function openBrowser(url) {
|
|
226
|
-
const cmd = platform() ===
|
|
227
|
-
|
|
228
|
-
|
|
233
|
+
const cmd = platform() === "darwin"
|
|
234
|
+
? "open"
|
|
235
|
+
: platform() === "win32"
|
|
236
|
+
? "start"
|
|
237
|
+
: "xdg-open";
|
|
229
238
|
const browserProcess = spawn(cmd, [url], {
|
|
230
|
-
stdio:
|
|
239
|
+
stdio: "ignore",
|
|
231
240
|
detached: true,
|
|
232
241
|
});
|
|
233
242
|
browserProcess.unref(); // Don't wait for browser to close
|
|
@@ -241,18 +250,21 @@ else {
|
|
|
241
250
|
if (mitmProcess && !mitmProcess.killed) {
|
|
242
251
|
mitmProcess.kill();
|
|
243
252
|
}
|
|
244
|
-
if (remainingRefs === 0 &&
|
|
253
|
+
if (remainingRefs === 0 &&
|
|
254
|
+
shouldShutdownProxy &&
|
|
255
|
+
serverProcess &&
|
|
256
|
+
!serverProcess.killed) {
|
|
245
257
|
serverProcess.kill();
|
|
246
258
|
}
|
|
247
259
|
process.exit(exitCode);
|
|
248
260
|
}
|
|
249
|
-
// Ignore SIGINT in the parent
|
|
261
|
+
// Ignore SIGINT in the parent. Let it flow to the child (claude/codex) naturally.
|
|
250
262
|
// The child handles Ctrl+C itself; when it eventually exits, cleanup runs via the 'exit' handler.
|
|
251
|
-
process.on(
|
|
252
|
-
// SIGTERM: external shutdown request
|
|
253
|
-
process.on(
|
|
263
|
+
process.on("SIGINT", () => { });
|
|
264
|
+
// SIGTERM: external shutdown request, forward to child
|
|
265
|
+
process.on("SIGTERM", () => {
|
|
254
266
|
if (childProcess && !childProcess.killed)
|
|
255
|
-
childProcess.kill(
|
|
267
|
+
childProcess.kill("SIGTERM");
|
|
256
268
|
});
|
|
257
269
|
}
|
|
258
270
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|