claude-code-infinite 1.0.35 → 1.0.37
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 +114 -10
- package/dist/body-shape.d.ts +49 -0
- package/dist/body-shape.d.ts.map +1 -0
- package/dist/body-shape.js +232 -0
- package/dist/body-shape.js.map +1 -0
- package/dist/cc-request.d.ts +15 -0
- package/dist/cc-request.d.ts.map +1 -1
- package/dist/cc-request.js +30 -0
- package/dist/cc-request.js.map +1 -1
- package/dist/claude-env.d.ts +24 -1
- package/dist/claude-env.d.ts.map +1 -1
- package/dist/claude-env.js +48 -7
- package/dist/claude-env.js.map +1 -1
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +1 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-main.js +113 -11
- package/dist/cli-main.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/count-tokens.d.ts +15 -2
- package/dist/count-tokens.d.ts.map +1 -1
- package/dist/count-tokens.js +13 -4
- package/dist/count-tokens.js.map +1 -1
- package/dist/desktop-command.d.ts +38 -0
- package/dist/desktop-command.d.ts.map +1 -0
- package/dist/desktop-command.js +324 -0
- package/dist/desktop-command.js.map +1 -0
- package/dist/desktop-service.d.ts +41 -0
- package/dist/desktop-service.d.ts.map +1 -0
- package/dist/desktop-service.js +449 -0
- package/dist/desktop-service.js.map +1 -0
- package/dist/desktop-setup.d.ts +94 -0
- package/dist/desktop-setup.d.ts.map +1 -0
- package/dist/desktop-setup.js +288 -0
- package/dist/desktop-setup.js.map +1 -0
- package/dist/financial-redaction.d.ts +12 -0
- package/dist/financial-redaction.d.ts.map +1 -0
- package/dist/financial-redaction.js +509 -0
- package/dist/financial-redaction.js.map +1 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -1
- package/dist/https-proxy-eligibility.d.ts +31 -0
- package/dist/https-proxy-eligibility.d.ts.map +1 -0
- package/dist/https-proxy-eligibility.js +204 -0
- package/dist/https-proxy-eligibility.js.map +1 -0
- package/dist/https-proxy-mode.d.ts +59 -0
- package/dist/https-proxy-mode.d.ts.map +1 -0
- package/dist/https-proxy-mode.js +255 -0
- package/dist/https-proxy-mode.js.map +1 -0
- package/dist/https-proxy-session.d.ts +64 -0
- package/dist/https-proxy-session.d.ts.map +1 -0
- package/dist/https-proxy-session.js +165 -0
- package/dist/https-proxy-session.js.map +1 -0
- package/dist/image-tokens.d.ts +6 -1
- package/dist/image-tokens.d.ts.map +1 -1
- package/dist/image-tokens.js +75 -14
- package/dist/image-tokens.js.map +1 -1
- package/dist/lane-activity.d.ts +42 -0
- package/dist/lane-activity.d.ts.map +1 -0
- package/dist/lane-activity.js +79 -0
- package/dist/lane-activity.js.map +1 -0
- package/dist/memtree-mcp.d.ts +32 -1
- package/dist/memtree-mcp.d.ts.map +1 -1
- package/dist/memtree-mcp.js +73 -7
- package/dist/memtree-mcp.js.map +1 -1
- package/dist/memtree.d.ts +10 -0
- package/dist/memtree.d.ts.map +1 -1
- package/dist/memtree.js +59 -12
- package/dist/memtree.js.map +1 -1
- package/dist/message-refs.d.ts +81 -0
- package/dist/message-refs.d.ts.map +1 -0
- package/dist/message-refs.js +378 -0
- package/dist/message-refs.js.map +1 -0
- package/dist/mitm-ca.d.ts +31 -0
- package/dist/mitm-ca.d.ts.map +1 -0
- package/dist/mitm-ca.js +236 -0
- package/dist/mitm-ca.js.map +1 -0
- package/dist/paused-session.d.ts.map +1 -1
- package/dist/paused-session.js +9 -2
- package/dist/paused-session.js.map +1 -1
- package/dist/proxy.d.ts +25 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +168 -22
- package/dist/proxy.js.map +1 -1
- package/dist/refusal-reason.d.ts +3 -2
- package/dist/refusal-reason.d.ts.map +1 -1
- package/dist/refusal-reason.js +4 -3
- package/dist/refusal-reason.js.map +1 -1
- package/dist/reqlog.d.ts +13 -3
- package/dist/reqlog.d.ts.map +1 -1
- package/dist/reqlog.js +1 -1
- package/dist/reqlog.js.map +1 -1
- package/dist/request-sizing.d.ts +38 -2
- package/dist/request-sizing.d.ts.map +1 -1
- package/dist/request-sizing.js +72 -6
- package/dist/request-sizing.js.map +1 -1
- package/dist/secret-redaction.d.ts +25 -0
- package/dist/secret-redaction.d.ts.map +1 -0
- package/dist/secret-redaction.js +492 -0
- package/dist/secret-redaction.js.map +1 -0
- package/dist/statusline-auto.d.ts +15 -0
- package/dist/statusline-auto.d.ts.map +1 -0
- package/dist/statusline-auto.js +125 -0
- package/dist/statusline-auto.js.map +1 -0
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +3 -2
- package/dist/statusline.js.map +1 -1
- package/dist/utf8-bytes.d.ts +10 -0
- package/dist/utf8-bytes.d.ts.map +1 -0
- package/dist/utf8-bytes.js +107 -0
- package/dist/utf8-bytes.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemTree for the Claude desktop app's Code tab.
|
|
3
|
+
*
|
|
4
|
+
* The desktop app starts its own Claude Code binary with ANTHROPIC_BASE_URL
|
|
5
|
+
* forced to api.anthropic.com and its own OAuth token in the env, so ccc can't
|
|
6
|
+
* wrap it or be its base URL. What the Code tab does honour is HTTPS_PROXY and
|
|
7
|
+
* NODE_EXTRA_CA_CERTS from a saved local environment (Desktop's environment
|
|
8
|
+
* editor), which applies only to the sessions started from that environment.
|
|
9
|
+
*
|
|
10
|
+
* So `ccc desktop setup` makes a long-lived loopback service (a launchd agent on
|
|
11
|
+
* macOS) that is those sessions' HTTPS proxy:
|
|
12
|
+
*
|
|
13
|
+
* - CONNECT api.anthropic.com:443 with the service token: TLS is terminated with
|
|
14
|
+
* a leaf from a CA name-constrained to api.anthropic.com (mitm-ca.ts). The CA
|
|
15
|
+
* key is discarded at setup; only the leaf key is kept (0600). Every other
|
|
16
|
+
* CONNECT is a blind tunnel (https-proxy-mode.ts, unchanged).
|
|
17
|
+
* - Each decrypted POST /v1/messages and /v1/messages/count_tokens goes to a
|
|
18
|
+
* per-session ccc proxy (proxy.ts's startProxy, in this process, on its own
|
|
19
|
+
* loopback port), picked by Claude Code's `x-claude-code-session-id` and made
|
|
20
|
+
* on that session's first request with the session's project (its working
|
|
21
|
+
* directory, read from the request's system prompt). Everything else
|
|
22
|
+
* (bridge/Remote Control, OAuth, telemetry, files) and session-less model
|
|
23
|
+
* calls go to a shared "default" proxy, whose intercepted handling passes them
|
|
24
|
+
* through verbatim as in terminal proxy mode.
|
|
25
|
+
* - The loopback routes (`/memtree/*` for the MemTree MCP server) need the
|
|
26
|
+
* service token (header) as well, since this port is fixed and long-lived.
|
|
27
|
+
* - Idle sessions (no request for SESSION_IDLE_MS) are drained and closed.
|
|
28
|
+
*/
|
|
29
|
+
import http from "node:http";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import fs from "node:fs";
|
|
32
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
33
|
+
import { attachHttpsProxyMode } from "./https-proxy-mode.js";
|
|
34
|
+
import { INTERCEPT_HOST } from "./mitm-ca.js";
|
|
35
|
+
import { HTTPS_PROXY_MODE_ENV, httpsProxyModeDecision } from "./https-proxy-eligibility.js";
|
|
36
|
+
import { INNER_INTERCEPTED_HEADER, INNER_TOKEN_HEADER, startProxy, } from "./proxy.js";
|
|
37
|
+
import { MemtreeClient } from "./memtree.js";
|
|
38
|
+
import { RequestLogger } from "./reqlog.js";
|
|
39
|
+
import { readProjectMeta } from "./project-meta.js";
|
|
40
|
+
import { ClaudeTranscriptUsage } from "./transcript-usage.js";
|
|
41
|
+
import { StablePrefixStore } from "./prefix-store.js";
|
|
42
|
+
import { ToolOutputStore } from "./tool-output-store.js";
|
|
43
|
+
import { MEMTREE_TOOLS_HEADER_VALUE } from "./memtree-mcp-config.js";
|
|
44
|
+
import { MEMTREE_MCP_SERVER_NAME, PROXY_TOKEN_HEADER } from "./memtree-mcp.js";
|
|
45
|
+
/** A session idle this long is closed and final-indexed (as a terminal ccc at exit). */
|
|
46
|
+
const SESSION_IDLE_MS = 30 * 60_000;
|
|
47
|
+
const SWEEP_MS = 10 * 60_000;
|
|
48
|
+
/** How long a closing session's final index and background calls may take. */
|
|
49
|
+
const FINAL_DRAIN_MS = 10_000;
|
|
50
|
+
/**
|
|
51
|
+
* The session's directory, from Claude Code's environment block ("Primary working
|
|
52
|
+
* directory: ..."): in the top-level `system` text, or (Claude Code 2.1.322) in a
|
|
53
|
+
* `role: "system"` entry of `messages`. Never user or assistant text.
|
|
54
|
+
*/
|
|
55
|
+
export function workingDirectoryFromBody(body) {
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(body);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const textsOf = (content) => typeof content === "string" ? [content]
|
|
64
|
+
: Array.isArray(content) ? content.map((b) => (b && typeof b === "object" && typeof b.text === "string"
|
|
65
|
+
? b.text : "")) : [];
|
|
66
|
+
const systemMessages = Array.isArray(parsed.messages)
|
|
67
|
+
? parsed.messages.filter((m) => m?.role === "system")
|
|
68
|
+
.flatMap((m) => textsOf(m.content))
|
|
69
|
+
: [];
|
|
70
|
+
for (const text of [...textsOf(parsed.system), ...systemMessages]) {
|
|
71
|
+
const m = /^\s*-?\s*Primary working directory: (.+)$/m.exec(text);
|
|
72
|
+
const dir = m?.[1]?.trim();
|
|
73
|
+
if (dir && path.isAbsolute(dir))
|
|
74
|
+
return dir;
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
export async function startDesktopService(opts) {
|
|
79
|
+
const log = opts.log ?? ((line) => process.stderr.write(`${new Date().toISOString()} ${line}\n`));
|
|
80
|
+
const reqlog = new RequestLogger(path.join(opts.paths.dir, "requests.jsonl"));
|
|
81
|
+
// The inner proxies answer only this process (ProxyOptions.innerToken): they are
|
|
82
|
+
// ordinary loopback listeners, so without it any local user could reach them.
|
|
83
|
+
const innerToken = randomBytes(24).toString("hex");
|
|
84
|
+
const newMemtree = () => new MemtreeClient({
|
|
85
|
+
baseUrl: opts.memtreeBaseUrl,
|
|
86
|
+
apiKey: opts.apiKey,
|
|
87
|
+
debug: opts.debug,
|
|
88
|
+
reqlog,
|
|
89
|
+
// Set per session from its model calls' tool list (toolsOffered).
|
|
90
|
+
memtreeTools: undefined,
|
|
91
|
+
});
|
|
92
|
+
const proxyOptions = (memtree, transcriptUsage) => ({
|
|
93
|
+
memtree,
|
|
94
|
+
reqlog,
|
|
95
|
+
innerToken,
|
|
96
|
+
stablePrefixStore,
|
|
97
|
+
toolOutputs,
|
|
98
|
+
debug: opts.debug,
|
|
99
|
+
nativeOneMillionContext: true,
|
|
100
|
+
toolRouteRecovery: true,
|
|
101
|
+
countTokens: true,
|
|
102
|
+
claudeCodeOnly: true,
|
|
103
|
+
// Usage and the final reply come from the session's transcript, as in terminal ccc.
|
|
104
|
+
...(transcriptUsage ? { transcriptUsage } : {}),
|
|
105
|
+
...(opts.upstreamOrigin ? { upstreamOrigin: opts.upstreamOrigin } : {}),
|
|
106
|
+
// Test-only, as in terminal ccc: a small budget so a cheap session crosses it.
|
|
107
|
+
...(Number(process.env.CCC_BUDGET_TOKENS) > 0 ? { budgetTokensOverride: Number(process.env.CCC_BUDGET_TOKENS) } : {}),
|
|
108
|
+
});
|
|
109
|
+
// As in terminal ccc (cli-main.ts): a session's adopted compressed prefix, so a fresh
|
|
110
|
+
// proxy for it (after an idle close or a restart) rides it instead of blocking on a
|
|
111
|
+
// compress; and full copies of tool results shortened to fit the window (the safety net).
|
|
112
|
+
const stablePrefixStore = new StablePrefixStore();
|
|
113
|
+
const toolOutputs = new ToolOutputStore();
|
|
114
|
+
const fallbackMemtree = newMemtree();
|
|
115
|
+
const fallback = await startProxy(proxyOptions(fallbackMemtree));
|
|
116
|
+
const sessions = new Map();
|
|
117
|
+
/**
|
|
118
|
+
* The session's proxy, made on its first request. Its project is set once a
|
|
119
|
+
* request names the working directory (Claude Code's first request in a
|
|
120
|
+
* session is often a title or quota call without one); proxy.ts reads
|
|
121
|
+
* `opts.projectMeta` per request, so setting it later on the same object works.
|
|
122
|
+
* A session seen again after it was closed (resumed) gets a fresh proxy, as a
|
|
123
|
+
* terminal `ccc --resume` gets a fresh process: its transcript is caught up first.
|
|
124
|
+
*/
|
|
125
|
+
const sessionProxy = (id, cwd) => {
|
|
126
|
+
let entry = sessions.get(id);
|
|
127
|
+
if (!entry) {
|
|
128
|
+
const started = Date.now();
|
|
129
|
+
const memtree = newMemtree();
|
|
130
|
+
const transcriptUsage = new ClaudeTranscriptUsage();
|
|
131
|
+
transcriptUsage.catchUp(id);
|
|
132
|
+
const popts = proxyOptions(memtree, transcriptUsage);
|
|
133
|
+
entry = {
|
|
134
|
+
lastUsed: started,
|
|
135
|
+
inFlight: 0,
|
|
136
|
+
memtree,
|
|
137
|
+
opts: popts,
|
|
138
|
+
proxy: startProxy(popts).then((proxy) => {
|
|
139
|
+
log(`session ${id.slice(0, 8)} proxy on :${proxy.port} (${Date.now() - started} ms)`);
|
|
140
|
+
return proxy;
|
|
141
|
+
}),
|
|
142
|
+
};
|
|
143
|
+
const created = entry;
|
|
144
|
+
// A failed start (EMFILE, ...) must not stick: the next request retries.
|
|
145
|
+
created.proxy.catch((err) => {
|
|
146
|
+
if (sessions.get(id) === created)
|
|
147
|
+
sessions.delete(id);
|
|
148
|
+
log(`session ${id.slice(0, 8)} proxy failed to start: ${String(err)}`);
|
|
149
|
+
});
|
|
150
|
+
sessions.set(id, entry);
|
|
151
|
+
}
|
|
152
|
+
if (cwd && entry.cwd === undefined) {
|
|
153
|
+
const target = entry;
|
|
154
|
+
target.cwd = cwd;
|
|
155
|
+
target.refused = projectRefusal(cwd, opts.state.claudeConfigDir);
|
|
156
|
+
if (target.refused)
|
|
157
|
+
log(`session ${id.slice(0, 8)} refused: ${target.refused}`);
|
|
158
|
+
target.projectReady = readProjectMeta(cwd).then((meta) => {
|
|
159
|
+
target.opts.projectMeta = meta;
|
|
160
|
+
log(`session ${id.slice(0, 8)} project ${meta.git_repo ?? path.basename(cwd)}${meta.git_branch ? `@${meta.git_branch}` : ""}`);
|
|
161
|
+
}, () => { });
|
|
162
|
+
}
|
|
163
|
+
entry.lastUsed = Date.now();
|
|
164
|
+
return entry;
|
|
165
|
+
};
|
|
166
|
+
/** As at a terminal ccc's exit: drain, final-index the conversation, finish background calls. */
|
|
167
|
+
const closeSession = async (entry, drainMs) => {
|
|
168
|
+
const proxy = await entry.proxy;
|
|
169
|
+
await proxy.drain(drainMs);
|
|
170
|
+
entry.memtree.flushFinalIndexes(FINAL_DRAIN_MS);
|
|
171
|
+
await entry.memtree.drainBackground(FINAL_DRAIN_MS);
|
|
172
|
+
proxy.close();
|
|
173
|
+
};
|
|
174
|
+
// `intercepted`: decrypted from a token-authenticated CONNECT api.anthropic.com:443.
|
|
175
|
+
const handler = (intercepted) => (req, res) => void route(req, res, intercepted).catch((err) => {
|
|
176
|
+
log(`route error: ${String(err)}`);
|
|
177
|
+
if (res.destroyed)
|
|
178
|
+
return;
|
|
179
|
+
if (!res.headersSent)
|
|
180
|
+
res.writeHead(502, { "content-type": "application/json" });
|
|
181
|
+
res.end(JSON.stringify({ type: "error",
|
|
182
|
+
error: { type: "api_error", message: "ccc desktop service error" } }));
|
|
183
|
+
});
|
|
184
|
+
const server = http.createServer(handler(false));
|
|
185
|
+
const tunnels = attachHttpsProxyMode(server, handler(true), interceptUpstream(opts.upstreamOrigin), {
|
|
186
|
+
ca: {
|
|
187
|
+
leafCertPem: fs.readFileSync(opts.paths.leafPem, "utf8"),
|
|
188
|
+
leafKeyPem: fs.readFileSync(opts.paths.leafKey, "utf8"),
|
|
189
|
+
},
|
|
190
|
+
proxyToken: opts.state.token,
|
|
191
|
+
...(opts.tracePath ? { tracePath: opts.tracePath } : {}),
|
|
192
|
+
});
|
|
193
|
+
let closing = false;
|
|
194
|
+
const pendingRoutes = new Set();
|
|
195
|
+
async function route(req, res, intercepted) {
|
|
196
|
+
if (closing) {
|
|
197
|
+
res.writeHead(503, { "content-type": "application/json", connection: "close" });
|
|
198
|
+
res.end(JSON.stringify({ type: "error", error: { type: "overloaded_error", message: "ccc desktop service is restarting" } }));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const task = routeInner(req, res, intercepted);
|
|
202
|
+
pendingRoutes.add(task);
|
|
203
|
+
try {
|
|
204
|
+
await task;
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
pendingRoutes.delete(task);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function routeInner(req, res, intercepted) {
|
|
211
|
+
// A client that goes away while we wait (body, git, proxy start) must not still be sent upstream.
|
|
212
|
+
let gone = false;
|
|
213
|
+
res.on("close", () => { if (!res.writableFinished)
|
|
214
|
+
gone = true; });
|
|
215
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
216
|
+
const sessionId = header(req, "x-claude-code-session-id");
|
|
217
|
+
if (intercepted) {
|
|
218
|
+
const isModelCall = req.method === "POST" &&
|
|
219
|
+
(url.pathname === "/v1/messages" || url.pathname === "/v1/messages/count_tokens");
|
|
220
|
+
if (isModelCall && sessionId) {
|
|
221
|
+
const body = await readBody(req);
|
|
222
|
+
const known = sessions.get(sessionId)?.cwd;
|
|
223
|
+
const text = body.toString("utf8");
|
|
224
|
+
const entry = sessionProxy(sessionId, known ?? workingDirectoryFromBody(text));
|
|
225
|
+
// Say the memory tools exist once this session's model calls carry them (an inert or
|
|
226
|
+
// disabled MCP server never sends them). Sticky per session: a concurrent side call
|
|
227
|
+
// with another tool list (WebSearch helper, a restricted subagent) must not clear it
|
|
228
|
+
// under the main conversation's compress (Codex r3). The client holds one value per
|
|
229
|
+
// session, so per-call precision would need it carried with each compress call.
|
|
230
|
+
if (url.pathname === "/v1/messages" && toolsOffered(text) === true) {
|
|
231
|
+
entry.memtree.setMemtreeTools(MEMTREE_TOOLS_HEADER_VALUE);
|
|
232
|
+
}
|
|
233
|
+
if (entry.refused)
|
|
234
|
+
return refuseSession(res, entry.refused);
|
|
235
|
+
entry.inFlight++;
|
|
236
|
+
try {
|
|
237
|
+
// A few ms of git on the session's first request with a directory, so its MemTree calls carry the project.
|
|
238
|
+
await entry.projectReady;
|
|
239
|
+
const port = (await entry.proxy).port;
|
|
240
|
+
if (gone)
|
|
241
|
+
return;
|
|
242
|
+
await forward(req, res, port, innerToken, true, body);
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
entry.inFlight--;
|
|
246
|
+
entry.lastUsed = Date.now();
|
|
247
|
+
}
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
return forward(req, res, fallback.port, innerToken, true);
|
|
251
|
+
}
|
|
252
|
+
// Loopback routes (the MCP server's /memtree reads): the token, then the session's proxy.
|
|
253
|
+
if (!tokenMatches(header(req, PROXY_TOKEN_HEADER), opts.state.token)) {
|
|
254
|
+
res.writeHead(403, { "content-type": "application/json" });
|
|
255
|
+
res.end(JSON.stringify({ detail: "ccc desktop service: missing or wrong token" }));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (url.pathname === "/ccc-desktop/status") {
|
|
259
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
260
|
+
res.end(JSON.stringify({ service: "ccc-desktop", mode: opts.state.mode, sessions: sessions.size }));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!url.pathname.startsWith("/memtree/")) {
|
|
264
|
+
res.writeHead(404, { "content-type": "application/json" });
|
|
265
|
+
res.end(JSON.stringify({ detail: "ccc desktop service: not found" }));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// The MCP server names the session in a header, or as `?session=` (/memtree/current).
|
|
269
|
+
const forSession = sessionId ?? (url.searchParams.get("session") || undefined);
|
|
270
|
+
const entry = forSession ? sessions.get(forSession) : undefined;
|
|
271
|
+
const port = entry ? (await entry.proxy).port : fallback.port;
|
|
272
|
+
if (gone)
|
|
273
|
+
return;
|
|
274
|
+
return forward(req, res, port, innerToken, false);
|
|
275
|
+
}
|
|
276
|
+
await new Promise((resolve, reject) => {
|
|
277
|
+
server.once("error", reject);
|
|
278
|
+
server.listen(opts.state.port, "127.0.0.1", () => resolve());
|
|
279
|
+
});
|
|
280
|
+
log(`ccc desktop service (${opts.state.mode}) listening on 127.0.0.1:${opts.state.port}`);
|
|
281
|
+
// Idle closes in progress, so shutdown waits for their final indexes too (Codex r3).
|
|
282
|
+
const idleClosing = new Set();
|
|
283
|
+
const closeIdle = async (idleMs = SESSION_IDLE_MS) => {
|
|
284
|
+
const now = Date.now();
|
|
285
|
+
const closing = [];
|
|
286
|
+
for (const [id, entry] of sessions) {
|
|
287
|
+
if (entry.inFlight > 0 || now - entry.lastUsed < idleMs)
|
|
288
|
+
continue;
|
|
289
|
+
sessions.delete(id);
|
|
290
|
+
log(`session ${id.slice(0, 8)} idle: closing (final index)`);
|
|
291
|
+
const done = closeSession(entry, 30_000).catch((err) => log(`session ${id.slice(0, 8)} close: ${String(err)}`));
|
|
292
|
+
idleClosing.add(done);
|
|
293
|
+
void done.finally(() => idleClosing.delete(done));
|
|
294
|
+
closing.push(done);
|
|
295
|
+
}
|
|
296
|
+
await Promise.all(closing);
|
|
297
|
+
};
|
|
298
|
+
const sweep = setInterval(() => void closeIdle(), SWEEP_MS);
|
|
299
|
+
sweep.unref();
|
|
300
|
+
return {
|
|
301
|
+
port: opts.state.port,
|
|
302
|
+
sessions: () => [...sessions.keys()],
|
|
303
|
+
closeIdle,
|
|
304
|
+
close: async () => {
|
|
305
|
+
clearInterval(sweep);
|
|
306
|
+
closing = true;
|
|
307
|
+
server.close();
|
|
308
|
+
tunnels.blind();
|
|
309
|
+
// Requests already being routed get a moment to reach their session proxy before the
|
|
310
|
+
// snapshot. Bounded: a long stream or long-poll is cut by the proxies' own drain
|
|
311
|
+
// deadline below, not waited for here (Codex r3).
|
|
312
|
+
await Promise.race([
|
|
313
|
+
Promise.allSettled([...pendingRoutes]),
|
|
314
|
+
new Promise((resolve) => setTimeout(resolve, 3_000).unref()),
|
|
315
|
+
]);
|
|
316
|
+
const all = [...sessions.values()];
|
|
317
|
+
sessions.clear();
|
|
318
|
+
await Promise.allSettled([
|
|
319
|
+
...all.map((e) => closeSession(e, 10_000)),
|
|
320
|
+
...idleClosing,
|
|
321
|
+
(async () => {
|
|
322
|
+
await fallback.drain(10_000);
|
|
323
|
+
await fallbackMemtree.drainBackground(FINAL_DRAIN_MS);
|
|
324
|
+
fallback.close();
|
|
325
|
+
})(),
|
|
326
|
+
]);
|
|
327
|
+
tunnels.all();
|
|
328
|
+
await reqlog.flush(2_000);
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Whether a /v1/messages body offers the memtree tools: true / false when it has a
|
|
334
|
+
* `tools` list with or without them, undefined when it has none (a side call: no change).
|
|
335
|
+
*/
|
|
336
|
+
export function toolsOffered(body) {
|
|
337
|
+
if (!body.includes('"tools"'))
|
|
338
|
+
return undefined;
|
|
339
|
+
try {
|
|
340
|
+
const tools = JSON.parse(body).tools;
|
|
341
|
+
if (!Array.isArray(tools) || tools.length === 0)
|
|
342
|
+
return undefined;
|
|
343
|
+
return tools.some((t) => typeof t?.name === "string" && t.name.startsWith(`mcp__${MEMTREE_MCP_SERVER_NAME}__`));
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function header(req, name) {
|
|
350
|
+
const v = req.headers[name];
|
|
351
|
+
const s = Array.isArray(v) ? v[0] : v;
|
|
352
|
+
return s && s.trim() ? s.trim() : undefined;
|
|
353
|
+
}
|
|
354
|
+
function tokenMatches(got, expected) {
|
|
355
|
+
if (!got)
|
|
356
|
+
return false;
|
|
357
|
+
const a = Buffer.from(got);
|
|
358
|
+
const b = Buffer.from(expected);
|
|
359
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
360
|
+
}
|
|
361
|
+
function readBody(req) {
|
|
362
|
+
return new Promise((resolve, reject) => {
|
|
363
|
+
const chunks = [];
|
|
364
|
+
req.on("data", (c) => chunks.push(c));
|
|
365
|
+
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
366
|
+
req.on("error", reject);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Plain HTTP to one of this process's inner proxies, with the inner token and, for a
|
|
371
|
+
* request decrypted from api.anthropic.com, the intercepted marker (proxy.ts
|
|
372
|
+
* acceptInnerRequest). Status, headers and body are streamed back.
|
|
373
|
+
*/
|
|
374
|
+
function forward(req, res, port, innerToken, intercepted, body) {
|
|
375
|
+
return new Promise((resolve) => {
|
|
376
|
+
const headers = { ...req.headers };
|
|
377
|
+
delete headers[PROXY_TOKEN_HEADER];
|
|
378
|
+
delete headers[INNER_INTERCEPTED_HEADER];
|
|
379
|
+
headers[INNER_TOKEN_HEADER] = innerToken;
|
|
380
|
+
if (intercepted)
|
|
381
|
+
headers[INNER_INTERCEPTED_HEADER] = "1";
|
|
382
|
+
// A loopback (MCP) call keeps the loopback-caller checks of the inner proxy.
|
|
383
|
+
else
|
|
384
|
+
headers.host = `127.0.0.1:${port}`;
|
|
385
|
+
if (body) {
|
|
386
|
+
headers["content-length"] = String(body.length);
|
|
387
|
+
delete headers["transfer-encoding"];
|
|
388
|
+
}
|
|
389
|
+
const out = http.request({
|
|
390
|
+
host: "127.0.0.1", port, method: req.method, path: req.url, headers,
|
|
391
|
+
}, (upstream) => {
|
|
392
|
+
res.writeHead(upstream.statusCode ?? 502, upstream.statusMessage, upstream.rawHeaders);
|
|
393
|
+
upstream.pipe(res);
|
|
394
|
+
upstream.on("end", resolve);
|
|
395
|
+
upstream.on("error", () => { res.destroy(); resolve(); });
|
|
396
|
+
});
|
|
397
|
+
out.on("error", () => {
|
|
398
|
+
if (res.destroyed)
|
|
399
|
+
return resolve();
|
|
400
|
+
if (!res.headersSent)
|
|
401
|
+
res.writeHead(502, { "content-type": "application/json" });
|
|
402
|
+
res.end(JSON.stringify({ type: "error", error: { type: "api_error", message: "ccc desktop service: session proxy unavailable" } }));
|
|
403
|
+
resolve();
|
|
404
|
+
});
|
|
405
|
+
res.on("close", () => { if (!res.writableFinished) {
|
|
406
|
+
out.destroy();
|
|
407
|
+
resolve();
|
|
408
|
+
} });
|
|
409
|
+
if (body)
|
|
410
|
+
out.end(body);
|
|
411
|
+
else
|
|
412
|
+
req.pipe(out);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
/** Where a WebSocket upgrade on a decrypted stream goes: api.anthropic.com, or a test's mock. */
|
|
416
|
+
function interceptUpstream(origin) {
|
|
417
|
+
const url = new URL(origin ?? `https://${INTERCEPT_HOST}`);
|
|
418
|
+
const secure = url.protocol === "https:";
|
|
419
|
+
return { host: url.hostname, port: url.port ? Number(url.port) : secure ? 443 : 80, secure };
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Why a Desktop session in `cwd` must not run through ccc: its project's (or the user's,
|
|
423
|
+
* re-read now) Claude Code settings turn on the Bash sandbox, whose proxy would forward
|
|
424
|
+
* through this service with the token and lose its private-address check, or set a proxy,
|
|
425
|
+
* NO_PROXY, CA or env file that breaks the routing (Codex r1 P1). Setup checks only what
|
|
426
|
+
* it can see; each project is checked here, on its session's first model call.
|
|
427
|
+
*/
|
|
428
|
+
export function projectRefusal(cwd, claudeConfigDir) {
|
|
429
|
+
// The service can't see which config dir a session uses: check the default one and the
|
|
430
|
+
// one setup ran with (Codex r2 P1), and refuse if either says so.
|
|
431
|
+
for (const dir of [undefined, claudeConfigDir]) {
|
|
432
|
+
const env = { [HTTPS_PROXY_MODE_ENV]: "1",
|
|
433
|
+
...(dir ? { CLAUDE_CONFIG_DIR: dir } : {}) };
|
|
434
|
+
const decision = httpsProxyModeDecision({
|
|
435
|
+
env, platform: process.platform, claudeArgs: [], cwd,
|
|
436
|
+
});
|
|
437
|
+
if (decision.mode === "base-url" && decision.requested)
|
|
438
|
+
return decision.reason;
|
|
439
|
+
}
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
/** The session's model calls get an error it shows, instead of running unprotected. */
|
|
443
|
+
function refuseSession(res, reason) {
|
|
444
|
+
const message = `ccc desktop can't serve this session: ${reason}. Start it from another ` +
|
|
445
|
+
"Desktop environment (without the ccc lines), or change that setting.";
|
|
446
|
+
res.writeHead(400, { "content-type": "application/json" });
|
|
447
|
+
res.end(JSON.stringify({ type: "error", error: { type: "invalid_request_error", message } }));
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=desktop-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-service.js","sourceRoot":"","sources":["../src/desktop-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export type DesktopMode = "production" | "staging" | "local";
|
|
2
|
+
export interface DesktopPaths {
|
|
3
|
+
dir: string;
|
|
4
|
+
/** The pasted NODE_EXTRA_CA_CERTS: the user's own extra CAs at setup, then ccc's CA. */
|
|
5
|
+
caPem: string;
|
|
6
|
+
/** ccc's CA certificate alone (public; its key was never kept). */
|
|
7
|
+
caCert: string;
|
|
8
|
+
/** The user's own extra CAs, for the service's own upstream TLS (only when there are some). */
|
|
9
|
+
upstreamCa: string;
|
|
10
|
+
leafPem: string;
|
|
11
|
+
leafKey: string;
|
|
12
|
+
state: string;
|
|
13
|
+
bashEnv: string;
|
|
14
|
+
log: string;
|
|
15
|
+
plist: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DesktopState {
|
|
18
|
+
mode: DesktopMode;
|
|
19
|
+
port: number;
|
|
20
|
+
token: string;
|
|
21
|
+
/** ISO times: the CA (and leaf) validity, for the rotation notice. */
|
|
22
|
+
createdAt: string;
|
|
23
|
+
notAfter: string;
|
|
24
|
+
/** Setup registered the memtree MCP server, so compress calls may say the tools exist. */
|
|
25
|
+
mcpRegistered?: boolean;
|
|
26
|
+
/** CLAUDE_CONFIG_DIR when setup ran, if any: its settings are checked for each session too. */
|
|
27
|
+
claudeConfigDir?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function desktopPaths(configDir: string, mode: DesktopMode): DesktopPaths;
|
|
30
|
+
export declare function desktopLaunchdLabel(mode: DesktopMode): string;
|
|
31
|
+
/** The lines to paste into Desktop's environment editor (one KEY=value per line). */
|
|
32
|
+
export declare function desktopEnvLines(paths: DesktopPaths, state: DesktopState): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Bash-tool commands get the session's env minus ccc's proxy and CA (else curl, Python
|
|
35
|
+
* and others would fail TLS to api.anthropic.com), each only while it still holds ccc's
|
|
36
|
+
* value (Claude Code's sandbox sets its own first; the token is matched by pattern, never
|
|
37
|
+
* written). Programs started from Bash (a nested `claude -p`, an SDK script) aren't routed
|
|
38
|
+
* through ccc, so they get Claude Code's own compaction back.
|
|
39
|
+
*/
|
|
40
|
+
export declare function desktopBashEnvScript(paths: DesktopPaths, state: DesktopState, userEnv?: DesktopUserEnv): string;
|
|
41
|
+
/** The shell values setup saw that the pasted lines replace for the session. */
|
|
42
|
+
export interface DesktopUserEnv {
|
|
43
|
+
NODE_EXTRA_CA_CERTS?: string;
|
|
44
|
+
CLAUDE_ENV_FILE?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function readDesktopState(paths: DesktopPaths): DesktopState | undefined;
|
|
47
|
+
/** Setup rotates the CA when it expires within this. */
|
|
48
|
+
export declare const CA_ROTATE_BEFORE_MS: number;
|
|
49
|
+
/**
|
|
50
|
+
* Make the CA and leaf, the token, the port and the Bash env file. A re-run keeps
|
|
51
|
+
* the port and token (the pasted lines stay valid) unless `rotateToken`, and keeps
|
|
52
|
+
* the CA (live sessions trust only the one they started with) unless `rotateCa`,
|
|
53
|
+
* it is missing or unreadable, or it expires within CA_ROTATE_BEFORE_MS.
|
|
54
|
+
*/
|
|
55
|
+
export declare function setupDesktopFiles(paths: DesktopPaths, mode: DesktopMode, opts?: {
|
|
56
|
+
rotateToken?: boolean;
|
|
57
|
+
rotateCa?: boolean;
|
|
58
|
+
userExtraCaPem?: string;
|
|
59
|
+
userEnv?: DesktopUserEnv;
|
|
60
|
+
claudeConfigDir?: string;
|
|
61
|
+
}): Promise<DesktopState & {
|
|
62
|
+
caRotated: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
export declare function writeDesktopState(paths: DesktopPaths, state: DesktopState): void;
|
|
65
|
+
/** The launchd agent: `node <cli.js> [staging|local] desktop serve`, kept alive. */
|
|
66
|
+
export declare function launchdPlist(mode: DesktopMode, paths: DesktopPaths, cliPath: string): string;
|
|
67
|
+
export declare function installLaunchAgent(mode: DesktopMode, paths: DesktopPaths, cliPath: string): void;
|
|
68
|
+
export declare function uninstallLaunchAgent(mode: DesktopMode, paths: DesktopPaths): void;
|
|
69
|
+
/**
|
|
70
|
+
* The `memtree` MCP server for every Claude Code on this account (Desktop
|
|
71
|
+
* re-delivers ~/.claude.json's stdio servers to its sessions). It is inert
|
|
72
|
+
* (no tools) unless the session's HTTPS_PROXY is a ccc proxy or it runs
|
|
73
|
+
* under terminal ccc (memtree-mcp.ts desktopMcpTarget). Registered through
|
|
74
|
+
* `claude mcp add-json --scope user`, never by editing ~/.claude.json directly.
|
|
75
|
+
*/
|
|
76
|
+
export declare function desktopMcpServerJson(): string;
|
|
77
|
+
/** The file `claude mcp --scope user` edits: `$CLAUDE_CONFIG_DIR/.claude.json`, else `~/.claude.json`. */
|
|
78
|
+
export declare function userClaudeJsonPath(env?: NodeJS.ProcessEnv): string;
|
|
79
|
+
/**
|
|
80
|
+
* Who owns the user-scope `memtree` entry (read only; never written here). A file that
|
|
81
|
+
* exists but can't be read or parsed is "other": ccc then touches nothing.
|
|
82
|
+
*/
|
|
83
|
+
export declare function userMcpOwner(claudeJsonPath?: string): "none" | "ccc-desktop" | "other";
|
|
84
|
+
/**
|
|
85
|
+
* Register (or refresh) ccc's entry. Someone else's `memtree` entry is left alone
|
|
86
|
+
* (false, with the reason): the user decides.
|
|
87
|
+
*/
|
|
88
|
+
export declare function registerDesktopMcp(claudeCommand: string, env?: NodeJS.ProcessEnv): {
|
|
89
|
+
ok: boolean;
|
|
90
|
+
reason?: string;
|
|
91
|
+
};
|
|
92
|
+
/** Remove ccc's entry only, and only when no other ccc desktop mode still uses it. */
|
|
93
|
+
export declare function unregisterDesktopMcp(claudeCommand: string, otherModesInstalled: boolean, env?: NodeJS.ProcessEnv): void;
|
|
94
|
+
//# sourceMappingURL=desktop-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-setup.d.ts","sourceRoot":"","sources":["../src/desktop-setup.ts"],"names":[],"mappings":"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"}
|