@jsonstudio/rcc 0.89.1552 → 0.89.1800

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 (236) hide show
  1. package/README.md +97 -13
  2. package/configsamples/config.json +8 -8
  3. package/configsamples/config.reference.json +1 -1
  4. package/configsamples/provider/crs/config.v1.json +1 -1
  5. package/configsamples/provider/glm/config.v1.json +1 -1
  6. package/configsamples/provider/glm-anthropic/config.v1.json +1 -1
  7. package/configsamples/provider/kimi/config.v1.json +1 -1
  8. package/configsamples/provider/lmstudio/config.v1.json +2 -1
  9. package/configsamples/provider/mimo/config.v1.json +1 -1
  10. package/configsamples/provider/modelscope/config.v1.json +1 -1
  11. package/configsamples/provider/qwen/config.v1.json +1 -1
  12. package/configsamples/provider/tab/config.v1.json +2 -1
  13. package/configsamples/provider/tabglm/config.v1.json +10 -15
  14. package/dist/build-info.js +2 -2
  15. package/dist/cli/commands/camoufox.d.ts +34 -0
  16. package/dist/cli/commands/camoufox.js +107 -0
  17. package/dist/cli/commands/camoufox.js.map +1 -0
  18. package/dist/cli/commands/config.js +8 -9
  19. package/dist/cli/commands/config.js.map +1 -1
  20. package/dist/cli/commands/restart.d.ts +4 -12
  21. package/dist/cli/commands/restart.js +226 -120
  22. package/dist/cli/commands/restart.js.map +1 -1
  23. package/dist/cli/commands/start.d.ts +1 -0
  24. package/dist/cli/commands/start.js +34 -6
  25. package/dist/cli/commands/start.js.map +1 -1
  26. package/dist/cli/commands/status.js +12 -6
  27. package/dist/cli/commands/status.js.map +1 -1
  28. package/dist/cli/config/init-provider-catalog.js +12 -11
  29. package/dist/cli/config/init-provider-catalog.js.map +1 -1
  30. package/dist/cli/register/camoufox-command.d.ts +20 -0
  31. package/dist/cli/register/camoufox-command.js +22 -0
  32. package/dist/cli/register/camoufox-command.js.map +1 -0
  33. package/dist/cli.js +14 -14
  34. package/dist/cli.js.map +1 -1
  35. package/dist/client/anthropic/anthropic-protocol-client.d.ts +1 -0
  36. package/dist/client/anthropic/anthropic-protocol-client.js +25 -0
  37. package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
  38. package/dist/commands/oauth.js +185 -9
  39. package/dist/commands/oauth.js.map +1 -1
  40. package/dist/commands/token-daemon.js +12 -2
  41. package/dist/commands/token-daemon.js.map +1 -1
  42. package/dist/commands/validate.js +1 -1
  43. package/dist/commands/validate.js.map +1 -1
  44. package/dist/docs/daemon-admin-ui.html +1355 -204
  45. package/dist/index.js +119 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/manager/index.d.ts +2 -0
  48. package/dist/manager/index.js +39 -2
  49. package/dist/manager/index.js.map +1 -1
  50. package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +29 -5
  51. package/dist/manager/modules/quota/antigravity-quota-manager.js +369 -113
  52. package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -1
  53. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.d.ts +7 -0
  54. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js +61 -0
  55. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js.map +1 -1
  56. package/dist/manager/modules/quota/provider-quota-daemon.d.ts +1 -0
  57. package/dist/manager/modules/quota/provider-quota-daemon.events.js +245 -1
  58. package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
  59. package/dist/manager/modules/quota/provider-quota-daemon.js +20 -13
  60. package/dist/manager/modules/quota/provider-quota-daemon.js.map +1 -1
  61. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.d.ts +1 -0
  62. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +8 -3
  63. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
  64. package/dist/manager/modules/token/index.js +2 -2
  65. package/dist/manager/modules/token/index.js.map +1 -1
  66. package/dist/manager/quota/provider-quota-center.d.ts +16 -1
  67. package/dist/manager/quota/provider-quota-center.js +24 -3
  68. package/dist/manager/quota/provider-quota-center.js.map +1 -1
  69. package/dist/modules/llmswitch/bridge.d.ts +33 -1
  70. package/dist/modules/llmswitch/bridge.js +170 -2
  71. package/dist/modules/llmswitch/bridge.js.map +1 -1
  72. package/dist/modules/llmswitch/core-loader.js +64 -11
  73. package/dist/modules/llmswitch/core-loader.js.map +1 -1
  74. package/dist/modules/pipeline/utils/debug-logger.d.ts +1 -0
  75. package/dist/modules/pipeline/utils/debug-logger.js +50 -3
  76. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  77. package/dist/providers/auth/apikey-auth.js +15 -3
  78. package/dist/providers/auth/apikey-auth.js.map +1 -1
  79. package/dist/providers/auth/oauth-lifecycle.d.ts +13 -1
  80. package/dist/providers/auth/oauth-lifecycle.js +346 -45
  81. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  82. package/dist/providers/auth/oauth-repair-cooldown.d.ts +21 -0
  83. package/dist/providers/auth/oauth-repair-cooldown.js +100 -0
  84. package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -0
  85. package/dist/providers/auth/oauth-repair-env.d.ts +1 -0
  86. package/dist/providers/auth/oauth-repair-env.js +79 -0
  87. package/dist/providers/auth/oauth-repair-env.js.map +1 -0
  88. package/dist/providers/auth/qwen-userinfo-helper.d.ts +2 -0
  89. package/dist/providers/auth/qwen-userinfo-helper.js +72 -40
  90. package/dist/providers/auth/qwen-userinfo-helper.js.map +1 -1
  91. package/dist/providers/auth/tokenfile-auth.js +148 -17
  92. package/dist/providers/auth/tokenfile-auth.js.map +1 -1
  93. package/dist/providers/core/api/provider-types.d.ts +10 -0
  94. package/dist/providers/core/config/camoufox-launcher.d.ts +3 -0
  95. package/dist/providers/core/config/camoufox-launcher.js +190 -3
  96. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  97. package/dist/providers/core/config/oauth-flows.js +50 -19
  98. package/dist/providers/core/config/oauth-flows.js.map +1 -1
  99. package/dist/providers/core/config/provider-oauth-configs.js +1 -1
  100. package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
  101. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +5 -0
  102. package/dist/providers/core/runtime/gemini-cli-http-provider.js +172 -15
  103. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  104. package/dist/providers/core/runtime/gemini-http-provider.d.ts +11 -0
  105. package/dist/providers/core/runtime/gemini-http-provider.js +281 -3
  106. package/dist/providers/core/runtime/gemini-http-provider.js.map +1 -1
  107. package/dist/providers/core/runtime/http-request-executor.js +55 -0
  108. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  109. package/dist/providers/core/runtime/http-transport-provider.js +10 -14
  110. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  111. package/dist/providers/core/runtime/provider-factory.d.ts +1 -0
  112. package/dist/providers/core/runtime/provider-factory.js +40 -2
  113. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  114. package/dist/providers/core/strategies/oauth-auth-code-flow.js +45 -2
  115. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  116. package/dist/providers/core/strategies/oauth-device-flow.js +13 -2
  117. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  118. package/dist/providers/core/strategies/oauth-refresh-errors.d.ts +1 -0
  119. package/dist/providers/core/strategies/oauth-refresh-errors.js +26 -0
  120. package/dist/providers/core/strategies/oauth-refresh-errors.js.map +1 -0
  121. package/dist/providers/core/utils/snapshot-writer.d.ts +4 -2
  122. package/dist/providers/core/utils/snapshot-writer.js +86 -23
  123. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  124. package/dist/scripts/camoufox/launch-auth.mjs +545 -49
  125. package/dist/server/handlers/chat-handler.js +1 -1
  126. package/dist/server/handlers/chat-handler.js.map +1 -1
  127. package/dist/server/handlers/handler-utils.d.ts +1 -0
  128. package/dist/server/handlers/handler-utils.js +231 -3
  129. package/dist/server/handlers/handler-utils.js.map +1 -1
  130. package/dist/server/handlers/messages-handler.js +1 -1
  131. package/dist/server/handlers/messages-handler.js.map +1 -1
  132. package/dist/server/handlers/responses-handler.js +17 -5
  133. package/dist/server/handlers/responses-handler.js.map +1 -1
  134. package/dist/server/handlers/sse-dispatcher.js +10 -1
  135. package/dist/server/handlers/sse-dispatcher.js.map +1 -1
  136. package/dist/server/runtime/http-server/daemon-admin/control-handler.d.ts +3 -0
  137. package/dist/server/runtime/http-server/daemon-admin/control-handler.js +389 -0
  138. package/dist/server/runtime/http-server/daemon-admin/control-handler.js.map +1 -0
  139. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +190 -5
  140. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
  141. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +2 -1
  142. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
  143. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +117 -14
  144. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -1
  145. package/dist/server/runtime/http-server/daemon-admin/routing-policy.d.ts +30 -0
  146. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +133 -0
  147. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -0
  148. package/dist/server/runtime/http-server/daemon-admin/status-handler.js +40 -1
  149. package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -1
  150. package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +5 -0
  151. package/dist/server/runtime/http-server/daemon-admin-routes.js +3 -0
  152. package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
  153. package/dist/server/runtime/http-server/executor-pipeline.d.ts +10 -0
  154. package/dist/server/runtime/http-server/executor-pipeline.js +6 -0
  155. package/dist/server/runtime/http-server/executor-pipeline.js.map +1 -1
  156. package/dist/server/runtime/http-server/executor-response.js +26 -0
  157. package/dist/server/runtime/http-server/executor-response.js.map +1 -1
  158. package/dist/server/runtime/http-server/hub-shadow-compare.js +41 -3
  159. package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
  160. package/dist/server/runtime/http-server/index.d.ts +9 -0
  161. package/dist/server/runtime/http-server/index.js +337 -91
  162. package/dist/server/runtime/http-server/index.js.map +1 -1
  163. package/dist/server/runtime/http-server/middleware.js +27 -1
  164. package/dist/server/runtime/http-server/middleware.js.map +1 -1
  165. package/dist/server/runtime/http-server/request-executor.js +199 -29
  166. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  167. package/dist/server/runtime/http-server/routes.d.ts +1 -0
  168. package/dist/server/runtime/http-server/routes.js +36 -3
  169. package/dist/server/runtime/http-server/routes.js.map +1 -1
  170. package/dist/server/runtime/http-server/server-id.d.ts +1 -0
  171. package/dist/server/runtime/http-server/server-id.js +18 -0
  172. package/dist/server/runtime/http-server/server-id.js.map +1 -0
  173. package/dist/server/runtime/http-server/stats-manager.d.ts +2 -0
  174. package/dist/server/runtime/http-server/stats-manager.js +63 -7
  175. package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
  176. package/dist/server/runtime/http-server/types.d.ts +2 -0
  177. package/dist/server/utils/stage-logger.js +54 -9
  178. package/dist/server/utils/stage-logger.js.map +1 -1
  179. package/dist/token-daemon/history-store.d.ts +8 -3
  180. package/dist/token-daemon/history-store.js +41 -20
  181. package/dist/token-daemon/history-store.js.map +1 -1
  182. package/dist/token-daemon/index.d.ts +5 -1
  183. package/dist/token-daemon/index.js +191 -11
  184. package/dist/token-daemon/index.js.map +1 -1
  185. package/dist/token-daemon/quota-auth-issue.d.ts +7 -0
  186. package/dist/token-daemon/quota-auth-issue.js +231 -0
  187. package/dist/token-daemon/quota-auth-issue.js.map +1 -0
  188. package/dist/token-daemon/server-utils.js +1 -1
  189. package/dist/token-daemon/server-utils.js.map +1 -1
  190. package/dist/token-daemon/token-daemon.d.ts +2 -0
  191. package/dist/token-daemon/token-daemon.js +177 -14
  192. package/dist/token-daemon/token-daemon.js.map +1 -1
  193. package/dist/token-portal/local-token-portal.js +6 -0
  194. package/dist/token-portal/local-token-portal.js.map +1 -1
  195. package/dist/tools/provider-update/fetch-models.js +0 -1
  196. package/dist/tools/provider-update/fetch-models.js.map +1 -1
  197. package/dist/tools/provider-update/key-probe.js +0 -1
  198. package/dist/tools/provider-update/key-probe.js.map +1 -1
  199. package/docs/ANTIGRAVITY_IDE_FORWARD_PROXY.md +61 -0
  200. package/docs/ANTIGRAVITY_THOUGHT_SIGNATURE_BOOTSTRAP_429.md +80 -0
  201. package/docs/CLOCK.md +94 -0
  202. package/docs/DAEMON_CONTROL_PLANE.md +34 -0
  203. package/docs/OAUTH.md +172 -0
  204. package/docs/PROVIDERS_BUILTIN.md +8 -5
  205. package/docs/PROVIDER_TYPES.md +6 -4
  206. package/docs/QUOTA_MANAGER_V3.md +54 -0
  207. package/docs/ROUTING_POLICY_SCHEMA.md +47 -0
  208. package/docs/ROUTING_POLICY_UI.md +11 -0
  209. package/docs/SERVERTOOL_CLOCK_DESIGN.md +56 -25
  210. package/docs/antigravity-routing-contract.md +17 -11
  211. package/docs/config-secrets.md +49 -0
  212. package/docs/daemon-admin-ui.html +1355 -204
  213. package/docs/oauth-authentication-guide.md +4 -0
  214. package/docs/oauth-iflow-implementation.md +4 -0
  215. package/docs/provider-quota-design.md +11 -0
  216. package/docs/providers/antigravity-fingerprint-ua-warmup.md +25 -0
  217. package/docs/providers/antigravity-gemini-provider-compat.md +1 -0
  218. package/docs/providers/antigravity-thought-signature.md +127 -0
  219. package/docs/providers/tabglm-claude-code-compat.md +39 -0
  220. package/docs/refactoring/host-sharedmodule-safe-migration-plan.md +164 -0
  221. package/docs/stop-message-auto.md +1 -0
  222. package/docs/token-daemon-preview.html +2 -2
  223. package/docs/token-refresh-daemon-plan.md +6 -6
  224. package/package.json +5 -5
  225. package/scripts/antigravity-ide-forward-proxy.mjs +362 -0
  226. package/scripts/backfill-apply-patch-exec-errorsamples.mjs +19 -0
  227. package/scripts/camoufox/launch-auth.mjs +545 -49
  228. package/scripts/ci/repo-sanity.mjs +2 -0
  229. package/scripts/install-global.sh +46 -0
  230. package/scripts/migrate-antigravity-session-signatures-alias.mjs +193 -0
  231. package/scripts/migrate-antigravity-session-signatures.mjs +165 -0
  232. package/scripts/responses-compare-server.mjs +1 -1
  233. package/scripts/tests/blackbox-rcc-vs-routecodex-antigravity.mjs +44 -9
  234. package/scripts/tests/ci-jest.mjs +3 -0
  235. package/scripts/verify-client-headers.mjs +33 -5
  236. package/scripts/virtual-router-dryrun.mjs +333 -0
