@scemoon/cdh 1.0.8 → 1.0.9-beta.2

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 (786) hide show
  1. package/ai-dlc-skill/SKILL.md +106 -0
  2. package/ai-dlc-skill/architecture/project-structure.md +78 -0
  3. package/ai-dlc-skill/brownfield/README.md +36 -0
  4. package/ai-dlc-skill/brownfield/entry.md +45 -0
  5. package/ai-dlc-skill/brownfield/generate-context.sh +64 -0
  6. package/ai-dlc-skill/brownfield/scripts/deps.sh +27 -0
  7. package/ai-dlc-skill/brownfield/scripts/discover.sh +34 -0
  8. package/ai-dlc-skill/brownfield/scripts/extract-api.sh +45 -0
  9. package/ai-dlc-skill/components/backend.md +47 -0
  10. package/ai-dlc-skill/components/desktop.md +63 -0
  11. package/ai-dlc-skill/components/mya.md +219 -0
  12. package/ai-dlc-skill/components/native.md +73 -0
  13. package/ai-dlc-skill/components/tta.md +235 -0
  14. package/ai-dlc-skill/components/web.md +77 -0
  15. package/ai-dlc-skill/components/wxa.md +219 -0
  16. package/ai-dlc-skill/contracts/README.md +25 -0
  17. package/ai-dlc-skill/core/adaptive-flow.md +107 -0
  18. package/ai-dlc-skill/core/security.md +29 -0
  19. package/ai-dlc-skill/core/task-registry.md +153 -0
  20. package/ai-dlc-skill/cross-tool/README.md +20 -0
  21. package/ai-dlc-skill/cross-tool/cline/export.sh +38 -0
  22. package/ai-dlc-skill/cross-tool/copilot/export.sh +41 -0
  23. package/ai-dlc-skill/cross-tool/cursor/export.sh +53 -0
  24. package/ai-dlc-skill/cross-tool/onecode/export.sh +27 -0
  25. package/ai-dlc-skill/cross-tool/opencode/export.sh +38 -0
  26. package/ai-dlc-skill/phases/debug/entry.md +48 -0
  27. package/ai-dlc-skill/phases/debug/lifecycle.md +284 -0
  28. package/ai-dlc-skill/phases/deliver/entry.md +35 -0
  29. package/ai-dlc-skill/phases/deliver/lifecycle.md +185 -0
  30. package/ai-dlc-skill/phases/deliver/prompt.md +54 -0
  31. package/ai-dlc-skill/phases/deliver/rules.md +61 -0
  32. package/ai-dlc-skill/phases/plan/design_system/accessibility.md +268 -0
  33. package/ai-dlc-skill/phases/plan/design_system/atomic_design.md +341 -0
  34. package/ai-dlc-skill/phases/plan/design_system/component_spec.md +398 -0
  35. package/ai-dlc-skill/phases/plan/design_system/design_tokens.md +190 -0
  36. package/ai-dlc-skill/phases/plan/design_system/iconography.md +299 -0
  37. package/ai-dlc-skill/phases/plan/design_system/platform_ui/desktop.md +318 -0
  38. package/ai-dlc-skill/phases/plan/design_system/platform_ui/mya.md +354 -0
  39. package/ai-dlc-skill/phases/plan/design_system/platform_ui/native.md +328 -0
  40. package/ai-dlc-skill/phases/plan/design_system/platform_ui/tta.md +394 -0
  41. package/ai-dlc-skill/phases/plan/design_system/platform_ui/web.md +287 -0
  42. package/ai-dlc-skill/phases/plan/design_system/platform_ui/wxa.md +374 -0
  43. package/ai-dlc-skill/phases/plan/design_system/theme_system.md +318 -0
  44. package/ai-dlc-skill/phases/plan/entry.md +33 -0
  45. package/ai-dlc-skill/phases/plan/lifecycle.md +260 -0
  46. package/ai-dlc-skill/phases/plan/prompt.md +75 -0
  47. package/ai-dlc-skill/phases/plan/rules.md +60 -0
  48. package/ai-dlc-skill/phases/understand/entry.md +36 -0
  49. package/ai-dlc-skill/phases/understand/lifecycle.md +184 -0
  50. package/ai-dlc-skill/phases/understand/prompt.md +58 -0
  51. package/ai-dlc-skill/phases/understand/rules.md +49 -0
  52. package/ai-dlc-skill/phases/verify/config/base_url.md +65 -0
  53. package/ai-dlc-skill/phases/verify/entry.md +59 -0
  54. package/ai-dlc-skill/phases/verify/gates/browser_e2e.md +96 -0
  55. package/ai-dlc-skill/phases/verify/lifecycle.md +217 -0
  56. package/ai-dlc-skill/phases/verify/prompt.md +73 -0
  57. package/ai-dlc-skill/phases/verify/rules.md +91 -0
  58. package/ai-dlc-skill/phases/verify/runners/playwright_local.md +103 -0
  59. package/ai-dlc-skill/practices/bdd.md +119 -0
  60. package/ai-dlc-skill/practices/sdd.md +84 -0
  61. package/ai-dlc-skill/practices/tdd.md +128 -0
  62. package/ai-dlc-skill/providers/README.md +114 -0
  63. package/ai-dlc-skill/providers/aliyun/SKILL.md +204 -0
  64. package/ai-dlc-skill/providers/aliyun/api/rest-api.md +214 -0
  65. package/ai-dlc-skill/providers/aliyun/api/sdk.md +307 -0
  66. package/ai-dlc-skill/providers/aliyun/best-practices/database-design.md +363 -0
  67. package/ai-dlc-skill/providers/aliyun/best-practices/function-design.md +424 -0
  68. package/ai-dlc-skill/providers/aliyun/best-practices/troubleshooting.md +258 -0
  69. package/ai-dlc-skill/providers/aliyun/cli/database.md +263 -0
  70. package/ai-dlc-skill/providers/aliyun/cli/functions.md +263 -0
  71. package/ai-dlc-skill/providers/aliyun/cli/hosting.md +226 -0
  72. package/ai-dlc-skill/providers/aliyun/cli/setup.md +235 -0
  73. package/ai-dlc-skill/providers/aliyun/cli/storage.md +315 -0
  74. package/ai-dlc-skill/providers/aliyun/deployment.yaml +66 -0
  75. package/ai-dlc-skill/providers/aliyun/integration/ci-cd.md +288 -0
  76. package/ai-dlc-skill/providers/aliyun/preview.yaml +84 -0
  77. package/ai-dlc-skill/providers/aliyun/provider.yaml +160 -0
  78. package/ai-dlc-skill/providers/aliyun/security/authentication.md +254 -0
  79. package/ai-dlc-skill/providers/aliyun/services/cdn-hosting.md +220 -0
  80. package/ai-dlc-skill/providers/aliyun/services/database.md +319 -0
  81. package/ai-dlc-skill/providers/aliyun/services/function-compute.md +273 -0
  82. package/ai-dlc-skill/providers/aliyun/services/overview.md +163 -0
  83. package/ai-dlc-skill/providers/aliyun/services/serverless-app-engine.md +266 -0
  84. package/ai-dlc-skill/providers/aliyun/services/storage.md +269 -0
  85. package/ai-dlc-skill/providers/tcb/SKILL.md +208 -0
  86. package/ai-dlc-skill/providers/tcb/api/rest-api.md +338 -0
  87. package/ai-dlc-skill/providers/tcb/api/sdk.md +288 -0
  88. package/ai-dlc-skill/providers/tcb/best-practices/database-design.md +452 -0
  89. package/ai-dlc-skill/providers/tcb/best-practices/function-design.md +502 -0
  90. package/ai-dlc-skill/providers/tcb/best-practices/troubleshooting.md +462 -0
  91. package/ai-dlc-skill/providers/tcb/cli/cls.md +133 -0
  92. package/ai-dlc-skill/providers/tcb/cli/database.md +230 -0
  93. package/ai-dlc-skill/providers/tcb/cli/env.md +207 -0
  94. package/ai-dlc-skill/providers/tcb/cli/functions.md +276 -0
  95. package/ai-dlc-skill/providers/tcb/cli/hosting.md +219 -0
  96. package/ai-dlc-skill/providers/tcb/cli/setup.md +218 -0
  97. package/ai-dlc-skill/providers/tcb/cli/storage.md +233 -0
  98. package/ai-dlc-skill/providers/tcb/deployment.yaml +111 -0
  99. package/ai-dlc-skill/providers/tcb/integration/ci-cd.md +309 -0
  100. package/ai-dlc-skill/providers/tcb/integration/mcp-server.md +371 -0
  101. package/ai-dlc-skill/providers/tcb/preview.yaml +83 -0
  102. package/ai-dlc-skill/providers/tcb/provider.yaml +172 -0
  103. package/ai-dlc-skill/providers/tcb/security/authentication.md +241 -0
  104. package/ai-dlc-skill/providers/tcb/services/cloud-database.md +299 -0
  105. package/ai-dlc-skill/providers/tcb/services/cloud-functions.md +265 -0
  106. package/ai-dlc-skill/providers/tcb/services/cloud-hosting.md +264 -0
  107. package/ai-dlc-skill/providers/tcb/services/cloud-run.md +285 -0
  108. package/ai-dlc-skill/providers/tcb/services/cloud-storage.md +245 -0
  109. package/ai-dlc-skill/providers/tcb/services/overview.md +174 -0
  110. package/ai-dlc-skill/pybdd/README.md +41 -0
  111. package/ai-dlc-skill/pybdd/conftest.py +17 -0
  112. package/ai-dlc-skill/pybdd/example/auth/login.feature +32 -0
  113. package/ai-dlc-skill/pybdd/pytest.ini +5 -0
  114. package/ai-dlc-skill/pybdd/steps/.gitkeep +1 -0
  115. package/ai-dlc-skill/pybdd/steps/test_example_steps.py +65 -0
  116. package/ai-dlc-skill/requirements.md +140 -0
  117. package/ai-dlc-skill/skill.yaml +135 -0
  118. package/ai-dlc-skill/templates/brownfield/context.md +78 -0
  119. package/ai-dlc-skill/templates/integration/CHANGELOG.md +41 -0
  120. package/ai-dlc-skill/templates/integration/asyncapi.yaml +43 -0
  121. package/ai-dlc-skill/templates/integration/contract-diff.md +63 -0
  122. package/ai-dlc-skill/templates/integration/contract-spec.md +49 -0
  123. package/ai-dlc-skill/templates/integration/openapi.yaml +18 -0
  124. package/ai-dlc-skill/templates/integration/runtime-contract.yaml +36 -0
  125. package/ai-dlc-skill/templates/plan/design.md +49 -0
  126. package/ai-dlc-skill/templates/plan/task-list.md +32 -0
  127. package/ai-dlc-skill/templates/project/README.md +126 -0
  128. package/ai-dlc-skill/templates/project/template.md +119 -0
  129. package/ai-dlc-skill/templates/understand/feature.feature +30 -0
  130. package/ai-dlc-skill/templates/understand/intent.md +29 -0
  131. package/ai-dlc-skill/templates/understand/spec-delta.md +47 -0
  132. package/ai-dlc-skill/templates/verify/test-unit.py +27 -0
  133. package/ai-dlc-skill/walkthrough/collect.sh +50 -0
  134. package/ai-dlc-skill/walkthrough/template.md +54 -0
  135. package/cdh/__init__.py +0 -0
  136. package/cdh/__main__.py +4 -0
  137. package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
  138. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  139. package/cdh/__pycache__/cli_logging.cpython-314.pyc +0 -0
  140. package/cdh/__pycache__/config.cpython-314.pyc +0 -0
  141. package/cdh/__pycache__/project_loader.cpython-314.pyc +0 -0
  142. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  143. package/cdh/__pycache__/session_store.cpython-314.pyc +0 -0
  144. package/cdh/cdh_session_aggregator.py +258 -0
  145. package/cdh/cli.py +3000 -0
  146. package/cdh/cli_logging.py +45 -0
  147. package/cdh/config.py +28 -0
  148. package/cdh/event_loop/__init__.py +7 -0
  149. package/cdh/event_loop/bus.py +123 -0
  150. package/cdh/event_loop/events.py +25 -0
  151. package/cdh/event_loop/runner.py +28 -0
  152. package/cdh/event_loop/scheduler.py +158 -0
  153. package/cdh/generators/__init__.py +35 -0
  154. package/cdh/generators/_runtime.py +176 -0
  155. package/cdh/generators/ada/MANIFEST.toml +14 -0
  156. package/cdh/generators/ada/template.ads.tmpl +7 -0
  157. package/cdh/generators/bash/MANIFEST.toml +14 -0
  158. package/cdh/generators/bash/template.sh.tmpl +16 -0
  159. package/cdh/generators/builtin_index.json +590 -0
  160. package/cdh/generators/c/MANIFEST.toml +14 -0
  161. package/cdh/generators/c/template.h.tmpl +20 -0
  162. package/cdh/generators/cli.py +379 -0
  163. package/cdh/generators/clojure/MANIFEST.toml +14 -0
  164. package/cdh/generators/clojure/template.clj.tmpl +13 -0
  165. package/cdh/generators/cobol/MANIFEST.toml +14 -0
  166. package/cdh/generators/cobol/template.cbl.tmpl +14 -0
  167. package/cdh/generators/cpp/MANIFEST.toml +14 -0
  168. package/cdh/generators/cpp/template.hpp.tmpl +32 -0
  169. package/cdh/generators/crystal/MANIFEST.toml +14 -0
  170. package/cdh/generators/crystal/template.cr.tmpl +11 -0
  171. package/cdh/generators/csharp/MANIFEST.toml +23 -0
  172. package/cdh/generators/csharp/template.cs.tmpl +14 -0
  173. package/cdh/generators/cython/MANIFEST.toml +14 -0
  174. package/cdh/generators/cython/template.pyx.tmpl +17 -0
  175. package/cdh/generators/d/MANIFEST.toml +14 -0
  176. package/cdh/generators/d/template.d.tmpl +24 -0
  177. package/cdh/generators/dart/MANIFEST.toml +17 -0
  178. package/cdh/generators/dart/template.dart.tmpl +27 -0
  179. package/cdh/generators/elixir/MANIFEST.toml +17 -0
  180. package/cdh/generators/elixir/template.ex.tmpl +27 -0
  181. package/cdh/generators/elm/MANIFEST.toml +14 -0
  182. package/cdh/generators/elm/template.elm.tmpl +20 -0
  183. package/cdh/generators/erlang/MANIFEST.toml +14 -0
  184. package/cdh/generators/erlang/template.erl.tmpl +18 -0
  185. package/cdh/generators/fortran/MANIFEST.toml +14 -0
  186. package/cdh/generators/fortran/template.f90.tmpl +24 -0
  187. package/cdh/generators/fsharp/MANIFEST.toml +14 -0
  188. package/cdh/generators/fsharp/template.fs.tmpl +17 -0
  189. package/cdh/generators/go/MANIFEST.toml +18 -0
  190. package/cdh/generators/go/imports.go.tmpl +3 -0
  191. package/cdh/generators/go/template.go.tmpl +9 -0
  192. package/cdh/generators/graphql-schema/MANIFEST.toml +18 -0
  193. package/cdh/generators/graphql-schema/template.graphqls.tmpl +12 -0
  194. package/cdh/generators/groovy/MANIFEST.toml +14 -0
  195. package/cdh/generators/groovy/template.groovy.tmpl +28 -0
  196. package/cdh/generators/hack/MANIFEST.toml +14 -0
  197. package/cdh/generators/hack/template.hh.tmpl +24 -0
  198. package/cdh/generators/haskell/MANIFEST.toml +14 -0
  199. package/cdh/generators/haskell/template.hs.tmpl +20 -0
  200. package/cdh/generators/haxe/MANIFEST.toml +14 -0
  201. package/cdh/generators/haxe/template.hx.tmpl +20 -0
  202. package/cdh/generators/idris/MANIFEST.toml +14 -0
  203. package/cdh/generators/idris/template.idr.tmpl +22 -0
  204. package/cdh/generators/java/MANIFEST.toml +18 -0
  205. package/cdh/generators/java/template.java.tmpl +13 -0
  206. package/cdh/generators/julia/MANIFEST.toml +14 -0
  207. package/cdh/generators/julia/template.jl.tmpl +27 -0
  208. package/cdh/generators/kotlin/MANIFEST.toml +18 -0
  209. package/cdh/generators/kotlin/template.kt.tmpl +12 -0
  210. package/cdh/generators/lua/MANIFEST.toml +14 -0
  211. package/cdh/generators/lua/template.lua.tmpl +27 -0
  212. package/cdh/generators/matlab/MANIFEST.toml +14 -0
  213. package/cdh/generators/matlab/template.m.tmpl +26 -0
  214. package/cdh/generators/nim/MANIFEST.toml +14 -0
  215. package/cdh/generators/nim/template.nim.tmpl +12 -0
  216. package/cdh/generators/nix/MANIFEST.toml +14 -0
  217. package/cdh/generators/nix/template.nix.tmpl +8 -0
  218. package/cdh/generators/objective-c/MANIFEST.toml +14 -0
  219. package/cdh/generators/objective-c/template.m.tmpl +31 -0
  220. package/cdh/generators/ocaml/MANIFEST.toml +14 -0
  221. package/cdh/generators/ocaml/template.ml.tmpl +13 -0
  222. package/cdh/generators/pascal/MANIFEST.toml +14 -0
  223. package/cdh/generators/pascal/template.pas.tmpl +5 -0
  224. package/cdh/generators/perl/MANIFEST.toml +14 -0
  225. package/cdh/generators/perl/template.pm.tmpl +27 -0
  226. package/cdh/generators/php/MANIFEST.toml +17 -0
  227. package/cdh/generators/php/template.php.tmpl +31 -0
  228. package/cdh/generators/powershell/MANIFEST.toml +14 -0
  229. package/cdh/generators/powershell/template.ps1.tmpl +20 -0
  230. package/cdh/generators/protobuf/MANIFEST.toml +18 -0
  231. package/cdh/generators/protobuf/template.proto.tmpl +13 -0
  232. package/cdh/generators/python/MANIFEST.toml +18 -0
  233. package/cdh/generators/python/template.py.tmpl +12 -0
  234. package/cdh/generators/r/MANIFEST.toml +14 -0
  235. package/cdh/generators/r/template.R.tmpl +29 -0
  236. package/cdh/generators/racket/MANIFEST.toml +14 -0
  237. package/cdh/generators/racket/template.rkt.tmpl +15 -0
  238. package/cdh/generators/registry.py +211 -0
  239. package/cdh/generators/ruby/MANIFEST.toml +17 -0
  240. package/cdh/generators/ruby/template.rb.tmpl +27 -0
  241. package/cdh/generators/rust/MANIFEST.toml +18 -0
  242. package/cdh/generators/rust/template.rs.tmpl +16 -0
  243. package/cdh/generators/scala/MANIFEST.toml +20 -0
  244. package/cdh/generators/scala/template.scala.tmpl +13 -0
  245. package/cdh/generators/scheme/MANIFEST.toml +14 -0
  246. package/cdh/generators/scheme/template.scm.tmpl +16 -0
  247. package/cdh/generators/solidity/MANIFEST.toml +14 -0
  248. package/cdh/generators/solidity/template.sol.tmpl +24 -0
  249. package/cdh/generators/swift/MANIFEST.toml +18 -0
  250. package/cdh/generators/swift/template.swift.tmpl +10 -0
  251. package/cdh/generators/typescript/MANIFEST.toml +18 -0
  252. package/cdh/generators/typescript/template.ts.tmpl +7 -0
  253. package/cdh/generators/version.py +214 -0
  254. package/cdh/generators/zig/MANIFEST.toml +14 -0
  255. package/cdh/generators/zig/template.zig.tmpl +20 -0
  256. package/cdh/logging.py +314 -0
  257. package/cdh/optimizer/__init__.py +7 -0
  258. package/cdh/optimizer/loop.py +201 -0
  259. package/cdh/optimizer/mutation.py +85 -0
  260. package/cdh/optimizer/reward.py +51 -0
  261. package/cdh/optimizer/tracker.py +118 -0
  262. package/cdh/project_loader.py +1022 -0
  263. package/cdh/rules/patterns.yaml +132 -0
  264. package/cdh/rules/spectral.yaml +301 -0
  265. package/cdh/scaffold.py +1436 -0
  266. package/cdh/session_store.py +221 -0
  267. package/cdh/state_schema.py +127 -0
  268. package/cdh/tools/__init__.py +57 -0
  269. package/cdh/tools/cls_search.py +406 -0
  270. package/cdh/tools/contract_diff.py +644 -0
  271. package/cdh/tools/deploy_stack.py +590 -0
  272. package/cdh/tools/generate_shared.py +300 -0
  273. package/cdh/tools/iac_gen.py +224 -0
  274. package/cdh/tools/otel_export.py +125 -0
  275. package/cdh/tools/pattern_detect.py +451 -0
  276. package/cdh/tools/retrofit_labels.py +505 -0
  277. package/cdh/trace/__init__.py +101 -0
  278. package/cdh/trace/__pycache__/__init__.cpython-314.pyc +0 -0
  279. package/cdh/trace/dashboard/__init__.py +61 -0
  280. package/cdh/trace/dashboard/api.py +1032 -0
  281. package/cdh/trace/dashboard/app.html +1321 -0
  282. package/cdh/trace/dashboard/server.py +310 -0
  283. package/cdh/trace/otel_exporter.py +462 -0
  284. package/cdh/trace/otel_tracer.py +281 -0
  285. package/cdh/tui.py +1084 -0
  286. package/cdh/validators/__init__.py +16 -0
  287. package/cdh/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  288. package/cdh/validators/__pycache__/bdd.cpython-314.pyc +0 -0
  289. package/cdh/validators/__pycache__/dag.cpython-314.pyc +0 -0
  290. package/cdh/validators/__pycache__/ears.cpython-314.pyc +0 -0
  291. package/cdh/validators/__pycache__/fr_namespace.cpython-314.pyc +0 -0
  292. package/cdh/validators/bdd.py +144 -0
  293. package/cdh/validators/dag.py +179 -0
  294. package/cdh/validators/ears.py +452 -0
  295. package/cdh/validators/fr_namespace.py +143 -0
  296. package/cdh/validators/spectral.py +475 -0
  297. package/cdh/verification/__init__.py +3 -0
  298. package/cdh/verification/aggregation.py +53 -0
  299. package/cdh/verification/gates/__init__.py +5 -0
  300. package/cdh/verification/gates/base.py +18 -0
  301. package/cdh/verification/gates/lint_gate.py +37 -0
  302. package/cdh/verification/gates/test_gate.py +41 -0
  303. package/cdh/verification/loop.py +93 -0
  304. package/cdh/verification/policy.py +24 -0
  305. package/onecode/__init__.py +1 -0
  306. package/onecode/__main__.py +4 -0
  307. package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
  308. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  309. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  310. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  311. package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
  312. package/onecode/agent/__init__.py +0 -0
  313. package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
  314. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  315. package/onecode/agent/__pycache__/checkpoint.cpython-314.pyc +0 -0
  316. package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
  317. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  318. package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
  319. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  320. package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
  321. package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
  322. package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
  323. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  324. package/onecode/agent/__pycache__/turn_record.cpython-314.pyc +0 -0
  325. package/onecode/agent/agents/__init__.py +29 -0
  326. package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
  327. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  328. package/onecode/agent/agents/prompts/build-agent.md +50 -0
  329. package/onecode/agent/agents/prompts/compaction-instructions.md +12 -0
  330. package/onecode/agent/agents/prompts/explore-agent.md +42 -0
  331. package/onecode/agent/agents/prompts/plan-agent.md +44 -0
  332. package/onecode/agent/agents/prompts/plan-gate-hard.md +4 -0
  333. package/onecode/agent/agents/prompts/plan-gate-soft.md +3 -0
  334. package/onecode/agent/agents/prompts/solo-agent.md +57 -0
  335. package/onecode/agent/agents/prompts/subagent-constraints.md +10 -0
  336. package/onecode/agent/agents/prompts/summary-instructions.md +7 -0
  337. package/onecode/agent/agents/prompts/title-instructions.md +3 -0
  338. package/onecode/agent/agents/prompts/tool-descriptions.md +129 -0
  339. package/onecode/agent/agents/types.py +786 -0
  340. package/onecode/agent/attachments.py +112 -0
  341. package/onecode/agent/cdh_loader.py +3 -0
  342. package/onecode/agent/checkpoint.py +285 -0
  343. package/onecode/agent/context.py +465 -0
  344. package/onecode/agent/engine.py +3547 -0
  345. package/onecode/agent/event_bridge.py +75 -0
  346. package/onecode/agent/hooks.py +86 -0
  347. package/onecode/agent/onecode_agent_acp.py +2993 -0
  348. package/onecode/agent/permissions.py +150 -0
  349. package/onecode/agent/permissions_store.py +73 -0
  350. package/onecode/agent/project_doc.py +19 -0
  351. package/onecode/agent/question_detect.py +230 -0
  352. package/onecode/agent/session.py +3 -0
  353. package/onecode/agent/snapshot.py +144 -0
  354. package/onecode/agent/tools/__init__.py +17 -0
  355. package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  356. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  357. package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
  358. package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
  359. package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
  360. package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
  361. package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
  362. package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
  363. package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
  364. package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
  365. package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
  366. package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
  367. package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
  368. package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
  369. package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
  370. package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
  371. package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
  372. package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
  373. package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
  374. package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
  375. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  376. package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
  377. package/onecode/agent/tools/agent_tools.py +128 -0
  378. package/onecode/agent/tools/apply_patch_tool.py +138 -0
  379. package/onecode/agent/tools/bash_tool.py +121 -0
  380. package/onecode/agent/tools/communication_tools.py +154 -0
  381. package/onecode/agent/tools/config_tool.py +130 -0
  382. package/onecode/agent/tools/cron_tools.py +178 -0
  383. package/onecode/agent/tools/errors.py +17 -0
  384. package/onecode/agent/tools/file_ops.py +221 -0
  385. package/onecode/agent/tools/file_tools.py +225 -0
  386. package/onecode/agent/tools/git_tools.py +88 -0
  387. package/onecode/agent/tools/lsp_tools.py +404 -0
  388. package/onecode/agent/tools/mcp_tools.py +211 -0
  389. package/onecode/agent/tools/permission_handler.py +46 -0
  390. package/onecode/agent/tools/permissions.py +77 -0
  391. package/onecode/agent/tools/protocol.py +20 -0
  392. package/onecode/agent/tools/registry.py +210 -0
  393. package/onecode/agent/tools/sandbox.py +460 -0
  394. package/onecode/agent/tools/schema_validation.py +100 -0
  395. package/onecode/agent/tools/skill_tools.py +52 -0
  396. package/onecode/agent/tools/todo_tools.py +208 -0
  397. package/onecode/agent/tools/web_tools.py +530 -0
  398. package/onecode/agent/turn_record.py +28 -0
  399. package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
  400. package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
  401. package/onecode/builtin_skills/cloudbase/SKILL.md +162 -0
  402. package/onecode/builtin_skills/cloudbase/skill.yaml +7 -0
  403. package/onecode/builtin_skills/git/SKILL.md +64 -0
  404. package/onecode/builtin_skills/git/skill.yaml +7 -0
  405. package/onecode/builtin_skills/shell/SKILL.md +58 -0
  406. package/onecode/builtin_skills/shell/skill.yaml +8 -0
  407. package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
  408. package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
  409. package/onecode/cli.py +1325 -0
  410. package/onecode/codebase/__init__.py +69 -0
  411. package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
  412. package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
  413. package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
  414. package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
  415. package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
  416. package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
  417. package/onecode/codebase/chunker.py +125 -0
  418. package/onecode/codebase/indexer.py +154 -0
  419. package/onecode/codebase/retriever.py +240 -0
  420. package/onecode/codebase/storage.py +153 -0
  421. package/onecode/codebase/tools.py +59 -0
  422. package/onecode/commands.py +673 -0
  423. package/onecode/config.py +539 -0
  424. package/onecode/config_screen.py +486 -0
  425. package/onecode/cron/__init__.py +3 -0
  426. package/onecode/lsp/__init__.py +3 -0
  427. package/onecode/mcp/__init__.py +11 -0
  428. package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
  429. package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
  430. package/onecode/mcp/__pycache__/cloudbase.cpython-314.pyc +0 -0
  431. package/onecode/mcp/__pycache__/config.cpython-314.pyc +0 -0
  432. package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
  433. package/onecode/mcp/__pycache__/oauth.cpython-314.pyc +0 -0
  434. package/onecode/mcp/client.py +305 -0
  435. package/onecode/mcp/cloudbase.py +188 -0
  436. package/onecode/mcp/config.py +363 -0
  437. package/onecode/mcp/manager.py +603 -0
  438. package/onecode/mcp/oauth.py +199 -0
  439. package/onecode/memory/__init__.py +106 -0
  440. package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
  441. package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
  442. package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
  443. package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
  444. package/onecode/memory/backend.py +179 -0
  445. package/onecode/memory/pyramid.py +145 -0
  446. package/onecode/memory/recall.py +322 -0
  447. package/onecode/migrate.py +122 -0
  448. package/onecode/models/__init__.py +4 -0
  449. package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
  450. package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
  451. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  452. package/onecode/models/__pycache__/ollama_manager.cpython-314.pyc +0 -0
  453. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  454. package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
  455. package/onecode/models/errors.py +104 -0
  456. package/onecode/models/messages.py +750 -0
  457. package/onecode/models/ollama_manager.py +167 -0
  458. package/onecode/models/provider.py +730 -0
  459. package/onecode/models/providers/__init__.py +17 -0
  460. package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
  461. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  462. package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
  463. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  464. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  465. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  466. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  467. package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
  468. package/onecode/models/providers/anthropic_provider.py +286 -0
  469. package/onecode/models/providers/deepseek_provider.py +221 -0
  470. package/onecode/models/providers/glm_provider.py +219 -0
  471. package/onecode/models/providers/minimax_provider.py +182 -0
  472. package/onecode/models/providers/minimaxi_provider.py +426 -0
  473. package/onecode/models/providers/ollama_provider.py +183 -0
  474. package/onecode/models/providers/openai_provider.py +234 -0
  475. package/onecode/models/registry.py +349 -0
  476. package/onecode/server/__init__.py +3 -0
  477. package/onecode/server/app.py +251 -0
  478. package/onecode/skills/__init__.py +11 -0
  479. package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
  480. package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
  481. package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
  482. package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
  483. package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
  484. package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
  485. package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
  486. package/onecode/skills/argument_substitution.py +38 -0
  487. package/onecode/skills/bootstrap.py +37 -0
  488. package/onecode/skills/create.py +56 -0
  489. package/onecode/skills/frontmatter.py +33 -0
  490. package/onecode/skills/loader.py +215 -0
  491. package/onecode/skills/manager.py +75 -0
  492. package/onecode/skills/model.py +43 -0
  493. package/onecode/storage/__init__.py +0 -0
  494. package/onecode/storage/activity.py +63 -0
  495. package/onecode/storage/project.py +54 -0
  496. package/onecode/storage/session.py +112 -0
  497. package/onecode/tasks/__init__.py +26 -0
  498. package/onecode/tasks/manager.py +232 -0
  499. package/onecode/tasks/models.py +240 -0
  500. package/onecode/trace/__init__.py +0 -0
  501. package/onecode/trace/tracer.py +173 -0
  502. package/onecode/utils/__init__.py +0 -0
  503. package/onecode/utils/helpers.py +20 -0
  504. package/onecode/verification/__init__.py +5 -0
  505. package/onecode/verification/__pycache__/__init__.cpython-314.pyc +0 -0
  506. package/onecode/verification/__pycache__/aggregation.cpython-314.pyc +0 -0
  507. package/onecode/verification/__pycache__/loop.cpython-314.pyc +0 -0
  508. package/onecode/verification/__pycache__/policy.cpython-314.pyc +0 -0
  509. package/onecode/verification/aggregation.py +53 -0
  510. package/onecode/verification/gates/__init__.py +6 -0
  511. package/onecode/verification/gates/__pycache__/__init__.cpython-314.pyc +0 -0
  512. package/onecode/verification/gates/__pycache__/base.cpython-314.pyc +0 -0
  513. package/onecode/verification/gates/__pycache__/lint_gate.cpython-314.pyc +0 -0
  514. package/onecode/verification/gates/__pycache__/test_gate.cpython-314.pyc +0 -0
  515. package/onecode/verification/gates/__pycache__/type_gate.cpython-314.pyc +0 -0
  516. package/onecode/verification/gates/base.py +20 -0
  517. package/onecode/verification/gates/lint_gate.py +45 -0
  518. package/onecode/verification/gates/test_gate.py +62 -0
  519. package/onecode/verification/gates/type_gate.py +46 -0
  520. package/onecode/verification/loop.py +95 -0
  521. package/onecode/verification/policy.py +29 -0
  522. package/package.json +2 -2
  523. package/pyproject.toml +84 -0
  524. package/tui/__init__.py +46 -0
  525. package/tui/__main__.py +4 -0
  526. package/tui/__pycache__/__init__.cpython-314.pyc +0 -0
  527. package/tui/__pycache__/_loop.cpython-314.pyc +0 -0
  528. package/tui/__pycache__/_path_fuzzy_search.cpython-314.pyc +0 -0
  529. package/tui/__pycache__/_path_match.cpython-314.pyc +0 -0
  530. package/tui/__pycache__/agent.cpython-314.pyc +0 -0
  531. package/tui/__pycache__/agent_schema.cpython-314.pyc +0 -0
  532. package/tui/__pycache__/agents.cpython-314.pyc +0 -0
  533. package/tui/__pycache__/answer.cpython-314.pyc +0 -0
  534. package/tui/__pycache__/app.cpython-314.pyc +0 -0
  535. package/tui/__pycache__/atomic.cpython-314.pyc +0 -0
  536. package/tui/__pycache__/complete.cpython-314.pyc +0 -0
  537. package/tui/__pycache__/constants.cpython-314.pyc +0 -0
  538. package/tui/__pycache__/conversation_markdown.cpython-314.pyc +0 -0
  539. package/tui/__pycache__/db.cpython-314.pyc +0 -0
  540. package/tui/__pycache__/dec.cpython-314.pyc +0 -0
  541. package/tui/__pycache__/directory.cpython-314.pyc +0 -0
  542. package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
  543. package/tui/__pycache__/format_path.cpython-314.pyc +0 -0
  544. package/tui/__pycache__/fuzzy.cpython-314.pyc +0 -0
  545. package/tui/__pycache__/fuzzy_index.cpython-314.pyc +0 -0
  546. package/tui/__pycache__/history.cpython-314.pyc +0 -0
  547. package/tui/__pycache__/jsonrpc.cpython-314.pyc +0 -0
  548. package/tui/__pycache__/menus.cpython-314.pyc +0 -0
  549. package/tui/__pycache__/message_log.cpython-314.pyc +0 -0
  550. package/tui/__pycache__/messages.cpython-314.pyc +0 -0
  551. package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
  552. package/tui/__pycache__/path_filter.cpython-314.pyc +0 -0
  553. package/tui/__pycache__/paths.cpython-314.pyc +0 -0
  554. package/tui/__pycache__/pill.cpython-314.pyc +0 -0
  555. package/tui/__pycache__/platform_commands.cpython-314.pyc +0 -0
  556. package/tui/__pycache__/protocol.cpython-314.pyc +0 -0
  557. package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
  558. package/tui/__pycache__/settings.cpython-314.pyc +0 -0
  559. package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
  560. package/tui/__pycache__/shell.cpython-314.pyc +0 -0
  561. package/tui/__pycache__/shell_read.cpython-314.pyc +0 -0
  562. package/tui/__pycache__/slash_command.cpython-314.pyc +0 -0
  563. package/tui/__pycache__/version.cpython-314.pyc +0 -0
  564. package/tui/_loop.py +86 -0
  565. package/tui/_path_fuzzy_search.py +48 -0
  566. package/tui/_path_match.py +141 -0
  567. package/tui/about.py +95 -0
  568. package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
  569. package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
  570. package/tui/acp/__pycache__/encode_tool_call_id.cpython-314.pyc +0 -0
  571. package/tui/acp/__pycache__/event_tap.cpython-314.pyc +0 -0
  572. package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
  573. package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
  574. package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
  575. package/tui/acp/agent.py +1212 -0
  576. package/tui/acp/api.py +79 -0
  577. package/tui/acp/encode_tool_call_id.py +12 -0
  578. package/tui/acp/event_tap.py +107 -0
  579. package/tui/acp/messages.py +222 -0
  580. package/tui/acp/prompt.py +53 -0
  581. package/tui/acp/protocol.py +551 -0
  582. package/tui/agent.py +70 -0
  583. package/tui/agent_schema.py +76 -0
  584. package/tui/agents.py +46 -0
  585. package/tui/ansi/__init__.py +1 -0
  586. package/tui/ansi/__pycache__/__init__.cpython-314.pyc +0 -0
  587. package/tui/ansi/__pycache__/_ansi.cpython-314.pyc +0 -0
  588. package/tui/ansi/__pycache__/_ansi_colors.cpython-314.pyc +0 -0
  589. package/tui/ansi/__pycache__/_control_codes.cpython-314.pyc +0 -0
  590. package/tui/ansi/__pycache__/_keys.cpython-314.pyc +0 -0
  591. package/tui/ansi/__pycache__/_sgr_styles.cpython-314.pyc +0 -0
  592. package/tui/ansi/__pycache__/_stream_parser.cpython-314.pyc +0 -0
  593. package/tui/ansi/_ansi.py +1689 -0
  594. package/tui/ansi/_ansi_colors.py +264 -0
  595. package/tui/ansi/_control_codes.py +37 -0
  596. package/tui/ansi/_keys.py +251 -0
  597. package/tui/ansi/_sgr_styles.py +64 -0
  598. package/tui/ansi/_stream_parser.py +418 -0
  599. package/tui/answer.py +12 -0
  600. package/tui/app.py +1195 -0
  601. package/tui/atomic.py +37 -0
  602. package/tui/cli.py +208 -0
  603. package/tui/code_analyze.py +27 -0
  604. package/tui/complete.py +38 -0
  605. package/tui/constants.py +61 -0
  606. package/tui/conversation_markdown.py +30 -0
  607. package/tui/danger.py +372 -0
  608. package/tui/data/agents/ampcode.com.toml +52 -0
  609. package/tui/data/agents/augmentcode.com.toml +41 -0
  610. package/tui/data/agents/cdh.cloud-dev-harness.toml +23 -0
  611. package/tui/data/agents/claude.com.toml +41 -0
  612. package/tui/data/agents/copilot.github.com.toml +29 -0
  613. package/tui/data/agents/crowai.dev.toml +36 -0
  614. package/tui/data/agents/cursor.com.toml +38 -0
  615. package/tui/data/agents/deepagents.langchain.com +34 -0
  616. package/tui/data/agents/docker.com.toml +60 -0
  617. package/tui/data/agents/geminicli.com.toml +28 -0
  618. package/tui/data/agents/goose.ai.toml +52 -0
  619. package/tui/data/agents/inference.huggingface.co.toml +41 -0
  620. package/tui/data/agents/kimi.com.toml +35 -0
  621. package/tui/data/agents/kiro.dev.toml +43 -0
  622. package/tui/data/agents/onecode.dev.toml +22 -0
  623. package/tui/data/agents/openai.com.toml +53 -0
  624. package/tui/data/agents/openclaw.ai.toml +37 -0
  625. package/tui/data/agents/opencode.ai.toml +39 -0
  626. package/tui/data/agents/openhands.dev.toml +46 -0
  627. package/tui/data/agents/stakpak.dev.toml +62 -0
  628. package/tui/data/agents/vibe.mistral.ai.toml +31 -0
  629. package/tui/data/agents/vtcode.dev.toml +63 -0
  630. package/tui/data/images/frog.png +0 -0
  631. package/tui/data/sounds/question.wav +0 -0
  632. package/tui/data/sounds/turn-over.wav +0 -0
  633. package/tui/db.py +213 -0
  634. package/tui/dec.py +332 -0
  635. package/tui/diff_utils.py +131 -0
  636. package/tui/directory.py +234 -0
  637. package/tui/directory_suggester.py +93 -0
  638. package/tui/directory_watcher.py +231 -0
  639. package/tui/format_path.py +25 -0
  640. package/tui/fuzzy.py +140 -0
  641. package/tui/fuzzy_index.py +275 -0
  642. package/tui/gist.py +33 -0
  643. package/tui/history.py +138 -0
  644. package/tui/jsonrpc.py +599 -0
  645. package/tui/menus.py +14 -0
  646. package/tui/message_log.py +69 -0
  647. package/tui/messages.py +144 -0
  648. package/tui/option_content.py +51 -0
  649. package/tui/os.py +0 -0
  650. package/tui/path_complete.py +217 -0
  651. package/tui/path_filter.py +124 -0
  652. package/tui/paths.py +87 -0
  653. package/tui/pill.py +23 -0
  654. package/tui/platform_commands.py +52 -0
  655. package/tui/prompt/__pycache__/extract.cpython-314.pyc +0 -0
  656. package/tui/prompt/__pycache__/resource.cpython-314.pyc +0 -0
  657. package/tui/prompt/extract.py +19 -0
  658. package/tui/prompt/resource.py +68 -0
  659. package/tui/protocol.py +28 -0
  660. package/tui/screens/__init__.py +0 -0
  661. package/tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
  662. package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
  663. package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
  664. package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
  665. package/tui/screens/action_modal.py +94 -0
  666. package/tui/screens/agent_modal.py +175 -0
  667. package/tui/screens/command_edit_modal.py +74 -0
  668. package/tui/screens/diff_explorer_screen.py +419 -0
  669. package/tui/screens/diff_screen.py +84 -0
  670. package/tui/screens/ide_screen.py +461 -0
  671. package/tui/screens/main.py +397 -0
  672. package/tui/screens/main.tcss +662 -0
  673. package/tui/screens/permissions.py +404 -0
  674. package/tui/screens/permissions.tcss +72 -0
  675. package/tui/screens/projects.tcss +84 -0
  676. package/tui/screens/projects_app.py +341 -0
  677. package/tui/screens/projects_screen.py +277 -0
  678. package/tui/screens/session_resume_modal.py +172 -0
  679. package/tui/screens/session_resume_modal.tcss +35 -0
  680. package/tui/screens/sessions.py +171 -0
  681. package/tui/screens/sessions.tcss +119 -0
  682. package/tui/screens/settings.py +293 -0
  683. package/tui/screens/settings.tcss +113 -0
  684. package/tui/screens/store.py +502 -0
  685. package/tui/screens/store.tcss +274 -0
  686. package/tui/screens/tool_content_screen.py +59 -0
  687. package/tui/screens/trace.py +317 -0
  688. package/tui/session_tracker.py +123 -0
  689. package/tui/settings.py +353 -0
  690. package/tui/settings_schema.py +467 -0
  691. package/tui/shell.py +304 -0
  692. package/tui/shell_read.py +42 -0
  693. package/tui/slash_command.py +34 -0
  694. package/tui/tui.tcss +246 -0
  695. package/tui/twitter.py +38 -0
  696. package/tui/version.py +80 -0
  697. package/tui/visuals/__init__.py +0 -0
  698. package/tui/visuals/__pycache__/__init__.cpython-314.pyc +0 -0
  699. package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
  700. package/tui/visuals/columns.py +272 -0
  701. package/tui/widgets/__init__.py +0 -0
  702. package/tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
  703. package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
  704. package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
  705. package/tui/widgets/__pycache__/aidlc.cpython-314.pyc +0 -0
  706. package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
  707. package/tui/widgets/__pycache__/condensed_path.cpython-314.pyc +0 -0
  708. package/tui/widgets/__pycache__/context_stats.cpython-314.pyc +0 -0
  709. package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
  710. package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
  711. package/tui/widgets/__pycache__/flash.cpython-314.pyc +0 -0
  712. package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
  713. package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
  714. package/tui/widgets/__pycache__/highlighted_textarea.cpython-314.pyc +0 -0
  715. package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
  716. package/tui/widgets/__pycache__/menu.cpython-314.pyc +0 -0
  717. package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
  718. package/tui/widgets/__pycache__/non_selectable_label.cpython-314.pyc +0 -0
  719. package/tui/widgets/__pycache__/note.cpython-314.pyc +0 -0
  720. package/tui/widgets/__pycache__/path_search.cpython-314.pyc +0 -0
  721. package/tui/widgets/__pycache__/pending_prompts.cpython-314.pyc +0 -0
  722. package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
  723. package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
  724. package/tui/widgets/__pycache__/prompt.cpython-314.pyc +0 -0
  725. package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
  726. package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
  727. package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
  728. package/tui/widgets/__pycache__/session_tabs.cpython-314.pyc +0 -0
  729. package/tui/widgets/__pycache__/shell_terminal.cpython-314.pyc +0 -0
  730. package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
  731. package/tui/widgets/__pycache__/slash_complete.cpython-314.pyc +0 -0
  732. package/tui/widgets/__pycache__/strike_text.cpython-314.pyc +0 -0
  733. package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
  734. package/tui/widgets/__pycache__/throbber.cpython-314.pyc +0 -0
  735. package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
  736. package/tui/widgets/__pycache__/user_input.cpython-314.pyc +0 -0
  737. package/tui/widgets/acp_content.py +70 -0
  738. package/tui/widgets/agent_response.py +76 -0
  739. package/tui/widgets/agent_thought.py +167 -0
  740. package/tui/widgets/aidlc.py +334 -0
  741. package/tui/widgets/ask_user.py +604 -0
  742. package/tui/widgets/command_pane.py +223 -0
  743. package/tui/widgets/condensed_path.py +115 -0
  744. package/tui/widgets/context_stats.py +66 -0
  745. package/tui/widgets/conversation.py +3235 -0
  746. package/tui/widgets/danger_warning.py +65 -0
  747. package/tui/widgets/diff_view.py +69 -0
  748. package/tui/widgets/directory_input.py +8 -0
  749. package/tui/widgets/edit_field.py +206 -0
  750. package/tui/widgets/flash.py +81 -0
  751. package/tui/widgets/future_text.py +126 -0
  752. package/tui/widgets/grid_select.py +234 -0
  753. package/tui/widgets/highlighted_textarea.py +183 -0
  754. package/tui/widgets/load_more.py +24 -0
  755. package/tui/widgets/mandelbrot.py +294 -0
  756. package/tui/widgets/markdown_note.py +13 -0
  757. package/tui/widgets/menu.py +147 -0
  758. package/tui/widgets/model_status.py +230 -0
  759. package/tui/widgets/modified_files.py +315 -0
  760. package/tui/widgets/non_selectable_label.py +5 -0
  761. package/tui/widgets/note.py +18 -0
  762. package/tui/widgets/path_search.py +492 -0
  763. package/tui/widgets/pending_prompts.py +36 -0
  764. package/tui/widgets/plan.py +285 -0
  765. package/tui/widgets/project_directory_tree.py +102 -0
  766. package/tui/widgets/project_grid_select.py +68 -0
  767. package/tui/widgets/project_summary.py +33 -0
  768. package/tui/widgets/prompt.py +935 -0
  769. package/tui/widgets/question.py +360 -0
  770. package/tui/widgets/session_grid_select.py +230 -0
  771. package/tui/widgets/session_summary.py +115 -0
  772. package/tui/widgets/session_tabs.py +194 -0
  773. package/tui/widgets/shell_result.py +35 -0
  774. package/tui/widgets/shell_terminal.py +40 -0
  775. package/tui/widgets/side_bar.py +124 -0
  776. package/tui/widgets/slash_complete.py +235 -0
  777. package/tui/widgets/strike_text.py +70 -0
  778. package/tui/widgets/subagent.py +287 -0
  779. package/tui/widgets/subagent_screen.py +715 -0
  780. package/tui/widgets/terminal.py +576 -0
  781. package/tui/widgets/terminal_tool.py +360 -0
  782. package/tui/widgets/throbber.py +100 -0
  783. package/tui/widgets/tool_call.py +432 -0
  784. package/tui/widgets/user_input.py +23 -0
  785. package/tui/widgets/version.py +5 -0
  786. package/tui/widgets/welcome.py +31 -0
