free-claude-code 6.2.64__py3-none-any.whl

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 (429) hide show
  1. free_claude_code/__init__.py +1 -0
  2. free_claude_code/api/__init__.py +1 -0
  3. free_claude_code/api/admin_cache.py +49 -0
  4. free_claude_code/api/admin_routes.py +501 -0
  5. free_claude_code/api/admin_security.py +67 -0
  6. free_claude_code/api/admin_static/admin.css +980 -0
  7. free_claude_code/api/admin_static/admin.js +1934 -0
  8. free_claude_code/api/admin_static/code_sessions.css +109 -0
  9. free_claude_code/api/admin_static/code_sessions.js +1693 -0
  10. free_claude_code/api/admin_static/form_controls.js +15 -0
  11. free_claude_code/api/admin_static/index.html +201 -0
  12. free_claude_code/api/admin_static/model_combobox.js +194 -0
  13. free_claude_code/api/admin_static/providers/LICENSE-llamacpp.txt +21 -0
  14. free_claude_code/api/admin_static/providers/LICENSE-lobe-icons.txt +21 -0
  15. free_claude_code/api/admin_static/providers/SOURCES.md +56 -0
  16. free_claude_code/api/admin_static/providers/agnesai.svg +1 -0
  17. free_claude_code/api/admin_static/providers/azure-color.svg +1 -0
  18. free_claude_code/api/admin_static/providers/bedrock-color.svg +1 -0
  19. free_claude_code/api/admin_static/providers/cerebras-color.svg +1 -0
  20. free_claude_code/api/admin_static/providers/chutes.png +0 -0
  21. free_claude_code/api/admin_static/providers/cline.svg +1 -0
  22. free_claude_code/api/admin_static/providers/cloudflare-color.svg +1 -0
  23. free_claude_code/api/admin_static/providers/cohere-color.svg +1 -0
  24. free_claude_code/api/admin_static/providers/deepinfra-color.svg +1 -0
  25. free_claude_code/api/admin_static/providers/deepseek-color.svg +1 -0
  26. free_claude_code/api/admin_static/providers/experiential.svg +9 -0
  27. free_claude_code/api/admin_static/providers/featherless-color.svg +1 -0
  28. free_claude_code/api/admin_static/providers/fireworks-color.svg +1 -0
  29. free_claude_code/api/admin_static/providers/gemini-color.svg +1 -0
  30. free_claude_code/api/admin_static/providers/githubcopilot.svg +1 -0
  31. free_claude_code/api/admin_static/providers/groq.svg +1 -0
  32. free_claude_code/api/admin_static/providers/huggingface-color.svg +1 -0
  33. free_claude_code/api/admin_static/providers/kilocode.svg +1 -0
  34. free_claude_code/api/admin_static/providers/kimi-color.svg +1 -0
  35. free_claude_code/api/admin_static/providers/lightning.png +0 -0
  36. free_claude_code/api/admin_static/providers/llamacpp.svg +77 -0
  37. free_claude_code/api/admin_static/providers/llm7.png +0 -0
  38. free_claude_code/api/admin_static/providers/lmstudio.svg +1 -0
  39. free_claude_code/api/admin_static/providers/minimax-color.svg +1 -0
  40. free_claude_code/api/admin_static/providers/mistral-color.svg +1 -0
  41. free_claude_code/api/admin_static/providers/nararoute.png +0 -0
  42. free_claude_code/api/admin_static/providers/nebius.svg +1 -0
  43. free_claude_code/api/admin_static/providers/novita-color.svg +1 -0
  44. free_claude_code/api/admin_static/providers/nvidia-color.svg +1 -0
  45. free_claude_code/api/admin_static/providers/ollama.svg +1 -0
  46. free_claude_code/api/admin_static/providers/openai.svg +1 -0
  47. free_claude_code/api/admin_static/providers/opencode.svg +1 -0
  48. free_claude_code/api/admin_static/providers/openrouter.svg +1 -0
  49. free_claude_code/api/admin_static/providers/poolside-color.svg +1 -0
  50. free_claude_code/api/admin_static/providers/qwen-color.svg +1 -0
  51. free_claude_code/api/admin_static/providers/sambanova-color.svg +1 -0
  52. free_claude_code/api/admin_static/providers/scaleway.svg +11 -0
  53. free_claude_code/api/admin_static/providers/siliconcloud-color.svg +1 -0
  54. free_claude_code/api/admin_static/providers/together-color.svg +1 -0
  55. free_claude_code/api/admin_static/providers/tokenrouter.png +0 -0
  56. free_claude_code/api/admin_static/providers/vercel.svg +1 -0
  57. free_claude_code/api/admin_static/providers/vertexai-color.svg +1 -0
  58. free_claude_code/api/admin_static/providers/wafer.png +0 -0
  59. free_claude_code/api/admin_static/providers/wandb.png +0 -0
  60. free_claude_code/api/admin_static/providers/xai.svg +1 -0
  61. free_claude_code/api/admin_static/providers/zai.svg +1 -0
  62. free_claude_code/api/admin_static/providers/zenmux.svg +1 -0
  63. free_claude_code/api/admin_static/session_layout.css +552 -0
  64. free_claude_code/api/admin_static/session_ui.js +202 -0
  65. free_claude_code/api/app.py +149 -0
  66. free_claude_code/api/code_sessions_routes.py +386 -0
  67. free_claude_code/api/command_utils.py +164 -0
  68. free_claude_code/api/dependencies.py +128 -0
  69. free_claude_code/api/detection.py +185 -0
  70. free_claude_code/api/handlers/__init__.py +7 -0
  71. free_claude_code/api/handlers/classifier_response.py +66 -0
  72. free_claude_code/api/handlers/messages.py +359 -0
  73. free_claude_code/api/handlers/responses.py +163 -0
  74. free_claude_code/api/handlers/token_count.py +87 -0
  75. free_claude_code/api/markdown.py +71 -0
  76. free_claude_code/api/model_catalog.py +282 -0
  77. free_claude_code/api/optimization_handlers.py +162 -0
  78. free_claude_code/api/ports.py +97 -0
  79. free_claude_code/api/request_errors.py +100 -0
  80. free_claude_code/api/request_ids.py +100 -0
  81. free_claude_code/api/request_lifetime.py +130 -0
  82. free_claude_code/api/response_streams.py +422 -0
  83. free_claude_code/api/routes.py +269 -0
  84. free_claude_code/api/validation_log.py +46 -0
  85. free_claude_code/application/__init__.py +1 -0
  86. free_claude_code/application/code_sessions/__init__.py +33 -0
  87. free_claude_code/application/code_sessions/models.py +227 -0
  88. free_claude_code/application/code_sessions/ports.py +197 -0
  89. free_claude_code/application/code_sessions/service.py +1123 -0
  90. free_claude_code/application/code_sessions/state.py +659 -0
  91. free_claude_code/application/connected_accounts.py +96 -0
  92. free_claude_code/application/errors.py +41 -0
  93. free_claude_code/application/execution.py +467 -0
  94. free_claude_code/application/model_catalog.py +95 -0
  95. free_claude_code/application/model_metadata.py +26 -0
  96. free_claude_code/application/ports.py +127 -0
  97. free_claude_code/application/readiness.py +43 -0
  98. free_claude_code/application/reasoning.py +134 -0
  99. free_claude_code/application/routing.py +291 -0
  100. free_claude_code/application/session_events.py +140 -0
  101. free_claude_code/application/web_tools/__init__.py +1 -0
  102. free_claude_code/application/web_tools/ports.py +35 -0
  103. free_claude_code/application/web_tools/request.py +348 -0
  104. free_claude_code/application/web_tools/service.py +481 -0
  105. free_claude_code/assets/app-icon.icns +0 -0
  106. free_claude_code/assets/app-icon.ico +0 -0
  107. free_claude_code/assets/app-icon.png +0 -0
  108. free_claude_code/assets/app-icon.svg +14 -0
  109. free_claude_code/cli/__init__.py +5 -0
  110. free_claude_code/cli/commands.py +379 -0
  111. free_claude_code/cli/desktop.py +156 -0
  112. free_claude_code/cli/desktop_assets.py +31 -0
  113. free_claude_code/cli/desktop_entrypoint.py +29 -0
  114. free_claude_code/cli/desktop_tray.py +67 -0
  115. free_claude_code/cli/entrypoints.py +25 -0
  116. free_claude_code/cli/launchers/__init__.py +1 -0
  117. free_claude_code/cli/launchers/aider.py +53 -0
  118. free_claude_code/cli/launchers/aider_config.py +80 -0
  119. free_claude_code/cli/launchers/catalog_http.py +134 -0
  120. free_claude_code/cli/launchers/claude.py +34 -0
  121. free_claude_code/cli/launchers/cline.py +60 -0
  122. free_claude_code/cli/launchers/cline_config.py +121 -0
  123. free_claude_code/cli/launchers/codex.py +47 -0
  124. free_claude_code/cli/launchers/common.py +103 -0
  125. free_claude_code/cli/launchers/dsh.py +69 -0
  126. free_claude_code/cli/launchers/dsh_config.py +124 -0
  127. free_claude_code/cli/launchers/grok.py +116 -0
  128. free_claude_code/cli/launchers/hermes.py +85 -0
  129. free_claude_code/cli/launchers/hermes_config.py +134 -0
  130. free_claude_code/cli/launchers/muse.py +68 -0
  131. free_claude_code/cli/launchers/opencode.py +83 -0
  132. free_claude_code/cli/launchers/opencode_config.py +107 -0
  133. free_claude_code/cli/launchers/pi.py +70 -0
  134. free_claude_code/cli/launchers/pi_extension.ts +190 -0
  135. free_claude_code/cli/launchers/runner.py +155 -0
  136. free_claude_code/cli/local_http.py +12 -0
  137. free_claude_code/cli/managed/__init__.py +6 -0
  138. free_claude_code/cli/managed/claude.py +225 -0
  139. free_claude_code/cli/managed/diagnostics.py +47 -0
  140. free_claude_code/cli/managed/manager.py +207 -0
  141. free_claude_code/cli/managed/session.py +293 -0
  142. free_claude_code/cli/process_registry.py +76 -0
  143. free_claude_code/cli/server_socket.py +71 -0
  144. free_claude_code/cli/uvicorn_server.py +41 -0
  145. free_claude_code/config/__init__.py +10 -0
  146. free_claude_code/config/admin/__init__.py +1 -0
  147. free_claude_code/config/admin/manifest.py +610 -0
  148. free_claude_code/config/admin/persistence.py +202 -0
  149. free_claude_code/config/admin/provider_manifest.py +443 -0
  150. free_claude_code/config/admin/specs.py +77 -0
  151. free_claude_code/config/admin/state.py +18 -0
  152. free_claude_code/config/admin/status.py +116 -0
  153. free_claude_code/config/admin/validation.py +40 -0
  154. free_claude_code/config/admin/values.py +115 -0
  155. free_claude_code/config/constants.py +9 -0
  156. free_claude_code/config/env_files.py +74 -0
  157. free_claude_code/config/env_migrations.py +457 -0
  158. free_claude_code/config/loader.py +196 -0
  159. free_claude_code/config/logging_config.py +197 -0
  160. free_claude_code/config/model_refs.py +118 -0
  161. free_claude_code/config/nim.py +121 -0
  162. free_claude_code/config/paths.py +104 -0
  163. free_claude_code/config/provider_catalog.py +746 -0
  164. free_claude_code/config/provider_proxies.py +44 -0
  165. free_claude_code/config/reasoning.py +24 -0
  166. free_claude_code/config/server_urls.py +55 -0
  167. free_claude_code/config/settings.py +812 -0
  168. free_claude_code/core/__init__.py +15 -0
  169. free_claude_code/core/anthropic/__init__.py +99 -0
  170. free_claude_code/core/anthropic/content.py +31 -0
  171. free_claude_code/core/anthropic/conversion.py +876 -0
  172. free_claude_code/core/anthropic/errors.py +97 -0
  173. free_claude_code/core/anthropic/image_sources.py +77 -0
  174. free_claude_code/core/anthropic/models.py +193 -0
  175. free_claude_code/core/anthropic/native.py +184 -0
  176. free_claude_code/core/anthropic/native_stream.py +306 -0
  177. free_claude_code/core/anthropic/request_serialization.py +57 -0
  178. free_claude_code/core/anthropic/request_snapshot.py +35 -0
  179. free_claude_code/core/anthropic/server_tool_sse.py +234 -0
  180. free_claude_code/core/anthropic/server_tool_types.py +9 -0
  181. free_claude_code/core/anthropic/sse_aggregation.py +144 -0
  182. free_claude_code/core/anthropic/stream_contracts.py +208 -0
  183. free_claude_code/core/anthropic/streaming/__init__.py +43 -0
  184. free_claude_code/core/anthropic/streaming/decoder.py +49 -0
  185. free_claude_code/core/anthropic/streaming/emitter.py +62 -0
  186. free_claude_code/core/anthropic/streaming/ledger.py +538 -0
  187. free_claude_code/core/anthropic/streaming/recovery.py +211 -0
  188. free_claude_code/core/anthropic/thinking.py +140 -0
  189. free_claude_code/core/anthropic/tokens.py +111 -0
  190. free_claude_code/core/anthropic/tool_results.py +63 -0
  191. free_claude_code/core/anthropic/tool_schema.py +94 -0
  192. free_claude_code/core/anthropic/tools.py +493 -0
  193. free_claude_code/core/anthropic/usage.py +38 -0
  194. free_claude_code/core/anthropic/utils.py +9 -0
  195. free_claude_code/core/async_iterators.py +26 -0
  196. free_claude_code/core/async_tasks.py +26 -0
  197. free_claude_code/core/data/README.md +12 -0
  198. free_claude_code/core/data/TIKTOKEN-LICENSE +21 -0
  199. free_claude_code/core/data/cl100k_base.tiktoken +100256 -0
  200. free_claude_code/core/diagnostics.py +319 -0
  201. free_claude_code/core/failures.py +50 -0
  202. free_claude_code/core/gateway_model_ids.py +73 -0
  203. free_claude_code/core/history_replay.py +561 -0
  204. free_claude_code/core/interprocess_lock.py +90 -0
  205. free_claude_code/core/json_types.py +7 -0
  206. free_claude_code/core/model_capabilities.py +10 -0
  207. free_claude_code/core/openai_chat.py +54 -0
  208. free_claude_code/core/openai_responses/__init__.py +90 -0
  209. free_claude_code/core/openai_responses/chat_request.py +747 -0
  210. free_claude_code/core/openai_responses/errors.py +78 -0
  211. free_claude_code/core/openai_responses/events.py +82 -0
  212. free_claude_code/core/openai_responses/ids.py +32 -0
  213. free_claude_code/core/openai_responses/items.py +35 -0
  214. free_claude_code/core/openai_responses/messages_request.py +624 -0
  215. free_claude_code/core/openai_responses/messages_stream.py +404 -0
  216. free_claude_code/core/openai_responses/models.py +33 -0
  217. free_claude_code/core/openai_responses/native.py +147 -0
  218. free_claude_code/core/openai_responses/provider_input.py +409 -0
  219. free_claude_code/core/openai_responses/provider_stream.py +282 -0
  220. free_claude_code/core/openai_responses/reasoning.py +73 -0
  221. free_claude_code/core/openai_responses/streaming/__init__.py +1 -0
  222. free_claude_code/core/openai_responses/streaming/blocks.py +36 -0
  223. free_claude_code/core/openai_responses/streaming/completion.py +169 -0
  224. free_claude_code/core/openai_responses/streaming/error_mapping.py +28 -0
  225. free_claude_code/core/openai_responses/streaming/event_builders.py +198 -0
  226. free_claude_code/core/openai_responses/streaming/ledger.py +96 -0
  227. free_claude_code/core/openai_responses/tokens.py +133 -0
  228. free_claude_code/core/openai_responses/tool_adaptation.py +828 -0
  229. free_claude_code/core/openai_responses/tool_search.py +204 -0
  230. free_claude_code/core/openai_responses/tools.py +169 -0
  231. free_claude_code/core/openai_tool_names.py +178 -0
  232. free_claude_code/core/rate_limit.py +72 -0
  233. free_claude_code/core/reasoning.py +136 -0
  234. free_claude_code/core/token_estimation.py +76 -0
  235. free_claude_code/core/tool_schema_patterns.py +168 -0
  236. free_claude_code/core/trace.py +197 -0
  237. free_claude_code/core/version.py +15 -0
  238. free_claude_code/core/web_tools.py +17 -0
  239. free_claude_code/core/windows_dpi.py +27 -0
  240. free_claude_code/harnesses/__init__.py +1 -0
  241. free_claude_code/harnesses/claude.py +42 -0
  242. free_claude_code/harnesses/claude_desktop_integration.py +418 -0
  243. free_claude_code/harnesses/claude_integration.py +167 -0
  244. free_claude_code/harnesses/codex.py +94 -0
  245. free_claude_code/harnesses/codex_integration.py +147 -0
  246. free_claude_code/harnesses/codex_model_catalog.py +109 -0
  247. free_claude_code/harnesses/config_file.py +33 -0
  248. free_claude_code/harnesses/environment.py +78 -0
  249. free_claude_code/harnesses/jetbrains_acp_integration.py +242 -0
  250. free_claude_code/harnesses/launch.py +21 -0
  251. free_claude_code/harnesses/resources.py +42 -0
  252. free_claude_code/messaging/__init__.py +16 -0
  253. free_claude_code/messaging/cli_event_constants.py +67 -0
  254. free_claude_code/messaging/command_context.py +99 -0
  255. free_claude_code/messaging/command_dispatcher.py +31 -0
  256. free_claude_code/messaging/commands.py +182 -0
  257. free_claude_code/messaging/event_parser.py +184 -0
  258. free_claude_code/messaging/limiter.py +342 -0
  259. free_claude_code/messaging/managed_protocols.py +35 -0
  260. free_claude_code/messaging/models.py +57 -0
  261. free_claude_code/messaging/node_event_pipeline.py +120 -0
  262. free_claude_code/messaging/node_runner.py +408 -0
  263. free_claude_code/messaging/platforms/__init__.py +20 -0
  264. free_claude_code/messaging/platforms/discord.py +319 -0
  265. free_claude_code/messaging/platforms/discord_inbound.py +112 -0
  266. free_claude_code/messaging/platforms/discord_io.py +167 -0
  267. free_claude_code/messaging/platforms/factory.py +109 -0
  268. free_claude_code/messaging/platforms/outbox.py +143 -0
  269. free_claude_code/messaging/platforms/ports.py +99 -0
  270. free_claude_code/messaging/platforms/telegram.py +300 -0
  271. free_claude_code/messaging/platforms/telegram_inbound.py +133 -0
  272. free_claude_code/messaging/platforms/telegram_io.py +287 -0
  273. free_claude_code/messaging/platforms/voice_flow.py +388 -0
  274. free_claude_code/messaging/rendering/__init__.py +3 -0
  275. free_claude_code/messaging/rendering/discord_markdown.py +318 -0
  276. free_claude_code/messaging/rendering/markdown_tables.py +47 -0
  277. free_claude_code/messaging/rendering/profiles.py +53 -0
  278. free_claude_code/messaging/rendering/telegram_markdown.py +331 -0
  279. free_claude_code/messaging/safe_diagnostics.py +15 -0
  280. free_claude_code/messaging/session/__init__.py +5 -0
  281. free_claude_code/messaging/session/managed_message_log.py +135 -0
  282. free_claude_code/messaging/session/persistence.py +161 -0
  283. free_claude_code/messaging/session/store.py +162 -0
  284. free_claude_code/messaging/transcript/__init__.py +6 -0
  285. free_claude_code/messaging/transcript/buffer.py +220 -0
  286. free_claude_code/messaging/transcript/context.py +18 -0
  287. free_claude_code/messaging/transcript/renderer.py +65 -0
  288. free_claude_code/messaging/transcript/segments.py +176 -0
  289. free_claude_code/messaging/transcript/subagents.py +108 -0
  290. free_claude_code/messaging/transcription.py +132 -0
  291. free_claude_code/messaging/trees/__init__.py +41 -0
  292. free_claude_code/messaging/trees/graph.py +250 -0
  293. free_claude_code/messaging/trees/identity.py +16 -0
  294. free_claude_code/messaging/trees/manager.py +587 -0
  295. free_claude_code/messaging/trees/node.py +56 -0
  296. free_claude_code/messaging/trees/processor.py +272 -0
  297. free_claude_code/messaging/trees/queue.py +47 -0
  298. free_claude_code/messaging/trees/repository.py +135 -0
  299. free_claude_code/messaging/trees/runtime.py +487 -0
  300. free_claude_code/messaging/trees/snapshot.py +221 -0
  301. free_claude_code/messaging/trees/transitions.py +174 -0
  302. free_claude_code/messaging/turn_intake.py +241 -0
  303. free_claude_code/messaging/ui_updates.py +99 -0
  304. free_claude_code/messaging/voice.py +376 -0
  305. free_claude_code/messaging/workflow.py +714 -0
  306. free_claude_code/providers/__init__.py +12 -0
  307. free_claude_code/providers/admission.py +942 -0
  308. free_claude_code/providers/anthropic_messages/__init__.py +1 -0
  309. free_claude_code/providers/anthropic_messages/request_policy.py +162 -0
  310. free_claude_code/providers/anthropic_messages/transport.py +499 -0
  311. free_claude_code/providers/base.py +73 -0
  312. free_claude_code/providers/cloudflare/__init__.py +8 -0
  313. free_claude_code/providers/cloudflare/client.py +166 -0
  314. free_claude_code/providers/credential_validation.py +314 -0
  315. free_claude_code/providers/deepseek/__init__.py +5 -0
  316. free_claude_code/providers/deepseek/client.py +117 -0
  317. free_claude_code/providers/deepseek/compat.py +241 -0
  318. free_claude_code/providers/endpoint.py +21 -0
  319. free_claude_code/providers/endpoint_types.py +21 -0
  320. free_claude_code/providers/failure_policy.py +574 -0
  321. free_claude_code/providers/gemini/__init__.py +5 -0
  322. free_claude_code/providers/gemini/client.py +42 -0
  323. free_claude_code/providers/github_copilot/__init__.py +1 -0
  324. free_claude_code/providers/github_copilot/auth.py +502 -0
  325. free_claude_code/providers/github_copilot/broker.py +248 -0
  326. free_claude_code/providers/github_copilot/lifecycle.py +18 -0
  327. free_claude_code/providers/github_copilot/login.py +112 -0
  328. free_claude_code/providers/github_copilot/native_cli.py +82 -0
  329. free_claude_code/providers/github_copilot/provider.py +367 -0
  330. free_claude_code/providers/github_copilot/request_policy.py +119 -0
  331. free_claude_code/providers/github_copilot/responses_events.py +90 -0
  332. free_claude_code/providers/github_copilot/sdk.py +496 -0
  333. free_claude_code/providers/github_copilot/types.py +67 -0
  334. free_claude_code/providers/google_openai/__init__.py +17 -0
  335. free_claude_code/providers/google_openai/provider.py +73 -0
  336. free_claude_code/providers/google_openai/reasoning.py +150 -0
  337. free_claude_code/providers/google_openai/thought_signatures.py +117 -0
  338. free_claude_code/providers/groq/__init__.py +5 -0
  339. free_claude_code/providers/groq/client.py +342 -0
  340. free_claude_code/providers/groq/tpm.py +114 -0
  341. free_claude_code/providers/history_replay.py +260 -0
  342. free_claude_code/providers/http.py +105 -0
  343. free_claude_code/providers/kilo/__init__.py +5 -0
  344. free_claude_code/providers/kilo/client.py +45 -0
  345. free_claude_code/providers/kilo/models.py +60 -0
  346. free_claude_code/providers/lmstudio/__init__.py +5 -0
  347. free_claude_code/providers/lmstudio/client.py +220 -0
  348. free_claude_code/providers/mistral/__init__.py +5 -0
  349. free_claude_code/providers/mistral/client.py +91 -0
  350. free_claude_code/providers/mistral/reasoning.py +410 -0
  351. free_claude_code/providers/model_listing.py +479 -0
  352. free_claude_code/providers/nvidia_nim/__init__.py +5 -0
  353. free_claude_code/providers/nvidia_nim/client.py +224 -0
  354. free_claude_code/providers/nvidia_nim/native_tool_stream.py +693 -0
  355. free_claude_code/providers/nvidia_nim/request_options.py +141 -0
  356. free_claude_code/providers/nvidia_nim/retry.py +85 -0
  357. free_claude_code/providers/nvidia_nim/tool_schema.py +255 -0
  358. free_claude_code/providers/nvidia_nim/voice.py +107 -0
  359. free_claude_code/providers/open_router/__init__.py +5 -0
  360. free_claude_code/providers/open_router/client.py +113 -0
  361. free_claude_code/providers/openai_api/__init__.py +5 -0
  362. free_claude_code/providers/openai_api/provider.py +150 -0
  363. free_claude_code/providers/openai_chat/__init__.py +72 -0
  364. free_claude_code/providers/openai_chat/base_url.py +7 -0
  365. free_claude_code/providers/openai_chat/behavior.py +133 -0
  366. free_claude_code/providers/openai_chat/client.py +40 -0
  367. free_claude_code/providers/openai_chat/extra_body.py +63 -0
  368. free_claude_code/providers/openai_chat/output_cap.py +161 -0
  369. free_claude_code/providers/openai_chat/profiles.py +778 -0
  370. free_claude_code/providers/openai_chat/provider.py +244 -0
  371. free_claude_code/providers/openai_chat/reasoning.py +169 -0
  372. free_claude_code/providers/openai_chat/reasoning_details.py +128 -0
  373. free_claude_code/providers/openai_chat/request_policy.py +140 -0
  374. free_claude_code/providers/openai_chat/stream_output.py +752 -0
  375. free_claude_code/providers/openai_chat/tool_calls.py +462 -0
  376. free_claude_code/providers/openai_chat/transport.py +1643 -0
  377. free_claude_code/providers/openai_chat/usage.py +117 -0
  378. free_claude_code/providers/openai_client.py +74 -0
  379. free_claude_code/providers/openai_codex/__init__.py +1 -0
  380. free_claude_code/providers/openai_codex/auth.py +626 -0
  381. free_claude_code/providers/openai_codex/endpoint.py +53 -0
  382. free_claude_code/providers/openai_codex/login.py +265 -0
  383. free_claude_code/providers/openai_codex/provider.py +259 -0
  384. free_claude_code/providers/openai_responses/__init__.py +5 -0
  385. free_claude_code/providers/openai_responses/presentation.py +115 -0
  386. free_claude_code/providers/openai_responses/transport.py +621 -0
  387. free_claude_code/providers/openai_stream.py +21 -0
  388. free_claude_code/providers/opencode/__init__.py +5 -0
  389. free_claude_code/providers/opencode/catalog.py +340 -0
  390. free_claude_code/providers/opencode/provider.py +359 -0
  391. free_claude_code/providers/reasoning_compatibility.py +199 -0
  392. free_claude_code/providers/request_recovery.py +122 -0
  393. free_claude_code/providers/runtime/__init__.py +10 -0
  394. free_claude_code/providers/runtime/config.py +91 -0
  395. free_claude_code/providers/runtime/discovery.py +63 -0
  396. free_claude_code/providers/runtime/factory.py +282 -0
  397. free_claude_code/providers/runtime/model_cache.py +93 -0
  398. free_claude_code/providers/runtime/runtime.py +108 -0
  399. free_claude_code/providers/stream_recovery.py +164 -0
  400. free_claude_code/providers/vertex/__init__.py +5 -0
  401. free_claude_code/providers/vertex/auth.py +105 -0
  402. free_claude_code/providers/vertex/client.py +140 -0
  403. free_claude_code/providers/vertex/endpoint.py +50 -0
  404. free_claude_code/providers/vertex/models.py +52 -0
  405. free_claude_code/runtime/__init__.py +1 -0
  406. free_claude_code/runtime/application.py +1121 -0
  407. free_claude_code/runtime/asgi.py +63 -0
  408. free_claude_code/runtime/bootstrap.py +153 -0
  409. free_claude_code/runtime/code_sessions_sqlite.py +785 -0
  410. free_claude_code/runtime/codex_app_server.py +775 -0
  411. free_claude_code/runtime/codex_catalog.py +62 -0
  412. free_claude_code/runtime/codex_protocol.py +662 -0
  413. free_claude_code/runtime/configuration.py +53 -0
  414. free_claude_code/runtime/folder_picker.py +134 -0
  415. free_claude_code/runtime/native_folder_dialog.py +123 -0
  416. free_claude_code/runtime/provider_manager.py +716 -0
  417. free_claude_code/runtime/retired_chat.py +47 -0
  418. free_claude_code/runtime/web_tools/__init__.py +1 -0
  419. free_claude_code/runtime/web_tools/client.py +238 -0
  420. free_claude_code/runtime/web_tools/constants.py +17 -0
  421. free_claude_code/runtime/web_tools/egress.py +89 -0
  422. free_claude_code/runtime/web_tools/parsers.py +78 -0
  423. free_claude_code-6.2.64.data/scripts/fcc-update +4 -0
  424. free_claude_code-6.2.64.data/scripts/fcc-update.cmd +5 -0
  425. free_claude_code-6.2.64.dist-info/METADATA +555 -0
  426. free_claude_code-6.2.64.dist-info/RECORD +429 -0
  427. free_claude_code-6.2.64.dist-info/WHEEL +4 -0
  428. free_claude_code-6.2.64.dist-info/entry_points.txt +15 -0
  429. free_claude_code-6.2.64.dist-info/licenses/LICENSE +239 -0
