claude-code-infinite 1.0.36 → 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.
Files changed (69) hide show
  1. package/README.md +100 -1
  2. package/dist/cc-request.d.ts +15 -0
  3. package/dist/cc-request.d.ts.map +1 -1
  4. package/dist/cc-request.js +30 -0
  5. package/dist/cc-request.js.map +1 -1
  6. package/dist/claude-env.d.ts +24 -1
  7. package/dist/claude-env.d.ts.map +1 -1
  8. package/dist/claude-env.js +48 -7
  9. package/dist/claude-env.js.map +1 -1
  10. package/dist/cli-args.d.ts +1 -1
  11. package/dist/cli-args.d.ts.map +1 -1
  12. package/dist/cli-args.js +1 -1
  13. package/dist/cli-args.js.map +1 -1
  14. package/dist/cli-main.js +99 -8
  15. package/dist/cli-main.js.map +1 -1
  16. package/dist/config.d.ts +5 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js.map +1 -1
  19. package/dist/desktop-command.d.ts +38 -0
  20. package/dist/desktop-command.d.ts.map +1 -0
  21. package/dist/desktop-command.js +324 -0
  22. package/dist/desktop-command.js.map +1 -0
  23. package/dist/desktop-service.d.ts +41 -0
  24. package/dist/desktop-service.d.ts.map +1 -0
  25. package/dist/desktop-service.js +449 -0
  26. package/dist/desktop-service.js.map +1 -0
  27. package/dist/desktop-setup.d.ts +94 -0
  28. package/dist/desktop-setup.d.ts.map +1 -0
  29. package/dist/desktop-setup.js +288 -0
  30. package/dist/desktop-setup.js.map +1 -0
  31. package/dist/https-proxy-eligibility.d.ts +31 -0
  32. package/dist/https-proxy-eligibility.d.ts.map +1 -0
  33. package/dist/https-proxy-eligibility.js +204 -0
  34. package/dist/https-proxy-eligibility.js.map +1 -0
  35. package/dist/https-proxy-mode.d.ts +59 -0
  36. package/dist/https-proxy-mode.d.ts.map +1 -0
  37. package/dist/https-proxy-mode.js +255 -0
  38. package/dist/https-proxy-mode.js.map +1 -0
  39. package/dist/https-proxy-session.d.ts +64 -0
  40. package/dist/https-proxy-session.d.ts.map +1 -0
  41. package/dist/https-proxy-session.js +165 -0
  42. package/dist/https-proxy-session.js.map +1 -0
  43. package/dist/memtree-mcp.d.ts +32 -1
  44. package/dist/memtree-mcp.d.ts.map +1 -1
  45. package/dist/memtree-mcp.js +73 -7
  46. package/dist/memtree-mcp.js.map +1 -1
  47. package/dist/memtree.d.ts +10 -0
  48. package/dist/memtree.d.ts.map +1 -1
  49. package/dist/memtree.js +59 -12
  50. package/dist/memtree.js.map +1 -1
  51. package/dist/message-refs.d.ts +81 -0
  52. package/dist/message-refs.d.ts.map +1 -0
  53. package/dist/message-refs.js +378 -0
  54. package/dist/message-refs.js.map +1 -0
  55. package/dist/mitm-ca.d.ts +31 -0
  56. package/dist/mitm-ca.d.ts.map +1 -0
  57. package/dist/mitm-ca.js +236 -0
  58. package/dist/mitm-ca.js.map +1 -0
  59. package/dist/paused-session.d.ts.map +1 -1
  60. package/dist/paused-session.js +9 -2
  61. package/dist/paused-session.js.map +1 -1
  62. package/dist/proxy.d.ts +20 -0
  63. package/dist/proxy.d.ts.map +1 -1
  64. package/dist/proxy.js +101 -16
  65. package/dist/proxy.js.map +1 -1
  66. package/dist/reqlog.d.ts +7 -1
  67. package/dist/reqlog.d.ts.map +1 -1
  68. package/dist/reqlog.js.map +1 -1
  69. package/package.json +1 -1
