indent 0.1.5__tar.gz → 0.1.6__tar.gz

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 indent might be problematic. Click here for more details.

Files changed (56) hide show
  1. {indent-0.1.5 → indent-0.1.6}/PKG-INFO +1 -1
  2. indent-0.1.6/exponent/__init__.py +1 -0
  3. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/cli_rpc_types.py +16 -0
  4. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/tool_execution.py +81 -0
  5. {indent-0.1.5 → indent-0.1.6}/pyproject.toml +1 -1
  6. indent-0.1.5/exponent/__init__.py +0 -1
  7. {indent-0.1.5 → indent-0.1.6}/.gitignore +0 -0
  8. {indent-0.1.5 → indent-0.1.6}/exponent/cli.py +0 -0
  9. {indent-0.1.5 → indent-0.1.6}/exponent/commands/cloud_commands.py +0 -0
  10. {indent-0.1.5 → indent-0.1.6}/exponent/commands/common.py +0 -0
  11. {indent-0.1.5 → indent-0.1.6}/exponent/commands/config_commands.py +0 -0
  12. {indent-0.1.5 → indent-0.1.6}/exponent/commands/github_app_commands.py +0 -0
  13. {indent-0.1.5 → indent-0.1.6}/exponent/commands/listen_commands.py +0 -0
  14. {indent-0.1.5 → indent-0.1.6}/exponent/commands/run_commands.py +0 -0
  15. {indent-0.1.5 → indent-0.1.6}/exponent/commands/settings.py +0 -0
  16. {indent-0.1.5 → indent-0.1.6}/exponent/commands/shell_commands.py +0 -0
  17. {indent-0.1.5 → indent-0.1.6}/exponent/commands/theme.py +0 -0
  18. {indent-0.1.5 → indent-0.1.6}/exponent/commands/types.py +0 -0
  19. {indent-0.1.5 → indent-0.1.6}/exponent/commands/upgrade.py +0 -0
  20. {indent-0.1.5 → indent-0.1.6}/exponent/commands/utils.py +0 -0
  21. {indent-0.1.5 → indent-0.1.6}/exponent/commands/workflow_commands.py +0 -0
  22. {indent-0.1.5 → indent-0.1.6}/exponent/core/config.py +0 -0
  23. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/__init__.py +0 -0
  24. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/client.py +0 -0
  25. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/cloud_config_queries.py +0 -0
  26. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/get_chats_query.py +0 -0
  27. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/github_config_queries.py +0 -0
  28. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/mutations.py +0 -0
  29. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/queries.py +0 -0
  30. {indent-0.1.5 → indent-0.1.6}/exponent/core/graphql/subscriptions.py +0 -0
  31. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/checkpoints.py +0 -0
  32. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/client.py +0 -0
  33. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/code_execution.py +0 -0
  34. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/error_info.py +0 -0
  35. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/exceptions.py +0 -0
  36. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/file_write.py +0 -0
  37. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/files.py +0 -0
  38. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/git.py +0 -0
  39. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/languages/python_execution.py +0 -0
  40. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/languages/shell_streaming.py +0 -0
  41. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/languages/types.py +0 -0
  42. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/session.py +0 -0
  43. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/system_context.py +0 -0
  44. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/truncation.py +0 -0
  45. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/types.py +0 -0
  46. {indent-0.1.5 → indent-0.1.6}/exponent/core/remote_execution/utils.py +0 -0
  47. {indent-0.1.5 → indent-0.1.6}/exponent/core/types/__init__.py +0 -0
  48. {indent-0.1.5 → indent-0.1.6}/exponent/core/types/command_data.py +0 -0
  49. {indent-0.1.5 → indent-0.1.6}/exponent/core/types/event_types.py +0 -0
  50. {indent-0.1.5 → indent-0.1.6}/exponent/core/types/generated/__init__.py +0 -0
  51. {indent-0.1.5 → indent-0.1.6}/exponent/core/types/generated/strategy_info.py +0 -0
  52. {indent-0.1.5 → indent-0.1.6}/exponent/migration-docs/login.md +0 -0
  53. {indent-0.1.5 → indent-0.1.6}/exponent/py.typed +0 -0
  54. {indent-0.1.5 → indent-0.1.6}/exponent/utils/__init__.py +0 -0
  55. {indent-0.1.5 → indent-0.1.6}/exponent/utils/colors.py +0 -0
  56. {indent-0.1.5 → indent-0.1.6}/exponent/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indent
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: Indent is an AI Pair Programmer
5
5
  Author-email: Sashank Thupukari <sashank@exponent.run>
6
6
  Requires-Python: <3.13,>=3.10
@@ -0,0 +1 @@
1
+ __version__ = "0.1.6" # Keep in sync with pyproject.toml
@@ -104,6 +104,20 @@ class GrepToolResult(ToolResult, tag=GREP_TOOL_NAME):
104
104
  truncated: bool = False
105
105
 
106
106
 
107
+ EDIT_TOOL_NAME = "edit"
108
+
109
+
110
+ class EditToolInput(ToolInput, tag=EDIT_TOOL_NAME):
111
+ file_path: str
112
+ old_string: str
113
+ new_string: str
114
+ replace_all: bool = False
115
+
116
+
117
+ class EditToolResult(ToolResult, tag=EDIT_TOOL_NAME):
118
+ message: str
119
+
120
+
107
121
  BASH_TOOL_NAME = "bash"
108
122
 
109
123
 
