wcgw 2.1.1__tar.gz → 2.2.0__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 wcgw might be problematic. Click here for more details.

Files changed (39) hide show
  1. {wcgw-2.1.1 → wcgw-2.2.0}/PKG-INFO +14 -3
  2. {wcgw-2.1.1 → wcgw-2.2.0}/README.md +13 -1
  3. {wcgw-2.1.1 → wcgw-2.2.0}/gpt_action_json_schema.json +3 -3
  4. {wcgw-2.1.1 → wcgw-2.2.0}/gpt_instructions.txt +4 -3
  5. {wcgw-2.1.1 → wcgw-2.2.0}/pyproject.toml +1 -2
  6. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/anthropic_client.py +14 -8
  7. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/mcp_server/server.py +8 -7
  8. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/openai_client.py +5 -4
  9. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/tools.py +16 -12
  10. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/relay/serve.py +4 -4
  11. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/types_.py +1 -1
  12. {wcgw-2.1.1 → wcgw-2.2.0}/tests/test_tools.py +2 -2
  13. {wcgw-2.1.1 → wcgw-2.2.0}/uv.lock +1 -3
  14. {wcgw-2.1.1 → wcgw-2.2.0}/.github/workflows/python-publish.yml +0 -0
  15. {wcgw-2.1.1 → wcgw-2.2.0}/.github/workflows/python-tests.yml +0 -0
  16. {wcgw-2.1.1 → wcgw-2.2.0}/.github/workflows/python-types.yml +0 -0
  17. {wcgw-2.1.1 → wcgw-2.2.0}/.gitignore +0 -0
  18. {wcgw-2.1.1 → wcgw-2.2.0}/.python-version +0 -0
  19. {wcgw-2.1.1 → wcgw-2.2.0}/.vscode/settings.json +0 -0
  20. {wcgw-2.1.1 → wcgw-2.2.0}/openai.md +0 -0
  21. {wcgw-2.1.1 → wcgw-2.2.0}/src/__init__.py +0 -0
  22. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/__init__.py +0 -0
  23. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/__init__.py +0 -0
  24. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/__main__.py +0 -0
  25. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/cli.py +0 -0
  26. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/common.py +0 -0
  27. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/computer_use.py +0 -0
  28. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/diff-instructions.txt +0 -0
  29. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/mcp_server/Readme.md +0 -0
  30. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/mcp_server/__init__.py +0 -0
  31. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/openai_utils.py +0 -0
  32. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/client/sys_utils.py +0 -0
  33. {wcgw-2.1.1 → wcgw-2.2.0}/src/wcgw/relay/static/privacy.txt +0 -0
  34. {wcgw-2.1.1 → wcgw-2.2.0}/static/claude-ss.jpg +0 -0
  35. {wcgw-2.1.1 → wcgw-2.2.0}/static/computer-use.jpg +0 -0
  36. {wcgw-2.1.1 → wcgw-2.2.0}/static/example.jpg +0 -0
  37. {wcgw-2.1.1 → wcgw-2.2.0}/static/rocket-icon.png +0 -0
  38. {wcgw-2.1.1 → wcgw-2.2.0}/static/ss1.png +0 -0
  39. {wcgw-2.1.1 → wcgw-2.2.0}/tests/test_basic.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wcgw
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: Shell and coding agent on claude and chatgpt
5
5
  Project-URL: Homepage, https://github.com/rusiaaman/wcgw
6
6
  Author-email: Aman Rusia <gapypi@arcfu.com>
@@ -9,7 +9,6 @@ Requires-Dist: anthropic>=0.39.0
9
9
  Requires-Dist: fastapi>=0.115.0
10
10
  Requires-Dist: humanize>=4.11.0
11
11
  Requires-Dist: mcp
12
- Requires-Dist: mypy>=1.11.2
13
12
  Requires-Dist: nltk>=3.9.1
14
13
  Requires-Dist: openai>=1.46.0
15
14
  Requires-Dist: petname>=2.6
@@ -33,12 +32,17 @@ Description-Content-Type: text/markdown
33
32
  - Claude - An MCP server on claude desktop for autonomous shell, coding and desktop control agent. (mac only)
34
33
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
35
34
 
