cecli-dev 0.93.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. cecli/__init__.py +20 -0
  2. cecli/__main__.py +4 -0
  3. cecli/_version.py +34 -0
  4. cecli/args.py +1092 -0
  5. cecli/args_formatter.py +228 -0
  6. cecli/change_tracker.py +133 -0
  7. cecli/coders/__init__.py +38 -0
  8. cecli/coders/agent_coder.py +1872 -0
  9. cecli/coders/architect_coder.py +63 -0
  10. cecli/coders/ask_coder.py +8 -0
  11. cecli/coders/base_coder.py +3993 -0
  12. cecli/coders/chat_chunks.py +116 -0
  13. cecli/coders/context_coder.py +52 -0
  14. cecli/coders/copypaste_coder.py +269 -0
  15. cecli/coders/editblock_coder.py +656 -0
  16. cecli/coders/editblock_fenced_coder.py +9 -0
  17. cecli/coders/editblock_func_coder.py +140 -0
  18. cecli/coders/editor_diff_fenced_coder.py +8 -0
  19. cecli/coders/editor_editblock_coder.py +8 -0
  20. cecli/coders/editor_whole_coder.py +8 -0
  21. cecli/coders/help_coder.py +15 -0
  22. cecli/coders/patch_coder.py +705 -0
  23. cecli/coders/search_replace.py +757 -0
  24. cecli/coders/shell.py +37 -0
  25. cecli/coders/single_wholefile_func_coder.py +101 -0
  26. cecli/coders/udiff_coder.py +428 -0
  27. cecli/coders/udiff_simple.py +12 -0
  28. cecli/coders/wholefile_coder.py +143 -0
  29. cecli/coders/wholefile_func_coder.py +133 -0
  30. cecli/commands/__init__.py +192 -0
  31. cecli/commands/add.py +226 -0
  32. cecli/commands/agent.py +51 -0
  33. cecli/commands/architect.py +46 -0
  34. cecli/commands/ask.py +44 -0
  35. cecli/commands/chat_mode.py +0 -0
  36. cecli/commands/clear.py +37 -0
  37. cecli/commands/code.py +46 -0
  38. cecli/commands/command_prefix.py +44 -0
  39. cecli/commands/commit.py +52 -0
  40. cecli/commands/context.py +47 -0
  41. cecli/commands/context_blocks.py +124 -0
  42. cecli/commands/context_management.py +51 -0
  43. cecli/commands/copy.py +62 -0
  44. cecli/commands/copy_context.py +81 -0
  45. cecli/commands/core.py +287 -0
  46. cecli/commands/diff.py +68 -0
  47. cecli/commands/drop.py +217 -0
  48. cecli/commands/editor.py +78 -0
  49. cecli/commands/exit.py +55 -0
  50. cecli/commands/git.py +57 -0
  51. cecli/commands/help.py +140 -0
  52. cecli/commands/history_search.py +40 -0
  53. cecli/commands/lint.py +109 -0
  54. cecli/commands/list_sessions.py +56 -0
  55. cecli/commands/load.py +85 -0
  56. cecli/commands/load_session.py +48 -0
  57. cecli/commands/load_skill.py +68 -0
  58. cecli/commands/ls.py +75 -0
  59. cecli/commands/map.py +37 -0
  60. cecli/commands/map_refresh.py +35 -0
  61. cecli/commands/model.py +118 -0
  62. cecli/commands/models.py +41 -0
  63. cecli/commands/multiline_mode.py +38 -0
  64. cecli/commands/paste.py +91 -0
  65. cecli/commands/quit.py +32 -0
  66. cecli/commands/read_only.py +267 -0
  67. cecli/commands/read_only_stub.py +270 -0
  68. cecli/commands/reasoning_effort.py +70 -0
  69. cecli/commands/remove_skill.py +68 -0
  70. cecli/commands/report.py +40 -0
  71. cecli/commands/reset.py +88 -0
  72. cecli/commands/run.py +99 -0
  73. cecli/commands/save.py +49 -0
  74. cecli/commands/save_session.py +43 -0
  75. cecli/commands/settings.py +69 -0
  76. cecli/commands/test.py +58 -0
  77. cecli/commands/think_tokens.py +74 -0
  78. cecli/commands/tokens.py +207 -0
  79. cecli/commands/undo.py +145 -0
  80. cecli/commands/utils/__init__.py +0 -0
  81. cecli/commands/utils/base_command.py +131 -0
  82. cecli/commands/utils/helpers.py +142 -0
  83. cecli/commands/utils/registry.py +53 -0
  84. cecli/commands/utils/save_load_manager.py +98 -0
  85. cecli/commands/voice.py +78 -0
  86. cecli/commands/weak_model.py +123 -0
  87. cecli/commands/web.py +87 -0
  88. cecli/deprecated_args.py +185 -0
  89. cecli/diffs.py +129 -0
  90. cecli/dump.py +29 -0
  91. cecli/editor.py +147 -0
  92. cecli/exceptions.py +115 -0
  93. cecli/format_settings.py +26 -0
  94. cecli/help.py +119 -0
  95. cecli/help_pats.py +19 -0
  96. cecli/helpers/__init__.py +9 -0
  97. cecli/helpers/copypaste.py +123 -0
  98. cecli/helpers/coroutines.py +8 -0
  99. cecli/helpers/file_searcher.py +142 -0
  100. cecli/helpers/model_providers.py +552 -0
  101. cecli/helpers/plugin_manager.py +81 -0
  102. cecli/helpers/profiler.py +162 -0
  103. cecli/helpers/requests.py +77 -0
  104. cecli/helpers/similarity.py +98 -0
  105. cecli/helpers/skills.py +577 -0
  106. cecli/history.py +186 -0
  107. cecli/io.py +1782 -0
  108. cecli/linter.py +304 -0
  109. cecli/llm.py +101 -0
  110. cecli/main.py +1280 -0
  111. cecli/mcp/__init__.py +154 -0
  112. cecli/mcp/oauth.py +250 -0
  113. cecli/mcp/server.py +278 -0
  114. cecli/mdstream.py +243 -0
  115. cecli/models.py +1255 -0
  116. cecli/onboarding.py +301 -0
  117. cecli/prompts/__init__.py +0 -0
  118. cecli/prompts/agent.yml +71 -0
  119. cecli/prompts/architect.yml +35 -0
  120. cecli/prompts/ask.yml +31 -0
  121. cecli/prompts/base.yml +99 -0
  122. cecli/prompts/context.yml +60 -0
  123. cecli/prompts/copypaste.yml +5 -0
  124. cecli/prompts/editblock.yml +143 -0
  125. cecli/prompts/editblock_fenced.yml +106 -0
  126. cecli/prompts/editblock_func.yml +25 -0
  127. cecli/prompts/editor_diff_fenced.yml +115 -0
  128. cecli/prompts/editor_editblock.yml +121 -0
  129. cecli/prompts/editor_whole.yml +46 -0
  130. cecli/prompts/help.yml +37 -0
  131. cecli/prompts/patch.yml +110 -0
  132. cecli/prompts/single_wholefile_func.yml +24 -0
  133. cecli/prompts/udiff.yml +106 -0
  134. cecli/prompts/udiff_simple.yml +13 -0
  135. cecli/prompts/utils/__init__.py +0 -0
  136. cecli/prompts/utils/prompt_registry.py +167 -0
  137. cecli/prompts/utils/system.py +56 -0
  138. cecli/prompts/wholefile.yml +50 -0
  139. cecli/prompts/wholefile_func.yml +24 -0
  140. cecli/queries/tree-sitter-language-pack/README.md +7 -0
  141. cecli/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
  142. cecli/queries/tree-sitter-language-pack/c-tags.scm +12 -0
  143. cecli/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
  144. cecli/queries/tree-sitter-language-pack/clojure-tags.scm +12 -0
  145. cecli/queries/tree-sitter-language-pack/commonlisp-tags.scm +127 -0
  146. cecli/queries/tree-sitter-language-pack/cpp-tags.scm +18 -0
  147. cecli/queries/tree-sitter-language-pack/csharp-tags.scm +32 -0
  148. cecli/queries/tree-sitter-language-pack/d-tags.scm +26 -0
  149. cecli/queries/tree-sitter-language-pack/dart-tags.scm +97 -0
  150. cecli/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
  151. cecli/queries/tree-sitter-language-pack/elixir-tags.scm +59 -0
  152. cecli/queries/tree-sitter-language-pack/elm-tags.scm +22 -0
  153. cecli/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
  154. cecli/queries/tree-sitter-language-pack/go-tags.scm +49 -0
  155. cecli/queries/tree-sitter-language-pack/java-tags.scm +26 -0
  156. cecli/queries/tree-sitter-language-pack/javascript-tags.scm +96 -0
  157. cecli/queries/tree-sitter-language-pack/lua-tags.scm +39 -0
  158. cecli/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
  159. cecli/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
  160. cecli/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +101 -0
  161. cecli/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
  162. cecli/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
  163. cecli/queries/tree-sitter-language-pack/python-tags.scm +24 -0
  164. cecli/queries/tree-sitter-language-pack/r-tags.scm +27 -0
  165. cecli/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
  166. cecli/queries/tree-sitter-language-pack/ruby-tags.scm +69 -0
  167. cecli/queries/tree-sitter-language-pack/rust-tags.scm +63 -0
  168. cecli/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
  169. cecli/queries/tree-sitter-language-pack/swift-tags.scm +54 -0
  170. cecli/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
  171. cecli/queries/tree-sitter-languages/README.md +24 -0
  172. cecli/queries/tree-sitter-languages/c-tags.scm +12 -0
  173. cecli/queries/tree-sitter-languages/c_sharp-tags.scm +52 -0
  174. cecli/queries/tree-sitter-languages/cpp-tags.scm +18 -0
  175. cecli/queries/tree-sitter-languages/dart-tags.scm +92 -0
  176. cecli/queries/tree-sitter-languages/elisp-tags.scm +8 -0
  177. cecli/queries/tree-sitter-languages/elixir-tags.scm +59 -0
  178. cecli/queries/tree-sitter-languages/elm-tags.scm +22 -0
  179. cecli/queries/tree-sitter-languages/fortran-tags.scm +18 -0
  180. cecli/queries/tree-sitter-languages/go-tags.scm +36 -0
  181. cecli/queries/tree-sitter-languages/haskell-tags.scm +5 -0
  182. cecli/queries/tree-sitter-languages/hcl-tags.scm +77 -0
  183. cecli/queries/tree-sitter-languages/java-tags.scm +26 -0
  184. cecli/queries/tree-sitter-languages/javascript-tags.scm +96 -0
  185. cecli/queries/tree-sitter-languages/julia-tags.scm +60 -0
  186. cecli/queries/tree-sitter-languages/kotlin-tags.scm +30 -0
  187. cecli/queries/tree-sitter-languages/matlab-tags.scm +10 -0
  188. cecli/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
  189. cecli/queries/tree-sitter-languages/ocaml_interface-tags.scm +104 -0
  190. cecli/queries/tree-sitter-languages/php-tags.scm +32 -0
  191. cecli/queries/tree-sitter-languages/python-tags.scm +22 -0
  192. cecli/queries/tree-sitter-languages/ql-tags.scm +26 -0
  193. cecli/queries/tree-sitter-languages/ruby-tags.scm +69 -0
  194. cecli/queries/tree-sitter-languages/rust-tags.scm +63 -0
  195. cecli/queries/tree-sitter-languages/scala-tags.scm +64 -0
  196. cecli/queries/tree-sitter-languages/typescript-tags.scm +44 -0
  197. cecli/queries/tree-sitter-languages/zig-tags.scm +20 -0
  198. cecli/reasoning_tags.py +82 -0
  199. cecli/repo.py +626 -0
  200. cecli/repomap.py +1368 -0
  201. cecli/report.py +260 -0
  202. cecli/resources/__init__.py +3 -0
  203. cecli/resources/model-metadata.json +25751 -0
  204. cecli/resources/model-settings.yml +2394 -0
  205. cecli/resources/providers.json +67 -0
  206. cecli/run_cmd.py +143 -0
  207. cecli/scrape.py +295 -0
  208. cecli/sendchat.py +250 -0
  209. cecli/sessions.py +281 -0
  210. cecli/special.py +203 -0
  211. cecli/tools/__init__.py +72 -0
  212. cecli/tools/command.py +103 -0
  213. cecli/tools/command_interactive.py +113 -0
  214. cecli/tools/context_manager.py +175 -0
  215. cecli/tools/delete_block.py +154 -0
  216. cecli/tools/delete_line.py +120 -0
  217. cecli/tools/delete_lines.py +144 -0
  218. cecli/tools/extract_lines.py +281 -0
  219. cecli/tools/finished.py +35 -0
  220. cecli/tools/git_branch.py +132 -0
  221. cecli/tools/git_diff.py +49 -0
  222. cecli/tools/git_log.py +43 -0
  223. cecli/tools/git_remote.py +39 -0
  224. cecli/tools/git_show.py +37 -0
  225. cecli/tools/git_status.py +32 -0
  226. cecli/tools/grep.py +242 -0
  227. cecli/tools/indent_lines.py +195 -0
  228. cecli/tools/insert_block.py +263 -0
  229. cecli/tools/list_changes.py +71 -0
  230. cecli/tools/load_skill.py +51 -0
  231. cecli/tools/ls.py +77 -0
  232. cecli/tools/remove_skill.py +51 -0
  233. cecli/tools/replace_all.py +113 -0
  234. cecli/tools/replace_line.py +135 -0
  235. cecli/tools/replace_lines.py +180 -0
  236. cecli/tools/replace_text.py +186 -0
  237. cecli/tools/show_numbered_context.py +137 -0
  238. cecli/tools/thinking.py +52 -0
  239. cecli/tools/undo_change.py +82 -0
  240. cecli/tools/update_todo_list.py +148 -0
  241. cecli/tools/utils/base_tool.py +64 -0
  242. cecli/tools/utils/helpers.py +359 -0
  243. cecli/tools/utils/output.py +119 -0
  244. cecli/tools/utils/registry.py +145 -0
  245. cecli/tools/view_files_matching.py +138 -0
  246. cecli/tools/view_files_with_symbol.py +117 -0
  247. cecli/tui/__init__.py +83 -0
  248. cecli/tui/app.py +971 -0
  249. cecli/tui/io.py +566 -0
  250. cecli/tui/styles.tcss +117 -0
  251. cecli/tui/widgets/__init__.py +19 -0
  252. cecli/tui/widgets/completion_bar.py +331 -0
  253. cecli/tui/widgets/file_list.py +76 -0
  254. cecli/tui/widgets/footer.py +165 -0
  255. cecli/tui/widgets/input_area.py +320 -0
  256. cecli/tui/widgets/key_hints.py +16 -0
  257. cecli/tui/widgets/output.py +354 -0
  258. cecli/tui/widgets/status_bar.py +279 -0
  259. cecli/tui/worker.py +160 -0
  260. cecli/urls.py +16 -0
  261. cecli/utils.py +499 -0
  262. cecli/versioncheck.py +90 -0
  263. cecli/voice.py +90 -0
  264. cecli/waiting.py +38 -0
  265. cecli/watch.py +316 -0
  266. cecli/watch_prompts.py +12 -0
  267. cecli/website/Gemfile +8 -0
  268. cecli/website/_includes/blame.md +162 -0
  269. cecli/website/_includes/get-started.md +22 -0
  270. cecli/website/_includes/help-tip.md +5 -0
  271. cecli/website/_includes/help.md +24 -0
  272. cecli/website/_includes/install.md +5 -0
  273. cecli/website/_includes/keys.md +4 -0
  274. cecli/website/_includes/model-warnings.md +67 -0
  275. cecli/website/_includes/multi-line.md +22 -0
  276. cecli/website/_includes/python-m-aider.md +5 -0
  277. cecli/website/_includes/recording.css +228 -0
  278. cecli/website/_includes/recording.md +34 -0
  279. cecli/website/_includes/replit-pipx.md +9 -0
  280. cecli/website/_includes/works-best.md +1 -0
  281. cecli/website/_sass/custom/custom.scss +103 -0
  282. cecli/website/docs/config/adv-model-settings.md +2498 -0
  283. cecli/website/docs/config/agent-mode.md +320 -0
  284. cecli/website/docs/config/aider_conf.md +548 -0
  285. cecli/website/docs/config/api-keys.md +90 -0
  286. cecli/website/docs/config/custom-commands.md +187 -0
  287. cecli/website/docs/config/dotenv.md +493 -0
  288. cecli/website/docs/config/editor.md +127 -0
  289. cecli/website/docs/config/mcp.md +210 -0
  290. cecli/website/docs/config/model-aliases.md +173 -0
  291. cecli/website/docs/config/options.md +890 -0
  292. cecli/website/docs/config/reasoning.md +210 -0
  293. cecli/website/docs/config/skills.md +172 -0
  294. cecli/website/docs/config/tui.md +126 -0
  295. cecli/website/docs/config.md +44 -0
  296. cecli/website/docs/faq.md +379 -0
  297. cecli/website/docs/git.md +76 -0
  298. cecli/website/docs/index.md +47 -0
  299. cecli/website/docs/install/codespaces.md +39 -0
  300. cecli/website/docs/install/docker.md +48 -0
  301. cecli/website/docs/install/optional.md +100 -0
  302. cecli/website/docs/install/replit.md +8 -0
  303. cecli/website/docs/install.md +115 -0
  304. cecli/website/docs/languages.md +264 -0
  305. cecli/website/docs/legal/contributor-agreement.md +111 -0
  306. cecli/website/docs/legal/privacy.md +104 -0
  307. cecli/website/docs/llms/anthropic.md +77 -0
  308. cecli/website/docs/llms/azure.md +48 -0
  309. cecli/website/docs/llms/bedrock.md +132 -0
  310. cecli/website/docs/llms/cohere.md +34 -0
  311. cecli/website/docs/llms/deepseek.md +32 -0
  312. cecli/website/docs/llms/gemini.md +49 -0
  313. cecli/website/docs/llms/github.md +111 -0
  314. cecli/website/docs/llms/groq.md +36 -0
  315. cecli/website/docs/llms/lm-studio.md +39 -0
  316. cecli/website/docs/llms/ollama.md +75 -0
  317. cecli/website/docs/llms/openai-compat.md +39 -0
  318. cecli/website/docs/llms/openai.md +58 -0
  319. cecli/website/docs/llms/openrouter.md +78 -0
  320. cecli/website/docs/llms/other.md +117 -0
  321. cecli/website/docs/llms/vertex.md +50 -0
  322. cecli/website/docs/llms/warnings.md +10 -0
  323. cecli/website/docs/llms/xai.md +53 -0
  324. cecli/website/docs/llms.md +54 -0
  325. cecli/website/docs/more/analytics.md +127 -0
  326. cecli/website/docs/more/edit-formats.md +116 -0
  327. cecli/website/docs/more/infinite-output.md +192 -0
  328. cecli/website/docs/more-info.md +8 -0
  329. cecli/website/docs/recordings/auto-accept-architect.md +31 -0
  330. cecli/website/docs/recordings/dont-drop-original-read-files.md +35 -0
  331. cecli/website/docs/recordings/index.md +21 -0
  332. cecli/website/docs/recordings/model-accepts-settings.md +69 -0
  333. cecli/website/docs/recordings/tree-sitter-language-pack.md +80 -0
  334. cecli/website/docs/repomap.md +112 -0
  335. cecli/website/docs/scripting.md +100 -0
  336. cecli/website/docs/sessions.md +213 -0
  337. cecli/website/docs/troubleshooting/aider-not-found.md +24 -0
  338. cecli/website/docs/troubleshooting/edit-errors.md +76 -0
  339. cecli/website/docs/troubleshooting/imports.md +62 -0
  340. cecli/website/docs/troubleshooting/models-and-keys.md +54 -0
  341. cecli/website/docs/troubleshooting/support.md +79 -0
  342. cecli/website/docs/troubleshooting/token-limits.md +96 -0
  343. cecli/website/docs/troubleshooting/warnings.md +12 -0
  344. cecli/website/docs/troubleshooting.md +11 -0
  345. cecli/website/docs/usage/browser.md +57 -0
  346. cecli/website/docs/usage/caching.md +49 -0
  347. cecli/website/docs/usage/commands.md +133 -0
  348. cecli/website/docs/usage/conventions.md +119 -0
  349. cecli/website/docs/usage/copypaste.md +136 -0
  350. cecli/website/docs/usage/images-urls.md +48 -0
  351. cecli/website/docs/usage/lint-test.md +118 -0
  352. cecli/website/docs/usage/modes.md +211 -0
  353. cecli/website/docs/usage/not-code.md +179 -0
  354. cecli/website/docs/usage/notifications.md +87 -0
  355. cecli/website/docs/usage/tips.md +79 -0
  356. cecli/website/docs/usage/tutorials.md +30 -0
  357. cecli/website/docs/usage/voice.md +121 -0
  358. cecli/website/docs/usage/watch.md +294 -0
  359. cecli/website/docs/usage.md +102 -0
  360. cecli/website/share/index.md +101 -0
  361. cecli_dev-0.93.1.dist-info/METADATA +549 -0
  362. cecli_dev-0.93.1.dist-info/RECORD +366 -0
  363. cecli_dev-0.93.1.dist-info/WHEEL +5 -0
  364. cecli_dev-0.93.1.dist-info/entry_points.txt +4 -0
  365. cecli_dev-0.93.1.dist-info/licenses/LICENSE.txt +202 -0
  366. cecli_dev-0.93.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,279 @@
