@scemoon/cdh 1.0.9 → 1.0.10-beta.1

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/package.json +9 -2
  2. package/ai-dlc-skill/SKILL.md +0 -106
  3. package/ai-dlc-skill/architecture/project-structure.md +0 -78
  4. package/ai-dlc-skill/brownfield/README.md +0 -36
  5. package/ai-dlc-skill/brownfield/entry.md +0 -45
  6. package/ai-dlc-skill/brownfield/generate-context.sh +0 -64
  7. package/ai-dlc-skill/brownfield/scripts/deps.sh +0 -27
  8. package/ai-dlc-skill/brownfield/scripts/discover.sh +0 -34
  9. package/ai-dlc-skill/brownfield/scripts/extract-api.sh +0 -45
  10. package/ai-dlc-skill/components/backend.md +0 -47
  11. package/ai-dlc-skill/components/desktop.md +0 -63
  12. package/ai-dlc-skill/components/mya.md +0 -219
  13. package/ai-dlc-skill/components/native.md +0 -73
  14. package/ai-dlc-skill/components/tta.md +0 -235
  15. package/ai-dlc-skill/components/web.md +0 -77
  16. package/ai-dlc-skill/components/wxa.md +0 -219
  17. package/ai-dlc-skill/contracts/README.md +0 -25
  18. package/ai-dlc-skill/core/adaptive-flow.md +0 -107
  19. package/ai-dlc-skill/core/security.md +0 -29
  20. package/ai-dlc-skill/core/task-registry.md +0 -153
  21. package/ai-dlc-skill/cross-tool/README.md +0 -20
  22. package/ai-dlc-skill/cross-tool/cline/export.sh +0 -38
  23. package/ai-dlc-skill/cross-tool/copilot/export.sh +0 -41
  24. package/ai-dlc-skill/cross-tool/cursor/export.sh +0 -53
  25. package/ai-dlc-skill/cross-tool/onecode/export.sh +0 -27
  26. package/ai-dlc-skill/cross-tool/opencode/export.sh +0 -38
  27. package/ai-dlc-skill/phases/debug/entry.md +0 -48
  28. package/ai-dlc-skill/phases/debug/lifecycle.md +0 -284
  29. package/ai-dlc-skill/phases/deliver/entry.md +0 -35
  30. package/ai-dlc-skill/phases/deliver/lifecycle.md +0 -185
  31. package/ai-dlc-skill/phases/deliver/prompt.md +0 -54
  32. package/ai-dlc-skill/phases/deliver/rules.md +0 -61
  33. package/ai-dlc-skill/phases/plan/design_system/accessibility.md +0 -268
  34. package/ai-dlc-skill/phases/plan/design_system/atomic_design.md +0 -341
  35. package/ai-dlc-skill/phases/plan/design_system/component_spec.md +0 -398
  36. package/ai-dlc-skill/phases/plan/design_system/design_tokens.md +0 -190
  37. package/ai-dlc-skill/phases/plan/design_system/iconography.md +0 -299
  38. package/ai-dlc-skill/phases/plan/design_system/platform_ui/desktop.md +0 -318
  39. package/ai-dlc-skill/phases/plan/design_system/platform_ui/mya.md +0 -354
  40. package/ai-dlc-skill/phases/plan/design_system/platform_ui/native.md +0 -328
  41. package/ai-dlc-skill/phases/plan/design_system/platform_ui/tta.md +0 -394
  42. package/ai-dlc-skill/phases/plan/design_system/platform_ui/web.md +0 -287
  43. package/ai-dlc-skill/phases/plan/design_system/platform_ui/wxa.md +0 -374
  44. package/ai-dlc-skill/phases/plan/design_system/theme_system.md +0 -318
  45. package/ai-dlc-skill/phases/plan/entry.md +0 -33
  46. package/ai-dlc-skill/phases/plan/lifecycle.md +0 -260
  47. package/ai-dlc-skill/phases/plan/prompt.md +0 -75
  48. package/ai-dlc-skill/phases/plan/rules.md +0 -60
  49. package/ai-dlc-skill/phases/understand/entry.md +0 -36
  50. package/ai-dlc-skill/phases/understand/lifecycle.md +0 -184
  51. package/ai-dlc-skill/phases/understand/prompt.md +0 -58
  52. package/ai-dlc-skill/phases/understand/rules.md +0 -49
  53. package/ai-dlc-skill/phases/verify/config/base_url.md +0 -65
  54. package/ai-dlc-skill/phases/verify/entry.md +0 -59
  55. package/ai-dlc-skill/phases/verify/gates/browser_e2e.md +0 -96
  56. package/ai-dlc-skill/phases/verify/lifecycle.md +0 -217
  57. package/ai-dlc-skill/phases/verify/prompt.md +0 -73
  58. package/ai-dlc-skill/phases/verify/rules.md +0 -91
  59. package/ai-dlc-skill/phases/verify/runners/playwright_local.md +0 -103
  60. package/ai-dlc-skill/practices/bdd.md +0 -119
  61. package/ai-dlc-skill/practices/sdd.md +0 -84
  62. package/ai-dlc-skill/practices/tdd.md +0 -128
  63. package/ai-dlc-skill/providers/README.md +0 -114
  64. package/ai-dlc-skill/providers/aliyun/SKILL.md +0 -204
  65. package/ai-dlc-skill/providers/aliyun/api/rest-api.md +0 -214
  66. package/ai-dlc-skill/providers/aliyun/api/sdk.md +0 -307
  67. package/ai-dlc-skill/providers/aliyun/best-practices/database-design.md +0 -363
  68. package/ai-dlc-skill/providers/aliyun/best-practices/function-design.md +0 -424
  69. package/ai-dlc-skill/providers/aliyun/best-practices/troubleshooting.md +0 -258
  70. package/ai-dlc-skill/providers/aliyun/cli/database.md +0 -263
  71. package/ai-dlc-skill/providers/aliyun/cli/functions.md +0 -263
  72. package/ai-dlc-skill/providers/aliyun/cli/hosting.md +0 -226
  73. package/ai-dlc-skill/providers/aliyun/cli/setup.md +0 -235
  74. package/ai-dlc-skill/providers/aliyun/cli/storage.md +0 -315
  75. package/ai-dlc-skill/providers/aliyun/deployment.yaml +0 -66
  76. package/ai-dlc-skill/providers/aliyun/integration/ci-cd.md +0 -288
  77. package/ai-dlc-skill/providers/aliyun/preview.yaml +0 -84
  78. package/ai-dlc-skill/providers/aliyun/provider.yaml +0 -160
  79. package/ai-dlc-skill/providers/aliyun/security/authentication.md +0 -254
  80. package/ai-dlc-skill/providers/aliyun/services/cdn-hosting.md +0 -220
  81. package/ai-dlc-skill/providers/aliyun/services/database.md +0 -319
  82. package/ai-dlc-skill/providers/aliyun/services/function-compute.md +0 -273
  83. package/ai-dlc-skill/providers/aliyun/services/overview.md +0 -163
  84. package/ai-dlc-skill/providers/aliyun/services/serverless-app-engine.md +0 -266
  85. package/ai-dlc-skill/providers/aliyun/services/storage.md +0 -269
  86. package/ai-dlc-skill/providers/tcb/SKILL.md +0 -208
  87. package/ai-dlc-skill/providers/tcb/api/rest-api.md +0 -338
  88. package/ai-dlc-skill/providers/tcb/api/sdk.md +0 -288
  89. package/ai-dlc-skill/providers/tcb/best-practices/database-design.md +0 -452
  90. package/ai-dlc-skill/providers/tcb/best-practices/function-design.md +0 -502
  91. package/ai-dlc-skill/providers/tcb/best-practices/troubleshooting.md +0 -462
  92. package/ai-dlc-skill/providers/tcb/cli/cls.md +0 -133
  93. package/ai-dlc-skill/providers/tcb/cli/database.md +0 -230
  94. package/ai-dlc-skill/providers/tcb/cli/env.md +0 -207
  95. package/ai-dlc-skill/providers/tcb/cli/functions.md +0 -276
  96. package/ai-dlc-skill/providers/tcb/cli/hosting.md +0 -219
  97. package/ai-dlc-skill/providers/tcb/cli/setup.md +0 -218
  98. package/ai-dlc-skill/providers/tcb/cli/storage.md +0 -233
  99. package/ai-dlc-skill/providers/tcb/deployment.yaml +0 -111
  100. package/ai-dlc-skill/providers/tcb/integration/ci-cd.md +0 -309
  101. package/ai-dlc-skill/providers/tcb/integration/mcp-server.md +0 -371
  102. package/ai-dlc-skill/providers/tcb/preview.yaml +0 -83
  103. package/ai-dlc-skill/providers/tcb/provider.yaml +0 -172
  104. package/ai-dlc-skill/providers/tcb/security/authentication.md +0 -241
  105. package/ai-dlc-skill/providers/tcb/services/cloud-database.md +0 -299
  106. package/ai-dlc-skill/providers/tcb/services/cloud-functions.md +0 -265
  107. package/ai-dlc-skill/providers/tcb/services/cloud-hosting.md +0 -264
  108. package/ai-dlc-skill/providers/tcb/services/cloud-run.md +0 -285
  109. package/ai-dlc-skill/providers/tcb/services/cloud-storage.md +0 -245
  110. package/ai-dlc-skill/providers/tcb/services/overview.md +0 -174
  111. package/ai-dlc-skill/pybdd/README.md +0 -41
  112. package/ai-dlc-skill/pybdd/conftest.py +0 -17
  113. package/ai-dlc-skill/pybdd/example/auth/login.feature +0 -32
  114. package/ai-dlc-skill/pybdd/pytest.ini +0 -5
  115. package/ai-dlc-skill/pybdd/steps/.gitkeep +0 -1
  116. package/ai-dlc-skill/pybdd/steps/test_example_steps.py +0 -65
  117. package/ai-dlc-skill/requirements.md +0 -140
  118. package/ai-dlc-skill/skill.yaml +0 -135
  119. package/ai-dlc-skill/templates/brownfield/context.md +0 -78
  120. package/ai-dlc-skill/templates/integration/CHANGELOG.md +0 -41
  121. package/ai-dlc-skill/templates/integration/asyncapi.yaml +0 -43
  122. package/ai-dlc-skill/templates/integration/contract-diff.md +0 -63
  123. package/ai-dlc-skill/templates/integration/contract-spec.md +0 -49
  124. package/ai-dlc-skill/templates/integration/openapi.yaml +0 -18
  125. package/ai-dlc-skill/templates/integration/runtime-contract.yaml +0 -36
  126. package/ai-dlc-skill/templates/plan/design.md +0 -49
  127. package/ai-dlc-skill/templates/plan/task-list.md +0 -32
  128. package/ai-dlc-skill/templates/project/README.md +0 -126
  129. package/ai-dlc-skill/templates/project/template.md +0 -119
  130. package/ai-dlc-skill/templates/understand/feature.feature +0 -30
  131. package/ai-dlc-skill/templates/understand/intent.md +0 -29
  132. package/ai-dlc-skill/templates/understand/spec-delta.md +0 -47
  133. package/ai-dlc-skill/templates/verify/test-unit.py +0 -27
  134. package/ai-dlc-skill/walkthrough/collect.sh +0 -50
  135. package/ai-dlc-skill/walkthrough/template.md +0 -54
  136. package/cdh/__init__.py +0 -0
  137. package/cdh/__main__.py +0 -4
  138. package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
  139. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  140. package/cdh/__pycache__/cli_logging.cpython-314.pyc +0 -0
  141. package/cdh/__pycache__/config.cpython-314.pyc +0 -0
  142. package/cdh/__pycache__/project_loader.cpython-314.pyc +0 -0
  143. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  144. package/cdh/__pycache__/session_store.cpython-314.pyc +0 -0
  145. package/cdh/cdh_session_aggregator.py +0 -258
  146. package/cdh/cli.py +0 -3000
  147. package/cdh/cli_logging.py +0 -45
  148. package/cdh/config.py +0 -28
  149. package/cdh/event_loop/__init__.py +0 -7
  150. package/cdh/event_loop/bus.py +0 -123
  151. package/cdh/event_loop/events.py +0 -25
  152. package/cdh/event_loop/runner.py +0 -28
  153. package/cdh/event_loop/scheduler.py +0 -158
  154. package/cdh/generators/__init__.py +0 -35
  155. package/cdh/generators/_runtime.py +0 -176
  156. package/cdh/generators/ada/MANIFEST.toml +0 -14
  157. package/cdh/generators/ada/template.ads.tmpl +0 -7
  158. package/cdh/generators/bash/MANIFEST.toml +0 -14
  159. package/cdh/generators/bash/template.sh.tmpl +0 -16
  160. package/cdh/generators/builtin_index.json +0 -590
  161. package/cdh/generators/c/MANIFEST.toml +0 -14
  162. package/cdh/generators/c/template.h.tmpl +0 -20
  163. package/cdh/generators/cli.py +0 -379
  164. package/cdh/generators/clojure/MANIFEST.toml +0 -14
  165. package/cdh/generators/clojure/template.clj.tmpl +0 -13
  166. package/cdh/generators/cobol/MANIFEST.toml +0 -14
  167. package/cdh/generators/cobol/template.cbl.tmpl +0 -14
  168. package/cdh/generators/cpp/MANIFEST.toml +0 -14
  169. package/cdh/generators/cpp/template.hpp.tmpl +0 -32
  170. package/cdh/generators/crystal/MANIFEST.toml +0 -14
  171. package/cdh/generators/crystal/template.cr.tmpl +0 -11
  172. package/cdh/generators/csharp/MANIFEST.toml +0 -23
  173. package/cdh/generators/csharp/template.cs.tmpl +0 -14
  174. package/cdh/generators/cython/MANIFEST.toml +0 -14
  175. package/cdh/generators/cython/template.pyx.tmpl +0 -17
  176. package/cdh/generators/d/MANIFEST.toml +0 -14
  177. package/cdh/generators/d/template.d.tmpl +0 -24
  178. package/cdh/generators/dart/MANIFEST.toml +0 -17
  179. package/cdh/generators/dart/template.dart.tmpl +0 -27
  180. package/cdh/generators/elixir/MANIFEST.toml +0 -17
  181. package/cdh/generators/elixir/template.ex.tmpl +0 -27
  182. package/cdh/generators/elm/MANIFEST.toml +0 -14
  183. package/cdh/generators/elm/template.elm.tmpl +0 -20
  184. package/cdh/generators/erlang/MANIFEST.toml +0 -14
  185. package/cdh/generators/erlang/template.erl.tmpl +0 -18
  186. package/cdh/generators/fortran/MANIFEST.toml +0 -14
  187. package/cdh/generators/fortran/template.f90.tmpl +0 -24
  188. package/cdh/generators/fsharp/MANIFEST.toml +0 -14
  189. package/cdh/generators/fsharp/template.fs.tmpl +0 -17
  190. package/cdh/generators/go/MANIFEST.toml +0 -18
  191. package/cdh/generators/go/imports.go.tmpl +0 -3
  192. package/cdh/generators/go/template.go.tmpl +0 -9
  193. package/cdh/generators/graphql-schema/MANIFEST.toml +0 -18
  194. package/cdh/generators/graphql-schema/template.graphqls.tmpl +0 -12
  195. package/cdh/generators/groovy/MANIFEST.toml +0 -14
  196. package/cdh/generators/groovy/template.groovy.tmpl +0 -28
  197. package/cdh/generators/hack/MANIFEST.toml +0 -14
  198. package/cdh/generators/hack/template.hh.tmpl +0 -24
  199. package/cdh/generators/haskell/MANIFEST.toml +0 -14
  200. package/cdh/generators/haskell/template.hs.tmpl +0 -20
  201. package/cdh/generators/haxe/MANIFEST.toml +0 -14
  202. package/cdh/generators/haxe/template.hx.tmpl +0 -20
  203. package/cdh/generators/idris/MANIFEST.toml +0 -14
  204. package/cdh/generators/idris/template.idr.tmpl +0 -22
  205. package/cdh/generators/java/MANIFEST.toml +0 -18
  206. package/cdh/generators/java/template.java.tmpl +0 -13
  207. package/cdh/generators/julia/MANIFEST.toml +0 -14
  208. package/cdh/generators/julia/template.jl.tmpl +0 -27
  209. package/cdh/generators/kotlin/MANIFEST.toml +0 -18
  210. package/cdh/generators/kotlin/template.kt.tmpl +0 -12
  211. package/cdh/generators/lua/MANIFEST.toml +0 -14
  212. package/cdh/generators/lua/template.lua.tmpl +0 -27
  213. package/cdh/generators/matlab/MANIFEST.toml +0 -14
  214. package/cdh/generators/matlab/template.m.tmpl +0 -26
  215. package/cdh/generators/nim/MANIFEST.toml +0 -14
  216. package/cdh/generators/nim/template.nim.tmpl +0 -12
  217. package/cdh/generators/nix/MANIFEST.toml +0 -14
  218. package/cdh/generators/nix/template.nix.tmpl +0 -8
  219. package/cdh/generators/objective-c/MANIFEST.toml +0 -14
  220. package/cdh/generators/objective-c/template.m.tmpl +0 -31
  221. package/cdh/generators/ocaml/MANIFEST.toml +0 -14
  222. package/cdh/generators/ocaml/template.ml.tmpl +0 -13
  223. package/cdh/generators/pascal/MANIFEST.toml +0 -14
  224. package/cdh/generators/pascal/template.pas.tmpl +0 -5
  225. package/cdh/generators/perl/MANIFEST.toml +0 -14
  226. package/cdh/generators/perl/template.pm.tmpl +0 -27
  227. package/cdh/generators/php/MANIFEST.toml +0 -17
  228. package/cdh/generators/php/template.php.tmpl +0 -31
  229. package/cdh/generators/powershell/MANIFEST.toml +0 -14
  230. package/cdh/generators/powershell/template.ps1.tmpl +0 -20
  231. package/cdh/generators/protobuf/MANIFEST.toml +0 -18
  232. package/cdh/generators/protobuf/template.proto.tmpl +0 -13
  233. package/cdh/generators/python/MANIFEST.toml +0 -18
  234. package/cdh/generators/python/template.py.tmpl +0 -12
  235. package/cdh/generators/r/MANIFEST.toml +0 -14
  236. package/cdh/generators/r/template.R.tmpl +0 -29
  237. package/cdh/generators/racket/MANIFEST.toml +0 -14
  238. package/cdh/generators/racket/template.rkt.tmpl +0 -15
  239. package/cdh/generators/registry.py +0 -211
  240. package/cdh/generators/ruby/MANIFEST.toml +0 -17
  241. package/cdh/generators/ruby/template.rb.tmpl +0 -27
  242. package/cdh/generators/rust/MANIFEST.toml +0 -18
  243. package/cdh/generators/rust/template.rs.tmpl +0 -16
  244. package/cdh/generators/scala/MANIFEST.toml +0 -20
  245. package/cdh/generators/scala/template.scala.tmpl +0 -13
  246. package/cdh/generators/scheme/MANIFEST.toml +0 -14
  247. package/cdh/generators/scheme/template.scm.tmpl +0 -16
  248. package/cdh/generators/solidity/MANIFEST.toml +0 -14
  249. package/cdh/generators/solidity/template.sol.tmpl +0 -24
  250. package/cdh/generators/swift/MANIFEST.toml +0 -18
  251. package/cdh/generators/swift/template.swift.tmpl +0 -10
  252. package/cdh/generators/typescript/MANIFEST.toml +0 -18
  253. package/cdh/generators/typescript/template.ts.tmpl +0 -7
  254. package/cdh/generators/version.py +0 -214
  255. package/cdh/generators/zig/MANIFEST.toml +0 -14
  256. package/cdh/generators/zig/template.zig.tmpl +0 -20
  257. package/cdh/logging.py +0 -314
  258. package/cdh/optimizer/__init__.py +0 -7
  259. package/cdh/optimizer/loop.py +0 -201
  260. package/cdh/optimizer/mutation.py +0 -85
  261. package/cdh/optimizer/reward.py +0 -51
  262. package/cdh/optimizer/tracker.py +0 -118
  263. package/cdh/project_loader.py +0 -1022
  264. package/cdh/rules/patterns.yaml +0 -132
  265. package/cdh/rules/spectral.yaml +0 -301
  266. package/cdh/scaffold.py +0 -1436
  267. package/cdh/session_store.py +0 -221
  268. package/cdh/state_schema.py +0 -127
  269. package/cdh/tools/__init__.py +0 -57
  270. package/cdh/tools/cls_search.py +0 -406
  271. package/cdh/tools/contract_diff.py +0 -644
  272. package/cdh/tools/deploy_stack.py +0 -590
  273. package/cdh/tools/generate_shared.py +0 -300
  274. package/cdh/tools/iac_gen.py +0 -224
  275. package/cdh/tools/otel_export.py +0 -125
  276. package/cdh/tools/pattern_detect.py +0 -451
  277. package/cdh/tools/retrofit_labels.py +0 -505
  278. package/cdh/trace/__init__.py +0 -101
  279. package/cdh/trace/__pycache__/__init__.cpython-314.pyc +0 -0
  280. package/cdh/trace/dashboard/__init__.py +0 -61
  281. package/cdh/trace/dashboard/api.py +0 -1032
  282. package/cdh/trace/dashboard/app.html +0 -1321
  283. package/cdh/trace/dashboard/server.py +0 -310
  284. package/cdh/trace/otel_exporter.py +0 -462
  285. package/cdh/trace/otel_tracer.py +0 -281
  286. package/cdh/tui.py +0 -1084
  287. package/cdh/validators/__init__.py +0 -16
  288. package/cdh/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  289. package/cdh/validators/__pycache__/bdd.cpython-314.pyc +0 -0
  290. package/cdh/validators/__pycache__/dag.cpython-314.pyc +0 -0
  291. package/cdh/validators/__pycache__/ears.cpython-314.pyc +0 -0
  292. package/cdh/validators/__pycache__/fr_namespace.cpython-314.pyc +0 -0
  293. package/cdh/validators/bdd.py +0 -144
  294. package/cdh/validators/dag.py +0 -179
  295. package/cdh/validators/ears.py +0 -452
  296. package/cdh/validators/fr_namespace.py +0 -143
  297. package/cdh/validators/spectral.py +0 -475
  298. package/cdh/verification/__init__.py +0 -3
  299. package/cdh/verification/aggregation.py +0 -53
  300. package/cdh/verification/gates/__init__.py +0 -5
  301. package/cdh/verification/gates/base.py +0 -18
  302. package/cdh/verification/gates/lint_gate.py +0 -37
  303. package/cdh/verification/gates/test_gate.py +0 -41
  304. package/cdh/verification/loop.py +0 -93
  305. package/cdh/verification/policy.py +0 -24
  306. package/onecode/__init__.py +0 -1
  307. package/onecode/__main__.py +0 -4
  308. package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
  309. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  310. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  311. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  312. package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
  313. package/onecode/agent/__init__.py +0 -0
  314. package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
  315. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  316. package/onecode/agent/__pycache__/checkpoint.cpython-314.pyc +0 -0
  317. package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
  318. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  319. package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
  320. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  321. package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
  322. package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
  323. package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
  324. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  325. package/onecode/agent/__pycache__/turn_record.cpython-314.pyc +0 -0
  326. package/onecode/agent/agents/__init__.py +0 -29
  327. package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
  328. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  329. package/onecode/agent/agents/prompts/build-agent.md +0 -50
  330. package/onecode/agent/agents/prompts/compaction-instructions.md +0 -12
  331. package/onecode/agent/agents/prompts/explore-agent.md +0 -42
  332. package/onecode/agent/agents/prompts/plan-agent.md +0 -44
  333. package/onecode/agent/agents/prompts/plan-gate-hard.md +0 -4
  334. package/onecode/agent/agents/prompts/plan-gate-soft.md +0 -3
  335. package/onecode/agent/agents/prompts/solo-agent.md +0 -57
  336. package/onecode/agent/agents/prompts/subagent-constraints.md +0 -10
  337. package/onecode/agent/agents/prompts/summary-instructions.md +0 -7
  338. package/onecode/agent/agents/prompts/title-instructions.md +0 -3
  339. package/onecode/agent/agents/prompts/tool-descriptions.md +0 -129
  340. package/onecode/agent/agents/types.py +0 -786
  341. package/onecode/agent/attachments.py +0 -112
  342. package/onecode/agent/cdh_loader.py +0 -3
  343. package/onecode/agent/checkpoint.py +0 -285
  344. package/onecode/agent/context.py +0 -465
  345. package/onecode/agent/engine.py +0 -3547
  346. package/onecode/agent/event_bridge.py +0 -75
  347. package/onecode/agent/hooks.py +0 -86
  348. package/onecode/agent/onecode_agent_acp.py +0 -2993
  349. package/onecode/agent/permissions.py +0 -150
  350. package/onecode/agent/permissions_store.py +0 -73
  351. package/onecode/agent/project_doc.py +0 -19
  352. package/onecode/agent/question_detect.py +0 -230
  353. package/onecode/agent/session.py +0 -3
  354. package/onecode/agent/snapshot.py +0 -144
  355. package/onecode/agent/tools/__init__.py +0 -17
  356. package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  357. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  358. package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
  359. package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
  360. package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
  361. package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
  362. package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
  363. package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
  364. package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
  365. package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
  366. package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
  367. package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
  368. package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
  369. package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
  370. package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
  371. package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
  372. package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
  373. package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
  374. package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
  375. package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
  376. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  377. package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
  378. package/onecode/agent/tools/agent_tools.py +0 -128
  379. package/onecode/agent/tools/apply_patch_tool.py +0 -138
  380. package/onecode/agent/tools/bash_tool.py +0 -121
  381. package/onecode/agent/tools/communication_tools.py +0 -154
  382. package/onecode/agent/tools/config_tool.py +0 -130
  383. package/onecode/agent/tools/cron_tools.py +0 -178
  384. package/onecode/agent/tools/errors.py +0 -17
  385. package/onecode/agent/tools/file_ops.py +0 -221
  386. package/onecode/agent/tools/file_tools.py +0 -225
  387. package/onecode/agent/tools/git_tools.py +0 -88
  388. package/onecode/agent/tools/lsp_tools.py +0 -404
  389. package/onecode/agent/tools/mcp_tools.py +0 -211
  390. package/onecode/agent/tools/permission_handler.py +0 -46
  391. package/onecode/agent/tools/permissions.py +0 -77
  392. package/onecode/agent/tools/protocol.py +0 -20
  393. package/onecode/agent/tools/registry.py +0 -210
  394. package/onecode/agent/tools/sandbox.py +0 -460
  395. package/onecode/agent/tools/schema_validation.py +0 -100
  396. package/onecode/agent/tools/skill_tools.py +0 -52
  397. package/onecode/agent/tools/todo_tools.py +0 -208
  398. package/onecode/agent/tools/web_tools.py +0 -530
  399. package/onecode/agent/turn_record.py +0 -28
  400. package/onecode/builtin_skills/agent-browser/SKILL.md +0 -212
  401. package/onecode/builtin_skills/agent-browser/skill.yaml +0 -8
  402. package/onecode/builtin_skills/cloudbase/SKILL.md +0 -162
  403. package/onecode/builtin_skills/cloudbase/skill.yaml +0 -7
  404. package/onecode/builtin_skills/git/SKILL.md +0 -64
  405. package/onecode/builtin_skills/git/skill.yaml +0 -7
  406. package/onecode/builtin_skills/shell/SKILL.md +0 -58
  407. package/onecode/builtin_skills/shell/skill.yaml +0 -8
  408. package/onecode/builtin_skills/skill-creator/SKILL.md +0 -106
  409. package/onecode/builtin_skills/skill-creator/skill.yaml +0 -8
  410. package/onecode/cli.py +0 -1325
  411. package/onecode/codebase/__init__.py +0 -69
  412. package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
  413. package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
  414. package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
  415. package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
  416. package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
  417. package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
  418. package/onecode/codebase/chunker.py +0 -125
  419. package/onecode/codebase/indexer.py +0 -154
  420. package/onecode/codebase/retriever.py +0 -240
  421. package/onecode/codebase/storage.py +0 -153
  422. package/onecode/codebase/tools.py +0 -59
  423. package/onecode/commands.py +0 -673
  424. package/onecode/config.py +0 -539
  425. package/onecode/config_screen.py +0 -486
  426. package/onecode/cron/__init__.py +0 -3
  427. package/onecode/lsp/__init__.py +0 -3
  428. package/onecode/mcp/__init__.py +0 -11
  429. package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
  430. package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
  431. package/onecode/mcp/__pycache__/cloudbase.cpython-314.pyc +0 -0
  432. package/onecode/mcp/__pycache__/config.cpython-314.pyc +0 -0
  433. package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
  434. package/onecode/mcp/__pycache__/oauth.cpython-314.pyc +0 -0
  435. package/onecode/mcp/client.py +0 -305
  436. package/onecode/mcp/cloudbase.py +0 -188
  437. package/onecode/mcp/config.py +0 -363
  438. package/onecode/mcp/manager.py +0 -603
  439. package/onecode/mcp/oauth.py +0 -199
  440. package/onecode/memory/__init__.py +0 -106
  441. package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
  442. package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
  443. package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
  444. package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
  445. package/onecode/memory/backend.py +0 -179
  446. package/onecode/memory/pyramid.py +0 -145
  447. package/onecode/memory/recall.py +0 -322
  448. package/onecode/migrate.py +0 -122
  449. package/onecode/models/__init__.py +0 -4
  450. package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
  451. package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
  452. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  453. package/onecode/models/__pycache__/ollama_manager.cpython-314.pyc +0 -0
  454. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  455. package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
  456. package/onecode/models/errors.py +0 -104
  457. package/onecode/models/messages.py +0 -750
  458. package/onecode/models/ollama_manager.py +0 -167
  459. package/onecode/models/provider.py +0 -730
  460. package/onecode/models/providers/__init__.py +0 -17
  461. package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
  462. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  463. package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
  464. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  465. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  466. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  467. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  468. package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
  469. package/onecode/models/providers/anthropic_provider.py +0 -286
  470. package/onecode/models/providers/deepseek_provider.py +0 -221
  471. package/onecode/models/providers/glm_provider.py +0 -219
  472. package/onecode/models/providers/minimax_provider.py +0 -182
  473. package/onecode/models/providers/minimaxi_provider.py +0 -426
  474. package/onecode/models/providers/ollama_provider.py +0 -183
  475. package/onecode/models/providers/openai_provider.py +0 -234
  476. package/onecode/models/registry.py +0 -349
  477. package/onecode/server/__init__.py +0 -3
  478. package/onecode/server/app.py +0 -251
  479. package/onecode/skills/__init__.py +0 -11
  480. package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
  481. package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
  482. package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
  483. package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
  484. package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
  485. package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
  486. package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
  487. package/onecode/skills/argument_substitution.py +0 -38
  488. package/onecode/skills/bootstrap.py +0 -37
  489. package/onecode/skills/create.py +0 -56
  490. package/onecode/skills/frontmatter.py +0 -33
  491. package/onecode/skills/loader.py +0 -215
  492. package/onecode/skills/manager.py +0 -75
  493. package/onecode/skills/model.py +0 -43
  494. package/onecode/storage/__init__.py +0 -0
  495. package/onecode/storage/activity.py +0 -63
  496. package/onecode/storage/project.py +0 -54
  497. package/onecode/storage/session.py +0 -112
  498. package/onecode/tasks/__init__.py +0 -26
  499. package/onecode/tasks/manager.py +0 -232
  500. package/onecode/tasks/models.py +0 -240
  501. package/onecode/trace/__init__.py +0 -0
  502. package/onecode/trace/tracer.py +0 -173
  503. package/onecode/utils/__init__.py +0 -0
  504. package/onecode/utils/helpers.py +0 -20
  505. package/onecode/verification/__init__.py +0 -5
  506. package/onecode/verification/__pycache__/__init__.cpython-314.pyc +0 -0
  507. package/onecode/verification/__pycache__/aggregation.cpython-314.pyc +0 -0
  508. package/onecode/verification/__pycache__/loop.cpython-314.pyc +0 -0
  509. package/onecode/verification/__pycache__/policy.cpython-314.pyc +0 -0
  510. package/onecode/verification/aggregation.py +0 -53
  511. package/onecode/verification/gates/__init__.py +0 -6
  512. package/onecode/verification/gates/__pycache__/__init__.cpython-314.pyc +0 -0
  513. package/onecode/verification/gates/__pycache__/base.cpython-314.pyc +0 -0
  514. package/onecode/verification/gates/__pycache__/lint_gate.cpython-314.pyc +0 -0
  515. package/onecode/verification/gates/__pycache__/test_gate.cpython-314.pyc +0 -0
  516. package/onecode/verification/gates/__pycache__/type_gate.cpython-314.pyc +0 -0
  517. package/onecode/verification/gates/base.py +0 -20
  518. package/onecode/verification/gates/lint_gate.py +0 -45
  519. package/onecode/verification/gates/test_gate.py +0 -62
  520. package/onecode/verification/gates/type_gate.py +0 -46
  521. package/onecode/verification/loop.py +0 -95
  522. package/onecode/verification/policy.py +0 -29
  523. package/pyproject.toml +0 -84
  524. package/tui/__init__.py +0 -46
  525. package/tui/__main__.py +0 -4
  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 +0 -86
  565. package/tui/_path_fuzzy_search.py +0 -48
  566. package/tui/_path_match.py +0 -141
  567. package/tui/about.py +0 -95
  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 +0 -1212
  576. package/tui/acp/api.py +0 -79
  577. package/tui/acp/encode_tool_call_id.py +0 -12
  578. package/tui/acp/event_tap.py +0 -107
  579. package/tui/acp/messages.py +0 -222
  580. package/tui/acp/prompt.py +0 -53
  581. package/tui/acp/protocol.py +0 -551
  582. package/tui/agent.py +0 -70
  583. package/tui/agent_schema.py +0 -76
  584. package/tui/agents.py +0 -46
  585. package/tui/ansi/__init__.py +0 -1
  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 +0 -1689
  594. package/tui/ansi/_ansi_colors.py +0 -264
  595. package/tui/ansi/_control_codes.py +0 -37
  596. package/tui/ansi/_keys.py +0 -251
  597. package/tui/ansi/_sgr_styles.py +0 -64
  598. package/tui/ansi/_stream_parser.py +0 -418
  599. package/tui/answer.py +0 -12
  600. package/tui/app.py +0 -1195
  601. package/tui/atomic.py +0 -37
  602. package/tui/cli.py +0 -208
  603. package/tui/code_analyze.py +0 -27
  604. package/tui/complete.py +0 -38
  605. package/tui/constants.py +0 -61
  606. package/tui/conversation_markdown.py +0 -30
  607. package/tui/danger.py +0 -372
  608. package/tui/data/agents/ampcode.com.toml +0 -52
  609. package/tui/data/agents/augmentcode.com.toml +0 -41
  610. package/tui/data/agents/cdh.cloud-dev-harness.toml +0 -23
  611. package/tui/data/agents/claude.com.toml +0 -42
  612. package/tui/data/agents/copilot.github.com.toml +0 -29
  613. package/tui/data/agents/crowai.dev.toml +0 -36
  614. package/tui/data/agents/cursor.com.toml +0 -38
  615. package/tui/data/agents/deepagents.langchain.com +0 -34
  616. package/tui/data/agents/docker.com.toml +0 -60
  617. package/tui/data/agents/geminicli.com.toml +0 -28
  618. package/tui/data/agents/goose.ai.toml +0 -52
  619. package/tui/data/agents/inference.huggingface.co.toml +0 -41
  620. package/tui/data/agents/kimi.com.toml +0 -35
  621. package/tui/data/agents/kiro.dev.toml +0 -43
  622. package/tui/data/agents/onecode.dev.toml +0 -22
  623. package/tui/data/agents/openai.com.toml +0 -53
  624. package/tui/data/agents/openclaw.ai.toml +0 -37
  625. package/tui/data/agents/opencode.ai.toml +0 -39
  626. package/tui/data/agents/openhands.dev.toml +0 -46
  627. package/tui/data/agents/stakpak.dev.toml +0 -62
  628. package/tui/data/agents/vibe.mistral.ai.toml +0 -31
  629. package/tui/data/agents/vtcode.dev.toml +0 -63
  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 +0 -213
  634. package/tui/dec.py +0 -332
  635. package/tui/diff_utils.py +0 -131
  636. package/tui/directory.py +0 -234
  637. package/tui/directory_suggester.py +0 -93
  638. package/tui/directory_watcher.py +0 -231
  639. package/tui/format_path.py +0 -25
  640. package/tui/fuzzy.py +0 -140
  641. package/tui/fuzzy_index.py +0 -275
  642. package/tui/gist.py +0 -33
  643. package/tui/history.py +0 -138
  644. package/tui/jsonrpc.py +0 -599
  645. package/tui/menus.py +0 -14
  646. package/tui/message_log.py +0 -69
  647. package/tui/messages.py +0 -144
  648. package/tui/option_content.py +0 -51
  649. package/tui/os.py +0 -0
  650. package/tui/path_complete.py +0 -217
  651. package/tui/path_filter.py +0 -124
  652. package/tui/paths.py +0 -87
  653. package/tui/pill.py +0 -23
  654. package/tui/platform_commands.py +0 -52
  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 +0 -19
  658. package/tui/prompt/resource.py +0 -68
  659. package/tui/protocol.py +0 -28
  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 +0 -94
  666. package/tui/screens/agent_modal.py +0 -175
  667. package/tui/screens/command_edit_modal.py +0 -74
  668. package/tui/screens/diff_explorer_screen.py +0 -419
  669. package/tui/screens/diff_screen.py +0 -84
  670. package/tui/screens/ide_screen.py +0 -461
  671. package/tui/screens/main.py +0 -397
  672. package/tui/screens/main.tcss +0 -662
  673. package/tui/screens/permissions.py +0 -404
  674. package/tui/screens/permissions.tcss +0 -72
  675. package/tui/screens/projects.tcss +0 -84
  676. package/tui/screens/projects_app.py +0 -341
  677. package/tui/screens/projects_screen.py +0 -277
  678. package/tui/screens/session_resume_modal.py +0 -172
  679. package/tui/screens/session_resume_modal.tcss +0 -35
  680. package/tui/screens/sessions.py +0 -171
  681. package/tui/screens/sessions.tcss +0 -119
  682. package/tui/screens/settings.py +0 -293
  683. package/tui/screens/settings.tcss +0 -113
  684. package/tui/screens/store.py +0 -502
  685. package/tui/screens/store.tcss +0 -274
  686. package/tui/screens/tool_content_screen.py +0 -59
  687. package/tui/screens/trace.py +0 -317
  688. package/tui/session_tracker.py +0 -123
  689. package/tui/settings.py +0 -353
  690. package/tui/settings_schema.py +0 -467
  691. package/tui/shell.py +0 -304
  692. package/tui/shell_read.py +0 -42
  693. package/tui/slash_command.py +0 -34
  694. package/tui/tui.tcss +0 -246
  695. package/tui/twitter.py +0 -38
  696. package/tui/version.py +0 -80
  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 +0 -272
  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 +0 -70
  738. package/tui/widgets/agent_response.py +0 -76
  739. package/tui/widgets/agent_thought.py +0 -167
  740. package/tui/widgets/aidlc.py +0 -334
  741. package/tui/widgets/ask_user.py +0 -604
  742. package/tui/widgets/command_pane.py +0 -223
  743. package/tui/widgets/condensed_path.py +0 -115
  744. package/tui/widgets/context_stats.py +0 -66
  745. package/tui/widgets/conversation.py +0 -3235
  746. package/tui/widgets/danger_warning.py +0 -65
  747. package/tui/widgets/diff_view.py +0 -69
  748. package/tui/widgets/directory_input.py +0 -8
  749. package/tui/widgets/edit_field.py +0 -206
  750. package/tui/widgets/flash.py +0 -81
  751. package/tui/widgets/future_text.py +0 -126
  752. package/tui/widgets/grid_select.py +0 -234
  753. package/tui/widgets/highlighted_textarea.py +0 -183
  754. package/tui/widgets/load_more.py +0 -24
  755. package/tui/widgets/mandelbrot.py +0 -294
  756. package/tui/widgets/markdown_note.py +0 -13
  757. package/tui/widgets/menu.py +0 -147
  758. package/tui/widgets/model_status.py +0 -230
  759. package/tui/widgets/modified_files.py +0 -315
  760. package/tui/widgets/non_selectable_label.py +0 -5
  761. package/tui/widgets/note.py +0 -18
  762. package/tui/widgets/path_search.py +0 -492
  763. package/tui/widgets/pending_prompts.py +0 -36
  764. package/tui/widgets/plan.py +0 -285
  765. package/tui/widgets/project_directory_tree.py +0 -102
  766. package/tui/widgets/project_grid_select.py +0 -68
  767. package/tui/widgets/project_summary.py +0 -33
  768. package/tui/widgets/prompt.py +0 -935
  769. package/tui/widgets/question.py +0 -360
  770. package/tui/widgets/session_grid_select.py +0 -230
  771. package/tui/widgets/session_summary.py +0 -115
  772. package/tui/widgets/session_tabs.py +0 -194
  773. package/tui/widgets/shell_result.py +0 -35
  774. package/tui/widgets/shell_terminal.py +0 -40
  775. package/tui/widgets/side_bar.py +0 -124
  776. package/tui/widgets/slash_complete.py +0 -235
  777. package/tui/widgets/strike_text.py +0 -70
  778. package/tui/widgets/subagent.py +0 -287
  779. package/tui/widgets/subagent_screen.py +0 -715
  780. package/tui/widgets/terminal.py +0 -576
  781. package/tui/widgets/terminal_tool.py +0 -360
  782. package/tui/widgets/throbber.py +0 -100
  783. package/tui/widgets/tool_call.py +0 -432
  784. package/tui/widgets/user_input.py +0 -23
  785. package/tui/widgets/version.py +0 -5
  786. package/tui/widgets/welcome.py +0 -31
package/tui/ansi/_ansi.py DELETED
@@ -1,1689 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import io
4
- from itertools import accumulate
5
- import re
6
-
7
- from dataclasses import dataclass, field
8
- from functools import lru_cache
9
- from typing import Awaitable, Callable, Iterable, Literal, Mapping, NamedTuple
10
-
11
- import rich.repr
12
-
13
- from textual import events
14
- from textual.color import Color
15
- from textual.content import Content, EMPTY_CONTENT
16
- from textual.geometry import clamp
17
- from textual.style import Style, NULL_STYLE
18
-
19
- from tui.ansi._ansi_colors import ANSI_COLORS
20
- from tui.ansi._keys import TERMINAL_KEY_MAP, CURSOR_KEYS_APPLICATION
21
- from tui.ansi._control_codes import CONTROL_CODES
22
- from tui.ansi._sgr_styles import SGR_STYLES
23
- from tui.ansi._stream_parser import (
24
- StreamParser,
25
- SeparatorToken,
26
- PatternToken,
27
- Pattern,
28
- PatternCheck,
29
- ParseResult,
30
- Token,
31
- )
32
-
33
- from tui.dec import CHARSET_MAP
34
-
35
-
36
- def character_range(start: int, end: int) -> frozenset:
37
- """Build a set of characters between to code-points.
38
-
39
- Args:
40
- start: Start codepoint.
41
- end: End codepoint (inclusive)
42
-
43
- Returns:
44
- A frozenset of the characters..
45
- """
46
- return frozenset(map(chr, range(start, end + 1)))
47
-
48
-
49
- class ANSIToken:
50
- pass
51
-
52
-
53
- class DEC(NamedTuple):
54
- slot: int
55
- character_set: str
56
-
57
-
58
- class DECInvoke(NamedTuple):
59
- gl: int | None = None
60
- gr: int | None = None
61
- shift: int | None = None
62
-
63
-
64
- DEC_SLOTS = {"(": 0, ")": 1, "*": 2, "+": 3, "-": 1, ".": 2, "//": 3}
65
-
66
-
67
-
68
-
69
-
70
- class FEPattern(Pattern):
71
- FINAL = character_range(0x30, 0x7E)
72
- INTERMEDIATE = character_range(0x20, 0x2F)
73
- CSI_TERMINATORS = character_range(0x40, 0x7E)
74
- OSC_TERMINATORS = frozenset({"\x07", "\x9c"})
75
- DSC_TERMINATORS = frozenset({"\x9c"})
76
-
77
- def check(self) -> PatternCheck:
78
- sequence = io.StringIO()
79
- store = sequence.write
80
- store(character := (yield))
81
-
82
- match character:
83
- # CSI
84
- case "[":
85
- CSI_TERMINATORS = self.CSI_TERMINATORS
86
- while (character := (yield)) not in CSI_TERMINATORS:
87
- store(character)
88
- store(character)
89
- return ("csi", sequence.getvalue())
90
-
91
- # OSC
92
- case "]":
93
- last_character = ""
94
- OSC_TERMINATORS = self.OSC_TERMINATORS
95
- while (character := (yield)) not in OSC_TERMINATORS:
96
- store(character)
97
- if last_character == "\x1b" and character in {"\\", "\0x5c"}:
98
- break
99
- last_character = character
100
- store(character)
101
-
102
- return ("osc", sequence.getvalue())
103
-
104
- # DCS
105
- case "P":
106
- last_character = ""
107
- DSC_TERMINATORS = self.DSC_TERMINATORS
108
- while (character := (yield)) not in DSC_TERMINATORS:
109
- store(character)
110
- if last_character == "\x1b" and character == "\\":
111
- break
112
- last_character = character
113
- store(character)
114
- return ("dcs", sequence.getvalue())
115
-
116
- # Character set designation
117
- case "(" | ")" | "*" | "+" | "-" | "." | "/":
118
- if (character := (yield)) not in self.FINAL:
119
- return False
120
- store(character)
121
- return ("dec", sequence.getvalue())
122
-
123
- case "n" | "o" | "~" | "}" | "|" | "N" | "O":
124
- return ("dec_invoke", sequence.getvalue())
125
-
126
- # Line attribute
127
- case "#":
128
- store((yield))
129
- return ("la", sequence.getvalue())
130
- # ISO 2022: ESC SP
131
- case " ":
132
- store((yield))
133
- return ("sp", sequence.getvalue())
134
- case _:
135
- return ("control", character)
136
-
137
-
138
- class ANSIParser(StreamParser[tuple[str, str]]):
139
- """Parse a stream of text containing escape sequences in to logical tokens."""
140
-
141
- def parse(self) -> ParseResult[tuple[str, str]]:
142
- NEW_LINE = "\n"
143
- CARRIAGE_RETURN = "\r"
144
- ESCAPE = "\x1b"
145
- BACKSPACE = "\x08"
146
-
147
- while True:
148
- token = yield self.read_until(NEW_LINE, CARRIAGE_RETURN, ESCAPE, BACKSPACE)
149
- if isinstance(token, SeparatorToken):
150
- if token.text == ESCAPE:
151
- token = yield self.read_patterns("\x1b", fe=FEPattern())
152
- if isinstance(token, PatternToken):
153
- yield token.value
154
- else:
155
- yield "separator", token.text
156
- continue
157
-
158
- yield "content", token.text
159
-
160
-
161
- EMPTY_LINE = Content()
162
-
163
-
164
- type ClearType = Literal["cursor_to_end", "cursor_to_beginning", "screen", "scrollback"]
165
- ANSI_CLEAR: Mapping[int, ClearType] = {
166
- 0: "cursor_to_end",
167
- 1: "cursor_to_beginning",
168
- 2: "screen",
169
- 3: "scrollback",
170
- }
171
-
172
-
173
- @rich.repr.auto
174
- class ANSIContent(NamedTuple):
175
- """Content to be written to the terminal."""
176
-
177
- text: str
178
-
179
- def __rich_repr__(self) -> rich.repr.Result:
180
- yield self.text
181
-
182
-
183
- @rich.repr.auto
184
- class ANSICursor(NamedTuple):
185
- """Represents a single operation on the ANSI output.
186
-
187
- All values may be `None` meaning "not set".
188
- """
189
-
190
- delta_x: int | None = None
191
- """Relative x change."""
192
- delta_y: int | None = None
193
- """Relative y change."""
194
- absolute_x: int | None = None
195
- """Replace x."""
196
- absolute_y: int | None = None
197
- """Replace y."""
198
- erase: bool = False
199
- """Erase (replace with spaces)?"""
200
- clear_range: tuple[int | None, int | None] | None = None
201
- """Replace range (slice like)."""
202
- relative: bool = False
203
- """Should replace be relative (`False`) or absolute (`True`)"""
204
- update_background: bool = False
205
- """Optional style for remaining line."""
206
- auto_scroll: bool = False
207
- """Perform a scroll with the movement?"""
208
- save: bool = False
209
- """Save cursor position (DECSC)."""
210
- restore: bool = False
211
- """Restore cursor position (DECRC)."""
212
- insert_lines: int = 0
213
- """Insert blank lines at cursor (IL)."""
214
- delete_lines: int = 0
215
- """Delete lines at cursor (DL)."""
216
-
217
- def __rich_repr__(self) -> rich.repr.Result:
218
- yield "delta_x", self.delta_x, None
219
- yield "delta_y", self.delta_y, None
220
- yield "absolute_x", self.absolute_x, None
221
- yield "absolute_y", self.absolute_y, None
222
- yield "erase", self.erase, False
223
- yield "clear_range", self.clear_range, None
224
- yield "relative", self.relative, False
225
- yield "update_background", self.update_background, False
226
- yield "auto_scroll", self.auto_scroll, False
227
-
228
- @lru_cache(maxsize=1024)
229
- def get_clear_offsets(
230
- self, cursor_offset: int, line_length: int
231
- ) -> tuple[int, int]:
232
- """Get replace offsets.
233
-
234
- Args:
235
- cursor_offset: Current cursor offset.
236
- line_length: Length of line.
237
-
238
- Returns:
239
- A pair of offsets (inclusive).
240
- """
241
- assert (
242
- self.clear_range is not None
243
- ), "Only call this if the replace attribute has a value"
244
- replace_start, replace_end = self.clear_range
245
- if replace_start is None:
246
- replace_start = cursor_offset
247
- if replace_end is None:
248
- replace_end = cursor_offset
249
- if replace_start < 0:
250
- replace_start = line_length + replace_start
251
- if replace_end < 0:
252
- replace_end = line_length + replace_end
253
- if self.relative:
254
- return (cursor_offset + replace_start, cursor_offset + replace_end)
255
- else:
256
- return (replace_start, replace_end)
257
-
258
-
259
- @rich.repr.auto
260
- class ANSINewLine:
261
- """New line (diffrent in alternate buffer)"""
262
-
263
-
264
- @rich.repr.auto
265
- class ANSIStyle(NamedTuple):
266
- """Update style."""
267
-
268
- style: Style
269
-
270
- def __rich_repr__(self) -> rich.repr.Result:
271
- yield self.style
272
-
273
-
274
- @rich.repr.auto
275
- class ANSIClear(NamedTuple):
276
- """Enumeration for clearing the 'screen'."""
277
-
278
- clear: ClearType
279
-
280
- def __rich_repr__(self) -> rich.repr.Result:
281
- yield self.clear
282
-
283
-
284
- @rich.repr.auto
285
- class ANSIScrollMargin(NamedTuple):
286
- """Set the scroll margin."""
287
-
288
- top: int | None = None
289
- bottom: int | None = None
290
-
291
- def __rich_repr__(self) -> rich.repr.Result:
292
- yield self.top
293
- yield self.bottom
294
-
295
-
296
- @rich.repr.auto
297
- class ANSIScroll(NamedTuple):
298
- """Scroll buffer."""
299
-
300
- direction: Literal[+1, -1]
301
- lines: int
302
-
303
- def __rich_repr__(self) -> rich.repr.Result:
304
- yield self.direction
305
- yield self.lines
306
-
307
-
308
- class ANSIFeatures(NamedTuple):
309
- """Terminal feature flags."""
310
-
311
- show_cursor: bool | None = None
312
- alternate_screen: bool | None = None
313
- bracketed_paste: bool | None = None
314
- cursor_blink: bool | None = None
315
- cursor_keys: bool | None = None
316
- replace_mode: bool | None = None
317
- auto_wrap: bool | None = None
318
-
319
-
320
- MOUSE_TRACKING_MODES = Literal["button", "drag", "all"]
321
- MOUSE_FORMAT = Literal["normal", "utf8", "sgr", "urxvt"]
322
-
323
-
324
- class ANSIMouseTracking(NamedTuple):
325
- """Set mouse tracking."""
326
-
327
- mode: Literal["none"] | MOUSE_TRACKING_MODES | None = None
328
- format: MOUSE_FORMAT | None = None
329
- focus_events: bool | None = None
330
- alternate_scroll: bool | None = None
331
-
332
-
333
- # Not technically part of the terminal protocol
334
- @rich.repr.auto
335
- class ANSIWorkingDirectory(NamedTuple):
336
- """Working directory changed"""
337
-
338
- path: str
339
-
340
- def __rich_repr__(self) -> rich.repr.Result:
341
- yield self.path
342
-
343
-
344
- @rich.repr.auto
345
- class ANSICharacterSet(NamedTuple):
346
- """Updated character set state."""
347
-
348
- dec: DEC | None = None
349
- dec_invoke: DECInvoke | None = None
350
-
351
-
352
- @rich.repr.auto
353
- class ANSICursorPositionRequest(NamedTuple):
354
- pass
355
-
356
-
357
- type ANSICommand = (
358
- ANSIStyle
359
- | ANSIContent
360
- | ANSICursor
361
- | ANSINewLine
362
- | ANSIClear
363
- | ANSIScrollMargin
364
- | ANSIScroll
365
- | ANSIWorkingDirectory
366
- | ANSICharacterSet
367
- | ANSIFeatures
368
- | ANSIMouseTracking
369
- | ANSICursorPositionRequest
370
- )
371
-
372
-
373
- class ANSIStream:
374
- def __init__(self) -> None:
375
- self.parser = ANSIParser()
376
- self.style = NULL_STYLE
377
- self.show_cursor = True
378
-
379
- @classmethod
380
- @lru_cache(maxsize=1024)
381
- def _parse_sgr(cls, sgr: str) -> Style | None:
382
- """Parse a SGR (Select Graphics Rendition) code in to a Style instance,
383
- or `None` to indicate a reset.
384
-
385
- Args:
386
- sgr: SGR sequence.
387
-
388
- Returns:
389
- A Visual Style, or `None`.
390
- """
391
- codes = [
392
- code if code < 255 else 255
393
- for code in map(int, [sgr_code or "0" for sgr_code in sgr.split(";")])
394
- ]
395
- style = NULL_STYLE
396
- while codes:
397
- match codes:
398
- case [38, 2, red, green, blue, *codes]:
399
- # Foreground RGB
400
- style += Style(foreground=Color(red, green, blue))
401
- case [48, 2, red, green, blue, *codes]:
402
- # Background RGB
403
- style += Style(background=Color(red, green, blue))
404
- case [38, 5, ansi_color, *codes]:
405
- # Foreground ANSI
406
- style += Style(foreground=ANSI_COLORS[ansi_color])
407
- case [48, 5, ansi_color, *codes]:
408
- # Background ANSI
409
- style += Style(background=ANSI_COLORS[ansi_color])
410
- case [0, *codes]:
411
- # reset
412
- return None
413
- case [code, *codes]:
414
- if sgr_style := SGR_STYLES.get(code):
415
- style += sgr_style
416
-
417
- return style
418
-
419
- def feed(self, text: str) -> Iterable[ANSICommand]:
420
- """Feed text potentially containing ANSI sequences, and parse in to
421
- an iterable of ansi commands.
422
-
423
- Args:
424
- text: Text to feed.
425
-
426
- Yields:
427
- `ANSICommand` instances.
428
- """
429
-
430
- for token in self.parser.feed(text):
431
- if not isinstance(token, Token):
432
- yield from self.on_token(token)
433
-
434
- ANSI_SEPARATORS = {
435
- "\n": ANSICursor(delta_y=+1, absolute_x=0),
436
- "\r": ANSICursor(absolute_x=0),
437
- "\x08": ANSICursor(delta_x=-1),
438
- }
439
- CLEAR_LINE_CURSOR_TO_END = ANSICursor(
440
- clear_range=(None, -1), erase=True, update_background=True
441
- )
442
- CLEAR_LINE_CURSOR_TO_BEGINNING = ANSICursor(
443
- clear_range=(0, None), erase=True, update_background=True
444
- )
445
- CLEAR_LINE = ANSICursor(clear_range=(0, -1), erase=True, update_background=True)
446
- CLEAR_SCREEN_CURSOR_TO_END = ANSIClear("cursor_to_end")
447
- CLEAR_SCREEN_CURSOR_TO_BEGINNING = ANSIClear("cursor_to_beginning")
448
- CLEAR_SCREEN = ANSIClear("screen")
449
- CLEAR_SCREEN_SCROLLBACK = ANSIClear("scrollback")
450
- SHOW_CURSOR = ANSIFeatures(show_cursor=True)
451
- HIDE_CURSOR = ANSIFeatures(show_cursor=False)
452
- ENABLE_ALTERNATE_SCREEN = ANSIFeatures(alternate_screen=True)
453
- DISABLE_ALTERNATE_SCREEN = ANSIFeatures(alternate_screen=False)
454
- ENABLE_BRACKETED_PASTE = ANSIFeatures(bracketed_paste=True)
455
- DISABLE_BRACKETED_PASTE = ANSIFeatures(bracketed_paste=False)
456
- ENABLE_CURSOR_BLINK = ANSIFeatures(cursor_blink=True)
457
- DISABLE_CURSOR_BLINK = ANSIFeatures(cursor_blink=False)
458
- ENABLE_CURSOR_KEYS_APPLICATION_MODE = ANSIFeatures(cursor_keys=True)
459
- DISABLE_CURSOR_KEYS_APPLICATION_MODE = ANSIFeatures(cursor_keys=False)
460
- ENABLE_REPLACE_MODE = ANSIFeatures(replace_mode=True)
461
- DISABLE_REPLACE_MODE = ANSIFeatures(replace_mode=False)
462
- ENABLE_AUTO_WRAP = ANSIFeatures(auto_wrap=True)
463
- DISABLE_AUTO_WRAP = ANSIFeatures(auto_wrap=False)
464
-
465
- INVOKE_G2_INTO_GL = DECInvoke(gl=2)
466
- INVOKE_G3_INTO_GL = DECInvoke(gl=3)
467
- INVOKE_G1_INTO_GR = DECInvoke(gr=1)
468
- INVOKE_G2_INTO_GR = DECInvoke(gr=2)
469
- INVOKE_G3_INTO_GR = DECInvoke(gr=3)
470
- SHIFT_G2 = DECInvoke(shift=2)
471
- SHIFT_G3 = DECInvoke(shift=3)
472
-
473
- DEC_INVOKE_MAP = {
474
- "n": INVOKE_G2_INTO_GL,
475
- "o": INVOKE_G3_INTO_GL,
476
- "~": INVOKE_G1_INTO_GR,
477
- "}": INVOKE_G2_INTO_GR,
478
- "|": INVOKE_G3_INTO_GR,
479
- "N": SHIFT_G2,
480
- "O": SHIFT_G3,
481
- }
482
-
483
- @classmethod
484
- @lru_cache(maxsize=1024)
485
- def _parse_csi(cls, csi: str) -> ANSICommand | None:
486
- """Parse CSI sequence in to an ansi segment.
487
-
488
- Args:
489
- csi: CSI sequence.
490
-
491
- Returns:
492
- Ansi segment, or `None` if one couldn't be decoded.
493
- """
494
-
495
- if match := re.fullmatch(r"\[(\d+)?(?:;)?(\d*)?(\w)", csi):
496
- match_groups = match.groups(default="")
497
- match match_groups:
498
- case [lines, _, "A"]:
499
- # CUU - Cursor Up: ESC[nA
500
- return ANSICursor(delta_y=-int(lines or 1))
501
- case [lines, _, "B"]:
502
- # CUD - Cursor Down: ESC[nB
503
- return ANSICursor(delta_y=+int(lines or 1))
504
- case [cells, _, "C"]:
505
- # CUF - Cursor Forward: ESC[nC
506
- return ANSICursor(delta_x=+int(cells or 1))
507
- case [cells, _, "D"]:
508
- # CUB - Cursor Back: ESC[nD
509
- return ANSICursor(delta_x=-int(cells or 1))
510
- case [lines, _, "E"]:
511
- # CNL - Cursor Next Line: ESC[nE
512
- return ANSICursor(absolute_x=0, delta_y=+int(lines or 1))
513
- case [lines, _, "F"]:
514
- # CPL - Cursor Previous Line: ESC[nF
515
- return ANSICursor(absolute_x=0, delta_y=-int(lines or 1))
516
- case [cells, _, "G"]:
517
- # CHA - Cursor Horizontal Absolute: ESC[nG
518
- return ANSICursor(absolute_x=+int(cells or 1) - 1)
519
- case [row, column, "H" | "f"]:
520
- # CUP - Cursor Position: ESC[n;mH
521
- # HVP - Horizontal Vertical Position: ESC[n;mf
522
- return ANSICursor(
523
- absolute_x=int(column or 1) - 1,
524
- absolute_y=int(row or 1) - 1,
525
- )
526
- case [characters, _, "P"]:
527
- return ANSICursor(
528
- clear_range=(0, int(characters or 1) - 1),
529
- relative=True,
530
- erase=True,
531
- )
532
- case [lines, _, "S"]:
533
- return ANSIScroll(-1, int(lines))
534
- case [lines, _, "T"]:
535
- return ANSIScroll(+1, int(lines))
536
- case [lines, _, "L"]:
537
- return ANSICursor(insert_lines=int(lines or 1))
538
- case [lines, _, "M"]:
539
- return ANSICursor(delete_lines=int(lines or 1))
540
- case [row, _, "d"]:
541
- # VPA - Vertical Position Absolute: ESC[nd
542
- return ANSICursor(absolute_y=int(row or 1) - 1)
543
- case [characters, _, "X"]:
544
- return ANSICursor(
545
- clear_range=(0, int(characters or 1) - 1),
546
- relative=True,
547
- erase=False,
548
- )
549
- case ["0" | "", _, "J"]:
550
- return cls.CLEAR_SCREEN_CURSOR_TO_END
551
- case ["1", _, "J"]:
552
- return cls.CLEAR_SCREEN_CURSOR_TO_BEGINNING
553
- case ["2", _, "J"]:
554
- return cls.CLEAR_SCREEN
555
- case ["3", _, "J"]:
556
- return cls.CLEAR_SCREEN_SCROLLBACK
557
- case ["0" | "", _, "K"]:
558
- return cls.CLEAR_LINE_CURSOR_TO_END
559
- case ["1", _, "K"]:
560
- return cls.CLEAR_LINE_CURSOR_TO_BEGINNING
561
- case ["2", _, "K"]:
562
- return cls.CLEAR_LINE
563
- case [top, bottom, "r"]:
564
- return ANSIScrollMargin(
565
- int(top or "1") - 1 if top else None,
566
- int(bottom or "1") - 1 if top else None,
567
- )
568
- case ["4", _, "h" | "l" as replace_mode]:
569
- return (
570
- cls.ENABLE_REPLACE_MODE
571
- if replace_mode == "h"
572
- else cls.DISABLE_REPLACE_MODE
573
- )
574
-
575
- case ["6", _, "n"]:
576
- return ANSICursorPositionRequest()
577
-
578
- case _:
579
- return None
580
-
581
- elif match := re.fullmatch(r"\[([0-9:;<=>?]*)([!-/]*)([@-~])", csi):
582
- match match.groups(default=""):
583
- case ["?25", "", "h"]:
584
- return cls.SHOW_CURSOR
585
- case ["?25", "", "l"]:
586
- return cls.HIDE_CURSOR
587
- case ["?1049", "", "h"]:
588
- return cls.ENABLE_ALTERNATE_SCREEN
589
- case ["?1049", "", "l"]:
590
- return cls.DISABLE_ALTERNATE_SCREEN
591
- case ["?2004", "", "h"]:
592
- return cls.ENABLE_BRACKETED_PASTE
593
- case ["?2004", "", "l"]:
594
- return cls.DISABLE_BRACKETED_PASTE
595
- case ["?12", "", "h"]:
596
- return cls.ENABLE_CURSOR_BLINK
597
- case ["?12", "", "l"]:
598
- return cls.DISABLE_CURSOR_BLINK
599
- case ["?1", "", "h"]:
600
- return cls.ENABLE_CURSOR_KEYS_APPLICATION_MODE
601
- case ["?1", "", "l"]:
602
- return cls.DISABLE_CURSOR_KEYS_APPLICATION_MODE
603
- case ["?7", "", "h"]:
604
- return cls.ENABLE_AUTO_WRAP
605
- case ["?7", "", "l"]:
606
- return cls.DISABLE_AUTO_WRAP
607
-
608
- # \x1b[22;0;0t
609
- case [param1, param2, "t"]:
610
- # 't' = XTWINOPS (Window manipulation)
611
- return None
612
- case _:
613
- if match := re.fullmatch(r"\[\?([0-9;]+)([hl])", csi):
614
- modes = [m for m in match.group(1).split(";")]
615
- enable = match.group(2) == "h"
616
- tracking: Literal["none"] | MOUSE_TRACKING_MODES | None = None
617
- format: MOUSE_FORMAT | None = None
618
- focus_events: bool | None = None
619
- alternate_scroll: bool | None = None
620
- for mode in modes:
621
- if mode == "1000":
622
- tracking = "button" if enable else "none"
623
- elif mode == "1002":
624
- tracking = "drag" if enable else "none"
625
- elif mode == "1003":
626
- tracking = "all" if enable else "none"
627
- elif mode == "1006":
628
- format = "sgr"
629
- elif mode == "1015":
630
- format = "urxvt"
631
- elif mode == "1004":
632
- focus_events = enable
633
- elif mode == "1007":
634
- alternate_scroll = enable
635
- return ANSIMouseTracking(
636
- mode=tracking,
637
- format=format,
638
- focus_events=focus_events,
639
- alternate_scroll=alternate_scroll,
640
- )
641
- else:
642
- return None
643
-
644
- return None
645
-
646
- def on_token(self, token: tuple[str, str]) -> Iterable[ANSICommand]:
647
- match token:
648
- case ["separator", separator]:
649
- if separator == "\n":
650
- yield ANSINewLine()
651
- else:
652
- yield self.ANSI_SEPARATORS[separator]
653
-
654
- case ["osc", osc]:
655
- match osc[1:].split(";"):
656
- case ["8", *_, link]:
657
- self.style += Style(link=link or None)
658
- case ["2025", current_directory, *_]:
659
- self.current_directory = current_directory
660
- yield ANSIWorkingDirectory(current_directory)
661
-
662
- case ["csi", csi]:
663
- if csi.endswith("m"):
664
- if (sgr_style := self._parse_sgr(csi[1:-1])) is None:
665
- self.style = NULL_STYLE
666
- else:
667
- self.style += sgr_style
668
- # Special case to use widget background rather
669
- # than theme background
670
- if (
671
- sgr_style.background is not None
672
- and sgr_style.background.ansi == -1
673
- ):
674
- self.style = (
675
- Style(foreground=self.style.foreground)
676
- + sgr_style.without_color
677
- )
678
- yield ANSIStyle(self.style)
679
- else:
680
- if (ansi_segment := self._parse_csi(csi)) is not None:
681
- yield ansi_segment
682
-
683
- case ["dec", dec]:
684
- slot, character_set = list(dec)
685
- yield ANSICharacterSet(DEC(DEC_SLOTS[slot], character_set))
686
-
687
- case ["dec_invoke", dec_invoke]:
688
- yield ANSICharacterSet(dec_invoke=self.DEC_INVOKE_MAP[dec_invoke[0]])
689
-
690
- case ["control", code]:
691
- if (control := CONTROL_CODES.get(code)) is not None:
692
- if control == "ri": # control code
693
- yield ANSICursor(delta_y=-1, auto_scroll=True)
694
- elif control == "ind":
695
- yield ANSICursor(delta_y=+1, auto_scroll=True)
696
- elif control == "decsc":
697
- yield ANSICursor(save=True)
698
- elif control == "decrc":
699
- yield ANSICursor(restore=True)
700
- else:
701
- pass
702
- else:
703
- pass
704
-
705
- case ["content", text]:
706
- yield ANSIContent(text)
707
-
708
- case _:
709
- pass
710
-
711
-
712
- class LineFold(NamedTuple):
713
- """A line from the terminal, folded for presentation."""
714
-
715
- line_no: int
716
- """The (unfolded) line number."""
717
-
718
- line_offset: int
719
- """The index of the folded line."""
720
-
721
- offset: int
722
- """The offset within the original line."""
723
-
724
- content: Content
725
- """The content."""
726
-
727
- updates: int = 0
728
- """Integer that increments on update."""
729
-
730
-
731
- @dataclass
732
- class LineRecord:
733
- """A single line in the terminal."""
734
-
735
- content: Content
736
- """The content."""
737
-
738
- style: Style = NULL_STYLE
739
- """The style for the remaining line."""
740
-
741
- folds: list[LineFold] = field(default_factory=list)
742
- """Line "folds" for wrapped lines."""
743
-
744
- updates: int = 0
745
- """An integer used for caching."""
746
-
747
-
748
- @rich.repr.auto
749
- class ScrollMargin(NamedTuple):
750
- """Margins at the top and bottom of a window that won't scroll."""
751
-
752
- top: int | None = None
753
- """Margin at the top (in lines), or `None` for no scroll margin set."""
754
- bottom: int | None = None
755
- """Margin at the bottom (in lines), or `None` for no scroll margin set."""
756
-
757
- def __rich_repr__(self) -> rich.repr.Result:
758
- yield self.top
759
- yield self.bottom
760
-
761
- def get_line_range(self, height: int) -> tuple[int, int]:
762
- """Get the scrollable line range (inclusive).
763
-
764
- Args:
765
- height: terminal height.
766
-
767
- Returns:
768
- A tuple of the (exclusive) top and bottom line numbers that scroll.
769
- """
770
- return (
771
- self.top or 0,
772
- height - 1 if self.bottom is None else self.bottom,
773
- )
774
-
775
-
776
- @dataclass
777
- class Buffer:
778
- """A terminal buffer (scrollback or alternate)"""
779
-
780
- name: str = "buffer"
781
- """Name of the buffer (debugging aid)."""
782
- lines: list[LineRecord] = field(default_factory=list)
783
- """unfolded lines."""
784
- line_to_fold: list[int] = field(default_factory=list)
785
- """An index from folded lines on to unfolded lines."""
786
- folded_lines: list[LineFold] = field(default_factory=list)
787
- """Folded lines."""
788
- scroll_margin: ScrollMargin = ScrollMargin(None, None)
789
- """Scroll margins"""
790
- cursor_line: int = 0
791
- """Folded line index."""
792
- cursor_offset: int = 0
793
- """Folded line offset."""
794
- max_line_width: int = 0
795
- """The longest line in the buffer."""
796
- updates: int = 0
797
- """Updates count (used in caching)."""
798
- _updated_lines: set[int] | None = None
799
-
800
- @property
801
- def line_count(self) -> int:
802
- """Total number of lines."""
803
- return len(self.lines)
804
-
805
- @property
806
- def height(self) -> int:
807
- """Height of the buffer (number of folded lines)."""
808
- height = len(self.folded_lines)
809
- if (
810
- height == 1
811
- and not self.lines[-1].content.plain
812
- and self.name == "scrollback"
813
- ):
814
- height -= 1
815
- return height
816
-
817
- @property
818
- def last_line_no(self) -> int:
819
- """Index of last lines."""
820
- return len(self.lines) - 1
821
-
822
- @property
823
- def cursor(self) -> tuple[int, int]:
824
- """The cursor offset within the un-folded lines."""
825
-
826
- if self.cursor_line >= len(self.folded_lines):
827
- return (len(self.folded_lines), 0)
828
- cursor_folded_line = self.folded_lines[self.cursor_line]
829
- cursor_line_offset = cursor_folded_line.line_offset
830
- line_no = cursor_folded_line.line_no
831
- line = self.lines[line_no]
832
- position = 0
833
- for folded_line_offset, folded_line in enumerate(line.folds):
834
- if folded_line_offset == cursor_line_offset:
835
- position += self.cursor_offset
836
- break
837
- position += len(folded_line.content)
838
-
839
- return (line_no, position)
840
-
841
- @property
842
- def is_blank(self) -> bool:
843
- """Is this buffer blank (spaces in all lines)?"""
844
- return not any(
845
- (line.content.plain.strip() or line.content.spans) for line in self.lines
846
- )
847
-
848
- def update_cursor(self, line_no: int, cursor_line_offset: int) -> None:
849
- """Move the cursor to the given unfolded line and offset.
850
-
851
- Sets `cursor_line` and `cursor_offset`.
852
-
853
- Args:
854
- line_no: Unfolded line number.
855
- cursor_line_offset: Offset within the line.
856
- """
857
- line = self.lines[line_no]
858
- fold_line_start = self.line_to_fold[line_no]
859
- position = 0
860
- fold_offset = 0
861
- for fold_offset, fold in enumerate(line.folds):
862
- line_length = len(fold.content)
863
- if (
864
- cursor_line_offset >= position
865
- and cursor_line_offset < position + line_length
866
- ):
867
- self.cursor_line = fold_line_start + fold_offset
868
- self.cursor_offset = cursor_line_offset - position
869
- break
870
- position += line_length
871
- else:
872
- self.cursor_line = fold_line_start + len(line.folds) - 1
873
- self.cursor_offset = len(line.folds[-1].content)
874
-
875
- def update_line(self, line_no: int) -> None:
876
- """Record an updated line.
877
-
878
- Args:
879
- line_no: Line number to update.
880
- """
881
- if self._updated_lines is not None:
882
- self._updated_lines.add(line_no)
883
-
884
- def clear(self, updates: int) -> None:
885
- """Clear the buffer to its initial state.
886
-
887
- Args:
888
- updates: the initial updates index.
889
-
890
- """
891
- del self.lines[:]
892
- del self.line_to_fold[:]
893
- del self.folded_lines[:]
894
- self.cursor_line = 0
895
- self.cursor_offset = 0
896
- self.max_line_width = 0
897
- self.updates = updates
898
-
899
- def remove_last_line(self) -> None:
900
- if not self.lines:
901
- return
902
- last_line_index = len(self.lines) - 1
903
- del self.lines[-1]
904
- del self.folded_lines[self.line_to_fold[last_line_index] :]
905
- del self.line_to_fold[last_line_index]
906
- self.updates += 1
907
-
908
-
909
- @dataclass
910
- class DECState:
911
- """The (somewhat bonkers) mechanism for switching characters sets pre-unicode."""
912
-
913
- slots: list[str] = field(default_factory=lambda: ["B", "B", "<", "0"])
914
- gl_slot: int = 0
915
- gr_slot: int = 2
916
- shift: int | None = None
917
-
918
- @property
919
- def gl(self) -> str:
920
- return self.slots[self.gl_slot]
921
-
922
- @property
923
- def gr(self) -> str:
924
- return self.slots[self.gr_slot]
925
-
926
- def update(self, dec: DEC | None, dec_invoke: DECInvoke | None) -> None:
927
- if dec is not None:
928
- self.slots[dec.slot] = dec.character_set
929
- elif dec_invoke is not None:
930
- if dec_invoke.shift:
931
- self.shift = dec_invoke.shift
932
- else:
933
- if dec_invoke.gl is not None:
934
- self.gl_slot = dec_invoke.gl
935
- elif dec_invoke.gr is not None:
936
- self.gr_slot = dec_invoke.gr
937
-
938
- def translate(self, text: str) -> str:
939
- translate_table: dict[int, str] | None
940
- first_character: str | None = None
941
- if self.shift is not None and (
942
- translate_table := CHARSET_MAP.get(self.slots[self.shift], None)
943
- ):
944
- first_character = text[0].translate(translate_table)
945
- self.shift = None
946
-
947
- if translate_table := CHARSET_MAP.get(self.gl, None):
948
- text = text.translate(translate_table)
949
- if first_character is None:
950
- return text
951
- return f"{first_character}{text}"
952
-
953
-
954
- @dataclass
955
- class MouseTracking:
956
- """The mouse tracking state."""
957
-
958
- tracking: MOUSE_TRACKING_MODES = "all"
959
- format: MOUSE_FORMAT = "normal"
960
- focus_events: bool = False
961
- alternate_scroll: bool = False
962
-
963
-
964
- @rich.repr.auto
965
- class TerminalState:
966
- """Abstract terminal state."""
967
-
968
- def __init__(
969
- self,
970
- write_stdin: Callable[[str], Awaitable],
971
- *,
972
- width: int = 80,
973
- height: int = 24,
974
- ) -> None:
975
- """
976
- Args:
977
- width: Initial width.
978
- height: Initial height.
979
- """
980
- self._write_stdin = write_stdin
981
-
982
- self._ansi_stream = ANSIStream()
983
- """ANSI stream processor."""
984
-
985
- self.width = width
986
- """Width of the terminal."""
987
- self.height = height
988
- """Height of the terminal."""
989
- self.style = NULL_STYLE
990
- """The current style."""
991
- self.show_cursor = True
992
- """Is the cursor visible?"""
993
- self.alternate_screen = False
994
- """Is the terminal in the alternate buffer state?"""
995
- self.bracketed_paste = False
996
- """Is bracketed pase enabled?"""
997
- self.cursor_blink = False
998
- """Should the cursor blink?"""
999
- self.cursor_keys = False
1000
- """Is cursor keys application mode enabled?"""
1001
- self.replace_mode = True
1002
- """Should content replaces characters (`True`) or insert (`False`)?"""
1003
- self.auto_wrap = True
1004
- """Should content wrap?"""
1005
- self.current_directory: str = ""
1006
- """Current working directory."""
1007
- self.scrollback_buffer = Buffer("scrollback")
1008
- """Scrollbar buffer lines."""
1009
- self.alternate_buffer = Buffer("alternate")
1010
- """Alternate buffer lines."""
1011
- self.dec_state = DECState()
1012
- """The DEC (character set) state."""
1013
- self.mouse_tracking: MouseTracking | None = None
1014
- """The mouse tracking state."""
1015
-
1016
- self._saved_cursor: tuple[int, int, DECState] | None = None
1017
- """Saved cursor position and DEC state (DECSC/DECRC)."""
1018
-
1019
- self._updates: int = 0
1020
- """Incrementing integer used in caching."""
1021
-
1022
- def __rich_repr__(self) -> rich.repr.Result:
1023
- yield "width", self.width
1024
- yield "height", self.height
1025
- yield "style", self.style, NULL_STYLE
1026
- yield "show_cursor", self.show_cursor, True
1027
- yield "alternate_screen", self.alternate_screen, False
1028
- yield "bracketed_paste", self.bracketed_paste, False
1029
- yield "cursor_blink", self.cursor_blink, False
1030
- yield "replace_mode", self.replace_mode, True
1031
- yield "auto_wrap", self.auto_wrap, True
1032
- yield "dec_state", self.dec_state
1033
- yield "mouse_tracking", self.mouse_tracking, None
1034
-
1035
- async def write_stdin(self, text: str) -> bool:
1036
- if self._write_stdin is not None:
1037
- return await self._write_stdin(text)
1038
- return False
1039
- return True
1040
-
1041
- @property
1042
- def screen_start_line_no(self) -> int:
1043
- return max(0, self.scrollback_buffer.height - self.height)
1044
-
1045
- @property
1046
- def screen_end_line_no(self) -> int:
1047
- return self.buffer.height
1048
-
1049
- @property
1050
- def updates(self) -> int:
1051
- """An integer that advanvces when the state is changed."""
1052
- return self._updates
1053
-
1054
- @property
1055
- def buffer(self) -> Buffer:
1056
- """The buffer (scrollack or alternate)"""
1057
- if self.alternate_screen:
1058
- return self.alternate_buffer
1059
- return self.scrollback_buffer
1060
-
1061
- @property
1062
- def max_line_width(self) -> int | None:
1063
- return self.scrollback_buffer.max_line_width
1064
-
1065
- def advance_updates(self) -> int:
1066
- """Advance the `updates` integer and return it.
1067
-
1068
- Returns:
1069
- int: Updates.
1070
- """
1071
- self._updates += 1
1072
- return self._updates
1073
-
1074
- def update_size(self, width: int | None = None, height: int | None = None) -> None:
1075
- """Update the dimensions of the terminal.
1076
-
1077
- Args:
1078
- width: New width, or `None` for no change.
1079
- height: New height, or `None` for no change.
1080
- """
1081
- previous_width = self.width
1082
- if width is not None:
1083
- self.width = width
1084
- if height is not None:
1085
- self.height = height
1086
-
1087
- if previous_width != width:
1088
- self._reflow()
1089
-
1090
- def key_event_to_stdin(self, event: events.Key) -> str | None:
1091
- """Get the stdin string for a key event.
1092
-
1093
- This will depend on the terminal state.
1094
-
1095
- Args:
1096
- event: Key event.
1097
-
1098
- Returns:
1099
- A string to be sent to stdin, or `None` if no key was produced.
1100
- """
1101
- if (
1102
- self.cursor_keys
1103
- and (sequence := CURSOR_KEYS_APPLICATION.get(event.key)) is not None
1104
- ):
1105
- return sequence
1106
-
1107
- if (mapped_key := TERMINAL_KEY_MAP.get(event.key)) is not None:
1108
- return mapped_key
1109
- if event.character:
1110
- return event.character
1111
- return None
1112
-
1113
- def key_escape(self) -> str:
1114
- """Generate the escape sequence for the escape key.
1115
-
1116
- Returns:
1117
- str: ANSI escape sequences.
1118
- """
1119
- return "\x1b"
1120
-
1121
- def remove_trailing_blank_lines_from_scrollback(self) -> None:
1122
- """Remove blank lines at the end of the scrollback buffer.
1123
-
1124
- A line is considered blank if it is whitespace and has no color or style applied.
1125
-
1126
- """
1127
- buffer = self.scrollback_buffer
1128
- while buffer.lines:
1129
- last_line_content = buffer.lines[-1].content
1130
- if last_line_content.spans or last_line_content.plain.rstrip():
1131
- break
1132
- buffer.remove_last_line()
1133
-
1134
- def _reflow(self) -> None:
1135
- buffer = self.buffer
1136
- if not buffer.lines:
1137
- return
1138
-
1139
- buffer._updated_lines = None
1140
- # Unfolded cursor position
1141
- cursor_line, cursor_offset = buffer.cursor
1142
-
1143
- buffer.folded_lines.clear()
1144
- buffer.line_to_fold.clear()
1145
- width = self.width
1146
-
1147
- for line_no, line_record in enumerate(buffer.lines):
1148
- line_expanded_tabs = line_record.content.expand_tabs(8)
1149
- line_record.folds[:] = self._fold_line(line_no, line_expanded_tabs, width)
1150
- line_record.updates = self.advance_updates()
1151
- buffer.line_to_fold.append(len(buffer.folded_lines))
1152
- buffer.folded_lines.extend(line_record.folds)
1153
-
1154
- # After reflow, we need to work out where the cursor is within the folded lines
1155
- # cursor_line = min(cursor_line, len(buffer.lines) - 1)
1156
- if cursor_line >= len(buffer.lines):
1157
- buffer.cursor_line = len(buffer.lines)
1158
- buffer.cursor_offset = 0
1159
- else:
1160
- line = buffer.lines[cursor_line]
1161
- fold_cursor_line = buffer.line_to_fold[cursor_line]
1162
-
1163
- fold_cursor_offset = 0
1164
- for fold in reversed(line.folds):
1165
- if cursor_offset >= fold.offset:
1166
- fold_cursor_line += fold.line_offset
1167
- fold_cursor_offset = cursor_offset - fold.offset
1168
- break
1169
-
1170
- buffer.cursor_line = fold_cursor_line
1171
- buffer.cursor_offset = fold_cursor_offset
1172
-
1173
- async def write(
1174
- self, text: str, *, hide_output: bool = False
1175
- ) -> tuple[set[int] | None, set[int] | None]:
1176
- """Write to the terminal.
1177
-
1178
- Args:
1179
- text: Text to write.
1180
- hide_output: Hide visible output from buffers.
1181
-
1182
- Returns:
1183
- A pair of deltas or `None for full refresh, for scrollback and alternate screen.
1184
- """
1185
- alternate_buffer = self.alternate_buffer
1186
- scrollback_buffer = self.scrollback_buffer
1187
-
1188
- # Reset updated lines delta
1189
- alternate_buffer._updated_lines = set()
1190
- scrollback_buffer._updated_lines = set()
1191
- # Write sequences and update
1192
- if hide_output:
1193
- for ansi_command in self._ansi_stream.feed(text):
1194
- if not isinstance(ansi_command, (ANSIContent, ANSICursor)):
1195
- await self._handle_ansi_command(ansi_command)
1196
- else:
1197
- for ansi_command in self._ansi_stream.feed(text):
1198
- await self._handle_ansi_command(ansi_command)
1199
-
1200
- # Get deltas
1201
- scrollback_updates = (
1202
- None
1203
- if scrollback_buffer._updated_lines is None
1204
- else scrollback_buffer._updated_lines.copy()
1205
- )
1206
- alternate_updates = (
1207
- None
1208
- if alternate_buffer._updated_lines is None
1209
- else alternate_buffer._updated_lines.copy()
1210
- )
1211
- # Reset deltas
1212
- self.alternate_buffer._updated_lines = set()
1213
- self.scrollback_buffer._updated_lines = set()
1214
- # Return deltas accumulated during write
1215
- return (scrollback_updates, alternate_updates)
1216
-
1217
- def get_cursor_line_offset(self, buffer: Buffer) -> int:
1218
- """The cursor offset within the un-folded lines."""
1219
- cursor_folded_line = buffer.folded_lines[buffer.cursor_line]
1220
- cursor_line_offset = cursor_folded_line.line_offset
1221
- line_no = cursor_folded_line.line_no
1222
- line = buffer.lines[line_no]
1223
- position = 0
1224
- for folded_line_offset, folded_line in enumerate(line.folds):
1225
- if folded_line_offset == cursor_line_offset:
1226
- position += buffer.cursor_offset
1227
- break
1228
- position += len(folded_line.content)
1229
- return position
1230
-
1231
- def clear_buffer(self, clear: ClearType) -> None:
1232
- buffer = self.buffer
1233
- if clear == "screen":
1234
- buffer.clear(self.advance_updates())
1235
- buffer._updated_lines = None
1236
- elif clear == "cursor_to_end":
1237
- buffer._updated_lines = None
1238
- folded_cursor_line = buffer.cursor_line
1239
- cursor_line, cursor_line_offset = buffer.cursor
1240
- while buffer.cursor_line >= len(buffer.folded_lines):
1241
- self.add_line(buffer, EMPTY_LINE)
1242
- line = buffer.lines[cursor_line]
1243
- del buffer.lines[cursor_line + 1 :]
1244
- del buffer.line_to_fold[cursor_line + 1 :]
1245
- del buffer.folded_lines[folded_cursor_line + 1 :]
1246
- self.update_line(buffer, cursor_line, line.content[:cursor_line_offset])
1247
- else:
1248
- # print(f"TODO: clear_buffer({clear!r})")
1249
- buffer.clear(self.advance_updates())
1250
-
1251
- def scroll_buffer(self, direction: int, lines: int) -> None:
1252
- """Scroll the buffer.
1253
-
1254
- Args:
1255
- direction: +1 for down, -1 for up.
1256
- lines: Number of lines.
1257
- """
1258
- buffer = self.buffer
1259
- margin_top, margin_bottom = buffer.scroll_margin.get_line_range(self.height)
1260
-
1261
- gutter_lines = max(0, buffer.height - self.height)
1262
-
1263
- if direction == -1:
1264
- # up (first in test)
1265
- for line_no in range(margin_top, margin_bottom + 1):
1266
- copy_line_no = line_no + lines
1267
- copy_content = EMPTY_CONTENT
1268
- copy_style = NULL_STYLE
1269
- if copy_line_no <= margin_bottom:
1270
- try:
1271
- copy_line = buffer.lines[copy_line_no + gutter_lines]
1272
- except IndexError:
1273
- pass
1274
- else:
1275
- copy_content = copy_line.content
1276
- copy_style = copy_line.style
1277
-
1278
- self.update_line(
1279
- buffer, line_no + gutter_lines, copy_content, copy_style
1280
- )
1281
- else:
1282
- # down
1283
- for line_no in reversed(range(margin_top, margin_bottom + 1)):
1284
- copy_line_no = line_no - lines
1285
- copy_content = EMPTY_CONTENT
1286
- copy_style = NULL_STYLE
1287
- if copy_line_no >= margin_top:
1288
- try:
1289
- copy_line = buffer.lines[copy_line_no + gutter_lines]
1290
- except IndexError:
1291
- pass
1292
- else:
1293
- copy_content = copy_line.content
1294
- copy_style = copy_line.style
1295
- self.update_line(
1296
- buffer, line_no + gutter_lines, copy_content, copy_style
1297
- )
1298
-
1299
- @classmethod
1300
- def _expand_content(cls, content: Content, offset: int, style: Style) -> Content:
1301
- """Expand content to be at least as long as a given offset.
1302
-
1303
- Args:
1304
- content: Content to expand.
1305
- offset: Offset within the content.
1306
- style: Style of padding.
1307
-
1308
- Returns:
1309
- New Content.
1310
- """
1311
- if offset > len(content):
1312
- content += Content.blank(offset - len(content), style)
1313
- return content
1314
-
1315
- async def _handle_ansi_command(self, ansi_command: ANSICommand) -> None:
1316
- if isinstance(ansi_command, ANSINewLine):
1317
- if self.alternate_screen:
1318
- # New line behaves differently in alternate screen
1319
- ansi_command = ANSICursor(delta_y=+1, auto_scroll=True)
1320
- else:
1321
- ansi_command = ANSICursor(delta_y=+1, absolute_x=0)
1322
-
1323
- match ansi_command:
1324
- case ANSIStyle(style):
1325
- self.style = style
1326
-
1327
- case ANSIContent(text):
1328
- buffer = self.buffer
1329
- folded_lines = buffer.folded_lines
1330
- while buffer.cursor_line >= len(folded_lines):
1331
- self.add_line(buffer, EMPTY_LINE)
1332
- folded_line = folded_lines[buffer.cursor_line]
1333
- previous_content = folded_line.content
1334
- line_no = folded_line.line_no
1335
- line = buffer.lines[line_no]
1336
-
1337
- cursor_line_offset = self.get_cursor_line_offset(buffer)
1338
- line_content = line.content
1339
- if cursor_line_offset > len(line_content):
1340
- line_content = self._expand_content(
1341
- line_content, cursor_line_offset, line.style
1342
- )
1343
- content = Content.styled(
1344
- self.dec_state.translate(text),
1345
- self.style,
1346
- strip_control_codes=False,
1347
- )
1348
- if self.replace_mode:
1349
- updated_line = Content.assemble(
1350
- line_content[:cursor_line_offset],
1351
- content,
1352
- line_content[cursor_line_offset + len(content) :],
1353
- strip_control_codes=False,
1354
- )
1355
- else:
1356
- updated_line = Content.assemble(
1357
- line_content[:cursor_line_offset],
1358
- content,
1359
- line_content[cursor_line_offset:],
1360
- strip_control_codes=False,
1361
- )
1362
- self.update_line(buffer, line_no, updated_line)
1363
- buffer.update_cursor(line_no, cursor_line_offset + len(content))
1364
- buffer.updates = self.advance_updates()
1365
-
1366
- case ANSICursor(
1367
- delta_x,
1368
- delta_y,
1369
- absolute_x,
1370
- absolute_y,
1371
- erase,
1372
- clear_range,
1373
- _relative,
1374
- update_background,
1375
- auto_scroll,
1376
- save,
1377
- restore,
1378
- insert_lines,
1379
- delete_lines,
1380
- ):
1381
- buffer = self.buffer
1382
-
1383
- if save:
1384
- self._saved_cursor = (
1385
- buffer.cursor_offset,
1386
- buffer.cursor_line,
1387
- self.dec_state,
1388
- )
1389
- if restore:
1390
- if self._saved_cursor is not None:
1391
- buffer.cursor_offset, buffer.cursor_line, self.dec_state = (
1392
- self._saved_cursor
1393
- )
1394
-
1395
- if insert_lines:
1396
- count = insert_lines
1397
- margin_top, margin_bottom = buffer.scroll_margin.get_line_range(self.height)
1398
- gutter_lines = max(0, buffer.height - self.height)
1399
- if margin_top <= buffer.cursor_line <= margin_bottom:
1400
- region_top = buffer.cursor_line
1401
- for _ in range(count):
1402
- for line_no in range(margin_bottom, region_top, -1):
1403
- copy_line_no = line_no - 1
1404
- try:
1405
- src = buffer.lines[copy_line_no + gutter_lines]
1406
- except IndexError:
1407
- self.update_line(buffer, line_no + gutter_lines, EMPTY_CONTENT, NULL_STYLE)
1408
- else:
1409
- self.update_line(buffer, line_no + gutter_lines, src.content, src.style)
1410
- self.update_line(buffer, region_top + gutter_lines, EMPTY_CONTENT, NULL_STYLE)
1411
-
1412
- if delete_lines:
1413
- count = delete_lines
1414
- margin_top, margin_bottom = buffer.scroll_margin.get_line_range(self.height)
1415
- gutter_lines = max(0, buffer.height - self.height)
1416
- if margin_top <= buffer.cursor_line <= margin_bottom:
1417
- region_top = buffer.cursor_line
1418
- for _ in range(count):
1419
- for line_no in range(region_top, margin_bottom):
1420
- copy_line_no = line_no + 1
1421
- try:
1422
- src = buffer.lines[copy_line_no + gutter_lines]
1423
- except IndexError:
1424
- self.update_line(buffer, line_no + gutter_lines, EMPTY_CONTENT, NULL_STYLE)
1425
- else:
1426
- self.update_line(buffer, line_no + gutter_lines, src.content, src.style)
1427
- self.update_line(buffer, margin_bottom + gutter_lines, EMPTY_CONTENT, NULL_STYLE)
1428
-
1429
- folded_lines = buffer.folded_lines
1430
- while buffer.cursor_line >= len(folded_lines):
1431
- self.add_line(buffer, EMPTY_LINE)
1432
-
1433
- if auto_scroll and delta_y is not None:
1434
- margins = buffer.scroll_margin.get_line_range(self.height)
1435
- margin_top, margin_bottom = margins
1436
-
1437
- screen_cursor_line = buffer.cursor_line - self.screen_start_line_no
1438
-
1439
- if (
1440
- screen_cursor_line >= margin_top
1441
- and screen_cursor_line <= margin_bottom
1442
- ):
1443
- start_line_no = self.screen_start_line_no
1444
-
1445
- scroll_cursor = screen_cursor_line + delta_y
1446
- if scroll_cursor > (start_line_no + margin_bottom):
1447
- self.scroll_buffer(-1, 1)
1448
- return
1449
- elif scroll_cursor < (start_line_no + margin_top):
1450
- self.scroll_buffer(+1, 1)
1451
- return
1452
-
1453
- folded_line = folded_lines[buffer.cursor_line]
1454
- previous_content = folded_line.content
1455
- line = buffer.lines[folded_line.line_no]
1456
- if update_background:
1457
- line.style = self.style
1458
-
1459
- if clear_range is not None:
1460
- cursor_line_offset = self.get_cursor_line_offset(buffer)
1461
-
1462
- line_content = line.content
1463
- if cursor_line_offset > len(line.content):
1464
- line_content = self._expand_content(
1465
- line.content, cursor_line_offset, line.style
1466
- )
1467
-
1468
- # Start and end replace are *inclusive*
1469
- clear_start, clear_end = ansi_command.get_clear_offsets(
1470
- cursor_line_offset, len(line_content)
1471
- )
1472
-
1473
- before_clear = line_content[:clear_start]
1474
- after_clear = line_content[clear_end + 1 :]
1475
-
1476
- if erase:
1477
- # Range is remove
1478
- updated_line = Content.assemble(
1479
- before_clear,
1480
- after_clear,
1481
- strip_control_codes=False,
1482
- )
1483
- self.update_line(buffer, folded_line.line_no, updated_line)
1484
- else:
1485
- # Range is replaced with spaces
1486
- blank_width = clear_end - clear_start + 1
1487
-
1488
- updated_line = Content.assemble(
1489
- before_clear,
1490
- Content.blank(blank_width, self.style),
1491
- after_clear,
1492
- strip_control_codes=False,
1493
- )
1494
- self.update_line(buffer, folded_line.line_no, updated_line)
1495
-
1496
- if not previous_content.is_same(folded_line.content):
1497
- buffer.updates = self.advance_updates()
1498
-
1499
- if delta_x is not None:
1500
- buffer.cursor_offset = clamp(
1501
- buffer.cursor_offset + delta_x, 0, self.width - 1
1502
- )
1503
- buffer.update_line(buffer.cursor_line)
1504
- if absolute_x is not None:
1505
- buffer.cursor_offset = clamp(absolute_x, 0, self.width - 1)
1506
- buffer.update_line(buffer.cursor_line)
1507
-
1508
- current_cursor_line = buffer.cursor_line
1509
- if delta_y is not None:
1510
- buffer.update_line(buffer.cursor_line)
1511
- buffer.cursor_line = max(
1512
- self.screen_start_line_no, buffer.cursor_line + delta_y
1513
- )
1514
- buffer.update_line(buffer.cursor_line)
1515
- if absolute_y is not None:
1516
- buffer.update_line(buffer.cursor_line)
1517
- if buffer.name == "scrollback":
1518
- buffer.cursor_line = self.screen_start_line_no + max(
1519
- 0, absolute_y
1520
- )
1521
- else:
1522
- buffer.cursor_line = max(0, absolute_y)
1523
- buffer.update_line(buffer.cursor_line)
1524
-
1525
- if current_cursor_line != buffer.cursor_line:
1526
- # Simplify when the cursor moves away from the current line
1527
- line.content.simplify() # Reduce segments
1528
- self._line_updated(buffer, current_cursor_line)
1529
- self._line_updated(buffer, buffer.cursor_line)
1530
-
1531
- case ANSIFeatures() as features:
1532
- if features.show_cursor is not None:
1533
- self.show_cursor = features.show_cursor
1534
- if features.alternate_screen is not None:
1535
- self.alternate_screen = features.alternate_screen
1536
- if features.bracketed_paste is not None:
1537
- self.bracketed_paste = features.bracketed_paste
1538
- if features.cursor_blink is not None:
1539
- self.cursor_blink = features.cursor_blink
1540
- if features.cursor_keys is not None:
1541
- self.cursor_keys = features.cursor_keys
1542
- if features.replace_mode is not None:
1543
- self.replace_mode = features.replace_mode
1544
- if features.auto_wrap is not None:
1545
- self.auto_wrap = features.auto_wrap
1546
- self.advance_updates()
1547
-
1548
- case ANSIClear(clear):
1549
- self.clear_buffer(clear)
1550
-
1551
- case ANSIScrollMargin(top, bottom):
1552
- self.buffer.scroll_margin = ScrollMargin(top, bottom)
1553
- # Setting the scroll margins moves the cursor to (1, 1)
1554
- buffer = self.buffer
1555
- self._line_updated(buffer, buffer.cursor_line)
1556
- buffer.cursor_line = 0
1557
- buffer.cursor_offset = 0
1558
- self._line_updated(buffer, buffer.cursor_line)
1559
-
1560
- case ANSIScroll(direction, lines):
1561
- self.scroll_buffer(direction, lines)
1562
-
1563
- case ANSICharacterSet(dec, dec_invoke):
1564
- self.dec_state.update(dec, dec_invoke)
1565
-
1566
- case ANSIWorkingDirectory(path):
1567
- self.current_directory = path
1568
-
1569
- case ANSIMouseTracking(tracking, format, focus_events, alternate_scroll):
1570
- if tracking == "none":
1571
- self.mouse_tracking = None
1572
- return
1573
- if (mouse_tracking := self.mouse_tracking) is None:
1574
- mouse_tracking = self.mouse_tracking = MouseTracking()
1575
- if tracking is not None:
1576
- mouse_tracking.tracking = tracking
1577
- if format is not None:
1578
- mouse_tracking.format = format
1579
- if focus_events is not None:
1580
- mouse_tracking.focus_events = focus_events
1581
- if alternate_scroll is not None:
1582
- mouse_tracking.alternate_scroll = alternate_scroll
1583
-
1584
- case ANSICursorPositionRequest():
1585
- row = self.buffer.cursor_line + 1
1586
- column = self.buffer.cursor_offset + 1
1587
- await self.write_stdin(f"\x1b[{row};{column}R")
1588
-
1589
- case _:
1590
- pass
1591
-
1592
- def _line_updated(self, buffer: Buffer, line_no: int) -> None:
1593
- """Mark a line has having been udpated.
1594
-
1595
- Args:
1596
- buffer: Buffer to use.
1597
- line_no: Line number to mark as updated.
1598
- """
1599
- try:
1600
- buffer.lines[line_no].updates = self.advance_updates()
1601
- if buffer._updated_lines is not None:
1602
- buffer._updated_lines.add(line_no)
1603
- except IndexError:
1604
- pass
1605
-
1606
- def _fold_line(self, line_no: int, line: Content, width: int) -> list[LineFold]:
1607
- updates = self._updates
1608
- if not self.auto_wrap:
1609
- return [LineFold(line_no, 0, 0, line, updates)]
1610
- if not width:
1611
- return [LineFold(0, 0, 0, line, updates)]
1612
- line_length = line.cell_length
1613
- if line_length <= width:
1614
- return [LineFold(line_no, 0, 0, line, updates)]
1615
-
1616
- folded_lines = line.fold(width)
1617
- offsets = [0, *accumulate(len(line) for line in folded_lines)][:-1]
1618
- folds = [
1619
- LineFold(line_no, line_offset, offset, folded_line, updates)
1620
- for line_offset, (offset, folded_line) in enumerate(
1621
- zip(offsets, folded_lines)
1622
- )
1623
- ]
1624
- assert len(folds)
1625
- return folds
1626
-
1627
- def add_line(
1628
- self, buffer: Buffer, content: Content, style: Style = NULL_STYLE
1629
- ) -> None:
1630
- updates = self.advance_updates()
1631
- line_no = buffer.line_count
1632
- width = self.width
1633
- line_record = LineRecord(
1634
- content,
1635
- style,
1636
- self._fold_line(line_no, content, width),
1637
- updates,
1638
- )
1639
- buffer.lines.append(line_record)
1640
- folds = line_record.folds
1641
- buffer.line_to_fold.append(len(buffer.folded_lines))
1642
- fold_count = len(buffer.folded_lines)
1643
- if buffer._updated_lines is not None:
1644
- buffer._updated_lines.update(range(fold_count, fold_count + len(folds)))
1645
- buffer.folded_lines.extend(folds)
1646
- buffer.updates = updates
1647
-
1648
- def update_line(
1649
- self, buffer: Buffer, line_index: int, line: Content, style: Style | None = None
1650
- ) -> None:
1651
- """Update a line (potentially refolding and moving subsequencte lines down).
1652
-
1653
- Args:
1654
- buffer: Buffer.
1655
- line_index: Line index (unfolded).
1656
- line: New line content.
1657
- style: New background style, or `None` not to update.
1658
- """
1659
- while line_index >= len(buffer.lines):
1660
- self.add_line(buffer, EMPTY_LINE)
1661
-
1662
- line_expanded_tabs = line.expand_tabs(8)
1663
- buffer.max_line_width = max(
1664
- line_expanded_tabs.cell_length, buffer.max_line_width
1665
- )
1666
- line_record = buffer.lines[line_index]
1667
- line_record.content = line
1668
- if style is not None:
1669
- line_record.style = style
1670
- line_record.folds[:] = self._fold_line(
1671
- line_index, line_expanded_tabs, self.width
1672
- )
1673
- line_record.updates = self.advance_updates()
1674
-
1675
- if buffer._updated_lines is not None:
1676
- fold_start = buffer.line_to_fold[line_index]
1677
- buffer._updated_lines.update(
1678
- range(fold_start, fold_start + len(line_record.folds))
1679
- )
1680
-
1681
- fold_line = buffer.line_to_fold[line_index]
1682
- del buffer.line_to_fold[line_index:]
1683
- del buffer.folded_lines[fold_line:]
1684
-
1685
- for line_no in range(line_index, buffer.line_count):
1686
- line_record = buffer.lines[line_no]
1687
- buffer.line_to_fold.append(len(buffer.folded_lines))
1688
- for fold in line_record.folds:
1689
- buffer.folded_lines.append(fold)