35
+
36
+ ⚠️ Warning: do not use this repo if you aren't scared of "Autonomous shell command execution"
37
+
36
38
  [![Tests](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml)
37
39
  [![Mypy strict](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml)
38
40
  [![Build](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml/badge.svg)](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml)
39
41
 
40
42
  ## Updates
41
43
 
44
+ - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
45
+
42
46
  - [01 Dec 2024] Removed author hosted relay server for chatgpt.
43
47
 
44
48
  - [26 Nov 2024] Introduced claude desktop support through mcp
@@ -143,7 +147,7 @@ The following requirements should be installed and working in the linux docker i
143
147
  2. Needs `scrot` to take screenshots.
144
148
  3. Needs `convert` from imagemagick to convert images.
145
149
 
146
- ## Usage
150
+ ### Usage
147
151
 
148
152
  Wait for a few seconds. You should be able to see this icon if everything goes right.
149
153
 
@@ -156,6 +160,13 @@ Then ask claude to execute shell commands, read files, edit files, run your code
156
160
 
157
161
  If you've run the docker for LLM to access, you can ask it to control the "docker os". If you don't provide the docker container id to it, it'll try to search for available docker using `docker ps` command.
158
162
 
163
+
164
+ ### [Optional] Vs code extension
165
+ https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
166
+
167
+ Commands:
168
+ - Select a text and press `cmd+'` and then enter instructions. This will switch the app to Claude and paste a text containing your instructions, file path, workspace dir, and the selected text.
169
+
159
170
  ## Chatgpt Setup
160
171
 
161
172
  Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
@@ -3,12 +3,17 @@
3
3
  - Claude - An MCP server on claude desktop for autonomous shell, coding and desktop control agent. (mac only)
4
4
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
5
5
 
6
+
7
+ ⚠️ Warning: do not use this repo if you aren't scared of "Autonomous shell command execution"
8
+
6
9
  [![Tests](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml)
7
10
  [![Mypy strict](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml)
8
11
  [![Build](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml/badge.svg)](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml)
9
12
 
10
13
  ## Updates
11
14
 
15
+ - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
16
+
12
17
  - [01 Dec 2024] Removed author hosted relay server for chatgpt.
13
18
 
14
19
  - [26 Nov 2024] Introduced claude desktop support through mcp
@@ -113,7 +118,7 @@ The following requirements should be installed and working in the linux docker i
113
118
  2. Needs `scrot` to take screenshots.
114
119
  3. Needs `convert` from imagemagick to convert images.
115
120
 
116
- ## Usage
121
+ ### Usage
117
122
 
118
123
  Wait for a few seconds. You should be able to see this icon if everything goes right.
119
124
 
@@ -126,6 +131,13 @@ Then ask claude to execute shell commands, read files, edit files, run your code
126
131
 
127
132
  If you've run the docker for LLM to access, you can ask it to control the "docker os". If you don't provide the docker container id to it, it'll try to search for available docker using `docker ps` command.
128
133
 
134
+
135
+ ### [Optional] Vs code extension
136
+ https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
137
+
138
+ Commands:
139
+ - Select a text and press `cmd+'` and then enter instructions. This will switch the app to Claude and paste a text containing your instructions, file path, workspace dir, and the selected text.
140
+
129
141
  ## Chatgpt Setup
130
142
 
131
143
  Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
@@ -19,7 +19,7 @@
19
19
  "content": {
20
20
  "application/json": {
21
21
  "schema": {
22
- "$ref": "#/components/schemas/CreateFileNewWithUUID"
22
+ "$ref": "#/components/schemas/WriteIfEmptyWithUUID"
23
23
  }
24
24
  }
25
25
  },
@@ -384,7 +384,7 @@
384
384
  ],
385
385
  "title": "CommandWithUUID"
386
386
  },
387
- "CreateFileNewWithUUID": {
387
+ "WriteIfEmptyWithUUID": {
388
388
  "properties": {
389
389
  "file_path": {
390
390
  "type": "string",
@@ -406,7 +406,7 @@
406
406
  "file_content",
407
407
  "user_id"
408
408
  ],
409
- "title": "CreateFileNewWithUUID"
409
+ "title": "WriteIfEmptyWithUUID"
410
410
  },
411
411
  "FileEditWithUUID": {
412
412
  "properties": {
@@ -5,7 +5,8 @@ Instructions:
5
5
  - You should use the provided bash execution, reading and writing file tools to complete objective.
6
6
  - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
7
7
  - Always read relevant files before editing.
8
- - Do not provide code snippets unless asked by the user, instead directly edit the code.
8
+ - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
9
+ - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
9
10
 
10
11
  Instructions for `Initialize`:
11
12
  - Always call this at the start of the conversation.
@@ -23,8 +24,8 @@ Instructions for `Read File`
23
24
  - Read full content of a file.
24
25
  - Provide absolute file path only.
25
26
 
26
- Instructions for `Create File New`
27
- - Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
27
+ Instructions for `Write if Empty`
28
+ - Write content to an empty or non-existent file. Provide file path and content. Use this instead of BashCommand for writing new files.
28
29
  - Provide absolute file path only.
29
30
  - For editing existing files, use FileEdit.
30
31
 
@@ -1,13 +1,12 @@
1
1
  [project]
2
2
  authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
3
3
  name = "wcgw"
4
- version = "2.1.1"
4
+ version = "2.2.0"
5
5
  description = "Shell and coding agent on claude and chatgpt"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11, <3.13"
8
8
  dependencies = [
9
9
  "openai>=1.46.0",
10
- "mypy>=1.11.2",
11
10
  "typer>=0.12.5",
12
11
  "rich>=13.8.1",
13
12
  "python-dotenv>=1.0.1",
@@ -24,7 +24,7 @@ import uuid
24
24
  from ..types_ import (
25
25
  BashCommand,
26
26
  BashInteraction,
27
- CreateFileNew,
27
+ WriteIfEmpty,
28
28
  FileEditFindReplace,
29
29
  FileEdit,
30
30
  Keyboard,
@@ -185,7 +185,7 @@ def loop(
185
185
  - Send send_specials=["Enter"] to recheck status of a running program.
186
186
  - Only one of send_text, send_specials, send_ascii should be provided.
187
187
  - This returns within 5 seconds, for heavy programs keep checking status for upto 10 turns before asking user to continue checking again.
188
- - Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again usign ["Enter"].
188
+ - Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again using ["Enter"].
189
189
 
190
190
  """,
191
191
  ),
@@ -198,10 +198,10 @@ def loop(
198
198
  """,
199
199
  ),
200
200
  ToolParam(
201
- input_schema=CreateFileNew.model_json_schema(),
202
- name="CreateFileNew",
201
+ input_schema=WriteIfEmpty.model_json_schema(),
202
+ name="WriteIfEmpty",
203
203
  description="""
204
- - Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
204
+ - Write content to an empty or non-existent file. Provide file path and content. Use this instead of BashCommand for writing new files.
205
205
  - Provide absolute file path only.
206
206
  - For editing existing files, use FileEdit instead of this tool.
207
207
  """,
@@ -246,7 +246,7 @@ def loop(
246
246
  description="""
247
247
  - Capture screenshot of the linux os on docker.
248
248
  - All actions on UI using mouse and keyboard return within 0.5 seconds.
249
- * So if you're doing something that takes longer for UI to update like heavy page loading, keep checking UI for update usign ScreenShot upto 10 turns.
249
+ * So if you're doing something that takes longer for UI to update like heavy page loading, keep checking UI for update using ScreenShot upto 10 turns.
250
250
  * Notice for smallest of the loading icons to check if your action worked.
251
251
  * After 10 turns of no change, ask user for permission to keep checking.
252
252
  * If you don't notice even slightest of the change, it's likely you clicked on the wrong place.
@@ -287,7 +287,8 @@ Instructions:
287
287
  - You should use the provided bash execution, reading and writing file tools to complete objective.
288
288
  - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
289
289
  - Always read relevant files before editing.
290
- - Do not provide code snippets unless asked by the user, instead directly edit the code.
290
+ - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
291
+ - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
291
292
 
292
293
  System information:
293
294
  - System: {uname_sysname}
@@ -494,7 +495,12 @@ System information:
494
495
  )
495
496
  else:
496
497
  _histories.append(
497
- {"role": "assistant", "content": full_response}
498
+ {
499
+ "role": "assistant",
500
+ "content": full_response
501
+ if full_response.strip()
502
+ else "...",
503
+ } # Fixes anthropic issue of non empty response only
498
504
  )
499
505
 
500
506
  except KeyboardInterrupt:
@@ -17,7 +17,7 @@ from ..tools import DoneFlag, get_tool_output, which_tool_name, default_enc
17
17
  from ...types_ import (
18
18
  BashCommand,
19
19
  BashInteraction,
20
- CreateFileNew,
20
+ WriteIfEmpty,
21
21
  FileEdit,
22
22
  Keyboard,
23
23
  Mouse,
@@ -105,7 +105,7 @@ async def handle_list_tools() -> list[types.Tool]:
105
105
  - Send send_specials=["Enter"] to recheck status of a running program.
106
106
  - Only one of send_text, send_specials, send_ascii should be provided.
107
107
  - This returns within 3 seconds, for heavy programs keep checking status for upto 10 turns before asking user to continue checking again.
108
- - Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again usign ["Enter"].
108
+ - Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again using ["Enter"].
109
109
  """,
110
110
  ),
111
111
  ToolParam(
@@ -117,10 +117,10 @@ async def handle_list_tools() -> list[types.Tool]:
117
117
  """,
118
118
  ),
119
119
  ToolParam(
120
- inputSchema=CreateFileNew.model_json_schema(),
121
- name="CreateFileNew",
120
+ inputSchema=WriteIfEmpty.model_json_schema(),
121
+ name="WriteIfEmpty",
122
122
  description="""
123
- - Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
123
+ - Write content to an empty or non-existent file. Provide file path and content. Use this instead of BashCommand for writing new files.
124
124
  - Provide absolute file path only.
125
125
  - For editing existing files, use FileEdit instead of this tool.
126
126
  """,
@@ -165,7 +165,7 @@ async def handle_list_tools() -> list[types.Tool]:
165
165
  description="""
166
166
  - Capture screenshot of the linux os on docker.
167
167
  - All actions on UI using mouse and keyboard return within 0.5 seconds.
168
- * So if you're doing something that takes longer for UI to update like heavy page loading, keep checking UI for update usign ScreenShot upto 10 turns.
168
+ * So if you're doing something that takes longer for UI to update like heavy page loading, keep checking UI for update using ScreenShot upto 10 turns.
169
169
  * Notice for smallest of the loading icons to check if your action worked.
170
170
  * After 10 turns of no change, ask user for permission to keep checking.
171
171
  * If you don't notice even slightest of the change, it's likely you clicked on the wrong place.
@@ -243,7 +243,8 @@ async def handle_call_tool(
243
243
  - You should use the provided bash execution, reading and writing file tools to complete objective.
244
244
  - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
245
245
  - Always read relevant files before editing.
246
- - Do not provide code snippets unless asked by the user, instead directly edit the code.
246
+ - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
247
+ - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
247
248
 
248
249
 
249
250
  Additional instructions:
@@ -23,7 +23,7 @@ import uuid
23
23
  from ..types_ import (
24
24
  BashCommand,
25
25
  BashInteraction,
26
- CreateFileNew,
26
+ WriteIfEmpty,
27
27
  FileEdit,
28
28
  ReadImage,
29
29
  ReadFile,
@@ -195,9 +195,9 @@ def loop(
195
195
  """,
196
196
  ),
197
197
  openai.pydantic_function_tool(
198
- CreateFileNew,
198
+ WriteIfEmpty,
199
199
  description="""
200
- - Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
200
+ - Write content to an empty or non-existent file. Provide file path and content. Use this instead of BashCommand for writing new files.
201
201
  - Provide absolute file path only.
202
202
  - For editing existing files, use FileEdit instead of this tool.""",
203
203
  ),
@@ -228,7 +228,8 @@ Instructions:
228
228
  - You should use the provided bash execution, reading and writing file tools to complete objective.
229
229
  - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
230
230
  - Always read relevant files before editing.
231
- - Do not provide code snippets unless asked by the user, instead directly edit the code.
231
+ - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
232
+ - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
232
233
 
233
234
  System information:
234
235
  - System: {uname_sysname}
@@ -55,7 +55,7 @@ from nltk.metrics.distance import edit_distance # type: ignore[import-untyped]
55
55
  from ..types_ import (
56
56
  BashCommand,
57
57
  BashInteraction,
58
- CreateFileNew,
58
+ WriteIfEmpty,
59
59
  FileEditFindReplace,
60
60
  FileEdit,
61
61
  Initialize,
@@ -531,7 +531,7 @@ def read_image_from_shell(file_path: str) -> ImageData:
531
531
  return ImageData(media_type=image_type, data=image_b64) # type: ignore
532
532
 
533
533
 
534
- def write_file(writefile: CreateFileNew, error_on_exist: bool) -> str:
534
+ def write_file(writefile: WriteIfEmpty, error_on_exist: bool) -> str:
535
535
  if not os.path.isabs(writefile.file_path):
536
536
  return f"Failure: file_path should be absolute path, current working directory is {BASH_STATE.cwd}"
537
537
  else:
@@ -620,7 +620,7 @@ def find_least_edit_distance_substring(
620
620
  + 1
621
621
  )
622
622
  min_edit_distance_lines = orig_content_lines[
623
- orig_start_index:orig_end_index
623
+ max(0, orig_start_index - 10) : (orig_end_index + 10)
624
624
  ]
625
625
  return "\n".join(min_edit_distance_lines), min_edit_distance
626
626
 
@@ -638,7 +638,9 @@ def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
638
638
  f"Exact match not found, found with whitespace removed edit distance: {min_edit_distance}"
639
639
  )
640
640
  raise Exception(
641
- f"Error: no match found for the provided `find_lines` in the file. Closest match:\n---\n{closest_match}\n---\nFile not edited"
641
+ f"""Error: no match found for the provided search block.
642
+ Requested search block: \n```\n{find_lines}\n```
643
+ Possible relevant section in the file:\n---\n```\n{closest_match}\n```\n---\nFile not edited"""
642
644
  )
643
645
 
644
646
  content = content.replace(find_lines, replace_with_lines, 1)
@@ -765,7 +767,7 @@ TOOLS = (
765
767
  | BashCommand
766
768
  | BashInteraction
767
769
  | ResetShell
768
- | CreateFileNew
770
+ | WriteIfEmpty
769
771
  | FileEditFindReplace
770
772
  | FileEdit
771
773
  | AIAssistant
@@ -794,8 +796,8 @@ def which_tool_name(name: str) -> Type[TOOLS]:
794
796
  return BashInteraction
795
797
  elif name == "ResetShell":
796
798
  return ResetShell
797
- elif name == "CreateFileNew":
798
- return CreateFileNew
799
+ elif name == "WriteIfEmpty":
800
+ return WriteIfEmpty
799
801
  elif name == "FileEditFindReplace":
800
802
  return FileEditFindReplace
801
803
  elif name == "FileEdit":
@@ -828,7 +830,7 @@ def get_tool_output(
828
830
  | BashCommand
829
831
  | BashInteraction
830
832
  | ResetShell
831
- | CreateFileNew
833
+ | WriteIfEmpty
832
834
  | FileEditFindReplace
833
835
  | FileEdit
834
836
  | AIAssistant
@@ -852,7 +854,7 @@ def get_tool_output(
852
854
  | BashCommand
853
855
  | BashInteraction
854
856
  | ResetShell
855
- | CreateFileNew
857
+ | WriteIfEmpty
856
858
  | FileEditFindReplace
857
859
  | FileEdit
858
860
  | AIAssistant
@@ -869,7 +871,7 @@ def get_tool_output(
869
871
  | BashCommand
870
872
  | BashInteraction
871
873
  | ResetShell
872
- | CreateFileNew
874
+ | WriteIfEmpty
873
875
  | FileEditFindReplace
874
876
  | FileEdit
875
877
  | AIAssistant
@@ -892,7 +894,7 @@ def get_tool_output(
892
894
  elif isinstance(arg, (BashCommand | BashInteraction)):
893
895
  console.print("Calling execute bash tool")
894
896
  output = execute_bash(enc, arg, max_tokens, None)
895
- elif isinstance(arg, CreateFileNew):
897
+ elif isinstance(arg, WriteIfEmpty):
896
898
  console.print("Calling write file tool")
897
899
  output = write_file(arg, True), 0
898
900
  elif isinstance(arg, FileEdit):
@@ -915,6 +917,8 @@ def get_tool_output(
915
917
  output = reset_shell(), 0.0
916
918
  elif isinstance(arg, Initialize):
917
919
  console.print("Calling initial info tool")
920
+ # First force reset
921
+ reset_shell()
918
922
  output = initial_info(), 0.0
919
923
  elif isinstance(arg, (Mouse, Keyboard, ScreenShot, GetScreenInfo)):
920
924
  console.print(f"Calling {type(arg).__name__} tool")
@@ -974,7 +978,7 @@ class Mdata(BaseModel):
974
978
  data: (
975
979
  BashCommand
976
980
  | BashInteraction
977
- | CreateFileNew
981
+ | WriteIfEmpty
978
982
  | ResetShell
979
983
  | FileEditFindReplace
980
984
  | FileEdit
@@ -17,7 +17,7 @@ from dotenv import load_dotenv
17
17
  from ..types_ import (
18
18
  BashCommand,
19
19
  BashInteraction,
20
- CreateFileNew,
20
+ WriteIfEmpty,
21
21
  FileEditFindReplace,
22
22
  FileEdit,
23
23
  Initialize,
@@ -31,7 +31,7 @@ class Mdata(BaseModel):
31
31
  data: (
32
32
  BashCommand
33
33
  | BashInteraction
34
- | CreateFileNew
34
+ | WriteIfEmpty
35
35
  | ResetShell
36
36
  | FileEditFindReplace
37
37
  | FileEdit
@@ -99,12 +99,12 @@ async def register_websocket(websocket: WebSocket, uuid: UUID) -> None:
99
99
  print(f"Client {uuid} disconnected")
100
100
 
101
101
 
102
- class CreateFileNewWithUUID(CreateFileNew):
102
+ class WriteIfEmptyWithUUID(WriteIfEmpty):
103
103
  user_id: UUID
104
104
 
105
105
 
106
106
  @app.post("/v1/create_file")
107
- async def create_file(write_file_data: CreateFileNewWithUUID) -> str:
107
+ async def create_file(write_file_data: WriteIfEmptyWithUUID) -> str:
108
108
  user_id = write_file_data.user_id
109
109
  if user_id not in clients:
110
110
  return "Failure: id not found, ask the user to check it."
@@ -24,7 +24,7 @@ class ReadImage(BaseModel):
24
24
  type: Literal["ReadImage"]
25
25
 
26
26
 
27
- class CreateFileNew(BaseModel):
27
+ class WriteIfEmpty(BaseModel):
28
28
  file_path: str
29
29
  file_content: str
30
30
 
@@ -1,7 +1,7 @@
1
1
  import unittest
2
2
  from unittest.mock import patch
3
3
  from src.wcgw.client.tools import render_terminal_output, ask_confirmation, Confirmation
4
- from src.wcgw.types_ import CreateFileNew
4
+ from src.wcgw.types_ import WriteIfEmpty
5
5
 
6
6
 
7
7
  class TestTools(unittest.TestCase):
@@ -32,7 +32,7 @@ class TestTools(unittest.TestCase):
32
32
 
33
33
  def test_writefile_model(self):
34
34
  # Test the Writefile Pydantic model
35
- file = CreateFileNew(file_path="test.txt", file_content="This is a test.")
35
+ file = WriteIfEmpty(file_path="test.txt", file_content="This is a test.")
36
36
  self.assertEqual(file.file_path, "test.txt")
37
37
  self.assertEqual(file.file_content, "This is a test.")
38
38
 
@@ -869,14 +869,13 @@ wheels = [
869
869
 
870
870
  [[package]]
871
871
  name = "wcgw"
872
- version = "2.1.1"
872
+ version = "2.2.0"
873
873
  source = { editable = "." }
874
874
  dependencies = [
875
875
  { name = "anthropic" },
876
876
  { name = "fastapi" },
877
877
  { name = "humanize" },
878
878
  { name = "mcp" },
879
- { name = "mypy" },
880
879
  { name = "nltk" },
881
880
  { name = "openai" },
882
881
  { name = "petname" },
@@ -910,7 +909,6 @@ requires-dist = [
910
909
  { name = "fastapi", specifier = ">=0.115.0" },
911
910
  { name = "humanize", specifier = ">=4.11.0" },
912
911
  { name = "mcp", git = "https://github.com/rusiaaman/python-sdk?rev=53b69f397eae6ac81a51b84b34ff52b3119f11cb" },
913
- { name = "mypy", specifier = ">=1.11.2" },
914
912
  { name = "nltk", specifier = ">=3.9.1" },
915
913
  { name = "openai", specifier = ">=1.46.0" },
916
914
  { name = "petname", specifier = ">=2.6" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes