tass 0.1.5__py3-none-any.whl → 0.1.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.
src/app.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import os
3
3
  import subprocess
4
+ from pathlib import Path
4
5
 
5
6
  import requests
6
7
  from rich.console import Console
@@ -56,7 +57,7 @@ class TassApp:
56
57
  console.print(f"[red]Unable to verify new host {self.host}. Continuing with it anyway.[/red]")
57
58
 
58
59
  def summarize(self):
59
- max_messages = 10
60
+ max_messages = 20
60
61
  if len(self.messages) <= max_messages:
61
62
  return
62
63
 
@@ -165,22 +166,52 @@ class TassApp:
165
166
  console.print(" [green]Command succeeded[/green]")
166
167
  return "".join(lines)
167
168
 
168
- def edit_file(self, path: str, line_start: int, line_end: int, replace: str) -> str:
169
- with open(path, "r") as f:
170
- original_content = f.read()
169
+ def edit_file(self, path: str, edits: list[dict]) -> str:
170
+ for edit in edits:
171
+ edit["applied"] = False
171
172
 
173
+ def find_edit(n: int) -> dict | None:
174
+ for edit in edits:
175
+ if edit["line_start"] <= n <= edit["line_end"]:
176
+ return edit
177
+
178
+ return None
179
+
180
+ file_exists = Path(path).exists()
181
+ if file_exists:
182
+ with open(path, "r") as f:
183
+ original_content = f.read()
184
+ else:
185
+ original_content = ""
186
+
187
+ final_lines = []
172
188
  original_lines = original_content.split("\n")
173
- replaced_lines = original_lines[line_start - 1:line_end]
174
- new_content = "\n".join(
175
- original_lines[:line_start - 1]
176
- + replace.split("\n")
177
- + original_lines[line_end:]
178
- )
189
+ diff_text = f"{'Editing' if file_exists else 'Creating'} {path}"
190
+ for i, line in enumerate(original_lines):
191
+ line_num = i + 1
192
+ edit = find_edit(line_num)
193
+ if not edit:
194
+ final_lines.append(line)
195
+ continue
196
+
197
+ if edit["applied"]:
198
+ continue
199
+
200
+ replace_lines = edit["replace"].split("\n")
201
+ final_lines.extend(replace_lines)
202
+ original_lines = original_content.split("\n")
203
+ replaced_lines = original_lines[edit["line_start"] - 1:edit["line_end"]]
204
+
205
+ prev_line_num = line_num if line_num == 1 else line_num - 1
206
+ line_before = "" if i == 0 else f" {original_lines[i - 1]}\n"
207
+ line_after = "" if i == len(original_lines) - 1 else f"\n {original_lines[i + 1]}"
208
+ replaced_with_minuses = "\n".join([f"-{line}" for line in replaced_lines]) if file_exists else ""
209
+ replace_with_pluses = "\n".join([f"+{line}" for line in edit["replace"].split("\n")])
210
+ diff_text = f"{diff_text}\n\n@@ -{prev_line_num},{len(replaced_lines)} +{prev_line_num},{len(replace_lines)} @@\n{line_before}{replaced_with_minuses}\n{replace_with_pluses}{line_after}"
211
+ edit["applied"] = True
179
212
 
180
- replaced_with_minuses = "\n".join([f"-{line}" for line in replaced_lines])
181
- replace_with_pluses = "\n".join([f"+{line}" for line in replace.split("\n")])
182
213
  console.print()
183
- console.print(Markdown(f"```diff\nEditing {path}\n{replaced_with_minuses}\n{replace_with_pluses}\n```"))
214
+ console.print(Markdown(f"```diff\n{diff_text}\n```"))
184
215
  answer = console.input("\n[bold]Run?[/] ([bold]Y[/]/n): ").strip().lower()
185
216
  if answer not in ("yes", "y", ""):
186
217
  reason = console.input("Why not? (optional, press Enter to skip): ").strip()
@@ -189,7 +220,7 @@ class TassApp:
189
220
  console.print(" └ Running...")
190
221
  try:
191
222
  with open(path, "w") as f:
192
- f.write(new_content)
223
+ f.write("\n".join(final_lines))
193
224
  except Exception as e:
194
225
  console.print(" [red]edit_file failed[/red]")
195
226
  console.print(f" [red]{str(e)}[/red]")
