wcgw 4.1.2__tar.gz → 5.0.1__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 (133) hide show
  1. {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-tests.yml +1 -2
  2. {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-types.yml +1 -2
  3. {wcgw-4.1.2 → wcgw-5.0.1}/PKG-INFO +12 -19
  4. {wcgw-4.1.2 → wcgw-5.0.1}/README.md +10 -17
  5. {wcgw-4.1.2 → wcgw-5.0.1}/pyproject.toml +17 -10
  6. wcgw-5.0.1/src/wcgw/__init__.py +4 -0
  7. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/bash_state.py +107 -0
  8. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/file_ops/diff_edit.py +1 -0
  9. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/modes.py +1 -8
  10. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/tool_prompts.py +1 -1
  11. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/tools.py +84 -42
  12. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/types_.py +6 -1
  13. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_edit.py +14 -0
  14. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_mcp_server.py +8 -2
  15. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_tools.py +76 -25
  16. {wcgw-4.1.2 → wcgw-5.0.1}/uv.lock +17 -7
  17. wcgw-4.1.2/gpt_action_json_schema.json +0 -577
  18. wcgw-4.1.2/gpt_instructions.txt +0 -113
  19. wcgw-4.1.2/openai.md +0 -71
  20. wcgw-4.1.2/src/wcgw/__init__.py +0 -2
  21. wcgw-4.1.2/src/wcgw/relay/client.py +0 -95
  22. wcgw-4.1.2/src/wcgw/relay/serve.py +0 -261
  23. wcgw-4.1.2/src/wcgw/relay/static/privacy.txt +0 -7
  24. {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-publish.yml +0 -0
  25. {wcgw-4.1.2 → wcgw-5.0.1}/.gitignore +0 -0
  26. {wcgw-4.1.2 → wcgw-5.0.1}/.gitmodules +0 -0
  27. {wcgw-4.1.2 → wcgw-5.0.1}/.python-version +0 -0
  28. {wcgw-4.1.2 → wcgw-5.0.1}/.vscode/settings.json +0 -0
  29. {wcgw-4.1.2 → wcgw-5.0.1}/CLAUDE.md +0 -0
  30. {wcgw-4.1.2 → wcgw-5.0.1}/Dockerfile +0 -0
  31. {wcgw-4.1.2 → wcgw-5.0.1}/LICENSE +0 -0
  32. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.git +0 -0
  33. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
  36. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
  37. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
  38. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
  39. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.gitignore +0 -0
  40. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.python-version +0 -0
  41. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
  42. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
  43. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/LICENSE +0 -0
  44. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/README.md +0 -0
  45. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/RELEASE.md +0 -0
  46. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/SECURITY.md +0 -0
  47. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/README.md +0 -0
  48. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
  49. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
  50. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  51. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  52. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  53. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
  54. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
  55. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
  56. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  57. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  58. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  59. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
  60. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
  61. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
  62. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  63. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  64. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  65. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
  66. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/pyproject.toml +0 -0
  67. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
  68. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
  69. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
  70. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
  71. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
  72. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
  73. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
  74. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
  75. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
  76. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
  77. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
  78. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
  79. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
  80. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
  81. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
  82. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
  83. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
  84. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
  85. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
  86. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
  87. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
  88. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -0
  89. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
  90. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
  91. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
  92. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
  93. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
  94. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
  95. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
  96. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
  97. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
  98. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
  99. {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/uv.lock +0 -0
  100. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/__init__.py +0 -0
  101. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
  102. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
  103. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/common.py +0 -0
  104. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/diff-instructions.txt +0 -0
  105. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/encoder/__init__.py +0 -0
  106. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/file_ops/search_replace.py +0 -0
  107. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/Readme.md +0 -0
  108. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/__init__.py +0 -0
  109. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/server.py +0 -0
  110. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/memory.py +0 -0
  111. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  112. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/file_stats.py +0 -0
  113. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  114. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  115. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  116. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  117. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/py.typed +0 -0
  118. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/__init__.py +0 -0
  119. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/__main__.py +0 -0
  120. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/anthropic_client.py +0 -0
  121. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/cli.py +0 -0
  122. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/openai_client.py +0 -0
  123. {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/openai_utils.py +0 -0
  124. {wcgw-4.1.2 → wcgw-5.0.1}/static/claude-ss.jpg +0 -0
  125. {wcgw-4.1.2 → wcgw-5.0.1}/static/computer-use.jpg +0 -0
  126. {wcgw-4.1.2 → wcgw-5.0.1}/static/example.jpg +0 -0
  127. {wcgw-4.1.2 → wcgw-5.0.1}/static/rocket-icon.png +0 -0
  128. {wcgw-4.1.2 → wcgw-5.0.1}/static/ss1.png +0 -0
  129. {wcgw-4.1.2 → wcgw-5.0.1}/static/workflow-demo.gif +0 -0
  130. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_bash_parser.py +0 -0
  131. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_bash_parser_complex.py +0 -0
  132. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_file_range_tracking.py +0 -0
  133. {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_readfiles.py +0 -0
@@ -25,10 +25,9 @@ jobs:
25
25
  - name: Install dependencies
26
26
  run: |
27
27
  pip install uv
28
- uv venv --python "${{ matrix.python-version }}"
29
28
  - name: Run tests with coverage
30
29
  run: |
31
- uv run --python "${{ matrix.python-version }}" pytest --cov=wcgw --cov-report=xml --cov-report=term-missing
30
+ uv run --group tests --python "${{ matrix.python-version }}" pytest --cov=wcgw --cov-report=xml --cov-report=term-missing
32
31
  - name: Upload coverage reports to Codecov
33
32
  uses: codecov/codecov-action@v4
34
33
  if: success()
@@ -25,7 +25,6 @@ jobs:
25
25
  - name: Install dependencies
26
26
  run: |
27
27
  pip install uv
28
- uv venv --python "${{ matrix.python-version }}"
29
28
  - name: Run type checks
30
29
  run: |
31
- uv run mypy --strict src/wcgw
30
+ uv run --group types --python "${{ matrix.python-version }}" mypy --strict src/wcgw
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 4.1.2
4
- Summary: Shell and coding agent on claude and chatgpt
3
+ Version: 5.0.1
4
+ Summary: Shell and coding agent for Claude and other mcp clients
5
5
  Project-URL: Homepage, https://github.com/rusiaaman/wcgw
6
6
  Author-email: Aman Rusia <gapypi@arcfu.com>
7
7
  License-File: LICENSE
@@ -28,12 +28,11 @@ Requires-Dist: uvicorn>=0.31.0
28
28
  Requires-Dist: websockets>=13.1
29
29
  Description-Content-Type: text/markdown
30
30
 
31
- # Shell and Coding agent for Claude and Chatgpt
31
+ # Shell and Coding agent for Claude and other mcp clients
32
32
 
33
33
  Empowering chat applications to code, build and run on your local machine.
34
34
 
35
- - Claude - MCP server with tightly integrated shell and code editing tools.
36
- - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux, mac, windows on wsl)
35
+ wcgw is an MCP server with tightly integrated shell and code editing tools.
37
36
 
38
37
  ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
39
38
 
@@ -49,6 +48,8 @@ Empowering chat applications to code, build and run on your local machine.
49
48
 
50
49
  ## Updates
51
50
 
51
+ - [27 Apr 2025] Removed support for GPTs over relay server. Only MCP server is supported in version >= 5.
52
+
52
53
  - [24 Mar 2025] Improved writing and editing experience for sonnet 3.7, CLAUDE.md gets loaded automatically.
53
54
 
54
55
  - [16 Feb 2025] You can now attach to the working terminal that the AI uses. See the "attach-to-terminal" section below.
@@ -119,11 +120,9 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
119
120
  "args": [
120
121
  "tool",
121
122
  "run",
122
- "--from",
123
- "wcgw@latest",
124
123
  "--python",
125
124
  "3.12",
126
- "wcgw_mcp"
125
+ "wcgw@latest"
127
126
  ]
128
127
  }
129
128
  }
@@ -135,10 +134,10 @@ Then restart claude app.
135
134
  _If there's an error in setting up_
136
135
 
137
136
  - 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.
138
- - 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.
137
+ - If there's still an issue, check that `uv tool run --python 3.12 wcgw@latest` runs in your terminal. It should have no output and shouldn't exit.
139
138
  - Try removing ~/.cache/uv folder
140
139
  - Try using `uv` version `0.6.0` for which this tool was tested.
141
- - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
140
+ - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --python 3.12 wcgw@latest`
142
141
 
143
142
  ### Windows on wsl
144
143
 
@@ -157,11 +156,9 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
157
156
  "uv",
158
157
  "tool",
159
158
  "run",
160
- "--from",
161
- "wcgw@latest",
162
159
  "--python",
163
160
  "3.12",
164
- "wcgw_mcp"
161
+ "wcgw@latest"
165
162
  ]
166
163
  }
167
164
  }
@@ -221,10 +218,6 @@ Commands:
221
218
 
222
219
  - 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.
223
220
 
224
- ## Chatgpt Setup
225
-
226
- Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
227
-
228
221
  ## Examples
229
222
 
230
223
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
@@ -261,7 +254,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
261
254
 
262
255
  Then run
263
256
 
264
- `uvx --from wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
257
+ `uvx wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
265
258
 
266
259
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
267
260
 
@@ -271,7 +264,7 @@ Add `ANTHROPIC_API_KEY` env variable.
271
264
 
272
265
  Then run
273
266
 
274
- `uvx --from wcgw@latest wcgw_local --claude`
267
+ `uvx wcgw@latest wcgw_local --claude`
275
268
 
276
269
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
277
270
 
@@ -1,9 +1,8 @@
1
- # Shell and Coding agent for Claude and Chatgpt
1
+ # Shell and Coding agent for Claude and other mcp clients
2
2
 
3
3
  Empowering chat applications to code, build and run on your local machine.
4
4
 
5
- - Claude - MCP server with tightly integrated shell and code editing tools.
6
- - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux, mac, windows on wsl)
5
+ wcgw is an MCP server with tightly integrated shell and code editing tools.
7
6
 
8
7
  ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
9
8
 
@@ -19,6 +18,8 @@ Empowering chat applications to code, build and run on your local machine.
19
18
 
20
19
  ## Updates
21
20
 
21
+ - [27 Apr 2025] Removed support for GPTs over relay server. Only MCP server is supported in version >= 5.
22
+
22
23
  - [24 Mar 2025] Improved writing and editing experience for sonnet 3.7, CLAUDE.md gets loaded automatically.
23
24
 
24
25
  - [16 Feb 2025] You can now attach to the working terminal that the AI uses. See the "attach-to-terminal" section below.
@@ -89,11 +90,9 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
89
90
  "args": [
90
91
  "tool",
91
92
  "run",
92
- "--from",
93
- "wcgw@latest",
94
93
  "--python",
95
94
  "3.12",
96
- "wcgw_mcp"
95
+ "wcgw@latest"
97
96
  ]
98
97
  }
99
98
  }
@@ -105,10 +104,10 @@ Then restart claude app.
105
104
  _If there's an error in setting up_
106
105
 
107
106
  - 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.
108
- - 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.
107
+ - If there's still an issue, check that `uv tool run --python 3.12 wcgw@latest` runs in your terminal. It should have no output and shouldn't exit.
109
108
  - Try removing ~/.cache/uv folder
110
109
  - Try using `uv` version `0.6.0` for which this tool was tested.
111
- - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
110
+ - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --python 3.12 wcgw@latest`
112
111
 
113
112
  ### Windows on wsl
114
113
 
@@ -127,11 +126,9 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
127
126
  "uv",
128
127
  "tool",
129
128
  "run",
130
- "--from",
131
- "wcgw@latest",
132
129
  "--python",
133
130
  "3.12",
134
- "wcgw_mcp"
131
+ "wcgw@latest"
135
132
  ]
136
133
  }
137
134
  }
@@ -191,10 +188,6 @@ Commands:
191
188
 
192
189
  - 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.
193
190
 
194
- ## Chatgpt Setup
195
-
196
- Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
197
-
198
191
  ## Examples
199
192
 
200
193
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
@@ -231,7 +224,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
231
224
 
232
225
  Then run
233
226
 
234
- `uvx --from wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
227
+ `uvx wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
235
228
 
236
229
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
237
230
 
@@ -241,7 +234,7 @@ Add `ANTHROPIC_API_KEY` env variable.
241
234
 
242
235
  Then run
243
236
 
244
- `uvx --from wcgw@latest wcgw_local --claude`
237
+ `uvx wcgw@latest wcgw_local --claude`
245
238
 
246
239
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
247
240
 
@@ -1,8 +1,8 @@
1
1
  [project]
2
2
  authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
3
3
  name = "wcgw"
4
- version = "4.1.2"
5
- description = "Shell and coding agent on claude and chatgpt"
4
+ version = "5.0.1"
5
+ description = "Shell and coding agent for Claude and other mcp clients"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11"
8
8
  dependencies = [
@@ -45,23 +45,30 @@ packages = ["src/wcgw", "src/mcp_wcgw_fork/src/mcp_wcgw", "src/wcgw_cli"]
45
45
 
46
46
  [project.scripts]
47
47
  wcgw_local = "wcgw_cli:app"
48
- wcgw = "wcgw:listen"
49
- wcgw_relay = "wcgw.relay.serve:run"
48
+ wcgw = "wcgw:mcp_server"
50
49
  wcgw_mcp = "wcgw:mcp_server"
51
50
 
52
51
  [tool.uv]
53
- dev-dependencies = [
52
+ default-groups = []
53
+
54
+ [dependency-groups]
55
+ types = [
54
56
  "mypy>=1.11.2",
55
57
  "types-toml>=0.10.8.20240310",
58
+ "types-pexpect>=4.9.0.20241208",
59
+ "types-psutil>=7.0.0.20250218",
60
+ "line-profiler>=4.2.0",
61
+ ]
62
+ tests = [
63
+ "pytest>=8.0.0",
64
+ "pytest-cov>=4.1.0",
65
+ "pytest-asyncio>=0.25.3",
66
+ ]
67
+ dev = [
56
68
  "autoflake",
57
69
  "ipython>=8.12.3",
58
70
  "gunicorn>=23.0.0",
59
- "pytest>=8.0.0",
60
- "pytest-cov>=4.1.0",
61
71
  "line-profiler>=4.2.0",
62
- "pytest-asyncio>=0.25.3",
63
- "types-pexpect>=4.9.0.20241208",
64
- "types-psutil>=7.0.0.20250218",
65
72
  ]
66
73
 
67
74
  [tool.pytest.ini_options]
@@ -0,0 +1,4 @@
1
+ from .client.mcp_server import main as mcp_server
2
+
3
+ # Export mcp_server as the default entry point for wcgw
4
+ listen = mcp_server
@@ -1,6 +1,8 @@
1
1
  import datetime
2
+ import json
2
3
  import os
3
4
  import platform
5
+ import random
4
6
  import subprocess
5
7
  import threading
6
8
  import time
@@ -332,8 +334,49 @@ P = ParamSpec("P")
332
334
  R = TypeVar("R")
333
335
 
334
336
 
337
+ def get_bash_state_dir_xdg() -> str:
338
+ """Get the XDG directory for storing bash state."""
339
+ xdg_data_dir = os.environ.get("XDG_DATA_HOME", os.path.expanduser("~/.local/share"))
340
+ bash_state_dir = os.path.join(xdg_data_dir, "wcgw", "bash_state")
341
+ os.makedirs(bash_state_dir, exist_ok=True)
342
+ return bash_state_dir
343
+
344
+
345
+ def generate_chat_id() -> str:
346
+ """Generate a random 4-digit chat ID."""
347
+ return f"i{random.randint(1000, 9999)}"
348
+
349
+
350
+ def save_bash_state_by_id(chat_id: str, bash_state_dict: dict[str, Any]) -> None:
351
+ """Save bash state to XDG directory with the given chat ID."""
352
+ if not chat_id:
353
+ return
354
+
355
+ bash_state_dir = get_bash_state_dir_xdg()
356
+ state_file = os.path.join(bash_state_dir, f"{chat_id}_bash_state.json")
357
+
358
+ with open(state_file, "w") as f:
359
+ json.dump(bash_state_dict, f, indent=2)
360
+
361
+
362
+ def load_bash_state_by_id(chat_id: str) -> Optional[dict[str, Any]]:
363
+ """Load bash state from XDG directory with the given chat ID."""
364
+ if not chat_id:
365
+ return None
366
+
367
+ bash_state_dir = get_bash_state_dir_xdg()
368
+ state_file = os.path.join(bash_state_dir, f"{chat_id}_bash_state.json")
369
+
370
+ if not os.path.exists(state_file):
371
+ return None
372
+
373
+ with open(state_file) as f:
374
+ return json.load(f) # type: ignore
375
+
376
+
335
377
  class BashState:
336
378
  _use_screen: bool
379
+ _current_chat_id: str
337
380
 
338
381
  def __init__(
339
382
  self,
@@ -345,6 +388,7 @@ class BashState:
345
388
  mode: Optional[Modes],
346
389
  use_screen: bool,
347
390
  whitelist_for_overwrite: Optional[dict[str, "FileWhitelistData"]] = None,
391
+ chat_id: Optional[str] = None,
348
392
  ) -> None:
349
393
  self._last_command: str = ""
350
394
  self.console = console
@@ -362,6 +406,8 @@ class BashState:
362
406
  self._whitelist_for_overwrite: dict[str, FileWhitelistData] = (
363
407
  whitelist_for_overwrite or {}
364
408
  )
409
+ # Always ensure we have a chat ID
410
+ self._current_chat_id = chat_id if chat_id is not None else generate_chat_id()
365
411
  self._bg_expect_thread: Optional[threading.Thread] = None
366
412
  self._bg_expect_thread_stop_event = threading.Event()
367
413
  self._use_screen = use_screen
@@ -585,6 +631,40 @@ class BashState:
585
631
  self.cleanup()
586
632
  self._init_shell()
587
633
 
634
+ @property
635
+ def current_chat_id(self) -> str:
636
+ """Get the current chat ID."""
637
+ return self._current_chat_id
638
+
639
+ def load_state_from_chat_id(self, chat_id: str) -> bool:
640
+ """
641
+ Load bash state from a chat ID.
642
+
643
+ Args:
644
+ chat_id: The chat ID to load state from
645
+
646
+ Returns:
647
+ bool: True if state was successfully loaded, False otherwise
648
+ """
649
+ # Try to load state from disk
650
+ loaded_state = load_bash_state_by_id(chat_id)
651
+ if not loaded_state:
652
+ return False
653
+
654
+ # Parse and load the state
655
+ parsed_state = BashState.parse_state(loaded_state)
656
+ self.load_state(
657
+ parsed_state[0],
658
+ parsed_state[1],
659
+ parsed_state[2],
660
+ parsed_state[3],
661
+ parsed_state[4],
662
+ parsed_state[5],
663
+ parsed_state[5],
664
+ chat_id,
665
+ )
666
+ return True
667
+
588
668
  def serialize(self) -> dict[str, Any]:
589
669
  """Serialize BashState to a dictionary for saving"""
590
670
  return {
@@ -596,8 +676,14 @@ class BashState:
596
676
  },
597
677
  "mode": self._mode,
598
678
  "workspace_root": self._workspace_root,
679
+ "chat_id": self._current_chat_id,
599
680
  }
600
681
 
682
+ def save_state_to_disk(self) -> None:
683
+ """Save the current bash state to disk using the chat ID."""
684
+ state_dict = self.serialize()
685
+ save_bash_state_by_id(self._current_chat_id, state_dict)
686
+
601
687
  @staticmethod
602
688
  def parse_state(
603
689
  state: dict[str, Any],
@@ -608,6 +694,7 @@ class BashState:
608
694
  Modes,
609
695
  dict[str, "FileWhitelistData"],
610
696
  str,
697
+ str,
611
698
  ]:
612
699
  whitelist_state = state["whitelist_for_overwrite"]
613
700
  # Convert serialized whitelist data back to FileWhitelistData objects
@@ -634,6 +721,11 @@ class BashState:
634
721
  for k in whitelist_state
635
722
  }
