@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,935 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ import shlex
5
+ from typing import TYPE_CHECKING, Callable, Literal, Self
6
+
7
+ from textual import on
8
+ from textual.reactive import var, Initialize
9
+ from textual.app import ComposeResult
10
+
11
+ from textual.actions import SkipAction
12
+ from textual.binding import Binding
13
+
14
+ from textual.content import Content
15
+ from textual import getters
16
+ from textual.message import Message
17
+ from textual.widgets import OptionList, TextArea, Label
18
+ from textual import containers
19
+ from textual.widget import Widget
20
+ from textual.widgets.option_list import Option
21
+ from textual.widgets.text_area import Selection
22
+ from textual.document._document import EditResult
23
+ from textual import events
24
+
25
+ from tui.app import A2TUIApp
26
+ from tui import messages
27
+ from tui.widgets.highlighted_textarea import HighlightedTextArea
28
+ from tui.widgets.condensed_path import CondensedPath
29
+ from tui.widgets.path_search import PathSearch
30
+ from tui.widgets.pending_prompts import PendingPrompts
31
+ from tui.widgets.plan import Plan
32
+ from tui.answer import Answer
33
+ from tui.widgets.question import Ask, Question
34
+ from tui.widgets.slash_complete import SlashComplete
35
+ from tui.messages import UserInputSubmitted
36
+ from tui.slash_command import SlashCommand
37
+ from tui.prompt.extract import extract_paths_from_prompt
38
+ from tui.path_complete import PathComplete
39
+
40
+ if TYPE_CHECKING:
41
+ from tui.acp.agent import Mode
42
+
43
+
44
+ class ModeSwitcher(OptionList):
45
+ BINDING_GROUP_TITLE = "Mode switcher"
46
+ BINDINGS = [Binding("escape", "dismiss", "Dismiss mode switcher")]
47
+
48
+ @on(OptionList.OptionSelected)
49
+ def on_option_selected(self, event: OptionList.OptionSelected):
50
+ self.post_message(messages.ChangeMode(event.option_id))
51
+ self.blur()
52
+
53
+ def action_dismiss(self):
54
+ self.blur()
55
+
56
+
57
+ class InvokeFileSearch(Message):
58
+ pass
59
+
60
+
61
+ class InvokeSlashComplete(Message):
62
+ pass
63
+
64
+
65
+ class AgentInfo(Label):
66
+ pass
67
+
68
+
69
+ class ModeInfo(Label):
70
+ pass
71
+
72
+
73
+ class StatusLine(Label):
74
+ status: var[str] = var("")
75
+
76
+ def watch_status(self, status: str) -> None:
77
+ self.set_class(not bool(status), "-hidden")
78
+ self.update(status)
79
+ self.tooltip = status
80
+
81
+
82
+ class PromptContainer(containers.HorizontalGroup):
83
+ def on_mouse_down(self, event: events.MouseUp) -> None:
84
+ for child in self.query("*"):
85
+ if child.has_focus:
86
+ return
87
+ prompt_text_area = self.query_one(PromptTextArea)
88
+ if not prompt_text_area.has_focus:
89
+ prompt_text_area.focus()
90
+
91
+
92
+ class PromptTextArea(HighlightedTextArea):
93
+ HELP = """\
94
+ ## Prompt
95
+
96
+ Talk to your agent in natural language.
97
+ See on-screen instructions for details.
98
+
99
+ - Be simple
100
+ - Be direct
101
+ - Nothing fancy
102
+ """
103
+
104
+ BINDING_GROUP_TITLE = "Prompt"
105
+
106
+ BINDINGS = [
107
+ Binding(
108
+ "enter",
109
+ "submit",
110
+ "Send",
111
+ key_display="⏎",
112
+ priority=True,
113
+ tooltip="Send the prompt to the agent",
114
+ show=False,
115
+ ),
116
+ Binding(
117
+ "alt+enter,shift+enter",
118
+ "newline",
119
+ "Line",
120
+ key_display="⌥+⏎",
121
+ tooltip="Insert a new line character",
122
+ show=False,
123
+ ),
124
+ Binding(
125
+ "alt+enter,shift+enter",
126
+ "multiline_submit",
127
+ "Send",
128
+ key_display="⌥+⏎",
129
+ tooltip="Send the prompt to the agent",
130
+ ),
131
+ Binding(
132
+ "tab",
133
+ "tab_complete",
134
+ "Complete",
135
+ tooltip="Complete path (if possible)",
136
+ priority=True,
137
+ show=False,
138
+ ),
139
+ ]
140
+
141
+ app = getters.app(A2TUIApp)
142
+
143
+ auto_completes: var[list[Option]] = var(list)
144
+ multi_line = var(False, bindings=True)
145
+ shell_mode = var(False, bindings=True)
146
+ agent_ready: var[bool] = var(False)
147
+ path_complete: var[PathComplete] = var(Initialize(lambda obj: PathComplete()))
148
+ suggestions: var[list[str] | None] = var(None)
149
+ suggestions_index: var[int] = var(0)
150
+
151
+ project_path = var(Path())
152
+ working_directory = var("")
153
+
154
+ slash_commands: var[list[SlashCommand]] = var([])
155
+ slash_command_prefixes: var[tuple[str, ...]] = var(())
156
+
157
+ class Submitted(Message):
158
+ def __init__(self, markdown: str) -> None:
159
+ self.markdown = markdown
160
+ super().__init__()
161
+
162
+ class RequestShellMode(Message):
163
+ pass
164
+
165
+ class CancelShell(Message):
166
+ pass
167
+
168
+ def watch_slash_commands(self, slash_commands: list[SlashCommand]) -> None:
169
+ """A tuple of slash commands for performance reasons (used with `str.startswith`)."""
170
+ self.slash_command_prefixes = tuple(
171
+ [slash_command.command for slash_command in slash_commands]
172
+ )
173
+
174
+ def highlight_slash_command(self, text: str) -> Content:
175
+ """Override slash command highlighting."""
176
+
177
+ if text.startswith(self.slash_command_prefixes):
178
+ content = Content(text)
179
+ for slash_command in self.slash_commands:
180
+ if text.startswith(slash_command.command + " "):
181
+ content = content.stylize(
182
+ "$text-success", 0, len(slash_command.command)
183
+ )
184
+ if (
185
+ slash_command.hint
186
+ and len(text) - (len(slash_command.command) + 1) == 0
187
+ ):
188
+ content += Content.styled(
189
+ slash_command.hint, "$text-secondary 70%"
190
+ )
191
+ break
192
+ return content
193
+ return Content(text)
194
+
195
+ def highlight_shell(self, text: str) -> Content:
196
+ """Override shell highlighting with additional danger detection."""
197
+ content = super().highlight_shell(text)
198
+
199
+ if not self.app.settings.get("shell.warn_dangerous", bool):
200
+ return content
201
+
202
+ from tui import danger
203
+
204
+ spans, _danger_level = danger.detect(
205
+ str(self.project_path), self.working_directory, content.plain
206
+ )
207
+ content = content.add_spans(spans)
208
+ return content
209
+
210
+ def on_mount(self) -> None:
211
+ self.highlight_cursor_line = False
212
+ self.hide_suggestion_on_blur = False
213
+ self._paste_queue: list[tuple[str, str]] = []
214
+ self._paste_fingerprint = ""
215
+ self._paste_summary_enabled: bool = not bool(
216
+ self.app.settings.get("experimental.disable_paste_summary", bool)
217
+ )
218
+
219
+ QUICK_COUNT_SAMPLE = 1000
220
+ HUGE_PASTE_THRESHOLD = 100000
221
+
222
+ async def _on_paste(self, event: events.Paste) -> None:
223
+ """Handle paste events with fast path for large text to avoid blocking UI."""
224
+ if self.read_only:
225
+ return
226
+
227
+ text_len = len(event.text)
228
+ MAX_PASTE_CHARS = 50000
229
+
230
+ if text_len > MAX_PASTE_CHARS:
231
+ self.post_message(
232
+ messages.Flash(
233
+ "内容过大,已截断",
234
+ style="warning",
235
+ duration=3,
236
+ )
237
+ )
238
+ self._paste_fingerprint = ""
239
+ self._paste_queue.clear()
240
+ text_copy = event.text[:MAX_PASTE_CHARS]
241
+ self._paste_queue.append((text_copy, "[Pasted large content]"))
242
+ self.insert("[Pasted large content] ")
243
+ return
244
+
245
+ await super()._on_paste(event)
246
+
247
+ def _replace_via_keyboard(self, text: str, start, end) -> EditResult | None:
248
+ if self.read_only:
249
+ return None
250
+
251
+ text_len = len(text)
252
+ MAX_PASTE_CHARS = 50000
253
+
254
+ if text_len > MAX_PASTE_CHARS:
255
+ self._paste_fingerprint = ""
256
+ self._paste_queue.clear()
257
+ sample = text[: self.QUICK_COUNT_SAMPLE]
258
+ sample_lines = sample.count("\n") + 1
259
+ estimated_line_count = int(sample_lines * text_len / len(sample))
260
+ marker = f"[Pasted ~{estimated_line_count} lines] (truncated)"
261
+ self._paste_queue.append((text[:MAX_PASTE_CHARS], marker))
262
+ self.post_message(
263
+ messages.Flash(
264
+ f"[Pasted ~{estimated_line_count} lines, 内容过大已截断]",
265
+ style="warning",
266
+ duration=3,
267
+ )
268
+ )
269
+ self.insert(marker + " ")
270
+ return None
271
+
272
+ fingerprint = text.replace("\r\n", "\n").replace("\r", "\n").strip()
273
+
274
+ if fingerprint and self._paste_fingerprint == fingerprint:
275
+ self._paste_fingerprint = ""
276
+ self._paste_queue.clear()
277
+ return None
278
+
279
+ if text_len <= 150:
280
+ self._paste_fingerprint = ""
281
+ self._paste_queue.clear()
282
+ return super()._replace_via_keyboard(text, start, end)
283
+
284
+ if not self._paste_summary_enabled:
285
+ self._paste_fingerprint = ""
286
+ self._paste_queue.clear()
287
+ return super()._replace_via_keyboard(text, start, end)
288
+
289
+ self._paste_fingerprint = fingerprint
290
+
291
+ sample = text[: self.QUICK_COUNT_SAMPLE]
292
+ sample_normalized = sample.replace("\r\n", "\n").replace("\r", "\n")
293
+ sample_lines = sample_normalized.count("\n") + 1
294
+ if text_len <= self.QUICK_COUNT_SAMPLE:
295
+ line_count = sample_lines
296
+ else:
297
+ line_count = int(sample_lines * text_len / len(sample))
298
+
299
+ char_count = text_len
300
+ text_to_store = text
301
+ truncated = False
302
+
303
+ if char_count > MAX_PASTE_CHARS:
304
+ text_to_store = text[:MAX_PASTE_CHARS]
305
+ truncated = True
306
+ self.post_message(
307
+ messages.Flash(
308
+ f"[Pasted ~{line_count} lines, 内容过大已截断]",
309
+ style="warning",
310
+ duration=3,
311
+ )
312
+ )
313
+ elif line_count > 30:
314
+ self.post_message(
315
+ messages.Flash(
316
+ f"[Pasted ~{line_count} lines]",
317
+ style="default",
318
+ duration=2,
319
+ )
320
+ )
321
+
322
+ marker = f"[Pasted ~{line_count} lines]" + (" (truncated)" if truncated else "")
323
+ self._paste_queue.append((text_to_store, marker))
324
+ self.insert(marker + " ")
325
+ return None
326
+
327
+ def action_copy(self) -> None:
328
+ """Copy selection to clipboard; if no selection, clear the text area."""
329
+ if not self.selection.is_empty:
330
+ self.app.copy_to_clipboard(self.selected_text)
331
+ else:
332
+ self.clear()
333
+ self._paste_queue.clear()
334
+
335
+ def on_key(self, event: events.Key) -> None:
336
+ if (
337
+ not self.shell_mode
338
+ and self.cursor_location == (0, 0)
339
+ and event.character in {"!", "$"}
340
+ ):
341
+ self.post_message(self.RequestShellMode())
342
+ event.prevent_default()
343
+ elif self.shell_mode and event.key == "tab":
344
+ event.prevent_default()
345
+ elif event.key == "escape":
346
+ self._paste_queue.clear()
347
+ else:
348
+ self.suggestions = None
349
+ self.suggestion = ""
350
+
351
+ def update_suggestion(self) -> None:
352
+ prompt = self.query_ancestor(Prompt)
353
+
354
+ if self.selection.start == self.selection.end and self.text.startswith("/"):
355
+ return
356
+
357
+ if self.shell_mode and self.cursor_at_end_of_text and "\n" not in self.text:
358
+ if prompt.complete_callback is not None:
359
+ if completes := prompt.complete_callback(self.text):
360
+ if self.text not in completes:
361
+ self.suggestion = completes[-1]
362
+
363
+ def check_action(self, action: str, parameters: tuple[object, ...]) -> bool | None:
364
+ if action == "newline" and self.multi_line:
365
+ return False
366
+ if action == "submit" and self.multi_line:
367
+ return False
368
+ if action == "multiline_submit":
369
+ return self.multi_line
370
+ return True
371
+
372
+ def action_multiline_submit(self) -> None:
373
+ if not self.agent_ready:
374
+ self.app.bell()
375
+ self.post_message(
376
+ messages.Flash(
377
+ "Agent is not ready. Please wait while the agent connects…",
378
+ "error",
379
+ )
380
+ )
381
+ return
382
+ body = self._expand_paste_markers(self.text)
383
+ self._paste_queue.clear()
384
+ self.post_message(UserInputSubmitted(body, self.shell_mode))
385
+ self.clear()
386
+
387
+ def action_newline(self) -> None:
388
+ self.insert("\n")
389
+
390
+ def _expand_paste_markers(self, body: str) -> str:
391
+ """Expand paste markers in body text by replacing them with original content."""
392
+ for original, marker in self._paste_queue:
393
+ if marker in body:
394
+ body = body.replace(marker, original, 1)
395
+ return body
396
+
397
+ def action_submit(self) -> None:
398
+ if not self.agent_ready and not self.shell_mode:
399
+ self.app.bell()
400
+ self.post_message(
401
+ messages.Flash(
402
+ "Agent is not ready. Please wait while the agent connects…",
403
+ "error",
404
+ )
405
+ )
406
+ return
407
+ if self.suggestion:
408
+ if " " not in self.text:
409
+ self.insert(self.suggestion + " ")
410
+ else:
411
+ prompt = self.query_ancestor(Prompt)
412
+ last_token = shlex.split(self.text + self.suggestion)[-1]
413
+ last_token_path = Path(prompt.working_directory) / last_token
414
+ if last_token_path.is_dir():
415
+ self.insert(self.suggestion)
416
+ else:
417
+ self.insert(self.suggestion + " ")
418
+ self.suggestion = ""
419
+ return
420
+ body = self._expand_paste_markers(self.text)
421
+ self._paste_queue.clear()
422
+ self.post_message(UserInputSubmitted(body, self.shell_mode))
423
+ self.clear()
424
+
425
+ def action_cursor_up(self, select: bool = False):
426
+ if self.selection.is_empty and not select:
427
+ row, _column = self.selection[0]
428
+ if row == 0:
429
+ self.post_message(messages.HistoryMove(-1, self.shell_mode, self.text))
430
+ return
431
+ super().action_cursor_up(select)
432
+
433
+ def action_cursor_down(self, select: bool = False):
434
+ if self.selection.is_empty and not select:
435
+ row, _column = self.selection[0]
436
+ if row == (self.wrapped_document.height - 1):
437
+ self.post_message(messages.HistoryMove(+1, self.shell_mode, self.text))
438
+ return
439
+ super().action_cursor_down(select)
440
+
441
+ def action_delete_left(self) -> None:
442
+ selection = self.selection
443
+ if selection.start == selection.end and self.selection.end == (0, 0):
444
+ self.post_message(self.CancelShell())
445
+ return
446
+ return super().action_delete_left()
447
+
448
+ def action_cursor_line_end(self, select: bool = False) -> None:
449
+ """Move the cursor to the end of the line."""
450
+ if not self._has_cursor:
451
+ self.scroll_end()
452
+ return
453
+ location = self.get_cursor_line_end_location()
454
+ if location == self.cursor_location:
455
+ # If the cursor is already at the end, then we assume the user wants to
456
+ # scroll the conversation to the end
457
+ from tui.widgets.conversation import Conversation
458
+
459
+ self.query_ancestor(Conversation).window.anchor()
460
+ else:
461
+ self.move_cursor(location, select=select)
462
+
463
+ async def action_tab_complete(self) -> None:
464
+ if not self.shell_mode:
465
+ raise SkipAction()
466
+
467
+ import shlex
468
+
469
+ prompt = self.query_ancestor(Prompt)
470
+
471
+ if not self.cursor_at_end_of_text:
472
+ return
473
+
474
+ _cursor_row, cursor_column = prompt.prompt_text_area.selection.end
475
+ pre_complete = self.text[:cursor_column]
476
+ post_complete = self.text[cursor_column:]
477
+ shlex_tokens = shlex.split(pre_complete)
478
+ if not shlex_tokens:
479
+ return
480
+
481
+ command = shlex_tokens[0]
482
+
483
+ exclude_node_type: Literal["file"] | Literal["dir"] | None = None
484
+ if (
485
+ command
486
+ in self.app.settings.get("shell.directory_commands", str).splitlines()
487
+ ):
488
+ exclude_node_type = "file"
489
+ elif command in self.app.settings.get("shell.file_commands", str).splitlines():
490
+ exclude_node_type = "dir"
491
+
492
+ tab_complete, suggestions = await self.path_complete(
493
+ Path(prompt.working_directory),
494
+ shlex_tokens[-1],
495
+ exclude_type=exclude_node_type,
496
+ )
497
+
498
+ if tab_complete is not None:
499
+ shlex_tokens = shlex_tokens[:-1] + [shlex_tokens[-1] + tab_complete]
500
+ path_component = Path(prompt.working_directory) / shlex_tokens[-1]
501
+ if path_component.is_file():
502
+ spaces = " "
503
+ else:
504
+ spaces = ""
505
+
506
+ self.clear()
507
+ self.insert(
508
+ " ".join(token.replace(" ", "\\ ") for token in shlex_tokens)
509
+ + post_complete
510
+ + spaces
511
+ )
512
+ self.suggestions = None
513
+ else:
514
+ if suggestions != self.suggestions:
515
+ self.suggestions = suggestions or None
516
+ self.suggestions_index = 0
517
+ if suggestions:
518
+ self.suggestion = suggestions[0]
519
+ elif self.suggestions:
520
+ self.suggestions_index = (self.suggestions_index + 1) % len(
521
+ self.suggestions
522
+ )
523
+ self.suggestion = self.suggestions[self.suggestions_index]
524
+
525
+ async def watch_selection(
526
+ self, previous_selection: Selection, selection: Selection
527
+ ) -> None:
528
+ if previous_selection == selection:
529
+ return
530
+ if selection.start == selection.end:
531
+ previous_y, previous_x = previous_selection.end
532
+ y, x = selection.end
533
+ if y == previous_y:
534
+ direction = -1 if x < previous_x else +1
535
+ else:
536
+ direction = 0
537
+ line = self.document.get_line(y)
538
+
539
+ if (
540
+ not self.shell_mode
541
+ and y == 0
542
+ and x == 1
543
+ and direction == +1
544
+ and line
545
+ and line[0] == "/"
546
+ ):
547
+ self.post_message(InvokeSlashComplete())
548
+ return
549
+
550
+ if y == 0 and line and line[0] == "/" and direction == -1:
551
+ if line in self.slash_command_prefixes:
552
+ self.selection = Selection((0, 0), (0, len(line)))
553
+ return
554
+
555
+ for _path, start, end in extract_paths_from_prompt(line):
556
+ if x > start and x < end:
557
+ self.selection = Selection((y, start), (y, end))
558
+ break
559
+ if direction == -1 and x == end:
560
+ self.selection = Selection((y, start), (y, end))
561
+ break
562
+
563
+ if x > 0 and x <= len(line) and line[x - 1] == "@":
564
+ remaining_line = line[x + 1 :]
565
+ if not remaining_line or remaining_line[0].isspace():
566
+ self.post_message(InvokeFileSearch())
567
+
568
+
569
+ class Prompt(containers.VerticalGroup):
570
+
571
+ BINDINGS = [
572
+ Binding("escape", "dismiss", "Dismiss", show=False),
573
+ ]
574
+
575
+ PROMPT_NULL = " "
576
+ PROMPT_SHELL = Content.styled("$", "$text-primary")
577
+ PROMPT_AI = Content.styled("❯", "$text-secondary")
578
+ PROMPT_MULTILINE = Content.styled("☰", "$text-secondary")
579
+
580
+ prompt_container = getters.query_one("#prompt-container", Widget)
581
+ prompt_text_area = getters.query_one(PromptTextArea)
582
+ prompt_label = getters.query_one("#prompt", Label)
583
+ current_directory = getters.query_one(CondensedPath)
584
+ path_search = getters.query_one(PathSearch)
585
+ slash_complete = getters.query_one(SlashComplete)
586
+ question = getters.query_one(Question)
587
+ mode_switcher = getters.query_one(ModeSwitcher)
588
+
589
+ slash_commands: var[list[SlashCommand]] = var(list)
590
+ shell_mode = var(False)
591
+ multi_line = var(False)
592
+ show_path_search = var(False, toggle_class="-show-path-search", bindings=True)
593
+ show_slash_complete = var(False, toggle_class="-show-slash-complete", bindings=True)
594
+ project_path = var(Path, init=False)
595
+ working_directory = var("")
596
+ agent_info = var(Content(""))
597
+ _ask: var[Ask | None] = var(None)
598
+ plan: var[list[Plan.Entry]]
599
+ agent_ready: var[bool] = var(False)
600
+ current_mode: var[Mode | None] = var(None)
601
+ modes: var[dict[str, Mode] | None] = var(None)
602
+ status: var[str] = var("")
603
+ pending_prompts: var[list[str]] = var([])
604
+
605
+ app = getters.app(A2TUIApp)
606
+
607
+ def __init__(
608
+ self,
609
+ *,
610
+ name: str | None = None,
611
+ id: str | None = None,
612
+ classes: str | None = None,
613
+ disabled: bool = False,
614
+ complete_callback: Callable[[str], list[str]] | None = None,
615
+ ):
616
+ super().__init__(name=name, id=id, classes=classes, disabled=disabled)
617
+ self.ask_queue: list[Ask] = []
618
+ self.complete_callback = complete_callback
619
+
620
+ @property
621
+ def text(self) -> str:
622
+ return self.prompt_text_area.text
623
+
624
+ @text.setter
625
+ def text(self, text: str) -> None:
626
+ self.prompt_text_area.text = text
627
+ self.prompt_text_area.selection = Selection.cursor(
628
+ self.prompt_text_area.get_cursor_line_end_location()
629
+ )
630
+
631
+ def watch_current_mode(self, mode: Mode | None) -> None:
632
+ self.set_class(mode is not None, "-has-mode")
633
+ if mode is not None:
634
+ tooltip = Content.from_markup(
635
+ "[b]$description[/]\n\n[dim](click to open mode switcher)",
636
+ description=mode.description,
637
+ )
638
+ self.query_one(ModeInfo).with_tooltip(tooltip).update(mode.name)
639
+ self.watch_modes(self.modes)
640
+
641
+ async def watch_project_path(self, old_path: Path, new_path: Path) -> None:
642
+ """Initial refresh of paths."""
643
+ if old_path != new_path:
644
+ self.call_later(self.path_search.refresh_paths)
645
+
646
+ def ask(self, ask: Ask) -> None:
647
+ """Replace the textarea prompt with a menu of options.
648
+
649
+ Args:
650
+ ask: An `Ask` instance which contains a question and responses.
651
+ """
652
+ self.ask_queue.append(ask)
653
+ self.app.terminal_alert()
654
+ if self._ask is None:
655
+ self._ask = self.ask_queue.pop(0)
656
+
657
+ @on(events.Click, "ModeInfo")
658
+ def on_click(self):
659
+ self.mode_switcher.focus()
660
+
661
+ def watch_modes(self, modes: dict[str, Mode] | None) -> None:
662
+ from tui.visuals.columns import Columns
663
+
664
+ columns = Columns("auto", "auto", "flex")
665
+ if modes is not None:
666
+ mode_list = sorted(modes.values(), key=lambda mode: mode.name.lower())
667
+ for mode in mode_list:
668
+ columns.add_row(
669
+ (
670
+ Content.styled("✔", "$text-success")
671
+ if self.current_mode and mode.id == self.current_mode.id
672
+ else ""
673
+ ),
674
+ Content.from_markup("[bold]$mode[/]", mode=mode.name),
675
+ Content.styled(mode.description or "", "dim"),
676
+ )
677
+ else:
678
+ mode_list = []
679
+
680
+ self.mode_switcher.set_options(
681
+ [Option(row, id=mode.id) for row, mode in zip(columns, mode_list)]
682
+ )
683
+ if self.current_mode is not None:
684
+ self.mode_switcher.highlighted = self.mode_switcher.get_option_index(
685
+ self.current_mode.id
686
+ )
687
+
688
+ def watch_agent_ready(self, ready: bool) -> None:
689
+ self.set_class(not ready, "-not-ready")
690
+ if ready:
691
+ self.query_one(AgentInfo).update(self.agent_info)
692
+
693
+ def watch_agent_info(self, agent_info: Content) -> None:
694
+ if self.agent_ready:
695
+ self.query_one(AgentInfo).update(agent_info)
696
+ else:
697
+ self.query_one(AgentInfo).update("Initializing…")
698
+
699
+ def watch_multiline(self) -> None:
700
+ self.update_prompt()
701
+
702
+ def watch_shell_mode(self) -> None:
703
+ self.update_prompt()
704
+
705
+ def watch_working_directory(self, working_directory: str) -> None:
706
+ if not working_directory:
707
+ return
708
+ out_of_bounds = not Path(working_directory).is_relative_to(self.project_path)
709
+ if out_of_bounds and not self.has_class("-working-directory-out-of-bounds"):
710
+ self.post_message(
711
+ messages.Flash(
712
+ "You have navigated away from the project directory",
713
+ style="error",
714
+ duration=5,
715
+ )
716
+ )
717
+ self.set_class(
718
+ out_of_bounds,
719
+ "-working-directory-out-of-bounds",
720
+ )
721
+
722
+ def watch__ask(self, ask: Ask | None) -> None:
723
+ self.set_class(ask is not None, "-mode-ask")
724
+ if ask is None:
725
+ self.prompt_text_area.focus()
726
+ else:
727
+ self.question.update(ask)
728
+ self.question.focus()
729
+
730
+ def update_prompt(self):
731
+ """Update the prompt according to the current mode."""
732
+ if self.shell_mode:
733
+ self.prompt_label.update(self.PROMPT_SHELL, layout=False)
734
+ self.add_class("-shell-mode")
735
+ self.prompt_text_area.placeholder = Content.from_markup(
736
+ "Enter shell command\t[r]▌esc▐[/r] prompt mode"
737
+ ).expand_tabs(8)
738
+ self.prompt_text_area.highlight_language = "shell"
739
+ else:
740
+ self.prompt_label.update(
741
+ self.PROMPT_MULTILINE if self.multi_line else self.PROMPT_AI,
742
+ layout=False,
743
+ )
744
+ self.remove_class("-shell-mode")
745
+
746
+ prompt_message = self.app.settings.get("ui.prompt_message", str)
747
+ self.prompt_text_area.placeholder = Content.assemble(
748
+ f"{prompt_message}\t".expandtabs(8),
749
+ ("▌!▐", "r"),
750
+ " shell ",
751
+ ("▌/▐", "r"),
752
+ " commands ",
753
+ ("▌@▐", "r"),
754
+ " files",
755
+ )
756
+ self.prompt_text_area.highlight_language = "markdown"
757
+
758
+ @property
759
+ def likely_shell(self) -> bool:
760
+ text = self.prompt_text_area.text
761
+ if "\n" in text or " " in text or not text.strip():
762
+ return False
763
+
764
+ shell_commands = {
765
+ command.strip()
766
+ for command in self.app.settings.get(
767
+ "shell.allow_commands", expect_type=str
768
+ ).split()
769
+ }
770
+ if text.split(" ", 1)[0] in shell_commands:
771
+ return True
772
+ return False
773
+
774
+ @property
775
+ def is_shell_mode(self) -> bool:
776
+ return self.shell_mode or self.likely_shell
777
+
778
+ def focus(self, scroll_visible: bool = True) -> Self:
779
+ if self._ask is not None:
780
+ self.question.focus()
781
+ else:
782
+ self.query(HighlightedTextArea).focus()
783
+ return self
784
+
785
+ def append(self, text: str) -> None:
786
+ self.query_one(HighlightedTextArea).insert(
787
+ text, maintain_selection_offset=False
788
+ )
789
+
790
+ def watch_show_path_search(self, show: bool) -> None:
791
+ self.prompt_text_area.suggestion = ""
792
+
793
+ def watch_show_slash_complete(self, show: bool) -> None:
794
+ if show:
795
+ self.slash_complete.focus()
796
+
797
+ def project_directory_updated(self) -> None:
798
+ """Called when there is may be new files"""
799
+ self.path_search.refresh_paths()
800
+
801
+ @on(PromptTextArea.RequestShellMode)
802
+ def on_request_shell_mode(self, event: PromptTextArea.RequestShellMode):
803
+ self.shell_mode = True
804
+ self.update_prompt()
805
+
806
+ @on(TextArea.Changed)
807
+ def on_text_area_changed(self, event: TextArea.Changed) -> None:
808
+ text = event.text_area.text
809
+
810
+ self.multi_line = "```" in text
811
+
812
+ if not self.multi_line and self.likely_shell:
813
+ self.shell_mode = True
814
+
815
+ self.update_prompt()
816
+
817
+ @on(PromptTextArea.CancelShell)
818
+ def on_cancel_shell(self, event: PromptTextArea.CancelShell):
819
+ self.shell_mode = False
820
+
821
+ @on(InvokeFileSearch)
822
+ def on_invoke_file_search(self, event: InvokeFileSearch) -> None:
823
+ event.stop()
824
+ if not self.shell_mode:
825
+ self.show_path_search = True
826
+ self.path_search.reset()
827
+
828
+ @on(InvokeSlashComplete)
829
+ def on_invoke_slash_complete(self, event: InvokeSlashComplete) -> None:
830
+ event.stop()
831
+ self.show_slash_complete = True
832
+
833
+ @on(messages.PromptSuggestion)
834
+ def on_prompt_suggestion(self, event: messages.PromptSuggestion) -> None:
835
+ event.stop()
836
+ self.prompt_text_area.suggestion = event.suggestion
837
+
838
+ @on(SlashComplete.Completed)
839
+ def on_slash_complete_completed(self, event: SlashComplete.Completed) -> None:
840
+ self.prompt_text_area.clear()
841
+ self.prompt_text_area.insert(f"{event.command} ")
842
+ self.prompt_text_area.suggestion = ""
843
+ self.focus()
844
+
845
+ @on(messages.Dismiss)
846
+ def on_dismiss(self, event: messages.Dismiss) -> None:
847
+ event.stop()
848
+ if event.widget is self.slash_complete and self.show_slash_complete:
849
+ self.show_slash_complete = False
850
+ self.prompt_text_area.suggestion = ""
851
+ self.focus()
852
+ elif event.widget is self.path_search and self.show_path_search:
853
+ self.show_path_search = False
854
+ self.focus()
855
+
856
+ @on(messages.InsertPath)
857
+ def on_insert_path(self, event: messages.InsertPath) -> None:
858
+ event.stop()
859
+ if " " in event.path:
860
+ path = f'"{event.path}"'
861
+ else:
862
+ path = event.path
863
+ if (
864
+ self.prompt_text_area.get_text_range(*self.prompt_text_area.selection)
865
+ != " "
866
+ ):
867
+ path += " "
868
+ self.prompt_text_area.insert(path)
869
+
870
+ @on(Question.Answer)
871
+ def on_question_answer(self, event: Question.Answer) -> None:
872
+ """Question has been answered."""
873
+ event.stop()
874
+
875
+ def remove_question() -> None:
876
+ """Remove the question and restore the text prompt."""
877
+ if self.ask_queue:
878
+ self._ask = self.ask_queue.pop(0)
879
+ else:
880
+ self._ask = None
881
+ self.app.terminal_alert(False)
882
+
883
+ if self._ask is not None and (callback := self._ask.callback) is not None:
884
+ callback(event.answer)
885
+
886
+ self.set_timer(0.3, remove_question)
887
+
888
+ def suggest(self, suggestion: str) -> None:
889
+ if suggestion.startswith(self.text) and self.text != suggestion:
890
+ self.prompt_text_area.suggestion = suggestion[len(self.text) :]
891
+
892
+ def compose(self) -> ComposeResult:
893
+ yield PathSearch(self.project_path).data_bind(root=Prompt.project_path)
894
+ yield SlashComplete().data_bind(slash_commands=Prompt.slash_commands)
895
+ yield PendingPrompts().data_bind(_prompts=Prompt.pending_prompts)
896
+ with PromptContainer(id="prompt-container"):
897
+ yield Question()
898
+ with containers.HorizontalGroup(id="text-prompt"):
899
+ yield Label(self.PROMPT_AI, id="prompt", markup=False)
900
+ yield PromptTextArea().data_bind(
901
+ multi_line=Prompt.multi_line,
902
+ shell_mode=Prompt.shell_mode,
903
+ agent_ready=Prompt.agent_ready,
904
+ project_path=Prompt.project_path,
905
+ working_directory=Prompt.working_directory,
906
+ slash_commands=Prompt.slash_commands,
907
+ )
908
+ with containers.HorizontalGroup(id="info-container"):
909
+ yield AgentInfo()
910
+ yield CondensedPath().data_bind(path=Prompt.working_directory)
911
+ yield StatusLine(markup=False).data_bind(status=Prompt.status)
912
+ yield ModeSwitcher()
913
+ yield ModeInfo("mode")
914
+
915
+ def check_action(self, action: str, parameters: tuple[object, ...]) -> bool | None:
916
+ return True
917
+
918
+ def action_dismiss(self) -> None:
919
+ if self._ask is not None:
920
+ ask = self._ask
921
+ if (callback := ask.callback) is not None:
922
+ callback(Answer("Cancelled", "reject_once", "reject_once"))
923
+ self.ask_queue.clear()
924
+ self._ask = None
925
+ self.app.terminal_alert(False)
926
+ return
927
+ if self.prompt_text_area.suggestion:
928
+ self.prompt_text_area.suggestion = ""
929
+ return
930
+ if self.shell_mode:
931
+ self.shell_mode = False
932
+ elif self.show_slash_complete:
933
+ self.show_slash_complete = False
934
+ else:
935
+ raise SkipAction()