tunacode-cli 0.1.21__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.

Files changed (174) hide show
  1. tunacode/__init__.py +0 -0
  2. tunacode/cli/textual_repl.tcss +283 -0
  3. tunacode/configuration/__init__.py +1 -0
  4. tunacode/configuration/defaults.py +45 -0
  5. tunacode/configuration/models.py +147 -0
  6. tunacode/configuration/models_registry.json +1 -0
  7. tunacode/configuration/pricing.py +74 -0
  8. tunacode/configuration/settings.py +35 -0
  9. tunacode/constants.py +227 -0
  10. tunacode/core/__init__.py +6 -0
  11. tunacode/core/agents/__init__.py +39 -0
  12. tunacode/core/agents/agent_components/__init__.py +48 -0
  13. tunacode/core/agents/agent_components/agent_config.py +441 -0
  14. tunacode/core/agents/agent_components/agent_helpers.py +290 -0
  15. tunacode/core/agents/agent_components/message_handler.py +99 -0
  16. tunacode/core/agents/agent_components/node_processor.py +477 -0
  17. tunacode/core/agents/agent_components/response_state.py +129 -0
  18. tunacode/core/agents/agent_components/result_wrapper.py +51 -0
  19. tunacode/core/agents/agent_components/state_transition.py +112 -0
  20. tunacode/core/agents/agent_components/streaming.py +271 -0
  21. tunacode/core/agents/agent_components/task_completion.py +40 -0
  22. tunacode/core/agents/agent_components/tool_buffer.py +44 -0
  23. tunacode/core/agents/agent_components/tool_executor.py +101 -0
  24. tunacode/core/agents/agent_components/truncation_checker.py +37 -0
  25. tunacode/core/agents/delegation_tools.py +109 -0
  26. tunacode/core/agents/main.py +545 -0
  27. tunacode/core/agents/prompts.py +66 -0
  28. tunacode/core/agents/research_agent.py +231 -0
  29. tunacode/core/compaction.py +218 -0
  30. tunacode/core/prompting/__init__.py +27 -0
  31. tunacode/core/prompting/loader.py +66 -0
  32. tunacode/core/prompting/prompting_engine.py +98 -0
  33. tunacode/core/prompting/sections.py +50 -0
  34. tunacode/core/prompting/templates.py +69 -0
  35. tunacode/core/state.py +409 -0
  36. tunacode/exceptions.py +313 -0
  37. tunacode/indexing/__init__.py +5 -0
  38. tunacode/indexing/code_index.py +432 -0
  39. tunacode/indexing/constants.py +86 -0
  40. tunacode/lsp/__init__.py +112 -0
  41. tunacode/lsp/client.py +351 -0
  42. tunacode/lsp/diagnostics.py +19 -0
  43. tunacode/lsp/servers.py +101 -0
  44. tunacode/prompts/default_prompt.md +952 -0
  45. tunacode/prompts/research/sections/agent_role.xml +5 -0
  46. tunacode/prompts/research/sections/constraints.xml +14 -0
  47. tunacode/prompts/research/sections/output_format.xml +57 -0
  48. tunacode/prompts/research/sections/tool_use.xml +23 -0
  49. tunacode/prompts/sections/advanced_patterns.xml +255 -0
  50. tunacode/prompts/sections/agent_role.xml +8 -0
  51. tunacode/prompts/sections/completion.xml +10 -0
  52. tunacode/prompts/sections/critical_rules.xml +37 -0
  53. tunacode/prompts/sections/examples.xml +220 -0
  54. tunacode/prompts/sections/output_style.xml +94 -0
  55. tunacode/prompts/sections/parallel_exec.xml +105 -0
  56. tunacode/prompts/sections/search_pattern.xml +100 -0
  57. tunacode/prompts/sections/system_info.xml +6 -0
  58. tunacode/prompts/sections/tool_use.xml +84 -0
  59. tunacode/prompts/sections/user_instructions.xml +3 -0
  60. tunacode/py.typed +0 -0
  61. tunacode/templates/__init__.py +5 -0
  62. tunacode/templates/loader.py +15 -0
  63. tunacode/tools/__init__.py +10 -0
  64. tunacode/tools/authorization/__init__.py +29 -0
  65. tunacode/tools/authorization/context.py +32 -0
  66. tunacode/tools/authorization/factory.py +20 -0
  67. tunacode/tools/authorization/handler.py +58 -0
  68. tunacode/tools/authorization/notifier.py +35 -0
  69. tunacode/tools/authorization/policy.py +19 -0
  70. tunacode/tools/authorization/requests.py +119 -0
  71. tunacode/tools/authorization/rules.py +72 -0
  72. tunacode/tools/bash.py +222 -0
  73. tunacode/tools/decorators.py +213 -0
  74. tunacode/tools/glob.py +353 -0
  75. tunacode/tools/grep.py +468 -0
  76. tunacode/tools/grep_components/__init__.py +9 -0
  77. tunacode/tools/grep_components/file_filter.py +93 -0
  78. tunacode/tools/grep_components/pattern_matcher.py +158 -0
  79. tunacode/tools/grep_components/result_formatter.py +87 -0
  80. tunacode/tools/grep_components/search_result.py +34 -0
  81. tunacode/tools/list_dir.py +205 -0
  82. tunacode/tools/prompts/bash_prompt.xml +10 -0
  83. tunacode/tools/prompts/glob_prompt.xml +7 -0
  84. tunacode/tools/prompts/grep_prompt.xml +10 -0
  85. tunacode/tools/prompts/list_dir_prompt.xml +7 -0
  86. tunacode/tools/prompts/read_file_prompt.xml +9 -0
  87. tunacode/tools/prompts/todoclear_prompt.xml +12 -0
  88. tunacode/tools/prompts/todoread_prompt.xml +16 -0
  89. tunacode/tools/prompts/todowrite_prompt.xml +28 -0
  90. tunacode/tools/prompts/update_file_prompt.xml +9 -0
  91. tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
  92. tunacode/tools/prompts/write_file_prompt.xml +7 -0
  93. tunacode/tools/react.py +111 -0
  94. tunacode/tools/read_file.py +68 -0
  95. tunacode/tools/todo.py +222 -0
  96. tunacode/tools/update_file.py +62 -0
  97. tunacode/tools/utils/__init__.py +1 -0
  98. tunacode/tools/utils/ripgrep.py +311 -0
  99. tunacode/tools/utils/text_match.py +352 -0
  100. tunacode/tools/web_fetch.py +245 -0
  101. tunacode/tools/write_file.py +34 -0
  102. tunacode/tools/xml_helper.py +34 -0
  103. tunacode/types/__init__.py +166 -0
  104. tunacode/types/base.py +94 -0
  105. tunacode/types/callbacks.py +53 -0
  106. tunacode/types/dataclasses.py +121 -0
  107. tunacode/types/pydantic_ai.py +31 -0
  108. tunacode/types/state.py +122 -0
  109. tunacode/ui/__init__.py +6 -0
  110. tunacode/ui/app.py +542 -0
  111. tunacode/ui/commands/__init__.py +430 -0
  112. tunacode/ui/components/__init__.py +1 -0
  113. tunacode/ui/headless/__init__.py +5 -0
  114. tunacode/ui/headless/output.py +72 -0
  115. tunacode/ui/main.py +252 -0
  116. tunacode/ui/renderers/__init__.py +41 -0
  117. tunacode/ui/renderers/errors.py +197 -0
  118. tunacode/ui/renderers/panels.py +550 -0
  119. tunacode/ui/renderers/search.py +314 -0
  120. tunacode/ui/renderers/tools/__init__.py +21 -0
  121. tunacode/ui/renderers/tools/bash.py +247 -0
  122. tunacode/ui/renderers/tools/diagnostics.py +186 -0
  123. tunacode/ui/renderers/tools/glob.py +226 -0
  124. tunacode/ui/renderers/tools/grep.py +228 -0
  125. tunacode/ui/renderers/tools/list_dir.py +198 -0
  126. tunacode/ui/renderers/tools/read_file.py +226 -0
  127. tunacode/ui/renderers/tools/research.py +294 -0
  128. tunacode/ui/renderers/tools/update_file.py +237 -0
  129. tunacode/ui/renderers/tools/web_fetch.py +182 -0
  130. tunacode/ui/repl_support.py +226 -0
  131. tunacode/ui/screens/__init__.py +16 -0
  132. tunacode/ui/screens/model_picker.py +303 -0
  133. tunacode/ui/screens/session_picker.py +181 -0
  134. tunacode/ui/screens/setup.py +218 -0
  135. tunacode/ui/screens/theme_picker.py +90 -0
  136. tunacode/ui/screens/update_confirm.py +69 -0
  137. tunacode/ui/shell_runner.py +129 -0
  138. tunacode/ui/styles/layout.tcss +98 -0
  139. tunacode/ui/styles/modals.tcss +38 -0
  140. tunacode/ui/styles/panels.tcss +81 -0
  141. tunacode/ui/styles/theme-nextstep.tcss +303 -0
  142. tunacode/ui/styles/widgets.tcss +33 -0
  143. tunacode/ui/styles.py +18 -0
  144. tunacode/ui/widgets/__init__.py +23 -0
  145. tunacode/ui/widgets/command_autocomplete.py +62 -0
  146. tunacode/ui/widgets/editor.py +402 -0
  147. tunacode/ui/widgets/file_autocomplete.py +47 -0
  148. tunacode/ui/widgets/messages.py +46 -0
  149. tunacode/ui/widgets/resource_bar.py +182 -0
  150. tunacode/ui/widgets/status_bar.py +98 -0
  151. tunacode/utils/__init__.py +0 -0
  152. tunacode/utils/config/__init__.py +13 -0
  153. tunacode/utils/config/user_configuration.py +91 -0
  154. tunacode/utils/messaging/__init__.py +10 -0
  155. tunacode/utils/messaging/message_utils.py +34 -0
  156. tunacode/utils/messaging/token_counter.py +77 -0
  157. tunacode/utils/parsing/__init__.py +13 -0
  158. tunacode/utils/parsing/command_parser.py +55 -0
  159. tunacode/utils/parsing/json_utils.py +188 -0
  160. tunacode/utils/parsing/retry.py +146 -0
  161. tunacode/utils/parsing/tool_parser.py +267 -0
  162. tunacode/utils/security/__init__.py +15 -0
  163. tunacode/utils/security/command.py +106 -0
  164. tunacode/utils/system/__init__.py +25 -0
  165. tunacode/utils/system/gitignore.py +155 -0
  166. tunacode/utils/system/paths.py +190 -0
  167. tunacode/utils/ui/__init__.py +9 -0
  168. tunacode/utils/ui/file_filter.py +135 -0
  169. tunacode/utils/ui/helpers.py +24 -0
  170. tunacode_cli-0.1.21.dist-info/METADATA +170 -0
  171. tunacode_cli-0.1.21.dist-info/RECORD +174 -0
  172. tunacode_cli-0.1.21.dist-info/WHEEL +4 -0
  173. tunacode_cli-0.1.21.dist-info/entry_points.txt +2 -0
  174. tunacode_cli-0.1.21.dist-info/licenses/LICENSE +21 -0
