wcgw 3.0.1rc3__tar.gz → 3.0.2__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 (123) hide show
  1. {wcgw-3.0.1rc3 → wcgw-3.0.2}/PKG-INFO +24 -8
  2. {wcgw-3.0.1rc3 → wcgw-3.0.2}/README.md +23 -7
  3. {wcgw-3.0.1rc3 → wcgw-3.0.2}/gpt_action_json_schema.json +11 -93
  4. {wcgw-3.0.1rc3 → wcgw-3.0.2}/gpt_instructions.txt +10 -13
  5. {wcgw-3.0.1rc3 → wcgw-3.0.2}/pyproject.toml +1 -1
  6. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/bash_state/bash_state.py +38 -117
  7. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/modes.py +13 -12
  8. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/tool_prompts.py +5 -11
  9. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/tools.py +87 -47
  10. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/relay/serve.py +0 -31
  11. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/types_.py +24 -20
  12. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/anthropic_client.py +26 -10
  13. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/openai_client.py +1 -0
  14. {wcgw-3.0.1rc3 → wcgw-3.0.2}/tests/test_edit.py +1 -0
  15. {wcgw-3.0.1rc3 → wcgw-3.0.2}/tests/test_mcp_server.py +2 -5
  16. {wcgw-3.0.1rc3 → wcgw-3.0.2}/tests/test_tools.py +79 -25
  17. {wcgw-3.0.1rc3 → wcgw-3.0.2}/uv.lock +105 -103
  18. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.github/workflows/python-publish.yml +0 -0
  19. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.github/workflows/python-tests.yml +0 -0
  20. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.github/workflows/python-types.yml +0 -0
  21. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.gitignore +0 -0
  22. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.gitmodules +0 -0
  23. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.python-version +0 -0
  24. {wcgw-3.0.1rc3 → wcgw-3.0.2}/.vscode/settings.json +0 -0
  25. {wcgw-3.0.1rc3 → wcgw-3.0.2}/Dockerfile +0 -0
  26. {wcgw-3.0.1rc3 → wcgw-3.0.2}/LICENSE +0 -0
  27. {wcgw-3.0.1rc3 → wcgw-3.0.2}/openai.md +0 -0
  28. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.git +0 -0
  29. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  30. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  31. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
  32. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
  33. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
  34. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
  35. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.gitignore +0 -0
  36. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/.python-version +0 -0
  37. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
  38. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
  39. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/LICENSE +0 -0
  40. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/README.md +0 -0
  41. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/RELEASE.md +0 -0
  42. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/SECURITY.md +0 -0
  43. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/README.md +0 -0
  44. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
  45. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
  46. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  47. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  48. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  49. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
  50. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
  51. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
  52. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  53. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  54. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  55. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
  56. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
  57. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
  58. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  59. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  60. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  61. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
  62. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/pyproject.toml +0 -0
  63. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
  64. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
  65. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
  66. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
  67. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
  68. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
  69. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
  70. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
  71. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
  72. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
  73. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
  74. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
  75. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
  76. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
  77. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
  78. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
  79. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
  80. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
  81. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
  82. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
  83. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
  84. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -0
  85. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
  86. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
  87. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
  88. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
  89. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
  90. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
  91. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
  92. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
  93. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
  94. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
  95. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/mcp_wcgw_fork/uv.lock +0 -0
  96. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/__init__.py +0 -0
  97. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/__init__.py +0 -0
  98. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/common.py +0 -0
  99. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/diff-instructions.txt +0 -0
  100. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/encoder/__init__.py +0 -0
  101. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/file_ops/diff_edit.py +0 -0
  102. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/file_ops/search_replace.py +0 -0
  103. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/mcp_server/Readme.md +0 -0
  104. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/mcp_server/__init__.py +0 -0
  105. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/mcp_server/server.py +0 -0
  106. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/memory.py +0 -0
  107. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  108. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  109. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  110. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  111. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  112. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/py.typed +0 -0
  113. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/relay/client.py +0 -0
  114. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw/relay/static/privacy.txt +0 -0
  115. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/__init__.py +0 -0
  116. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/__main__.py +0 -0
  117. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/cli.py +0 -0
  118. {wcgw-3.0.1rc3 → wcgw-3.0.2}/src/wcgw_cli/openai_utils.py +0 -0
  119. {wcgw-3.0.1rc3 → wcgw-3.0.2}/static/claude-ss.jpg +0 -0
  120. {wcgw-3.0.1rc3 → wcgw-3.0.2}/static/computer-use.jpg +0 -0
  121. {wcgw-3.0.1rc3 → wcgw-3.0.2}/static/example.jpg +0 -0
  122. {wcgw-3.0.1rc3 → wcgw-3.0.2}/static/rocket-icon.png +0 -0
  123. {wcgw-3.0.1rc3 → wcgw-3.0.2}/static/ss1.png +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 3.0.1rc3