@@ -0,0 +1,362 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Antigravity IDE forward proxy (best-effort recorder).
4
+ *
5
+ * - Supports HTTP proxy requests (absolute-form) and CONNECT tunneling.
6
+ * - Logs what it can see (CONNECT targets, HTTP method/url/status).
7
+ * - Does NOT MITM TLS; HTTPS payloads remain encrypted unless the client uses a MITM-capable proxy.
8
+ */
9
+
10
+ import http from 'node:http';
11
+ import https from 'node:https';
12
+ import net from 'node:net';
13
+ import fs from 'node:fs';
14
+ import { randomUUID } from 'node:crypto';
15
+
16
+ function parseArgs(argv) {
17
+ const out = {};
18
+ for (let i = 0; i < argv.length; i += 1) {
19
+ const raw = String(argv[i] ?? '');
20
+ if (!raw.startsWith('--')) {
21
+ continue;
22
+ }
23
+ const eq = raw.indexOf('=');
24
+ if (eq > 0) {
25
+ const k = raw.slice(2, eq);
26
+ const v = raw.slice(eq + 1);
27
+ out[k] = v;
28
+ continue;
29
+ }
30
+ const k = raw.slice(2);
31
+ const next = argv[i + 1];
32
+ if (next && !String(next).startsWith('--')) {
33
+ out[k] = String(next);
34
+ i += 1;
35
+ continue;
36
+ }
37
+ out[k] = true;
38
+ }
39
+ return out;
40
+ }
41
+
42
+ function toInt(value, fallback) {
43
+ const n = Number.parseInt(String(value ?? ''), 10);
44
+ return Number.isFinite(n) ? n : fallback;
45
+ }
46
+
47
+ function nowIso() {
48
+ return new Date().toISOString();
49
+ }
50
+
51
+ function createJsonlLogger(options) {
52
+ const logFile = typeof options.logFile === 'string' && options.logFile.trim() ? options.logFile.trim() : null;
53
+ const stream = logFile ? fs.createWriteStream(logFile, { flags: 'a' }) : null;
54
+
55
+ function write(entry) {
56
+ const line = `${JSON.stringify(entry)}\n`;
57
+ if (stream) {
58
+ stream.write(line);
59
+ return;
60
+ }
61
+ process.stdout.write(line);
62
+ }
63
+
64
+ function close() {
65
+ try {
66
+ stream?.end();
67
+ } catch {
68
+ // ignore
69
+ }
70
+ }
71
+
72
+ return { write, close, logFile };
73
+ }
74
+
75
+ function redactHeaders(headers) {
76
+ const out = {};
77
+ const redacted = new Set(['authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-goog-api-key']);
78
+ for (const [k, v] of Object.entries(headers ?? {})) {
79
+ const key = String(k).toLowerCase();
80
+ if (redacted.has(key)) {
81
+ out[k] = '<redacted>';
82
+ continue;
83
+ }
84
+ out[k] = v;
85
+ }
86
+ return out;
87
+ }
88
+
89
+ function stripHopByHopHeaders(headers) {
90
+ const out = { ...(headers ?? {}) };
91
+ const hopByHop = [
92
+ 'connection',
93
+ 'proxy-connection',
94
+ 'keep-alive',
95
+ 'transfer-encoding',
96
+ 'te',
97
+ 'trailer',
98
+ 'upgrade',
99
+ 'proxy-authorization'
100
+ ];
101
+ for (const h of hopByHop) {
102
+ for (const key of Object.keys(out)) {
103
+ if (String(key).toLowerCase() === h) {
104
+ delete out[key];
105
+ }
106
+ }
107
+ }
108
+ return out;
109
+ }
110
+
111
+ function safeUrlForLog(url) {
112
+ const raw = typeof url === 'string' ? url : '';
113
+ // Keep as-is: do not attempt to parse/normalize (some clients send non-standard forms).
114
+ return raw.length > 4096 ? `${raw.slice(0, 4096)}…` : raw;
115
+ }
116
+
117
+ async function main() {
118
+ const args = parseArgs(process.argv.slice(2));
119
+ const host = String(args.host || '127.0.0.1');
120
+ const port = toInt(args.port || 8080, 8080);
121
+ const logFile = typeof args['log-file'] === 'string' ? args['log-file'] : null;
122
+ const recordBody = String(args['record-body'] || '').trim() === '1' || args['record-body'] === true;
123
+ const maxBodyBytes = toInt(args['max-body-bytes'] || 4096, 4096);
124
+
125
+ const logger = createJsonlLogger({ logFile });
126
+
127
+ const server = http.createServer((req, res) => {
128
+ const id = randomUUID();
129
+ const startedAt = Date.now();
130
+ const method = String(req.method || 'GET');
131
+ const rawUrl = String(req.url || '');
132
+
133
+ let parsed;
134
+ try {
135
+ // Proxy requests use absolute-form (RFC 9110). Fallback to host header for origin-form.
136
+ parsed = rawUrl.startsWith('http://') || rawUrl.startsWith('https://')
137
+ ? new URL(rawUrl)
138
+ : null;
139
+ } catch {
140
+ parsed = null;
141
+ }
142
+
143
+ const targetProtocol = parsed?.protocol || 'http:';
144
+ const targetHost = parsed?.hostname || String(req.headers.host || '');
145
+ const targetPort =
146
+ parsed?.port
147
+ ? Number(parsed.port)
148
+ : targetProtocol === 'https:'
149
+ ? 443
150
+ : 80;
151
+ const targetPath = parsed ? `${parsed.pathname || '/'}${parsed.search || ''}` : rawUrl || '/';
152
+
153
+ const requestHeaders = stripHopByHopHeaders(req.headers);
154
+ if (targetHost) {
155
+ requestHeaders.host = targetHost;
156
+ }
157
+
158
+ let reqBodyBufs = [];
159
+ let reqBodyBytes = 0;
160
+
161
+ const client = targetProtocol === 'https:' ? https : http;
162
+ const upstreamReq = client.request(
163
+ {
164
+ protocol: targetProtocol,
165
+ hostname: targetHost,
166
+ port: targetPort,
167
+ method,
168
+ path: targetPath,
169
+ headers: requestHeaders
170
+ },
171
+ (upstreamRes) => {
172
+ res.writeHead(upstreamRes.statusCode || 502, upstreamRes.headers);
173
+ let resBytes = 0;
174
+ upstreamRes.on('data', (chunk) => {
175
+ resBytes += chunk?.length || 0;
176
+ });
177
+ upstreamRes.on('end', () => {
178
+ const durationMs = Date.now() - startedAt;
179
+ let requestBodyText = null;
180
+ if (recordBody && reqBodyBufs.length) {
181
+ try {
182
+ requestBodyText = Buffer.concat(reqBodyBufs).toString('utf8');
183
+ } catch {
184
+ requestBodyText = null;
185
+ }
186
+ }
187
+ logger.write({
188
+ ts: nowIso(),
189
+ kind: 'http',
190
+ id,
191
+ method,
192
+ url: safeUrlForLog(rawUrl),
193
+ target: {
194
+ protocol: targetProtocol,
195
+ host: targetHost,
196
+ port: targetPort,
197
+ path: targetPath
198
+ },
199
+ request: {
200
+ headers: redactHeaders(req.headers),
201
+ ...(recordBody ? { body: requestBodyText } : {})
202
+ },
203
+ response: {
204
+ statusCode: upstreamRes.statusCode || null,
205
+ bytes: resBytes
206
+ },
207
+ durationMs
208
+ });
209
+ });
210
+ upstreamRes.pipe(res);
211
+ }
212
+ );
213
+
214
+ upstreamReq.on('error', (err) => {
215
+ const durationMs = Date.now() - startedAt;
216
+ logger.write({
217
+ ts: nowIso(),
218
+ kind: 'http',
219
+ id,
220
+ method,
221
+ url: safeUrlForLog(rawUrl),
222
+ target: { protocol: targetProtocol, host: targetHost, port: targetPort, path: targetPath },
223
+ error: { name: err?.name || 'Error', message: err?.message || String(err) },
224
+ durationMs
225
+ });
226
+ if (!res.headersSent) {
227
+ res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });
228
+ }
229
+ res.end('Bad Gateway');
230
+ });
231
+
232
+ req.on('data', (chunk) => {
233
+ if (!recordBody) {
234
+ return;
235
+ }
236
+ if (!chunk) {
237
+ return;
238
+ }
239
+ const nextBytes = reqBodyBytes + (chunk.length || 0);
240
+ if (nextBytes > maxBodyBytes) {
241
+ const remaining = Math.max(0, maxBodyBytes - reqBodyBytes);
242
+ if (remaining > 0) {
243
+ reqBodyBufs.push(chunk.subarray(0, remaining));
244
+ reqBodyBytes += remaining;
245
+ }
246
+ return;
247
+ }
248
+ reqBodyBufs.push(chunk);
249
+ reqBodyBytes = nextBytes;
250
+ });
251
+
252
+ req.pipe(upstreamReq);
253
+ });
254
+
255
+ server.on('connect', (req, clientSocket, head) => {
256
+ const id = randomUUID();
257
+ const startedAt = Date.now();
258
+ const rawUrl = String(req.url || '');
259
+ const [host, portRaw] = rawUrl.split(':');
260
+ const targetHost = String(host || '').trim();
261
+ const targetPort = toInt(portRaw || 443, 443);
262
+
263
+ logger.write({
264
+ ts: nowIso(),
265
+ kind: 'connect_start',
266
+ id,
267
+ target: { host: targetHost, port: targetPort },
268
+ request: { url: safeUrlForLog(rawUrl), headers: redactHeaders(req.headers) }
269
+ });
270
+
271
+ const upstreamSocket = net.connect(targetPort, targetHost, () => {
272
+ clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
273
+ if (head && head.length) {
274
+ upstreamSocket.write(head);
275
+ }
276
+ clientSocket.pipe(upstreamSocket);
277
+ upstreamSocket.pipe(clientSocket);
278
+ });
279
+
280
+ let c2u = 0;
281
+ let u2c = 0;
282
+ clientSocket.on('data', (chunk) => {
283
+ c2u += chunk?.length || 0;
284
+ });
285
+ upstreamSocket.on('data', (chunk) => {
286
+ u2c += chunk?.length || 0;
287
+ });
288
+
289
+ let finished = false;
290
+ const finish = (extra) => {
291
+ if (finished) {
292
+ return;
293
+ }
294
+ finished = true;
295
+ const durationMs = Date.now() - startedAt;
296
+ logger.write({
297
+ ts: nowIso(),
298
+ kind: 'connect_end',
299
+ id,
300
+ target: { host: targetHost, port: targetPort },
301
+ request: { url: safeUrlForLog(rawUrl), headers: redactHeaders(req.headers) },
302
+ tunnel: { bytesClientToUpstream: c2u, bytesUpstreamToClient: u2c },
303
+ durationMs,
304
+ ...(extra ? { extra } : {})
305
+ });
306
+ };
307
+
308
+ upstreamSocket.on('error', (err) => {
309
+ try {
310
+ clientSocket.write('HTTP/1.1 502 Bad Gateway\r\n\r\n');
311
+ } catch {
312
+ // ignore
313
+ }
314
+ finish({ error: { name: err?.name || 'Error', message: err?.message || String(err) } });
315
+ try { clientSocket.destroy(); } catch { /* ignore */ }
316
+ });
317
+
318
+ clientSocket.on('error', (err) => {
319
+ finish({ clientError: { name: err?.name || 'Error', message: err?.message || String(err) } });
320
+ try { upstreamSocket.destroy(); } catch { /* ignore */ }
321
+ });
322
+
323
+ clientSocket.on('close', () => finish({ closedBy: 'client' }));
324
+ upstreamSocket.on('close', () => finish({ closedBy: 'upstream' }));
325
+ });
326
+
327
+ server.on('clientError', (err, socket) => {
328
+ try {
329
+ socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
330
+ } catch {
331
+ // ignore
332
+ }
333
+ logger.write({ ts: nowIso(), kind: 'client_error', error: { name: err?.name || 'Error', message: err?.message || String(err) } });
334
+ });
335
+
336
+ const shutdown = () => {
337
+ try { logger.close(); } catch { /* ignore */ }
338
+ try { server.close(); } catch { /* ignore */ }
339
+ };
340
+
341
+ process.on('SIGINT', shutdown);
342
+ process.on('SIGTERM', shutdown);
343
+
344
+ server.listen(port, host, () => {
345
+ const addr = server.address();
346
+ const bind = typeof addr === 'object' && addr ? `${addr.address}:${addr.port}` : `${host}:${port}`;
347
+ logger.write({
348
+ ts: nowIso(),
349
+ kind: 'startup',
350
+ bind,
351
+ logFile: logger.logFile,
352
+ recordBody,
353
+ maxBodyBytes,
354
+ note: 'Forward proxy started. HTTPS payloads are encrypted unless using a MITM proxy.'
355
+ });
356
+ });
357
+ }
358
+
359
+ main().catch((err) => {
360
+ process.stderr.write(`proxy failed: ${err?.message || String(err)}\n`);
361
+ process.exit(1);
362
+ });
@@ -25,6 +25,7 @@ const ERR_BASE =
25
25
  const OUT_ROOT = path.join(ERR_BASE, 'apply_patch_exec');