tunacode/exceptions.py ADDED
@@ -0,0 +1,313 @@
1
+ """
2
+ TunaCode CLI exception hierarchy.
3
+
4
+ This module defines all custom exceptions used throughout the TunaCode CLI.
5
+ All exceptions inherit from TunaCodeError for easy catching of any TunaCode-specific error.
6
+ """
7
+
8
+ from tunacode.types import ErrorMessage, FilePath, OriginalError, ToolName
9
+
10
+ SECTION_SEPARATOR = "\n\n"
11
+ LINE_SEPARATOR = "\n"
12
+ BULLET_PREFIX = " - "
13
+ NUMBERED_ITEM_PREFIX = " {index}. "
14
+
15
+ SUGGESTED_FIX_LABEL = "Suggested fix"
16
+ VALID_EXAMPLES_LABEL = "Valid examples"
17
+ RECOVERY_COMMANDS_LABEL = "Recovery commands"
18
+ TROUBLESHOOTING_STEPS_LABEL = "Troubleshooting steps"
19
+ HELP_LABEL = "More help"
20
+
21
+ VALIDATION_PREFIX = "Validation failed: "
22
+ AGENT_ERROR_PREFIX = "Agent error: "
23
+ TOOL_ERROR_PREFIX = "Tool '{tool_name}' failed: "
24
+
25
+ JSON_TRUNCATION_LIMIT = 100
26
+ VALID_MODEL_EXAMPLE_LIMIT = 3
27
+
28
+
29
+ def _format_section(label: str, lines: list[str]) -> str:
30
+ if not lines:
31
+ return ""
32
+
33
+ section_header = f"{label}:"
34
+ section_body = LINE_SEPARATOR.join(lines)
35
+ return f"{section_header}{LINE_SEPARATOR}{section_body}"
36
+
37
+
38
+ def _build_error_message(
39
+ base_message: str,
40
+ suggested_fix: str | None = None,
41
+ help_url: str | None = None,
42
+ valid_examples: list[str] | None = None,
43
+ recovery_commands: list[str] | None = None,
44
+ troubleshooting_steps: list[str] | None = None,
45
+ ) -> str:
46
+ sections: list[str] = []
47
+
48
+ if suggested_fix:
49
+ suggested_fix_section = _format_section(SUGGESTED_FIX_LABEL, [suggested_fix])
50
+ sections.append(suggested_fix_section)
51
+
52
+ if help_url:
53
+ help_section = _format_section(HELP_LABEL, [help_url])
54
+ sections.append(help_section)
55
+
56
+ if valid_examples:
57
+ example_lines = [f"{BULLET_PREFIX}{example}" for example in valid_examples]
58
+ examples_section = _format_section(VALID_EXAMPLES_LABEL, example_lines)
59
+ sections.append(examples_section)
60
+
61
+ if recovery_commands:
62
+ recovery_lines = [f"{BULLET_PREFIX}{cmd}" for cmd in recovery_commands]
63
+ recovery_section = _format_section(RECOVERY_COMMANDS_LABEL, recovery_lines)
64
+ sections.append(recovery_section)
65
+
66
+ if troubleshooting_steps:
67
+ step_lines = [
68
+ f"{NUMBERED_ITEM_PREFIX.format(index=i + 1)}{step}"
69
+ for i, step in enumerate(troubleshooting_steps)
70
+ ]
71
+ troubleshooting_section = _format_section(TROUBLESHOOTING_STEPS_LABEL, step_lines)
72
+ sections.append(troubleshooting_section)
73
+
74
+ if not sections:
75
+ return base_message
76
+
77
+ sections_text = SECTION_SEPARATOR.join(sections)
78
+ return f"{base_message}{SECTION_SEPARATOR}{sections_text}"
79
+
80
+
81
+ class TunaCodeError(Exception):
82
+ """Base exception for all TunaCode errors."""
83
+
84
+ pass
85
+
86
+
87
+ class ConfigurationError(TunaCodeError):
88
+ """Raised when there's a configuration issue."""
89
+
90
+ def __init__(self, message: str, suggested_fix: str | None = None, help_url: str | None = None):
91
+ self.suggested_fix = suggested_fix
92
+ self.help_url = help_url
93
+
94
+ full_message = _build_error_message(
95
+ message,
96
+ suggested_fix=suggested_fix,
97
+ help_url=help_url,
98
+ )
99
+ super().__init__(full_message)
100
+
101
+
102
+ # User Interaction Exceptions
103
+ class UserAbortError(TunaCodeError):
104
+ """Raised when user aborts an operation."""
105
+
106
+ pass
107
+
108
+
109
+ class ValidationError(TunaCodeError):
110
+ """Raised when input validation fails."""
111
+
112
+ def __init__(
113
+ self,
114
+ message: str,
115
+ suggested_fix: str | None = None,
116
+ valid_examples: list | None = None,
117
+ ):
118
+ self.suggested_fix = suggested_fix
119
+ self.valid_examples = valid_examples or []
120
+
121
+ base_message = f"{VALIDATION_PREFIX}{message}"
122
+ full_message = _build_error_message(
123
+ base_message,
124
+ suggested_fix=suggested_fix,
125
+ valid_examples=self.valid_examples,
126
+ )
127
+ super().__init__(full_message)
128
+
129
+
130
+ # Tool and Agent Exceptions
131
+ class ToolExecutionError(TunaCodeError):
132
+ """Raised when a tool fails to execute."""
133
+
134
+ def __init__(
135
+ self,
136
+ tool_name: ToolName,
137
+ message: ErrorMessage,
138
+ original_error: OriginalError = None,
139
+ suggested_fix: str | None = None,
140
+ recovery_commands: list | None = None,
141
+ ):
142
+ self.tool_name = tool_name
143
+ self.original_error = original_error
144
+ self.suggested_fix = suggested_fix
145
+ self.recovery_commands = recovery_commands or []
146
+
147
+ base_message = TOOL_ERROR_PREFIX.format(tool_name=tool_name) + str(message)
148
+ full_message = _build_error_message(
149
+ base_message,
150
+ suggested_fix=suggested_fix,
151
+ recovery_commands=self.recovery_commands,
152
+ )
153
+ super().__init__(full_message)
154
+
155
+
156
+ class AgentError(TunaCodeError):
157
+ """Raised when agent operations fail."""
158
+
159
+ def __init__(
160
+ self,
161
+ message: str,
162
+ suggested_fix: str | None = None,
163
+ troubleshooting_steps: list | None = None,
164
+ ):
165
+ self.suggested_fix = suggested_fix
166
+ self.troubleshooting_steps = troubleshooting_steps or []
167
+
168
+ base_message = f"{AGENT_ERROR_PREFIX}{message}"
169
+ full_message = _build_error_message(
170
+ base_message,
171
+ suggested_fix=suggested_fix,
172
+ troubleshooting_steps=self.troubleshooting_steps,
173
+ )
174
+ super().__init__(full_message)
175
+
176
+
177
+ # State Management Exceptions
178
+ class StateError(TunaCodeError):
179
+ """Raised when there's an issue with application state."""
180
+
181
+ pass
182
+
183
+
184
+ # External Service Exceptions
185
+ class ServiceError(TunaCodeError):
186
+ """Base exception for external service failures."""
187
+
188
+ pass
189
+
190
+
191
+ class GitOperationError(ServiceError):
192
+ """Raised when Git operations fail."""
193
+
194
+ def __init__(self, operation: str, message: ErrorMessage, original_error: OriginalError = None):
195
+ self.operation = operation
196
+ self.original_error = original_error
197
+ super().__init__(f"Git {operation} failed: {message}")
198
+
199
+
200
+ # File System Exceptions
201
+ class FileOperationError(TunaCodeError):
202
+ """Raised when file system operations fail."""
203
+
204
+ def __init__(
205
+ self,
206
+ operation: str,
207
+ path: FilePath,
208
+ message: ErrorMessage,
209
+ original_error: OriginalError = None,
210
+ ):
211
+ self.operation = operation
212
+ self.path = path
213
+ self.original_error = original_error
214
+ super().__init__(f"File {operation} failed for '{path}': {message}")
215
+
216
+
217
+ class ModelConfigurationError(ConfigurationError):
218
+ """Raised when model configuration is invalid."""
219
+
220
+ def __init__(self, model: str, issue: str, valid_models: list | None = None):
221
+ self.model = model
222
+ self.issue = issue
223
+ self.valid_models = valid_models or []
224
+
225
+ suggested_fix = "Use --setup for guided setup or --model with a valid model name"
226
+ help_url = "https://docs.anthropic.com/en/docs/claude-code"
227
+
228
+ message = f"Model '{model}' configuration error: {issue}"
229
+ if valid_models:
230
+ examples = valid_models[:VALID_MODEL_EXAMPLE_LIMIT]
231
+ suggested_fix += f"\n\nValid examples: {', '.join(examples)}"
232
+
233
+ super().__init__(message, suggested_fix=suggested_fix, help_url=help_url)
234
+
235
+
236
+ class SetupValidationError(ValidationError):
237
+ """Raised when setup validation fails."""
238
+
239
+ def __init__(self, validation_type: str, details: str, quick_fixes: list | None = None):
240
+ self.validation_type = validation_type
241
+ self.details = details
242
+ self.quick_fixes = quick_fixes or []
243
+
244
+ suggested_fix = "Run 'tunacode --setup' for guided setup"
245
+ if quick_fixes:
246
+ suggested_fix = f"Try these quick fixes: {', '.join(quick_fixes)}"
247
+
248
+ super().__init__(
249
+ f"{validation_type} validation failed: {details}",
250
+ suggested_fix=suggested_fix,
251
+ valid_examples=["tunacode --setup", "tunacode --help"],
252
+ )
253
+
254
+
255
+ class TooBroadPatternError(ToolExecutionError):
256
+ """Raised when a search pattern is too broad and times out."""
257
+
258
+ def __init__(self, pattern: str, timeout_seconds: float):
259
+ self.pattern = pattern
260
+ self.timeout_seconds = timeout_seconds
261
+ super().__init__(
262
+ "grep",
263
+ f"Pattern '{pattern}' is too broad - no matches found within {timeout_seconds}s. "
264
+ "Please use a more specific pattern.",
265
+ )
266
+
267
+
268
+ class GlobalRequestTimeoutError(TunaCodeError):
269
+ """Raised when a request exceeds the global timeout limit."""
270
+
271
+ def __init__(self, timeout_seconds: float):
272
+ self.timeout_seconds = timeout_seconds
273
+ super().__init__(
274
+ f"Request exceeded global timeout of {timeout_seconds}s. "
275
+ f"The model API may be slow or unresponsive. "
276
+ f"Try increasing settings.global_request_timeout in tunacode.json "
277
+ f"or check model API status."
278
+ )
279
+
280
+
281
+ class ToolBatchingJSONError(TunaCodeError):
282
+ """Raised when JSON parsing fails during tool batching after all retries are exhausted."""
283
+
284
+ def __init__(
285
+ self,
286
+ json_content: str,
287
+ retry_count: int,
288
+ original_error: OriginalError = None,
289
+ ):
290
+ self.json_content = json_content
291
+ self.retry_count = retry_count
292
+ self.original_error = original_error
293
+
294
+ # Truncate JSON content for display if too long
295
+ truncated_content = json_content[:JSON_TRUNCATION_LIMIT]
296
+ display_content = (
297
+ f"{truncated_content}..." if len(json_content) > JSON_TRUNCATION_LIMIT else json_content
298
+ )
299
+
300
+ super().__init__(
301
+ f"The model is having issues with tool batching. "
302
+ f"JSON parsing failed after {retry_count} retries. "
303
+ f"Invalid JSON: {display_content}"
304
+ )
305
+
306
+
307
+ class AggregateToolError(TunaCodeError):
308
+ """Raised when multiple tools fail in parallel execution after retries exhausted."""
309
+
310
+ def __init__(self, failures: list[tuple[str, Exception]]):
311
+ self.failures = failures
312
+ tool_names = [name for name, _ in failures]
313
+ super().__init__(f"Multiple tools failed: {', '.join(tool_names)}")
@@ -0,0 +1,5 @@
1
+ """File indexing for fast repository lookups."""
2
+
3
+ from tunacode.indexing.code_index import CodeIndex
4
+
5
+ __all__ = ["CodeIndex"]