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,47 @@
1
+ """Remove saved data belonging to the retired Admin Chat Sessions feature."""
2
+
3
+ from loguru import logger
4
+
5
+ from free_claude_code.config import paths
6
+ from free_claude_code.core.interprocess_lock import InterprocessFileLock
7
+
8
+
9
+ def remove_retired_chat_history() -> None:
10
+ """Delete only owned history files, deferring failures to the next startup."""
11
+ try:
12
+ directory = paths.config_dir_path().resolve() / "chat"
13
+ try:
14
+ resolved = directory.resolve(strict=True)
15
+ except FileNotFoundError:
16
+ return
17
+ if resolved != directory:
18
+ logger.warning("Chat history cleanup deferred: redirected directory")
19
+ return
20
+ files = tuple(
21
+ directory / name
22
+ for name in ("chat.db", "chat.db-wal", "chat.db-shm", "chat.db-journal")
23
+ )
24
+ for path in files:
25
+ try:
26
+ path.lstat()
27
+ except FileNotFoundError:
28
+ continue
29
+ break
30
+ else:
31
+ return
32
+
33
+ lock = InterprocessFileLock(directory / "chat.lock")
34
+ try:
35
+ if not lock.acquire():
36
+ logger.warning("Chat history cleanup deferred: history is in use")
37
+ return
38
+ for path in files:
39
+ path.unlink(missing_ok=True)
40
+ finally:
41
+ # Keep the lock file: unlinking it could create two independent locks.
42
+ lock.release()
43
+ except OSError as exc:
44
+ logger.warning(
45
+ "Chat history cleanup deferred until next startup: exc_type={}",
46
+ type(exc).__name__,
47
+ )
@@ -0,0 +1 @@
1
+ """Outbound HTTP implementation for local web tools."""
@@ -0,0 +1,238 @@
1
+ """Outbound HTTP for web_search / web_fetch with operation-scoped resources."""
2
+
3
+ import asyncio
4
+ import socket
5
+ from collections.abc import AsyncIterator
6
+ from urllib.parse import urljoin, urlparse
7
+
8
+ import aiohttp
9
+ import httpx
10
+ from aiohttp import ClientSession, ClientTimeout, TCPConnector
11
+ from aiohttp.abc import AbstractResolver, ResolveResult
12
+
13
+ from free_claude_code.application.web_tools.ports import (
14
+ WebFetchEgressPolicy,
15
+ WebFetchEgressViolation,
16
+ )
17
+ from free_claude_code.core.web_tools import WebFetchResult, WebSearchResult
18
+
19
+ from . import constants
20
+ from .constants import (
21
+ _MAX_FETCH_CHARS,
22
+ _MAX_SEARCH_RESULTS,
23
+ _REDIRECT_RESPONSE_BODY_CAP_BYTES,
24
+ _REQUEST_TIMEOUT_S,
25
+ _WEB_FETCH_REDIRECT_STATUSES,
26
+ _WEB_TOOL_HTTP_HEADERS,
27
+ )
28
+ from .egress import (
29
+ get_validated_stream_addrinfos_for_egress,
30
+ )
31
+ from .parsers import HTMLTextParser, SearchResultParser
32
+
33
+
34
+ async def _iter_response_body_under_cap(
35
+ response: httpx.Response, max_bytes: int
36
+ ) -> AsyncIterator[bytes]:
37
+ if max_bytes <= 0:
38
+ return
39
+ received = 0
40
+ async for chunk in response.aiter_bytes(chunk_size=65_536):
41
+ if received >= max_bytes:
42
+ break
43
+ remaining = max_bytes - received
44
+ if len(chunk) <= remaining:
45
+ received += len(chunk)
46
+ yield chunk
47
+ if received >= max_bytes:
48
+ break
49
+ else:
50
+ yield chunk[:remaining]
51
+ break
52
+
53
+
54
+ async def _drain_response_body_capped(response: httpx.Response, max_bytes: int) -> None:
55
+ async for _ in _iter_response_body_under_cap(response, max_bytes):
56
+ pass
57
+
58
+
59
+ async def _read_response_body_capped(response: httpx.Response, max_bytes: int) -> bytes:
60
+ return b"".join(
61
+ [piece async for piece in _iter_response_body_under_cap(response, max_bytes)]
62
+ )
63
+
64
+
65
+ _NUMERIC_RESOLVE_FLAGS = socket.AI_NUMERICHOST | socket.AI_NUMERICSERV
66
+ _NAME_RESOLVE_FLAGS = socket.NI_NUMERICHOST | socket.NI_NUMERICSERV
67
+
68
+
69
+ def getaddrinfo_rows_to_resolve_results(
70
+ host: str, addrinfos: list[tuple]
71
+ ) -> list[ResolveResult]:
72
+ """Map :func:`socket.getaddrinfo` rows to aiohttp :class:`ResolveResult` (ThreadedResolver logic)."""
73
+ out: list[ResolveResult] = []
74
+ for family, _type, proto, _canon, sockaddr in addrinfos:
75
+ if family == socket.AF_INET6:
76
+ if len(sockaddr) < 3:
77
+ continue
78
+ if sockaddr[3]:
79
+ resolved_host, port = socket.getnameinfo(sockaddr, _NAME_RESOLVE_FLAGS)
80
+ else:
81
+ resolved_host, port = sockaddr[:2]
82
+ else:
83
+ assert family == socket.AF_INET, family
84
+ resolved_host, port = sockaddr[0], sockaddr[1]
85
+ resolved_host = str(resolved_host)
86
+ port = int(port)
87
+ out.append(
88
+ ResolveResult(
89
+ hostname=host,
90
+ host=resolved_host,
91
+ port=int(port),
92
+ family=family,
93
+ proto=proto,
94
+ flags=_NUMERIC_RESOLVE_FLAGS,
95
+ )
96
+ )
97
+ return out
98
+
99
+
100
+ class _PinnedEgressStaticResolver(AbstractResolver):
101
+ """Return only pre-validated :class:`ResolveResult` for the outbound request."""
102
+
103
+ def __init__(self, results: list[ResolveResult]) -> None:
104
+ self._results = results
105
+
106
+ async def resolve(
107
+ self, host: str, port: int = 0, family: int = socket.AF_INET
108
+ ) -> list[ResolveResult]:
109
+ return self._results
110
+
111
+ async def close(self) -> None: # pragma: no cover - aiohttp contract
112
+ return
113
+
114
+
115
+ async def _read_aiohttp_body_capped(
116
+ response: aiohttp.ClientResponse, max_bytes: int
117
+ ) -> bytes:
118
+ received = 0
119
+ parts: list[bytes] = []
120
+ async for chunk in response.content.iter_chunked(65_536):
121
+ if received >= max_bytes:
122
+ break
123
+ remaining = max_bytes - received
124
+ if len(chunk) <= remaining:
125
+ received += len(chunk)
126
+ parts.append(chunk)
127
+ else:
128
+ parts.append(chunk[:remaining])
129
+ break
130
+ return b"".join(parts)
131
+
132
+
133
+ async def _drain_aiohttp_body_capped(
134
+ response: aiohttp.ClientResponse, max_bytes: int
135
+ ) -> None:
136
+ if max_bytes <= 0:
137
+ return
138
+ received = 0
139
+ async for chunk in response.content.iter_chunked(65_536):
140
+ received += len(chunk)
141
+ if received >= max_bytes:
142
+ break
143
+
144
+
145
+ class HTTPWebToolsClient:
146
+ """Stateless adapter; each call owns its HTTP resources until completion."""
147
+
148
+ async def search(self, query: str) -> list[WebSearchResult]:
149
+ async with (
150
+ httpx.AsyncClient(
151
+ timeout=_REQUEST_TIMEOUT_S,
152
+ follow_redirects=True,
153
+ headers=_WEB_TOOL_HTTP_HEADERS,
154
+ ) as client,
155
+ client.stream(
156
+ "GET",
157
+ "https://lite.duckduckgo.com/lite/",
158
+ params={"q": query},
159
+ ) as response,
160
+ ):
161
+ response.raise_for_status()
162
+ body_bytes = await _read_response_body_capped(
163
+ response, constants._MAX_WEB_FETCH_RESPONSE_BYTES
164
+ )
165
+ text = body_bytes.decode("utf-8", errors="replace")
166
+ parser = SearchResultParser()
167
+ parser.feed(text)
168
+ return parser.results[:_MAX_SEARCH_RESULTS]
169
+
170
+ async def fetch(self, url: str, *, egress: WebFetchEgressPolicy) -> WebFetchResult:
171
+ """Fetch URL with manual redirects; each hop is DNS-pinned to validated addresses."""
172
+ current_url = url
173
+ redirect_hops = 0
174
+ timeout = ClientTimeout(total=_REQUEST_TIMEOUT_S)
175
+
176
+ while True:
177
+ addr_infos = await asyncio.to_thread(
178
+ get_validated_stream_addrinfos_for_egress, current_url, egress
179
+ )
180
+ host = urlparse(current_url).hostname or ""
181
+ results = getaddrinfo_rows_to_resolve_results(host, addr_infos)
182
+ resolver = _PinnedEgressStaticResolver(results)
183
+ connector = TCPConnector(
184
+ resolver=resolver,
185
+ force_close=True,
186
+ )
187
+ try:
188
+ async with (
189
+ ClientSession(
190
+ timeout=timeout,
191
+ headers=_WEB_TOOL_HTTP_HEADERS,
192
+ connector=connector,
193
+ ) as session,
194
+ session.get(current_url, allow_redirects=False) as response,
195
+ ):
196
+ if response.status in _WEB_FETCH_REDIRECT_STATUSES:
197
+ await _drain_aiohttp_body_capped(
198
+ response, _REDIRECT_RESPONSE_BODY_CAP_BYTES
199
+ )
200
+ if redirect_hops >= constants._MAX_WEB_FETCH_REDIRECTS:
201
+ raise WebFetchEgressViolation(
202
+ "web_fetch exceeded maximum redirects "
203
+ f"({constants._MAX_WEB_FETCH_REDIRECTS})"
204
+ )
205
+ location = response.headers.get("location")
206
+ if not location or not location.strip():
207
+ raise WebFetchEgressViolation(
208
+ "web_fetch redirect response missing Location header"
209
+ )
210
+ current_url = urljoin(str(response.url), location.strip())
211
+ redirect_hops += 1
212
+ continue
213
+ response.raise_for_status()
214
+ content_type = response.headers.get("content-type", "text/plain")
215
+ final_url = str(response.url)
216
+ encoding = response.get_encoding() or "utf-8"
217
+ body_bytes = await _read_aiohttp_body_capped(
218
+ response, constants._MAX_WEB_FETCH_RESPONSE_BYTES
219
+ )
220
+ finally:
221
+ await connector.close()
222
+
223
+ break
224
+
225
+ text = body_bytes.decode(encoding, errors="replace")
226
+ title = final_url
227
+ data = text
228
+ if "html" in content_type.lower():
229
+ parser = HTMLTextParser()
230
+ parser.feed(text)
231
+ title = parser.title or final_url
232
+ data = "\n".join(parser.text_parts)
233
+ return WebFetchResult(
234
+ url=final_url,
235
+ title=title,
236
+ media_type="text/plain",
237
+ data=data[:_MAX_FETCH_CHARS],
238
+ )
@@ -0,0 +1,17 @@
1
+ """Limits and defaults for outbound web server tool HTTP."""
2
+
3
+ from free_claude_code.core.version import package_version
4
+
5
+ _REQUEST_TIMEOUT_S = 20.0
6
+ _MAX_SEARCH_RESULTS = 10
7
+ _MAX_FETCH_CHARS = 24_000
8
+ # Hard cap on raw bytes read from HTTP responses before decode / HTML parse (memory bound).
9
+ _MAX_WEB_FETCH_RESPONSE_BYTES = 2 * 1024 * 1024
10
+ # Drain at most this many bytes from redirect responses before following Location.
11
+ _REDIRECT_RESPONSE_BODY_CAP_BYTES = 65_536
12
+ _MAX_WEB_FETCH_REDIRECTS = 10
13
+ _WEB_FETCH_REDIRECT_STATUSES = frozenset({301, 302, 303, 307, 308})
14
+
15
+ _WEB_TOOL_HTTP_HEADERS = {
16
+ "User-Agent": f"Mozilla/5.0 compatible; free-claude-code/{package_version()}",
17
+ }
@@ -0,0 +1,89 @@
1
+ """Egress policy for user-controlled web_fetch URLs (SSRF guard)."""
2
+
3
+ import ipaddress
4
+ import socket
5
+ from urllib.parse import urlparse
6
+
7
+ from free_claude_code.application.web_tools.ports import (
8
+ WebFetchEgressPolicy,
9
+ WebFetchEgressViolation,
10
+ )
11
+
12
+
13
+ def _port_for_url(parsed) -> int:
14
+ if parsed.port is not None:
15
+ return parsed.port
16
+ return 443 if (parsed.scheme or "").lower() == "https" else 80
17
+
18
+
19
+ def _stream_getaddrinfo_or_raise(host: str, port: int) -> list[tuple]:
20
+ try:
21
+ return socket.getaddrinfo(
22
+ host, port, type=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP
23
+ )
24
+ except OSError as exc:
25
+ raise WebFetchEgressViolation(
26
+ f"Could not resolve host {host!r}: {exc}"
27
+ ) from exc
28
+
29
+
30
+ def get_validated_stream_addrinfos_for_egress(
31
+ url: str, policy: WebFetchEgressPolicy
32
+ ) -> list[tuple]:
33
+ """Resolve and validate a URL for web_fetch, returning getaddrinfo rows for pinning.
34
+
35
+ Each HTTP connect pins to only these `getaddrinfo` results so a malicious DNS
36
+ server cannot rebind to a disallowed address between resolution and the TCP
37
+ connect (used by :meth:`runtime.web_tools.client.HTTPWebToolsClient.fetch`).
38
+ """
39
+ parsed = urlparse(url)
40
+ scheme = (parsed.scheme or "").lower()
41
+ if scheme not in policy.allowed_schemes:
42
+ raise WebFetchEgressViolation(
43
+ f"URL scheme {scheme!r} is not allowed for web_fetch"
44
+ )
45
+
46
+ host = parsed.hostname
47
+ if host is None or host == "":
48
+ raise WebFetchEgressViolation("web_fetch URL must include a host")
49
+
50
+ port = _port_for_url(parsed)
51
+
52
+ if policy.allow_private_network_targets:
53
+ return _stream_getaddrinfo_or_raise(host, port)
54
+
55
+ host_lower = host.lower()
56
+ if host_lower == "localhost" or host_lower.endswith(".localhost"):
57
+ raise WebFetchEgressViolation("localhost targets are not allowed for web_fetch")
58
+ if host_lower.endswith(".local"):
59
+ raise WebFetchEgressViolation(".local hostnames are not allowed for web_fetch")
60
+
61
+ try:
62
+ parsed_ip = ipaddress.ip_address(host)
63
+ except ValueError:
64
+ parsed_ip = None
65
+
66
+ if parsed_ip is not None:
67
+ if not parsed_ip.is_global:
68
+ raise WebFetchEgressViolation(
69
+ f"Non-public IP host {host!r} is not allowed for web_fetch"
70
+ )
71
+ return _stream_getaddrinfo_or_raise(host, port)
72
+
73
+ infos = _stream_getaddrinfo_or_raise(host, port)
74
+ for *_, sockaddr in infos:
75
+ addr = sockaddr[0]
76
+ try:
77
+ resolved = ipaddress.ip_address(addr)
78
+ except ValueError:
79
+ continue
80
+ if not resolved.is_global:
81
+ raise WebFetchEgressViolation(
82
+ f"Host {host!r} resolves to a non-public address ({resolved})"
83
+ )
84
+ return infos
85
+
86
+
87
+ def enforce_web_fetch_egress(url: str, policy: WebFetchEgressPolicy) -> None:
88
+ """Validate ``url`` (scheme, host, and resolved addresses) for web_fetch."""
89
+ get_validated_stream_addrinfos_for_egress(url, policy)
@@ -0,0 +1,78 @@
1
+ """HTML parsing for web_search / web_fetch."""
2
+
3
+ import html
4
+ from html.parser import HTMLParser
5
+ from urllib.parse import parse_qs, unquote, urlparse
6
+
7
+ from free_claude_code.core.web_tools import WebSearchResult
8
+
9
+
10
+ class SearchResultParser(HTMLParser):
11
+ """DuckDuckGo lite HTML: extract result links and titles."""
12
+
13
+ def __init__(self) -> None:
14
+ super().__init__()
15
+ self.results: list[WebSearchResult] = []
16
+ self._href: str | None = None
17
+ self._title_parts: list[str] = []
18
+
19
+ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
20
+ if tag != "a":
21
+ return
22
+ href = dict(attrs).get("href")
23
+ if not href or "uddg=" not in href:
24
+ return
25
+ parsed = urlparse(href)
26
+ query = parse_qs(parsed.query)
27
+ uddg = query.get("uddg", [""])[0]
28
+ if not uddg:
29
+ return
30
+ self._href = unquote(uddg)
31
+ self._title_parts = []
32
+
33
+ def handle_data(self, data: str) -> None:
34
+ if self._href is not None:
35
+ self._title_parts.append(data)
36
+
37
+ def handle_endtag(self, tag: str) -> None:
38
+ if tag != "a" or self._href is None:
39
+ return
40
+ title = " ".join("".join(self._title_parts).split())
41
+ if title and not any(result.url == self._href for result in self.results):
42
+ self.results.append(
43
+ WebSearchResult(title=html.unescape(title), url=self._href)
44
+ )
45
+ self._href = None
46
+ self._title_parts = []
47
+
48
+
49
+ class HTMLTextParser(HTMLParser):
50
+ """Strip scripts/styles and collect visible text + title for fetch previews."""
51
+
52
+ def __init__(self) -> None:
53
+ super().__init__()
54
+ self.title = ""
55
+ self.text_parts: list[str] = []
56
+ self._in_title = False
57
+ self._skip_depth = 0
58
+
59
+ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
60
+ if tag in {"script", "style", "noscript"}:
61
+ self._skip_depth += 1
62
+ elif tag == "title":
63
+ self._in_title = True
64
+
65
+ def handle_endtag(self, tag: str) -> None:
66
+ if tag in {"script", "style", "noscript"} and self._skip_depth:
67
+ self._skip_depth -= 1
68
+ elif tag == "title":
69
+ self._in_title = False
70
+
71
+ def handle_data(self, data: str) -> None:
72
+ text = " ".join(data.split())
73
+ if not text:
74
+ return
75
+ if self._in_title:
76
+ self.title = f"{self.title} {text}".strip()
77
+ elif not self._skip_depth:
78
+ self.text_parts.append(text)
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ set -eu
3
+ installer=$(curl -fsSL "https://raw.githubusercontent.com/Alishahryar1/free-claude-code/main/scripts/install.sh")
4
+ exec sh -c "$installer" sh "$@"
@@ -0,0 +1,5 @@
1
+ @echo off
2
+ (
3
+ powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference = 'Stop'; & ([scriptblock]::Create((Invoke-RestMethod 'https://raw.githubusercontent.com/Alishahryar1/free-claude-code/main/scripts/install.ps1')))" %*
4
+ call exit /b %%errorlevel%%
5
+ )