@@ -0,0 +1,248 @@
1
+ """Account-scoped discovery and inert endpoint sessions with draining leases."""
2
+
3
+ import asyncio
4
+ import time
5
+ from collections.abc import AsyncIterator, Mapping
6
+ from contextlib import asynccontextmanager
7
+ from dataclasses import replace
8
+ from types import MappingProxyType
9
+
10
+ from free_claude_code.application.errors import InvalidRequestError
11
+ from free_claude_code.providers.endpoint_types import HttpEndpoint
12
+
13
+ from .lifecycle import drain_owned
14
+ from .types import (
15
+ CopilotAuthenticationRequired,
16
+ CopilotEgress,
17
+ CopilotEndpoint,
18
+ CopilotIdentity,
19
+ CopilotModel,
20
+ CopilotRuntime,
21
+ CopilotSession,
22
+ CopilotUnavailable,
23
+ )
24
+
25
+ _REFRESH_EARLY_SECONDS = 30
26
+
27
+
28
+ class _EndpointOwner:
29
+ def __init__(self, runtime: CopilotRuntime, model_id: str) -> None:
30
+ self._runtime = runtime
31
+ self._model_id = model_id
32
+ self._lock = asyncio.Lock()
33
+ self._session_task: asyncio.Task[CopilotSession] | None = None
34
+ self._snapshot: CopilotEndpoint | None = None
35
+
36
+ async def endpoint(self, *, force_refresh: bool) -> CopilotEndpoint:
37
+ async with self._lock:
38
+ if self._session_task is None or (
39
+ self._session_task.done()
40
+ and (
41
+ self._session_task.cancelled()
42
+ or self._session_task.exception() is not None
43
+ )
44
+ ):
45
+ self._session_task = asyncio.create_task(
46
+ self._runtime.session(self._model_id)
47
+ )
48
+ session = await asyncio.shield(self._session_task)
49
+ snapshot = self._snapshot
50
+ if (
51
+ force_refresh
52
+ or snapshot is None
53
+ or (
54
+ snapshot.expires_at is not None
55
+ and snapshot.expires_at <= time.time() + _REFRESH_EARLY_SECONDS
56
+ )
57
+ ):
58
+ snapshot = await session.endpoint()
59
+ if (
60
+ snapshot.expires_at is not None
61
+ and snapshot.expires_at <= time.time()
62
+ ):
63
+ raise CopilotUnavailable(
64
+ "Copilot returned an expired endpoint credential. Reconnect Copilot."
65
+ )
66
+ self._snapshot = snapshot
67
+ return snapshot
68
+
69
+ async def drain_creation(self) -> None:
70
+ if self._session_task is not None:
71
+ await asyncio.gather(self._session_task, return_exceptions=True)
72
+
73
+
74
+ class CopilotLease:
75
+ """Retain one concrete model and its routing family throughout inference."""
76
+
77
+ def __init__(
78
+ self,
79
+ broker: CopilotBroker,
80
+ owner: _EndpointOwner,
81
+ model: CopilotModel,
82
+ egress: CopilotEgress,
83
+ ) -> None:
84
+ self._broker = broker
85
+ self._owner = owner
86
+ self.model = model
87
+ self.egress = egress
88
+ self._released = False
89
+
90
+ async def endpoint(self, *, force_refresh: bool = False) -> HttpEndpoint:
91
+ if self._released:
92
+ raise CopilotUnavailable("Copilot endpoint lease has already closed.")
93
+ await self._broker.validate_identity()
94
+ self._broker.validate_model(self.model.info.model_id)
95
+ snapshot = await self._owner.endpoint(force_refresh=force_refresh)
96
+ identity = await self._broker.validate_identity()
97
+ self._broker.validate_model(self.model.info.model_id)
98
+ if snapshot.egress is not self.egress:
99
+ raise CopilotUnavailable(
100
+ "Copilot changed this model's upstream protocol. Retry the request to use its new endpoint."
101
+ )
102
+ return replace(snapshot.http, account_id=f"{identity.host}/{identity.login}")
103
+
104
+ def release(self) -> None:
105
+ self._released = True
106
+
107
+
108
+ class CopilotBroker:
109
+ """Coalesce SDK discovery and retain sessions until every response closes."""
110
+
111
+ def __init__(
112
+ self,
113
+ runtime: CopilotRuntime,
114
+ *,
115
+ expected_identity: CopilotIdentity | None = None,
116
+ ) -> None:
117
+ self._runtime = runtime
118
+ self._identity = expected_identity
119
+ self._models: Mapping[str, CopilotModel] = MappingProxyType({})
120
+ self._owners: dict[str, _EndpointOwner] = {}
121
+ self._condition = asyncio.Condition()
122
+ self._start_task: asyncio.Task[None] | None = None
123
+ self._refresh_task: asyncio.Task[Mapping[str, CopilotModel]] | None = None
124
+ self._close_task: asyncio.Task[None] | None = None
125
+ self._closing = False
126
+ self._closed = False
127
+ self._leases = 0
128
+
129
+ @property
130
+ def identity(self) -> CopilotIdentity | None:
131
+ return self._identity
132
+
133
+ @property
134
+ def current_models(self) -> Mapping[str, CopilotModel]:
135
+ return self._models
136
+
137
+ async def _start(self) -> None:
138
+ async with self._condition:
139
+ if self._closing:
140
+ raise CopilotUnavailable("Copilot connection is closing.")
141
+ if self._start_task is None:
142
+ self._start_task = asyncio.create_task(self._runtime.start())
143
+ task = self._start_task
144
+ await asyncio.shield(task)
145
+
146
+ async def validate_identity(self) -> CopilotIdentity:
147
+ identity = await self._runtime.identity()
148
+ if identity is None:
149
+ raise CopilotAuthenticationRequired(
150
+ "Copilot is signed out. Connect your GitHub account in Admin."
151
+ )
152
+ if self._identity is not None and identity != self._identity:
153
+ raise CopilotAuthenticationRequired(
154
+ "The selected GitHub profile changed. Reconnect Copilot in Admin."
155
+ )
156
+ self._identity = identity
157
+ return identity
158
+
159
+ async def snapshot(self, *, refresh: bool = False) -> Mapping[str, CopilotModel]:
160
+ await self._start()
161
+ await self.validate_identity()
162
+ async with self._condition:
163
+ if self._closing:
164
+ raise CopilotUnavailable("Copilot connection is closing.")
165
+ task = self._refresh_task
166
+ if task is None or task.done():
167
+ if self._models and not refresh:
168
+ return self._models
169
+ task = asyncio.create_task(self._discover())
170
+ self._refresh_task = task
171
+ return await asyncio.shield(task)
172
+
173
+ def validate_model(self, model_id: str) -> CopilotModel:
174
+ model = self._models.get(model_id)
175
+ if model is None:
176
+ raise InvalidRequestError(
177
+ "This model is not available from the connected Copilot account. Refresh the model list."
178
+ )
179
+ return model
180
+
181
+ async def _discover(self) -> Mapping[str, CopilotModel]:
182
+ await self.validate_identity()
183
+ models = await self._runtime.models()
184
+ await self.validate_identity()
185
+ result = {model.info.model_id: model for model in models}
186
+ if len(result) != len(models):
187
+ raise CopilotUnavailable("Copilot returned conflicting model identifiers.")
188
+ async with self._condition:
189
+ if self._closing:
190
+ raise CopilotUnavailable("Copilot connection closed during discovery.")
191
+ self._models = MappingProxyType(result)
192
+ if not result:
193
+ raise CopilotUnavailable(
194
+ "This GitHub account exposes no enabled Copilot models. Check its subscription and model policies."
195
+ )
196
+ return self._models
197
+
198
+ @asynccontextmanager
199
+ async def lease(self, model_id: str) -> AsyncIterator[CopilotLease]:
200
+ await self.snapshot()
201
+ async with self._condition:
202
+ if self._closing:
203
+ raise CopilotUnavailable("Copilot connection is closing.")
204
+ model = self.validate_model(model_id)
205
+ self._leases += 1
206
+ owner = self._owners.get(model_id)
207
+ if owner is None:
208
+ owner = _EndpointOwner(self._runtime, model_id)
209
+ self._owners[model_id] = owner
210
+ lease = None
211
+ try:
212
+ await self.validate_identity()
213
+ endpoint = await owner.endpoint(force_refresh=False)
214
+ await self.validate_identity()
215
+ self.validate_model(model_id)
216
+ lease = CopilotLease(self, owner, model, endpoint.egress)
217
+ yield lease
218
+ finally:
219
+ if lease is not None:
220
+ lease.release()
221
+ async with self._condition:
222
+ self._leases -= 1
223
+ self._condition.notify_all()
224
+
225
+ async def close(self) -> None:
226
+ if self._closed:
227
+ return
228
+ if self._close_task is None or self._close_task.done():
229
+ self._closing = True
230
+ self._close_task = asyncio.create_task(self._close())
231
+ await drain_owned(self._close_task)
232
+
233
+ async def _close(self) -> None:
234
+ # Stop discovery publication; SDK-owned work itself has bounded RPC timeouts.
235
+ tasks = [
236
+ task for task in (self._start_task, self._refresh_task) if task is not None
237
+ ]
238
+ if tasks:
239
+ await asyncio.gather(*tasks, return_exceptions=True)
240
+ async with self._condition:
241
+ await self._condition.wait_for(lambda: self._leases == 0)
242
+ await asyncio.gather(
243
+ *(owner.drain_creation() for owner in self._owners.values())
244
+ )
245
+ await self._runtime.close()
246
+ self._owners.clear()
247
+ self._models = MappingProxyType({})
248
+ self._closed = True
@@ -0,0 +1,18 @@
1
+ """Drain Copilot-owned work before propagating caller cancellation."""
2
+
3
+ import asyncio
4
+
5
+
6
+ async def drain_owned[T](task: asyncio.Task[T]) -> T:
7
+ cancelled = False
8
+ while not task.done():
9
+ try:
10
+ await asyncio.shield(task)
11
+ except asyncio.CancelledError:
12
+ if task.cancelled():
13
+ raise
14
+ cancelled = True
15
+ result = task.result()
16
+ if cancelled:
17
+ raise asyncio.CancelledError
18
+ return result
@@ -0,0 +1,112 @@
1
+ """Official native Copilot device login; FCC never handles the resulting token."""
2
+
3
+ import asyncio
4
+ import os
5
+ import re
6
+ import subprocess
7
+ from collections.abc import Callable
8
+ from contextlib import suppress
9
+ from dataclasses import dataclass
10
+ from urllib.parse import urlsplit
11
+
12
+ from .lifecycle import drain_owned
13
+ from .native_cli import profile_environment, verified_cli_path
14
+ from .types import CopilotUnavailable
15
+
16
+ LOGIN_TIMEOUT_SECONDS = 15 * 60
17
+ _CHALLENGE = re.compile(
18
+ r"visit\s+(https://[^\s]+/login/device)\s+and enter code\s+([A-Z0-9]{4}-[A-Z0-9]{4})",
19
+ re.IGNORECASE,
20
+ )
21
+
22
+
23
+ @dataclass(frozen=True, slots=True)
24
+ class DeviceChallenge:
25
+ verification_url: str
26
+ user_code: str
27
+
28
+
29
+ def parse_challenge(text: str) -> DeviceChallenge | None:
30
+ match = _CHALLENGE.search(text)
31
+ if match is None:
32
+ return None
33
+ url, code = match.groups()
34
+ parsed = urlsplit(url)
35
+ if not parsed.hostname or parsed.username or parsed.password:
36
+ return None
37
+ return DeviceChallenge(url, code.upper())
38
+
39
+
40
+ async def device_login(on_challenge: Callable[[DeviceChallenge], None]) -> None:
41
+ """Run the pinned CLI login and own its child and both bounded readers."""
42
+ env = profile_environment()
43
+ path = await verified_cli_path(env)
44
+ spawning = asyncio.create_task(
45
+ asyncio.create_subprocess_exec(
46
+ path,
47
+ "login",
48
+ "--device-code",
49
+ stdout=asyncio.subprocess.PIPE,
50
+ stderr=asyncio.subprocess.PIPE,
51
+ env=env,
52
+ creationflags=subprocess.CREATE_NO_WINDOW if os.name == "nt" else 0,
53
+ )
54
+ )
55
+ readers: list[asyncio.Task[None]] = []
56
+
57
+ async def read_output(stream: asyncio.StreamReader) -> None:
58
+ buffer = ""
59
+ previous: DeviceChallenge | None = None
60
+ while chunk := await stream.read(1024):
61
+ buffer = (buffer + chunk.decode("utf-8", errors="replace"))[-4096:]
62
+ challenge = parse_challenge(buffer)
63
+ if challenge is not None and challenge != previous:
64
+ on_challenge(challenge)
65
+ previous = challenge
66
+
67
+ async def cleanup() -> None:
68
+ try:
69
+ process = await spawning
70
+ except Exception:
71
+ return
72
+ # Cancellation can arrive before normal readers are installed, or cancel
73
+ # their gather. Pipe transports must finish before process.wait can settle.
74
+ for reader in readers:
75
+ reader.cancel()
76
+ await asyncio.gather(*readers, return_exceptions=True)
77
+
78
+ async def discard(stream: asyncio.StreamReader) -> None:
79
+ while await stream.read(65536):
80
+ pass
81
+
82
+ draining = [
83
+ asyncio.create_task(discard(stream))
84
+ for stream in (process.stdout, process.stderr)
85
+ if stream is not None
86
+ ]
87
+ try:
88
+ if process.returncode is None:
89
+ with suppress(ProcessLookupError):
90
+ process.kill()
91
+ await process.wait()
92
+ finally:
93
+ await asyncio.gather(*draining)
94
+
95
+ try:
96
+ process = await asyncio.shield(spawning)
97
+ if process.stdout is None or process.stderr is None:
98
+ raise CopilotUnavailable("Copilot login output is unavailable.")
99
+ readers.extend(
100
+ (
101
+ asyncio.create_task(read_output(process.stdout)),
102
+ asyncio.create_task(read_output(process.stderr)),
103
+ )
104
+ )
105
+ code = await process.wait()
106
+ await asyncio.gather(*readers)
107
+ if code != 0:
108
+ raise CopilotUnavailable(
109
+ "Copilot sign-in did not complete. Retry Connect or run copilot login --device-code."
110
+ )
111
+ finally:
112
+ await drain_owned(asyncio.create_task(cleanup()))
@@ -0,0 +1,82 @@
1
+ """Native Copilot CLI checks without importing the Copilot SDK."""
2
+
3
+ import asyncio
4
+ import os
5
+ import re
6
+ import shutil
7
+ import subprocess
8
+ from collections.abc import Mapping
9
+ from contextlib import suppress
10
+
11
+ from .lifecycle import drain_owned
12
+ from .types import CopilotUnavailable
13
+
14
+ COPILOT_CLI_VERSION = "1.0.83"
15
+
16
+
17
+ _TOKEN_ENV = frozenset(
18
+ {
19
+ "COPILOT_GITHUB_TOKEN",
20
+ "GH_TOKEN",
21
+ "GITHUB_TOKEN",
22
+ "GITHUB_COPILOT_API_TOKEN",
23
+ "COPILOT_API_URL",
24
+ "COPILOT_SDK_AUTH_TOKEN",
25
+ "COPILOT_DISABLE_KEYTAR",
26
+ "COPILOT_OFFLINE",
27
+ }
28
+ )
29
+
30
+
31
+ def profile_environment(source: Mapping[str, str] | None = None) -> dict[str, str]:
32
+ """Keep native profile selection while excluding token and BYOK overrides."""
33
+ return {
34
+ key: value
35
+ for key, value in (os.environ if source is None else source).items()
36
+ if key.upper() not in _TOKEN_ENV
37
+ and not key.upper().startswith("COPILOT_PROVIDER_")
38
+ }
39
+
40
+
41
+ async def verified_cli_path(env: Mapping[str, str]) -> str:
42
+ path = shutil.which("copilot", path=env.get("PATH"))
43
+ if path is None:
44
+ raise CopilotUnavailable(
45
+ f"Install GitHub Copilot CLI {COPILOT_CLI_VERSION}, then connect again."
46
+ )
47
+ process = await asyncio.create_subprocess_exec(
48
+ path,
49
+ "--version",
50
+ stdout=asyncio.subprocess.PIPE,
51
+ stderr=asyncio.subprocess.PIPE,
52
+ env=env,
53
+ creationflags=subprocess.CREATE_NO_WINDOW if os.name == "nt" else 0,
54
+ )
55
+ try:
56
+ async with asyncio.timeout(15):
57
+ stdout, _ = await process.communicate()
58
+ except TimeoutError:
59
+ raise CopilotUnavailable(
60
+ "Copilot CLI did not report its version in time. Check the CLI installation and reconnect."
61
+ ) from None
62
+ finally:
63
+ if process.returncode is None:
64
+ await drain_owned(asyncio.create_task(_close_cli_probe(process)))
65
+ if (
66
+ process.returncode != 0
67
+ or re.match(
68
+ rf"GitHub Copilot CLI {re.escape(COPILOT_CLI_VERSION)}\.?(?:\r?\n|\Z)",
69
+ stdout.decode("utf-8", errors="replace"),
70
+ )
71
+ is None
72
+ ):
73
+ raise CopilotUnavailable(
74
+ f"FCC requires GitHub Copilot CLI {COPILOT_CLI_VERSION} for its pinned SDK. Install that version and reconnect."
75
+ )
76
+ return path
77
+
78
+
79
+ async def _close_cli_probe(process: asyncio.subprocess.Process) -> None:
80
+ with suppress(ProcessLookupError):
81
+ process.kill()
82
+ await process.communicate()