tunacode-cli 0.0.55__py3-none-any.whl → 0.0.56__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.

@@ -0,0 +1,208 @@
1
+ """Tool for presenting a structured plan and exiting plan mode."""
2
+
3
+ from typing import List, Optional
4
+
5
+ from tunacode.tools.base import BaseTool
6
+ from tunacode.ui import console as ui
7
+ from tunacode.types import ToolResult, PlanDoc, PlanPhase
8
+
9
+
10
+ class PresentPlanTool(BaseTool):
11
+ """Present a structured implementation plan and request user approval."""
12
+
13
+ def __init__(self, state_manager, ui_logger=None):
14
+ """Initialize the present plan tool.
15
+
16
+ Args:
17
+ state_manager: StateManager instance for controlling plan mode state
18
+ ui_logger: UI logger instance for displaying messages
19
+ """
20
+ super().__init__(ui_logger)
21
+ self.state_manager = state_manager
22
+
23
+ @property
24
+ def tool_name(self) -> str:
25
+ return "present_plan"
26
+
27
+ async def _execute(
28
+ self,
29
+ title: str,
30
+ overview: str,
31
+ steps: List[str],
32
+ files_to_modify: List[str] = None,
33
+ files_to_create: List[str] = None,
34
+ risks: List[str] = None,
35
+ tests: List[str] = None,
36
+ rollback: Optional[str] = None,
37
+ open_questions: List[str] = None,
38
+ success_criteria: List[str] = None,
39
+ references: List[str] = None,
40
+ ) -> ToolResult:
41
+ """Present the implementation plan for user approval."""
42
+
43
+ # Create PlanDoc from parameters
44
+ plan_doc = PlanDoc(
45
+ title=title,
46
+ overview=overview,
47
+ steps=steps,
48
+ files_to_modify=files_to_modify or [],
49
+ files_to_create=files_to_create or [],
50
+ risks=risks or [],
51
+ tests=tests or [],
52
+ rollback=rollback,
53
+ open_questions=open_questions or [],
54
+ success_criteria=success_criteria or [],
55
+ references=references or []
56
+ )
57
+
58
+ # Validate the plan
59
+ is_valid, missing_sections = plan_doc.validate()
60
+ if not is_valid:
61
+ return f"❌ Plan incomplete. Missing sections: {', '.join(missing_sections)}. Continue researching and refining your plan."
62
+
63
+ # Set plan phase to PLAN_READY and store the plan
64
+ # The REPL will handle displaying the plan when it detects PLAN_READY phase
65
+ self.state_manager.session.plan_phase = PlanPhase.PLAN_READY
66
+ self.state_manager.session.current_plan = plan_doc
67
+
68
+ return "Plan ready for review. The system will now present it to the user for approval."
69
+
70
+ async def _present_plan(self, plan_doc: PlanDoc) -> None:
71
+ """Present the plan in a formatted way."""
72
+ output = []
73
+ output.append("")
74
+ output.append("╭─────────────────────────────────────────────────────────╮")
75
+ output.append("│ 📋 IMPLEMENTATION PLAN │")
76
+ output.append("╰─────────────────────────────────────────────────────────╯")
77
+ output.append("")
78
+ output.append(f"🎯 **{plan_doc.title}**")
79
+ output.append("")
80
+
81
+ if plan_doc.overview:
82
+ output.append(f"📝 **Overview:** {plan_doc.overview}")
83
+ output.append("")
84
+
85
+ # Files section
86
+ if plan_doc.files_to_modify:
87
+ output.append("📝 **Files to Modify:**")
88
+ for f in plan_doc.files_to_modify:
89
+ output.append(f" • {f}")
90
+ output.append("")
91
+
92
+ if plan_doc.files_to_create:
93
+ output.append("📄 **Files to Create:**")
94
+ for f in plan_doc.files_to_create:
95
+ output.append(f" • {f}")
96
+ output.append("")
97
+
98
+ # Implementation steps
99
+ output.append("🔧 **Implementation Steps:**")
100
+ for i, step in enumerate(plan_doc.steps, 1):
101
+ output.append(f" {i}. {step}")
102
+ output.append("")
103
+
104
+ # Testing approach
105
+ if plan_doc.tests:
106
+ output.append("🧪 **Testing Approach:**")
107
+ for test in plan_doc.tests:
108
+ output.append(f" • {test}")
109
+ output.append("")
110
+
111
+ # Success criteria
112
+ if plan_doc.success_criteria:
113
+ output.append("✅ **Success Criteria:**")
114
+ for criteria in plan_doc.success_criteria:
115
+ output.append(f" • {criteria}")
116
+ output.append("")
117
+
118
+ # Risks and considerations
119
+ if plan_doc.risks:
120
+ output.append("⚠️ **Risks & Considerations:**")
121
+ for risk in plan_doc.risks:
122
+ output.append(f" • {risk}")
123
+ output.append("")
124
+
125
+ # Open questions
126
+ if plan_doc.open_questions:
127
+ output.append("❓ **Open Questions:**")
128
+ for question in plan_doc.open_questions:
129
+ output.append(f" • {question}")
130
+ output.append("")
131
+
132
+ # References
133
+ if plan_doc.references:
134
+ output.append("📚 **References:**")
135
+ for ref in plan_doc.references:
136
+ output.append(f" • {ref}")
137
+ output.append("")
138
+
139
+ # Rollback plan
140
+ if plan_doc.rollback:
141
+ output.append(f"🔄 **Rollback Plan:** {plan_doc.rollback}")
142
+ output.append("")
143
+
144
+ # Print everything at once
145
+ await ui.info("\n".join(output))
146
+
147
+
148
+ def create_present_plan_tool(state_manager):
149
+ """
150
+ Factory function to create present_plan tool with the correct state manager.
151
+
152
+ Args:
153
+ state_manager: The StateManager instance to use
154
+
155
+ Returns:
156
+ Callable: The present_plan function bound to the provided state manager
157
+ """
158
+ async def present_plan(
159
+ title: str,
160
+ overview: str,
161
+ steps: List[str],
162
+ files_to_modify: List[str] = None,
163
+ files_to_create: List[str] = None,
164
+ risks: List[str] = None,
165
+ tests: List[str] = None,
166
+ rollback: Optional[str] = None,
167
+ open_questions: List[str] = None,
168
+ success_criteria: List[str] = None,
169
+ references: List[str] = None,
170
+ ) -> str:
171
+ """
172
+ Present a structured implementation plan for user approval.
173
+
174
+ This tool should ONLY be called when you have a complete, well-researched plan.
175
+ All required sections must be filled out before calling this tool.
176
+
177
+ Args:
178
+ title: Brief, descriptive title for the implementation plan
179
+ overview: High-level summary of what needs to be implemented and why
180
+ steps: Ordered list of specific implementation steps (required)
181
+ files_to_modify: List of existing files that need to be modified
182
+ files_to_create: List of new files that need to be created
183
+ risks: Potential risks, challenges, or considerations
184
+ tests: Testing approach and test cases to validate implementation
185
+ rollback: Plan for reverting changes if needed
186
+ open_questions: Any remaining questions or uncertainties
187
+ success_criteria: Specific criteria for considering the task complete
188
+ references: External resources, documentation, or research sources
189
+
190
+ Returns:
191
+ str: Status message about plan presentation
192
+ """
193
+ tool = PresentPlanTool(state_manager=state_manager)
194
+ return await tool._execute(
195
+ title=title,
196
+ overview=overview,
197
+ steps=steps,
198
+ files_to_modify=files_to_modify,
199
+ files_to_create=files_to_create,
200
+ risks=risks,
201
+ tests=tests,
202
+ rollback=rollback,
203
+ open_questions=open_questions,
204
+ success_criteria=success_criteria,
205
+ references=references,
206
+ )
207
+
208
+ return present_plan
tunacode/types.py CHANGED
@@ -21,6 +21,9 @@ from typing import (
21
21
  Union,
22
22
  )
23
23
 
24
+ # Plan types will be defined below
25
+ from enum import Enum
26
+
24
27
  # Try to import pydantic-ai types if available
25
28
  try:
26
29
  from pydantic_ai import Agent
@@ -192,6 +195,60 @@ class SimpleResult:
192
195
  output: str
193
196
 
194
197
 
198
+ # =============================================================================
199
+ # Plan Types
200
+ # =============================================================================
201
+
202
+
203
+ class PlanPhase(Enum):
204
+ """Plan Mode phases."""
205
+ PLANNING_RESEARCH = "research"
206
+ PLANNING_DRAFT = "draft"
207
+ PLAN_READY = "ready"
208
+ REVIEW_DECISION = "review"
209
+
210
+
211
+ @dataclass
212
+ class PlanDoc:
213
+ """Structured plan document with all required sections."""
214
+
215
+ # Required sections
216
+ title: str
217
+ overview: str
218
+ steps: List[str]
219
+ files_to_modify: List[str]
220
+ files_to_create: List[str]
221
+
222
+ # Optional but recommended sections
223
+ risks: List[str] = field(default_factory=list)
224
+ tests: List[str] = field(default_factory=list)
225
+ rollback: Optional[str] = None
226
+ open_questions: List[str] = field(default_factory=list)
227
+ success_criteria: List[str] = field(default_factory=list)
228
+ references: List[str] = field(default_factory=list)
229
+
230
+ def validate(self) -> Tuple[bool, List[str]]:
231
+ """
232
+ Validate the plan document.
233
+
234
+ Returns:
235
+ tuple: (is_valid, list_of_missing_sections)
236
+ """
237
+ missing = []
238
+
239
+ # Check required fields
240
+ if not self.title or not self.title.strip():
241
+ missing.append("title")
242
+ if not self.overview or not self.overview.strip():
243
+ missing.append("overview")
244
+ if not self.steps:
245
+ missing.append("steps")
246
+ if not self.files_to_modify and not self.files_to_create:
247
+ missing.append("files_to_modify or files_to_create")
248
+
249
+ return len(missing) == 0, missing
250
+
251
+
195
252
  # =============================================================================