src/constants.py CHANGED
@@ -37,7 +37,7 @@ TOOLS = [
37
37
  "type": "function",
38
38
  "function": {
39
39
  "name": "edit_file",
40
- "description": "Edits a file. Removes the contents between the lines 'line_start' and 'line_end' inclusive entirely and replaces it with 'replace'.",
40
+ "description": "Edits (or creates) a file. Makes multiple replacements in one call. Each edit removes the contents between 'line_start' and 'line_end' inclusive and replaces it with 'replace'. If creating a file, only return a single edit where the line_start and line_end are both 1 and replace is the entire contents of the file.",
41
41
  "parameters": {
42
42
  "type": "object",
43
43
  "properties": {
@@ -45,20 +45,30 @@ TOOLS = [
45
45
  "type": "string",
46
46
  "description": "Relative path of the file",
47
47
  },
48
- "line_start": {
49
- "type": "integer",
50
- "description": "The first line to remove the contents of (inclusive)",
51
- },
52
- "line_end": {
53
- "type": "integer",
54
- "description": "The last line to remove the contents of (inclusive)",
55
- },
56
- "replace": {
57
- "type": "string",
58
- "description": "The string to replace with. Must have the correct spacing and indentation for all lines.",
48
+ "edits": {
49
+ "type": "array",
50
+ "description": "List of edits to apply. Each edit must contain 'line_start', 'line_end', and 'replace'.",
51
+ "items": {
52
+ "type": "object",
53
+ "properties": {
54
+ "line_start": {
55
+ "type": "integer",
56
+ "description": "The first line to remove (inclusive)",
57
+ },
58
+ "line_end": {
59
+ "type": "integer",
60
+ "description": "The last line to remove (inclusive)",
61
+ },
62
+ "replace": {
63
+ "type": "string",
64
+ "description": "The string to replace with. Must have the correct spacing and indentation for all lines.",
65
+ },
66
+ },
67
+ "required": ["line_start", "line_end", "replace"],
68
+ },
59
69
  },
60
70
  },
61
- "required": ["path", "find", "replace"],
71
+ "required": ["path", "edits"],
62
72
  "$schema": "http://json-schema.org/draft-07/schema#",
63
73
  },
64
74
  },
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tass
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: A terminal assistant that allows you to ask an LLM to run commands.
5
5
  Project-URL: Homepage, https://github.com/cetincan0/tass
6
6
  Author: Can Cetin
@@ -33,4 +33,4 @@ tass
33
33
 
34
34
  tass has only been tested with gpt-oss-120b using llama.cpp so far, but in theory any LLM with tool calling capabilities should work. By default, it will try connecting to http://localhost:8080. If you want to use another host, set the `TASS_HOST` environment variable.
35
35
 
36
- Once it's running, you can ask questions like "Can you create an empty file called test.txt?" and it will propose a command to run after user confirmation.
36
+ Once it's running, you can ask questions or give commands like "Create an empty file called test.txt" and it will propose a command to run after user confirmation.
@@ -0,0 +1,10 @@
1
+ src/__init__.py,sha256=tu2q9W5_pkq30l3tRMTGahColBAAubbLP6LaB3l3IFg,89
2
+ src/app.py,sha256=SZGIStkRskTraOARKR-sh8hjfQT7EXwJBG-oymIABhU,11466
3
+ src/cli.py,sha256=op3fYcyfek_KqCCiA-Zdlc9jVZSCi036whMmR2ZjjAs,76
4
+ src/constants.py,sha256=2MWn3-tvZjJ2xW68BE7S1V8CgqDuBt3cBG5Bx8ILrKY,4620
5
+ src/utils.py,sha256=rKq34DVmFbsWPy7R6Bfdvv1ztzFLPT4hUd8BFpPHjqs,681
6
+ tass-0.1.6.dist-info/METADATA,sha256=xu-OHc1sIrlDrxXVCUSdPmzYnjVam5tYB96EYJiTWCc,1079
7
+ tass-0.1.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
8
+ tass-0.1.6.dist-info/entry_points.txt,sha256=pviKuIOuHvaQ7_YiFxatJEY8XYfh3EzVWy4LJh0v-A0,38
9
+ tass-0.1.6.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
10
+ tass-0.1.6.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- src/__init__.py,sha256=tu2q9W5_pkq30l3tRMTGahColBAAubbLP6LaB3l3IFg,89
2
- src/app.py,sha256=Jej2qjyBRqQREpvm6WWvd6cPy9RLzW74rYegeM8ICPI,10224
3
- src/cli.py,sha256=op3fYcyfek_KqCCiA-Zdlc9jVZSCi036whMmR2ZjjAs,76
4
- src/constants.py,sha256=gFIMWh38-uyh2XJdiKUsOwAh7yk4jbdfxmeJZ9yl4fw,3847
5
- src/utils.py,sha256=rKq34DVmFbsWPy7R6Bfdvv1ztzFLPT4hUd8BFpPHjqs,681
6
- tass-0.1.5.dist-info/METADATA,sha256=HskJ2m7qsulvtK_N5nZ_aJAcq1PH5zGMDnYMm_cjda8,1071
7
- tass-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
8
- tass-0.1.5.dist-info/entry_points.txt,sha256=pviKuIOuHvaQ7_YiFxatJEY8XYfh3EzVWy4LJh0v-A0,38
9
- tass-0.1.5.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
10
- tass-0.1.5.dist-info/RECORD,,
File without changes