@@ -0,0 +1,730 @@
1
+ from __future__ import annotations
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import logging
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+ from typing import Any, AsyncIterator, Callable, Optional
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class ChatResponse:
15
+ """Structured response from a streaming provider call (Clawd-Code style).
16
+
17
+ Unlike ModelResponse (which uses ContentBlock list), ChatResponse provides
18
+ a flat structure for the agent loop: content text + structured tool_uses + usage.
19
+ """
20
+ content: str = ""
21
+ tool_uses: list[dict[str, Any]] = field(default_factory=list)
22
+ usage: dict[str, int] = field(default_factory=dict)
23
+
24
+
25
+ class ContentBlockType(str, Enum):
26
+ TEXT = "text"
27
+ IMAGE = "image"
28
+ THINKING = "thinking"
29
+ TOOL_USE = "tool_use"
30
+ TOOL_RESULT = "tool_result"
31
+ SERVER_TOOL_USE = "server_tool_use"
32
+ TOOL_SEARCH_RESULT = "tool_search_tool_result"
33
+ CODE_EXECUTION_RESULT = "code_execution_tool_result"
34
+
35
+
36
+ @dataclass
37
+ class ToolUse:
38
+ id: str
39
+ name: str
40
+ input: dict[str, Any]
41
+ caller: str = "agent"
42
+
43
+
44
+ @dataclass
45
+ class ServerToolUse:
46
+ id: str
47
+ name: str
48
+ input: dict[str, Any]
49
+
50
+
51
+ @dataclass
52
+ class ToolSearchResult:
53
+ tool_use_id: str
54
+ content: Any # Can be dict with search results
55
+
56
+
57
+ @dataclass
58
+ class CodeExecutionResult:
59
+ tool_use_id: str
60
+ content: Any # Can be dict with execution output
61
+
62
+
63
+ @dataclass
64
+ class ImageContent:
65
+ data: str # base64-encoded image data
66
+ mime_type: str = "image/png"
67
+
68
+
69
+ @dataclass
70
+ class ToolResult:
71
+ tool_use_id: str
72
+ content: str
73
+ is_error: bool = False
74
+ content_blocks: list["ContentBlock"] = field(default_factory=list)
75
+
76
+
77
+ @dataclass
78
+ class ContentBlock:
79
+ type: ContentBlockType
80
+ text: Optional[str] = None
81
+ thinking: Optional[str] = None
82
+ image: Optional[ImageContent] = None
83
+ tool_use: Optional[ToolUse] = None
84
+ tool_result: Optional[ToolResult] = None
85
+ server_tool_use: Optional[ServerToolUse] = None
86
+ tool_search_result: Optional[ToolSearchResult] = None
87
+ code_execution_result: Optional[CodeExecutionResult] = None
88
+ cache_control: Optional[str] = None
89
+
90
+
91
+ @dataclass
92
+ class Message:
93
+ role: str # user | assistant | system | tool
94
+ content: list[ContentBlock] = field(default_factory=list)
95
+ name: Optional[str] = None
96
+
97
+ def __init__(self, role: str, content: str | list[ContentBlock] = "", name: Optional[str] = None):
98
+ self.role = role
99
+ self.name = name
100
+ if isinstance(content, str):
101
+ if role == "tool" and name:
102
+ self.content = [ContentBlock(
103
+ type=ContentBlockType.TOOL_RESULT,
104
+ tool_result=ToolResult(tool_use_id=name, content=content),
105
+ )]
106
+ else:
107
+ self.content = [ContentBlock(type=ContentBlockType.TEXT, text=content)] if content else []
108
+ else:
109
+ self.content = content
110
+
111
+ def add_text(self, text: str) -> None:
112
+ self.content.append(ContentBlock(type=ContentBlockType.TEXT, text=text))
113
+
114
+ def add_image(self, data: str, mime_type: str = "image/png") -> None:
115
+ self.content.append(ContentBlock(
116
+ type=ContentBlockType.IMAGE,
117
+ image=ImageContent(data=data, mime_type=mime_type),
118
+ ))
119
+
120
+ def add_thinking(self, thinking: str) -> None:
121
+ self.content.append(ContentBlock(type=ContentBlockType.THINKING, thinking=thinking))
122
+
123
+ def add_tool_use(self, tool_use: ToolUse) -> None:
124
+ self.content.append(ContentBlock(type=ContentBlockType.TOOL_USE, tool_use=tool_use))
125
+
126
+ def add_tool_result(self, tool_result: ToolResult) -> None:
127
+ self.content.append(ContentBlock(type=ContentBlockType.TOOL_RESULT, tool_result=tool_result))
128
+
129
+ def to_api_content(self) -> str:
130
+ """Serialize text/thinking content for API calls.
131
+
132
+ For image blocks, includes a placeholder describing the image
133
+ so non-vision providers still get context about attached images.
134
+ """
135
+ parts = []
136
+ for cb in self.content:
137
+ if cb.type == ContentBlockType.TEXT and cb.text:
138
+ parts.append(cb.text)
139
+ elif cb.type == ContentBlockType.THINKING and cb.thinking:
140
+ parts.append(cb.thinking)
141
+ elif cb.type == ContentBlockType.IMAGE and cb.image:
142
+ parts.append(f"[Image: {cb.image.mime_type}]")
143
+ return "\n".join(parts)
144
+
145
+ def to_api_dict(self) -> dict:
146
+ """Serialize to OpenAI-compatible message dict (text-only).
147
+
148
+ For vision-capable providers, use to_multimodal_dict() to include
149
+ image content as content parts.
150
+ """
151
+ text = self.to_api_content()
152
+ msg: dict = {"role": self.role}
153
+ msg["content"] = text if text else None
154
+
155
+ tool_calls = []
156
+ for cb in self.content:
157
+ if cb.type == ContentBlockType.TOOL_USE and cb.tool_use:
158
+ tc = {
159
+ "id": cb.tool_use.id,
160
+ "type": "function",
161
+ "function": {
162
+ "name": cb.tool_use.name,
163
+ "arguments": cb.tool_use.input if isinstance(cb.tool_use.input, str) else __import__("json").dumps(cb.tool_use.input),
164
+ }
165
+ }
166
+ tool_calls.append(tc)
167
+ if cb.type == ContentBlockType.TOOL_RESULT and cb.tool_result:
168
+ msg["role"] = "tool"
169
+ msg["tool_call_id"] = cb.tool_result.tool_use_id
170
+ msg["content"] = cb.tool_result.content
171
+
172
+ if tool_calls:
173
+ msg["tool_calls"] = tool_calls
174
+
175
+ return msg
176
+
177
+ def to_multimodal_dict(self) -> dict:
178
+ """Serialize to OpenAI-compatible message dict with image content.
179
+
180
+ Returns content as a list of parts (text + image_url) for vision
181
+ API calls. Falls back to to_api_dict() when no images are present.
182
+ """
183
+ has_image = any(cb.type == ContentBlockType.IMAGE and cb.image for cb in self.content)
184
+ if not has_image:
185
+ return self.to_api_dict()
186
+
187
+ content_parts: list[dict] = []
188
+ for cb in self.content:
189
+ if cb.type == ContentBlockType.TEXT and cb.text:
190
+ content_parts.append({"type": "text", "text": cb.text})
191
+ elif cb.type == ContentBlockType.IMAGE and cb.image:
192
+ content_parts.append({
193
+ "type": "image_url",
194
+ "image_url": {
195
+ "url": f"data:{cb.image.mime_type};base64,{cb.image.data}",
196
+ },
197
+ })
198
+
199
+ msg: dict = self.to_api_dict()
200
+ msg["content"] = content_parts
201
+ return msg
202
+
203
+
204
+ @dataclass
205
+ class ModelResponse:
206
+ content: list[ContentBlock] = field(default_factory=list)
207
+ model: str = ""
208
+ usage: dict[str, Any] = field(default_factory=dict)
209
+ raw: Any = None
210
+
211
+ def __init__(self, content: str | list[ContentBlock | dict] = "", model: str = "", usage: dict[str, Any] = None, raw: Any = None):
212
+ self.model = model
213
+ self.usage = usage or {}
214
+ self.raw = raw
215
+ if isinstance(content, str):
216
+ self.content = [ContentBlock(type=ContentBlockType.TEXT, text=content)] if content else []
217
+ elif isinstance(content, list):
218
+ self.content = []
219
+ for item in content:
220
+ if isinstance(item, ContentBlock):
221
+ self.content.append(item)
222
+ elif isinstance(item, dict):
223
+ cb_type = ContentBlockType(item.get("type", "text"))
224
+ if cb_type == ContentBlockType.TEXT:
225
+ self.content.append(ContentBlock(type=cb_type, text=item.get("text", "")))
226
+ elif cb_type == ContentBlockType.IMAGE:
227
+ source = item.get("source", {})
228
+ self.content.append(ContentBlock(
229
+ type=cb_type,
230
+ image=ImageContent(
231
+ data=source.get("data", item.get("data", "")),
232
+ mime_type=source.get("media_type", item.get("mimeType", "image/png")),
233
+ ),
234
+ ))
235
+ elif cb_type == ContentBlockType.THINKING:
236
+ self.content.append(ContentBlock(type=cb_type, thinking=item.get("thinking", "")))
237
+ elif cb_type == ContentBlockType.TOOL_USE:
238
+ self.content.append(ContentBlock(
239
+ type=cb_type,
240
+ tool_use=ToolUse(
241
+ id=item.get("id", ""),
242
+ name=item.get("name", ""),
243
+ input=item.get("input", {}),
244
+ caller=item.get("caller", "agent"),
245
+ )
246
+ ))
247
+ elif cb_type == ContentBlockType.TOOL_RESULT:
248
+ self.content.append(ContentBlock(
249
+ type=cb_type,
250
+ tool_result=ToolResult(
251
+ tool_use_id=item.get("tool_use_id", ""),
252
+ content=item.get("content", ""),
253
+ is_error=item.get("is_error", False),
254
+ )
255
+ ))
256
+ elif cb_type == ContentBlockType.SERVER_TOOL_USE:
257
+ self.content.append(ContentBlock(
258
+ type=cb_type,
259
+ server_tool_use=ServerToolUse(
260
+ id=item.get("id", ""),
261
+ name=item.get("name", ""),
262
+ input=item.get("input", {}),
263
+ )
264
+ ))
265
+ elif cb_type == ContentBlockType.TOOL_SEARCH_RESULT:
266
+ self.content.append(ContentBlock(
267
+ type=cb_type,
268
+ tool_search_result=ToolSearchResult(
269
+ tool_use_id=item.get("tool_use_id", ""),
270
+ content=item.get("content", {}),
271
+ )
272
+ ))
273
+ elif cb_type == ContentBlockType.CODE_EXECUTION_RESULT:
274
+ self.content.append(ContentBlock(
275
+ type=cb_type,
276
+ code_execution_result=CodeExecutionResult(
277
+ tool_use_id=item.get("tool_use_id", ""),
278
+ content=item.get("content", {}),
279
+ )
280
+ ))
281
+ else:
282
+ self.content.append(ContentBlock(type=cb_type, text=str(item)))
283
+ else:
284
+ self.content.append(ContentBlock(type=ContentBlockType.TEXT, text=str(item)))
285
+ else:
286
+ self.content = []
287
+
288
+ def get_text(self) -> str:
289
+ return "".join(cb.text or "" for cb in self.content if cb.type == ContentBlockType.TEXT)
290
+
291
+ def get_thinking(self) -> Optional[str]:
292
+ for cb in self.content:
293
+ if cb.type == ContentBlockType.THINKING:
294
+ return cb.thinking
295
+ return None
296
+
297
+
298
+ class Provider(ABC):
299
+ name: str = ""
300
+
301
+ _prep_logger = logging.getLogger("onecode.provider.prepare")
302
+
303
+ @abstractmethod
304
+ async def chat(
305
+ self, messages: list[Message], model: str, **kwargs
306
+ ) -> ModelResponse:
307
+ ...
308
+
309
+ @abstractmethod
310
+ async def chat_stream(
311
+ self, messages: list[Message], model: str, **kwargs
312
+ ) -> AsyncIterator[str]:
313
+ ...
314
+ yield ""
315
+
316
+ def resolve_api_key(self, key: Optional[str]) -> str:
317
+ from onecode.config import resolve_env
318
+
319
+ if key and key.startswith("${"):
320
+ return resolve_env(key)
321
+ return key or ""
322
+
323
+ @staticmethod
324
+ def _content_text(content: object) -> str:
325
+ """Extract plain-text from content (string or multimodal list)."""
326
+ if isinstance(content, str):
327
+ return content.strip()
328
+ if isinstance(content, list):
329
+ parts: list[str] = []
330
+ for p in content:
331
+ if isinstance(p, dict):
332
+ parts.append(str(p.get("text", "") or p.get("image_url", "")))
333
+ else:
334
+ parts.append(str(p))
335
+ return " ".join(parts).strip()
336
+ return str(content or "").strip()
337
+
338
+ def _non_system_to_dict(self, msg: "Message") -> dict:
339
+ """Convert a non-system message to an API-ready dict.
340
+
341
+ Override in subclasses to use a different serialisation
342
+ (e.g. ``to_multimodal_dict`` for vision providers).
343
+ """
344
+ return msg.to_api_dict()
345
+
346
+ def prepare_messages(self, messages: list["Message"]) -> list[dict]:
347
+ """Prepare messages for API call. Handles tool, tool_use, tool_result blocks properly.
348
+
349
+ Hardening applied before serialization:
350
+ 1. Drop ``tool`` messages with empty content and no ``tool_call_id``
351
+ (the OpenAI-compatible API rejects these with HTTP 400).
352
+ 2. Coalesce runs of consecutive identical ``user`` content into one
353
+ message (some MiniMax gateways reject back-to-back duplicates).
354
+ 3. Cap the combined system-prompt length at 32 KiB, keeping the
355
+ highest-priority blocks (``AGENT_CONFIG`` → ``REACT_PHASE`` →
356
+ newest skills) and dropping older skill bodies first.
357
+ 4. Drop ``tool`` messages whose ``tool_call_id`` is not present in
358
+ the immediately preceding assistant message's ``tool_calls`` —
359
+ the MiniMax gateway returns ``(2013) tool call result does not
360
+ follow tool call`` otherwise.
361
+ 5. When a tool message is dropped (empty or orphan), also strip
362
+ the matching ``tool_call`` entry from the *owning* assistant
363
+ message — i.e. the assistant that originally emitted that
364
+ ``tool_call.id``. Without this, the request still contains
365
+ an ``assistant.tool_calls`` reference with no following
366
+ ``tool`` result, which MiniMax rejects with the same (2013)
367
+ error (``tool call and result not match`` in the stricter
368
+ validator). Tracking is per-id, not per-last-assistant, so
369
+ drops that span multiple turns (e.g. an empty result from
370
+ turn 1 and a legitimate one from turn 2) are each routed
371
+ back to the right assistant.
372
+ """
373
+ _SYSTEM_CAP_BYTES = 32 * 1024
374
+ log = Provider._prep_logger
375
+ dropped_empty_tools = 0
376
+ dropped_orphan_tools = 0
377
+ coalesced_user_msgs = 0
378
+
379
+ system_parts: list[tuple[str, str]] = [] # (marker, body)
380
+ non_system: list[dict] = []
381
+
382
+ for m in messages:
383
+ if m.role == "system":
384
+ body = m.to_api_content()
385
+ marker = ""
386
+ if "<!-- AGENT_CONFIG -->" in body:
387
+ marker = "AGENT_CONFIG"
388
+ elif "<!-- REACT_PHASE -->" in body:
389
+ marker = "REACT_PHASE"
390
+ elif "<!-- SKILL:" in body:
391
+ marker = "SKILL"
392
+ elif "<!-- CDH_PROJECT -->" in body:
393
+ marker = "CDH_PROJECT"
394
+ if body:
395
+ system_parts.append((marker, body))
396
+ elif m.role == "tool":
397
+ api = self._non_system_to_dict(m)
398
+ has_id = bool(api.get("tool_call_id"))
399
+ has_content = bool(self._content_text(api.get("content")))
400
+ if not has_id or not has_content:
401
+ dropped_empty_tools += 1
402
+ log.debug(
403
+ "prepare_messages: dropped empty tool message (id=%r content_len=%d)",
404
+ api.get("tool_call_id"),
405
+ len(self._content_text(api.get("content"))),
406
+ )
407
+ continue
408
+ non_system.append(api)
409
+ else:
410
+ non_system.append(self._non_system_to_dict(m))
411
+
412
+ coalesced: list[dict] = []
413
+ for msg in non_system:
414
+ if (
415
+ msg.get("role") == "user"
416
+ and coalesced
417
+ and coalesced[-1].get("role") == "user"
418
+ and (msg.get("content") or "") == (coalesced[-1].get("content") or "")
419
+ and not msg.get("tool_calls")
420
+ and not coalesced[-1].get("tool_calls")
421
+ ):
422
+ coalesced_user_msgs += 1
423
+ continue
424
+ coalesced.append(msg)
425
+ non_system = coalesced
426
+
427
+ # First pass: walk messages, drop orphan tool messages, and build
428
+ # a per-id map of ``tc_id -> owning assistant index`` so we know
429
+ # exactly which assistant emitted each ``tool_call`` entry.
430
+ linked: list[dict] = []
431
+ last_assistant_tc_ids: set[str] = set()
432
+ # Maps tool_call.id -> index in ``linked`` of the assistant that
433
+ # currently owns it. Rebuilt whenever a new assistant message
434
+ # is appended (matches the same reset semantics as
435
+ # ``last_assistant_tc_ids``).
436
+ tc_owner: dict[str, int] = {}
437
+ for msg in non_system:
438
+ if msg.get("role") == "tool":
439
+ tcid = msg.get("tool_call_id") or ""
440
+ if tcid not in last_assistant_tc_ids:
441
+ dropped_orphan_tools += 1
442
+ log.debug(
443
+ "prepare_messages: dropped orphan tool message "
444
+ "(tool_call_id=%r not in preceding assistant.tool_calls)",
445
+ tcid,
446
+ )
447
+ continue
448
+ linked.append(msg)
449
+ continue
450
+ new_index = len(linked)
451
+ linked.append(msg)
452
+ if msg.get("role") == "assistant":
453
+ last_assistant_tc_ids = {
454
+ tc.get("id") for tc in (msg.get("tool_calls") or []) if tc.get("id")
455
+ }
456
+ for tc in msg.get("tool_calls") or []:
457
+ tcid = tc.get("id")
458
+ if tcid:
459
+ tc_owner[tcid] = new_index
460
+ else:
461
+ last_assistant_tc_ids = set()
462
+ non_system = linked
463
+
464
+ # Second pass: any tool_call whose matching tool message was
465
+ # dropped (empty content caught above, or otherwise missing)
466
+ # must be removed from the *owning* assistant message — not just
467
+ # the last assistant. We do this in two steps:
468
+ # 1. Walk the full list and collect every tool_call_id that
469
+ # appears in any tool message — these are the "seen" ids.
470
+ # 2. Walk again and, for each assistant message, find any
471
+ # tool_call.id that is NOT in the seen set. Those are
472
+ # dangling entries that must be stripped.
473
+ seen_tool_ids: set[str] = set()
474
+ for msg in non_system:
475
+ if msg.get("role") == "tool":
476
+ tcid = msg.get("tool_call_id") or ""
477
+ if tcid:
478
+ seen_tool_ids.add(tcid)
479
+
480
+ dangling: dict[int, set[str]] = {}
481
+ for msg in non_system:
482
+ if msg.get("role") != "assistant":
483
+ continue
484
+ tcs = msg.get("tool_calls") or []
485
+ if not tcs:
486
+ continue
487
+ for tc in tcs:
488
+ tcid = tc.get("id") or ""
489
+ if tcid and tcid not in seen_tool_ids:
490
+ owner_idx = tc_owner.get(tcid)
491
+ if owner_idx is not None:
492
+ dangling.setdefault(owner_idx, set()).add(tcid)
493
+ # Also strip tool_call entries with an empty id — those can
494
+ # never be matched to a tool result and would be silently
495
+ # dangling. This mirrors the upstream filter in the first-pass
496
+ # tool tracking (``if tc.get("id")`` / ``if tcid``).
497
+ for msg in non_system:
498
+ if msg.get("role") != "assistant":
499
+ continue
500
+ tcs = msg.get("tool_calls") or []
501
+ if not tcs:
502
+ continue
503
+ kept = [tc for tc in tcs if tc.get("id")]
504
+ if len(kept) < len(tcs):
505
+ log.debug(
506
+ "prepare_messages: stripped %d empty-id tool_call entr%s "
507
+ "from assistant message",
508
+ len(tcs) - len(kept),
509
+ "y" if len(tcs) - len(kept) == 1 else "ies",
510
+ )
511
+ if kept:
512
+ msg["tool_calls"] = kept
513
+ else:
514
+ msg.pop("tool_calls", None)
515
+
516
+ # Apply the cleanup: strip dangling tool_call entries. Empty
517
+ # ``tool_calls`` lists are removed entirely.
518
+ if dangling:
519
+ total_stripped = 0
520
+ for idx, ids in dangling.items():
521
+ assistant_msg = non_system[idx]
522
+ tcs = assistant_msg.get("tool_calls") or []
523
+ kept = [tc for tc in tcs if (tc.get("id") or "") not in ids]
524
+ stripped = len(tcs) - len(kept)
525
+ if stripped:
526
+ total_stripped += stripped
527
+ log.debug(
528
+ "prepare_messages: stripped %d dangling tool_call entr%s "
529
+ "from assistant message idx=%d (ids=%r)",
530
+ stripped,
531
+ "y" if stripped == 1 else "ies",
532
+ idx,
533
+ sorted(ids),
534
+ )
535
+ if kept:
536
+ assistant_msg["tool_calls"] = kept
537
+ else:
538
+ assistant_msg.pop("tool_calls", None)
539
+ if total_stripped:
540
+ log.info(
541
+ "prepare_messages(%s): stripped %d dangling tool_call entr%s across %d assistant message(s)",
542
+ self.name or "?",
543
+ total_stripped,
544
+ "y" if total_stripped == 1 else "ies",
545
+ len(dangling),
546
+ )
547
+
548
+ if dropped_empty_tools or dropped_orphan_tools or coalesced_user_msgs:
549
+ log.info(
550
+ "prepare_messages(%s): dropped empty_tools=%d orphan_tools=%d "
551
+ "coalesced_user=%d (input=%d output=%d)",
552
+ self.name or "?",
553
+ dropped_empty_tools,
554
+ dropped_orphan_tools,
555
+ coalesced_user_msgs,
556
+ len(messages),
557
+ len(non_system) + (1 if system_parts else 0),
558
+ )
559
+
560
+ combined_system = ""
561
+ if system_parts:
562
+ combined_parts = [body for _, body in system_parts]
563
+ combined_system = "\n\n".join(combined_parts)
564
+ if len(combined_system.encode("utf-8")) > _SYSTEM_CAP_BYTES:
565
+ priority = {"AGENT_CONFIG": 0, "REACT_PHASE": 1, "CDH_PROJECT": 2, "SKILL": 3}
566
+ ordered = sorted(
567
+ range(len(system_parts)),
568
+ key=lambda i: (priority.get(system_parts[i][0], 9), -i),
569
+ )
570
+ kept_indices: set[int] = set()
571
+ running = 0
572
+ for idx in ordered:
573
+ marker, body = system_parts[idx]
574
+ size = len(body.encode("utf-8")) + 2
575
+ if marker == "AGENT_CONFIG":
576
+ kept_indices.add(idx)
577
+ running = max(running, size)
578
+ continue
579
+ if running + size <= _SYSTEM_CAP_BYTES:
580
+ kept_indices.add(idx)
581
+ running += size
582
+ kept = [body for i, body in enumerate(combined_parts) if i in kept_indices]
583
+ if not any("<!-- AGENT_CONFIG -->" in b for b in kept) and system_parts:
584
+ kept.insert(0, system_parts[0][1])
585
+ combined_system = "\n\n".join(kept).encode("utf-8")[:_SYSTEM_CAP_BYTES].decode("utf-8", errors="ignore")
586
+
587
+ if combined_system:
588
+ non_system.insert(0, {"role": "system", "content": combined_system})
589
+
590
+ return non_system
591
+
592
+ def parse_response_tool_calls(self, response_data: dict) -> list[dict]:
593
+ """Extract tool calls from a non-streaming API response."""
594
+ choice = response_data.get("choices", [{}])[0]
595
+ msg = choice.get("message", {})
596
+ tool_calls = msg.get("tool_calls", [])
597
+ result = []
598
+ for tc in tool_calls:
599
+ func = tc.get("function", {})
600
+ try:
601
+ args = __import__("json").loads(func.get("arguments", "{}"))
602
+ except Exception:
603
+ args = {"raw": func.get("arguments", "")}
604
+ if not isinstance(args, dict):
605
+ args = {"raw": args}
606
+ result.append({
607
+ "id": tc.get("id", ""),
608
+ "name": func.get("name", ""),
609
+ "input": args,
610
+ })
611
+ return result
612
+
613
+ # ── Clawd-Code style structured streaming ──
614
+
615
+ def is_anthropic_style(self) -> bool:
616
+ """Whether this provider uses Anthropic-style 'system' kwarg."""
617
+ return False
618
+
619
+ def supports_native_tools(self) -> bool:
620
+ """Whether this provider accepts structured tools param in API calls.
621
+
622
+ When True, TOOL_DESCRIPTIONS prose in the system prompt is skipped
623
+ because the provider's native tool schema (passed via the ``tools``
624
+ kwarg to ``chat_stream_response``) provides equivalent information.
625
+ """
626
+ return True
627
+
628
+ async def chat_stream_response(
629
+ self,
630
+ messages: list[Message],
631
+ model: str,
632
+ on_text_chunk: Optional[Callable[[str], None]] = None,
633
+ on_tool_call_delta: Optional[Callable[[str, str, str], None]] = None,
634
+ cancel_check: Optional[Callable[[], bool]] = None,
635
+ **kwargs,
636
+ ) -> ChatResponse:
637
+ """Stream with structured ChatResponse return (Clawd-Code style).
638
+
639
+ Default implementation: falls back to chat() for providers that
640
+ don't implement structured streaming.
641
+ """
642
+ if cancel_check and cancel_check():
643
+ raise asyncio.CancelledError("cancelled before chat_stream_response")
644
+ logging.getLogger("onecode.models.provider").warning(
645
+ "[PROVIDER-STREAM] %s does not override chat_stream_response — "
646
+ "falling back to non-streaming chat() (on_text_chunk will NOT fire)",
647
+ type(self).__name__,
648
+ )
649
+ response = await asyncio.wait_for(
650
+ self.chat(messages, model=model, **kwargs),
651
+ timeout=300,
652
+ )
653
+ return ChatResponse(
654
+ content=response.get_text(),
655
+ tool_uses=[
656
+ {"id": tu.id, "name": tu.name, "input": tu.input}
657
+ for cb in response.content
658
+ if cb.type == ContentBlockType.TOOL_USE and cb.tool_use
659
+ for tu in [cb.tool_use]
660
+ ],
661
+ usage=response.usage,
662
+ )
663
+
664
+ # ── Error classification ────────────────────────────────────────
665
+
666
+ @staticmethod
667
+ def classify_http_error(
668
+ status_code: int,
669
+ body: str,
670
+ *,
671
+ retry_after: Optional[float] = None,
672
+ ) -> "ProviderError": # noqa: F821
673
+ """Convert an upstream HTTP error into the most specific
674
+ :class:`ProviderError` subclass.
675
+
676
+ The 4 KiB body cap is applied here too so callers don't have to
677
+ remember to truncate before constructing the exception.
678
+ """
679
+ from onecode.models.errors import (
680
+ AuthError,
681
+ ContextLengthError,
682
+ ProviderError,
683
+ RateLimitError,
684
+ TransientProviderError,
685
+ )
686
+ snippet = (body or "").strip()
687
+ body_excerpt = snippet[:200] if snippet else ""
688
+ if status_code == 429:
689
+ return RateLimitError(
690
+ "rate limit exceeded", status_code=status_code,
691
+ retry_after=retry_after, body=snippet,
692
+ )
693
+ if status_code in (401, 403):
694
+ return AuthError(
695
+ "authentication failed", status_code=status_code, body=snippet,
696
+ )
697
+ if status_code == 400 and (
698
+ ("context" in snippet.lower() and ("length" in snippet.lower() or "window" in snippet.lower()))
699
+ or "context window" in snippet.lower()
700
+ or ("exceed" in snippet.lower() and "limit" in snippet.lower())
701
+ or "(2013)" in snippet
702
+ ):
703
+ return ContextLengthError(
704
+ "context length exceeded", status_code=status_code, body=snippet,
705
+ )
706
+ if status_code == 529 or (500 <= status_code < 600):
707
+ msg = f"upstream {status_code}: {body_excerpt}" if body_excerpt else f"upstream {status_code}"
708
+ return TransientProviderError(
709
+ msg, status_code=status_code, retry_after=retry_after, body=snippet,
710
+ )
711
+ msg = f"upstream error {status_code}: {body_excerpt}" if body_excerpt else f"upstream error {status_code}"
712
+ return ProviderError(
713
+ msg, status_code=status_code, body=snippet,
714
+ )
715
+
716
+
717
+ class ProviderRegistry:
718
+ _providers: dict[str, type[Provider]] = {}
719
+
720
+ @classmethod
721
+ def register(cls, name: str, provider_cls: type[Provider]):
722
+ cls._providers[name] = provider_cls
723
+
724
+ @classmethod
725
+ def get(cls, name: str) -> Optional[type[Provider]]:
726
+ return cls._providers.get(name)
727
+
728
+ @classmethod
729
+ def list(cls) -> list[str]:
730
+ return list(cls._providers.keys())