196
253
  # Session and State Types
197
254
  # =============================================================================
tunacode/ui/input.py CHANGED
@@ -76,19 +76,28 @@ async def multiline_input(
76
76
  ) -> str:
77
77
  """Get multiline input from the user with @file completion and highlighting."""
78
78
  kb = create_key_bindings(state_manager)
79
+
80
+ # Clear any residual terminal output
81
+ import sys
82
+ sys.stdout.flush()
83
+
84
+ # Full placeholder with all keyboard shortcuts
79
85
  placeholder = formatted_text(
80
86
  (
81
87
  "<darkgrey>"
82
88
  "<bold>Enter</bold> to submit • "
83
89
  "<bold>Esc + Enter</bold> for new line • "
84
90
  "<bold>Esc twice</bold> to cancel • "
91
+ "<bold>Shift + Tab</bold> toggle plan mode • "
85
92
  "<bold>/help</bold> for commands"
86
93
  "</darkgrey>"
87
94
  )
88
95
  )
89
- return await input(
96
+
97
+ # Display input area (Plan Mode indicator is handled dynamically in prompt manager)
98
+ result = await input(
90
99
  "multiline",
91
- pretext="> ", # Default prompt
100
+ pretext="> ",
92
101
  key_bindings=kb,
93
102
  multiline=True,
94
103
  placeholder=placeholder,
@@ -96,3 +105,5 @@ async def multiline_input(
96
105
  lexer=FileReferenceLexer(),
97
106
  state_manager=state_manager,
98
107
  )
108
+
109
+ return result
@@ -30,8 +30,8 @@ def create_key_bindings(state_manager: StateManager = None) -> KeyBindings:
30
30
 
31
31
  @kb.add("escape")
32
32
  def _escape(event):
33
- """Handle ESC key - raises KeyboardInterrupt for unified abort handling."""
34
- logger.debug("ESC key pressed - raising KeyboardInterrupt")
33
+ """Handle ESC key - trigger Ctrl+C behavior."""
34
+ logger.debug("ESC key pressed - simulating Ctrl+C")
35
35
 
36
36
  # Cancel any active task if present
37
37
  if state_manager and hasattr(state_manager.session, "current_task"):
@@ -44,7 +44,27 @@ def create_key_bindings(state_manager: StateManager = None) -> KeyBindings:
44
44
  except Exception as e:
45
45
  logger.debug(f"Failed to cancel task: {e}")
46
46
 
47
- # Raise KeyboardInterrupt to trigger unified abort handling in REPL
48
- raise KeyboardInterrupt()
47
+ # Trigger the same behavior as Ctrl+C by sending the signal
48
+ import os
49
+ import signal
50
+ os.kill(os.getpid(), signal.SIGINT)
51
+
52
+ @kb.add("s-tab") # shift+tab
53
+ def _toggle_plan_mode(event):
54
+ """Toggle between Plan Mode and normal mode."""
55
+ if state_manager:
56
+ # Toggle the state
57
+ if state_manager.is_plan_mode():
58
+ state_manager.exit_plan_mode()
59
+ logger.debug("Toggled to normal mode via Shift+Tab")
60
+ else:
61
+ state_manager.enter_plan_mode()
62
+ logger.debug("Toggled to Plan Mode via Shift+Tab")
63
+
64
+ # Clear the current buffer and refresh the display
65
+ event.current_buffer.reset()
66
+
67
+ # Force a refresh of the application without exiting
68
+ event.app.invalidate()
49
69
 
50
70
  return kb
tunacode/ui/panels.py CHANGED
@@ -170,6 +170,18 @@ class StreamingAgentPanel:
170
170
  # Defensive: some providers may yield None chunks intermittently
171
171
  if content_chunk is None:
172
172
  content_chunk = ""
173
+
174
+ # Filter out plan mode system prompts and tool definitions from streaming
175
+ if any(phrase in str(content_chunk) for phrase in [
176
+ "🔧 PLAN MODE",
177
+ "TOOL EXECUTION ONLY",
178
+ "planning assistant that ONLY communicates",
179
+ "namespace functions {",
180
+ "namespace multi_tool_use {",
181
+ "You are trained on data up to"
182
+ ]):
183
+ return
184
+
173
185
  # Ensure type safety for concatenation
174
186
  self.content = (self.content or "") + str(content_chunk)
175
187
 
@@ -182,6 +194,17 @@ class StreamingAgentPanel:
182
194
 
183
195
  async def set_content(self, content: str):
184
196
  """Set the complete content (overwrites previous)."""
197
+ # Filter out plan mode system prompts and tool definitions
198
+ if any(phrase in str(content) for phrase in [
199
+ "🔧 PLAN MODE",
200
+ "TOOL EXECUTION ONLY",
201
+ "planning assistant that ONLY communicates",
202
+ "namespace functions {",
203
+ "namespace multi_tool_use {",
204
+ "You are trained on data up to"
205
+ ]):
206
+ return
207
+
185
208
  self.content = content
186
209
  if self.live:
187
210
  self.live.update(self._create_panel())
@@ -100,15 +100,32 @@ class PromptManager:
100
100
  """
101
101
  session = self.get_session(session_key, config)
102
102
 
103
- # Create a custom prompt that changes based on input
103
+ # Create a custom prompt that changes based on input and plan mode
104
104
  def get_prompt():
105
+ # Start with the base prompt
106
+ base_prompt = prompt
107
+
108
+ # Add Plan Mode indicator if active
109
+ if (self.state_manager and
110
+ self.state_manager.is_plan_mode() and
111
+ "PLAN MODE ON" not in base_prompt):
112
+ base_prompt = '<style fg="#40E0D0"><bold>⏸ PLAN MODE ON</bold></style>\n' + base_prompt
113
+ elif (self.state_manager and
114
+ not self.state_manager.is_plan_mode() and
115
+ ("⏸" in base_prompt or "PLAN MODE ON" in base_prompt)):
116
+ # Remove plan mode indicator if no longer in plan mode
117
+ lines = base_prompt.split("\n")
118
+ if len(lines) > 1 and ("⏸" in lines[0] or "PLAN MODE ON" in lines[0]):
119
+ base_prompt = "\n".join(lines[1:])
120
+
105
121
  # Check if current buffer starts with "!"
106
122
  if hasattr(session.app, "current_buffer") and session.app.current_buffer:
107
123
  text = session.app.current_buffer.text
108
124
  if text.startswith("!"):
109
125
  # Use bright yellow background with black text for high visibility
110
126
  return HTML('<style bg="#ffcc00" fg="black"><b> ◆ BASH MODE ◆ </b></style> ')
111
- return HTML(prompt) if isinstance(prompt, str) else prompt
127
+
128
+ return HTML(base_prompt) if isinstance(base_prompt, str) else base_prompt
112
129
 
113
130
  try:
114
131
  # Get user input with dynamic prompt
tunacode/ui/tool_ui.py CHANGED
@@ -76,8 +76,9 @@ class ToolUI:
76
76
 
77
77
  # Show file content on write_file
78
78
  elif tool_name == TOOL_WRITE_FILE:
79
- markdown_obj = self._create_code_block(args["filepath"], args["content"])
80
- return str(markdown_obj)
79
+ lang = ext_to_lang(args["filepath"])
80
+ code_block = f"```{lang}\n{args['content']}\n```"
81
+ return code_block
81
82
 
82
83
  # Default to showing key and value on new line
83
84
  content = ""
@@ -9,11 +9,21 @@ def get_message_content(message: Any) -> str:
9
9
  return message
10
10
  if isinstance(message, dict):
11
11
  if "content" in message:
12
- return message["content"]
12
+ content = message["content"]
13
+ # Handle nested content structures
14
+ if isinstance(content, list):
15
+ return " ".join(get_message_content(item) for item in content)
16
+ return str(content)
13
17
  if "thought" in message:
14
- return message["thought"]
18
+ return str(message["thought"])
15
19
  if hasattr(message, "content"):
16
- return message.content
20
+ content = message.content
21
+ if isinstance(content, list):
22
+ return " ".join(get_message_content(item) for item in content)
23
+ return str(content)
17
24
  if hasattr(message, "parts"):
18
- return " ".join(get_message_content(part) for part in message.parts)
25
+ parts = message.parts
26
+ if isinstance(parts, list):
27
+ return " ".join(get_message_content(part) for part in parts)
28
+ return str(parts)
19
29
  return ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tunacode-cli
3
- Version: 0.0.55
3
+ Version: 0.0.56
4
4
  Summary: Your agentic CLI developer.
5
5
  Author-email: larock22 <noreply@github.com>
6
6
  License: MIT
@@ -39,6 +39,7 @@ Requires-Dist: vulture>=2.7; extra == "dev"
39
39
  Requires-Dist: unimport>=1.0.0; extra == "dev"
40
40
  Requires-Dist: autoflake>=2.0.0; extra == "dev"
41
41
  Requires-Dist: dead>=1.5.0; extra == "dev"
42
+ Requires-Dist: hatch>=1.6.0; extra == "dev"
42
43
  Dynamic: license-file
43
44
 
44
45
  # TunaCode CLI
@@ -106,7 +107,7 @@ tunacode --model "anthropic:claude-3.5-sonnet" --key "sk-ant-your-anthropic-key"
106
107
  tunacode --model "openrouter:openai/gpt-4o" --key "sk-or-your-openrouter-key"
107
108
  ```
108
109
 
109
- Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.config/tunacode.json`)
110
+ Your config is saved to `~/.config/tunacode.json`. This file stores your API keys, model preferences, and runtime settings like `max_iterations` (default: 40) and `context_window_size`. You can edit it directly with `nvim ~/.config/tunacode.json` or see [the complete configuration example](documentation/configuration/config-file-example.md) for all available options.
110
111
 
111
112
  ### Recommended Models
112
113
 
@@ -243,7 +244,7 @@ tunacode --model "anthropic:claude-3.5-sonnet" --key "sk-ant-your-anthropic-key"
243
244
  tunacode --model "openrouter:openai/gpt-4o" --key "sk-or-your-openrouter-key"
244
245
  ```
245
246
 
246
- Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.config/tunacode.json`)
247
+ Your config is saved to `~/.config/tunacode.json`. This file stores your API keys, model preferences, and runtime settings like `max_iterations` (default: 40) and `context_window_size`. You can edit it directly with `nvim ~/.config/tunacode.json` or see [the complete configuration example](documentation/configuration/config-file-example.md) for all available options.
247
248
 
248
249
  ### Recommended Models
249
250
 
@@ -1,47 +1,48 @@
1
1
  tunacode/__init__.py,sha256=yUul8igNYMfUrHnYfioIGAqvrH8b5BKiO_pt1wVnmd0,119
2
- tunacode/constants.py,sha256=nNS_4fOgxWjzUxnCm-FBXgfVRifwFytkt7yICn7eL1I,5968
2
+ tunacode/constants.py,sha256=7expbYlpKFgNIAF-zkeUWQ4HBw6PQb1Lnvk0u85qleo,6077
3
3
  tunacode/context.py,sha256=YtfRjUiqsSkk2k9Nn_pjb_m-AXyh6XcOBOJWtFI0wVw,2405
4
4
  tunacode/exceptions.py,sha256=oDO1SVKOgjcKIylwqdbqh_g5my4roU5mB9Nv4n_Vb0s,3877
5
5
  tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  tunacode/setup.py,sha256=a5S-uGkVYoBTvH9nsqMBgAFoH4CILOgfKvgS30qGnoU,1978
7
- tunacode/types.py,sha256=bCJ0mq1iQKa42fhBN5Pimkx0FV0f2J3-qRzbMzFhmBw,8499
7
+ tunacode/types.py,sha256=9cprg2Lc9vkzRkiGQlwHwLXO09tZYaob12s6PJHxc3Y,10196
8
8
  tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
9
9
  tunacode/cli/main.py,sha256=4MF4nGEU-CB83ckIl85AY-015EeUJHrE_UdbuSa9wCU,2968
10
- tunacode/cli/repl.py,sha256=GMEvDW8LP1iM-bwOY83BviYk0fMngDJiZiI3f28CHwo,16327
10
+ tunacode/cli/repl.py,sha256=RVx1D3s2t9-Ur1q_-voyknFOQn4URlJExR9yceSjW8g,30745
11
11
  tunacode/cli/commands/__init__.py,sha256=7rPwGkdYbPUgf__cPVX9oQUJOPQ18MdxDT_I64crdak,1740
12
12
  tunacode/cli/commands/base.py,sha256=Ge_lNQA-GDfcb1Ap1oznCH3UrifBiHH3bA9DNL-tCDw,2519
13
- tunacode/cli/commands/registry.py,sha256=Xmfb4qRZ1wvT-3OggGsuDxpXlCykuhOkSBberysj1SE,9345
13
+ tunacode/cli/commands/registry.py,sha256=OOZG51x1DTFfjIzStxBVxAOb6SOsUSh2bfIOsKY3Z1Q,9515
14
14
  tunacode/cli/commands/template_shortcut.py,sha256=ApYTPkDVBRaLxa7rWaPrsGcJdkR7eg09k18KyTjYg_E,3447
15
15
  tunacode/cli/commands/implementations/__init__.py,sha256=DHjQm1f14OV1go0ZyqacFa3yfnGWH7LZFbZVVQZ5Iw0,1011
16
16
  tunacode/cli/commands/implementations/conversation.py,sha256=ZijCNaRi1p5v1Q-IaVHtU2_BripSW3JCVKTtqFkOUjg,4676
17
17
  tunacode/cli/commands/implementations/debug.py,sha256=ornvceGF4GbJd2OJXnnT9i9KpHBAMJUYNs9wNhzViGM,6764
18
18
  tunacode/cli/commands/implementations/development.py,sha256=I8jHgYY3VgjTU8its0D0ysruuVqKbNTBur0JjPIUIZA,2844
19
19
  tunacode/cli/commands/implementations/model.py,sha256=uthx6IX9KwgwywNTDklkJpqCbaTX9h1_p-eVmqL73WQ,2245
20
+ tunacode/cli/commands/implementations/plan.py,sha256=gFMcwoz9glLctvkyuNMqIkxoK6RAZA4f7JLQOBtgtqk,1865
20
21
  tunacode/cli/commands/implementations/system.py,sha256=2cGw5iCJO3aNhXTFF28CgAIyLgslvHmpfyL2ZHVB6oQ,7903
21
22
  tunacode/cli/commands/implementations/template.py,sha256=YeFOjbKKfPswPCHPvlDUwXvg6J0MesyAyVsujiIgPbU,5482
22
23
  tunacode/cli/commands/implementations/todo.py,sha256=Dtz5bgcuK2VXGPWEBBZQgnWUMYkRXNzTGf_qkVPLF2U,8125
23
24
  tunacode/cli/repl_components/__init__.py,sha256=5ZjPJ3yUvZ5x6Vg9EYJ03-tdxfEEdmfradCmwSlVY3E,334
24
25
  tunacode/cli/repl_components/command_parser.py,sha256=SuDRP-nt8Sq5klI4-tXkllN_4nVzji5VJ-dQvbxDmDw,880
25
26
  tunacode/cli/repl_components/error_recovery.py,sha256=yPoWXzuMi6B_Pwlm1wnFIJV55lJEOChvHGDca4XtoVI,3064
26
- tunacode/cli/repl_components/output_display.py,sha256=SGhP7Hc1ymfZf-AvrkELgdJCZ3UVEzTx2Y6W737zdoY,816
27
- tunacode/cli/repl_components/tool_executor.py,sha256=p5oSpoO0qkiKr9fsgIQVSXCv6ZiSWk8QtPb_x7IpKhE,3147
27
+ tunacode/cli/repl_components/output_display.py,sha256=ry-F2fG8m_oqfWt8lhvzeEhq0XgCI_Ed4H4plibfHJ8,1437
28
+ tunacode/cli/repl_components/tool_executor.py,sha256=1E8kL0eCP9f3wx2dZtNOFY0x7_B7eHdK9zYFpc11C0Y,3754
28
29
  tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
29
30
  tunacode/configuration/defaults.py,sha256=5TUeSqMTeA7kW7gz9hND_H4s9Key0_khPvc6mNFMlZc,838
30
31
  tunacode/configuration/models.py,sha256=buH8ZquvcYI3OQBDIZeJ08cu00rSCeNABtUwl3VQS0E,4103
31
32
  tunacode/configuration/settings.py,sha256=9wtIWBlLhW_ZBlLx-GA4XDfVZyGj2Gs6Zk49vk-nHq0,1047
32
33
  tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
34
  tunacode/core/code_index.py,sha256=jgAx3lSWP_DwnyiP5Jkm1YvX4JJyI4teMzlNrJSpEOA,15661
34
- tunacode/core/state.py,sha256=RGBTOHTpe4z42MbIjRKhGNz9MIGyY0QbpdDJMldm53o,6284
35
- tunacode/core/tool_handler.py,sha256=FqA3w8M_fhpyOQKJIgl_8MAhSFVEguufbZH6gm_b7NI,2932
35
+ tunacode/core/state.py,sha256=IDCoHOWn40BBAXnd2h8OCpMtQRpt2d95KUgX8vkHu6M,7897
36
+ tunacode/core/tool_handler.py,sha256=A9wbnSpS0DsyqcOOS57I6txiuc74HEZ5mlc4qkRIgK0,3658
36
37
  tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
37
38
  tunacode/core/agents/main.py,sha256=myz_K2lxqYH8pQdbw8n8bai8F40Mqfj-kTLagPR1dP4,18253
38
39
  tunacode/core/agents/utils.py,sha256=dJsdbvWs48vxQpwAtUjJLMj7_huv12Mx3E2CEgwoK94,14467
39
40
  tunacode/core/agents/agent_components/__init__.py,sha256=CL4XH47T6v_iYy7xCPYjyiEFNOFnkcKwbTuKw6IjKTs,1474
40
- tunacode/core/agents/agent_components/agent_config.py,sha256=6m2RBZ7Y-0p_KFBVmfPW4ZGLGzTAw3YFQ4i94qsqEpM,4373
41
+ tunacode/core/agents/agent_components/agent_config.py,sha256=MwYGFvUGxgENU_IOy76EECA1TXc4Jc4-jeZctxZ8RSE,9664
41
42
  tunacode/core/agents/agent_components/agent_helpers.py,sha256=G3zF5GPRzBhA3yOcsXf8gar892ackGDcwFk9wM6FA9s,8119
42
43
  tunacode/core/agents/agent_components/json_tool_parser.py,sha256=HuyNT0rs-ppx_gLAI2e0XMVGbR_F0WXZfP3sx38VoMg,3447
43
44
  tunacode/core/agents/agent_components/message_handler.py,sha256=KJGOtb9VhumgZpxxwO45HrKLhU9_MwuoWRsSQwJviNU,3704
44
- tunacode/core/agents/agent_components/node_processor.py,sha256=FmjIEJWkqc0uzRfgTINv8uJwKG7-w00mV5lgOS4Jcd8,20426
45
+ tunacode/core/agents/agent_components/node_processor.py,sha256=77XxHjBI6hFmC_c4hWguVjmHGr5o-8KA3aWHxIL6gPg,20736
45
46
  tunacode/core/agents/agent_components/response_state.py,sha256=_C2loLeyZHMFHwjGny4h0dI02UoFJcJAVaabkh9H9JQ,343
46
47
  tunacode/core/agents/agent_components/result_wrapper.py,sha256=9CFK0wpsfZx2WT4PBHfkSv22GxL1gAQuUYVMlmYtCJU,1761
47
48
  tunacode/core/agents/agent_components/task_completion.py,sha256=BSnjNEFbxlzgzcXdjdTVGeCr1RpCiAaEp_D7f5FXa5Q,819
@@ -75,9 +76,11 @@ tunacode/templates/loader.py,sha256=6_Dk4jX47_GKUAWxlHG2Mzkl9lkXFUOiAdlcJqb6rBA,
75
76
  tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
76
77
  tunacode/tools/base.py,sha256=DhlanZZZxU2JJaBOwwyGFKMUcoCWR_CzLuwVeSXC0Go,7297
77
78
  tunacode/tools/bash.py,sha256=mgZqugfDFevZ4BETuUv90pzXvtq7qKGUGFiuDxzmytk,8766
79
+ tunacode/tools/exit_plan_mode.py,sha256=UCtoqBPlT7auP2VJ1_KDsPIB9FatylqwQdD7cU4kz2g,7683
78
80
  tunacode/tools/glob.py,sha256=mQwVGC8dfvzwzUOeTikfnHhExnLcYnGQwDoHOWrt_fE,10342
79
81
  tunacode/tools/grep.py,sha256=SfpLazOMbizganPO16w7v6iHRcUn0cD6-6lyUwrl-3U,17834
80
82
  tunacode/tools/list_dir.py,sha256=1kNqzYCNlcA5rqXIEVqcjQy6QxlLZLj5AG6YIECfwio,7217
83
+ tunacode/tools/present_plan.py,sha256=dxHlFMIeiSfxuXSkox7znw4YsrteyXswWNHpcbDz8XU,7988
81
84
  tunacode/tools/read_file.py,sha256=z2omev9xzj4-0GG9mRssD13rj-Aa1c-pszFi2Z7Hxvk,3268
82
85
  tunacode/tools/read_file_async_poc.py,sha256=2v2ckLQlwahgPGWGdE2c5Es37B35Y7zWdseZwT46E1E,6453
83
86
  tunacode/tools/run_command.py,sha256=7UvXjFQI1Av4vceXx48MbQCTrsFNj4PlygTAAhNDYIA,4376
@@ -94,15 +97,15 @@ tunacode/ui/completers.py,sha256=18f1Im5210-b-qNKyCoOMnSjW99FXNoF0DtgRvEWTm0,490
94
97
  tunacode/ui/console.py,sha256=HfE30vUy8ebXCobP7psFNJc17-dvH6APChg2tbi7aTw,2632
95
98
  tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
96
99
  tunacode/ui/decorators.py,sha256=jJDNztO8MyX_IG1nqXAL8-sQUFjaAzBnc5BsM3ioX24,1955
97
- tunacode/ui/input.py,sha256=NCZlj5qzNPy0gsSeGKeDNdAOMKZVGph8Z-UBXhX-Sbk,3020
98
- tunacode/ui/keybindings.py,sha256=YUyi6I0xXs9mNjT0qnKh_SXsfSYb6eNUD44pV_q5TVI,1685
100
+ tunacode/ui/input.py,sha256=xnxpprr5K6Asd6vezvVhStnQEdKeY7f7pwo849X8UeE,3305
101
+ tunacode/ui/keybindings.py,sha256=vyETOZiEuWnnCsrd_bmnlbon6qLD0fK6llG9oU500zY,2373
99
102
  tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
100
103
  tunacode/ui/logging_compat.py,sha256=5v6lcjVaG1CxdY1Zm9FAGr9H7Sy-tP6ihGfhP-5YvAY,1406
101
104
  tunacode/ui/output.py,sha256=C2LHKAZxBySsIfk9saJ-jZrsZBE7f3WeP-RHpn5TChQ,6808
102
- tunacode/ui/panels.py,sha256=wccIQ-exLs5oBedFZRU1lsY69fRqf-em_5gTTRM0Luc,11527
103
- tunacode/ui/prompt_manager.py,sha256=489r-WtuR3gdaugEr1lSV7SvtmXF2IlhDQckvzjYG2c,4676
105
+ tunacode/ui/panels.py,sha256=0U63lISyrqE7FMOllaPx_Cp9hRGIR6Ra2NdGTCCR2oE,12381
106
+ tunacode/ui/prompt_manager.py,sha256=ENT2eqdOO5Hlf4Ga7kXaPVS4QNjxD2E7NQN6AmHQRPM,5522
104
107
  tunacode/ui/tool_descriptions.py,sha256=vk61JPIXy7gHNfJ--77maXgK6WwNwxqY47QYsw_a2uw,4126
105
- tunacode/ui/tool_ui.py,sha256=bLydo5Y42b2gbUMP2kM6m_stIkj4Q1wbwaqO-1P6O1g,7198
108
+ tunacode/ui/tool_ui.py,sha256=MVmBLXx6OTJVFLl58SpoW0KoStOrbAY9sc6XXMKgWtQ,7216
106
109
  tunacode/ui/utils.py,sha256=yvoCTz8AOdRfV0XIqUX3sgg88g_wntV9yhnQP6WzAVs,114
107
110
  tunacode/ui/validators.py,sha256=MMIMT1I2v0l2jIy-gxX_4GSApvUTi8XWIOACr_dmoBA,758
108
111
  tunacode/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -110,7 +113,7 @@ tunacode/utils/bm25.py,sha256=fd59YQXovC8rXwZrdoqIAfFrLn_WCVjzCh0pkU22APE,1966
110
113
  tunacode/utils/diff_utils.py,sha256=V9QqQ0q4MfabVTnWptF3IXDp3estnfOKcJtDe_Sj14I,2372
111
114
  tunacode/utils/file_utils.py,sha256=84g-MQRzmBI2aG_CuXsDl2OhvvWoSL7YdL5Kz_UKSwk,979
112
115
  tunacode/utils/import_cache.py,sha256=q_xjJbtju05YbFopLDSkIo1hOtCx3DOTl3GQE5FFDgs,295
113
- tunacode/utils/message_utils.py,sha256=qb_EgPRq5a4pbQNcCLhmfcQVQ6vjekjsfgKrhIiszGQ,610
116
+ tunacode/utils/message_utils.py,sha256=V4MrZZPmwO22_MVGupMqtE5ltQEBwaSIqGD5LEb_bLw,1050
114
117
  tunacode/utils/retry.py,sha256=AHdUzY6m-mwlT4OPXdtWWMAafL_NeS7JAMORGyM8c5k,4931
115
118
  tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
116
119
  tunacode/utils/security.py,sha256=i3eGKg4o-qY2S_ObTlEaHO93q14iBfiPXR5O7srHn58,6579
@@ -118,9 +121,9 @@ tunacode/utils/system.py,sha256=J8KqJ4ZqQrNSnM5rrJxPeMk9z2xQQp6dWtI1SKBY1-0,1112
118
121
  tunacode/utils/text_utils.py,sha256=HAwlT4QMy41hr53cDbbNeNo05MI461TpI9b_xdIv8EY,7288
119
122
  tunacode/utils/token_counter.py,sha256=dmFuqVz4ywGFdLfAi5Mg9bAGf8v87Ek-mHU-R3fsYjI,2711
120
123
  tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
121
- tunacode_cli-0.0.55.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
122
- tunacode_cli-0.0.55.dist-info/METADATA,sha256=nB8M3oUVfbFFUBxldQFl86PjnnuxhhL6KGeal1iE88g,10193
123
- tunacode_cli-0.0.55.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
- tunacode_cli-0.0.55.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
125
- tunacode_cli-0.0.55.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
126
- tunacode_cli-0.0.55.dist-info/RECORD,,
124
+ tunacode_cli-0.0.56.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
125
+ tunacode_cli-0.0.56.dist-info/METADATA,sha256=92Fa9XfK5XiYYOwiHlKuWHbnFkb0cGX1tAVOGwLalXQ,10773
126
+ tunacode_cli-0.0.56.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
127
+ tunacode_cli-0.0.56.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
128
+ tunacode_cli-0.0.56.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
129
+ tunacode_cli-0.0.56.dist-info/RECORD,,