26
26
 
27
27
  const MAX_PER_TYPE = 250;
28
+ const EXEC_ERRORSAMPLES_ENABLED = String(process.env.ROUTECODEX_ERRORSAMPLES_APPLY_PATCH_EXEC || '').trim() === '1';
28
29
 
29
30
  function detectApplyPatchToolMode() {
30
31
  return 'freeform';
@@ -47,6 +48,16 @@ function classifyExecutionFailure(content) {
47
48
  return { errorType: 'unknown', message: msg };
48
49
  }
49
50
 
51
+ function isContextExecutionFailureType(errorType) {
52
+ const t = String(errorType || '').trim().toLowerCase();
53
+ return (
54
+ t === 'read_file_failed' ||
55
+ t === 'file_not_found' ||
56
+ t === 'context_not_found' ||
57
+ t === 'expected_lines_not_found'
58
+ );
59
+ }
60
+
50
61
  function stableId({ errorType, errorMessage, toolCallId, toolCallArgs, requestId, mode }) {
51
62
  const key = `${String(errorType)}:${String(errorMessage)}:${String(toolCallId || '')}:${String(toolCallArgs || '')}:${String(
52
63
  requestId || ''
@@ -111,6 +122,11 @@ function buildToolCallArgsIndex(messages) {
111
122
  }
112
123
 
113
124
  async function main() {
125
+ if (!EXEC_ERRORSAMPLES_ENABLED) {
126
+ console.log('[backfill:apply_patch_exec] skip (disabled; set ROUTECODEX_ERRORSAMPLES_APPLY_PATCH_EXEC=1 to enable)');
127
+ return;
128
+ }
129
+
114
130
  const roots = [];
115
131
  if (await fileExists(CODEX_ROOT_PRIMARY)) roots.push(CODEX_ROOT_PRIMARY);
116
132
  if (await fileExists(CODEX_ROOT_ALT)) roots.push(CODEX_ROOT_ALT);
@@ -167,6 +183,9 @@ async function main() {
167
183
 
168
184
  for (const m of toolMsgs) {
169
185
  const { errorType, message } = classifyExecutionFailure(m.content);
186
+ // RouteCodex policy: keep shape-ish errors only (parse/format). Skip context/execution mismatches.
187
+ if (isContextExecutionFailureType(errorType)) continue;
188
+ if (String(errorType || '').trim().toLowerCase() === 'unknown') continue;
170
189
  const safeType = String(errorType || 'unknown').replace(/[^a-z0-9-]/gi, '_');
171
190
  const typeDir = path.join(OUT_ROOT, safeType);
172
191
  await ensureDir(typeDir);