@@ -0,0 +1,288 @@
1
+ /**
2
+ * `ccc desktop setup`'s files and registrations (desktop-command.ts): the service's state,
3
+ * its certificate (mitm-ca.ts: a CA name-constrained to api.anthropic.com whose key is
4
+ * dropped at once; only the leaf key is kept, 0600), the Bash env file, the launchd agent
5
+ * and the user-scope `memtree` MCP server. The service itself is desktop-service.ts.
6
+ */
7
+ import http from "node:http";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import fs from "node:fs";
11
+ import { spawnSync } from "node:child_process";
12
+ import { randomBytes } from "node:crypto";
13
+ import { createSessionCa } from "./mitm-ca.js";
14
+ import { MESSAGE_THREADS_OFF, UNREACHABLE_BLOCKING_LIMIT } from "./claude-env.js";
15
+ import { MEMTREE_MCP_SCRIPT } from "./memtree-mcp-config.js";
16
+ import { MEMTREE_MCP_SERVER_NAME } from "./memtree-mcp.js";
17
+ import { proxyUrlFor } from "./https-proxy-mode.js";
18
+ import { cccProxyRestoreLines, ifStill, shellQuote } from "./https-proxy-session.js";
19
+ const LAUNCHD_LABEL = "co.polychat.ccc-desktop";
20
+ export function desktopPaths(configDir, mode) {
21
+ const dir = path.join(configDir, mode === "production" ? "desktop" : `desktop-${mode}`);
22
+ const label = mode === "production" ? LAUNCHD_LABEL : `${LAUNCHD_LABEL}-${mode}`;
23
+ return {
24
+ dir,
25
+ caPem: path.join(dir, "ca.pem"),
26
+ caCert: path.join(dir, "ccc-ca.pem"),
27
+ upstreamCa: path.join(dir, "upstream-ca.pem"),
28
+ leafPem: path.join(dir, "leaf.pem"),
29
+ leafKey: path.join(dir, "leaf-key.pem"),
30
+ state: path.join(dir, "service.json"),
31
+ bashEnv: path.join(dir, "bash-env.sh"),
32
+ log: path.join(dir, "service.log"),
33
+ plist: path.join(os.homedir(), "Library", "LaunchAgents", `${label}.plist`),
34
+ };
35
+ }
36
+ export function desktopLaunchdLabel(mode) {
37
+ return mode === "production" ? LAUNCHD_LABEL : `${LAUNCHD_LABEL}-${mode}`;
38
+ }
39
+ /** The lines to paste into Desktop's environment editor (one KEY=value per line). */
40
+ export function desktopEnvLines(paths, state) {
41
+ return [
42
+ `HTTPS_PROXY=${proxyUrlFor(state.port, state.token)}`,
43
+ `NODE_EXTRA_CA_CERTS=${paths.caPem}`,
44
+ ...Object.entries(PASTED_LIMITS).map(([name, value]) => `${name}=${value}`),
45
+ `CLAUDE_ENV_FILE=${paths.bashEnv}`,
46
+ ];
47
+ }
48
+ /** What terminal ccc sets for MemTree (claude-env.ts), pasted for Desktop sessions. */
49
+ const PASTED_LIMITS = {
50
+ DISABLE_AUTO_COMPACT: "1",
51
+ CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE: UNREACHABLE_BLOCKING_LIMIT,
52
+ CLAUDE_CODE_RESUME_TOKEN_THRESHOLD: "1000000000",
53
+ ...MESSAGE_THREADS_OFF,
54
+ };
55
+ /**
56
+ * Bash-tool commands get the session's env minus ccc's proxy and CA (else curl, Python
57
+ * and others would fail TLS to api.anthropic.com), each only while it still holds ccc's
58
+ * value (Claude Code's sandbox sets its own first; the token is matched by pattern, never
59
+ * written). Programs started from Bash (a nested `claude -p`, an SDK script) aren't routed
60
+ * through ccc, so they get Claude Code's own compaction back.
61
+ */
62
+ export function desktopBashEnvScript(paths, state, userEnv = {}) {
63
+ const userFile = userEnv.CLAUDE_ENV_FILE;
64
+ return [
65
+ "# ccc desktop: written by `ccc desktop setup`; sourced by Claude Code before each Bash command.",
66
+ // The user's own CA file (seen at setup) comes back for Bash; ccc's bundle goes.
67
+ ...cccProxyRestoreLines(state.port, paths.caPem, userEnv.NODE_EXTRA_CA_CERTS ? { NODE_EXTRA_CA_CERTS: userEnv.NODE_EXTRA_CA_CERTS } : {}),
68
+ ...Object.entries(PASTED_LIMITS).map(([name, value]) => ifStill(name, value, `unset ${name}`)),
69
+ userFile ? `export CLAUDE_ENV_FILE=${shellQuote(userFile)}` : "unset CLAUDE_ENV_FILE",
70
+ // An env file of the user's own, which the pasted line replaced, still runs (as in
71
+ // terminal proxy mode).
72
+ ...(userFile ? [`if [ -r ${shellQuote(userFile)} ]; then . ${shellQuote(userFile)}; fi`] : []),
73
+ "true",
74
+ "",
75
+ ].join("\n");
76
+ }
77
+ function freePort() {
78
+ return new Promise((resolve, reject) => {
79
+ const s = http.createServer();
80
+ s.once("error", reject);
81
+ s.listen(0, "127.0.0.1", () => {
82
+ const port = s.address().port;
83
+ s.close(() => resolve(port));
84
+ });
85
+ });
86
+ }
87
+ export function readDesktopState(paths) {
88
+ try {
89
+ return JSON.parse(fs.readFileSync(paths.state, "utf8"));
90
+ }
91
+ catch {
92
+ return undefined;
93
+ }
94
+ }
95
+ /** Setup rotates the CA when it expires within this. */
96
+ export const CA_ROTATE_BEFORE_MS = 30 * 24 * 3600_000;
97
+ /**
98
+ * Make the CA and leaf, the token, the port and the Bash env file. A re-run keeps
99
+ * the port and token (the pasted lines stay valid) unless `rotateToken`, and keeps
100
+ * the CA (live sessions trust only the one they started with) unless `rotateCa`,
101
+ * it is missing or unreadable, or it expires within CA_ROTATE_BEFORE_MS.
102
+ */
103
+ export async function setupDesktopFiles(paths, mode, opts = {}) {
104
+ fs.mkdirSync(paths.dir, { recursive: true, mode: 0o700 });
105
+ fs.chmodSync(paths.dir, 0o700);
106
+ const previous = readDesktopState(paths);
107
+ const now = Date.now();
108
+ const write = (file, text, mode) => {
109
+ const tmp = `${file}.${process.pid}.tmp`;
110
+ fs.writeFileSync(tmp, text, { mode });
111
+ fs.renameSync(tmp, file);
112
+ };
113
+ const caUsable = previous !== undefined && Date.parse(previous.notAfter) - now > CA_ROTATE_BEFORE_MS &&
114
+ [paths.caCert, paths.leafPem, paths.leafKey].every((f) => fs.existsSync(f));
115
+ const caRotated = opts.rotateCa === true || !caUsable;
116
+ if (caRotated) {
117
+ // The CA's key never leaves createSessionCa: it signs this one leaf and is dropped.
118
+ const ca = createSessionCa();
119
+ write(paths.leafKey, ca.leafKeyPem, 0o600);
120
+ write(paths.leafPem, ca.leafCertPem, 0o600);
121
+ write(paths.caCert, ca.caCertPem, 0o644);
122
+ }
123
+ // The pasted NODE_EXTRA_CA_CERTS replaces any the session would have had (a corporate
124
+ // CA from the login shell): keep those first, as terminal proxy mode does.
125
+ const extra = opts.userExtraCaPem?.trim() ?? "";
126
+ const parts = [extra, fs.readFileSync(paths.caCert, "utf8").trim()];
127
+ write(paths.caPem, `${parts.filter(Boolean).join("\n")}\n`, 0o644);
128
+ // The service's own connections to Anthropic need those roots too (launchd gives it
129
+ // none of the shell's env): the plist names this file when it exists (Codex r1 P2).
130
+ if (extra)
131
+ write(paths.upstreamCa, `${extra}\n`, 0o644);
132
+ else
133
+ fs.rmSync(paths.upstreamCa, { force: true });
134
+ const state = {
135
+ mode,
136
+ port: previous?.port ?? await pickServicePort(),
137
+ token: !opts.rotateToken && previous?.token ? previous.token : randomBytes(24).toString("hex"),
138
+ createdAt: caRotated || !previous ? new Date(now).toISOString() : previous.createdAt,
139
+ notAfter: caRotated || !previous ? new Date(now + 365 * 24 * 3600_000).toISOString() : previous.notAfter,
140
+ ...(previous?.mcpRegistered ? { mcpRegistered: true } : {}),
141
+ ...(opts.claudeConfigDir ? { claudeConfigDir: opts.claudeConfigDir } : {}),
142
+ };
143
+ write(paths.state, `${JSON.stringify(state, null, 2)}\n`, 0o600);
144
+ write(paths.bashEnv, desktopBashEnvScript(paths, state, opts.userEnv), 0o600);
145
+ return { ...state, caRotated };
146
+ }
147
+ export function writeDesktopState(paths, state) {
148
+ const { mode, port, token, createdAt, notAfter, mcpRegistered, claudeConfigDir } = state;
149
+ const tmp = `${paths.state}.${process.pid}.tmp`;
150
+ const kept = { mode, port, token, createdAt, notAfter, mcpRegistered, claudeConfigDir };
151
+ fs.writeFileSync(tmp, `${JSON.stringify(kept, null, 2)}\n`, { mode: 0o600 });
152
+ fs.renameSync(tmp, paths.state);
153
+ }
154
+ /**
155
+ * A fixed port for the pasted lines: below the macOS ephemeral range (49152+), so an
156
+ * outgoing connection can't hold it when the service restarts. Free when chosen.
157
+ */
158
+ async function pickServicePort() {
159
+ for (let i = 0; i < 50; i++) {
160
+ const port = 41000 + Math.floor(Math.random() * 7000);
161
+ if (await portFree(port))
162
+ return port;
163
+ }
164
+ return freePort();
165
+ }
166
+ function portFree(port) {
167
+ return new Promise((resolve) => {
168
+ const s = http.createServer();
169
+ s.once("error", () => resolve(false));
170
+ s.listen(port, "127.0.0.1", () => s.close(() => resolve(true)));
171
+ });
172
+ }
173
+ /** The launchd agent: `node <cli.js> [staging|local] desktop serve`, kept alive. */
174
+ export function launchdPlist(mode, paths, cliPath) {
175
+ const args = [process.execPath, cliPath, ...(mode === "production" ? [] : [mode]), "desktop", "serve"];
176
+ // Transcripts (usage, the final reply) are read where setup's Claude Code keeps them.
177
+ const configDir = readDesktopState(paths)?.claudeConfigDir;
178
+ const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
179
+ return `<?xml version="1.0" encoding="UTF-8"?>
180
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
181
+ <plist version="1.0">
182
+ <dict>
183
+ <key>Label</key><string>${desktopLaunchdLabel(mode)}</string>
184
+ <key>ProgramArguments</key>
185
+ <array>
186
+ ${args.map((a) => ` <string>${esc(a)}</string>`).join("\n")}
187
+ </array>
188
+ <key>EnvironmentVariables</key>
189
+ <dict>
190
+ <key>PATH</key><string>${esc(`${path.dirname(process.execPath)}:/usr/bin:/bin:/usr/sbin:/sbin`)}</string>${fs.existsSync(paths.upstreamCa)
191
+ ? `\n <key>NODE_EXTRA_CA_CERTS</key><string>${esc(paths.upstreamCa)}</string>` : ""}${configDir ? `\n <key>CLAUDE_CONFIG_DIR</key><string>${esc(configDir)}</string>` : ""}
192
+ </dict>
193
+ <key>RunAtLoad</key><true/>
194
+ <key>ExitTimeOut</key><integer>45</integer>
195
+ <key>KeepAlive</key><true/>
196
+ <key>ProcessType</key><string>Background</string>
197
+ <key>StandardOutPath</key><string>${esc(paths.log)}</string>
198
+ <key>StandardErrorPath</key><string>${esc(paths.log)}</string>
199
+ </dict>
200
+ </plist>
201
+ `;
202
+ }
203
+ export function installLaunchAgent(mode, paths, cliPath) {
204
+ fs.mkdirSync(path.dirname(paths.plist), { recursive: true });
205
+ fs.writeFileSync(paths.plist, launchdPlist(mode, paths, cliPath), { mode: 0o644 });
206
+ const domain = `gui/${process.getuid?.() ?? 501}`;
207
+ spawnSync("launchctl", ["bootout", `${domain}/${desktopLaunchdLabel(mode)}`], { stdio: "ignore" });
208
+ // bootout returns before the job is fully gone (it may take its ExitTimeOut to final-index);
209
+ // wait for it to leave, then bootstrap, retrying the transient 5/37 errors.
210
+ for (let i = 0; i < 200 && spawnSync("launchctl", ["print", `${domain}/${desktopLaunchdLabel(mode)}`], { stdio: "ignore" }).status === 0; i++) {
211
+ spawnSync("sleep", ["0.25"]);
212
+ }
213
+ let last = "";
214
+ for (let attempt = 0; attempt < 40; attempt++) {
215
+ const r = spawnSync("launchctl", ["bootstrap", domain, paths.plist], { encoding: "utf8" });
216
+ if (r.status === 0)
217
+ return;
218
+ last = `${r.status}: ${(r.stderr || "").trim()}`;
219
+ spawnSync("sleep", ["0.25"]);
220
+ }
221
+ throw new Error(`launchctl bootstrap failed (${last})`);
222
+ }
223
+ export function uninstallLaunchAgent(mode, paths) {
224
+ const domain = `gui/${process.getuid?.() ?? 501}`;
225
+ spawnSync("launchctl", ["bootout", `${domain}/${desktopLaunchdLabel(mode)}`], { stdio: "ignore" });
226
+ fs.rmSync(paths.plist, { force: true });
227
+ }
228
+ /**
229
+ * The `memtree` MCP server for every Claude Code on this account (Desktop
230
+ * re-delivers ~/.claude.json's stdio servers to its sessions). It is inert
231
+ * (no tools) unless the session's HTTPS_PROXY is a ccc proxy or it runs
232
+ * under terminal ccc (memtree-mcp.ts desktopMcpTarget). Registered through
233
+ * `claude mcp add-json --scope user`, never by editing ~/.claude.json directly.
234
+ */
235
+ export function desktopMcpServerJson() {
236
+ return JSON.stringify({
237
+ type: "stdio",
238
+ command: process.execPath,
239
+ args: [MEMTREE_MCP_SCRIPT],
240
+ env: { CCC_MEMTREE_MCP_DESKTOP: "1" },
241
+ alwaysLoad: true,
242
+ });
243
+ }
244
+ /** The file `claude mcp --scope user` edits: `$CLAUDE_CONFIG_DIR/.claude.json`, else `~/.claude.json`. */
245
+ export function userClaudeJsonPath(env = process.env) {
246
+ return env.CLAUDE_CONFIG_DIR ? path.join(env.CLAUDE_CONFIG_DIR, ".claude.json") : path.join(os.homedir(), ".claude.json");
247
+ }
248
+ /**
249
+ * Who owns the user-scope `memtree` entry (read only; never written here). A file that
250
+ * exists but can't be read or parsed is "other": ccc then touches nothing.
251
+ */
252
+ export function userMcpOwner(claudeJsonPath = userClaudeJsonPath()) {
253
+ let config;
254
+ try {
255
+ config = JSON.parse(fs.readFileSync(claudeJsonPath, "utf8"));
256
+ }
257
+ catch (err) {
258
+ return err?.code === "ENOENT" ? "none" : "other";
259
+ }
260
+ const entry = config.mcpServers?.[MEMTREE_MCP_SERVER_NAME];
261
+ if (!entry)
262
+ return "none";
263
+ return entry.env?.CCC_MEMTREE_MCP_DESKTOP === "1" ? "ccc-desktop" : "other";
264
+ }
265
+ /**
266
+ * Register (or refresh) ccc's entry. Someone else's `memtree` entry is left alone
267
+ * (false, with the reason): the user decides.
268
+ */
269
+ export function registerDesktopMcp(claudeCommand, env = process.env) {
270
+ const owner = userMcpOwner(userClaudeJsonPath(env));
271
+ if (owner === "other") {
272
+ return { ok: false, reason: "a user-scope MCP server named `memtree` that ccc didn't add already exists" };
273
+ }
274
+ if (owner === "ccc-desktop") {
275
+ spawnSync(claudeCommand, ["mcp", "remove", "--scope", "user", MEMTREE_MCP_SERVER_NAME], { stdio: "ignore", env });
276
+ }
277
+ const r = spawnSync(claudeCommand, [
278
+ "mcp", "add-json", "--scope", "user", MEMTREE_MCP_SERVER_NAME, desktopMcpServerJson(),
279
+ ], { stdio: "inherit", env });
280
+ return r.status === 0 ? { ok: true } : { ok: false, reason: `\`claude mcp add-json\` exited ${r.status}` };
281
+ }
282
+ /** Remove ccc's entry only, and only when no other ccc desktop mode still uses it. */
283
+ export function unregisterDesktopMcp(claudeCommand, otherModesInstalled, env = process.env) {
284
+ if (otherModesInstalled || userMcpOwner(userClaudeJsonPath(env)) !== "ccc-desktop")
285
+ return;
286
+ spawnSync(claudeCommand, ["mcp", "remove", "--scope", "user", MEMTREE_MCP_SERVER_NAME], { stdio: "ignore", env });
287
+ }
288
+ //# sourceMappingURL=desktop-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-setup.js","sourceRoot":"","sources":["../src/desktop-setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export declare const HTTPS_PROXY_MODE_ENV = "CCC_HTTPS_PROXY_MODE";
2
+ export type HttpsProxyModeDecision = {
3
+ mode: "https-proxy";
4
+ } | {
5
+ mode: "base-url";
6
+ requested: false;
7
+ } | {
8
+ mode: "base-url";
9
+ requested: true;
10
+ reason: string;
11
+ };
12
+ export interface EligibilityInput {
13
+ env: NodeJS.ProcessEnv;
14
+ /** The `httpsProxyMode` config key. */
15
+ configured?: boolean;
16
+ platform: NodeJS.Platform;
17
+ /** Claude Code's arguments (a `--settings` file or JSON is read too). */
18
+ claudeArgs: readonly string[];
19
+ cwd: string;
20
+ homedir?: string;
21
+ readFile?: (file: string) => string | null;
22
+ listDir?: (dir: string) => string[];
23
+ }
24
+ export declare function httpsProxyModeDecision(input: EligibilityInput): HttpsProxyModeDecision;
25
+ /** `CCC_HTTPS_PROXY_MODE` wins (1/true/yes/on or 0/false/no/off), else the config key. */
26
+ export declare function httpsProxyModeRequested(env: NodeJS.ProcessEnv, configured?: boolean): boolean;
27
+ /** The one-line notice for a requested mode that was skipped. */
28
+ export declare function skippedNoticeText(reason: string): string;
29
+ /** Every `--settings <value>` / `--settings=<value>` before a `--`. */
30
+ export declare function settingsArgs(args: readonly string[]): string[];
31
+ //# sourceMappingURL=https-proxy-eligibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"https-proxy-eligibility.d.ts","sourceRoot":"","sources":["../src/https-proxy-eligibility.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAe3D,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,KAAK,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,uCAAuC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,yEAAyE;IACzE,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CACrC;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,sBAAsB,CAQtF;AAED,0FAA0F;AAC1F,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAK7F;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAqGD,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAS9D"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Whether this session runs in HTTPS-proxy mode (https-proxy-mode.ts) or in today's
3
+ * base-URL mode. Opt-in: `CCC_HTTPS_PROXY_MODE=1` (or `=0` to force it off), else the
4
+ * `httpsProxyMode` config key. Even when asked for, it is skipped, with one line saying
5
+ * why, wherever it can't work yet (plans/2026-11-08_PLAN_https_proxy_remote_control.md,
6
+ * section 5):
7
+ *
8
+ * - Windows: Claude Code's PowerShell tool doesn't apply the Bash env file.
9
+ * - A proxy in ccc's own environment: blind tunnels and ccc's upstream would bypass it.
10
+ * - Claude Code settings (user, project, local, managed, or a `--settings` argument)
11
+ * whose `env` sets a proxy, NO_PROXY or NODE_EXTRA_CA_CERTS: settings env overrides
12
+ * the process env, so model calls would skip MemTree silently or fail TLS.
13
+ * - Claude Code's Bash sandbox enabled in any of those settings: its proxy forwards
14
+ * through Claude Code's HTTPS_PROXY (with the token), so sandboxed calls to
15
+ * api.anthropic.com would hit the interception and fail, and the sandbox's
16
+ * private-address check would not apply.
17
+ *
18
+ * These are read once, at startup: enabling the sandbox or a settings proxy mid-session
19
+ * isn't seen here (https-proxy-session.ts warns when prompts then get no model call).
20
+ */
21
+ import { execFileSync } from "node:child_process";
22
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
23
+ import os from "node:os";
24
+ import path from "node:path";
25
+ export const HTTPS_PROXY_MODE_ENV = "CCC_HTTPS_PROXY_MODE";
26
+ /** A proxy in any of these (either case) means the user already routes through one. */
27
+ const PROXY_VARS = [
28
+ "HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy",
29
+ ];
30
+ /**
31
+ * Settings `env` keys that would override what proxy mode gives Claude Code. A settings
32
+ * CLAUDE_ENV_FILE would replace the Bash env file, so Bash commands would keep the token
33
+ * proxy and the session CA.
34
+ */
35
+ const SETTINGS_ENV_BLOCKERS = [
36
+ ...PROXY_VARS, "NO_PROXY", "no_proxy", "NODE_EXTRA_CA_CERTS", "CLAUDE_ENV_FILE",
37
+ ];
38
+ export function httpsProxyModeDecision(input) {
39
+ if (!httpsProxyModeRequested(input.env, input.configured)) {
40
+ return { mode: "base-url", requested: false };
41
+ }
42
+ const reason = blockingReason(input);
43
+ return reason === undefined
44
+ ? { mode: "https-proxy" }
45
+ : { mode: "base-url", requested: true, reason };
46
+ }
47
+ /** `CCC_HTTPS_PROXY_MODE` wins (1/true/yes/on or 0/false/no/off), else the config key. */
48
+ export function httpsProxyModeRequested(env, configured) {
49
+ const value = env[HTTPS_PROXY_MODE_ENV]?.trim().toLowerCase();
50
+ if (value && ["1", "true", "yes", "on"].includes(value))
51
+ return true;
52
+ if (value && ["0", "false", "no", "off"].includes(value))
53
+ return false;
54
+ return configured === true;
55
+ }
56
+ /** The one-line notice for a requested mode that was skipped. */
57
+ export function skippedNoticeText(reason) {
58
+ return `ccc: HTTPS-proxy mode (Remote Control) is off for this session: ${reason}. ` +
59
+ "Using the base-URL mode.";
60
+ }
61
+ function blockingReason(input) {
62
+ if (input.platform === "win32")
63
+ return "Windows isn't supported yet";
64
+ const own = PROXY_VARS.find((name) => nonEmpty(input.env[name]));
65
+ if (own)
66
+ return `${own} is already set (ccc can't chain to your proxy yet)`;
67
+ const readFile = input.readFile ?? readTextFile;
68
+ for (const source of settingsSources(input, readFile)) {
69
+ const reason = settingsBlocker(source.settings);
70
+ if (reason)
71
+ return `${reason} in ${source.name}`;
72
+ }
73
+ return undefined;
74
+ }
75
+ function settingsBlocker(settings) {
76
+ if (!isRecord(settings))
77
+ return undefined;
78
+ const sandbox = settings.sandbox;
79
+ if (isRecord(sandbox) && sandbox.enabled === true)
80
+ return "Claude Code's Bash sandbox is on";
81
+ const env = settings.env;
82
+ if (!isRecord(env))
83
+ return undefined;
84
+ // Present at all, even empty: a settings value replaces the process env's (an empty
85
+ // HTTPS_PROXY would send Claude Code straight to api.anthropic.com, past MemTree).
86
+ const key = SETTINGS_ENV_BLOCKERS.find((name) => Object.hasOwn(env, name));
87
+ return key ? `${key} is set` : undefined;
88
+ }
89
+ /** Every settings scope Claude Code may load for this session, parsed; unreadable ones skipped. */
90
+ function settingsSources(input, readFile) {
91
+ const files = [
92
+ ...userSettingsFiles(input.env, input.homedir),
93
+ ...projectSettingsFiles(input.cwd),
94
+ ...managedSettingsFiles(input.platform, input.listDir ?? listJsonFiles),
95
+ ];
96
+ const out = [];
97
+ for (const file of files) {
98
+ const settings = parseJson(readFile(file));
99
+ if (settings !== undefined)
100
+ out.push({ name: file, settings });
101
+ }
102
+ for (const value of settingsArgs(input.claudeArgs)) {
103
+ const inline = value.trim().startsWith("{");
104
+ const settings = parseJson(inline ? value : readFile(path.resolve(input.cwd, value)));
105
+ if (settings !== undefined)
106
+ out.push({ name: "--settings", settings });
107
+ }
108
+ return out;
109
+ }
110
+ function userSettingsFiles(env, homedir) {
111
+ const dir = nonEmpty(env.CLAUDE_CONFIG_DIR)
112
+ ? env.CLAUDE_CONFIG_DIR
113
+ : path.join(homedir ?? os.homedir(), ".claude");
114
+ return [path.join(dir, "settings.json"), path.join(dir, "settings.local.json")];
115
+ }
116
+ /** `.claude/settings{,.local}.json` from the cwd up to its git root (or the filesystem root). */
117
+ function projectSettingsFiles(cwd) {
118
+ const files = [];
119
+ let dir = path.resolve(cwd);
120
+ for (;;) {
121
+ files.push(path.join(dir, ".claude", "settings.json"), path.join(dir, ".claude", "settings.local.json"));
122
+ const parent = path.dirname(dir);
123
+ if (parent === dir || existsSync(path.join(dir, ".git")))
124
+ return files;
125
+ dir = parent;
126
+ }
127
+ }
128
+ function managedSettingsFiles(platform, listDir) {
129
+ const dir = platform === "darwin"
130
+ ? "/Library/Application Support/ClaudeCode"
131
+ : "/etc/claude-code";
132
+ const dropIns = path.join(dir, "managed-settings.d");
133
+ return [
134
+ path.join(dir, "managed-settings.json"),
135
+ ...listDir(dropIns).map((name) => path.join(dropIns, name)),
136
+ // macOS MDM profiles (managed preferences), machine-wide or for this user.
137
+ ...(platform === "darwin" ? [
138
+ `/Library/Managed Preferences/${MDM_DOMAIN}.plist`,
139
+ `/Library/Managed Preferences/${userName()}/${MDM_DOMAIN}.plist`,
140
+ ] : []),
141
+ ];
142
+ }
143
+ const MDM_DOMAIN = "com.anthropic.claudecode";
144
+ function userName() {
145
+ try {
146
+ return os.userInfo().username;
147
+ }
148
+ catch {
149
+ return process.env.USER ?? "";
150
+ }
151
+ }
152
+ /** Every `--settings <value>` / `--settings=<value>` before a `--`. */
153
+ export function settingsArgs(args) {
154
+ const out = [];
155
+ for (let i = 0; i < args.length; i++) {
156
+ const arg = args[i];
157
+ if (arg === "--")
158
+ break;
159
+ if (arg === "--settings" && i + 1 < args.length)
160
+ out.push(args[++i]);
161
+ else if (arg.startsWith("--settings="))
162
+ out.push(arg.slice("--settings=".length));
163
+ }
164
+ return out;
165
+ }
166
+ function listJsonFiles(dir) {
167
+ try {
168
+ return readdirSync(dir).filter((name) => name.endsWith(".json")).sort();
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ }
174
+ /** A settings file's text; a property list (MDM) as JSON through plutil. */
175
+ function readTextFile(file) {
176
+ try {
177
+ if (!file.endsWith(".plist"))
178
+ return readFileSync(file, "utf8");
179
+ if (!existsSync(file))
180
+ return null;
181
+ return execFileSync("/usr/bin/plutil", ["-convert", "json", "-o", "-", file], { encoding: "utf8", timeout: 2_000, stdio: ["ignore", "pipe", "ignore"] });
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ }
187
+ /** JSON as Claude Code reads settings: a leading byte-order mark is allowed. */
188
+ function parseJson(text) {
189
+ if (text === null)
190
+ return undefined;
191
+ try {
192
+ return JSON.parse(text.replace(/^\uFEFF/, ""));
193
+ }
194
+ catch {
195
+ return undefined;
196
+ }
197
+ }
198
+ function isRecord(value) {
199
+ return typeof value === "object" && value !== null && !Array.isArray(value);
200
+ }
201
+ function nonEmpty(value) {
202
+ return typeof value === "string" ? value.trim() !== "" : value !== undefined && value !== null;
203
+ }
204
+ //# sourceMappingURL=https-proxy-eligibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"https-proxy-eligibility.js","sourceRoot":"","sources":["../src/https-proxy-eligibility.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * ccc's loopback server as Claude Code's HTTPS_PROXY (opt-in: CCC_HTTPS_PROXY_MODE=1 or
3
+ * the `httpsProxyMode` config key; https-proxy-session.ts decides and sets it up). Claude
4
+ * Code then keeps api.anthropic.com as its base URL, and with it Remote Control, while its
5
+ * model calls still reach ccc and MemTree.
6
+ *
7
+ * - A CONNECT without this session's proxy token gets 407: other local users and programs
8
+ * can use neither the tunnel nor the interception.
9
+ * - CONNECT api.anthropic.com:443: TLS is terminated with the session CA's leaf
10
+ * (mitm-ca.ts) and the decrypted stream goes to a separate, never-listening http.Server
11
+ * that shares ccc's request handler. proxy.ts routes only POST /v1/messages and
12
+ * /v1/messages/count_tokens from it to MemTree; every other path (Remote Control's
13
+ * bridge, sessions, files, OAuth, telemetry) goes verbatim to api.anthropic.com, and
14
+ * ccc's loopback-only routes (hooks, /memtree/*) are not reachable from it.
15
+ * - Every other CONNECT: a blind TCP tunnel. ccc never decrypts or logs those bytes.
16
+ * - An HTTP upgrade (WebSocket) on an intercepted stream: piped raw to api.anthropic.com
17
+ * over a fresh TLS connection. The loopback server itself gets no upgrade listener, so
18
+ * its requests behave exactly as without proxy mode.
19
+ *
20
+ * The optional trace (CCC_PROXY_TRACE) records CONNECT targets and, for intercepted
21
+ * requests, method, path (no query), status and User-Agent: no other header values, no
22
+ * bodies.
23
+ */
24
+ import http from "node:http";
25
+ import { type SessionCa } from "./mitm-ca.js";
26
+ /** The user name in HTTPS_PROXY; the session token is its password. */
27
+ export declare const PROXY_USER = "ccc";
28
+ export interface HttpsProxyModeOptions {
29
+ /** The leaf for api.anthropic.com (its CA's key is already gone). */
30
+ ca: Pick<SessionCa, "leafCertPem" | "leafKeyPem">;
31
+ /** Per-session secret: Claude Code sends it on every CONNECT (HTTPS_PROXY's userinfo). */
32
+ proxyToken: string;
33
+ /** Debug trace (CONNECT targets, intercepted method/path/status, User-Agent). */
34
+ tracePath?: string;
35
+ }
36
+ /** Where intercepted traffic goes: api.anthropic.com, or a test's fake upstream. */
37
+ export interface InterceptUpstream {
38
+ host: string;
39
+ port: number;
40
+ secure: boolean;
41
+ }
42
+ /**
43
+ * Raw sockets drain can't see (they keep server.close() waiting): `blind` destroys the
44
+ * blind tunnels (no ccc work in them; called when drain starts), `all` everything left
45
+ * (at the drain deadline).
46
+ */
47
+ export interface CloseTunnels {
48
+ blind: () => void;
49
+ all: () => void;
50
+ }
51
+ /** The HTTPS_PROXY value Claude Code gets: the loopback port with the token. */
52
+ export declare function proxyUrlFor(port: number, proxyToken: string): string;
53
+ export declare function attachHttpsProxyMode(server: http.Server, onInterceptedRequest: http.RequestListener, upstream: InterceptUpstream, opts: HttpsProxyModeOptions): CloseTunnels;
54
+ /** host:port of a CONNECT (IPv6 in brackets); null when malformed. */
55
+ export declare function parseAuthority(authority: string): {
56
+ host: string;
57
+ port: number;
58
+ } | null;
59
+ //# sourceMappingURL=https-proxy-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"https-proxy-mode.d.ts","sourceRoot":"","sources":["../src/https-proxy-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9D,uEAAuE;AACvE,eAAO,MAAM,UAAU,QAAQ,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,aAAa,GAAG,YAAY,CAAC,CAAC;IAClD,0FAA0F;IAC1F,UAAU,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,oBAAoB,EAAE,IAAI,CAAC,eAAe,EAC1C,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,qBAAqB,GAC1B,YAAY,CAmBd;AAwID,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAMvF"}