636
723
 
724
+ # Get the chat_id from state, or generate a new one if not present
725
+ chat_id = state.get("chat_id")
726
+ if chat_id is None:
727
+ chat_id = generate_chat_id()
728
+
637
729
  return (
638
730
  BashCommandMode.deserialize(state["bash_command_mode"]),
639
731
  FileEditMode.deserialize(state["file_edit_mode"]),
@@ -641,6 +733,7 @@ class BashState:
641
733
  state["mode"],
642
734
  whitelist_dict,
643
735
  state.get("workspace_root", ""),
736
+ chat_id,
644
737
  )
645
738
 
646
739
  def load_state(
@@ -652,6 +745,7 @@ class BashState:
652
745
  whitelist_for_overwrite: dict[str, "FileWhitelistData"],
653
746
  cwd: str,
654
747
  workspace_root: str,
748
+ chat_id: str,
655
749
  ) -> None:
656
750
  """Create a new BashState instance from a serialized state dictionary"""
657
751
  self._bash_command_mode = bash_command_mode
@@ -661,8 +755,12 @@ class BashState:
661
755
  self._write_if_empty_mode = write_if_empty_mode
662
756
  self._whitelist_for_overwrite = dict(whitelist_for_overwrite)
663
757
  self._mode = mode
758
+ self._current_chat_id = chat_id
664
759
  self.reset_shell()
