@scemoon/cdh 1.0.6 → 1.0.7

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 (550) hide show
  1. package/package.json +2 -2
  2. package/ai-dlc-skill/SKILL.md +0 -77
  3. package/ai-dlc-skill/agents/deliver-agent.md +0 -24
  4. package/ai-dlc-skill/agents/master.md +0 -50
  5. package/ai-dlc-skill/agents/plan-agent.md +0 -23
  6. package/ai-dlc-skill/agents/understand-agent.md +0 -23
  7. package/ai-dlc-skill/agents/verify-agent.md +0 -27
  8. package/ai-dlc-skill/architecture/project-structure.md +0 -78
  9. package/ai-dlc-skill/brownfield/README.md +0 -30
  10. package/ai-dlc-skill/brownfield/generate-context.sh +0 -64
  11. package/ai-dlc-skill/brownfield/scripts/deps.sh +0 -27
  12. package/ai-dlc-skill/brownfield/scripts/discover.sh +0 -34
  13. package/ai-dlc-skill/brownfield/scripts/extract-api.sh +0 -45
  14. package/ai-dlc-skill/components/backend.md +0 -34
  15. package/ai-dlc-skill/components/desktop.md +0 -30
  16. package/ai-dlc-skill/components/mya.md +0 -29
  17. package/ai-dlc-skill/components/native.md +0 -30
  18. package/ai-dlc-skill/components/tta.md +0 -29
  19. package/ai-dlc-skill/components/web.md +0 -31
  20. package/ai-dlc-skill/components/wxa.md +0 -29
  21. package/ai-dlc-skill/contracts/README.md +0 -25
  22. package/ai-dlc-skill/core/adaptive-flow.md +0 -36
  23. package/ai-dlc-skill/core/security.md +0 -29
  24. package/ai-dlc-skill/cross-tool/cline/export.sh +0 -31
  25. package/ai-dlc-skill/cross-tool/copilot/export.sh +0 -47
  26. package/ai-dlc-skill/cross-tool/cursor/export.sh +0 -32
  27. package/ai-dlc-skill/cross-tool/export.sh +0 -22
  28. package/ai-dlc-skill/cross-tool/onecode/config.yaml.tpl +0 -17
  29. package/ai-dlc-skill/cross-tool/onecode/export-skills.sh +0 -35
  30. package/ai-dlc-skill/cross-tool/onecode/export.sh +0 -54
  31. package/ai-dlc-skill/phases/deliver/entry.md +0 -26
  32. package/ai-dlc-skill/phases/deliver/lifecycle.md +0 -185
  33. package/ai-dlc-skill/phases/deliver/prompt.md +0 -40
  34. package/ai-dlc-skill/phases/deliver/rules.md +0 -61
  35. package/ai-dlc-skill/phases/plan/entry.md +0 -25
  36. package/ai-dlc-skill/phases/plan/lifecycle.md +0 -204
  37. package/ai-dlc-skill/phases/plan/prompt.md +0 -38
  38. package/ai-dlc-skill/phases/plan/rules.md +0 -25
  39. package/ai-dlc-skill/phases/understand/entry.md +0 -26
  40. package/ai-dlc-skill/phases/understand/lifecycle.md +0 -184
  41. package/ai-dlc-skill/phases/understand/prompt.md +0 -41
  42. package/ai-dlc-skill/phases/understand/rules.md +0 -37
  43. package/ai-dlc-skill/phases/verify/entry.md +0 -26
  44. package/ai-dlc-skill/phases/verify/lifecycle.md +0 -192
  45. package/ai-dlc-skill/phases/verify/prompt.md +0 -43
  46. package/ai-dlc-skill/phases/verify/rules.md +0 -73
  47. package/ai-dlc-skill/practices/bdd.md +0 -91
  48. package/ai-dlc-skill/practices/sdd.md +0 -84
  49. package/ai-dlc-skill/practices/tdd.md +0 -95
  50. package/ai-dlc-skill/providers/README.md +0 -114
  51. package/ai-dlc-skill/providers/aliyun/deployment.yaml +0 -66
  52. package/ai-dlc-skill/providers/aliyun/preview.yaml +0 -84
  53. package/ai-dlc-skill/providers/aliyun/provider.yaml +0 -160
  54. package/ai-dlc-skill/providers/tcb/deployment.yaml +0 -69
  55. package/ai-dlc-skill/providers/tcb/preview.yaml +0 -83
  56. package/ai-dlc-skill/providers/tcb/provider.yaml +0 -172
  57. package/ai-dlc-skill/requirements.md +0 -140
  58. package/ai-dlc-skill/skill.yaml +0 -147
  59. package/ai-dlc-skill/templates/integration/CHANGELOG.md +0 -41
  60. package/ai-dlc-skill/templates/integration/asyncapi.yaml +0 -43
  61. package/ai-dlc-skill/templates/integration/contract-diff.md +0 -63
  62. package/ai-dlc-skill/templates/integration/contract-spec.md +0 -49
  63. package/ai-dlc-skill/templates/integration/openapi.yaml +0 -18
  64. package/ai-dlc-skill/templates/integration/runtime-contract.yaml +0 -36
  65. package/ai-dlc-skill/templates/plan/design.md +0 -49
  66. package/ai-dlc-skill/templates/plan/task-list.md +0 -32
  67. package/ai-dlc-skill/templates/project/README.md +0 -126
  68. package/ai-dlc-skill/templates/project/template.md +0 -119
  69. package/ai-dlc-skill/templates/understand/feature.feature +0 -23
  70. package/ai-dlc-skill/templates/understand/intent.md +0 -29
  71. package/ai-dlc-skill/templates/understand/spec-delta.md +0 -47
  72. package/ai-dlc-skill/templates/verify/test-unit.py +0 -27
  73. package/ai-dlc-skill/walkthrough/collect.sh +0 -50
  74. package/ai-dlc-skill/walkthrough/template.md +0 -54
  75. package/ai-dlc-skill/workflows/ai-dlc.yaml +0 -110
  76. package/ai-dlc-skill/workflows/deployment.yaml +0 -199
  77. package/cdh/__init__.py +0 -0
  78. package/cdh/__main__.py +0 -4
  79. package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
  80. package/cdh/__pycache__/cdh_mcp_injector.cpython-314.pyc +0 -0
  81. package/cdh/__pycache__/cdh_mcp_loader.cpython-314.pyc +0 -0
  82. package/cdh/__pycache__/cdh_mcp_manager.cpython-314.pyc +0 -0
  83. package/cdh/__pycache__/cdh_session_aggregator.cpython-314.pyc +0 -0
  84. package/cdh/__pycache__/cdh_skill_loader.cpython-314.pyc +0 -0
  85. package/cdh/__pycache__/cdh_skill_manager.cpython-314.pyc +0 -0
  86. package/cdh/__pycache__/cli.cpython-313.pyc +0 -0
  87. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  88. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  89. package/cdh/cdh_mcp_injector.py +0 -115
  90. package/cdh/cdh_mcp_loader.py +0 -67
  91. package/cdh/cdh_mcp_manager.py +0 -73
  92. package/cdh/cdh_session_aggregator.py +0 -258
  93. package/cdh/cdh_skill_manager.py +0 -105
  94. package/cdh/cli.py +0 -807
  95. package/cdh/scaffold.py +0 -728
  96. package/onecode/__init__.py +0 -1
  97. package/onecode/__main__.py +0 -4
  98. package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
  99. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  100. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  101. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  102. package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
  103. package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
  104. package/onecode/agent/__init__.py +0 -0
  105. package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
  106. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  107. package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
  108. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  109. package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
  110. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  111. package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
  112. package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
  113. package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
  114. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  115. package/onecode/agent/agents/__init__.py +0 -29
  116. package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
  117. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  118. package/onecode/agent/agents/types.py +0 -589
  119. package/onecode/agent/attachments.py +0 -112
  120. package/onecode/agent/cdh_loader.py +0 -267
  121. package/onecode/agent/context.py +0 -343
  122. package/onecode/agent/engine.py +0 -2700
  123. package/onecode/agent/hooks.py +0 -86
  124. package/onecode/agent/onecode_agent_acp.py +0 -2743
  125. package/onecode/agent/onecode_agent_acp.py.bak +0 -2447
  126. package/onecode/agent/permissions.py +0 -150
  127. package/onecode/agent/permissions_store.py +0 -62
  128. package/onecode/agent/project_doc.py +0 -19
  129. package/onecode/agent/session.py +0 -195
  130. package/onecode/agent/snapshot.py +0 -144
  131. package/onecode/agent/tools/__init__.py +0 -17
  132. package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  133. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  134. package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
  135. package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
  136. package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
  137. package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
  138. package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
  139. package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
  140. package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
  141. package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
  142. package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
  143. package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
  144. package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
  145. package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
  146. package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
  147. package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
  148. package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
  149. package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
  150. package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
  151. package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
  152. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  153. package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
  154. package/onecode/agent/tools/agent_tools.py +0 -132
  155. package/onecode/agent/tools/apply_patch_tool.py +0 -138
  156. package/onecode/agent/tools/bash_tool.py +0 -111
  157. package/onecode/agent/tools/communication_tools.py +0 -148
  158. package/onecode/agent/tools/config_tool.py +0 -130
  159. package/onecode/agent/tools/cron_tools.py +0 -178
  160. package/onecode/agent/tools/errors.py +0 -17
  161. package/onecode/agent/tools/file_ops.py +0 -221
  162. package/onecode/agent/tools/file_tools.py +0 -225
  163. package/onecode/agent/tools/git_tools.py +0 -88
  164. package/onecode/agent/tools/lsp_tools.py +0 -404
  165. package/onecode/agent/tools/mcp_tools.py +0 -127
  166. package/onecode/agent/tools/permission_handler.py +0 -46
  167. package/onecode/agent/tools/permissions.py +0 -77
  168. package/onecode/agent/tools/protocol.py +0 -20
  169. package/onecode/agent/tools/registry.py +0 -201
  170. package/onecode/agent/tools/sandbox.py +0 -358
  171. package/onecode/agent/tools/schema_validation.py +0 -100
  172. package/onecode/agent/tools/skill_tools.py +0 -52
  173. package/onecode/agent/tools/todo_tools.py +0 -207
  174. package/onecode/agent/tools/web_tools.py +0 -169
  175. package/onecode/builtin_skills/agent-browser/SKILL.md +0 -212
  176. package/onecode/builtin_skills/agent-browser/skill.yaml +0 -8
  177. package/onecode/builtin_skills/git/SKILL.md +0 -64
  178. package/onecode/builtin_skills/git/skill.yaml +0 -7
  179. package/onecode/builtin_skills/shell/SKILL.md +0 -58
  180. package/onecode/builtin_skills/shell/skill.yaml +0 -8
  181. package/onecode/builtin_skills/skill-creator/SKILL.md +0 -106
  182. package/onecode/builtin_skills/skill-creator/skill.yaml +0 -8
  183. package/onecode/cli.py +0 -935
  184. package/onecode/cloud/__init__.py +0 -0
  185. package/onecode/cloud/base.py +0 -20
  186. package/onecode/codebase/__init__.py +0 -69
  187. package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
  188. package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
  189. package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
  190. package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
  191. package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
  192. package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
  193. package/onecode/codebase/chunker.py +0 -125
  194. package/onecode/codebase/indexer.py +0 -149
  195. package/onecode/codebase/retriever.py +0 -203
  196. package/onecode/codebase/storage.py +0 -131
  197. package/onecode/codebase/tools.py +0 -59
  198. package/onecode/commands.py +0 -596
  199. package/onecode/config.py +0 -314
  200. package/onecode/config_screen.py +0 -600
  201. package/onecode/cron/__init__.py +0 -3
  202. package/onecode/lsp/__init__.py +0 -3
  203. package/onecode/mcp/__init__.py +0 -4
  204. package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
  205. package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
  206. package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
  207. package/onecode/mcp/client.py +0 -193
  208. package/onecode/mcp/manager.py +0 -190
  209. package/onecode/memory/__init__.py +0 -49
  210. package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
  211. package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
  212. package/onecode/memory/__pycache__/offload.cpython-314.pyc +0 -0
  213. package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
  214. package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
  215. package/onecode/memory/__pycache__/symbolic.cpython-314.pyc +0 -0
  216. package/onecode/memory/backend.py +0 -159
  217. package/onecode/memory/pyramid.py +0 -133
  218. package/onecode/memory/recall.py +0 -203
  219. package/onecode/migrate.py +0 -122
  220. package/onecode/models/__init__.py +0 -4
  221. package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
  222. package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
  223. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  224. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  225. package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
  226. package/onecode/models/errors.py +0 -104
  227. package/onecode/models/messages.py +0 -739
  228. package/onecode/models/provider.py +0 -699
  229. package/onecode/models/providers/__init__.py +0 -17
  230. package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
  231. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  232. package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
  233. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  234. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  235. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  236. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  237. package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
  238. package/onecode/models/providers/anthropic_provider.py +0 -273
  239. package/onecode/models/providers/deepseek_provider.py +0 -212
  240. package/onecode/models/providers/glm_provider.py +0 -195
  241. package/onecode/models/providers/minimax_provider.py +0 -158
  242. package/onecode/models/providers/minimaxi_provider.py +0 -417
  243. package/onecode/models/providers/ollama_provider.py +0 -100
  244. package/onecode/models/providers/openai_provider.py +0 -237
  245. package/onecode/models/registry.py +0 -212
  246. package/onecode/server/__init__.py +0 -3
  247. package/onecode/server/app.py +0 -224
  248. package/onecode/skills/__init__.py +0 -11
  249. package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
  250. package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
  251. package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
  252. package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
  253. package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
  254. package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
  255. package/onecode/skills/__pycache__/manager.cpython-314.pyc +0 -0
  256. package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
  257. package/onecode/skills/argument_substitution.py +0 -38
  258. package/onecode/skills/bootstrap.py +0 -124
  259. package/onecode/skills/create.py +0 -56
  260. package/onecode/skills/frontmatter.py +0 -33
  261. package/onecode/skills/loader.py +0 -139
  262. package/onecode/skills/manager.py +0 -75
  263. package/onecode/skills/model.py +0 -43
  264. package/onecode/storage/__init__.py +0 -0
  265. package/onecode/storage/activity.py +0 -63
  266. package/onecode/storage/project.py +0 -54
  267. package/onecode/storage/session.py +0 -112
  268. package/onecode/tasks/__init__.py +0 -26
  269. package/onecode/tasks/manager.py +0 -232
  270. package/onecode/tasks/models.py +0 -240
  271. package/onecode/trace/__init__.py +0 -0
  272. package/onecode/trace/tracer.py +0 -173
  273. package/onecode/utils/__init__.py +0 -0
  274. package/onecode/utils/helpers.py +0 -20
  275. package/pyproject.toml +0 -74
  276. package/tui/__init__.py +0 -46
  277. package/tui/__main__.py +0 -4
  278. package/tui/__pycache__/__init__.cpython-314.pyc +0 -0
  279. package/tui/__pycache__/_loop.cpython-314.pyc +0 -0
  280. package/tui/__pycache__/_path_fuzzy_search.cpython-314.pyc +0 -0
  281. package/tui/__pycache__/_path_match.cpython-314.pyc +0 -0
  282. package/tui/__pycache__/about.cpython-314.pyc +0 -0
  283. package/tui/__pycache__/agent.cpython-314.pyc +0 -0
  284. package/tui/__pycache__/agent_schema.cpython-314.pyc +0 -0
  285. package/tui/__pycache__/agents.cpython-314.pyc +0 -0
  286. package/tui/__pycache__/answer.cpython-314.pyc +0 -0
  287. package/tui/__pycache__/app.cpython-313.pyc +0 -0
  288. package/tui/__pycache__/app.cpython-314.pyc +0 -0
  289. package/tui/__pycache__/atomic.cpython-314.pyc +0 -0
  290. package/tui/__pycache__/complete.cpython-314.pyc +0 -0
  291. package/tui/__pycache__/constants.cpython-314.pyc +0 -0
  292. package/tui/__pycache__/conversation_markdown.cpython-314.pyc +0 -0
  293. package/tui/__pycache__/danger.cpython-314.pyc +0 -0
  294. package/tui/__pycache__/db.cpython-314.pyc +0 -0
  295. package/tui/__pycache__/dec.cpython-314.pyc +0 -0
  296. package/tui/__pycache__/directory.cpython-314.pyc +0 -0
  297. package/tui/__pycache__/directory_suggester.cpython-314.pyc +0 -0
  298. package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
  299. package/tui/__pycache__/format_path.cpython-314.pyc +0 -0
  300. package/tui/__pycache__/fuzzy.cpython-314.pyc +0 -0
  301. package/tui/__pycache__/fuzzy_index.cpython-314.pyc +0 -0
  302. package/tui/__pycache__/history.cpython-314.pyc +0 -0
  303. package/tui/__pycache__/jsonrpc.cpython-314.pyc +0 -0
  304. package/tui/__pycache__/menus.cpython-314.pyc +0 -0
  305. package/tui/__pycache__/message_log.cpython-314.pyc +0 -0
  306. package/tui/__pycache__/messages.cpython-314.pyc +0 -0
  307. package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
  308. package/tui/__pycache__/path_filter.cpython-314.pyc +0 -0
  309. package/tui/__pycache__/paths.cpython-314.pyc +0 -0
  310. package/tui/__pycache__/pill.cpython-314.pyc +0 -0
  311. package/tui/__pycache__/platform_commands.cpython-314.pyc +0 -0
  312. package/tui/__pycache__/protocol.cpython-314.pyc +0 -0
  313. package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
  314. package/tui/__pycache__/settings.cpython-314.pyc +0 -0
  315. package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
  316. package/tui/__pycache__/shell.cpython-314.pyc +0 -0
  317. package/tui/__pycache__/shell_read.cpython-314.pyc +0 -0
  318. package/tui/__pycache__/slash_command.cpython-314.pyc +0 -0
  319. package/tui/__pycache__/version.cpython-314.pyc +0 -0
  320. package/tui/_loop.py +0 -86
  321. package/tui/_path_fuzzy_search.py +0 -48
  322. package/tui/_path_match.py +0 -141
  323. package/tui/about.py +0 -95
  324. package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
  325. package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
  326. package/tui/acp/__pycache__/encode_tool_call_id.cpython-314.pyc +0 -0
  327. package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
  328. package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
  329. package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
  330. package/tui/acp/agent.py +0 -1002
  331. package/tui/acp/api.py +0 -73
  332. package/tui/acp/encode_tool_call_id.py +0 -12
  333. package/tui/acp/messages.py +0 -203
  334. package/tui/acp/prompt.py +0 -53
  335. package/tui/acp/protocol.py +0 -499
  336. package/tui/agent.py +0 -70
  337. package/tui/agent_schema.py +0 -76
  338. package/tui/agents.py +0 -46
  339. package/tui/ansi/__init__.py +0 -1
  340. package/tui/ansi/__pycache__/__init__.cpython-314.pyc +0 -0
  341. package/tui/ansi/__pycache__/_ansi.cpython-314.pyc +0 -0
  342. package/tui/ansi/__pycache__/_ansi_colors.cpython-314.pyc +0 -0
  343. package/tui/ansi/__pycache__/_control_codes.cpython-314.pyc +0 -0
  344. package/tui/ansi/__pycache__/_keys.cpython-314.pyc +0 -0
  345. package/tui/ansi/__pycache__/_sgr_styles.cpython-314.pyc +0 -0
  346. package/tui/ansi/__pycache__/_stream_parser.cpython-314.pyc +0 -0
  347. package/tui/ansi/_ansi.py +0 -1689
  348. package/tui/ansi/_ansi_colors.py +0 -264
  349. package/tui/ansi/_control_codes.py +0 -37
  350. package/tui/ansi/_keys.py +0 -251
  351. package/tui/ansi/_sgr_styles.py +0 -64
  352. package/tui/ansi/_stream_parser.py +0 -418
  353. package/tui/answer.py +0 -12
  354. package/tui/app.py +0 -1266
  355. package/tui/atomic.py +0 -37
  356. package/tui/cli.py +0 -313
  357. package/tui/code_analyze.py +0 -27
  358. package/tui/complete.py +0 -38
  359. package/tui/constants.py +0 -61
  360. package/tui/conversation_markdown.py +0 -30
  361. package/tui/danger.py +0 -372
  362. package/tui/data/agents/ampcode.com.toml +0 -52
  363. package/tui/data/agents/augmentcode.com.toml +0 -41
  364. package/tui/data/agents/cdh.cloud-dev-harness.toml +0 -23
  365. package/tui/data/agents/claude.com.toml +0 -41
  366. package/tui/data/agents/copilot.github.com.toml +0 -29
  367. package/tui/data/agents/crowai.dev.toml +0 -36
  368. package/tui/data/agents/cursor.com.toml +0 -38
  369. package/tui/data/agents/deepagents.langchain.com +0 -34
  370. package/tui/data/agents/docker.com.toml +0 -60
  371. package/tui/data/agents/geminicli.com.toml +0 -28
  372. package/tui/data/agents/goose.ai.toml +0 -52
  373. package/tui/data/agents/inference.huggingface.co.toml +0 -41
  374. package/tui/data/agents/kimi.com.toml +0 -35
  375. package/tui/data/agents/kiro.dev.toml +0 -43
  376. package/tui/data/agents/onecode.dev.toml +0 -22
  377. package/tui/data/agents/openai.com.toml +0 -53
  378. package/tui/data/agents/openclaw.ai.toml +0 -37
  379. package/tui/data/agents/opencode.ai.toml +0 -39
  380. package/tui/data/agents/openhands.dev.toml +0 -46
  381. package/tui/data/agents/stakpak.dev.toml +0 -62
  382. package/tui/data/agents/vibe.mistral.ai.toml +0 -31
  383. package/tui/data/agents/vtcode.dev.toml +0 -63
  384. package/tui/data/images/frog.png +0 -0
  385. package/tui/data/sounds/question.wav +0 -0
  386. package/tui/data/sounds/turn-over.wav +0 -0
  387. package/tui/db.py +0 -213
  388. package/tui/dec.py +0 -332
  389. package/tui/directory.py +0 -234
  390. package/tui/directory_suggester.py +0 -93
  391. package/tui/directory_watcher.py +0 -231
  392. package/tui/format_path.py +0 -25
  393. package/tui/fuzzy.py +0 -140
  394. package/tui/fuzzy_index.py +0 -275
  395. package/tui/gist.py +0 -33
  396. package/tui/history.py +0 -138
  397. package/tui/jsonrpc.py +0 -578
  398. package/tui/menus.py +0 -14
  399. package/tui/message_log.py +0 -69
  400. package/tui/messages.py +0 -144
  401. package/tui/option_content.py +0 -51
  402. package/tui/os.py +0 -0
  403. package/tui/path_complete.py +0 -217
  404. package/tui/path_filter.py +0 -124
  405. package/tui/paths.py +0 -87
  406. package/tui/pill.py +0 -23
  407. package/tui/platform_commands.py +0 -52
  408. package/tui/prompt/__pycache__/extract.cpython-314.pyc +0 -0
  409. package/tui/prompt/__pycache__/resource.cpython-314.pyc +0 -0
  410. package/tui/prompt/extract.py +0 -19
  411. package/tui/prompt/resource.py +0 -68
  412. package/tui/protocol.py +0 -28
  413. package/tui/screens/__init__.py +0 -0
  414. package/tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
  415. package/tui/screens/__pycache__/agent_modal.cpython-314.pyc +0 -0
  416. package/tui/screens/__pycache__/component_picker.cpython-314.pyc +0 -0
  417. package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
  418. package/tui/screens/__pycache__/log.cpython-314.pyc +0 -0
  419. package/tui/screens/__pycache__/main.cpython-313.pyc +0 -0
  420. package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
  421. package/tui/screens/__pycache__/permissions.cpython-314.pyc +0 -0
  422. package/tui/screens/__pycache__/projects_app.cpython-314.pyc +0 -0
  423. package/tui/screens/__pycache__/projects_screen.cpython-314.pyc +0 -0
  424. package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
  425. package/tui/screens/__pycache__/store.cpython-314.pyc +0 -0
  426. package/tui/screens/__pycache__/tool_content_screen.cpython-314.pyc +0 -0
  427. package/tui/screens/action_modal.py +0 -94
  428. package/tui/screens/agent_modal.py +0 -175
  429. package/tui/screens/command_edit_modal.py +0 -74
  430. package/tui/screens/component_picker.py +0 -168
  431. package/tui/screens/diff_screen.py +0 -84
  432. package/tui/screens/log.py +0 -553
  433. package/tui/screens/main.py +0 -385
  434. package/tui/screens/main.tcss +0 -655
  435. package/tui/screens/permissions.py +0 -404
  436. package/tui/screens/permissions.tcss +0 -72
  437. package/tui/screens/projects.tcss +0 -80
  438. package/tui/screens/projects_app.py +0 -347
  439. package/tui/screens/projects_screen.py +0 -284
  440. package/tui/screens/session_resume_modal.py +0 -172
  441. package/tui/screens/session_resume_modal.tcss +0 -35
  442. package/tui/screens/sessions.py +0 -164
  443. package/tui/screens/sessions.tcss +0 -119
  444. package/tui/screens/settings.py +0 -254
  445. package/tui/screens/settings.tcss +0 -101
  446. package/tui/screens/store.py +0 -500
  447. package/tui/screens/store.tcss +0 -274
  448. package/tui/screens/tool_content_screen.py +0 -59
  449. package/tui/session_tracker.py +0 -123
  450. package/tui/settings.py +0 -353
  451. package/tui/settings_schema.py +0 -431
  452. package/tui/shell.py +0 -304
  453. package/tui/shell_read.py +0 -42
  454. package/tui/slash_command.py +0 -34
  455. package/tui/tui.tcss +0 -246
  456. package/tui/twitter.py +0 -38
  457. package/tui/version.py +0 -80
  458. package/tui/visuals/__init__.py +0 -0
  459. package/tui/visuals/__pycache__/__init__.cpython-314.pyc +0 -0
  460. package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
  461. package/tui/visuals/columns.py +0 -272
  462. package/tui/widgets/__init__.py +0 -0
  463. package/tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
  464. package/tui/widgets/__pycache__/acp_content.cpython-314.pyc +0 -0
  465. package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
  466. package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
  467. package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
  468. package/tui/widgets/__pycache__/condensed_path.cpython-314.pyc +0 -0
  469. package/tui/widgets/__pycache__/context_stats.cpython-314.pyc +0 -0
  470. package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
  471. package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
  472. package/tui/widgets/__pycache__/directory_input.cpython-314.pyc +0 -0
  473. package/tui/widgets/__pycache__/flash.cpython-314.pyc +0 -0
  474. package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
  475. package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
  476. package/tui/widgets/__pycache__/highlighted_textarea.cpython-314.pyc +0 -0
  477. package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
  478. package/tui/widgets/__pycache__/mandelbrot.cpython-314.pyc +0 -0
  479. package/tui/widgets/__pycache__/markdown_note.cpython-314.pyc +0 -0
  480. package/tui/widgets/__pycache__/menu.cpython-314.pyc +0 -0
  481. package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
  482. package/tui/widgets/__pycache__/non_selectable_label.cpython-314.pyc +0 -0
  483. package/tui/widgets/__pycache__/note.cpython-314.pyc +0 -0
  484. package/tui/widgets/__pycache__/path_search.cpython-314.pyc +0 -0
  485. package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
  486. package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
  487. package/tui/widgets/__pycache__/project_grid_select.cpython-314.pyc +0 -0
  488. package/tui/widgets/__pycache__/project_summary.cpython-314.pyc +0 -0
  489. package/tui/widgets/__pycache__/prompt.cpython-314.pyc +0 -0
  490. package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
  491. package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
  492. package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
  493. package/tui/widgets/__pycache__/session_tabs.cpython-314.pyc +0 -0
  494. package/tui/widgets/__pycache__/shell_result.cpython-314.pyc +0 -0
  495. package/tui/widgets/__pycache__/shell_terminal.cpython-314.pyc +0 -0
  496. package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
  497. package/tui/widgets/__pycache__/slash_complete.cpython-314.pyc +0 -0
  498. package/tui/widgets/__pycache__/strike_text.cpython-314.pyc +0 -0
  499. package/tui/widgets/__pycache__/subagent.cpython-314.pyc +0 -0
  500. package/tui/widgets/__pycache__/subagent_screen.cpython-314.pyc +0 -0
  501. package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
  502. package/tui/widgets/__pycache__/throbber.cpython-314.pyc +0 -0
  503. package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
  504. package/tui/widgets/__pycache__/user_input.cpython-314.pyc +0 -0
  505. package/tui/widgets/acp_content.py +0 -70
  506. package/tui/widgets/agent_response.py +0 -76
  507. package/tui/widgets/agent_thought.py +0 -167
  508. package/tui/widgets/ask_user.py +0 -264
  509. package/tui/widgets/command_pane.py +0 -223
  510. package/tui/widgets/condensed_path.py +0 -115
  511. package/tui/widgets/context_stats.py +0 -66
  512. package/tui/widgets/conversation.py +0 -2641
  513. package/tui/widgets/danger_warning.py +0 -65
  514. package/tui/widgets/diff_view.py +0 -69
  515. package/tui/widgets/directory_input.py +0 -8
  516. package/tui/widgets/flash.py +0 -81
  517. package/tui/widgets/future_text.py +0 -126
  518. package/tui/widgets/grid_select.py +0 -234
  519. package/tui/widgets/highlighted_textarea.py +0 -180
  520. package/tui/widgets/load_more.py +0 -24
  521. package/tui/widgets/mandelbrot.py +0 -294
  522. package/tui/widgets/markdown_note.py +0 -13
  523. package/tui/widgets/menu.py +0 -147
  524. package/tui/widgets/modified_files.py +0 -306
  525. package/tui/widgets/non_selectable_label.py +0 -5
  526. package/tui/widgets/note.py +0 -18
  527. package/tui/widgets/path_search.py +0 -492
  528. package/tui/widgets/plan.py +0 -285
  529. package/tui/widgets/project_directory_tree.py +0 -102
  530. package/tui/widgets/project_grid_select.py +0 -64
  531. package/tui/widgets/project_summary.py +0 -33
  532. package/tui/widgets/prompt.py +0 -795
  533. package/tui/widgets/question.py +0 -360
  534. package/tui/widgets/session_grid_select.py +0 -230
  535. package/tui/widgets/session_summary.py +0 -115
  536. package/tui/widgets/session_tabs.py +0 -188
  537. package/tui/widgets/shell_result.py +0 -35
  538. package/tui/widgets/shell_terminal.py +0 -40
  539. package/tui/widgets/side_bar.py +0 -124
  540. package/tui/widgets/slash_complete.py +0 -235
  541. package/tui/widgets/strike_text.py +0 -70
  542. package/tui/widgets/subagent.py +0 -287
  543. package/tui/widgets/subagent_screen.py +0 -709
  544. package/tui/widgets/terminal.py +0 -576
  545. package/tui/widgets/terminal_tool.py +0 -360
  546. package/tui/widgets/throbber.py +0 -100
  547. package/tui/widgets/tool_call.py +0 -398
  548. package/tui/widgets/user_input.py +0 -23
  549. package/tui/widgets/version.py +0 -5
  550. package/tui/widgets/welcome.py +0 -31