@@ -131,6 +145,7 @@ ToolInputType = (
131
145
  | ListToolInput
132
146
  | GlobToolInput
133
147
  | GrepToolInput
148
+ | EditToolInput
134
149
  | BashToolInput
135
150
  )
136
151
  PartialToolResultType = PartialBashToolResult
@@ -141,6 +156,7 @@ ToolResultType = (
141
156
  | ListToolResult
142
157
  | GlobToolResult
143
158
  | GrepToolResult
159
+ | EditToolResult
144
160
  | BashToolResult
145
161
  | ErrorToolResult
146
162
  )
@@ -9,6 +9,8 @@ from exponent.core.remote_execution import files
9
9
  from exponent.core.remote_execution.cli_rpc_types import (
10
10
  BashToolInput,
11
11
  BashToolResult,
12
+ EditToolInput,
13
+ EditToolResult,
12
14
  ErrorToolResult,
13
15
  GlobToolInput,
14
16
  GlobToolResult,
@@ -51,6 +53,8 @@ async def execute_tool(
51
53
  return await execute_glob_files(tool_input, working_directory)
52
54
  elif isinstance(tool_input, GrepToolInput):
53
55
  return await execute_grep_files(tool_input, working_directory)
56
+ elif isinstance(tool_input, EditToolInput):
57
+ return await execute_edit_file(tool_input, working_directory)
54
58
  elif isinstance(tool_input, BashToolInput):
55
59
  raise ValueError("Bash tool input should be handled by execute_bash_tool")
56
60
  else:
@@ -190,6 +194,83 @@ async def execute_write_file(
190
194
  return WriteToolResult(message=result)
191
195
 
192
196
 
197
+ async def execute_edit_file( # noqa: PLR0911
198
+ tool_input: EditToolInput, working_directory: str
199
+ ) -> EditToolResult | ErrorToolResult:
200
+ # Validate absolute path requirement
201
+ if not tool_input.file_path.startswith("/"):
202
+ return ErrorToolResult(
203
+ error_message=f"File path must be absolute, got relative path: {tool_input.file_path}"
204
+ )
205
+
206
+ file = AsyncPath(working_directory, tool_input.file_path)
207
+
208
+ try:
209
+ exists = await file.exists()
210
+ except (OSError, PermissionError) as e:
211
+ return ErrorToolResult(error_message=f"Cannot access file: {e!s}")
212
+
213
+ if not exists:
214
+ return ErrorToolResult(error_message="File not found")
215
+
216
+ try:
217
+ if await file.is_dir():
218
+ return ErrorToolResult(
219
+ error_message=f"{await file.absolute()} is a directory"
220
+ )
221
+ except (OSError, PermissionError) as e:
222
+ return ErrorToolResult(error_message=f"Cannot check file type: {e!s}")
223
+
224
+ try:
225
+ # Read the entire file without truncation limits
226
+ content = await safe_read_file(file)
227
+ except PermissionError:
228
+ return ErrorToolResult(
229
+ error_message=f"Permission denied: cannot read {tool_input.file_path}"
230
+ )
231
+ except UnicodeDecodeError:
232
+ return ErrorToolResult(
233
+ error_message="File appears to be binary or has invalid text encoding"
234
+ )
235
+ except Exception as e: # noqa: BLE001
236
+ return ErrorToolResult(error_message=f"Error reading file: {e!s}")
237
+
238
+ # Check if search text exists
239
+ if tool_input.old_string not in content:
240
+ return ErrorToolResult(
241
+ error_message=f"Search text not found in {tool_input.file_path}"
242
+ )
243
+
244
+ # Check if old_string and new_string are identical
245
+ if tool_input.old_string == tool_input.new_string:
246
+ return ErrorToolResult(error_message="Old string and new string are identical")
247
+
248
+ # Check uniqueness if replace_all is False
249
+ if not tool_input.replace_all:
250
+ occurrences = content.count(tool_input.old_string)
251
+ if occurrences > 1:
252
+ return ErrorToolResult(
253
+ error_message=f"String '{tool_input.old_string}' appears {occurrences} times in file. Use a larger context or replace_all=True"
254
+ )
255
+
256
+ # Perform replacement
257
+ if tool_input.replace_all:
258
+ new_content = content.replace(tool_input.old_string, tool_input.new_string)
259
+ else:
260
+ # Replace only the first occurrence
261
+ new_content = content.replace(tool_input.old_string, tool_input.new_string, 1)
262
+
263
+ # Write back to file
264
+ try:
265
+ path = Path(working_directory, tool_input.file_path)
266
+ await execute_full_file_rewrite(path, new_content, working_directory)
267
+ return EditToolResult(
268
+ message=f"Successfully replaced text in {tool_input.file_path}"
269
+ )
270
+ except Exception as e: # noqa: BLE001
271
+ return ErrorToolResult(error_message=f"Error writing file: {e!s}")
272
+
273
+
193
274
  async def execute_list_files(
194
275
  tool_input: ListToolInput, working_directory: str
195
276
  ) -> ListToolResult | ErrorToolResult:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "indent"
7
- version = "0.1.5"
7
+ version = "0.1.6"
8
8
  description = "Indent is an AI Pair Programmer"
9
9
  authors = [{ name = "Sashank Thupukari", email = "sashank@exponent.run" }]
10
10
  requires-python = ">=3.10,<3.13"
@@ -1 +0,0 @@
1
- __version__ = "0.1.5" # Keep in sync with pyproject.toml
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes