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,281 @@
1
+ import os
2
+
3
+ from cecli.tools.utils.base_tool import BaseTool
4
+ from cecli.tools.utils.helpers import (
5
+ ToolError,
6
+ apply_change,
7
+ generate_unified_diff_snippet,
8
+ handle_tool_error,
9
+ validate_file_for_edit,
10
+ )
11
+
12
+
13
+ class Tool(BaseTool):
14
+ NORM_NAME = "extractlines"
15
+ SCHEMA = {
16
+ "type": "function",
17
+ "function": {
18
+ "name": "ExtractLines",
19
+ "description": "Extract lines from a source file and append them to a target file.",
20
+ "parameters": {
21
+ "type": "object",
22
+ "properties": {
23
+ "source_file_path": {"type": "string"},
24
+ "target_file_path": {"type": "string"},
25
+ "start_pattern": {"type": "string"},
26
+ "end_pattern": {"type": "string"},
27
+ "line_count": {"type": "integer"},
28
+ "near_context": {"type": "string"},
29
+ "occurrence": {"type": "integer", "default": 1},
30
+ "dry_run": {"type": "boolean", "default": False},
31
+ },
32
+ "required": ["source_file_path", "target_file_path", "start_pattern"],
33
+ },
34
+ },
35
+ }
36
+
37
+ @classmethod
38
+ def execute(
39
+ cls,
40
+ coder,
41
+ source_file_path,
42
+ target_file_path,
43
+ start_pattern,
44
+ end_pattern=None,
45
+ line_count=None,
46
+ near_context=None,
47
+ occurrence=1,
48
+ dry_run=False,
49
+ ):
50
+ """
51
+ Extract a range of lines from a source file and move them to a target file.
52
+
53
+ Parameters:
54
+ - coder: The Coder instance
55
+ - source_file_path: Path to the file to extract lines from
56
+ - target_file_path: Path to the file to append extracted lines to (will be created if needed)
57
+ - start_pattern: Pattern marking the start of the block to extract
58
+ - end_pattern: Optional pattern marking the end of the block
59
+ - line_count: Optional number of lines to extract (alternative to end_pattern)
60
+ - near_context: Optional text nearby to help locate the correct instance of the start_pattern
61
+ - occurrence: Which occurrence of the start_pattern to use (1-based index, or -1 for last)
62
+ - dry_run: If True, simulate the change without modifying files
63
+
64
+ Returns a result message.
65
+ """
66
+ tool_name = "ExtractLines"
67
+ try:
68
+ # --- Validate Source File ---
69
+ abs_source_path, rel_source_path, source_content = validate_file_for_edit(
70
+ coder, source_file_path
71
+ )
72
+
73
+ # --- Validate Target File ---
74
+ abs_target_path = coder.abs_root_path(target_file_path)
75
+ rel_target_path = coder.get_rel_fname(abs_target_path)
76
+ target_exists = os.path.isfile(abs_target_path)
77
+
78
+ if target_exists:
79
+ # If target exists, validate it for editing
80
+ try:
81
+ _, _, target_content = validate_file_for_edit(coder, target_file_path)
82
+ except ToolError as e:
83
+ coder.io.tool_error(f"Target file validation failed: {str(e)}")
84
+ return f"Error: {str(e)}"
85
+ else:
86
+ # Target doesn't exist, start with empty content
87
+ target_content = ""
88
+
89
+ # --- Find Extraction Range ---
90
+ if end_pattern and line_count:
91
+ coder.io.tool_error("Cannot specify both end_pattern and line_count")
92
+ return "Error: Cannot specify both end_pattern and line_count"
93
+
94
+ source_lines = source_content.splitlines()
95
+
96
+ start_pattern_line_indices = []
97
+ for i, line in enumerate(source_lines):
98
+ if start_pattern in line:
99
+ if near_context:
100
+ context_window_start = max(0, i - 5)
101
+ context_window_end = min(len(source_lines), i + 6)
102
+ context_block = "\n".join(
103
+ source_lines[context_window_start:context_window_end]
104
+ )
105
+ if near_context in context_block:
106
+ start_pattern_line_indices.append(i)
107
+ else:
108
+ start_pattern_line_indices.append(i)
109
+
110
+ if not start_pattern_line_indices:
111
+ err_msg = f"Start pattern '{start_pattern}' not found"
112
+ if near_context:
113
+ err_msg += f" near context '{near_context}'"
114
+ err_msg += f" in source file '{source_file_path}'."
115
+ coder.io.tool_error(err_msg)
116
+ return f"Error: {err_msg}"
117
+
118
+ num_occurrences = len(start_pattern_line_indices)
119
+ try:
120
+ occurrence = int(occurrence)
121
+ if occurrence == -1:
122
+ target_idx = num_occurrences - 1
123
+ elif occurrence > 0 and occurrence <= num_occurrences:
124
+ target_idx = occurrence - 1
125
+ else:
126
+ err_msg = (
127
+ f"Occurrence number {occurrence} is out of range for start pattern"
128
+ f" '{start_pattern}'. Found {num_occurrences} occurrences"
129
+ )
130
+ if near_context:
131
+ err_msg += f" near '{near_context}'"
132
+ err_msg += f" in '{source_file_path}'."
133
+ coder.io.tool_error(err_msg)
134
+ return f"Error: {err_msg}"
135
+ except ValueError:
136
+ coder.io.tool_error(
137
+ f"Invalid occurrence value: '{occurrence}'. Must be an integer."
138
+ )
139
+ return f"Error: Invalid occurrence value '{occurrence}'"
140
+
141
+ start_line = start_pattern_line_indices[target_idx]
142
+ occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
143
+
144
+ end_line = -1
145
+ if end_pattern:
146
+ for i in range(start_line, len(source_lines)):
147
+ if end_pattern in source_lines[i]:
148
+ end_line = i
149
+ break
150
+ if end_line == -1:
151
+ err_msg = (
152
+ f"End pattern '{end_pattern}' not found after {occurrence_str}start"
153
+ f" pattern '{start_pattern}' (line {start_line + 1}) in"
154
+ f" '{source_file_path}'."
155
+ )
156
+ coder.io.tool_error(err_msg)
157
+ return f"Error: {err_msg}"
158
+ elif line_count:
159
+ try:
160
+ line_count = int(line_count)
161
+ if line_count <= 0:
162
+ raise ValueError("Line count must be positive")
163
+ end_line = min(start_line + line_count - 1, len(source_lines) - 1)
164
+ except ValueError:
165
+ coder.io.tool_error(
166
+ f"Invalid line_count value: '{line_count}'. Must be a positive integer."
167
+ )
168
+ return f"Error: Invalid line_count value '{line_count}'"
169
+ else:
170
+ end_line = start_line # Extract just the start line if no end specified
171
+
172
+ # --- Prepare Content Changes ---
173
+ extracted_lines = source_lines[start_line : end_line + 1]
174
+ new_source_lines = source_lines[:start_line] + source_lines[end_line + 1 :]
175
+ new_source_content = "\n".join(new_source_lines)
176
+
177
+ # Append extracted lines to target content, ensuring a newline if target wasn't empty
178
+ extracted_block = "\n".join(extracted_lines)
179
+ if target_content and not target_content.endswith("\n"):
180
+ target_content += "\n" # Add newline before appending if needed
181
+ new_target_content = target_content + extracted_block
182
+
183
+ # --- Generate Diffs ---
184
+ source_diff_snippet = generate_unified_diff_snippet(
185
+ source_content, new_source_content, rel_source_path
186
+ )
187
+ target_insertion_line = len(target_content.splitlines()) if target_content else 0
188
+ target_diff_snippet = generate_unified_diff_snippet(
189
+ target_content, new_target_content, rel_target_path
190
+ )
191
+
192
+ # --- Handle Dry Run ---
193
+ if dry_run:
194
+ num_extracted = end_line - start_line + 1
195
+ target_action = "append to" if target_exists else "create"
196
+ coder.io.tool_output(
197
+ f"Dry run: Would extract {num_extracted} lines (from {occurrence_str}start"
198
+ f" pattern '{start_pattern}') in {source_file_path} and {target_action}"
199
+ f" {target_file_path}"
200
+ )
201
+ # Provide more informative dry run response with diffs
202
+ return (
203
+ f"Dry run: Would extract {num_extracted} lines from {rel_source_path} and"
204
+ f" {target_action} {rel_target_path}.\nSource Diff"
205
+ f" (Deletion):\n{source_diff_snippet}\nTarget Diff"
206
+ f" (Insertion):\n{target_diff_snippet}"
207
+ )
208
+
209
+ # --- Apply Changes (Not Dry Run) ---
210
+ # Apply source change
211
+ source_metadata = {
212
+ "start_line": start_line + 1,
213
+ "end_line": end_line + 1,
214
+ "start_pattern": start_pattern,
215
+ "end_pattern": end_pattern,
216
+ "line_count": line_count,
217
+ "near_context": near_context,
218
+ "occurrence": occurrence,
219
+ "extracted_content": extracted_block,
220
+ "target_file": rel_target_path,
221
+ }
222
+ source_change_id = apply_change(
223
+ coder,
224
+ abs_source_path,
225
+ rel_source_path,
226
+ source_content,
227
+ new_source_content,
228
+ "extractlines_source",
229
+ source_metadata,
230
+ )
231
+
232
+ # Apply target change
233
+ target_metadata = {
234
+ "insertion_line": target_insertion_line + 1,
235
+ "inserted_content": extracted_block,
236
+ "source_file": rel_source_path,
237
+ }
238
+ target_change_id = apply_change(
239
+ coder,
240
+ abs_target_path,
241
+ rel_target_path,
242
+ target_content,
243
+ new_target_content,
244
+ "extractlines_target",
245
+ target_metadata,
246
+ )
247
+
248
+ # --- Update Context ---
249
+ coder.files_edited_by_tools.add(rel_source_path)
250
+ coder.files_edited_by_tools.add(rel_target_path)
251
+
252
+ if not target_exists:
253
+ # Add the newly created file to editable context
254
+ coder.abs_fnames.add(abs_target_path)
255
+ coder.io.tool_output(
256
+ f"✨ Created and added '{target_file_path}' to editable context."
257
+ )
258
+
259
+ # --- Return Result ---
260
+ num_extracted = end_line - start_line + 1
261
+ target_action = "appended to" if target_exists else "created"
262
+ coder.io.tool_output(
263
+ f"✅ Extracted {num_extracted} lines from {rel_source_path} (change_id:"
264
+ f" {source_change_id}) and {target_action} {rel_target_path} (change_id:"
265
+ f" {target_change_id})"
266
+ )
267
+ # Provide more informative success response with change IDs and diffs
268
+ return (
269
+ f"Successfully extracted {num_extracted} lines from {rel_source_path} and"
270
+ f" {target_action} {rel_target_path}.\nSource Change ID:"
271
+ f" {source_change_id}\nSource Diff (Deletion):\n{source_diff_snippet}\nTarget"
272
+ f" Change ID: {target_change_id}\nTarget Diff"
273
+ f" (Insertion):\n{target_diff_snippet}"
274
+ )
275
+
276
+ except ToolError as e:
277
+ # Handle errors raised by utility functions or explicitly raised here
278
+ return handle_tool_error(coder, tool_name, e, add_traceback=False)
279
+ except Exception as e:
280
+ # Handle unexpected errors
281
+ return handle_tool_error(coder, tool_name, e)
@@ -0,0 +1,35 @@
1
+ from cecli.tools.utils.base_tool import BaseTool
2
+
3
+
4
+ class Tool(BaseTool):
5
+ NORM_NAME = "finished"
6
+ SCHEMA = {
7
+ "type": "function",
8
+ "function": {
9
+ "name": "Finished",
10
+ "description": (
11
+ "Declare that we are done with every single sub goal and no further work is needed."
12
+ ),
13
+ "parameters": {
14
+ "type": "object",
15
+ "properties": {},
16
+ "required": [],
17
+ },
18
+ },
19
+ }
20
+
21
+ @classmethod
22
+ def execute(cls, coder):
23
+ """
24
+ Mark that the current generation task needs no further effort.
25
+
26
+ This gives the LLM explicit control over when it can stop looping
27
+ """
28
+
29
+ if coder:
30
+ coder.agent_finished = True
31
+ # coder.io.tool_output("Task Finished!")
32
+ return "Task Finished!"
33
+
34
+ # coder.io.tool_Error("Error: Could not mark agent task as finished")
35
+ return "Error: Could not mark agent task as finished"
@@ -0,0 +1,132 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitbranch"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitBranch",
11
+ "description": (
12
+ "List branches in the repository with various filtering and formatting options."
13
+ ),
14
+ "parameters": {
15
+ "type": "object",
16
+ "properties": {
17
+ "remotes": {
18
+ "type": "boolean",
19
+ "description": "List remote-tracking branches (-r/--remotes flag)",
20
+ },
21
+ "all": {
22
+ "type": "boolean",
23
+ "description": "List both local and remote branches (-a/--all flag)",
24
+ },
25
+ "verbose": {
26
+ "type": "boolean",
27
+ "description": (
28
+ "Show verbose information including commit hash and subject (-v flag)"
29
+ ),
30
+ },
31
+ "very_verbose": {
32
+ "type": "boolean",
33
+ "description": (
34
+ "Show very verbose information including upstream branch (-vv flag)"
35
+ ),
36
+ },
37
+ "merged": {
38
+ "type": "string",
39
+ "description": "Show branches merged into specified commit (--merged flag)",
40
+ },
41
+ "no_merged": {
42
+ "type": "string",
43
+ "description": (
44
+ "Show branches not merged into specified commit (--no-merged flag)"
45
+ ),
46
+ },
47
+ "sort": {
48
+ "type": "string",
49
+ "description": (
50
+ "Sort branches by key (committerdate, authordate, refname, etc.)"
51
+ " (--sort flag)"
52
+ ),
53
+ },
54
+ "format": {
55
+ "type": "string",
56
+ "description": "Custom output format using placeholders (--format flag)",
57
+ },
58
+ "show_current": {
59
+ "type": "boolean",
60
+ "description": "Show only current branch name (--show-current flag)",
61
+ },
62
+ },
63
+ "required": [],
64
+ },
65
+ },
66
+ }
67
+
68
+ @classmethod
69
+ def execute(
70
+ cls,
71
+ coder,
72
+ remotes=False,
73
+ all=False,
74
+ verbose=False,
75
+ very_verbose=False,
76
+ merged=None,
77
+ no_merged=None,
78
+ sort=None,
79
+ format=None,
80
+ show_current=False,
81
+ ):
82
+ """
83
+ List branches in the repository with various filtering and formatting options.
84
+ """
85
+ if not coder.repo:
86
+ return "Not in a git repository."
87
+
88
+ try:
89
+ # Build git command arguments
90
+ args = []
91
+
92
+ # Handle boolean flags
93
+ if remotes:
94
+ args.append("--remotes")
95
+ if all:
96
+ args.append("--all")
97
+ if verbose:
98
+ args.append("--verbose")
99
+ if very_verbose:
100
+ args.append("--verbose")
101
+ args.append("--verbose")
102
+ if show_current:
103
+ args.append("--show-current")
104
+
105
+ # Handle string parameters
106
+ if merged:
107
+ args.extend(["--merged", merged])
108
+ if no_merged:
109
+ args.extend(["--no-merged", no_merged])
110
+ if sort:
111
+ args.extend(["--sort", sort])
112
+ if format:
113
+ args.extend(["--format", format])
114
+
115
+ # Execute git command
116
+ result = coder.repo.repo.git.branch(*args).strip()
117
+
118
+ # If no result and show_current was used, get current branch directly
119
+ if not result and show_current:
120
+ try:
121
+ head = coder.repo.repo.head
122
+ if head.is_detached:
123
+ return "HEAD (detached)"
124
+ return coder.repo.repo.active_branch.name
125
+ except ANY_GIT_ERROR:
126
+ return "No current branch found."
127
+
128
+ return result if result else "No branches found matching the criteria."
129
+
130
+ except ANY_GIT_ERROR as e:
131
+ coder.io.tool_error(f"Error running git branch: {e}")
132
+ return f"Error running git branch: {e}"
@@ -0,0 +1,49 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitdiff"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitDiff",
11
+ "description": (
12
+ "Show the diff between the current working directory and a git branch or commit."
13
+ ),
14
+ "parameters": {
15
+ "type": "object",
16
+ "properties": {
17
+ "branch": {
18
+ "type": "string",
19
+ "description": (
20
+ "The branch or commit hash to diff against. Defaults to HEAD."
21
+ ),
22
+ },
23
+ },
24
+ "required": [],
25
+ },
26
+ },
27
+ }
28
+
29
+ @classmethod
30
+ def execute(cls, coder, branch=None):
31
+ """
32
+ Show the diff between the current working directory and a git branch or commit.
33
+ """
34
+ if not coder.repo:
35
+ return "Not in a git repository."
36
+
37
+ try:
38
+ if branch:
39
+ # Diff working tree against the requested branch/commit
40
+ diff = coder.repo.diff_commits(False, branch, None)
41
+ else:
42
+ diff = coder.repo.diff_commits(False, "HEAD", None)
43
+
44
+ if not diff:
45
+ return "No differences found."
46
+ return diff
47
+ except ANY_GIT_ERROR as e:
48
+ coder.io.tool_error(f"Error running git diff: {e}")
49
+ return f"Error running git diff: {e}"
cecli/tools/git_log.py ADDED
@@ -0,0 +1,43 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitlog"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitLog",
11
+ "description": "Show the git log.",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {
15
+ "limit": {
16
+ "type": "integer",
17
+ "description": "The maximum number of commits to show. Defaults to 10.",
18
+ },
19
+ },
20
+ "required": [],
21
+ },
22
+ },
23
+ }
24
+
25
+ @classmethod
26
+ def execute(cls, coder, limit=10):
27
+ """
28
+ Show the git log.
29
+ """
30
+ if not coder.repo:
31
+ return "Not in a git repository."
32
+
33
+ try:
34
+ commits = list(coder.repo.repo.iter_commits(max_count=limit))
35
+ log_output = []
36
+ for commit in commits:
37
+ short_hash = commit.hexsha[:8]
38
+ message = commit.message.strip().split("\n")[0]
39
+ log_output.append(f"{short_hash} {message}")
40
+ return "\n".join(log_output)
41
+ except ANY_GIT_ERROR as e:
42
+ coder.io.tool_error(f"Error running git log: {e}")
43
+ return f"Error running git log: {e}"
@@ -0,0 +1,39 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitremote"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitRemote",
11
+ "description": "List remote repositories.",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {},
15
+ "required": [],
16
+ },
17
+ },
18
+ }
19
+
20
+ @classmethod
21
+ def execute(cls, coder):
22
+ """
23
+ List remote repositories.
24
+ """
25
+ if not coder.repo:
26
+ return "Not in a git repository."
27
+
28
+ try:
29
+ remotes = coder.repo.repo.remotes
30
+ if not remotes:
31
+ return "No remotes configured."
32
+
33
+ result = []
34
+ for remote in remotes:
35
+ result.append(f"{remote.name}\t{remote.url}")
36
+ return "\n".join(result)
37
+ except ANY_GIT_ERROR as e:
38
+ coder.io.tool_error(f"Error running git remote: {e}")
39
+ return f"Error running git remote: {e}"
@@ -0,0 +1,37 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitshow"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitShow",
11
+ "description": "Show various types of objects (blobs, trees, tags, and commits).",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {
15
+ "object": {
16
+ "type": "string",
17
+ "description": "The object to show. Defaults to HEAD.",
18
+ },
19
+ },
20
+ "required": [],
21
+ },
22
+ },
23
+ }
24
+
25
+ @classmethod
26
+ def execute(cls, coder, object="HEAD"):
27
+ """
28
+ Show various types of objects (blobs, trees, tags, and commits).
29
+ """
30
+ if not coder.repo:
31
+ return "Not in a git repository."
32
+
33
+ try:
34
+ return coder.repo.repo.git.show(object)
35
+ except ANY_GIT_ERROR as e:
36
+ coder.io.tool_error(f"Error running git show: {e}")
37
+ return f"Error running git show: {e}"
@@ -0,0 +1,32 @@
1
+ from cecli.repo import ANY_GIT_ERROR
2
+ from cecli.tools.utils.base_tool import BaseTool
3
+
4
+
5
+ class Tool(BaseTool):
6
+ NORM_NAME = "gitstatus"
7
+ SCHEMA = {
8
+ "type": "function",
9
+ "function": {
10
+ "name": "GitStatus",
11
+ "description": "Show the working tree status.",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {},
15
+ "required": [],
16
+ },
17
+ },
18
+ }
19
+
20
+ @classmethod
21
+ def execute(cls, coder):
22
+ """
23
+ Show the working tree status.
24
+ """
25
+ if not coder.repo:
26
+ return "Not in a git repository."
27
+
28
+ try:
29
+ return coder.repo.repo.git.status()
30
+ except ANY_GIT_ERROR as e:
31
+ coder.io.tool_error(f"Error running git status: {e}")
32
+ return f"Error running git status: {e}"