@@ -1,795 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
- import shlex
5
- from typing import TYPE_CHECKING, Callable, Literal, Self
6
-
7
- from textual import on
8
- from textual.reactive import var, Initialize
9
- from textual.app import ComposeResult
10
-
11
- from textual.actions import SkipAction
12
- from textual.binding import Binding
13
-
14
- from textual.content import Content
15
- from textual import getters
16
- from textual.message import Message
17
- from textual.widgets import OptionList, TextArea, Label
18
- from textual import containers
19
- from textual.widget import Widget
20
- from textual.widgets.option_list import Option
21
- from textual.widgets.text_area import Selection
22
- from textual import events
23
-
24
- from tui.app import A2TUIApp
25
- from tui import messages
26
- from tui.widgets.highlighted_textarea import HighlightedTextArea
27
- from tui.widgets.condensed_path import CondensedPath
28
- from tui.widgets.path_search import PathSearch
29
- from tui.widgets.plan import Plan
30
- from tui.answer import Answer
31
- from tui.widgets.question import Ask, Question
32
- from tui.widgets.slash_complete import SlashComplete
33
- from tui.messages import UserInputSubmitted
34
- from tui.slash_command import SlashCommand
35
- from tui.prompt.extract import extract_paths_from_prompt
36
- from tui.path_complete import PathComplete
37
-
38
- if TYPE_CHECKING:
39
- from tui.acp.agent import Mode
40
-
41
-
42
- class ModeSwitcher(OptionList):
43
- BINDING_GROUP_TITLE = "Mode switcher"
44
- BINDINGS = [Binding("escape", "dismiss", "Dismiss mode switcher")]
45
-
46
- @on(OptionList.OptionSelected)
47
- def on_option_selected(self, event: OptionList.OptionSelected):
48
- self.post_message(messages.ChangeMode(event.option_id))
49
- self.blur()
50
-
51
- def action_dismiss(self):
52
- self.blur()
53
-
54
-
55
- class InvokeFileSearch(Message):
56
- pass
57
-
58
-
59
- class InvokeSlashComplete(Message):
60
- pass
61
-
62
-
63
- class AgentInfo(Label):
64
- pass
65
-
66
-
67
- class ModeInfo(Label):
68
- pass
69
-
70
-
71
- class StatusLine(Label):
72
- status: var[str] = var("")
73
-
74
- def watch_status(self, status: str) -> None:
75
- self.set_class(not bool(status), "-hidden")
76
- self.update(status)
77
- self.tooltip = status
78
-
79
-
80
- class PromptContainer(containers.HorizontalGroup):
81
- def on_mouse_down(self, event: events.MouseUp) -> None:
82
- for child in self.query("*"):
83
- if child.has_focus:
84
- return
85
- prompt_text_area = self.query_one(PromptTextArea)
86
- if not prompt_text_area.has_focus:
87
- prompt_text_area.focus()
88
-
89
-
90
- class PromptTextArea(HighlightedTextArea):
91
- HELP = """\
92
- ## Prompt
93
-
94
- Talk to your agent in natural language.
95
- See on-screen instructions for details.
96
-
97
- - Be simple
98
- - Be direct
99
- - Nothing fancy
100
- """
101
-
102
- BINDING_GROUP_TITLE = "Prompt"
103
-
104
- BINDINGS = [
105
- Binding(
106
- "enter",
107
- "submit",
108
- "Send",
109
- key_display="⏎",
110
- priority=True,
111
- tooltip="Send the prompt to the agent",
112
- ),
113
- Binding(
114
- "ctrl+j,shift+enter",
115
- "newline",
116
- "Line",
117
- key_display="⇧+⏎",
118
- tooltip="Insert a new line character",
119
- ),
120
- Binding(
121
- "ctrl+j,shift+enter",
122
- "multiline_submit",
123
- "Send",
124
- key_display="⇧+⏎",
125
- tooltip="Send the prompt to the agent",
126
- ),
127
- Binding(
128
- "tab",
129
- "tab_complete",
130
- "Complete",
131
- tooltip="Complete path (if possible)",
132
- priority=True,
133
- show=False,
134
- ),
135
- ]
136
-
137
- app = getters.app(A2TUIApp)
138
-
139
- auto_completes: var[list[Option]] = var(list)
140
- multi_line = var(False, bindings=True)
141
- shell_mode = var(False, bindings=True)
142
- agent_ready: var[bool] = var(False)
143
- path_complete: var[PathComplete] = var(Initialize(lambda obj: PathComplete()))
144
- suggestions: var[list[str] | None] = var(None)
145
- suggestions_index: var[int] = var(0)
146
-
147
- project_path = var(Path())
148
- working_directory = var("")
149
-
150
- slash_commands: var[list[SlashCommand]] = var([])
151
- slash_command_prefixes: var[tuple[str, ...]] = var(())
152
-
153
- class Submitted(Message):
154
- def __init__(self, markdown: str) -> None:
155
- self.markdown = markdown
156
- super().__init__()
157
-
158
- class RequestShellMode(Message):
159
- pass
160
-
161
- class CancelShell(Message):
162
- pass
163
-
164
- def watch_slash_commands(self, slash_commands: list[SlashCommand]) -> None:
165
- """A tuple of slash commands for performance reasons (used with `str.startswith`)."""
166
- self.slash_command_prefixes = tuple(
167
- [slash_command.command for slash_command in slash_commands]
168
- )
169
-
170
- def highlight_slash_command(self, text: str) -> Content:
171
- """Override slash command highlighting."""
172
-
173
- if text.startswith(self.slash_command_prefixes):
174
- content = Content(text)
175
- for slash_command in self.slash_commands:
176
- if text.startswith(slash_command.command + " "):
177
- content = content.stylize(
178
- "$text-success", 0, len(slash_command.command)
179
- )
180
- if (
181
- slash_command.hint
182
- and len(text) - (len(slash_command.command) + 1) == 0
183
- ):
184
- content += Content.styled(
185
- slash_command.hint, "$text-secondary 70%"
186
- )
187
- break
188
- return content
189
- return Content(text)
190
-
191
- def highlight_shell(self, text: str) -> Content:
192
- """Override shell highlighting with additional danger detection."""
193
- content = super().highlight_shell(text)
194
-
195
- if not self.app.settings.get("shell.warn_dangerous", bool):
196
- return content
197
-
198
- from tui import danger
199
-
200
- spans, _danger_level = danger.detect(
201
- str(self.project_path), self.working_directory, content.plain
202
- )
203
- content = content.add_spans(spans)
204
- return content
205
-
206
- def on_mount(self) -> None:
207
- self.highlight_cursor_line = False
208
- self.hide_suggestion_on_blur = False
209
-
210
- def on_key(self, event: events.Key) -> None:
211
- if (
212
- not self.shell_mode
213
- and self.cursor_location == (0, 0)
214
- and event.character in {"!", "$"}
215
- ):
216
- self.post_message(self.RequestShellMode())
217
- event.prevent_default()
218
- elif self.shell_mode and event.key == "tab":
219
- event.prevent_default()
220
- elif event.key != "escape":
221
- self.suggestions = None
222
- self.suggestion = ""
223
-
224
- def update_suggestion(self) -> None:
225
- prompt = self.query_ancestor(Prompt)
226
-
227
- if self.selection.start == self.selection.end and self.text.startswith("/"):
228
- return
229
-
230
- if self.shell_mode and self.cursor_at_end_of_text and "\n" not in self.text:
231
- if prompt.complete_callback is not None:
232
- if completes := prompt.complete_callback(self.text):
233
- if self.text not in completes:
234
- self.suggestion = completes[-1]
235
-
236
- def check_action(self, action: str, parameters: tuple[object, ...]) -> bool | None:
237
- if action == "newline" and self.multi_line:
238
- return False
239
- if action == "submit" and self.multi_line:
240
- return False
241
- if action == "multiline_submit":
242
- return self.multi_line
243
- return True
244
-
245
- def action_multiline_submit(self) -> None:
246
- if not self.agent_ready:
247
- self.app.bell()
248
- self.post_message(
249
- messages.Flash(
250
- "Agent is not ready. Please wait while the agent connects…",
251
- "error",
252
- )
253
- )
254
- return
255
- self.post_message(UserInputSubmitted(self.text, self.shell_mode))
256
- self.clear()
257
-
258
- def action_newline(self) -> None:
259
- self.insert("\n")
260
-
261
- def action_submit(self) -> None:
262
- if not self.agent_ready and not self.shell_mode:
263
- self.app.bell()
264
- self.post_message(
265
- messages.Flash(
266
- "Agent is not ready. Please wait while the agent connects…",
267
- "error",
268
- )
269
- )
270
- return
271
- if self.suggestion:
272
- if " " not in self.text:
273
- self.insert(self.suggestion + " ")
274
- else:
275
- prompt = self.query_ancestor(Prompt)
276
- last_token = shlex.split(self.text + self.suggestion)[-1]
277
- last_token_path = Path(prompt.working_directory) / last_token
278
- if last_token_path.is_dir():
279
- self.insert(self.suggestion)
280
- else:
281
- self.insert(self.suggestion + " ")
282
- self.suggestion = ""
283
- return
284
- self.post_message(UserInputSubmitted(self.text, self.shell_mode))
285
- self.clear()
286
-
287
- def action_cursor_up(self, select: bool = False):
288
- if self.selection.is_empty and not select:
289
- row, _column = self.selection[0]
290
- if row == 0:
291
- self.post_message(messages.HistoryMove(-1, self.shell_mode, self.text))
292
- return
293
- super().action_cursor_up(select)
294
-
295
- def action_cursor_down(self, select: bool = False):
296
- if self.selection.is_empty and not select:
297
- row, _column = self.selection[0]
298
- if row == (self.wrapped_document.height - 1):
299
- self.post_message(messages.HistoryMove(+1, self.shell_mode, self.text))
300
- return
301
- super().action_cursor_down(select)
302
-
303
- def action_delete_left(self) -> None:
304
- selection = self.selection
305
- if selection.start == selection.end and self.selection.end == (0, 0):
306
- self.post_message(self.CancelShell())
307
- return
308
- return super().action_delete_left()
309
-
310
- def action_cursor_line_end(self, select: bool = False) -> None:
311
- """Move the cursor to the end of the line."""
312
- if not self._has_cursor:
313
- self.scroll_end()
314
- return
315
- location = self.get_cursor_line_end_location()
316
- if location == self.cursor_location:
317
- # If the cursor is already at the end, then we assume the user wants to
318
- # scroll the conversation to the end
319
- from tui.widgets.conversation import Conversation
320
-
321
- self.query_ancestor(Conversation).window.anchor()
322
- else:
323
- self.move_cursor(location, select=select)
324
-
325
- async def action_tab_complete(self) -> None:
326
- if not self.shell_mode:
327
- return
328
-
329
- import shlex
330
-
331
- prompt = self.query_ancestor(Prompt)
332
-
333
- if not self.cursor_at_end_of_text:
334
- return
335
-
336
- _cursor_row, cursor_column = prompt.prompt_text_area.selection.end
337
- pre_complete = self.text[:cursor_column]
338
- post_complete = self.text[cursor_column:]
339
- shlex_tokens = shlex.split(pre_complete)
340
- if not shlex_tokens:
341
- return
342
-
343
- command = shlex_tokens[0]
344
-
345
- exclude_node_type: Literal["file"] | Literal["dir"] | None = None
346
- if (
347
- command
348
- in self.app.settings.get("shell.directory_commands", str).splitlines()
349
- ):
350
- exclude_node_type = "file"
351
- elif command in self.app.settings.get("shell.file_commands", str).splitlines():
352
- exclude_node_type = "dir"
353
-
354
- tab_complete, suggestions = await self.path_complete(
355
- Path(prompt.working_directory),
356
- shlex_tokens[-1],
357
- exclude_type=exclude_node_type,
358
- )
359
-
360
- if tab_complete is not None:
361
- shlex_tokens = shlex_tokens[:-1] + [shlex_tokens[-1] + tab_complete]
362
- path_component = Path(prompt.working_directory) / shlex_tokens[-1]
363
- if path_component.is_file():
364
- spaces = " "
365
- else:
366
- spaces = ""
367
-
368
- self.clear()
369
- self.insert(
370
- " ".join(token.replace(" ", "\\ ") for token in shlex_tokens)
371
- + post_complete
372
- + spaces
373
- )
374
- self.suggestions = None
375
- else:
376
- if suggestions != self.suggestions:
377
- self.suggestions = suggestions or None
378
- self.suggestions_index = 0
379
- if suggestions:
380
- self.suggestion = suggestions[0]
381
- elif self.suggestions:
382
- self.suggestions_index = (self.suggestions_index + 1) % len(
383
- self.suggestions
384
- )
385
- self.suggestion = self.suggestions[self.suggestions_index]
386
-
387
- async def watch_selection(
388
- self, previous_selection: Selection, selection: Selection
389
- ) -> None:
390
- if previous_selection == selection:
391
- return
392
- if selection.start == selection.end:
393
- previous_y, previous_x = previous_selection.end
394
- y, x = selection.end
395
- if y == previous_y:
396
- direction = -1 if x < previous_x else +1
397
- else:
398
- direction = 0
399
- line = self.document.get_line(y)
400
-
401
- if (
402
- not self.shell_mode
403
- and y == 0
404
- and x == 1
405
- and direction == +1
406
- and line
407
- and line[0] == "/"
408
- ):
409
- self.post_message(InvokeSlashComplete())
410
- return
411
-
412
- if y == 0 and line and line[0] == "/" and direction == -1:
413
- if line in self.slash_command_prefixes:
414
- self.selection = Selection((0, 0), (0, len(line)))
415
- return
416
-
417
- for _path, start, end in extract_paths_from_prompt(line):
418
- if x > start and x < end:
419
- self.selection = Selection((y, start), (y, end))
420
- break
421
- if direction == -1 and x == end:
422
- self.selection = Selection((y, start), (y, end))
423
- break
424
-
425
- if x > 0 and x <= len(line) and line[x - 1] == "@":
426
- remaining_line = line[x + 1 :]
427
- if not remaining_line or remaining_line[0].isspace():
428
- self.post_message(InvokeFileSearch())
429
-
430
-
431
- class Prompt(containers.VerticalGroup):
432
-
433
- BINDINGS = [
434
- Binding("escape", "dismiss", "Dismiss", show=False),
435
- ]
436
-
437
- PROMPT_NULL = " "
438
- PROMPT_SHELL = Content.styled("$", "$text-primary")
439
- PROMPT_AI = Content.styled("❯", "$text-secondary")
440
- PROMPT_MULTILINE = Content.styled("☰", "$text-secondary")
441
-
442
- prompt_container = getters.query_one("#prompt-container", Widget)
443
- prompt_text_area = getters.query_one(PromptTextArea)
444
- prompt_label = getters.query_one("#prompt", Label)
445
- current_directory = getters.query_one(CondensedPath)
446
- path_search = getters.query_one(PathSearch)
447
- slash_complete = getters.query_one(SlashComplete)
448
- question = getters.query_one(Question)
449
- mode_switcher = getters.query_one(ModeSwitcher)
450
-
451
- slash_commands: var[list[SlashCommand]] = var(list)
452
- shell_mode = var(False)
453
- multi_line = var(False)
454
- show_path_search = var(False, toggle_class="-show-path-search", bindings=True)
455
- show_slash_complete = var(False, toggle_class="-show-slash-complete", bindings=True)
456
- project_path = var(Path, init=False)
457
- working_directory = var("")
458
- agent_info = var(Content(""))
459
- _ask: var[Ask | None] = var(None)
460
- plan: var[list[Plan.Entry]]
461
- agent_ready: var[bool] = var(False)
462
- current_mode: var[Mode | None] = var(None)
463
- modes: var[dict[str, Mode] | None] = var(None)
464
- status: var[str] = var("")
465
-
466
- app = getters.app(A2TUIApp)
467
-
468
- def __init__(
469
- self,
470
- *,
471
- name: str | None = None,
472
- id: str | None = None,
473
- classes: str | None = None,
474
- disabled: bool = False,
475
- complete_callback: Callable[[str], list[str]] | None = None,
476
- ):
477
- super().__init__(name=name, id=id, classes=classes, disabled=disabled)
478
- self.ask_queue: list[Ask] = []
479
- self.complete_callback = complete_callback
480
-
481
- @property
482
- def text(self) -> str:
483
- return self.prompt_text_area.text
484
-
485
- @text.setter
486
- def text(self, text: str) -> None:
487
- self.prompt_text_area.text = text
488
- self.prompt_text_area.selection = Selection.cursor(
489
- self.prompt_text_area.get_cursor_line_end_location()
490
- )
491
-
492
- def watch_current_mode(self, mode: Mode | None) -> None:
493
- self.set_class(mode is not None, "-has-mode")
494
- if mode is not None:
495
- tooltip = Content.from_markup(
496
- "[b]$description[/]\n\n[dim](click to open mode switcher)",
497
- description=mode.description,
498
- )
499
- self.query_one(ModeInfo).with_tooltip(tooltip).update(mode.name)
500
- self.watch_modes(self.modes)
501
-
502
- async def watch_project_path(self, old_path: Path, new_path: Path) -> None:
503
- """Initial refresh of paths."""
504
- if old_path != new_path:
505
- self.call_later(self.path_search.refresh_paths)
506
-
507
- def ask(self, ask: Ask) -> None:
508
- """Replace the textarea prompt with a menu of options.
509
-
510
- Args:
511
- ask: An `Ask` instance which contains a question and responses.
512
- """
513
- self.ask_queue.append(ask)
514
- self.app.terminal_alert()
515
- if self._ask is None:
516
- self._ask = self.ask_queue.pop(0)
517
-
518
- @on(events.Click, "ModeInfo")
519
- def on_click(self):
520
- self.mode_switcher.focus()
521
-
522
- def watch_modes(self, modes: dict[str, Mode] | None) -> None:
523
- from tui.visuals.columns import Columns
524
-
525
- columns = Columns("auto", "auto", "flex")
526
- if modes is not None:
527
- mode_list = sorted(modes.values(), key=lambda mode: mode.name.lower())
528
- for mode in mode_list:
529
- columns.add_row(
530
- (
531
- Content.styled("✔", "$text-success")
532
- if self.current_mode and mode.id == self.current_mode.id
533
- else ""
534
- ),
535
- Content.from_markup("[bold]$mode[/]", mode=mode.name),
536
- Content.styled(mode.description or "", "dim"),
537
- )
538
- else:
539
- mode_list = []
540
-
541
- self.mode_switcher.set_options(
542
- [Option(row, id=mode.id) for row, mode in zip(columns, mode_list)]
543
- )
544
- if self.current_mode is not None:
545
- self.mode_switcher.highlighted = self.mode_switcher.get_option_index(
546
- self.current_mode.id
547
- )
548
-
549
- def watch_agent_ready(self, ready: bool) -> None:
550
- self.set_class(not ready, "-not-ready")
551
- if ready:
552
- self.query_one(AgentInfo).update(self.agent_info)
553
-
554
- def watch_agent_info(self, agent_info: Content) -> None:
555
- if self.agent_ready:
556
- self.query_one(AgentInfo).update(agent_info)
557
- else:
558
- self.query_one(AgentInfo).update("Initializing…")
559
-
560
- def watch_multiline(self) -> None:
561
- self.update_prompt()
562
-
563
- def watch_shell_mode(self) -> None:
564
- self.update_prompt()
565
-
566
- def watch_working_directory(self, working_directory: str) -> None:
567
- if not working_directory:
568
- return
569
- out_of_bounds = not Path(working_directory).is_relative_to(self.project_path)
570
- if out_of_bounds and not self.has_class("-working-directory-out-of-bounds"):
571
- self.post_message(
572
- messages.Flash(
573
- "You have navigated away from the project directory",
574
- style="error",
575
- duration=5,
576
- )
577
- )
578
- self.set_class(
579
- out_of_bounds,
580
- "-working-directory-out-of-bounds",
581
- )
582
-
583
- def watch__ask(self, ask: Ask | None) -> None:
584
- self.set_class(ask is not None, "-mode-ask")
585
- if ask is None:
586
- self.prompt_text_area.focus()
587
- else:
588
- self.question.update(ask)
589
- self.question.focus()
590
-
591
- def update_prompt(self):
592
- """Update the prompt according to the current mode."""
593
- if self.shell_mode:
594
- self.prompt_label.update(self.PROMPT_SHELL, layout=False)
595
- self.add_class("-shell-mode")
596
- self.prompt_text_area.placeholder = Content.from_markup(
597
- "Enter shell command\t[r]▌esc▐[/r] prompt mode"
598
- ).expand_tabs(8)
599
- self.prompt_text_area.highlight_language = "shell"
600
- else:
601
- self.prompt_label.update(
602
- self.PROMPT_MULTILINE if self.multi_line else self.PROMPT_AI,
603
- layout=False,
604
- )
605
- self.remove_class("-shell-mode")
606
-
607
- prompt_message = self.app.settings.get("ui.prompt_message", str)
608
- self.prompt_text_area.placeholder = Content.assemble(
609
- f"{prompt_message}\t".expandtabs(8),
610
- ("▌!▐", "r"),
611
- " shell ",
612
- ("▌/▐", "r"),
613
- " commands ",
614
- ("▌@▐", "r"),
615
- " files",
616
- )
617
- self.prompt_text_area.highlight_language = "markdown"
618
-
619
- @property
620
- def likely_shell(self) -> bool:
621
- text = self.prompt_text_area.text
622
- if "\n" in text or " " in text or not text.strip():
623
- return False
624
-
625
- shell_commands = {
626
- command.strip()
627
- for command in self.app.settings.get(
628
- "shell.allow_commands", expect_type=str
629
- ).split()
630
- }
631
- if text.split(" ", 1)[0] in shell_commands:
632
- return True
633
- return False
634
-
635
- @property
636
- def is_shell_mode(self) -> bool:
637
- return self.shell_mode or self.likely_shell
638
-
639
- def focus(self, scroll_visible: bool = True) -> Self:
640
- if self._ask is not None:
641
- self.question.focus()
642
- else:
643
- self.query(HighlightedTextArea).focus()
644
- return self
645
-
646
- def append(self, text: str) -> None:
647
- self.query_one(HighlightedTextArea).insert(
648
- text, maintain_selection_offset=False
649
- )
650
-
651
- def watch_show_path_search(self, show: bool) -> None:
652
- self.prompt_text_area.suggestion = ""
653
-
654
- def watch_show_slash_complete(self, show: bool) -> None:
655
- if show:
656
- self.slash_complete.focus()
657
-
658
- def project_directory_updated(self) -> None:
659
- """Called when there is may be new files"""
660
- self.path_search.refresh_paths()
661
-
662
- @on(PromptTextArea.RequestShellMode)
663
- def on_request_shell_mode(self, event: PromptTextArea.RequestShellMode):
664
- self.shell_mode = True
665
- self.update_prompt()
666
-
667
- @on(TextArea.Changed)
668
- def on_text_area_changed(self, event: TextArea.Changed) -> None:
669
- text = event.text_area.text
670
-
671
- self.multi_line = "```" in text
672
-
673
- if not self.multi_line and self.likely_shell:
674
- self.shell_mode = True
675
-
676
- self.update_prompt()
677
-
678
- @on(PromptTextArea.CancelShell)
679
- def on_cancel_shell(self, event: PromptTextArea.CancelShell):
680
- self.shell_mode = False
681
-
682
- @on(InvokeFileSearch)
683
- def on_invoke_file_search(self, event: InvokeFileSearch) -> None:
684
- event.stop()
685
- if not self.shell_mode:
686
- self.show_path_search = True
687
- self.path_search.reset()
688
-
689
- @on(InvokeSlashComplete)
690
- def on_invoke_slash_complete(self, event: InvokeSlashComplete) -> None:
691
- event.stop()
692
- self.show_slash_complete = True
693
-
694
- @on(messages.PromptSuggestion)
695
- def on_prompt_suggestion(self, event: messages.PromptSuggestion) -> None:
696
- event.stop()
697
- self.prompt_text_area.suggestion = event.suggestion
698
-
699
- @on(SlashComplete.Completed)
700
- def on_slash_complete_completed(self, event: SlashComplete.Completed) -> None:
701
- self.prompt_text_area.clear()
702
- self.prompt_text_area.insert(f"{event.command} ")
703
- self.prompt_text_area.suggestion = ""
704
- self.focus()
705
-
706
- @on(messages.Dismiss)
707
- def on_dismiss(self, event: messages.Dismiss) -> None:
708
- event.stop()
709
- if event.widget is self.slash_complete and self.show_slash_complete:
710
- self.show_slash_complete = False
711
- self.prompt_text_area.suggestion = ""
712
- self.focus()
713
- elif event.widget is self.path_search and self.show_path_search:
714
- self.show_path_search = False
715
- self.focus()
716
-
717
- @on(messages.InsertPath)
718
- def on_insert_path(self, event: messages.InsertPath) -> None:
719
- event.stop()
720
- if " " in event.path:
721
- path = f'"{event.path}"'
722
- else:
723
- path = event.path
724
- if (
725
- self.prompt_text_area.get_text_range(*self.prompt_text_area.selection)
726
- != " "
727
- ):
728
- path += " "
729
- self.prompt_text_area.insert(path)
730
-
731
- @on(Question.Answer)
732
- def on_question_answer(self, event: Question.Answer) -> None:
733
- """Question has been answered."""
734
- event.stop()
735
-
736
- def remove_question() -> None:
737
- """Remove the question and restore the text prompt."""
738
- if self.ask_queue:
739
- self._ask = self.ask_queue.pop(0)
740
- else:
741
- self._ask = None
742
- self.app.terminal_alert(False)
743
-
744
- if self._ask is not None and (callback := self._ask.callback) is not None:
745
- callback(event.answer)
746
-
747
- self.set_timer(0.3, remove_question)
748
-
749
- def suggest(self, suggestion: str) -> None:
750
- if suggestion.startswith(self.text) and self.text != suggestion:
751
- self.prompt_text_area.suggestion = suggestion[len(self.text) :]
752
-
753
- def compose(self) -> ComposeResult:
754
- yield PathSearch(self.project_path).data_bind(root=Prompt.project_path)
755
- yield SlashComplete().data_bind(slash_commands=Prompt.slash_commands)
756
- with PromptContainer(id="prompt-container"):
757
- yield Question()
758
- with containers.HorizontalGroup(id="text-prompt"):
759
- yield Label(self.PROMPT_AI, id="prompt", markup=False)
760
- yield PromptTextArea().data_bind(
761
- multi_line=Prompt.multi_line,
762
- shell_mode=Prompt.shell_mode,
763
- agent_ready=Prompt.agent_ready,
764
- project_path=Prompt.project_path,
765
- working_directory=Prompt.working_directory,
766
- slash_commands=Prompt.slash_commands,
767
- )
768
- with containers.HorizontalGroup(id="info-container"):
769
- yield AgentInfo()
770
- yield CondensedPath().data_bind(path=Prompt.working_directory)
771
- yield StatusLine(markup=False).data_bind(status=Prompt.status)
772
- yield ModeSwitcher()
773
- yield ModeInfo("mode")
774
-
775
- def check_action(self, action: str, parameters: tuple[object, ...]) -> bool | None:
776
- return True
777
-
778
- def action_dismiss(self) -> None:
779
- if self._ask is not None:
780
- ask = self._ask
781
- if (callback := ask.callback) is not None:
782
- callback(Answer("Cancelled", "reject_once", "reject_once"))
783
- self.ask_queue.clear()
784
- self._ask = None
785
- self.app.terminal_alert(False)
786
- return
787
- if self.prompt_text_area.suggestion:
788
- self.prompt_text_area.suggestion = ""
789
- return
790
- if self.shell_mode:
791
- self.shell_mode = False
792
- elif self.show_slash_complete:
793
- self.show_slash_complete = False
794
- else:
795
- raise SkipAction()