@jsonstudio/rcc 0.89.3 → 0.89.168

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 (284) hide show
  1. package/README.md +240 -179
  2. package/config/modules.json +1 -11
  3. package/dist/build-info.js +3 -3
  4. package/dist/build-info.js.map +1 -1
  5. package/dist/client/gemini-cli/gemini-cli-protocol-client.d.ts +16 -0
  6. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +56 -0
  7. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -0
  8. package/dist/client/openai/chat-protocol-client.js.map +1 -1
  9. package/dist/config/modules.json +1 -11
  10. package/dist/core/provider-health-manager.d.ts +17 -0
  11. package/dist/core/provider-health-manager.js +66 -0
  12. package/dist/core/provider-health-manager.js.map +1 -0
  13. package/dist/error-handling/route-error-hub.d.ts +48 -0
  14. package/dist/error-handling/route-error-hub.js +131 -0
  15. package/dist/error-handling/route-error-hub.js.map +1 -0
  16. package/dist/index.js +26 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/modules/llmswitch/bridge.d.ts +2 -0
  19. package/dist/modules/llmswitch/bridge.js +17 -0
  20. package/dist/modules/llmswitch/bridge.js.map +1 -1
  21. package/dist/modules/pipeline/utils/colored-logger.d.ts +14 -0
  22. package/dist/modules/pipeline/utils/colored-logger.js +48 -0
  23. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -0
  24. package/dist/modules/pipeline/utils/debug-logger.d.ts +2 -0
  25. package/dist/modules/pipeline/utils/debug-logger.js +36 -0
  26. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  27. package/dist/providers/auth/gemini-cli-userinfo-helper.d.ts +53 -0
  28. package/dist/providers/auth/gemini-cli-userinfo-helper.js +152 -0
  29. package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -0
  30. package/dist/providers/auth/oauth-auth.js +3 -2
  31. package/dist/providers/auth/oauth-auth.js.map +1 -1
  32. package/dist/providers/auth/oauth-lifecycle.js +21 -20
  33. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  34. package/dist/providers/auth/oauth-logger.d.ts +1 -0
  35. package/dist/providers/auth/oauth-logger.js +21 -0
  36. package/dist/providers/auth/oauth-logger.js.map +1 -0
  37. package/dist/providers/compat/compat-directory-loader.js +2 -55
  38. package/dist/providers/compat/compat-directory-loader.js.map +1 -1
  39. package/dist/providers/compat/compatibility-factory.d.ts +4 -4
  40. package/dist/providers/compat/compatibility-factory.js +108 -0
  41. package/dist/providers/compat/compatibility-factory.js.map +1 -1
  42. package/dist/providers/compat/glm/glm-compatibility.d.ts +2 -2
  43. package/dist/providers/compat/glm/glm-compatibility.js +7 -7
  44. package/dist/providers/compat/glm/glm-compatibility.js.map +1 -1
  45. package/dist/providers/compat/glm/index.js +0 -6
  46. package/dist/providers/compat/glm/index.js.map +1 -1
  47. package/dist/providers/compat/iflow/iflow-compatibility.d.ts +1 -1
  48. package/dist/providers/compat/iflow/iflow-compatibility.js +6 -6
  49. package/dist/providers/compat/iflow/iflow-compatibility.js.map +1 -1
  50. package/dist/providers/compat/index.d.ts +0 -6
  51. package/dist/providers/compat/index.js +0 -7
  52. package/dist/providers/compat/index.js.map +1 -1
  53. package/dist/providers/compat/lmstudio-compatibility.d.ts +2 -2
  54. package/dist/providers/compat/lmstudio-compatibility.js +4 -4
  55. package/dist/providers/compat/lmstudio-compatibility.js.map +1 -1
  56. package/dist/providers/compat/passthrough-compatibility.d.ts +1 -1
  57. package/dist/providers/compat/passthrough-compatibility.js +3 -3
  58. package/dist/providers/compat/passthrough-compatibility.js.map +1 -1
  59. package/dist/providers/compat/profiles/chat/glm/index.d.ts +6 -0
  60. package/dist/providers/compat/profiles/chat/glm/index.js +6 -0
  61. package/dist/providers/compat/profiles/chat/glm/index.js.map +1 -0
  62. package/dist/providers/compat/profiles/chat/iflow/index.d.ts +6 -0
  63. package/dist/providers/compat/profiles/chat/iflow/index.js +6 -0
  64. package/dist/providers/compat/profiles/chat/iflow/index.js.map +1 -0
  65. package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +6 -0
  66. package/dist/providers/compat/profiles/chat/lmstudio/index.js +6 -0
  67. package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +1 -0
  68. package/dist/providers/compat/profiles/chat/qwen/index.d.ts +6 -0
  69. package/dist/providers/compat/profiles/chat/qwen/index.js +6 -0
  70. package/dist/providers/compat/profiles/chat/qwen/index.js.map +1 -0
  71. package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +6 -0
  72. package/dist/providers/compat/profiles/compat/passthrough/index.js +6 -0
  73. package/dist/providers/compat/profiles/compat/passthrough/index.js.map +1 -0
  74. package/dist/providers/compat/profiles/responses/c4m/index.d.ts +6 -0
  75. package/dist/providers/compat/profiles/responses/c4m/index.js +6 -0
  76. package/dist/providers/compat/profiles/responses/c4m/index.js.map +1 -0
  77. package/dist/providers/compat/profiles/responses/default/index.d.ts +6 -0
  78. package/dist/providers/compat/profiles/responses/default/index.js +6 -0
  79. package/dist/providers/compat/profiles/responses/default/index.js.map +1 -0
  80. package/dist/providers/compat/profiles/responses/fai/index.d.ts +6 -0
  81. package/dist/providers/compat/profiles/responses/fai/index.js +6 -0
  82. package/dist/providers/compat/profiles/responses/fai/index.js.map +1 -0
  83. package/dist/providers/compat/profiles/responses/fc/index.d.ts +6 -0
  84. package/dist/providers/compat/profiles/responses/fc/index.js +6 -0
  85. package/dist/providers/compat/profiles/responses/fc/index.js.map +1 -0
  86. package/dist/providers/compat/qwen/index.js +0 -6
  87. package/dist/providers/compat/qwen/index.js.map +1 -1
  88. package/dist/providers/compat/qwen-compatibility.d.ts +2 -2
  89. package/dist/providers/compat/qwen-compatibility.js +4 -4
  90. package/dist/providers/compat/qwen-compatibility.js.map +1 -1
  91. package/dist/providers/compat/register-compat-module.d.ts +8 -0
  92. package/dist/providers/compat/register-compat-module.js +53 -0
  93. package/dist/providers/compat/register-compat-module.js.map +1 -0
  94. package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +6 -2
  95. package/dist/providers/compat/responses/c4m-responses-compatibility.js +85 -3
  96. package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +1 -1
  97. package/dist/providers/compat/standard-compatibility-utils.js +45 -15
  98. package/dist/providers/compat/standard-compatibility-utils.js.map +1 -1
  99. package/dist/providers/core/api/provider-config.d.ts +1 -1
  100. package/dist/providers/core/api/provider-types.d.ts +3 -1
  101. package/dist/providers/core/api/provider-types.js +1 -0
  102. package/dist/providers/core/api/provider-types.js.map +1 -1
  103. package/dist/providers/core/config/service-profiles.js +19 -2
  104. package/dist/providers/core/config/service-profiles.js.map +1 -1
  105. package/dist/providers/core/runtime/base-provider.d.ts +8 -0
  106. package/dist/providers/core/runtime/base-provider.js +79 -36
  107. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  108. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +33 -0
  109. package/dist/providers/core/runtime/gemini-cli-http-provider.js +156 -0
  110. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -0
  111. package/dist/providers/core/runtime/gemini-http-provider.d.ts +1 -2
  112. package/dist/providers/core/runtime/gemini-http-provider.js +0 -12
  113. package/dist/providers/core/runtime/gemini-http-provider.js.map +1 -1
  114. package/dist/providers/core/runtime/http-request-executor.d.ts +42 -0
  115. package/dist/providers/core/runtime/http-request-executor.js +133 -0
  116. package/dist/providers/core/runtime/http-request-executor.js.map +1 -0
  117. package/dist/providers/core/runtime/http-transport-provider.d.ts +7 -11
  118. package/dist/providers/core/runtime/http-transport-provider.js +226 -371
  119. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  120. package/dist/providers/core/runtime/provider-error-classifier.d.ts +25 -0
  121. package/dist/providers/core/runtime/provider-error-classifier.js +139 -0
  122. package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -0
  123. package/dist/providers/core/runtime/provider-error-types.d.ts +23 -0
  124. package/dist/providers/core/runtime/provider-error-types.js +2 -0
  125. package/dist/providers/core/runtime/provider-error-types.js.map +1 -0
  126. package/dist/providers/core/runtime/provider-factory.d.ts +1 -1
  127. package/dist/providers/core/runtime/provider-factory.js +14 -0
  128. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  129. package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +1 -0
  130. package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
  131. package/dist/providers/core/runtime/responses-provider.d.ts +7 -0
  132. package/dist/providers/core/runtime/responses-provider.js +228 -12
  133. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  134. package/dist/providers/core/strategies/oauth-auth-code-flow.js +10 -9
  135. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  136. package/dist/providers/core/strategies/oauth-device-flow.js +10 -9
  137. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  138. package/dist/providers/core/utils/provider-error-reporter.js +63 -15
  139. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  140. package/dist/providers/core/utils/provider-type-utils.d.ts +1 -1
  141. package/dist/providers/core/utils/provider-type-utils.js +6 -1
  142. package/dist/providers/core/utils/provider-type-utils.js.map +1 -1
  143. package/dist/providers/core/utils/snapshot-writer.d.ts +10 -0
  144. package/dist/providers/core/utils/snapshot-writer.js +85 -0
  145. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  146. package/dist/providers/mock/mock-provider-runtime.js +44 -0
  147. package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
  148. package/dist/providers/profile/provider-profile-loader.js +26 -19
  149. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  150. package/dist/providers/profile/provider-profile.d.ts +2 -2
  151. package/dist/server/handlers/chat-handler.js +9 -3
  152. package/dist/server/handlers/chat-handler.js.map +1 -1
  153. package/dist/server/handlers/handler-utils.d.ts +7 -1
  154. package/dist/server/handlers/handler-utils.js +64 -52
  155. package/dist/server/handlers/handler-utils.js.map +1 -1
  156. package/dist/server/handlers/messages-handler.js +9 -3
  157. package/dist/server/handlers/messages-handler.js.map +1 -1
  158. package/dist/server/handlers/responses-handler.js +21 -13
  159. package/dist/server/handlers/responses-handler.js.map +1 -1
  160. package/dist/server/runtime/http-server/colored-logger.d.ts +1 -0
  161. package/dist/server/runtime/http-server/colored-logger.js +33 -0
  162. package/dist/server/runtime/http-server/colored-logger.js.map +1 -0
  163. package/dist/server/runtime/http-server/index.d.ts +3 -0
  164. package/dist/server/runtime/http-server/index.js +76 -19
  165. package/dist/server/runtime/http-server/index.js.map +1 -1
  166. package/dist/server/runtime/http-server/provider-utils.d.ts +3 -1
  167. package/dist/server/runtime/http-server/provider-utils.js +12 -2
  168. package/dist/server/runtime/http-server/provider-utils.js.map +1 -1
  169. package/dist/server/runtime/http-server/request-executor.js +6 -2
  170. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  171. package/dist/server/runtime/http-server/routes.js +31 -11
  172. package/dist/server/runtime/http-server/routes.js.map +1 -1
  173. package/dist/server/runtime/http-server/types.d.ts +2 -1
  174. package/dist/utils/error-center-payload.d.ts +7 -0
  175. package/dist/utils/error-center-payload.js +67 -0
  176. package/dist/utils/error-center-payload.js.map +1 -0
  177. package/dist/utils/error-handler-registry.d.ts +7 -0
  178. package/dist/utils/error-handler-registry.js +44 -12
  179. package/dist/utils/error-handler-registry.js.map +1 -1
  180. package/node_modules/@jsonstudio/llms/dist/conversion/codecs/responses-openai-codec.js +16 -1
  181. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +17 -0
  182. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +36 -0
  183. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +37 -0
  184. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +18 -0
  185. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +45 -0
  186. package/node_modules/@jsonstudio/llms/dist/conversion/config/compat-profiles.json +38 -0
  187. package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +314 -0
  188. package/node_modules/@jsonstudio/llms/dist/conversion/config/version-switch.json +150 -0
  189. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +4 -0
  190. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +667 -0
  191. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.d.ts +2 -0
  192. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.js +76 -0
  193. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +62 -0
  194. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.js +1 -0
  195. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
  196. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +110 -29
  197. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.d.ts +14 -0
  198. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +23 -0
  199. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +34 -0
  200. package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +4 -1
  201. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +26 -0
  202. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.d.ts +1 -0
  203. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +71 -0
  204. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.d.ts +35 -0
  205. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.js +64 -19
  206. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.d.ts +21 -0
  207. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +138 -22
  208. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.d.ts +21 -0
  209. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.js +116 -1
  210. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +52 -2
  211. package/node_modules/@jsonstudio/llms/dist/filters/config/openai-openai.fieldmap.json +18 -0
  212. package/node_modules/@jsonstudio/llms/dist/filters/special/request-tools-normalize.js +20 -1
  213. package/node_modules/@jsonstudio/llms/dist/guidance/index.js +6 -2
  214. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +16 -7
  215. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +40 -37
  216. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.d.ts +1 -0
  217. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.js +13 -0
  218. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +39 -0
  219. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +52 -11
  220. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +340 -11
  221. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.d.ts +2 -0
  222. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +105 -0
  223. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +8 -0
  224. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +2 -2
  225. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.d.ts +2 -0
  226. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +53 -11
  227. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/results.json +1 -0
  228. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/summary.json +12 -0
  229. package/node_modules/@jsonstudio/llms/dist/tools/tool-registry.js +4 -3
  230. package/node_modules/@jsonstudio/llms/package.json +3 -3
  231. package/package.json +13 -10
  232. package/scripts/analyze-routing-classifier.mjs +166 -0
  233. package/scripts/analyze-routing-samples.mjs +216 -0
  234. package/scripts/analyze-thinking-keywords.mjs +17 -2
  235. package/scripts/build-core.mjs +8 -0
  236. package/scripts/classify-sample-tools.mjs +252 -0
  237. package/scripts/ensure-llmswitch-mode.mjs +95 -0
  238. package/scripts/gen-build-info.mjs +58 -4
  239. package/scripts/install-global.sh +1 -1
  240. package/scripts/install-release.sh +7 -0
  241. package/scripts/mock-provider/run-regressions.mjs +60 -14
  242. package/scripts/pack-mode.mjs +30 -1
  243. package/scripts/publish-rcc.mjs +31 -0
  244. package/scripts/tests/apply-patch-loop.mjs +100 -9
  245. package/scripts/tests/golden-provider-cycle.mjs +12 -1
  246. package/scripts/tests/responses-provider-dry-run.mjs +15 -1
  247. package/scripts/tests/virtual-router-health.mjs +12 -5
  248. package/scripts/tools/capture-provider-goldens.mjs +75 -25
  249. package/scripts/tools/responses-golden-dry-run.mjs +17 -1
  250. package/scripts/tools/responses-provider-replay.mjs +17 -1
  251. package/scripts/tools/sync-ci-goldens.mjs +131 -0
  252. package/scripts/verification/samples/openai-chat-list-local-files.json +19 -796
  253. package/scripts/verify-e2e-toolcall.mjs +52 -0
  254. package/dist/providers/compat/config/index.d.ts +0 -1
  255. package/dist/providers/compat/config/index.js +0 -5
  256. package/dist/providers/compat/config/index.js.map +0 -1
  257. package/dist/providers/compat/iflow/index.d.ts +0 -27
  258. package/dist/providers/compat/iflow/index.js +0 -32
  259. package/dist/providers/compat/iflow/index.js.map +0 -1
  260. package/dist/providers/compat/lmstudio/index.d.ts +0 -4
  261. package/dist/providers/compat/lmstudio/index.js +0 -10
  262. package/dist/providers/compat/lmstudio/index.js.map +0 -1
  263. package/dist/providers/compat/passthrough/index.d.ts +0 -4
  264. package/dist/providers/compat/passthrough/index.js +0 -9
  265. package/dist/providers/compat/passthrough/index.js.map +0 -1
  266. package/dist/providers/compat/responses/index.d.ts +0 -1
  267. package/dist/providers/compat/responses/index.js +0 -8
  268. package/dist/providers/compat/responses/index.js.map +0 -1
  269. package/dist/providers/core/composite/compat/anthropic.d.ts +0 -3
  270. package/dist/providers/core/composite/compat/anthropic.js +0 -7
  271. package/dist/providers/core/composite/compat/anthropic.js.map +0 -1
  272. package/dist/providers/core/composite/compat/gemini.d.ts +0 -3
  273. package/dist/providers/core/composite/compat/gemini.js +0 -7
  274. package/dist/providers/core/composite/compat/gemini.js.map +0 -1
  275. package/dist/providers/core/composite/compat/openai-compat-aggregator.d.ts +0 -9
  276. package/dist/providers/core/composite/compat/openai-compat-aggregator.js +0 -135
  277. package/dist/providers/core/composite/compat/openai-compat-aggregator.js.map +0 -1
  278. package/dist/providers/core/composite/compat/responses.d.ts +0 -3
  279. package/dist/providers/core/composite/compat/responses.js +0 -91
  280. package/dist/providers/core/composite/compat/responses.js.map +0 -1
  281. package/dist/providers/core/composite/provider-composite.d.ts +0 -50
  282. package/dist/providers/core/composite/provider-composite.js +0 -235
  283. package/dist/providers/core/composite/provider-composite.js.map +0 -1
  284. package/scripts/tests/apply-patch-loop.mjs.bak +0 -363
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+
6
+ const suffix = '_req_process_tool_filters_request_pre.json';
7
+ const sampleRoot = process.argv[2] || path.join(os.homedir(), '.routecodex', 'codex-samples');
8
+
9
+ const SHELL_PATTERNS = {
10
+ read: [
11
+ 'ls',
12
+ 'dir ',
13
+ 'pwd',
14
+ 'cat ',
15
+ 'type ',
16
+ 'head ',
17
+ 'tail ',
18
+ 'stat',
19
+ 'tree',
20
+ 'wc ',
21
+ 'du ',
22
+ 'printf "',
23
+ 'python - <<',
24
+ 'python -c',
25
+ 'node - <<',
26
+ 'node -e',
27
+ 'codesign --display'
28
+ ],
29
+ search: [
30
+ 'rg ',
31
+ 'rg-',
32
+ 'grep ',
33
+ 'grep-',
34
+ 'ripgrep',
35
+ 'find ',
36
+ 'fd ',
37
+ 'locate ',
38
+ 'search ',
39
+ 'codesearch',
40
+ 'ack ',
41
+ 'ag ',
42
+ 'where ',
43
+ 'which '
44
+ ],
45
+ write: [
46
+ 'apply_patch',
47
+ 'sed -i',
48
+ 'perl -pi',
49
+ 'tee ',
50
+ 'cat <<',
51
+ 'cat >',
52
+ 'printf >',
53
+ 'touch ',
54
+ 'truncate',
55
+ 'mkdir',
56
+ 'mktemp',
57
+ 'rmdir',
58
+ 'rm ',
59
+ 'rm -',
60
+ 'unlink',
61
+ 'mv ',
62
+ 'cp ',
63
+ 'ln -',
64
+ 'chmod',
65
+ 'chown',
66
+ 'chgrp',
67
+ 'tar xf',
68
+ 'tar cf',
69
+ 'git add',
70
+ 'git commit',
71
+ 'git apply',
72
+ 'git am',
73
+ 'git rebase',
74
+ 'git checkout',
75
+ 'git merge',
76
+ 'patch <<',
77
+ 'npm install',
78
+ 'pnpm install',
79
+ 'yarn add',
80
+ 'yarn install',
81
+ 'pip install',
82
+ 'pip3 install',
83
+ 'brew install',
84
+ 'cargo add',
85
+ 'cargo install',
86
+ 'go install',
87
+ 'make install'
88
+ ]
89
+ };
90
+
91
+ function canonicalizeToolName(name) {
92
+ if (!name) return '';
93
+ const trimmed = name.trim();
94
+ const idx = trimmed.indexOf('arg_');
95
+ if (idx > 0) return trimmed.slice(0, idx);
96
+ return trimmed;
97
+ }
98
+
99
+ function normalizeCommand(cmd) {
100
+ if (!cmd) return '';
101
+ if (Array.isArray(cmd)) return cmd.join(' ');
102
+ if (typeof cmd === 'object') {
103
+ if (cmd.command) return normalizeCommand(cmd.command);
104
+ if (cmd.args) return normalizeCommand(cmd.args);
105
+ try {
106
+ return JSON.stringify(cmd);
107
+ } catch {
108
+ return String(cmd);
109
+ }
110
+ }
111
+ return String(cmd || '').trim();
112
+ }
113
+
114
+ function detectCategory(tool, cmd) {
115
+ if (!tool) return 'other';
116
+ const lowTool = tool.toLowerCase();
117
+ if (lowTool === 'apply_patch') return 'write';
118
+ if (lowTool === 'describe_current_request') return 'read';
119
+ if (lowTool === 'list_mcp_resources' || lowTool === 'list_mcp_tools') return 'other';
120
+ if (lowTool === 'update_plan') return 'other';
121
+
122
+ const normalizedCmd = cmd.toLowerCase();
123
+ if (lowTool === 'shell_command' || lowTool === 'shell' || lowTool === 'bash') {
124
+ return detectShellCommandCategory(normalizedCmd);
125
+ }
126
+ if (matchesAny(normalizedCmd, SHELL_PATTERNS.write)) return 'write';
127
+ if (matchesAny(normalizedCmd, SHELL_PATTERNS.search)) return 'search';
128
+ if (matchesAny(normalizedCmd, SHELL_PATTERNS.read)) return 'read';
129
+ return 'other';
130
+ }
131
+
132
+ function detectShellCommandCategory(cmd) {
133
+ if (!cmd) return 'other';
134
+ const segments = splitCommandSegments(cmd);
135
+ if (segments.some((seg) => matchesAny(seg, SHELL_PATTERNS.write))) return 'write';
136
+ if (segments.some((seg) => matchesAny(seg, SHELL_PATTERNS.search))) return 'search';
137
+ if (segments.some((seg) => matchesAny(seg, SHELL_PATTERNS.read))) return 'read';
138
+ return 'other';
139
+ }
140
+
141
+ function splitCommandSegments(cmd) {
142
+ return cmd
143
+ .split(/[\n;&]+/)
144
+ .map((segment) => segment.trim())
145
+ .filter(Boolean);
146
+ }
147
+
148
+ function matchesAny(text, patterns) {
149
+ const lower = text.toLowerCase();
150
+ return patterns.some((pattern) => lower.includes(pattern.toLowerCase()));
151
+ }
152
+
153
+ async function listCandidateFiles(dir) {
154
+ const entries = await fs.readdir(dir, { withFileTypes: true });
155
+ const out = [];
156
+ for (const entry of entries) {
157
+ const full = path.join(dir, entry.name);
158
+ if (entry.isDirectory()) {
159
+ out.push(...(await listCandidateFiles(full)));
160
+ } else if (entry.isFile() && entry.name.endsWith(suffix)) {
161
+ out.push(full);
162
+ }
163
+ }
164
+ return out;
165
+ }
166
+
167
+ function extractRequestKey(filePath) {
168
+ const base = path.basename(filePath);
169
+ const match = base.match(/^(req_\d+_[^_]+)/);
170
+ return match ? match[1] : base;
171
+ }
172
+
173
+ function ensureSummary(summary, tool) {
174
+ if (!summary.has(tool)) {
175
+ summary.set(tool, {
176
+ total: 0,
177
+ categories: { read: 0, write: 0, search: 0, other: 0 },
178
+ samples: []
179
+ });
180
+ }
181
+ return summary.get(tool);
182
+ }
183
+
184
+ function recordSample(summary, tool, category, command, filePath) {
185
+ const item = ensureSummary(summary, tool);
186
+ item.total += 1;
187
+ item.categories[category] += 1;
188
+ if (item.samples.length < 5) {
189
+ item.samples.push({ category, command, file: path.basename(filePath) });
190
+ }
191
+ }
192
+
193
+ async function main() {
194
+ const protocols = await fs.readdir(sampleRoot, { withFileTypes: true });
195
+ const files = [];
196
+ for (const proto of protocols) {
197
+ if (!proto.isDirectory()) continue;
198
+ const dir = path.join(sampleRoot, proto.name);
199
+ const protoFiles = await listCandidateFiles(dir);
200
+ files.push(...protoFiles);
201
+ }
202
+ files.sort((a, b) => a.localeCompare(b));
203
+ const summary = new Map();
204
+ const processedRequests = new Set();
205
+ for (const filePath of files) {
206
+ const reqKey = extractRequestKey(filePath);
207
+ if (processedRequests.has(reqKey)) {
208
+ continue;
209
+ }
210
+ processedRequests.add(reqKey);
211
+ let data;
212
+ try {
213
+ const raw = await fs.readFile(filePath, 'utf8');
214
+ data = JSON.parse(raw);
215
+ } catch {
216
+ continue;
217
+ }
218
+ const messages = Array.isArray(data?.messages) ? data.messages : [];
219
+ for (const msg of messages) {
220
+ if (!msg || msg.role !== 'assistant') continue;
221
+ if (!Array.isArray(msg.tool_calls)) continue;
222
+ for (const call of msg.tool_calls) {
223
+ const name = canonicalizeToolName(call?.function?.name || call?.name || '');
224
+ if (!name) continue;
225
+ let parsedArgs;
226
+ if (typeof call?.function?.arguments === 'string') {
227
+ try {
228
+ parsedArgs = JSON.parse(call.function.arguments);
229
+ } catch {
230
+ parsedArgs = undefined;
231
+ }
232
+ } else if (call?.function?.arguments && typeof call.function.arguments === 'object') {
233
+ parsedArgs = call.function.arguments;
234
+ }
235
+ const command = normalizeCommand(parsedArgs?.command || parsedArgs?.input || parsedArgs?.args || parsedArgs);
236
+ const category = detectCategory(name, command);
237
+ recordSample(summary, name, category, command, filePath);
238
+ }
239
+ }
240
+ }
241
+
242
+ const result = Array.from(summary.entries())
243
+ .map(([name, info]) => ({ name, ...info }))
244
+ .sort((a, b) => b.total - a.total);
245
+
246
+ console.log(JSON.stringify({ sampleRoot, toolCount: result.length, tools: result }, null, 2));
247
+ }
248
+
249
+ main().catch((err) => {
250
+ console.error('Failed to classify tools:', err);
251
+ process.exit(1);
252
+ });
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
9
+
10
+ const rawMode = String(process.env.BUILD_MODE || process.env.RCC_BUILD_MODE || 'release').toLowerCase();
11
+ const mode = rawMode === 'dev' ? 'dev' : 'release';
12
+
13
+ const sharedCoreDir = path.join(PROJECT_ROOT, 'sharedmodule', 'llmswitch-core');
14
+ const nodeModulesScope = path.join(PROJECT_ROOT, 'node_modules', '@jsonstudio');
15
+ const llmsPath = path.join(nodeModulesScope, 'llms');
16
+
17
+ function runNodeScript(relativePath, args = []) {
18
+ const scriptPath = path.join(PROJECT_ROOT, relativePath);
19
+ const res = spawnSync(process.execPath, [scriptPath, ...args], { stdio: 'inherit' });
20
+ if ((res.status ?? 0) !== 0) {
21
+ process.exit(res.status ?? 2);
22
+ }
23
+ }
24
+
25
+ function isSymlink(p) {
26
+ try {
27
+ return fs.lstatSync(p).isSymbolicLink();
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ function readLink(p) {
34
+ try {
35
+ return fs.readlinkSync(p);
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function exists(p) {
42
+ try {
43
+ fs.accessSync(p);
44
+ return true;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ function ensureDevLink() {
51
+ if (!exists(sharedCoreDir)) {
52
+ console.error(`[llmswitch:ensure] BUILD_MODE=dev 但未找到 ${sharedCoreDir}`);
53
+ console.error('[llmswitch:ensure] 请先 clone sharedmodule/llmswitch-core,或改用 BUILD_MODE=release');
54
+ process.exit(2);
55
+ }
56
+ if (isSymlink(llmsPath)) {
57
+ const target = readLink(llmsPath);
58
+ if (target) {
59
+ const resolved = path.resolve(nodeModulesScope, target);
60
+ const expected = path.resolve(sharedCoreDir);
61
+ if (resolved === expected) {
62
+ console.log('[llmswitch:ensure] dev link ok: node_modules/@jsonstudio/llms -> sharedmodule/llmswitch-core');
63
+ return;
64
+ }
65
+ }
66
+ }
67
+ console.log('[llmswitch:ensure] linking dev core: node_modules/@jsonstudio/llms -> sharedmodule/llmswitch-core');
68
+ runNodeScript('scripts/link-llmswitch.mjs');
69
+ }
70
+
71
+ function ensureReleasePackage() {
72
+ if (isSymlink(llmsPath)) {
73
+ console.log('[llmswitch:ensure] release mode: unlinking node_modules/@jsonstudio/llms symlink');
74
+ runNodeScript('scripts/link-llmswitch.mjs', ['unlink']);
75
+ }
76
+ const pkgPath = path.join(llmsPath, 'package.json');
77
+ if (!exists(pkgPath)) {
78
+ console.log('[llmswitch:ensure] BUILD_MODE=release: installing @jsonstudio/llms via npm (missing in node_modules)');
79
+ const res = spawnSync('npm', ['install', '--no-audit', '--no-fund'], { cwd: PROJECT_ROOT, stdio: 'inherit' });
80
+ if ((res.status ?? 0) !== 0) {
81
+ process.exit(res.status ?? 2);
82
+ }
83
+ if (!exists(pkgPath)) {
84
+ console.error('[llmswitch:ensure] npm install completed but @jsonstudio/llms is still missing');
85
+ process.exit(2);
86
+ }
87
+ }
88
+ console.log('[llmswitch:ensure] release package ok: using npm-installed @jsonstudio/llms');
89
+ }
90
+
91
+ if (mode === 'dev') {
92
+ ensureDevLink();
93
+ } else {
94
+ ensureReleasePackage();
95
+ }
@@ -4,16 +4,32 @@ import path from 'node:path';
4
4
 
5
5
  const cwd = process.cwd();
6
6
  const pkgPath = path.join(cwd, 'package.json');
7
+ const lockPath = path.join(cwd, 'package-lock.json');
7
8
  const outPath = path.join(cwd, 'src', 'build-info.ts');
8
9
 
9
10
  const mode = String(process.env.BUILD_MODE || process.env.RCC_BUILD_MODE || 'release').toLowerCase();
10
11
  const valid = new Set(['dev', 'release']);
11
12
  const buildMode = valid.has(mode) ? mode : 'release';
12
13
 
13
- let version = '0.0.0';
14
- try {
15
- version = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version || version;
16
- } catch {}
14
+ const skipAutoBump = ['1', 'true', 'yes'].includes(
15
+ String(process.env.ROUTECODEX_SKIP_AUTO_BUMP || process.env.BUILD_SKIP_AUTO_BUMP || '').trim().toLowerCase()
16
+ );
17
+
18
+ const pkg = readJson(pkgPath);
19
+ let version = typeof pkg?.version === 'string' ? pkg.version : '0.0.0';
20
+
21
+ if (!skipAutoBump) {
22
+ const nextVersion = bumpPatchVersion(version);
23
+ if (nextVersion !== version) {
24
+ version = nextVersion;
25
+ if (pkg) {
26
+ pkg.version = nextVersion;
27
+ writeJson(pkgPath, pkg);
28
+ updatePackageLock(lockPath, nextVersion);
29
+ console.log(`[build-info] auto-bump version → ${nextVersion}`);
30
+ }
31
+ }
32
+ }
17
33
 
18
34
  const content = `// Auto-generated by scripts/gen-build-info.mjs
19
35
  export interface BuildInfo { mode: 'dev' | 'release'; version: string; buildTime: string }
@@ -28,3 +44,41 @@ fs.mkdirSync(path.dirname(outPath), { recursive: true });
28
44
  fs.writeFileSync(outPath, content, 'utf-8');
29
45
  console.log(`[build-info] mode=${buildMode} version=${version} → ${outPath}`);
30
46
 
47
+ function readJson(targetPath) {
48
+ try {
49
+ return JSON.parse(fs.readFileSync(targetPath, 'utf-8'));
50
+ } catch {
51
+ return undefined;
52
+ }
53
+ }
54
+
55
+ function writeJson(targetPath, data) {
56
+ fs.writeFileSync(targetPath, `${JSON.stringify(data, null, 2)}\n`, 'utf-8');
57
+ }
58
+
59
+ function bumpPatchVersion(input) {
60
+ if (!input || typeof input !== 'string') {
61
+ return '0.0.001';
62
+ }
63
+ const segments = input.split('.');
64
+ while (segments.length < 3) {
65
+ segments.push('0');
66
+ }
67
+ const [major, minor, patchRaw] = segments;
68
+ const parsedPatch = Number.parseInt(patchRaw, 10);
69
+ const nextPatch = Number.isFinite(parsedPatch) ? parsedPatch + 1 : 1;
70
+ const formattedPatch = String(nextPatch).padStart(3, '0');
71
+ return `${major}.${minor}.${formattedPatch}`;
72
+ }
73
+
74
+ function updatePackageLock(targetPath, version) {
75
+ const lock = readJson(targetPath);
76
+ if (!lock) {
77
+ return;
78
+ }
79
+ lock.version = version;
80
+ if (lock.packages && lock.packages['']) {
81
+ lock.packages[''].version = version;
82
+ }
83
+ writeJson(targetPath, lock);
84
+ }
@@ -82,7 +82,7 @@ build_project() {
82
82
  # 构建项目
83
83
  echo "🔨 编译TypeScript..."
84
84
  # dev 包:显式使用 BUILD_MODE=dev 以便在编译期区分 dev/release
85
- BUILD_MODE=dev timeout 300 npm run build || {
85
+ BUILD_MODE=dev ROUTECODEX_SKIP_AUTO_BUMP=1 timeout 300 npm run build || {
86
86
  echo "❌ 构建超时或失败"
87
87
  echo "💡 尝试手动构建:npm run build"
88
88
  exit 1
@@ -18,6 +18,13 @@ echo "🔨 构建源码..."
18
18
  # release 包:显式使用 BUILD_MODE=release 以便在编译期区分 dev/release
19
19
  BUILD_MODE=release npm run build
20
20
 
21
+ # 构建过程可能自动 bump 版本号,因此需要重新读取
22
+ NEW_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "${VERSION}")
23
+ if [ "${NEW_VERSION}" != "${VERSION}" ]; then
24
+ echo "ℹ️ 构建后版本变更: ${VERSION} → ${NEW_VERSION}"
25
+ VERSION=${NEW_VERSION}
26
+ fi
27
+
21
28
  TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/rcc-release.XXXXXX")
22
29
  TARBALL="routecodex-${VERSION}.tgz"
23
30
 
@@ -23,7 +23,7 @@ function resolveSamplesDir() {
23
23
  }
24
24
 
25
25
  function parseEntryFilter() {
26
- const raw = String(process.env.ROUTECODEX_MOCK_ENTRY_FILTER || 'openai-chat').trim();
26
+ const raw = String(process.env.ROUTECODEX_MOCK_ENTRY_FILTER || 'openai-chat,openai-responses').trim();
27
27
  if (!raw || raw.toLowerCase() === 'all') {
28
28
  return null;
29
29
  }
@@ -57,15 +57,23 @@ async function loadRegistry() {
57
57
  });
58
58
  }
59
59
 
60
- async function loadSampleDocument(sample) {
60
+ async function loadSampleDocument(sample, options = {}) {
61
+ const fileName = options.fileName || 'request.json';
61
62
  const sampleDir = path.join(MOCK_SAMPLES_DIR, sample.path);
62
- const requestPath = path.join(sampleDir, 'request.json');
63
- const raw = await fs.readFile(requestPath, 'utf-8');
64
- const doc = JSON.parse(raw);
65
- if (!doc || typeof doc !== 'object' || !doc.body) {
66
- throw new Error(`Sample ${sample.reqId} missing request body`);
63
+ const requestPath = path.join(sampleDir, fileName);
64
+ try {
65
+ const raw = await fs.readFile(requestPath, 'utf-8');
66
+ const doc = JSON.parse(raw);
67
+ if (!doc || typeof doc !== 'object' || !doc.body) {
68
+ throw new Error(`Sample ${sample.reqId} missing request body (${fileName})`);
69
+ }
70
+ return doc;
71
+ } catch (error) {
72
+ if (options.optional) {
73
+ return null;
74
+ }
75
+ throw error;
67
76
  }
68
- return doc;
69
77
  }
70
78
 
71
79
  function parseProviderKey(providerKey) {
@@ -103,7 +111,7 @@ function buildConfig(sample, port) {
103
111
  type: 'mock-provider',
104
112
  providerType: 'responses',
105
113
  baseURL: `https://mock.local/${providerId}`,
106
- compat: 'passthrough',
114
+ compatibilityProfile: 'compat:passthrough',
107
115
  providerId: sample.providerId,
108
116
  auth: {
109
117
  type: 'apikey',
@@ -154,7 +162,8 @@ function createServer(configPath, port) {
154
162
  ROUTECODEX_PORT: String(port),
155
163
  ROUTECODEX_CONFIG_PATH: configPath
156
164
  };
157
- const child = spawn('routecodex', ['start', '--config', configPath], {
165
+ const entry = path.join(PROJECT_ROOT, 'dist', 'index.js');
166
+ const child = spawn(process.execPath, [entry], {
158
167
  cwd: PROJECT_ROOT,
159
168
  env,
160
169
  stdio: ['ignore', 'pipe', 'pipe']
@@ -255,10 +264,46 @@ function collectInvalidNames(payload) {
255
264
  return failures;
256
265
  }
257
266
 
267
+ function extractRequestBody(doc) {
268
+ const body = doc && typeof doc === 'object' ? doc.body : undefined;
269
+ if (!body || typeof body !== 'object') {
270
+ return {};
271
+ }
272
+ if (body.body && typeof body.body === 'object') {
273
+ return body.body;
274
+ }
275
+ if (body.payload && typeof body.payload === 'object') {
276
+ return body.payload;
277
+ }
278
+ return body;
279
+ }
280
+
281
+ function resolveRequestUrl(sample, requestDoc, port) {
282
+ const rawCandidate =
283
+ requestDoc.endpoint ||
284
+ (requestDoc.meta && typeof requestDoc.meta.entryEndpoint === 'string' ? requestDoc.meta.entryEndpoint : undefined) ||
285
+ requestDoc.url ||
286
+ sample.entry ||
287
+ '/v1/responses';
288
+ if (typeof rawCandidate === 'string' && /^https?:\/\//i.test(rawCandidate.trim())) {
289
+ return rawCandidate.trim();
290
+ }
291
+ const normalizedPath = typeof rawCandidate === 'string' && rawCandidate.trim().length
292
+ ? rawCandidate.trim()
293
+ : '/v1/responses';
294
+ const pathWithSlash = normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`;
295
+ return `http://127.0.0.1:${port}${pathWithSlash}`;
296
+ }
297
+
258
298
  async function sendRequest(sample, requestDoc, port) {
259
- const url = `http://127.0.0.1:${port}${requestDoc.endpoint || sample.entry}`;
299
+ const url = resolveRequestUrl(sample, requestDoc, port);
300
+ const payload = extractRequestBody(requestDoc);
260
301
  const headers = { 'content-type': 'application/json' };
261
- if (requestDoc.body?.stream === true) {
302
+ const wantsStream =
303
+ payload?.stream === true ||
304
+ (requestDoc.body && typeof requestDoc.body === 'object' && requestDoc.body.stream === true) ||
305
+ (requestDoc.meta && requestDoc.meta.stream === true);
306
+ if (wantsStream) {
262
307
  headers.accept = 'text/event-stream';
263
308
  }
264
309
  const controller = new AbortController();
@@ -267,7 +312,7 @@ async function sendRequest(sample, requestDoc, port) {
267
312
  const res = await fetch(url, {
268
313
  method: 'POST',
269
314
  headers,
270
- body: JSON.stringify(requestDoc.body),
315
+ body: JSON.stringify(payload),
271
316
  signal: controller.signal
272
317
  });
273
318
  const text = await res.text();
@@ -283,7 +328,8 @@ async function sendRequest(sample, requestDoc, port) {
283
328
  }
284
329
 
285
330
  async function runSample(sample, index) {
286
- const requestDoc = await loadSampleDocument(sample);
331
+ const clientDoc = await loadSampleDocument(sample, { fileName: 'client-request.json', optional: true });
332
+ const requestDoc = clientDoc || (await loadSampleDocument(sample));
287
333
  const port = 5800 + index;
288
334
  const { dir, file } = await writeTempConfig(sample, port);
289
335
  const server = createServer(file, port);
@@ -14,14 +14,36 @@ function parseArgs(argv) {
14
14
  return out;
15
15
  }
16
16
 
17
+ const projectRoot = process.cwd();
17
18
  const args = parseArgs(process.argv);
18
19
  if (!args.name || !args.bin) {
19
20
  console.error('Usage: node scripts/pack-mode.mjs --name <packageName> --bin <binName>');
20
21
  process.exit(1);
21
22
  }
22
23
 
23
- const pkgPath = path.join(process.cwd(), 'package.json');
24
+ const pkgPath = path.join(projectRoot, 'package.json');
24
25
  const backupPath = pkgPath + '.bak.pack';
26
+ const ensureScriptPath = path.join(projectRoot, 'scripts', 'ensure-llmswitch-mode.mjs');
27
+ const llmsPath = path.join(projectRoot, 'node_modules', '@jsonstudio', 'llms');
28
+
29
+ function runEnsureMode(mode) {
30
+ const env = { ...process.env, BUILD_MODE: mode };
31
+ const res = spawnSync(process.execPath, [ensureScriptPath], { stdio: 'inherit', env });
32
+ if ((res.status ?? 0) !== 0) {
33
+ throw new Error(`ensure-llmswitch-mode failed for ${mode}`);
34
+ }
35
+ }
36
+
37
+ function isSymlink(p) {
38
+ try {
39
+ return fs.lstatSync(p).isSymbolicLink();
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ const hadDevLink = isSymlink(llmsPath);
46
+ runEnsureMode('release');
25
47
 
26
48
  const original = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
27
49
  fs.writeFileSync(backupPath, JSON.stringify(original, null, 2));
@@ -55,4 +77,11 @@ try {
55
77
  // restore
56
78
  fs.writeFileSync(pkgPath, fs.readFileSync(backupPath, 'utf-8'));
57
79
  fs.unlinkSync(backupPath);
80
+ if (hadDevLink) {
81
+ try {
82
+ runEnsureMode('dev');
83
+ } catch (err) {
84
+ console.warn('[pack-mode] failed to restore dev llms link:', err);
85
+ }
86
+ }
58
87
  }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
9
+ const PACK_SCRIPT = path.join(PROJECT_ROOT, 'scripts', 'pack-mode.mjs');
10
+ const packageJson = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf-8'));
11
+ const version = packageJson.version;
12
+ const tarballName = `jsonstudio-rcc-${version}.tgz`;
13
+ const tarballPath = path.join(PROJECT_ROOT, tarballName);
14
+
15
+ function run(command, args, options = {}) {
16
+ const res = spawnSync(command, args, { stdio: 'inherit', ...options });
17
+ if ((res.status ?? 0) !== 0) {
18
+ throw new Error(`${command} ${args.join(' ')} failed`);
19
+ }
20
+ }
21
+
22
+ try {
23
+ run(process.execPath, [PACK_SCRIPT, '--name', '@jsonstudio/rcc', '--bin', 'rcc'], { cwd: PROJECT_ROOT });
24
+ if (!fs.existsSync(tarballPath)) {
25
+ throw new Error(`tarball not found: ${tarballPath}`);
26
+ }
27
+ run('npm', ['publish', tarballName], { cwd: PROJECT_ROOT });
28
+ } catch (err) {
29
+ console.error('[publish-rcc] failed:', err.message);
30
+ process.exit(1);
31
+ }