3
+ Version: 3.0.2
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>
@@ -43,6 +43,8 @@ Empowering chat applications to code, build and run on your local machine.
43
43
 
44
44
  ## Updates
45
45
 
46
+ - [16 Feb 2025] You can now attach to the working terminal that the AI uses. See the "attach-to-terminal" section below.
47
+
46
48
  - [15 Jan 2025] Modes introduced: architect, code-writer, and all powerful wcgw mode.
47
49
 
48
50
  - [8 Jan 2025] Context saving tool for saving relevant file paths along with a description in a single file. Can be used as a task checkpoint or for knowledge transfer.
@@ -51,9 +53,6 @@ Empowering chat applications to code, build and run on your local machine.
51
53
 
52
54
  - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
53
55
 
54
- - [01 Dec 2024] Removed author hosted relay server for chatgpt.
55
-
56
- - [26 Nov 2024] Introduced claude desktop support through mcp
57
56
 
58
57
  ## 🚀 Highlights
59
58
 
@@ -100,7 +99,7 @@ First install `uv` using homebrew `brew install uv`
100
99
 
101
100
  (**Important:** use homebrew to install uv. Otherwise make sure `uv` is present in a global location like /usr/bin/)
102
101
 
103
- Then update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json)
102
+ Then create or update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json) with following json.
104
103
 
105
104
  ```json
106
105
  {
@@ -127,6 +126,8 @@ _If there's an error in setting up_
127
126
 
128
127
  - If there's an error like "uv ENOENT", make sure `uv` is installed. Then run 'which uv' in the terminal, and use its output in place of "uv" in the configuration.
129
128
  - If there's still an issue, check that `uv tool run --from wcgw@latest --python 3.12 wcgw_mcp` runs in your terminal. It should have no output and shouldn't exit.
129
+ - Try removing ~/.cache/uv folder
130
+ - Try using `uv` version `0.6.0` for which this tool was tested.
130
131
  - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
131
132
 
132
133
  ### Alternative configuration using smithery (npx required)
@@ -139,6 +140,9 @@ Then to configure wcgw for Claude Desktop automatically via [Smithery](https://s
139
140
  npx -y @smithery/cli install wcgw --client claude
140
141
  ```
141
142
 
143
+ _If there's an error in setting up_
144
+ - Try removing ~/.cache/uv folder
145
+
142
146
  ### Usage
143
147
 
144
148
  Wait for a few seconds. You should be able to see this icon if everything goes right.
@@ -168,6 +172,21 @@ There are three built-in modes. You may ask Claude to run in one of the modes, l
168
172
 
169
173
  Note: in code-writer mode either all commands are allowed or none are allowed for now. If you give a list of allowed commands, Claude is instructed to run only those commands, but no actual check happens. (WIP)
170
174
 
175
+ #### Attach to the working terminal to investigate
176
+ If you've `screen` command installed, wcgw runs on a screen instance automatically. If you've started wcgw mcp server, you can list the screen sessions:
177
+
178
+ `screen -ls`
179
+
180
+ And note down the wcgw screen name which will be something like `93358.wcgw.235521` where the last number is in the hour-minute-second format.
181
+
182
+ You can then attach to the session using `screen -x 93358.wcgw.235521`
183
+
184
+ You may interrupt any running command safely.
185
+
186
+ You can interact with the terminal but beware that the AI might be running in parallel and it may conflict with what you're doing. It's recommended to keep your interactions to minimum.
187
+
188
+ You shouldn't exit the session using `exit `or Ctrl-d, instead you should use `ctrl+a+d` to safely detach without destroying the screen session.
189
+
171
190
  ### [Optional] Vs code extension
172
191
 
173
192
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -216,7 +235,6 @@ The server provides the following MCP tools:
216
235
  - Parameters: `any_workspace_path` (string), `initial_files_to_read` (string[]), `mode_name` ("wcgw"|"architect"|"code_writer"), `task_id_to_resume` (string)
217
236
  - `BashCommand`: Execute shell commands with timeout control
218
237
  - Parameters: `command` (string), `wait_for_seconds` (int, optional)
219
- - `BashInteraction`: Send keyboard input to running programs
220
238
  - Parameters: `send_text` (string) or `send_specials` (["Enter"|"Key-up"|...]) or `send_ascii` (int[]), `wait_for_seconds` (int, optional)
221
239
 
222
240
  **File Operations:**
@@ -234,7 +252,5 @@ The server provides the following MCP tools:
234
252
 
235
253
  - `ContextSave`: Save project context and files for Knowledge Transfer or saving task checkpoints to be resumed later
236
254
  - Parameters: `id` (string), `project_root_path` (string), `description` (string), `relevant_file_globs` (string[])
237
- - `ResetShell`: Emergency reset for shell environment
238
- - Parameters: `should_reset` (boolean)
239
255
 
240
256
  All tools support absolute paths and include built-in protections against common errors. See the [MCP specification](https://modelcontextprotocol.io/) for detailed protocol information.
@@ -15,6 +15,8 @@ Empowering chat applications to code, build and run on your local machine.
15
15
 
16
16
  ## Updates
17
17
 
18
+ - [16 Feb 2025] You can now attach to the working terminal that the AI uses. See the "attach-to-terminal" section below.
19
+
18
20
  - [15 Jan 2025] Modes introduced: architect, code-writer, and all powerful wcgw mode.
19
21
 
20
22
  - [8 Jan 2025] Context saving tool for saving relevant file paths along with a description in a single file. Can be used as a task checkpoint or for knowledge transfer.
@@ -23,9 +25,6 @@ Empowering chat applications to code, build and run on your local machine.
23
25
 
24
26
  - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
25
27
 
26
- - [01 Dec 2024] Removed author hosted relay server for chatgpt.
27
-
28
- - [26 Nov 2024] Introduced claude desktop support through mcp
29
28
 
30
29
  ## 🚀 Highlights
31
30
 
@@ -72,7 +71,7 @@ First install `uv` using homebrew `brew install uv`
72
71
 
73
72
  (**Important:** use homebrew to install uv. Otherwise make sure `uv` is present in a global location like /usr/bin/)
74
73
 
75
- Then update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json)
74
+ Then create or update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json) with following json.
76
75
 
77
76
  ```json
78
77
  {
@@ -99,6 +98,8 @@ _If there's an error in setting up_
99
98
 
100
99
  - If there's an error like "uv ENOENT", make sure `uv` is installed. Then run 'which uv' in the terminal, and use its output in place of "uv" in the configuration.
101
100
  - If there's still an issue, check that `uv tool run --from wcgw@latest --python 3.12 wcgw_mcp` runs in your terminal. It should have no output and shouldn't exit.
101
+ - Try removing ~/.cache/uv folder
102
+ - Try using `uv` version `0.6.0` for which this tool was tested.
102
103
  - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
103
104
 
104
105
  ### Alternative configuration using smithery (npx required)
@@ -111,6 +112,9 @@ Then to configure wcgw for Claude Desktop automatically via [Smithery](https://s
111
112
  npx -y @smithery/cli install wcgw --client claude
112
113
  ```
113
114
 
115
+ _If there's an error in setting up_
116
+ - Try removing ~/.cache/uv folder
117
+
114
118
  ### Usage
115
119
 
116
120
  Wait for a few seconds. You should be able to see this icon if everything goes right.
@@ -140,6 +144,21 @@ There are three built-in modes. You may ask Claude to run in one of the modes, l
140
144
 
141
145
  Note: in code-writer mode either all commands are allowed or none are allowed for now. If you give a list of allowed commands, Claude is instructed to run only those commands, but no actual check happens. (WIP)
142
146
 
147
+ #### Attach to the working terminal to investigate
148
+ If you've `screen` command installed, wcgw runs on a screen instance automatically. If you've started wcgw mcp server, you can list the screen sessions:
149
+
150
+ `screen -ls`
151
+
152
+ And note down the wcgw screen name which will be something like `93358.wcgw.235521` where the last number is in the hour-minute-second format.
153
+
154
+ You can then attach to the session using `screen -x 93358.wcgw.235521`
155
+
156
+ You may interrupt any running command safely.
157
+
158
+ You can interact with the terminal but beware that the AI might be running in parallel and it may conflict with what you're doing. It's recommended to keep your interactions to minimum.
159
+
160
+ You shouldn't exit the session using `exit `or Ctrl-d, instead you should use `ctrl+a+d` to safely detach without destroying the screen session.
161
+
143
162
  ### [Optional] Vs code extension
144
163
 
145
164
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -188,7 +207,6 @@ The server provides the following MCP tools:
188
207
  - Parameters: `any_workspace_path` (string), `initial_files_to_read` (string[]), `mode_name` ("wcgw"|"architect"|"code_writer"), `task_id_to_resume` (string)
189
208
  - `BashCommand`: Execute shell commands with timeout control
190
209
  - Parameters: `command` (string), `wait_for_seconds` (int, optional)
191
- - `BashInteraction`: Send keyboard input to running programs
192
210
  - Parameters: `send_text` (string) or `send_specials` (["Enter"|"Key-up"|...]) or `send_ascii` (int[]), `wait_for_seconds` (int, optional)
193
211
 
194
212
  **File Operations:**
@@ -206,7 +224,5 @@ The server provides the following MCP tools:
206
224
 
207
225
  - `ContextSave`: Save project context and files for Knowledge Transfer or saving task checkpoints to be resumed later
208
226
  - Parameters: `id` (string), `project_root_path` (string), `description` (string), `relevant_file_globs` (string[])
209
- - `ResetShell`: Emergency reset for shell environment
210
- - Parameters: `should_reset` (boolean)
211
227
 
212
228
  All tools support absolute paths and include built-in protections against common errors. See the [MCP specification](https://modelcontextprotocol.io/) for detailed protocol information.
@@ -90,46 +90,6 @@
90
90
  }
91
91
  }
92
92
  },
93
- "/v1/reset_wcgw": {
94
- "post": {
95
- "x-openai-isConsequential": false,
96
- "summary": "Reset Wcgw",
97
- "operationId": "reset_wcgw_v1_reset_wcgw_post",
98
- "requestBody": {
99
- "content": {
100
- "application/json": {
101
- "schema": {
102
- "$ref": "#/components/schemas/ResetWcgwWithUUID"
103
- }
104
- }
105
- },
106
- "required": true
107
- },
108
- "responses": {
109
- "200": {
110
- "description": "Successful Response",
111
- "content": {
112
- "application/json": {
113
- "schema": {
114
- "type": "string",
115
- "title": "Response Reset Wcgw V1 Reset Wcgw Post"
116
- }
117
- }
118
- }
119
- },
120
- "422": {
121
- "description": "Validation Error",
122
- "content": {
123
- "application/json": {
124
- "schema": {
125
- "$ref": "#/components/schemas/HTTPValidationError"
126
- }
127
- }
128
- }
129
- }
130
- }
131
- }
132
- },
133
93
  "/v1/bash_command": {
134
94
  "post": {
135
95
  "x-openai-isConsequential": false,
@@ -473,6 +433,16 @@
473
433
  },
474
434
  "InitializeWithUUID": {
475
435
  "properties": {
436
+ "type": {
437
+ "type": "string",
438
+ "enum": [
439
+ "first_call",
440
+ "user_asked_mode_change",
441
+ "reset_shell",
442
+ "user_asked_change_workspace"
443
+ ],
444
+ "title": "Type"
445
+ },
476
446
  "any_workspace_path": {
477
447
  "type": "string",
478
448
  "title": "Any Workspace Path"
@@ -516,6 +486,7 @@
516
486
  "additionalProperties": false,
517
487
  "type": "object",
518
488
  "required": [
489
+ "type",
519
490
  "any_workspace_path",
520
491
  "initial_files_to_read",
521
492
  "task_id_to_resume",
@@ -547,59 +518,6 @@
547
518
  ],
548
519
  "title": "ReadFileWithUUID"
549
520
  },
550
- "ResetWcgwWithUUID": {
551
- "properties": {
552
- "should_reset": {
553
- "type": "boolean",
554
- "const": true,
555
- "title": "Should Reset"
556
- },
557
- "change_mode": {
558
- "anyOf": [
559
- {
560
- "type": "string",
561
- "enum": [
562
- "wcgw",
563
- "architect",
564
- "code_writer"
565
- ]
566
- },
567
- {
568
- "type": "null"
569
- }
570
- ],
571
- "title": "Change Mode"
572
- },
573
- "code_writer_config": {
574
- "anyOf": [
575
- {
576
- "$ref": "#/components/schemas/CodeWriterMode"
577
- },
578
- {
579
- "type": "null"
580
- }
581
- ]
582
- },
583
- "starting_directory": {
584
- "type": "string",
585
- "title": "Starting Directory"
586
- },
587
- "user_id": {
588
- "type": "string",
589
- "format": "uuid",
590
- "title": "User Id"
591
- }
592
- },
593
- "additionalProperties": false,
594
- "type": "object",
595
- "required": [
596
- "should_reset",
597
- "change_mode",
598
- "starting_directory",
599
- "user_id"
600
- ],
601
- "title": "ResetWcgwWithUUID"
602
- },
603
521
  "SendAscii": {
604
522
  "properties": {
605
523
  "send_ascii": {
@@ -9,16 +9,16 @@ Instructions:
9
9
  - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
10
10
 
11
11
  Instructions for `Initialize`:
12
- - Always call this at the start of the conversation.- This will reset the shell.
13
- - Use `any_workspace_path` to initialize the shell in the appropriate project directory.
14
- - If the user has mentioned a workspace or project root, use it to set `any_workspace_path`.
15
- - If the user has mentioned a folder or file with unclear project root, use the file or folder as `any_workspace_path`.
16
- - If user has mentioned any files use `initial_files_to_read` to read, use absolute paths only.
17
- - If `any_workspace_path` is provided, a tree structure of the workspace will be shown.
18
- - Leave `any_workspace_path` as empty if no file or folder is mentioned.
19
- - By default use mode `wcgw`
20
- - In code-writer mode, set the commands and globs which user asked to set, otherwise use 'all'.
21
- - Call `ResetWcgw` if you want to change the mode later.
12
+ - Always call this at the start of the conversation before using any of the shell tools from wcgw.
13
+ - Use `any_workspace_path` to initialize the shell in the appropriate project directory.
14
+ - If the user has mentioned a workspace or project root or any other file or folder use it to set `any_workspace_path`.
15
+ - If user has mentioned any files use `initial_files_to_read` to read, use absolute paths only.
16
+ - By default use mode "wcgw"
17
+ - In "code-writer" mode, set the commands and globs which user asked to set, otherwise use 'all'.
18
+ - Use type="first_call" if it's the first call to this tool.
19
+ - Use type="user_asked_mode_change" if in a conversation user has asked to change mode.
20
+ - Use type="reset_shell" if in a conversation shell is not working after multiple tries.
21
+ - Use type="user_asked_change_workspace" if in a conversation user asked to change workspace
22
22
 
23
23
  Instructions for `BashCommand`:
24
24
  - Execute a bash command. This is stateful (beware with subsequent calls).
@@ -40,9 +40,6 @@ Instructions for `Write if Empty`
40
40
  - Provide absolute file path only.
41
41
  - For editing existing files, use FileEdit.
42
42
 
43
- Instructions for `ResetWcgw`
44
- - Resets the shell. Use either when changing mode, or when all interrupts and prompt reset attempts have failed repeatedly.
45
-
46
43
  Instructions for `ContextSave`
47
44
  - Saves provided description and file contents of all the relevant file paths or globs in a single text file.
48
45
  - Provide random unqiue id or whatever user provided.
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
3
3
  name = "wcgw"
4
- version = "3.0.1rc3"
4
+ version = "3.0.2"
5
5
  description = "Shell and coding agent on claude and chatgpt"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11"
@@ -8,8 +8,6 @@ import traceback
8
8
  from dataclasses import dataclass
9
9
  from typing import (
10
10
  Any,
11
- Callable,
12
- Concatenate,
13
11
  Literal,
14
12
  Optional,
15
13
  ParamSpec,
@@ -107,6 +105,9 @@ def cleanup_all_screens_with_name(name: str, console: Console) -> None:
107
105
  output = (e.stdout or "") + (e.stderr or "")
108
106
  except FileNotFoundError:
109
107
  return
108
+ except Exception as e:
109
+ console.log(f"{e}: exception while clearing running screens.")
110
+ return
110
111
 
111
112
  sessions_to_kill = []
112
113
 
@@ -130,8 +131,8 @@ def cleanup_all_screens_with_name(name: str, console: Console) -> None:
130
131
  check=True,
131
132
  timeout=CONFIG.timeout,
132
133
  )
133
- except (subprocess.CalledProcessError, FileNotFoundError):
134
- console.log(f"Failed to kill screen session: {session}")
134
+ except Exception as e:
135
+ console.log(f"Failed to kill screen session: {session}\n{e}")
135
136
 
136
137
 
137
138
  def start_shell(
@@ -217,33 +218,7 @@ P = ParamSpec("P")
217
218
  R = TypeVar("R")
218
219
 
219
220
 
220
- def requires_shell(
221
- func: Callable[Concatenate["BashState", "pexpect.spawn[str]", P], R],
222
- ) -> Callable[Concatenate["BashState", P], R]:
223
- def wrapper(self: "BashState", /, *args: P.args, **kwargs: P.kwargs) -> R:
224
- if not self._shell_loading.is_set():
225
- if not self._shell_loading.wait(
226
- timeout=CONFIG.timeout * 2
227
- ): # Twice in worst case if screen fails
228
- raise RuntimeError("Shell initialization timeout")
229
-
230
- if self._shell_error:
231
- raise RuntimeError(f"Shell failed to initialize: {self._shell_error}.")
232
-
233
- if not self._shell:
234
- raise RuntimeError("Shell not initialized")
235
-
236
- return func(self, self._shell, *args, **kwargs)
237
-
238
- return wrapper
239
-
240
-
241
221
  class BashState:
242
- _shell: Optional["pexpect.spawn[str]"]
243
- _shell_id: Optional[str]
244
- _shell_lock: threading.Lock
245
- _shell_loading: threading.Event
246
- _shell_error: Optional[Exception]
247
222
  _use_screen: bool
248
223
 
249
224
  def __init__(
@@ -266,67 +241,39 @@ class BashState:
266
241
  self._write_if_empty_mode: WriteIfEmptyMode = (
267
242
  write_if_empty_mode or WriteIfEmptyMode("all")
268
243
  )
269
- self._mode = mode or Modes.wcgw
244
+ self._mode = mode or "wcgw"
270
245
  self._whitelist_for_overwrite: set[str] = whitelist_for_overwrite or set()
271
246
  self._bg_expect_thread: Optional[threading.Thread] = None
272
247
  self._bg_expect_thread_stop_event = threading.Event()
273
- self._shell = None
274
- self._shell_id = None
275
- self._shell_lock = threading.Lock()
276
- self._shell_loading = threading.Event()
277
- self._shell_error = None
278
248
  self._use_screen = use_screen
279
- self._start_shell_loading()
249
+ self._init_shell()
280
250
 
281
- def _start_shell_loading(self) -> None:
282
- def load_shell() -> None:
283
- try:
284
- with self._shell_lock:
285
- if self._shell is not None:
286
- return
287
- self._init_shell()
288
- self.run_bg_expect_thread()
289
- except Exception as e:
290
- self._shell_error = e
291
- finally:
292
- self._shell_loading.set()
293
-
294
- threading.Thread(target=load_shell).start()
295
-
296
- @requires_shell
297
- def expect(
298
- self, shell: "pexpect.spawn[str]", pattern: Any, timeout: Optional[float] = -1
299
- ) -> int:
251
+ def expect(self, pattern: Any, timeout: Optional[float] = -1) -> int:
300
252
  self.close_bg_expect_thread()
301
- output = shell.expect(pattern, timeout)
253
+ output = self._shell.expect(pattern, timeout)
302
254
  return output
303
255
 
304
- @requires_shell
305
- def send(self, shell: "pexpect.spawn[str]", s: str | bytes) -> int:
256
+ def send(self, s: str | bytes) -> int:
306
257
  self.close_bg_expect_thread()
307
- output = shell.send(s)
258
+ output = self._shell.send(s)
308
259
  return output
309
260
 
310
- @requires_shell
311
- def sendline(self, shell: "pexpect.spawn[str]", s: str | bytes) -> int:
261
+ def sendline(self, s: str | bytes) -> int:
312
262
  self.close_bg_expect_thread()
313
- output = shell.sendline(s)
263
+ output = self._shell.sendline(s)
314
264
  return output
315
265
 
316
266
  @property
317
- @requires_shell
318
- def linesep(self, shell: "pexpect.spawn[str]") -> Any:
319
- return shell.linesep
267
+ def linesep(self) -> Any:
268
+ return self._shell.linesep
320
269
 
321
- @requires_shell
322
- def sendintr(self, shell: "pexpect.spawn[str]") -> None:
270
+ def sendintr(self) -> None:
323
271
  self.close_bg_expect_thread()
324
- shell.sendintr()
272
+ self._shell.sendintr()
325
273
 
326
274
  @property
327
- @requires_shell
328
- def before(self, shell: "pexpect.spawn[str]") -> Optional[str]:
329
- return shell.before
275
+ def before(self) -> Optional[str]:
276
+ return self._shell.before
330
277
 
331
278
  def run_bg_expect_thread(self) -> None:
332
279
  """
@@ -337,16 +284,11 @@ class BashState:
337
284
  while True:
338
285
  if self._bg_expect_thread_stop_event.is_set():
339
286
  break
340
- if self._shell is None:
341
- time.sleep(0.1)
342
- continue
343
287
  output = self._shell.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=0.1)
344
288
  if output == 0:
345
289
  break
346
290
 
347
- if self._bg_expect_thread and self._bg_expect_thread.is_alive():
348
- if not self._bg_expect_thread_stop_event.is_set():
349
- return
291
+ if self._bg_expect_thread:
350
292
  self.close_bg_expect_thread()
351
293
 
352
294
  self._bg_expect_thread = threading.Thread(
@@ -363,13 +305,8 @@ class BashState:
363
305
 
364
306
  def cleanup(self) -> None:
365
307
  self.close_bg_expect_thread()
366
- with self._shell_lock:
367
- if self._shell:
368
- self._shell.close(True)
369
- if self._shell_id:
370
- cleanup_all_screens_with_name(self._shell_id, self.console)
371
- self._shell = None
372
- self._shell_id = None
308
+ self._shell.close(True)
309
+ cleanup_all_screens_with_name(self._shell_id, self.console)
373
310
 
374
311
  def __enter__(self) -> "BashState":
375
312
  return self
@@ -393,31 +330,24 @@ class BashState:
393
330
  def write_if_empty_mode(self) -> WriteIfEmptyMode:
394
331
  return self._write_if_empty_mode
395
332
 
396
- @requires_shell
397
- def ensure_env_and_bg_jobs(self, _: "pexpect.spawn[str]") -> Optional[int]:
398
- return self._ensure_env_and_bg_jobs()
399
-
400
- def _ensure_env_and_bg_jobs(self) -> Optional[int]:
401
- # Do not add @requires_shell decorator here, as it will cause deadlock
402
- self.close_bg_expect_thread()
403
- assert self._shell is not None, "Bad state, shell is not initialized"
333
+ def ensure_env_and_bg_jobs(self) -> Optional[int]:
404
334
  quick_timeout = 0.2 if not self.over_screen else 1
405
335
  # First reset the prompt in case venv was sourced or other reasons.
406
- self._shell.sendline(PROMPT_STATEMENT)
407
- self._shell.expect(PROMPT_CONST, timeout=quick_timeout)
336
+ self.sendline(PROMPT_STATEMENT)
337
+ self.expect(PROMPT_CONST, timeout=quick_timeout)
408
338
  # Reset echo also if it was enabled
409
339
  command = "jobs | wc -l"
410
- self._shell.sendline(command)
340
+ self.sendline(command)
411
341
  before = ""
412
342
  counts = 0
413
343
  while not _is_int(before): # Consume all previous output
414
344
  try:
415
- self._shell.expect(PROMPT_CONST, timeout=quick_timeout)
345
+ self.expect(PROMPT_CONST, timeout=quick_timeout)
416
346
  except pexpect.TIMEOUT:
417
347
  self.console.print(f"Couldn't get exit code, before: {before}")
418
348
  raise
419
349
 
420
- before_val = self._shell.before
350
+ before_val = self.before
421
351
  if not isinstance(before_val, str):
422
352
  before_val = str(before_val)
423
353
  assert isinstance(before_val, str)
@@ -435,7 +365,6 @@ class BashState:
435
365
 
436
366
  def _init_shell(self) -> None:
437
367
  self._state: Literal["repl"] | datetime.datetime = "repl"
438
- self._is_in_docker: Optional[str] = ""
439
368
  # Ensure self._cwd exists
440
369
  os.makedirs(self._cwd, exist_ok=True)
441
370
  try:
@@ -461,10 +390,12 @@ class BashState:
461
390
 
462
391
  self._pending_output = ""
463
392
  try:
464
- self._ensure_env_and_bg_jobs()
393
+ self.ensure_env_and_bg_jobs()
465
394
  except ValueError as e:
466
395
  self.console.log("Error while running _ensure_env_and_bg_jobs" + str(e))
467
396
 
397
+ self.run_bg_expect_thread()
398
+
468
399
  def set_pending(self, last_pending_output: str) -> None:
469
400
  if not isinstance(self._state, datetime.datetime):
470
401
  self._state = datetime.datetime.now()
@@ -480,13 +411,6 @@ class BashState:
480
411
  return "repl"
481
412
  return "pending"
482
413
 
483
- @property
484
- def is_in_docker(self) -> Optional[str]:
485
- return self._is_in_docker
486
-
487
- def set_in_docker(self, docker_image_id: str) -> None:
488
- self._is_in_docker = docker_image_id
489
-
490
414
  @property
491
415
  def cwd(self) -> str:
492
416
  return self._cwd
@@ -495,11 +419,10 @@ class BashState:
495
419
  def prompt(self) -> str:
496
420
  return PROMPT_CONST
497
421
 
498
- @requires_shell
499
- def update_cwd(self, shell: "pexpect.spawn[str]") -> str:
500
- shell.sendline("pwd")
501
- shell.expect(PROMPT_CONST, timeout=0.2)
502
- before_val = shell.before
422
+ def update_cwd(self) -> str:
423
+ self.sendline("pwd")
424
+ self.expect(PROMPT_CONST, timeout=0.2)
425
+ before_val = self.before
503
426
  if not isinstance(before_val, str):
504
427
  before_val = str(before_val)
505
428
  before_lines = render_terminal_output(before_val)
@@ -509,9 +432,7 @@ class BashState:
509
432
 
510
433
  def reset_shell(self) -> None:
511
434
  self.cleanup()
512
- self._shell_loading.clear()
513
- self._shell_error = None
514
- self._start_shell_loading()
435
+ self._init_shell()
515
436
 
516
437
  def serialize(self) -> dict[str, Any]:
517
438
  """Serialize BashState to a dictionary for saving"""
@@ -531,7 +452,7 @@ class BashState:
531
452
  BashCommandMode.deserialize(state["bash_command_mode"]),
532
453
  FileEditMode.deserialize(state["file_edit_mode"]),
533
454
  WriteIfEmptyMode.deserialize(state["write_if_empty_mode"]),
534
- Modes[str(state["mode"])],
455
+ state["mode"],
535
456
  state["whitelist_for_overwrite"],
536
457
  )
537
458
 
@@ -595,7 +516,7 @@ WAITING_INPUT_MESSAGE = """A command is already running. NOTE: You can't run mul
595
516
  1. Get its output using `send_ascii: [10] or send_specials: ["Enter"]`
596
517
  2. Use `send_ascii` or `send_specials` to give inputs to the running program, don't use `BashCommand` OR
597
518
  3. kill the previous program by sending ctrl+c first using `send_ascii` or `send_specials`
598
- 4. Send the process in background using `send_specials: ["Ctrl-z"]` followed by BashCommand: `bg`
519
+ 4. Interrupt and run the process in background by re-running it using screen
599
520
  """
600
521
 
601
522