@jsonstudio/rcc 0.89.1562 → 0.89.1803

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 (223) 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 +1 -1
  14. package/dist/build-info.js +3 -3
  15. package/dist/build-info.js.map +1 -1
  16. package/dist/cli/commands/config.js +8 -9
  17. package/dist/cli/commands/config.js.map +1 -1
  18. package/dist/cli/commands/restart.d.ts +4 -12
  19. package/dist/cli/commands/restart.js +226 -120
  20. package/dist/cli/commands/restart.js.map +1 -1
  21. package/dist/cli/commands/start.d.ts +1 -0
  22. package/dist/cli/commands/start.js +28 -1
  23. package/dist/cli/commands/start.js.map +1 -1
  24. package/dist/cli/commands/status.js +12 -6
  25. package/dist/cli/commands/status.js.map +1 -1
  26. package/dist/cli/config/init-provider-catalog.js +12 -11
  27. package/dist/cli/config/init-provider-catalog.js.map +1 -1
  28. package/dist/cli.js +3 -14
  29. package/dist/cli.js.map +1 -1
  30. package/dist/client/anthropic/anthropic-protocol-client.d.ts +1 -0
  31. package/dist/client/anthropic/anthropic-protocol-client.js +25 -0
  32. package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
  33. package/dist/commands/oauth.js +185 -9
  34. package/dist/commands/oauth.js.map +1 -1
  35. package/dist/commands/token-daemon.js +12 -2
  36. package/dist/commands/token-daemon.js.map +1 -1
  37. package/dist/docs/daemon-admin-ui.html +1242 -234
  38. package/dist/index.js +119 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/manager/index.d.ts +2 -0
  41. package/dist/manager/index.js +39 -2
  42. package/dist/manager/index.js.map +1 -1
  43. package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +29 -5
  44. package/dist/manager/modules/quota/antigravity-quota-manager.js +369 -113
  45. package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -1
  46. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.d.ts +7 -0
  47. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js +61 -0
  48. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js.map +1 -1
  49. package/dist/manager/modules/quota/provider-quota-daemon.d.ts +1 -0
  50. package/dist/manager/modules/quota/provider-quota-daemon.events.js +134 -5
  51. package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
  52. package/dist/manager/modules/quota/provider-quota-daemon.js +19 -13
  53. package/dist/manager/modules/quota/provider-quota-daemon.js.map +1 -1
  54. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.d.ts +1 -0
  55. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +8 -3
  56. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
  57. package/dist/manager/modules/token/index.js +2 -2
  58. package/dist/manager/modules/token/index.js.map +1 -1
  59. package/dist/manager/quota/provider-quota-center.d.ts +9 -0
  60. package/dist/manager/quota/provider-quota-center.js +19 -2
  61. package/dist/manager/quota/provider-quota-center.js.map +1 -1
  62. package/dist/modules/llmswitch/bridge.d.ts +33 -1
  63. package/dist/modules/llmswitch/bridge.js +170 -2
  64. package/dist/modules/llmswitch/bridge.js.map +1 -1
  65. package/dist/modules/llmswitch/core-loader.js +64 -11
  66. package/dist/modules/llmswitch/core-loader.js.map +1 -1
  67. package/dist/modules/pipeline/utils/debug-logger.d.ts +1 -0
  68. package/dist/modules/pipeline/utils/debug-logger.js +50 -3
  69. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  70. package/dist/providers/auth/apikey-auth.js +15 -3
  71. package/dist/providers/auth/apikey-auth.js.map +1 -1
  72. package/dist/providers/auth/oauth-auth.js +26 -2
  73. package/dist/providers/auth/oauth-auth.js.map +1 -1
  74. package/dist/providers/auth/oauth-lifecycle.d.ts +13 -1
  75. package/dist/providers/auth/oauth-lifecycle.js +346 -45
  76. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  77. package/dist/providers/auth/oauth-repair-cooldown.d.ts +21 -0
  78. package/dist/providers/auth/oauth-repair-cooldown.js +100 -0
  79. package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -0
  80. package/dist/providers/auth/oauth-repair-env.d.ts +1 -0
  81. package/dist/providers/auth/oauth-repair-env.js +79 -0
  82. package/dist/providers/auth/oauth-repair-env.js.map +1 -0
  83. package/dist/providers/auth/qwen-userinfo-helper.d.ts +2 -0
  84. package/dist/providers/auth/qwen-userinfo-helper.js +72 -40
  85. package/dist/providers/auth/qwen-userinfo-helper.js.map +1 -1
  86. package/dist/providers/auth/tokenfile-auth.d.ts +2 -0
  87. package/dist/providers/auth/tokenfile-auth.js +163 -21
  88. package/dist/providers/auth/tokenfile-auth.js.map +1 -1
  89. package/dist/providers/core/api/provider-types.d.ts +10 -0
  90. package/dist/providers/core/config/camoufox-launcher.d.ts +3 -0
  91. package/dist/providers/core/config/camoufox-launcher.js +190 -3
  92. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  93. package/dist/providers/core/config/oauth-flows.js +50 -19
  94. package/dist/providers/core/config/oauth-flows.js.map +1 -1
  95. package/dist/providers/core/config/provider-oauth-configs.js +1 -1
  96. package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
  97. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +5 -0
  98. package/dist/providers/core/runtime/gemini-cli-http-provider.js +172 -15
  99. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  100. package/dist/providers/core/runtime/gemini-http-provider.d.ts +11 -0
  101. package/dist/providers/core/runtime/gemini-http-provider.js +281 -3
  102. package/dist/providers/core/runtime/gemini-http-provider.js.map +1 -1
  103. package/dist/providers/core/runtime/http-request-executor.js +55 -0
  104. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  105. package/dist/providers/core/runtime/http-transport-provider.js +10 -14
  106. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  107. package/dist/providers/core/runtime/provider-factory.d.ts +1 -0
  108. package/dist/providers/core/runtime/provider-factory.js +40 -2
  109. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  110. package/dist/providers/core/strategies/oauth-auth-code-flow.js +45 -2
  111. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  112. package/dist/providers/core/strategies/oauth-device-flow.js +13 -2
  113. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  114. package/dist/providers/core/strategies/oauth-refresh-errors.d.ts +1 -0
  115. package/dist/providers/core/strategies/oauth-refresh-errors.js +26 -0
  116. package/dist/providers/core/strategies/oauth-refresh-errors.js.map +1 -0
  117. package/dist/providers/core/utils/snapshot-writer.d.ts +4 -2
  118. package/dist/providers/core/utils/snapshot-writer.js +86 -23
  119. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  120. package/dist/scripts/camoufox/launch-auth.mjs +545 -49
  121. package/dist/server/handlers/chat-handler.js +1 -1
  122. package/dist/server/handlers/chat-handler.js.map +1 -1
  123. package/dist/server/handlers/handler-utils.d.ts +1 -0
  124. package/dist/server/handlers/handler-utils.js +231 -3
  125. package/dist/server/handlers/handler-utils.js.map +1 -1
  126. package/dist/server/handlers/messages-handler.js +1 -1
  127. package/dist/server/handlers/messages-handler.js.map +1 -1
  128. package/dist/server/handlers/responses-handler.js +17 -5
  129. package/dist/server/handlers/responses-handler.js.map +1 -1
  130. package/dist/server/handlers/sse-dispatcher.js +10 -1
  131. package/dist/server/handlers/sse-dispatcher.js.map +1 -1
  132. package/dist/server/runtime/http-server/daemon-admin/control-handler.d.ts +3 -0
  133. package/dist/server/runtime/http-server/daemon-admin/control-handler.js +389 -0
  134. package/dist/server/runtime/http-server/daemon-admin/control-handler.js.map +1 -0
  135. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +190 -5
  136. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
  137. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +2 -1
  138. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
  139. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +116 -14
  140. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -1
  141. package/dist/server/runtime/http-server/daemon-admin/routing-policy.d.ts +30 -0
  142. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +133 -0
  143. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -0
  144. package/dist/server/runtime/http-server/daemon-admin/status-handler.js +40 -1
  145. package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -1
  146. package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +5 -0
  147. package/dist/server/runtime/http-server/daemon-admin-routes.js +3 -0
  148. package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
  149. package/dist/server/runtime/http-server/executor-pipeline.d.ts +10 -0
  150. package/dist/server/runtime/http-server/executor-pipeline.js +6 -0
  151. package/dist/server/runtime/http-server/executor-pipeline.js.map +1 -1
  152. package/dist/server/runtime/http-server/executor-response.js +26 -0
  153. package/dist/server/runtime/http-server/executor-response.js.map +1 -1
  154. package/dist/server/runtime/http-server/hub-shadow-compare.js +41 -3
  155. package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
  156. package/dist/server/runtime/http-server/index.d.ts +9 -0
  157. package/dist/server/runtime/http-server/index.js +337 -91
  158. package/dist/server/runtime/http-server/index.js.map +1 -1
  159. package/dist/server/runtime/http-server/middleware.js +27 -1
  160. package/dist/server/runtime/http-server/middleware.js.map +1 -1
  161. package/dist/server/runtime/http-server/request-executor.js +159 -24
  162. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  163. package/dist/server/runtime/http-server/routes.d.ts +1 -0
  164. package/dist/server/runtime/http-server/routes.js +36 -3
  165. package/dist/server/runtime/http-server/routes.js.map +1 -1
  166. package/dist/server/runtime/http-server/server-id.d.ts +1 -0
  167. package/dist/server/runtime/http-server/server-id.js +18 -0
  168. package/dist/server/runtime/http-server/server-id.js.map +1 -0
  169. package/dist/server/runtime/http-server/stats-manager.d.ts +2 -0
  170. package/dist/server/runtime/http-server/stats-manager.js +63 -7
  171. package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
  172. package/dist/server/runtime/http-server/types.d.ts +2 -0
  173. package/dist/server/utils/stage-logger.js +54 -9
  174. package/dist/server/utils/stage-logger.js.map +1 -1
  175. package/dist/token-daemon/history-store.d.ts +8 -3
  176. package/dist/token-daemon/history-store.js +41 -20
  177. package/dist/token-daemon/history-store.js.map +1 -1
  178. package/dist/token-daemon/index.d.ts +5 -1
  179. package/dist/token-daemon/index.js +191 -11
  180. package/dist/token-daemon/index.js.map +1 -1
  181. package/dist/token-daemon/quota-auth-issue.d.ts +7 -0
  182. package/dist/token-daemon/quota-auth-issue.js +231 -0
  183. package/dist/token-daemon/quota-auth-issue.js.map +1 -0
  184. package/dist/token-daemon/token-daemon.d.ts +2 -0
  185. package/dist/token-daemon/token-daemon.js +177 -14
  186. package/dist/token-daemon/token-daemon.js.map +1 -1
  187. package/dist/token-portal/local-token-portal.js +6 -0
  188. package/dist/token-portal/local-token-portal.js.map +1 -1
  189. package/docs/ANTIGRAVITY_IDE_FORWARD_PROXY.md +61 -0
  190. package/docs/ANTIGRAVITY_THOUGHT_SIGNATURE_BOOTSTRAP_429.md +80 -0
  191. package/docs/CLOCK.md +94 -0
  192. package/docs/DAEMON_CONTROL_PLANE.md +34 -0
  193. package/docs/OAUTH.md +172 -0
  194. package/docs/PROVIDERS_BUILTIN.md +5 -3
  195. package/docs/PROVIDER_TYPES.md +6 -4
  196. package/docs/QUOTA_MANAGER_V3.md +54 -0
  197. package/docs/ROUTING_POLICY_SCHEMA.md +47 -0
  198. package/docs/ROUTING_POLICY_UI.md +11 -0
  199. package/docs/SERVERTOOL_CLOCK_DESIGN.md +56 -25
  200. package/docs/antigravity-routing-contract.md +17 -11
  201. package/docs/config-secrets.md +49 -0
  202. package/docs/daemon-admin-ui.html +1242 -234
  203. package/docs/oauth-authentication-guide.md +4 -0
  204. package/docs/oauth-iflow-implementation.md +4 -0
  205. package/docs/provider-quota-design.md +11 -0
  206. package/docs/providers/antigravity-gemini-provider-compat.md +1 -0
  207. package/docs/providers/antigravity-thought-signature.md +127 -0
  208. package/docs/providers/tabglm-claude-code-compat.md +11 -3
  209. package/docs/refactoring/host-sharedmodule-safe-migration-plan.md +164 -0
  210. package/docs/token-daemon-preview.html +2 -2
  211. package/docs/token-refresh-daemon-plan.md +6 -6
  212. package/package.json +4 -3
  213. package/scripts/antigravity-ide-forward-proxy.mjs +362 -0
  214. package/scripts/backfill-apply-patch-exec-errorsamples.mjs +19 -0
  215. package/scripts/camoufox/launch-auth.mjs +545 -49
  216. package/scripts/ci/repo-sanity.mjs +2 -0
  217. package/scripts/install-global.sh +46 -0
  218. package/scripts/migrate-antigravity-session-signatures-alias.mjs +193 -0
  219. package/scripts/migrate-antigravity-session-signatures.mjs +165 -0
  220. package/scripts/tests/blackbox-rcc-vs-routecodex-antigravity.mjs +44 -9
  221. package/scripts/tests/ci-jest.mjs +3 -0
  222. package/scripts/verify-client-headers.mjs +33 -5
  223. package/scripts/virtual-router-dryrun.mjs +333 -0
