tunacode-cli 0.0.55__py3-none-any.whl → 0.0.78.6__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.
Potentially problematic release.
This version of tunacode-cli might be problematic. Click here for more details.
- tunacode/cli/commands/__init__.py +2 -2
- tunacode/cli/commands/implementations/__init__.py +2 -3
- tunacode/cli/commands/implementations/command_reload.py +48 -0
- tunacode/cli/commands/implementations/debug.py +2 -2
- tunacode/cli/commands/implementations/development.py +10 -8
- tunacode/cli/commands/implementations/model.py +357 -29
- tunacode/cli/commands/implementations/quickstart.py +43 -0
- tunacode/cli/commands/implementations/system.py +96 -3
- tunacode/cli/commands/implementations/template.py +0 -2
- tunacode/cli/commands/registry.py +139 -5
- tunacode/cli/commands/slash/__init__.py +32 -0
- tunacode/cli/commands/slash/command.py +157 -0
- tunacode/cli/commands/slash/loader.py +135 -0
- tunacode/cli/commands/slash/processor.py +294 -0
- tunacode/cli/commands/slash/types.py +93 -0
- tunacode/cli/commands/slash/validator.py +400 -0
- tunacode/cli/main.py +23 -2
- tunacode/cli/repl.py +217 -190
- tunacode/cli/repl_components/command_parser.py +38 -4
- tunacode/cli/repl_components/error_recovery.py +85 -4
- tunacode/cli/repl_components/output_display.py +12 -1
- tunacode/cli/repl_components/tool_executor.py +1 -1
- tunacode/configuration/defaults.py +12 -3
- tunacode/configuration/key_descriptions.py +284 -0
- tunacode/configuration/settings.py +0 -1
- tunacode/constants.py +12 -40
- tunacode/core/agents/__init__.py +43 -2
- tunacode/core/agents/agent_components/__init__.py +7 -0
- tunacode/core/agents/agent_components/agent_config.py +249 -55
- tunacode/core/agents/agent_components/agent_helpers.py +43 -13
- tunacode/core/agents/agent_components/node_processor.py +179 -139
- tunacode/core/agents/agent_components/response_state.py +123 -6
- tunacode/core/agents/agent_components/state_transition.py +116 -0
- tunacode/core/agents/agent_components/streaming.py +296 -0
- tunacode/core/agents/agent_components/task_completion.py +19 -6
- tunacode/core/agents/agent_components/tool_buffer.py +21 -1
- tunacode/core/agents/agent_components/tool_executor.py +10 -0
- tunacode/core/agents/main.py +522 -370
- tunacode/core/agents/main_legact.py +538 -0
- tunacode/core/agents/prompts.py +66 -0
- tunacode/core/agents/utils.py +29 -121
- tunacode/core/code_index.py +83 -29
- tunacode/core/setup/__init__.py +0 -2
- tunacode/core/setup/config_setup.py +110 -20
- tunacode/core/setup/config_wizard.py +230 -0
- tunacode/core/setup/coordinator.py +14 -5
- tunacode/core/state.py +16 -20
- tunacode/core/token_usage/usage_tracker.py +5 -3
- tunacode/core/tool_authorization.py +352 -0
- tunacode/core/tool_handler.py +67 -40
- tunacode/exceptions.py +119 -5
- tunacode/prompts/system.xml +751 -0
- tunacode/services/mcp.py +125 -7
- tunacode/setup.py +5 -25
- tunacode/tools/base.py +163 -0
- tunacode/tools/bash.py +110 -1
- tunacode/tools/glob.py +332 -34
- tunacode/tools/grep.py +179 -82
- tunacode/tools/grep_components/result_formatter.py +98 -4
- tunacode/tools/list_dir.py +132 -2
- tunacode/tools/prompts/bash_prompt.xml +72 -0
- tunacode/tools/prompts/glob_prompt.xml +45 -0
- tunacode/tools/prompts/grep_prompt.xml +98 -0
- tunacode/tools/prompts/list_dir_prompt.xml +31 -0
- tunacode/tools/prompts/react_prompt.xml +23 -0
- tunacode/tools/prompts/read_file_prompt.xml +54 -0
- tunacode/tools/prompts/run_command_prompt.xml +64 -0
- tunacode/tools/prompts/update_file_prompt.xml +53 -0
- tunacode/tools/prompts/write_file_prompt.xml +37 -0
- tunacode/tools/react.py +153 -0
- tunacode/tools/read_file.py +91 -0
- tunacode/tools/run_command.py +114 -0
- tunacode/tools/schema_assembler.py +167 -0
- tunacode/tools/update_file.py +94 -0
- tunacode/tools/write_file.py +86 -0
- tunacode/tools/xml_helper.py +83 -0
- tunacode/tutorial/__init__.py +9 -0
- tunacode/tutorial/content.py +98 -0
- tunacode/tutorial/manager.py +182 -0
- tunacode/tutorial/steps.py +124 -0
- tunacode/types.py +20 -27
- tunacode/ui/completers.py +434 -50
- tunacode/ui/config_dashboard.py +585 -0
- tunacode/ui/console.py +63 -11
- tunacode/ui/input.py +20 -3
- tunacode/ui/keybindings.py +7 -4
- tunacode/ui/model_selector.py +395 -0
- tunacode/ui/output.py +40 -19
- tunacode/ui/panels.py +212 -43
- tunacode/ui/path_heuristics.py +91 -0
- tunacode/ui/prompt_manager.py +5 -1
- tunacode/ui/tool_ui.py +33 -10
- tunacode/utils/api_key_validation.py +93 -0
- tunacode/utils/config_comparator.py +340 -0
- tunacode/utils/json_utils.py +206 -0
- tunacode/utils/message_utils.py +14 -4
- tunacode/utils/models_registry.py +593 -0
- tunacode/utils/ripgrep.py +332 -9
- tunacode/utils/text_utils.py +18 -1
- tunacode/utils/user_configuration.py +45 -0
- tunacode_cli-0.0.78.6.dist-info/METADATA +260 -0
- tunacode_cli-0.0.78.6.dist-info/RECORD +158 -0
- {tunacode_cli-0.0.55.dist-info → tunacode_cli-0.0.78.6.dist-info}/WHEEL +1 -2
- tunacode/cli/commands/implementations/todo.py +0 -217
- tunacode/context.py +0 -71
- tunacode/core/setup/git_safety_setup.py +0 -182
- tunacode/prompts/system.md +0 -731
- tunacode/tools/read_file_async_poc.py +0 -196
- tunacode/tools/todo.py +0 -349
- tunacode_cli-0.0.55.dist-info/METADATA +0 -322
- tunacode_cli-0.0.55.dist-info/RECORD +0 -126
- tunacode_cli-0.0.55.dist-info/top_level.txt +0 -1
- {tunacode_cli-0.0.55.dist-info → tunacode_cli-0.0.78.6.dist-info}/entry_points.txt +0 -0
- {tunacode_cli-0.0.55.dist-info → tunacode_cli-0.0.78.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
tunacode/__init__.py,sha256=yUul8igNYMfUrHnYfioIGAqvrH8b5BKiO_pt1wVnmd0,119
|
|
2
|
+
tunacode/constants.py,sha256=r08u5GRo9jK_ySVI4g_itxnvNs09kRVrrnazwavAVes,5151
|
|
3
|
+
tunacode/exceptions.py,sha256=m80njR-LqBXhFAEOPqCE7N2QPU4Fkjlf_f6CWKO0_Is,8479
|
|
4
|
+
tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
tunacode/setup.py,sha256=m8-198OY5Yp9NSR3OzS_rWeFQPD83ex2UCazDarjA04,1341
|
|
6
|
+
tunacode/types.py,sha256=XllBT4miOtpz4maY5Q6qWoWJLhZB4ksVuMEWDtPlGps,8366
|
|
7
|
+
tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
|
|
8
|
+
tunacode/cli/main.py,sha256=cRqSto2PNYipgGxOX5Q4zabsYR0YCwbaVmGjAx0FuTA,3699
|
|
9
|
+
tunacode/cli/repl.py,sha256=L4dtH7j9io9SKzD7S8heFC41bgTSA5NKR2iaVQLA8U4,17315
|
|
10
|
+
tunacode/cli/commands/__init__.py,sha256=XmDNszfG0AnLK46P6OHP8LR6khKNYahXfqgmkSJt6wc,1758
|
|
11
|
+
tunacode/cli/commands/base.py,sha256=Ge_lNQA-GDfcb1Ap1oznCH3UrifBiHH3bA9DNL-tCDw,2519
|
|
12
|
+
tunacode/cli/commands/registry.py,sha256=WMmZCK5rMDrtW9cjKbK51GDquvE-dfO_m36XzFVdwcA,14906
|
|
13
|
+
tunacode/cli/commands/template_shortcut.py,sha256=ApYTPkDVBRaLxa7rWaPrsGcJdkR7eg09k18KyTjYg_E,3447
|
|
14
|
+
tunacode/cli/commands/implementations/__init__.py,sha256=QLOS4S2mXxRH65bIXcX3r4IMek_aVaRNJMK1wW0oN2I,1019
|
|
15
|
+
tunacode/cli/commands/implementations/command_reload.py,sha256=GyjeKvJbgE4VYkaasGajspdk9wffumZMNLzfCUeNazM,1555
|
|
16
|
+
tunacode/cli/commands/implementations/conversation.py,sha256=ZijCNaRi1p5v1Q-IaVHtU2_BripSW3JCVKTtqFkOUjg,4676
|
|
17
|
+
tunacode/cli/commands/implementations/debug.py,sha256=w2fUgqFB4ipBCmNotbvaOOVW4OiCwJM6MXNWlyKyoqs,6754
|
|
18
|
+
tunacode/cli/commands/implementations/development.py,sha256=arMtmRX8Nw7irbeV7xCbkma5iEOp5r9sS7OQ26KItYk,2839
|
|
19
|
+
tunacode/cli/commands/implementations/model.py,sha256=dFRmMlcN78TdGMFX-B2OPyoWqOVQL72XC8ayPyUQmpA,16166
|
|
20
|
+
tunacode/cli/commands/implementations/quickstart.py,sha256=53H7ubYMGMgmCeYCs6o_F91Q4pd3Ky008lCU4GPuRP8,1363
|
|
21
|
+
tunacode/cli/commands/implementations/system.py,sha256=EV3-_bvygRWdVRAIUqm5pGKIZ8uKWE2DcHWrKX9-I0w,12023
|
|
22
|
+
tunacode/cli/commands/implementations/template.py,sha256=Akm4kz0sQCx3n0KWQmACQrVyvTLhavC9I2Eg9SRjNu8,5394
|
|
23
|
+
tunacode/cli/commands/slash/__init__.py,sha256=O5EiITHZJgzIciKA_nylj5PyOZNvXE9jPmOHioDk3cU,824
|
|
24
|
+
tunacode/cli/commands/slash/command.py,sha256=ewtyLJNAW0cJLwpSiycyVH0LpqsR3xVqCBhSym7d_7w,6329
|
|
25
|
+
tunacode/cli/commands/slash/loader.py,sha256=i37m_reKbcezK405-J-OmnpyBzV_QXoZB3Oa_bPw8kY,5632
|
|
26
|
+
tunacode/cli/commands/slash/processor.py,sha256=JQ_sE9Vu7LAdSnUmMz-hBPfD8E60aIHPNeaFMn7PQjM,11751
|
|
27
|
+
tunacode/cli/commands/slash/types.py,sha256=v52tDX7T5I3nEETakloXLQzJqWXSyxcM1K5FbFNdtzw,2375
|
|
28
|
+
tunacode/cli/commands/slash/validator.py,sha256=UKPE4dijq6VbhcyKcAnuij7Gw1IkvHUijheeiWWEer0,13985
|
|
29
|
+
tunacode/cli/repl_components/__init__.py,sha256=5ZjPJ3yUvZ5x6Vg9EYJ03-tdxfEEdmfradCmwSlVY3E,334
|
|
30
|
+
tunacode/cli/repl_components/command_parser.py,sha256=iRSs4K6aKjKstNNNCYQoGWd3hN1FHDrQrOa7uB9z0Z4,2376
|
|
31
|
+
tunacode/cli/repl_components/error_recovery.py,sha256=1Zm9W_AE9WKfv8n5LnTA_myAu9qotRPEVt72_hnaSq4,6222
|
|
32
|
+
tunacode/cli/repl_components/output_display.py,sha256=7a5CIUjm99RUyK7jj1taEySI1lKlcQxa3T3DzKUa4Go,1107
|
|
33
|
+
tunacode/cli/repl_components/tool_executor.py,sha256=dbvrJFfL1i2kf2XpPXhvCgbTKVSyCAA110brA2ze5B4,3142
|
|
34
|
+
tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
|
|
35
|
+
tunacode/configuration/defaults.py,sha256=eFUDD73tTWa3HM320BEn0VWM-XuDKW7d6m32qTK2eRI,1313
|
|
36
|
+
tunacode/configuration/key_descriptions.py,sha256=tvFhdA98RgRoE-Xsb5gfuzB3HSl_GY568Q5vg0C8s2A,11249
|
|
37
|
+
tunacode/configuration/models.py,sha256=buH8ZquvcYI3OQBDIZeJ08cu00rSCeNABtUwl3VQS0E,4103
|
|
38
|
+
tunacode/configuration/settings.py,sha256=zLeTmntMY94M87aD9xPNhS4yc8yApdPWltw6u4slP2Q,1020
|
|
39
|
+
tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
tunacode/core/code_index.py,sha256=2qxEn2eTIegV4F_gLeZO5lAOv8mkf4Y_t21whZ9F2Fk,17370
|
|
41
|
+
tunacode/core/state.py,sha256=esGjB3zCfdwqcZzurH7oxAC5Klkd0gskkAgY3fviCDU,6367
|
|
42
|
+
tunacode/core/tool_authorization.py,sha256=VBPNCWxoxlq_dEuo8EfkQoSwCJqCdn0vOIu9spB82v4,11655
|
|
43
|
+
tunacode/core/tool_handler.py,sha256=PzLg3VYtIGj9dnyJ4kCfCwyncmuxzsMgPwQqn2jmzqI,4444
|
|
44
|
+
tunacode/core/agents/__init__.py,sha256=HmrifkzSUykt4hcL-SeZUgEshYVSZBxLDUSgaS81-A8,1107
|
|
45
|
+
tunacode/core/agents/main.py,sha256=H3PHfQCvDYazlu-hqzlmeEUE-uImjSf1aqYcBmb0vQo,23314
|
|
46
|
+
tunacode/core/agents/main_legact.py,sha256=5p5k7Em1_dH5ZoytWEhPHYKx3Nhb71KoE_TN-mwOfOE,20856
|
|
47
|
+
tunacode/core/agents/prompts.py,sha256=Eps3qQm8zdgPnyYOvRYwINMGVa71ttuqGlgtH17-3ag,2357
|
|
48
|
+
tunacode/core/agents/utils.py,sha256=jqR7xIeeqj45SbFjUcIBi1-f10Af8iKwM2Abezvb0II,10607
|
|
49
|
+
tunacode/core/agents/agent_components/__init__.py,sha256=65V5ijSKen0F0zLvUO3AkZJmCrocSW3lEbqNPrHqxoc,1706
|
|
50
|
+
tunacode/core/agents/agent_components/agent_config.py,sha256=9mjZlRVUTSJh7Y2fbBmyLrojBHfSGpqwQ4ES5-C6ozc,11872
|
|
51
|
+
tunacode/core/agents/agent_components/agent_helpers.py,sha256=pfoP_pX4N1g950UDcLkZS-FSq5at3IvNDZhJStt7IWk,9157
|
|
52
|
+
tunacode/core/agents/agent_components/json_tool_parser.py,sha256=HuyNT0rs-ppx_gLAI2e0XMVGbR_F0WXZfP3sx38VoMg,3447
|
|
53
|
+
tunacode/core/agents/agent_components/message_handler.py,sha256=KJGOtb9VhumgZpxxwO45HrKLhU9_MwuoWRsSQwJviNU,3704
|
|
54
|
+
tunacode/core/agents/agent_components/node_processor.py,sha256=2DqM__dU2bNlcrCS7ptD05a3xI7mR4GURCj5DzofuiY,21533
|
|
55
|
+
tunacode/core/agents/agent_components/response_state.py,sha256=XHaJrkn4kWecVM008kWf_nEAkoR2UPYfqaH-azdzhj8,5061
|
|
56
|
+
tunacode/core/agents/agent_components/result_wrapper.py,sha256=9CFK0wpsfZx2WT4PBHfkSv22GxL1gAQuUYVMlmYtCJU,1761
|
|
57
|
+
tunacode/core/agents/agent_components/state_transition.py,sha256=uyvLJriexosBDQIrxbVDLR_luvXAMG6tnDsX10mbZcI,4077
|
|
58
|
+
tunacode/core/agents/agent_components/streaming.py,sha256=hVtxxZTkJZPSqlQxi5twRoWz0FXRApQ8pG83zRNSHSU,15207
|
|
59
|
+
tunacode/core/agents/agent_components/task_completion.py,sha256=iLzwspVDtkXTJNQFk8YNSbb6wzMWEelmSMwSnzLIzbk,1193
|
|
60
|
+
tunacode/core/agents/agent_components/tool_buffer.py,sha256=h9PeP9glW_rlGKElH-JD_CPUVhS3tS4AUwZSn4oINzg,1520
|
|
61
|
+
tunacode/core/agents/agent_components/tool_executor.py,sha256=MMGjRmjBnuyYnKh64fMTAQJujIEgDizQFMUdNSbP0Cc,2401
|
|
62
|
+
tunacode/core/agents/agent_components/truncation_checker.py,sha256=XbJ3wwtdC4NhgIMIvFR0z_cfNnYMkiYAZo9zGDBPU8Y,2685
|
|
63
|
+
tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
+
tunacode/core/background/manager.py,sha256=AxNcuuE7T2pqeI2lLIGJgaS_jEw60YzBfZY9EOY54fc,1160
|
|
65
|
+
tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
+
tunacode/core/logging/__init__.py,sha256=vykmcZPOo_FhIPJvPuH0gbUqprpGp9Sbrj13X0iOil4,709
|
|
67
|
+
tunacode/core/logging/config.py,sha256=bhJ6KYrEliKC5BehXKXZHHPBJUBX0g5O3uxbr8qUKQ0,2515
|
|
68
|
+
tunacode/core/logging/formatters.py,sha256=uWx-M0jSvsAVo5JVdCK1VIVawXNONjJ2CvMwPuuUTg8,1236
|
|
69
|
+
tunacode/core/logging/handlers.py,sha256=lkLczpcI6kSammSdjrCccosGMrRdcAA_3UmuTOiPnxg,3788
|
|
70
|
+
tunacode/core/logging/logger.py,sha256=9RjRuX0GoUojRJ8WnJGQPFdXiluiJMCoFmvc8xEioB8,142
|
|
71
|
+
tunacode/core/setup/__init__.py,sha256=edzZ5tdWPdokPaOuFgYGEUGY_Fcn6bcWSiDOhGGZTBc,372
|
|
72
|
+
tunacode/core/setup/agent_setup.py,sha256=tpOIW85C6o1m8pwAZQBIMKxKIyBUOpHHn4JJmDBFH3Q,1403
|
|
73
|
+
tunacode/core/setup/base.py,sha256=FMjBQQS_q3KOxHqfg7NJGmKq-1nxC40htiPZprzTu7I,970
|
|
74
|
+
tunacode/core/setup/config_setup.py,sha256=lzVsnXZ6jnrD1tasjd4BDPFrSrFNcreZXEf3Twp_re0,19192
|
|
75
|
+
tunacode/core/setup/config_wizard.py,sha256=0QnJk6UzdXhfNWlu_YgndLP5oMyxJEt-zzGdQaRFjnU,9376
|
|
76
|
+
tunacode/core/setup/coordinator.py,sha256=_tGi5QuV00IJ4QK8mYfpaHZn0esB6CWCuiTE55zhSuw,2407
|
|
77
|
+
tunacode/core/setup/environment_setup.py,sha256=n3IrObKEynHZSwtUJ1FddMg2C4sHz7ca42awemImV8s,2225
|
|
78
|
+
tunacode/core/setup/template_setup.py,sha256=0lDGhNVCvGN7ykqHnl3pj4CONH3I2PvMzkmIZibfSoc,2640
|
|
79
|
+
tunacode/core/token_usage/api_response_parser.py,sha256=plLltHg4zGVzxjv3MFj45bbd-NOJeT_v3P0Ki4zlvn4,1831
|
|
80
|
+
tunacode/core/token_usage/cost_calculator.py,sha256=RjO-O0JENBuGOrWP7QgBZlZxeXC-PAIr8tj_9p_BxOU,2058
|
|
81
|
+
tunacode/core/token_usage/usage_tracker.py,sha256=lF-ehx-UQnorS4T1Xxa06GGRRjpaEnfmZl5LukGW9LY,6068
|
|
82
|
+
tunacode/prompts/system.xml,sha256=CdUctusc2qBoTYF3zWAzXv9djrqAZcj68-eyT3FF714,25122
|
|
83
|
+
tunacode/services/__init__.py,sha256=w_E8QK6RnvKSvU866eDe8BCRV26rAm4d3R-Yg06OWCU,19
|
|
84
|
+
tunacode/services/mcp.py,sha256=AXDbEEDiVA6VhcGUmSm4uo7cBk-2qBHp-j6r57Cjt3k,7573
|
|
85
|
+
tunacode/templates/__init__.py,sha256=ssEOPrPjyCywtKI-QFcoqcWhMjlfI5TbI8Ip0_wyqGM,241
|
|
86
|
+
tunacode/templates/loader.py,sha256=6_Dk4jX47_GKUAWxlHG2Mzkl9lkXFUOiAdlcJqb6rBA,6765
|
|
87
|
+
tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
|
|
88
|
+
tunacode/tools/base.py,sha256=PqXBYbXncGoUDWrLPwMxLJiM0CLFqGmieIMBnoi3TL8,12767
|
|
89
|
+
tunacode/tools/bash.py,sha256=3fQgeJSm0bCwNbr3DoGYGiDbagGMl0GtzABeoUWLUrU,13160
|
|
90
|
+
tunacode/tools/glob.py,sha256=OEs-DZmXGn1ak-hcMBLJC3vMo2hwU2O-C5eauRdm1dY,22998
|
|
91
|
+
tunacode/tools/grep.py,sha256=cI73BKgW-StCVsGyjWowgPrCEHqptOvH3MA82ZHwxK8,21597
|
|
92
|
+
tunacode/tools/list_dir.py,sha256=aJ2FdAUU-HxOmAwBk188KYIYB94thESIrSBflzoUlYs,12402
|
|
93
|
+
tunacode/tools/react.py,sha256=qEXhtxFM3skoz__L9R0Rabt1bmKdNkRyFMyAgNB_TFo,5602
|
|
94
|
+
tunacode/tools/read_file.py,sha256=Xy8vkckjq8kBNNYJMpMhq0pabVi4Kp8b57C3C3picI4,6729
|
|
95
|
+
tunacode/tools/run_command.py,sha256=C267wJG6uw2goSTzLhCPTeDphoI0wXTC9zX043iagks,8846
|
|
96
|
+
tunacode/tools/schema_assembler.py,sha256=sUePWvprfTHz9hau1q7hmWd12ew3rHdbASAGkpjBhuM,5507
|
|
97
|
+
tunacode/tools/update_file.py,sha256=0KTbEe1awS53CZPh1G3F3-TWuemWWBuDVQhcRYwXKOg,7619
|
|
98
|
+
tunacode/tools/write_file.py,sha256=WHEXdUKqUHZZ8Jh1muyupJgjud-x6h99x7qAMaloLao,6021
|
|
99
|
+
tunacode/tools/xml_helper.py,sha256=iDEUeLDNWwdGFyb8T9Vqfo_V7oX7oXm4l3IFPTdJtCM,2996
|
|
100
|
+
tunacode/tools/grep_components/__init__.py,sha256=qy3kwzxOiE6ydlRzpCC39TaIp5BJc5X_bRfXukiu4eM,266
|
|
101
|
+
tunacode/tools/grep_components/file_filter.py,sha256=-XYlmVLOipjuAGdLhHDApLMKZJ1qtlzRUXvOvHc7VYU,3152
|
|
102
|
+
tunacode/tools/grep_components/pattern_matcher.py,sha256=ZvEUqBZ6UWf9wZzb1DIRGSTFQuJCBV0GJG3DVG4r4Ss,5177
|
|
103
|
+
tunacode/tools/grep_components/result_formatter.py,sha256=S2TKdkJ81akFWyhwico0xR4jSx4yubfqchErEW-mEDQ,5223
|
|
104
|
+
tunacode/tools/grep_components/search_result.py,sha256=xzb_htSANuPIPVWViPAqIMsCCWVA8loxWdaZOA8RqMs,869
|
|
105
|
+
tunacode/tools/prompts/bash_prompt.xml,sha256=TzbZDFPhpRdYit0w3AVX66uCtJGDQhrdCEqY_FbHSC8,4051
|
|
106
|
+
tunacode/tools/prompts/glob_prompt.xml,sha256=G_ZTrHrhgzL3IvO9GIZPMBT6uEKy6AUU_xYTl7ZVPsU,1940
|
|
107
|
+
tunacode/tools/prompts/grep_prompt.xml,sha256=yxZcebUH_TtmllepXUdPnifr1TFlG0jsk3o1wOjl3mM,4944
|
|
108
|
+
tunacode/tools/prompts/list_dir_prompt.xml,sha256=oijSGEMOVh7FglSFQUawQMmmutfC_msZYBJt_KC6mjs,1401
|
|
109
|
+
tunacode/tools/prompts/react_prompt.xml,sha256=etF23T96I5XFs8MczeScjF7NH6jeEHaPOOmwGBwnnv0,829
|
|
110
|
+
tunacode/tools/prompts/read_file_prompt.xml,sha256=K_5FxytYACoj45oAvAnzrrOgU5CJMs421jdzuckUZaE,3123
|
|
111
|
+
tunacode/tools/prompts/run_command_prompt.xml,sha256=JVz0CXdXrI6nthI9QaWN-b1OTTlbIy-TQ7_3MwBs7hI,2332
|
|
112
|
+
tunacode/tools/prompts/update_file_prompt.xml,sha256=TmIc8K6myqgT_eauYMZmHPfhj-y1S3Gcp680e40pfyA,2831
|
|
113
|
+
tunacode/tools/prompts/write_file_prompt.xml,sha256=n7Q2evuCT0NLEDcoiiBkFcjBeQayF66TF5u-bYplk7U,1610
|
|
114
|
+
tunacode/tutorial/__init__.py,sha256=JyTt2S2cy8u1PnoChBmcOPk1Ru7ElhierltCLqZ-2BY,163
|
|
115
|
+
tunacode/tutorial/content.py,sha256=qaQewFwXtKKEmzLH-4oMECGAa4Z4nd1qh2HfRWLpwyk,3278
|
|
116
|
+
tunacode/tutorial/manager.py,sha256=ZgkzSC6ZtYSDq5Ce_TfYk9O9cvgFSL-pXrLZb7_HStM,6309
|
|
117
|
+
tunacode/tutorial/steps.py,sha256=l2bbRVJuYlC186A-U1TIoMPBtLl4j053h4Wlzo1VO8c,4393
|
|
118
|
+
tunacode/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
|
|
119
|
+
tunacode/ui/completers.py,sha256=QAXnJeq5-p5BFkohCJ-VEe30U7ugetUXo7ZNO7kGMYM,19554
|
|
120
|
+
tunacode/ui/config_dashboard.py,sha256=iwY-52zTeC2EOVn7Cg6LKa2Soxcy9VAGZW-91qOGElI,22213
|
|
121
|
+
tunacode/ui/console.py,sha256=H9BoQpmo-rFpGFcfXW41XAFxbNZn4N7dmcg_PTPvORk,3801
|
|
122
|
+
tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
|
|
123
|
+
tunacode/ui/decorators.py,sha256=jJDNztO8MyX_IG1nqXAL8-sQUFjaAzBnc5BsM3ioX24,1955
|
|
124
|
+
tunacode/ui/input.py,sha256=Mg-w2FvZqf4aw0bS840KfxDq9NY1fMMrzOSlDqo0pD8,3430
|
|
125
|
+
tunacode/ui/keybindings.py,sha256=BGEP3-Gv4p_PbDmCJYy5eJsWhnGbDJpaK-o6xuXJ_Hw,1692
|
|
126
|
+
tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
|
|
127
|
+
tunacode/ui/logging_compat.py,sha256=5v6lcjVaG1CxdY1Zm9FAGr9H7Sy-tP6ihGfhP-5YvAY,1406
|
|
128
|
+
tunacode/ui/model_selector.py,sha256=PZH7P6C3sJMU8TAne-VAOCcdUSnwmBChUQ_gqaDiqHc,13449
|
|
129
|
+
tunacode/ui/output.py,sha256=oMozluhzospH8zGSj6Vu2egzWSCJgYSa-T1P7wS8iGM,6381
|
|
130
|
+
tunacode/ui/panels.py,sha256=EeXFMbITcuY44L_1rBpFyKc4tcfhILon10hB4g2BggM,18396
|
|
131
|
+
tunacode/ui/path_heuristics.py,sha256=YfAP7AteI5FCUH2jZX9erSLADfDuH4OCny96OWb0M-Q,2185
|
|
132
|
+
tunacode/ui/prompt_manager.py,sha256=YRtSKPe7uVaJOizNEoTghB82a01K9dnhN-PKka8ZbFU,4767
|
|
133
|
+
tunacode/ui/tool_descriptions.py,sha256=vk61JPIXy7gHNfJ--77maXgK6WwNwxqY47QYsw_a2uw,4126
|
|
134
|
+
tunacode/ui/tool_ui.py,sha256=tB1w01ffPVtWJn1veutcUrOZE6yb7t7kMqzxVNPfZZs,8132
|
|
135
|
+
tunacode/ui/utils.py,sha256=yvoCTz8AOdRfV0XIqUX3sgg88g_wntV9yhnQP6WzAVs,114
|
|
136
|
+
tunacode/ui/validators.py,sha256=MMIMT1I2v0l2jIy-gxX_4GSApvUTi8XWIOACr_dmoBA,758
|
|
137
|
+
tunacode/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
|
+
tunacode/utils/api_key_validation.py,sha256=djfayP2g01d7YDVQXZUdW5ZhFtWAWw5oPhHCo_p74t0,2677
|
|
139
|
+
tunacode/utils/bm25.py,sha256=fd59YQXovC8rXwZrdoqIAfFrLn_WCVjzCh0pkU22APE,1966
|
|
140
|
+
tunacode/utils/config_comparator.py,sha256=iMShhYCKlo0dXycbfpRu5rj3ckT460FoDvkbr5_-yTY,12879
|
|
141
|
+
tunacode/utils/diff_utils.py,sha256=V9QqQ0q4MfabVTnWptF3IXDp3estnfOKcJtDe_Sj14I,2372
|
|
142
|
+
tunacode/utils/file_utils.py,sha256=84g-MQRzmBI2aG_CuXsDl2OhvvWoSL7YdL5Kz_UKSwk,979
|
|
143
|
+
tunacode/utils/import_cache.py,sha256=q_xjJbtju05YbFopLDSkIo1hOtCx3DOTl3GQE5FFDgs,295
|
|
144
|
+
tunacode/utils/json_utils.py,sha256=cMVctSwwV9Z1c-rZdj6UuOlZwsUPSTF5oUruP6uPix0,6470
|
|
145
|
+
tunacode/utils/message_utils.py,sha256=V4MrZZPmwO22_MVGupMqtE5ltQEBwaSIqGD5LEb_bLw,1050
|
|
146
|
+
tunacode/utils/models_registry.py,sha256=Tn2ByGFV1yJsWumFYy6JuT0eVpuPeZ1Zxj6JYsRRy1g,21277
|
|
147
|
+
tunacode/utils/retry.py,sha256=AHdUzY6m-mwlT4OPXdtWWMAafL_NeS7JAMORGyM8c5k,4931
|
|
148
|
+
tunacode/utils/ripgrep.py,sha256=VdGWYPQ1zCwUidw2QicuVmG5OiAgqI93jAsjS3y3ksE,11001
|
|
149
|
+
tunacode/utils/security.py,sha256=i3eGKg4o-qY2S_ObTlEaHO93q14iBfiPXR5O7srHn58,6579
|
|
150
|
+
tunacode/utils/system.py,sha256=J8KqJ4ZqQrNSnM5rrJxPeMk9z2xQQp6dWtI1SKBY1-0,11121
|
|
151
|
+
tunacode/utils/text_utils.py,sha256=KBI_xARsttD03rnCipNHG2RsC-0HV_TPbraT36M9tEI,8218
|
|
152
|
+
tunacode/utils/token_counter.py,sha256=dmFuqVz4ywGFdLfAi5Mg9bAGf8v87Ek-mHU-R3fsYjI,2711
|
|
153
|
+
tunacode/utils/user_configuration.py,sha256=OA-L0BgWNbf9sWpc8lyivgLscwJdpdI8TAYbe0wRs1s,4836
|
|
154
|
+
tunacode_cli-0.0.78.6.dist-info/METADATA,sha256=UcS7USp5Eibu_5fxYd0n6feaOsXqV5kz3VgT3dbNRdc,9004
|
|
155
|
+
tunacode_cli-0.0.78.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
156
|
+
tunacode_cli-0.0.78.6.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
|
|
157
|
+
tunacode_cli-0.0.78.6.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
|
|
158
|
+
tunacode_cli-0.0.78.6.dist-info/RECORD,,
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
"""Todo command implementation."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
|
|
5
|
-
from rich.box import ROUNDED
|
|
6
|
-
from rich.table import Table
|
|
7
|
-
|
|
8
|
-
from tunacode.types import CommandArgs, CommandContext, CommandResult, TodoItem
|
|
9
|
-
from tunacode.ui import console as ui
|
|
10
|
-
|
|
11
|
-
from ..base import CommandCategory, CommandSpec, SimpleCommand
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class TodoCommand(SimpleCommand):
|
|
15
|
-
"""Manage todo items."""
|
|
16
|
-
|
|
17
|
-
spec = CommandSpec(
|
|
18
|
-
name="todo",
|
|
19
|
-
aliases=["/todo", "todos"],
|
|
20
|
-
description="Manage todo items.",
|
|
21
|
-
category=CommandCategory.DEVELOPMENT,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
async def execute(self, args: CommandArgs, context: CommandContext) -> CommandResult:
|
|
25
|
-
if not args:
|
|
26
|
-
await self.list_todos(context)
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
subcommand = args[0].lower()
|
|
30
|
-
subcommand_args = args[1:]
|
|
31
|
-
|
|
32
|
-
if subcommand == "list":
|
|
33
|
-
await self.list_todos(context)
|
|
34
|
-
elif subcommand == "add":
|
|
35
|
-
await self.add_todo(subcommand_args, context)
|
|
36
|
-
elif subcommand == "done":
|
|
37
|
-
await self.mark_done(subcommand_args, context)
|
|
38
|
-
elif subcommand == "update":
|
|
39
|
-
await self.update_todo(subcommand_args, context)
|
|
40
|
-
elif subcommand == "priority":
|
|
41
|
-
await self.set_priority(subcommand_args, context)
|
|
42
|
-
elif subcommand == "remove":
|
|
43
|
-
await self.remove_todo(subcommand_args, context)
|
|
44
|
-
elif subcommand == "clear":
|
|
45
|
-
await self.clear_todos(context)
|
|
46
|
-
else:
|
|
47
|
-
await ui.error(
|
|
48
|
-
"Invalid todo subcommand. Available subcommands: list, add, done, update, priority, remove, clear"
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
async def list_todos(self, context: CommandContext) -> None:
|
|
52
|
-
"""Display the todo list with Rich formatting."""
|
|
53
|
-
todos = context.state_manager.session.todos
|
|
54
|
-
if not todos:
|
|
55
|
-
await ui.info("No todos found.")
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
# Create Rich table
|
|
59
|
-
table = Table(show_header=True, box=ROUNDED, padding=(0, 1))
|
|
60
|
-
table.add_column("ID", style="bold cyan", width=4, justify="center")
|
|
61
|
-
table.add_column("Status", width=12, justify="center")
|
|
62
|
-
table.add_column("Task", style="white", min_width=20)
|
|
63
|
-
table.add_column("Priority", width=10, justify="center")
|
|
64
|
-
table.add_column("Created", style="dim", width=12)
|
|
65
|
-
|
|
66
|
-
# Sort todos by status and priority
|
|
67
|
-
pending = [t for t in todos if t.status == "pending"]
|
|
68
|
-
in_progress = [t for t in todos if t.status == "in_progress"]
|
|
69
|
-
completed = [t for t in todos if t.status == "completed"]
|
|
70
|
-
|
|
71
|
-
# Sort each group by priority (high->medium->low)
|
|
72
|
-
priority_order = {"high": 0, "medium": 1, "low": 2}
|
|
73
|
-
|
|
74
|
-
for group in [in_progress, pending, completed]:
|
|
75
|
-
group.sort(key=lambda x: priority_order.get(x.priority, 3))
|
|
76
|
-
|
|
77
|
-
# Add rows to table
|
|
78
|
-
for todo in in_progress + pending + completed:
|
|
79
|
-
# Status with emoji
|
|
80
|
-
if todo.status == "pending":
|
|
81
|
-
status_display = "○ pending"
|
|
82
|
-
elif todo.status == "in_progress":
|
|
83
|
-
status_display = "○ in progress"
|
|
84
|
-
else:
|
|
85
|
-
status_display = "✓ completed"
|
|
86
|
-
|
|
87
|
-
# Priority with color coding
|
|
88
|
-
if todo.priority == "high":
|
|
89
|
-
priority_display = "[red] high[/red]"
|
|
90
|
-
elif todo.priority == "medium":
|
|
91
|
-
priority_display = "[yellow] medium[/yellow]"
|
|
92
|
-
else:
|
|
93
|
-
priority_display = "[green] low[/green]"
|
|
94
|
-
|
|
95
|
-
# Format created date
|
|
96
|
-
created_display = todo.created_at.strftime("%m/%d %H:%M")
|
|
97
|
-
|
|
98
|
-
table.add_row(todo.id, status_display, todo.content, priority_display, created_display)
|
|
99
|
-
|
|
100
|
-
await ui.print(table)
|
|
101
|
-
|
|
102
|
-
async def add_todo(self, args: CommandArgs, context: CommandContext) -> None:
|
|
103
|
-
"""Add a new todo and show updated list."""
|
|
104
|
-
if not args:
|
|
105
|
-
await ui.error("Please provide a task to add.")
|
|
106
|
-
return
|
|
107
|
-
|
|
108
|
-
content = " ".join(args)
|
|
109
|
-
new_id = f"{int(datetime.now().timestamp() * 1000000)}"
|
|
110
|
-
new_todo = TodoItem(
|
|
111
|
-
id=new_id,
|
|
112
|
-
content=content,
|
|
113
|
-
status="pending",
|
|
114
|
-
priority="medium",
|
|
115
|
-
created_at=datetime.now(),
|
|
116
|
-
)
|
|
117
|
-
context.state_manager.add_todo(new_todo)
|
|
118
|
-
|
|
119
|
-
await ui.success(f"Todo created: {content}")
|
|
120
|
-
await self.list_todos(context)
|
|
121
|
-
|
|
122
|
-
async def mark_done(self, args: CommandArgs, context: CommandContext) -> None:
|
|
123
|
-
"""Mark a todo as done and show updated list."""
|
|
124
|
-
if not args:
|
|
125
|
-
await ui.error("Please provide a todo ID to mark as done.")
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
todo_id = args[0]
|
|
129
|
-
# Find the todo to get its content for feedback
|
|
130
|
-
todo_content = None
|
|
131
|
-
for todo in context.state_manager.session.todos:
|
|
132
|
-
if todo.id == todo_id:
|
|
133
|
-
todo_content = todo.content
|
|
134
|
-
break
|
|
135
|
-
|
|
136
|
-
if not todo_content:
|
|
137
|
-
await ui.error(f"Todo with id {todo_id} not found.")
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
context.state_manager.update_todo(todo_id, "completed")
|
|
141
|
-
await ui.success(f"Marked todo {todo_id} as done: {todo_content}")
|
|
142
|
-
await self.list_todos(context)
|
|
143
|
-
|
|
144
|
-
async def update_todo(self, args: CommandArgs, context: CommandContext) -> None:
|
|
145
|
-
"""Update a todo status and show updated list."""
|
|
146
|
-
if len(args) < 2:
|
|
147
|
-
await ui.error("Please provide a todo ID and a new status.")
|
|
148
|
-
return
|
|
149
|
-
|
|
150
|
-
todo_id = args[0]
|
|
151
|
-
new_status = args[1].lower()
|
|
152
|
-
if new_status not in ["pending", "in_progress", "completed"]:
|
|
153
|
-
await ui.error("Invalid status. Must be one of: pending, in_progress, completed")
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
for todo in context.state_manager.session.todos:
|
|
157
|
-
if todo.id == todo_id:
|
|
158
|
-
todo.status = new_status
|
|
159
|
-
await ui.success(f"Updated todo {todo_id} to status {new_status}: {todo.content}")
|
|
160
|
-
await self.list_todos(context)
|
|
161
|
-
return
|
|
162
|
-
|
|
163
|
-
await ui.error(f"Todo with id {todo_id} not found.")
|
|
164
|
-
|
|
165
|
-
async def set_priority(self, args: CommandArgs, context: CommandContext) -> None:
|
|
166
|
-
"""Set todo priority and show updated list."""
|
|
167
|
-
if len(args) < 2:
|
|
168
|
-
await ui.error("Please provide a todo ID and a new priority.")
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
todo_id = args[0]
|
|
172
|
-
new_priority = args[1].lower()
|
|
173
|
-
if new_priority not in ["high", "medium", "low"]:
|
|
174
|
-
await ui.error("Invalid priority. Must be one of: high, medium, low")
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
-
for todo in context.state_manager.session.todos:
|
|
178
|
-
if todo.id == todo_id:
|
|
179
|
-
todo.priority = new_priority
|
|
180
|
-
await ui.success(f"Set todo {todo_id} to priority {new_priority}: {todo.content}")
|
|
181
|
-
await self.list_todos(context)
|
|
182
|
-
return
|
|
183
|
-
|
|
184
|
-
await ui.error(f"Todo with id {todo_id} not found.")
|
|
185
|
-
|
|
186
|
-
async def remove_todo(self, args: CommandArgs, context: CommandContext) -> None:
|
|
187
|
-
"""Remove a todo and show updated list."""
|
|
188
|
-
if not args:
|
|
189
|
-
await ui.error("Please provide a todo ID to remove.")
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
todo_id = args[0]
|
|
193
|
-
# Find the todo to get its content for feedback
|
|
194
|
-
todo_content = None
|
|
195
|
-
for todo in context.state_manager.session.todos:
|
|
196
|
-
if todo.id == todo_id:
|
|
197
|
-
todo_content = todo.content
|
|
198
|
-
break
|
|
199
|
-
|
|
200
|
-
if not todo_content:
|
|
201
|
-
await ui.error(f"Todo with id {todo_id} not found.")
|
|
202
|
-
return
|
|
203
|
-
|
|
204
|
-
context.state_manager.remove_todo(todo_id)
|
|
205
|
-
await ui.success(f"Removed todo {todo_id}: {todo_content}")
|
|
206
|
-
await self.list_todos(context)
|
|
207
|
-
|
|
208
|
-
async def clear_todos(self, context: CommandContext) -> None:
|
|
209
|
-
"""Clear all todos and show confirmation."""
|
|
210
|
-
todo_count = len(context.state_manager.session.todos)
|
|
211
|
-
if todo_count == 0:
|
|
212
|
-
await ui.info("No todos to clear.")
|
|
213
|
-
return
|
|
214
|
-
|
|
215
|
-
context.state_manager.clear_todos()
|
|
216
|
-
await ui.success(f"Cleared all {todo_count} todos.")
|
|
217
|
-
await self.list_todos(context)
|
tunacode/context.py
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import subprocess
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Dict, List
|
|
5
|
-
|
|
6
|
-
from tunacode.utils.ripgrep import ripgrep
|
|
7
|
-
from tunacode.utils.system import list_cwd
|
|
8
|
-
|
|
9
|
-
logger = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
async def get_git_status() -> Dict[str, object]:
|
|
13
|
-
"""Return git branch and dirty state information."""
|
|
14
|
-
try:
|
|
15
|
-
result = subprocess.run(
|
|
16
|
-
["git", "status", "--porcelain", "--branch"],
|
|
17
|
-
capture_output=True,
|
|
18
|
-
text=True,
|
|
19
|
-
check=True,
|
|
20
|
-
timeout=5,
|
|
21
|
-
)
|
|
22
|
-
lines = result.stdout.splitlines()
|
|
23
|
-
branch_line = lines[0][2:] if lines else ""
|
|
24
|
-
branch = branch_line.split("...")[0]
|
|
25
|
-
ahead = behind = 0
|
|
26
|
-
if "[" in branch_line and "]" in branch_line:
|
|
27
|
-
bracket = branch_line.split("[", 1)[1].split("]", 1)[0]
|
|
28
|
-
for part in bracket.split(","):
|
|
29
|
-
if "ahead" in part:
|
|
30
|
-
ahead = int(part.split("ahead")[1].strip().strip(" ]"))
|
|
31
|
-
if "behind" in part:
|
|
32
|
-
behind = int(part.split("behind")[1].strip().strip(" ]"))
|
|
33
|
-
dirty = any(line for line in lines[1:])
|
|
34
|
-
return {"branch": branch, "ahead": ahead, "behind": behind, "dirty": dirty}
|
|
35
|
-
except Exception as e:
|
|
36
|
-
logger.warning(f"Failed to get git status: {e}")
|
|
37
|
-
return {}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
async def get_directory_structure(max_depth: int = 3) -> str:
|
|
41
|
-
"""Return a simple directory tree string."""
|
|
42
|
-
files = list_cwd(max_depth=max_depth)
|
|
43
|
-
lines: List[str] = []
|
|
44
|
-
for path in files:
|
|
45
|
-
depth = path.count("/")
|
|
46
|
-
indent = " " * depth
|
|
47
|
-
name = path.split("/")[-1]
|
|
48
|
-
lines.append(f"{indent}{name}")
|
|
49
|
-
return "\n".join(lines)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
async def get_code_style() -> str:
|
|
53
|
-
"""Concatenate contents of all TUNACODE.md files up the directory tree."""
|
|
54
|
-
parts: List[str] = []
|
|
55
|
-
current = Path.cwd()
|
|
56
|
-
while True:
|
|
57
|
-
file = current / "TUNACODE.md"
|
|
58
|
-
if file.exists():
|
|
59
|
-
try:
|
|
60
|
-
parts.append(file.read_text(encoding="utf-8"))
|
|
61
|
-
except Exception as e:
|
|
62
|
-
logger.debug(f"Failed to read TUNACODE.md at {file}: {e}")
|
|
63
|
-
if current == current.parent:
|
|
64
|
-
break
|
|
65
|
-
current = current.parent
|
|
66
|
-
return "\n".join(parts)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
async def get_claude_files() -> List[str]:
|
|
70
|
-
"""Return a list of additional TUNACODE.md files in the repo."""
|
|
71
|
-
return ripgrep("TUNACODE.md", ".")
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
"""Git safety setup to create a working branch for TunaCode."""
|
|
2
|
-
|
|
3
|
-
import subprocess
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from tunacode.core.setup.base import BaseSetup
|
|
7
|
-
from tunacode.core.state import StateManager
|
|
8
|
-
from tunacode.ui import console as ui
|
|
9
|
-
from tunacode.ui.input import input as prompt_input
|
|
10
|
-
from tunacode.ui.panels import panel
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async def yes_no_prompt(question: str, default: bool = True) -> bool:
|
|
14
|
-
"""Simple yes/no prompt."""
|
|
15
|
-
default_text = "[Y/n]" if default else "[y/N]"
|
|
16
|
-
response = await prompt_input(session_key="yes_no", pretext=f"{question} {default_text}: ")
|
|
17
|
-
|
|
18
|
-
if not response.strip():
|
|
19
|
-
return default
|
|
20
|
-
|
|
21
|
-
return response.lower().strip() in ["y", "yes"]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class GitSafetySetup(BaseSetup):
|
|
25
|
-
"""Setup step to create a safe working branch for TunaCode."""
|
|
26
|
-
|
|
27
|
-
def __init__(self, state_manager: StateManager):
|
|
28
|
-
super().__init__(state_manager)
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def name(self) -> str:
|
|
32
|
-
"""Return the name of this setup step."""
|
|
33
|
-
return "Git Safety"
|
|
34
|
-
|
|
35
|
-
async def should_run(self, _force: bool = False) -> bool:
|
|
36
|
-
"""Check if we should run git safety setup."""
|
|
37
|
-
# Always run unless user has explicitly disabled it
|
|
38
|
-
return not self.state_manager.session.user_config.get("skip_git_safety", False)
|
|
39
|
-
|
|
40
|
-
async def execute(self, _force: bool = False) -> None:
|
|
41
|
-
"""Create a safety branch for TunaCode operations."""
|
|
42
|
-
try:
|
|
43
|
-
# Check if git is installed
|
|
44
|
-
result = subprocess.run(
|
|
45
|
-
["git", "--version"], capture_output=True, text=True, check=False
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
if result.returncode != 0:
|
|
49
|
-
await panel(
|
|
50
|
-
" Git Not Found",
|
|
51
|
-
"Git is not installed or not in PATH. TunaCode will modify files directly.\n"
|
|
52
|
-
"It's strongly recommended to install Git for safety.",
|
|
53
|
-
border_style="yellow",
|
|
54
|
-
)
|
|
55
|
-
return
|
|
56
|
-
|
|
57
|
-
# Check if we're in a git repository
|
|
58
|
-
result = subprocess.run(
|
|
59
|
-
["git", "rev-parse", "--git-dir"],
|
|
60
|
-
capture_output=True,
|
|
61
|
-
text=True,
|
|
62
|
-
check=False,
|
|
63
|
-
cwd=Path.cwd(),
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
if result.returncode != 0:
|
|
67
|
-
await panel(
|
|
68
|
-
" Not a Git Repository",
|
|
69
|
-
"This directory is not a Git repository. TunaCode will modify files directly.\n"
|
|
70
|
-
"Consider initializing a Git repository for safety: git init",
|
|
71
|
-
border_style="yellow",
|
|
72
|
-
)
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
# Get current branch name
|
|
76
|
-
result = subprocess.run(
|
|
77
|
-
["git", "branch", "--show-current"], capture_output=True, text=True, check=True
|
|
78
|
-
)
|
|
79
|
-
current_branch = result.stdout.strip()
|
|
80
|
-
|
|
81
|
-
if not current_branch:
|
|
82
|
-
# Detached HEAD state
|
|
83
|
-
await panel(
|
|
84
|
-
" Detached HEAD State",
|
|
85
|
-
"You're in a detached HEAD state. TunaCode will continue without creating a branch.",
|
|
86
|
-
border_style="yellow",
|
|
87
|
-
)
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
# Check if we're already on a -tunacode branch
|
|
91
|
-
if current_branch.endswith("-tunacode"):
|
|
92
|
-
await ui.info(f"Already on a TunaCode branch: {current_branch}")
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
# Propose new branch name
|
|
96
|
-
new_branch = f"{current_branch}-tunacode"
|
|
97
|
-
|
|
98
|
-
# Check if there are uncommitted changes
|
|
99
|
-
result = subprocess.run(
|
|
100
|
-
["git", "status", "--porcelain"], capture_output=True, text=True, check=True
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
has_changes = bool(result.stdout.strip())
|
|
104
|
-
|
|
105
|
-
# Ask user if they want to create a safety branch
|
|
106
|
-
message = (
|
|
107
|
-
f"For safety, TunaCode can create a new branch '{new_branch}' based on '{current_branch}'.\n"
|
|
108
|
-
f"This helps protect your work from unintended changes.\n"
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
if has_changes:
|
|
112
|
-
message += "\n You have uncommitted changes that will be brought to the new branch."
|
|
113
|
-
|
|
114
|
-
create_branch = await yes_no_prompt(f"{message}\n\nCreate safety branch?", default=True)
|
|
115
|
-
|
|
116
|
-
if not create_branch:
|
|
117
|
-
# User declined - show warning
|
|
118
|
-
await panel(
|
|
119
|
-
" Working Without Safety Branch",
|
|
120
|
-
"You've chosen to work directly on your current branch.\n"
|
|
121
|
-
"TunaCode will modify files in place. Make sure you have backups!",
|
|
122
|
-
border_style="red",
|
|
123
|
-
)
|
|
124
|
-
# Save preference
|
|
125
|
-
self.state_manager.session.user_config["skip_git_safety"] = True
|
|
126
|
-
# Save the updated configuration to disk
|
|
127
|
-
try:
|
|
128
|
-
from tunacode.utils.user_configuration import save_config
|
|
129
|
-
|
|
130
|
-
save_config(self.state_manager)
|
|
131
|
-
except Exception as e:
|
|
132
|
-
# Log the error but don't fail the setup process
|
|
133
|
-
import logging
|
|
134
|
-
|
|
135
|
-
logging.warning(f"Failed to save skip_git_safety preference: {e}")
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
# Create and checkout the new branch
|
|
139
|
-
try:
|
|
140
|
-
# Check if branch already exists
|
|
141
|
-
result = subprocess.run(
|
|
142
|
-
["git", "show-ref", "--verify", f"refs/heads/{new_branch}"],
|
|
143
|
-
capture_output=True,
|
|
144
|
-
check=False,
|
|
145
|
-
text=True,
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
if result.returncode == 0:
|
|
149
|
-
# Branch exists, ask to use it
|
|
150
|
-
use_existing = await yes_no_prompt(
|
|
151
|
-
f"Branch '{new_branch}' already exists. Switch to it?", default=True
|
|
152
|
-
)
|
|
153
|
-
if use_existing:
|
|
154
|
-
subprocess.run(["git", "checkout", new_branch], check=True)
|
|
155
|
-
await ui.success(f"Switched to existing branch: {new_branch}")
|
|
156
|
-
else:
|
|
157
|
-
await ui.warning("Continuing on current branch")
|
|
158
|
-
else:
|
|
159
|
-
# Create new branch
|
|
160
|
-
subprocess.run(["git", "checkout", "-b", new_branch], check=True)
|
|
161
|
-
await ui.success(f"Created and switched to new branch: {new_branch}")
|
|
162
|
-
|
|
163
|
-
except subprocess.CalledProcessError as e:
|
|
164
|
-
await panel(
|
|
165
|
-
" Failed to Create Branch",
|
|
166
|
-
f"Could not create branch '{new_branch}': {str(e)}\n"
|
|
167
|
-
"Continuing on current branch.",
|
|
168
|
-
border_style="red",
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
except Exception as e:
|
|
172
|
-
# Non-fatal error - just warn the user
|
|
173
|
-
await panel(
|
|
174
|
-
" Git Safety Setup Failed",
|
|
175
|
-
f"Could not set up Git safety: {str(e)}\n"
|
|
176
|
-
"TunaCode will continue without branch protection.",
|
|
177
|
-
border_style="yellow",
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
async def validate(self) -> bool:
|
|
181
|
-
"""Validate git safety setup - always returns True as this is optional."""
|
|
182
|
-
return True
|