1
+ """Unified status bar widget for notifications and confirmations."""
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Horizontal
5
+ from textual.message import Message
6
+ from textual.reactive import reactive
7
+ from textual.widget import Widget
8
+ from textual.widgets import Static
9
+
10
+
11
+ class StatusBar(Widget, can_focus=True):
12
+ """Unified status bar for notifications, confirmations, and prompts.
13
+
14
+ Modes:
15
+ - hidden: Bar is not displayed
16
+ - notification: Shows a transient message (auto-dismisses)
17
+ - confirm: Shows a y/n/a confirmation prompt
18
+ """
19
+
20
+ DEFAULT_CSS = """
21
+ StatusBar {
22
+ height: auto;
23
+ background: $surface;
24
+ margin: 0 0;
25
+ padding: 0;
26
+ }
27
+
28
+ StatusBar.hidden {
29
+ display: none;
30
+ }
31
+
32
+ /* Content container */
33
+ StatusBar .status-content {
34
+ height: 3;
35
+ padding: 1 0 0 2;
36
+ layout: horizontal;
37
+ align: left middle;
38
+ background: $surface;
39
+ }
40
+
41
+ /* Notification styles */
42
+ StatusBar .notification-text {
43
+ width: 1fr;
44
+ height: 1;
45
+ color: $secondary;
46
+ content-align: left middle;
47
+ background: $surface;
48
+ }
49
+
50
+ StatusBar .notification-text.info {
51
+ color: $secondary;
52
+ }
53
+
54
+ StatusBar .notification-text.warning {
55
+ color: $warning;
56
+ }
57
+
58
+ StatusBar .notification-text.error {
59
+ color: $error;
60
+ }
61
+
62
+ StatusBar .notification-text.success {
63
+ color: $success;
64
+ }
65
+
66
+ /* Confirmation styles */
67
+ StatusBar .confirm-question {
68
+ width: 1fr;
69
+ height: 1;
70
+ color: $foreground;
71
+ content-align: left middle;
72
+ background: $surface;
73
+ }
74
+
75
+ StatusBar .confirm-hints {
76
+ width: auto;
77
+ height: 1;
78
+ dock: right;
79
+ background: $surface;
80
+ }
81
+
82
+ StatusBar .hint {
83
+ width: auto;
84
+ height: 1;
85
+ margin-left: 2;
86
+ color: $secondary;
87
+ background: $surface;
88
+ }
89
+
90
+ StatusBar .hint-yes {
91
+ color: $success;
92
+ }
93
+
94
+ StatusBar .hint-no {
95
+ color: $warning;
96
+ }
97
+
98
+ StatusBar .hint-all {
99
+ color: $secondary;
100
+ }
101
+
102
+ StatusBar .hint-skip {
103
+ color: $secondary;
104
+ }
105
+
106
+ StatusBar .hint-tweak {
107
+ color: $accent;
108
+ }
109
+
110
+ StatusBar .hint-never {
111
+ color: $warning;
112
+ }
113
+ """
114
+
115
+ # Current mode
116
+ mode: reactive[str] = reactive("hidden")
117
+
118
+ class ConfirmResponse(Message):
119
+ """Confirmation response message."""
120
+
121
+ def __init__(self, result: bool | str):
122
+ self.result = result
123
+ super().__init__()
124
+
125
+ def __init__(self, **kwargs):
126
+ """Initialize status bar."""
127
+ super().__init__(**kwargs)
128
+ self._text = ""
129
+ self._severity = "info"
130
+ self._show_all = False
131
+ self._allow_tweak = False
132
+ self._allow_never = False
133
+ self._default = "y"
134
+ self._explicit_yes_required = False
135
+ self._timer = None
136
+
137
+ def compose(self) -> ComposeResult:
138
+ """Create empty container - content added dynamically."""
139
+ yield Horizontal(classes="status-content")
140
+
141
+ def watch_mode(self, mode: str) -> None:
142
+ """React to mode changes."""
143
+ self.remove_class("hidden")
144
+ if mode == "hidden":
145
+ self.add_class("hidden")
146
+ self.can_focus = False
147
+ else:
148
+ self.can_focus = mode == "confirm"
149
+
150
+ def _rebuild_content(self) -> None:
151
+ """Rebuild the content based on current mode."""
152
+ container = self.query_one(".status-content")
153
+ container.remove_children()
154
+
155
+ if self.mode == "notification":
156
+ container.mount(Static(self._text, classes=f"notification-text {self._severity}"))
157
+ elif self.mode == "confirm":
158
+ container.mount(Static(self._text, classes="confirm-question"))
159
+ hints = Horizontal(classes="confirm-hints")
160
+ container.mount(hints)
161
+ hints.mount(Static("\\[y]es", classes="hint hint-yes"))
162
+ hints.mount(Static("\\[n]o", classes="hint hint-no"))
163
+ if self._show_all:
164
+ hints.mount(Static("\\[a]ll", classes="hint hint-all"))
165
+ hints.mount(Static("\\[s]kip", classes="hint hint-skip"))
166
+ if self._allow_tweak:
167
+ hints.mount(Static("\\[t]weak", classes="hint hint-tweak"))
168
+ if self._allow_never:
169
+ hints.mount(Static("\\[d]on't ask", classes="hint hint-never"))
170
+
171
+ def show_notification(
172
+ self, text: str, severity: str = "info", timeout: float | None = 3.0
173
+ ) -> None:
174
+ """Show a transient notification message.
175
+
176
+ Args:
177
+ text: Message to display
178
+ severity: One of "info", "warning", "error", "success"
179
+ timeout: Auto-dismiss after this many seconds (None = no auto-dismiss)
180
+ """
181
+ # Cancel any existing timer
182
+ if self._timer:
183
+ self._timer.stop()
184
+ self._timer = None
185
+
186
+ self._text = text
187
+ self._severity = severity
188
+ self.mode = "notification"
189
+ self._rebuild_content()
190
+
191
+ if timeout:
192
+ self._timer = self.set_timer(timeout, self.hide)
193
+
194
+ def show_confirm(
195
+ self,
196
+ question: str,
197
+ show_all: bool = False,
198
+ allow_tweak: bool = False,
199
+ allow_never: bool = False,
200
+ default: str = "y",
201
+ explicit_yes_required: bool = False,
202
+ ) -> None:
203
+ """Show a confirmation prompt.
204
+
205
+ Args:
206
+ question: Question to display
207
+ show_all: Whether to show "all" option
208
+ allow_tweak: Whether to show "tweak" option
209
+ allow_never: Whether to show "don't ask again" option
210
+ default: Default response ("y" or "n")
211
+ explicit_yes_required: Whether explicit yes is required
212
+ """
213
+ # Cancel any existing timer
214
+ if self._timer:
215
+ self._timer.stop()
216
+ self._timer = None
217
+
218
+ self._text = question
219
+ self._show_all = show_all
220
+ self._allow_tweak = allow_tweak
221
+ self._allow_never = allow_never
222
+ self._default = default
223
+ self._explicit_yes_required = explicit_yes_required
224
+ self.mode = "confirm"
225
+ self._rebuild_content()
226
+ self.focus()
227
+
228
+ def hide(self) -> None:
229
+ """Hide the status bar."""
230
+ if self._timer:
231
+ self._timer.stop()
232
+ self._timer = None
233
+ self.mode = "hidden"
234
+
235
+ def on_key(self, event) -> None:
236
+ """Handle key shortcuts for confirm mode."""
237
+ if self.mode != "confirm":
238
+ return
239
+
240
+ key = event.key.lower()
241
+ if key == "y":
242
+ event.stop()
243
+ event.prevent_default()
244
+ self.post_message(self.ConfirmResponse(True))
245
+ self.hide()
246
+ elif key == "n":
247
+ event.stop()
248
+ event.prevent_default()
249
+ self.post_message(self.ConfirmResponse(False))
250
+ self.hide()
251
+ elif key == "a" and self._show_all:
252
+ event.stop()
253
+ event.prevent_default()
254
+ self.post_message(self.ConfirmResponse("all"))
255
+ self.hide()
256
+ elif key == "s" and self._show_all:
257
+ event.stop()
258
+ event.prevent_default()
259
+ self.post_message(self.ConfirmResponse("skip"))
260
+ self.hide()
261
+ elif key == "t" and self._allow_tweak:
262
+ event.stop()
263
+ event.prevent_default()
264
+ self.post_message(self.ConfirmResponse("tweak"))
265
+ self.hide()
266
+ elif key == "d" and self._allow_never:
267
+ event.stop()
268
+ event.prevent_default()
269
+ self.post_message(self.ConfirmResponse("never"))
270
+ self.hide()
271
+ elif key == "escape":
272
+ event.stop()
273
+ event.prevent_default()
274
+ # Return default based on default parameter
275
+ if self._default.lower().startswith("y"):
276
+ self.post_message(self.ConfirmResponse(True))
277
+ else:
278
+ self.post_message(self.ConfirmResponse(False))
279
+ self.hide()
cecli/tui/worker.py ADDED
@@ -0,0 +1,160 @@
1
+ """Worker thread for running Coder in background."""
2
+
3
+ import asyncio
4
+ import logging
5
+ import threading
6
+ import warnings
7
+ from typing import Optional
8
+
9
+ from cecli.coders import Coder
10
+ from cecli.commands import SwitchCoderSignal
11
+
12
+ # Suppress asyncio task destroyed warnings during shutdown
13
+ logging.getLogger("asyncio").setLevel(logging.CRITICAL)
14
+
15
+ # Also suppress via warnings module
16
+ warnings.filterwarnings("ignore", message=".*Task was destroyed.*")
17
+ warnings.filterwarnings("ignore", message=".*coroutine.*was never awaited.*")
18
+
19
+
20
+ class CoderWorker:
21
+ """Runs Coder in a background thread with its own event loop."""
22
+
23
+ def __init__(self, coder, output_queue, input_queue):
24
+ """Initialize worker with coder instance and communication queues.
25
+
26
+ Args:
27
+ coder: The Coder instance to run
28
+ output_queue: queue.Queue for sending output to TUI
29
+ input_queue: queue.Queue for receiving input from TUI
30
+ """
31
+ self.coder = coder
32
+ self.output_queue = output_queue # queue.Queue
33
+ self.input_queue = input_queue # queue.Queue
34
+ self.thread: Optional[threading.Thread] = None
35
+ self.loop: Optional[asyncio.AbstractEventLoop] = None
36
+ self.running = False
37
+
38
+ def start(self):
39
+ """Start the worker thread."""
40
+ self.running = True
41
+ self.thread = threading.Thread(target=self._run_thread, daemon=True)
42
+ self.thread.start()
43
+
44
+ def _run_thread(self):
45
+ """Thread entry point - creates event loop and runs coder."""
46
+ self.loop = asyncio.new_event_loop()
47
+ asyncio.set_event_loop(self.loop)
48
+
49
+ try:
50
+ self.loop.run_until_complete(self._async_run())
51
+ except asyncio.CancelledError:
52
+ pass
53
+ except RuntimeError:
54
+ # Event loop stopped - this is expected during shutdown
55
+ pass
56
+ finally:
57
+ self._cleanup_loop()
58
+
59
+ def _cleanup_loop(self):
60
+ """Clean up the event loop safely."""
61
+ if not self.loop:
62
+ return
63
+
64
+ try:
65
+ # Cancel pending tasks if loop is still running
66
+ if not self.loop.is_closed():
67
+ pending = asyncio.all_tasks(self.loop)
68
+ for task in pending:
69
+ task.cancel()
70
+
71
+ # Only try to gather if loop isn't stopped
72
+ if self.loop.is_running():
73
+ pass # Can't do much if loop is still running
74
+ elif pending:
75
+ try:
76
+ self.loop.run_until_complete(
77
+ asyncio.gather(*pending, return_exceptions=True)
78
+ )
79
+ except RuntimeError:
80
+ pass # Loop already stopped
81
+
82
+ self.loop.close()
83
+ except Exception:
84
+ pass # Ignore cleanup errors
85
+
86
+ async def _async_run(self):
87
+ """Async entry point - runs coder loop."""
88
+ while self.running:
89
+ try:
90
+ await self.coder.run()
91
+ break # Normal exit
92
+ except asyncio.CancelledError:
93
+ break
94
+ except SwitchCoderSignal as switch:
95
+ # Handle chat mode switches (e.g., /chat-mode architect)
96
+ try:
97
+ kwargs = dict(io=self.coder.io, from_coder=self.coder)
98
+ kwargs.update(switch.kwargs)
99
+ if "show_announcements" in kwargs:
100
+ del kwargs["show_announcements"]
101
+ kwargs["num_cache_warming_pings"] = 0
102
+ kwargs["args"] = self.coder.args
103
+ # Skip summarization to avoid blocking LLM calls during mode switch
104
+ kwargs["summarize_from_coder"] = False
105
+
106
+ new_coder = await Coder.create(**kwargs)
107
+ new_coder.args = self.coder.args
108
+
109
+ if switch.kwargs.get("show_announcements") is False:
110
+ new_coder.suppress_announcements_for_next_prompt = True
111
+
112
+ # Notify TUI of mode change
113
+ self.coder = new_coder
114
+ edit_format = getattr(self.coder, "edit_format", "code") or "code"
115
+ self.output_queue.put(
116
+ {
117
+ "type": "mode_change",
118
+ "mode": edit_format,
119
+ }
120
+ )
121
+ except Exception as e:
122
+ self.output_queue.put(
123
+ {"type": "error", "message": f"Failed to switch mode: {e}"}
124
+ )
125
+ break
126
+ # Continue the loop with the new coder
127
+ except Exception as e:
128
+ self.output_queue.put({"type": "error", "message": str(e)})
129
+ break
130
+
131
+ def interrupt(self):
132
+ """Cancel the current output task on the coder instance."""
133
+ if self.coder and hasattr(self.coder, "io") and self.coder.io:
134
+ # Cancel the output task if it exists
135
+ if hasattr(self.coder.io, "output_task") and self.coder.io.output_task:
136
+ self.coder.io.output_task.cancel()
137
+ # Also set output_running to False to stop the output_task loop
138
+ if hasattr(self.coder, "output_running"):
139
+ self.coder.output_running = False
140
+
141
+ def stop(self):
142
+ """Stop the worker thread gracefully."""
143
+ self.running = False
144
+
145
+ # Signal the coder to stop
146
+ if hasattr(self.coder, "input_running"):
147
+ self.coder.input_running = False
148
+ if hasattr(self.coder, "output_running"):
149
+ self.coder.output_running = False
150
+
151
+ if self.loop and self.loop.is_running():
152
+ try:
153
+ self.loop.call_soon_threadsafe(self.loop.stop)
154
+ except RuntimeError:
155
+ # Loop may already be closed
156
+ pass
157
+
158
+ # Wait for thread to finish
159
+ if self.thread and self.thread.is_alive():
160
+ self.thread.join(timeout=2.0)
cecli/urls.py ADDED
@@ -0,0 +1,16 @@
1
+ website = "https://cecli.dev/"
2
+ add_all_files = "https://cecli.dev/docs/faq.html#how-can-i-add-all-the-files-to-the-chat"
3
+ edit_errors = "https://cecli.dev/docs/troubleshooting/edit-errors.html"
4
+ git = "https://cecli.dev/docs/git.html"
5
+ enable_playwright = "https://cecli.dev/docs/install/optional.html#enable-playwright"
6
+ favicon = "https://cecli.dev/assets/icons/favicon-32x32.png"
7
+ model_warnings = "https://cecli.dev/docs/llms/warnings.html"
8
+ token_limits = "https://cecli.dev/docs/troubleshooting/token-limits.html"
9
+ llms = "https://cecli.dev/docs/llms.html"
10
+ large_repos = "https://cecli.dev/docs/faq.html#can-i-use-cecli-in-a-large-mono-repo"
11
+ github_issues = "https://github.com/dwash96/aider-ce/issues/new"
12
+ git_index_version = "https://github.com/Aider-AI/aider/issues/211"
13
+ install_properly = "https://cecli.dev/docs/troubleshooting/imports.html"
14
+ release_notes = "https://github.com/dwash96/aider-ce/releases/latest"
15
+ edit_formats = "https://cecli.dev/docs/more/edit-formats.html"
16
+ models_and_keys = "https://cecli.dev/docs/troubleshooting/models-and-keys.html"