@@ -68,7 +68,9 @@ function checkRootLayout() {
68
68
  // Fixed top-level layout. Adding new root entries requires an explicit policy change.
69
69
  const allowed = new Set([
70
70
  'eslint.config.js',
71
+ '.beads',
71
72
  '.github',
73
+ '.gitattributes',
72
74
  '.gitignore',
73
75
  'AGENTS.md',
74
76
  'README.md',
@@ -135,12 +135,57 @@ global_install() {
135
135
  fi
136
136
  }
137
137
 
138
+ link_global_llms_dev() {
139
+ echo "🔗 链接全局 @jsonstudio/llms 到本地 sharedmodule (dev 模式)..."
140
+
141
+ local npm_prefix
142
+ local global_node_modules
143
+ npm_prefix=$(npm config get prefix)
144
+ global_node_modules=$(npm root -g 2>/dev/null || true)
145
+ if [ -z "${global_node_modules:-}" ]; then
146
+ global_node_modules="$npm_prefix/lib/node_modules"
147
+ fi
148
+
149
+ local global_routecodex
150
+ local local_llms
151
+ local global_llms_parent
152
+ local global_llms_link
153
+
154
+ global_routecodex="$global_node_modules/routecodex"
155
+ local_llms="$PWD/sharedmodule/llmswitch-core"
156
+ global_llms_parent="$global_routecodex/node_modules/@jsonstudio"
157
+ global_llms_link="$global_llms_parent/llms"
158
+
159
+ if [ ! -d "$global_routecodex" ]; then
160
+ echo "❌ 未找到全局 routecodex 安装目录: $global_routecodex"
161
+ exit 1
162
+ fi
163
+ if [ ! -d "$local_llms" ] || [ ! -f "$local_llms/package.json" ]; then
164
+ echo "❌ 未找到本地 llmswitch-core: $local_llms"
165
+ exit 1
166
+ fi
167
+ if [ ! -d "$local_llms/dist" ]; then
168
+ echo "❌ 本地 llmswitch-core 尚未构建 (缺少 dist/): $local_llms"
169
+ echo "💡 请先在 sharedmodule/llmswitch-core 执行 npm run build"
170
+ exit 1
171
+ fi
172
+
173
+ mkdir -p "$global_llms_parent"
174
+ rm -rf "$global_llms_link"
175
+ ln -s "$local_llms" "$global_llms_link"
176
+
177
+ local resolved_target
178
+ resolved_target=$(readlink "$global_llms_link" || true)
179
+ echo "✅ 全局 llms 已链接: $global_llms_link -> $resolved_target"
180
+ }
181
+
138
182
  # 验证安装
139
183
  verify_install() {
140
184
  echo "🔍 验证全局安装..."
141
185
  if command -v routecodex &> /dev/null; then
142
186
  echo "✅ routecodex 已全局安装"
143
187
  routecodex --version
188
+ node -e "const path=require('path');const cp=require('child_process');const root=cp.execSync('npm root -g').toString().trim();const pkg=path.join(root,'routecodex','node_modules','@jsonstudio','llms','package.json');const fs=require('fs');if(fs.existsSync(pkg)){const v=require(pkg).version;console.log('🔎 全局 @jsonstudio/llms 版本:',v);}else{console.log('⚠️ 未找到全局 @jsonstudio/llms package.json');}"
144
189
  else
145
190
  echo "❌ 全局安装失败(未找到 routecodex 命令)"
146
191
  exit 1
@@ -198,6 +243,7 @@ main() {
198
243
  cleanup_old_install
199
244
  build_project
200
245
  global_install
246
+ link_global_llms_dev
201
247
  verify_install
202
248
  verify_server_health
203
249
 
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ function usage() {
7
+ console.log(
8
+ [
9
+ 'Usage:',
10
+ ' node scripts/migrate-antigravity-session-signatures-alias.mjs [--file <path>] --from <aliasKey> --to <aliasKey> [--dry-run]',
11
+ '',
12
+ 'Defaults:',
13
+ ' --file ~/.routecodex/state/antigravity-session-signatures.json'
14
+ ].join('\n')
15
+ );
16
+ }
17
+
18
+ function parseArgs(argv) {
19
+ const out = { file: '', from: '', to: '', dryRun: false, help: false };
20
+ for (let i = 0; i < argv.length; i++) {
21
+ const arg = argv[i];
22
+ if (arg === '--help' || arg === '-h') {
23
+ out.help = true;
24
+ continue;
25
+ }
26
+ if (arg === '--dry-run') {
27
+ out.dryRun = true;
28
+ continue;
29
+ }
30
+ if (arg === '--file') {
31
+ out.file = String(argv[i + 1] || '');
32
+ i++;
33
+ continue;
34
+ }
35
+ if (arg === '--from') {
36
+ out.from = String(argv[i + 1] || '');
37
+ i++;
38
+ continue;
39
+ }
40
+ if (arg === '--to') {
41
+ out.to = String(argv[i + 1] || '');
42
+ i++;
43
+ continue;
44
+ }
45
+ if (arg.startsWith('--file=')) {
46
+ out.file = arg.slice('--file='.length);
47
+ continue;
48
+ }
49
+ if (arg.startsWith('--from=')) {
50
+ out.from = arg.slice('--from='.length);
51
+ continue;
52
+ }
53
+ if (arg.startsWith('--to=')) {
54
+ out.to = arg.slice('--to='.length);
55
+ continue;
56
+ }
57
+ }
58
+ return out;
59
+ }
60
+
61
+ function isRecord(value) {
62
+ return !!value && typeof value === 'object' && !Array.isArray(value);
63
+ }
64
+
65
+ function normalizeAliasKey(value) {
66
+ const raw = typeof value === 'string' ? value.trim().toLowerCase() : '';
67
+ return raw;
68
+ }
69
+
70
+ function nowStamp() {
71
+ const d = new Date();
72
+ const pad = (n) => String(n).padStart(2, '0');
73
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}T${pad(d.getHours())}${pad(d.getMinutes())}${pad(
74
+ d.getSeconds()
75
+ )}`;
76
+ }
77
+
78
+ async function main() {
79
+ const args = parseArgs(process.argv.slice(2));
80
+ if (args.help) {
81
+ usage();
82
+ process.exit(0);
83
+ }
84
+
85
+ const fromKey = normalizeAliasKey(args.from);
86
+ const toKey = normalizeAliasKey(args.to);
87
+ if (!fromKey || !toKey) {
88
+ console.error('[migrate-antigravity-signatures-alias] missing required flags: --from and --to');
89
+ usage();
90
+ process.exit(1);
91
+ }
92
+
93
+ const defaultFile = path.join(os.homedir(), '.routecodex', 'state', 'antigravity-session-signatures.json');
94
+ const filePath = path.resolve(args.file && args.file.trim().length ? args.file : defaultFile);
95
+
96
+ let parsed;
97
+ try {
98
+ parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
99
+ } catch (err) {
100
+ console.error(`[migrate-antigravity-signatures-alias] failed to read/parse: ${filePath}`);
101
+ console.error(err && err.message ? err.message : err);
102
+ process.exit(1);
103
+ }
104
+
105
+ if (!isRecord(parsed)) {
106
+ console.log(`[migrate-antigravity-signatures-alias] not an object; skip: ${filePath}`);
107
+ process.exit(0);
108
+ }
109
+
110
+ const sessionsRaw = parsed.sessions;
111
+ const sessions = isRecord(sessionsRaw) ? sessionsRaw : null;
112
+ const latestByAliasRaw = parsed.latestByAlias;
113
+ const latestByAlias = isRecord(latestByAliasRaw) ? latestByAliasRaw : null;
114
+
115
+ let rewrittenSessions = 0;
116
+ let rewrittenLatest = 0;
117
+
118
+ const nextSessions = {};
119
+ if (sessions) {
120
+ for (const [k, v] of Object.entries(sessions)) {
121
+ const key = typeof k === 'string' ? k.trim() : '';
122
+ if (!key) continue;
123
+ const parts = key.split('|');
124
+ if (parts.length >= 2) {
125
+ const alias = normalizeAliasKey(parts[0]);
126
+ const sid = parts.slice(1).join('|');
127
+ if (alias === fromKey) {
128
+ nextSessions[`${toKey}|${sid}`] = v;
129
+ rewrittenSessions++;
130
+ continue;
131
+ }
132
+ }
133
+ nextSessions[key] = v;
134
+ }
135
+ }
136
+
137
+ const nextLatestByAlias = {};
138
+ if (latestByAlias) {
139
+ for (const [k, v] of Object.entries(latestByAlias)) {
140
+ const alias = normalizeAliasKey(k);
141
+ if (!alias) continue;
142
+ if (alias === fromKey) {
143
+ nextLatestByAlias[toKey] = v;
144
+ rewrittenLatest++;
145
+ continue;
146
+ }
147
+ nextLatestByAlias[alias] = v;
148
+ }
149
+ }
150
+
151
+ const out = {
152
+ ...parsed,
153
+ ...(sessions ? { sessions: nextSessions } : {}),
154
+ ...(latestByAlias ? { latestByAlias: nextLatestByAlias } : {}),
155
+ updatedAt: Date.now()
156
+ };
157
+
158
+ console.log(`[migrate-antigravity-signatures-alias] file=${filePath}`);
159
+ console.log(`[migrate-antigravity-signatures-alias] from=${fromKey} to=${toKey}`);
160
+ console.log(`[migrate-antigravity-signatures-alias] rewritten sessions=${rewrittenSessions} latestByAlias=${rewrittenLatest}`);
161
+
162
+ if (args.dryRun) {
163
+ console.log('[migrate-antigravity-signatures-alias] dry-run: no files written');
164
+ process.exit(0);
165
+ }
166
+
167
+ const backupPath = `${filePath}.bak.${nowStamp()}`;
168
+ const tmpPath = `${filePath}.tmp.${process.pid}.${out.updatedAt}`;
169
+ try {
170
+ fs.copyFileSync(filePath, backupPath);
171
+ fs.writeFileSync(tmpPath, JSON.stringify(out, null, 2), 'utf8');
172
+ fs.renameSync(tmpPath, filePath);
173
+ } catch (err) {
174
+ try {
175
+ if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);
176
+ } catch {
177
+ // ignore
178
+ }
179
+ console.error('[migrate-antigravity-signatures-alias] write failed');
180
+ console.error(err && err.message ? err.message : err);
181
+ console.error(`[migrate-antigravity-signatures-alias] backup may exist at: ${backupPath}`);
182
+ process.exit(1);
183
+ }
184
+
185
+ console.log(`[migrate-antigravity-signatures-alias] backup: ${backupPath}`);
186
+ console.log('[migrate-antigravity-signatures-alias] done');
187
+ }
188
+
189
+ main().catch((err) => {
190
+ console.error(err && err.stack ? err.stack : err);
191
+ process.exit(1);
192
+ });
193
+
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ function usage() {
7
+ console.log(
8
+ [
9
+ 'Usage:',
10
+ ' node scripts/migrate-antigravity-session-signatures.mjs [--file <path>] [--alias <aliasKey>] [--dry-run]',
11
+ '',
12
+ 'Defaults:',
13
+ ' --file ~/.routecodex/state/antigravity-session-signatures.json',
14
+ ' --alias antigravity.unknown'
15
+ ].join('\n')
16
+ );
17
+ }
18
+
19
+ function parseArgs(argv) {
20
+ const out = { file: '', alias: 'antigravity.unknown', dryRun: false, help: false };
21
+ for (let i = 0; i < argv.length; i++) {
22
+ const arg = argv[i];
23
+ if (arg === '--help' || arg === '-h') {
24
+ out.help = true;
25
+ continue;
26
+ }
27
+ if (arg === '--dry-run') {
28
+ out.dryRun = true;
29
+ continue;
30
+ }
31
+ if (arg === '--file') {
32
+ out.file = String(argv[i + 1] || '');
33
+ i++;
34
+ continue;
35
+ }
36
+ if (arg === '--alias') {
37
+ out.alias = String(argv[i + 1] || '');
38
+ i++;
39
+ continue;
40
+ }
41
+ if (arg.startsWith('--file=')) {
42
+ out.file = arg.slice('--file='.length);
43
+ continue;
44
+ }
45
+ if (arg.startsWith('--alias=')) {
46
+ out.alias = arg.slice('--alias='.length);
47
+ continue;
48
+ }
49
+ }
50
+ return out;
51
+ }
52
+
53
+ function isRecord(value) {
54
+ return !!value && typeof value === 'object' && !Array.isArray(value);
55
+ }
56
+
57
+ function normalizeAliasKey(value) {
58
+ const raw = typeof value === 'string' ? value.trim() : '';
59
+ return raw.length ? raw.toLowerCase() : 'antigravity.unknown';
60
+ }
61
+
62
+ function nowStamp() {
63
+ const d = new Date();
64
+ const pad = (n) => String(n).padStart(2, '0');
65
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}T${pad(d.getHours())}${pad(d.getMinutes())}${pad(
66
+ d.getSeconds()
67
+ )}`;
68
+ }
69
+
70
+ async function main() {
71
+ const args = parseArgs(process.argv.slice(2));
72
+ if (args.help) {
73
+ usage();
74
+ process.exit(0);
75
+ }
76
+
77
+ const defaultFile = path.join(os.homedir(), '.routecodex', 'state', 'antigravity-session-signatures.json');
78
+ const filePath = path.resolve(args.file && args.file.trim().length ? args.file : defaultFile);
79
+ const aliasKey = normalizeAliasKey(args.alias);
80
+
81
+ let parsed;
82
+ try {
83
+ parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
84
+ } catch (err) {
85
+ console.error(`[migrate-antigravity-signatures] failed to read/parse: ${filePath}`);
86
+ console.error(err && err.message ? err.message : err);
87
+ process.exit(1);
88
+ }
89
+
90
+ const sessionsRaw = isRecord(parsed) ? parsed.sessions : undefined;
91
+ const sessions = isRecord(sessionsRaw) ? sessionsRaw : null;
92
+ if (!sessions) {
93
+ console.log(`[migrate-antigravity-signatures] no sessions found; skip: ${filePath}`);
94
+ process.exit(0);
95
+ }
96
+
97
+ const migratedSessions = {};
98
+ let migrated = 0;
99
+ let kept = 0;
100
+ for (const [key, entry] of Object.entries(sessions)) {
101
+ if (!key || typeof key !== 'string') continue;
102
+ const trimmed = key.trim();
103
+ if (!trimmed) continue;
104
+ const newKey = trimmed.includes('|') ? trimmed : `${aliasKey}|${trimmed}`;
105
+ if (newKey !== trimmed) migrated++;
106
+ else kept++;
107
+ migratedSessions[newKey] = entry;
108
+ }
109
+
110
+ const latestByAlias = {};
111
+ const latestByAliasRaw = isRecord(parsed) ? parsed.latestByAlias : undefined;
112
+ if (isRecord(latestByAliasRaw)) {
113
+ for (const [k, v] of Object.entries(latestByAliasRaw)) {
114
+ const ak = normalizeAliasKey(k);
115
+ latestByAlias[ak] = v;
116
+ }
117
+ } else if (isRecord(parsed) && isRecord(parsed.latest)) {
118
+ latestByAlias[aliasKey] = parsed.latest;
119
+ }
120
+
121
+ const updatedAt = Date.now();
122
+ const output = {
123
+ version: 2,
124
+ migratedAt: updatedAt,
125
+ updatedAt,
126
+ sessions: migratedSessions,
127
+ ...(Object.keys(latestByAlias).length ? { latestByAlias } : {})
128
+ };
129
+
130
+ const backupPath = `${filePath}.bak.${nowStamp()}`;
131
+ const tmpPath = `${filePath}.tmp.${process.pid}.${updatedAt}`;
132
+
133
+ console.log(`[migrate-antigravity-signatures] file=${filePath}`);
134
+ console.log(`[migrate-antigravity-signatures] alias=${aliasKey}`);
135
+ console.log(`[migrate-antigravity-signatures] sessions: migrated=${migrated} kept=${kept} total=${migrated + kept}`);
136
+
137
+ if (args.dryRun) {
138
+ console.log('[migrate-antigravity-signatures] dry-run: no files written');
139
+ process.exit(0);
140
+ }
141
+
142
+ try {
143
+ fs.copyFileSync(filePath, backupPath);
144
+ fs.writeFileSync(tmpPath, JSON.stringify(output, null, 2), 'utf8');
145
+ fs.renameSync(tmpPath, filePath);
146
+ } catch (err) {
147
+ try {
148
+ if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);
149
+ } catch {
150
+ // ignore
151
+ }
152
+ console.error('[migrate-antigravity-signatures] write failed');
153
+ console.error(err && err.message ? err.message : err);
154
+ console.error(`[migrate-antigravity-signatures] backup may exist at: ${backupPath}`);
155
+ process.exit(1);
156
+ }
157
+
158
+ console.log(`[migrate-antigravity-signatures] backup: ${backupPath}`);
159
+ console.log('[migrate-antigravity-signatures] done');
160
+ }
161
+
162
+ main().catch((err) => {
163
+ console.error(err && err.stack ? err.stack : err);
164
+ process.exit(1);
165
+ });
@@ -518,7 +518,8 @@ async function runOnceBlackbox(opts) {
518
518
  port,
519
519
  configPath,
520
520
  homeDir,
521
- antigravityApiBase
521
+ antigravityApiBase,
522
+ sessionId: sessionIdOverride
522
523
  } = opts;
523
524
 
524
525
  const env = {
@@ -567,6 +568,10 @@ async function runOnceBlackbox(opts) {
567
568
  try {
568
569
  await withTimeout(waitForHealth(baseUrl), 25000, `${label}:waitForHealth`);
569
570
 
571
+ const sessionId = typeof sessionIdOverride === 'string' && sessionIdOverride.trim().length
572
+ ? sessionIdOverride.trim()
573
+ : `bb-antigravity-session-${Date.now()}`;
574
+
570
575
  // 1) /v1/responses smoke (existing parity baseline)
571
576
  const res = await withTimeout(
572
577
  fetch(`${baseUrl}/v1/responses`, {
@@ -576,7 +581,7 @@ async function runOnceBlackbox(opts) {
576
581
  'Accept': 'application/json',
577
582
  'x-api-key': 'verify-key',
578
583
  'x-route-hint': 'thinking',
579
- 'x-session-id': 'bb-antigravity-session'
584
+ 'x-session-id': sessionId
580
585
  },
581
586
  body: JSON.stringify({
582
587
  model: 'gpt-5.2-codex',
@@ -627,7 +632,7 @@ async function runOnceBlackbox(opts) {
627
632
  'Accept': 'application/json',
628
633
  'x-api-key': 'verify-key',
629
634
  'x-route-hint': 'thinking',
630
- 'x-session-id': 'bb-antigravity-session'
635
+ 'x-session-id': sessionId
631
636
  },
632
637
  body: JSON.stringify({
633
638
  model: 'gpt-5.2-codex',
@@ -686,7 +691,7 @@ async function runOnceBlackbox(opts) {
686
691
  'Accept': 'application/json',
687
692
  'x-api-key': 'verify-key',
688
693
  'x-route-hint': 'thinking',
689
- 'x-session-id': 'bb-antigravity-session'
694
+ 'x-session-id': sessionId
690
695
  },
691
696
  body: JSON.stringify({
692
697
  model: 'gpt-5.2-codex',
@@ -730,7 +735,7 @@ async function runOnceBlackbox(opts) {
730
735
  'Accept': 'application/json',
731
736
  'x-api-key': 'verify-key',
732
737
  'x-route-hint': 'thinking',
733
- 'x-session-id': 'bb-antigravity-session'
738
+ 'x-session-id': sessionId
734
739
  },
735
740
  body: JSON.stringify({
736
741
  model: 'gpt-5.2-codex',
@@ -841,6 +846,7 @@ async function main() {
841
846
  port: 5591,
842
847
  configPath: cfg1,
843
848
  homeDir: tempDir,
849
+ sessionId: 'bb-antigravity-session-gemini',
844
850
  antigravityApiBase: upstream.baseUrl
845
851
  });
846
852
  const afterA = upstream.requests.length;
@@ -920,6 +926,7 @@ async function main() {
920
926
  port: 5593,
921
927
  configPath: cfgClaude,
922
928
  homeDir: tempDir,
929
+ sessionId: 'bb-antigravity-session-claude',
923
930
  antigravityApiBase: upstream.baseUrl
924
931
  });
925
932
  const afterC = upstream.requests.length;
@@ -943,8 +950,23 @@ async function main() {
943
950
  );
944
951
  const coldPresenceC = extractThoughtSignaturePresenceFromGeminiRequest(coldReqC);
945
952
  if (coldPresenceC.some(Boolean)) {
946
- safeWriteJson(path.join(tempDir, 'upstream.routecodex.claude.cold.json'), coldReqC);
947
- throw new Error(`routecodex (claude): cold followup unexpectedly contains thoughtSignature keys (captures in ${tempDir})`);
953
+ // New behavior (alias-scoped cache): if the previous run already primed a signature for this alias,
954
+ // the cold followup may immediately reuse it (with sessionId rewind handled in provider/runtime).
955
+ //
956
+ // Keep this deterministic: when present, it must be the mock signature (never the dummy sentinel).
957
+ const coldInjected = coldSigsC.includes(MOCK_THOUGHT_SIGNATURE);
958
+ if (!coldInjected) {
959
+ safeWriteJson(path.join(tempDir, 'upstream.routecodex.claude.cold.json'), coldReqC);
960
+ safeWriteJson(path.join(tempDir, 'debug.routecodex.claude.cold-signature.json'), {
961
+ expected: MOCK_THOUGHT_SIGNATURE,
962
+ got: coldSigsC,
963
+ firstUserText: getFirstUserTextFromGeminiRequest(coldReqC)
964
+ });
965
+ }
966
+ assert.ok(
967
+ coldInjected,
968
+ `routecodex (claude): cold followup signature mismatch (captures in ${tempDir})`
969
+ );
948
970
  }
949
971
 
950
972
  const sigsC = extractThoughtSignaturesFromGeminiRequest(followUpReqC).filter((s) => s);
@@ -1014,8 +1036,21 @@ async function main() {
1014
1036
  );
1015
1037
  const coldPresenceB = extractThoughtSignaturePresenceFromGeminiRequest(coldReqB);
1016
1038
  if (coldPresenceB.some(Boolean)) {
1017
- safeWriteJson(path.join(tempDir, 'upstream.rcc.cold.json'), coldReqB);
1018
- throw new Error(`rcc: cold followup unexpectedly contains thoughtSignature keys (captures in ${tempDir})`);
1039
+ // When the alias-scoped cache is already populated (e.g. by the routecodex run above),
1040
+ // the cold followup may immediately reuse the cached signature.
1041
+ const coldInjected = coldSigsB.includes(MOCK_THOUGHT_SIGNATURE);
1042
+ if (!coldInjected) {
1043
+ safeWriteJson(path.join(tempDir, 'upstream.rcc.cold.json'), coldReqB);
1044
+ safeWriteJson(path.join(tempDir, 'debug.rcc.cold-signature.json'), {
1045
+ expected: MOCK_THOUGHT_SIGNATURE,
1046
+ got: coldSigsB,
1047
+ firstUserText: getFirstUserTextFromGeminiRequest(coldReqB)
1048
+ });
1049
+ }
1050
+ assert.ok(
1051
+ coldInjected,
1052
+ `rcc: cold followup signature mismatch (captures in ${tempDir})`
1053
+ );
1019
1054
  }
1020
1055
  }
1021
1056
 
@@ -6,6 +6,9 @@ import process from 'node:process';
6
6
  // - Prefer pure unit tests / mock-provider tests (no external network).
7
7
  // - Expand coverage by adding more suites here (don’t run `jest --all` in CI).
8
8
  const routingInstructionTests = [
9
+ 'tests/token-daemon/interactive-refresh.spec.ts',
10
+ 'tests/token-daemon/token-daemon.auto-refresh-noninteractive.spec.ts',
11
+ 'tests/commands/oauth-command.qwen-auto.spec.ts',
9
12
  'tests/server/runtime/request-executor.single-attempt.spec.ts',
10
13
  'tests/server/runtime/executor-provider.retryable.spec.ts',
11
14
  'tests/providers/auth/tokenfile-auth.iflow.spec.ts',
@@ -1,12 +1,32 @@
1
1
  #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
2
3
  import path from 'node:path';
3
4
  import { fileURLToPath, pathToFileURL } from 'node:url';
4
5
 
5
6
  const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
6
7
 
7
- async function loadModule(relPath) {
8
- const modulePath = pathToFileURL(path.join(ROOT, relPath)).href;
9
- return import(modulePath);
8
+ async function loadModule(relPaths) {
9
+ const candidates = Array.isArray(relPaths) ? relPaths : [relPaths];
10
+ const errors = [];
11
+
12
+ for (const relPath of candidates) {
13
+ const absolutePath = path.join(ROOT, relPath);
14
+ try {
15
+ await fs.access(absolutePath);
16
+ } catch {
17
+ errors.push(`${relPath}: missing`);
18
+ continue;
19
+ }
20
+
21
+ try {
22
+ return await import(pathToFileURL(absolutePath).href);
23
+ } catch (error) {
24
+ const message = error instanceof Error ? error.message : String(error);
25
+ errors.push(`${relPath}: ${message}`);
26
+ }
27
+ }
28
+
29
+ throw new Error(`Unable to load module from dist candidates (${errors.join('; ')})`);
10
30
  }
11
31
 
12
32
  class RecordingHttpClient {
@@ -82,8 +102,16 @@ async function main() {
82
102
  }
83
103
  };
84
104
 
85
- const { HttpTransportProvider } = await loadModule('dist/providers/core/runtime/http-transport-provider.js');
86
- const { attachProviderRuntimeMetadata } = await loadModule('dist/providers/core/runtime/provider-runtime-metadata.js');
105
+ const { HttpTransportProvider } = await loadModule([
106
+ 'dist/providers/core/runtime/http-transport-provider.js',
107
+ 'dist/providers/core/runtime/http-transport-provider.mjs',
108
+ 'dist/providers/core/runtime/http-transport-provider/index.js'
109
+ ]);
110
+ const { attachProviderRuntimeMetadata } = await loadModule([
111
+ 'dist/providers/core/runtime/provider-runtime-metadata.js',
112
+ 'dist/providers/core/runtime/provider-runtime-metadata.mjs',
113
+ 'dist/providers/core/runtime/provider-runtime-metadata/index.js'
114
+ ]);
87
115
 
88
116
  class TestProvider extends HttpTransportProvider {
89
117
  createHttpClient() {