wcgw 2.1.2__py3-none-any.whl → 2.2.0__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 wcgw might be problematic. Click here for more details.

@@ -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,
@@ -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
  """,
@@ -495,7 +495,12 @@ System information:
495
495
  )
496
496
  else:
497
497
  _histories.append(
498
- {"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
499
504
  )
500
505
 
501
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,
@@ -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
  """,
@@ -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
  ),
wcgw/client/tools.py CHANGED
@@ -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
wcgw/relay/serve.py CHANGED
@@ -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."
wcgw/types_.py CHANGED
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wcgw
3
- Version: 2.1.2
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
@@ -1,22 +1,22 @@
1
1
  wcgw/__init__.py,sha256=9K2QW7QuSLhMTVbKbBYd9UUp-ZyrfBrxcjuD_xk458k,118
2
- wcgw/types_.py,sha256=rDz4olJS2zvYC13jzeOppA2tci-tVDyWAqeA5BesAaU,1773
2
+ wcgw/types_.py,sha256=5QM97K3kOJ7vNBgZ1NYmKPqwSe9WfzDImAIvjbRcClo,1772
3
3
  wcgw/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  wcgw/client/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
5
- wcgw/client/anthropic_client.py,sha256=xhJdQps422d0R6YaQX6tpoJdYp4dgX0dgEtODx3WmEM,20381
5
+ wcgw/client/anthropic_client.py,sha256=Lfby2Tj4NZn5nrUH6d0VGhdHkD8Z_xk-qtG-S7XB0rc,20664
6
6
  wcgw/client/cli.py,sha256=-z0kpDAW3mzfQrQeZfaVJhBCAQY3HXnt9GdgQ8s-u0Y,1003
7
7
  wcgw/client/common.py,sha256=grH-yV_4tnTQZ29xExn4YicGLxEq98z-HkEZwH0ReSg,1410
8
8
  wcgw/client/computer_use.py,sha256=35NKAlMrxwD0TBlMMRnbCwz4g8TBRGOlcy-cmS-yJ_A,15247
9
9
  wcgw/client/diff-instructions.txt,sha256=s5AJKG23JsjwRYhFZFQVvwDpF67vElawrmdXwvukR1A,1683
10
- wcgw/client/openai_client.py,sha256=u2YQrAswfNil_j6bMxOA4rxscT0TWA-wCgEKbr5rwrE,17868
10
+ wcgw/client/openai_client.py,sha256=xfB96A4qZM7-CUJhyDMqX9rUIzhCw4AtV9ryTKE8SOM,17885
11
11
  wcgw/client/openai_utils.py,sha256=YNwCsA-Wqq7jWrxP0rfQmBTb1dI0s7dWXzQqyTzOZT4,2629
12
12
  wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
13
- wcgw/client/tools.py,sha256=kokbgxxBikIK39moSeg5uGvtBUzLXHnP5-d4jywZYRQ,35762
13
+ wcgw/client/tools.py,sha256=fbMzRXudIBwLQwpINEYYx4nBDc5uyu7pSUF3pZUarug,35931
14
14
  wcgw/client/mcp_server/Readme.md,sha256=I8N4dHkTUVGNQ63BQkBMBhCCBTgqGOSF_pUR6iOEiUk,2495
15
15
  wcgw/client/mcp_server/__init__.py,sha256=hyPPwO9cabAJsOMWhKyat9yl7OlSmIobaoAZKHu3DMc,381
16
- wcgw/client/mcp_server/server.py,sha256=_pzphHJxPyqpLP0YtyddYyaCh83K_OyHKkTuWeSVRHw,10935
17
- wcgw/relay/serve.py,sha256=RUcUeyL4Xt0EEo12Ul6VQjb4tRle4uIdsa85v7XXxEw,8771
16
+ wcgw/client/mcp_server/server.py,sha256=VPs6Dm2XHoMmsUKDJlyxh-mJQzqzlrtyviEi_LutjLk,10951
17
+ wcgw/relay/serve.py,sha256=KLYjTvM9CfqdxgFOfHM8LUkFGZ9kKyyJunpNdEIFQUk,8766
18
18
  wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
19
- wcgw-2.1.2.dist-info/METADATA,sha256=i7GFT8uKfejFukjIHWRGMCBDEQXdfAPw_kI8hb_ZRrI,7421
20
- wcgw-2.1.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
21
- wcgw-2.1.2.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
22
- wcgw-2.1.2.dist-info/RECORD,,
19
+ wcgw-2.2.0.dist-info/METADATA,sha256=bJcxxDqBnsvcO_NKSkJ95wl9Y-EK7P-V_T6XPwoUI2s,7939
20
+ wcgw-2.2.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
21
+ wcgw-2.2.0.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
22
+ wcgw-2.2.0.dist-info/RECORD,,
File without changes