665
760
 
761
+ # Save state to disk after loading
762
+ self.save_state_to_disk()
763
+
666
764
  def get_pending_for(self) -> str:
667
765
  if isinstance(self._state, datetime.datetime):
668
766
  timedelta = datetime.datetime.now() - self._state
@@ -902,6 +1000,15 @@ def execute_bash(
902
1000
  timeout_s: Optional[float],
903
1001
  ) -> tuple[str, float]:
904
1002
  try:
1003
+ # Check if the chat ID matches current
1004
+ if bash_arg.chat_id != bash_state.current_chat_id:
1005
+ # Try to load state from the chat ID
1006
+ if not bash_state.load_state_from_chat_id(bash_arg.chat_id):
1007
+ return (
1008
+ f"Error: No saved bash state found for chat ID {bash_arg.chat_id}. Please initialize first with this ID.",
1009
+ 0.0,
1010
+ )
1011
+
905
1012
  output, cost = _execute_bash(bash_state, enc, bash_arg, max_tokens, timeout_s)
906
1013
 
907
1014
  # Remove echo if it's a command
@@ -11,6 +11,7 @@ class SearchReplaceMatchError(Exception):
11
11
  message = f"""
12
12
  {message}
13
13
  ---
14
+ Edit failed, no changes are applied. You'll have to reapply all search/replace blocks again.
14
15
  Retry immediately with same "percentage_to_change" using search replace blocks fixing above error.
15
16
  """
16
17
  super().__init__(message)
@@ -89,7 +89,6 @@ You are now running in "code_writer" mode.
89
89
  - Do not use echo to write multi-line files, always use FileWriteOrEdit tool to update a code.
90
90
  - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
91
91
  - You should use the provided bash execution, reading and writing file tools to complete objective.
92
- - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
93
92
  - Do not use artifacts if you have access to the repository and not asked by the user to provide artifacts/snippets. Directly create/update using wcgw tools.
94
93
  """
95
94
 
@@ -114,13 +113,9 @@ You are now running in "code_writer" mode.
114
113
 
115
114
 
116
115
  WCGW_PROMPT = """
117
- ---
118
- You're an expert software engineer with shell and code knowledge.
119
-
120
- Instructions:
116
+ # Instructions
121
117
 
122
118
  - You should use the provided bash execution, reading and writing file tools to complete objective.
123
- - First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
124
119
  - Do not provide code snippets unless asked by the user, instead directly add/edit the code.
125
120
  - Do not install new tools/packages before ensuring no such tools/package or an alternative already exists.
126
121
  - Do not use artifacts if you have access to the repository and not asked by the user to provide artifacts/snippets. Directly create/update using wcgw tools
@@ -131,8 +126,6 @@ Instructions:
131
126
  Additional instructions:
132
127
  Always run `pwd` if you get any file or directory not found error to make sure you're not lost, or to get absolute cwd.
133
128
 
134
- Always write production ready, syntactically correct code.
135
-
136
129
 
137
130
  """
138
131
  ARCHITECT_PROMPT = """
@@ -91,7 +91,7 @@ TOOL_PROMPTS = [
91
91
  name="ContextSave",
92
92
  description="""
93
93
  Saves provided description and file contents of all the relevant file paths or globs in a single text file.
94
- - Provide random unqiue id or whatever user provided.
94
+ - Provide random 3 word unqiue id or whatever user provided.
95
95
  - Leave project path as empty string if no project path""",
96
96
  ),
97
97
  ]