wcgw 4.1.1__tar.gz → 5.0.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 (133) hide show
  1. {wcgw-4.1.1 → wcgw-5.0.0}/.github/workflows/python-tests.yml +1 -2
  2. {wcgw-4.1.1 → wcgw-5.0.0}/.github/workflows/python-types.yml +1 -2
  3. {wcgw-4.1.1 → wcgw-5.0.0}/PKG-INFO +13 -20
  4. {wcgw-4.1.1 → wcgw-5.0.0}/README.md +9 -18
  5. {wcgw-4.1.1 → wcgw-5.0.0}/pyproject.toml +19 -12
  6. wcgw-5.0.0/src/wcgw/__init__.py +4 -0
  7. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/bash_state/bash_state.py +107 -0
  8. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/file_ops/diff_edit.py +1 -0
  9. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/modes.py +1 -8
  10. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/tool_prompts.py +1 -1
  11. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/tools.py +80 -41
  12. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/types_.py +6 -1
  13. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_edit.py +14 -0
  14. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_mcp_server.py +8 -2
  15. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_tools.py +52 -25
  16. {wcgw-4.1.1 → wcgw-5.0.0}/uv.lock +17 -7
  17. wcgw-4.1.1/gpt_action_json_schema.json +0 -577
  18. wcgw-4.1.1/gpt_instructions.txt +0 -113
  19. wcgw-4.1.1/openai.md +0 -71
  20. wcgw-4.1.1/src/wcgw/__init__.py +0 -2
  21. wcgw-4.1.1/src/wcgw/relay/client.py +0 -95
  22. wcgw-4.1.1/src/wcgw/relay/serve.py +0 -261
  23. wcgw-4.1.1/src/wcgw/relay/static/privacy.txt +0 -7
  24. {wcgw-4.1.1 → wcgw-5.0.0}/.github/workflows/python-publish.yml +0 -0
  25. {wcgw-4.1.1 → wcgw-5.0.0}/.gitignore +0 -0
  26. {wcgw-4.1.1 → wcgw-5.0.0}/.gitmodules +0 -0
  27. {wcgw-4.1.1 → wcgw-5.0.0}/.python-version +0 -0
  28. {wcgw-4.1.1 → wcgw-5.0.0}/.vscode/settings.json +0 -0
  29. {wcgw-4.1.1 → wcgw-5.0.0}/CLAUDE.md +0 -0
  30. {wcgw-4.1.1 → wcgw-5.0.0}/Dockerfile +0 -0
  31. {wcgw-4.1.1 → wcgw-5.0.0}/LICENSE +0 -0
  32. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.git +0 -0
  33. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
  36. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
  37. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
  38. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
  39. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.gitignore +0 -0
  40. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/.python-version +0 -0
  41. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
  42. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
  43. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/LICENSE +0 -0
  44. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/README.md +0 -0
  45. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/RELEASE.md +0 -0
  46. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/SECURITY.md +0 -0
  47. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/README.md +0 -0
  48. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
  49. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
  50. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  51. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  52. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  53. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
  54. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
  55. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
  56. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  57. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  58. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  59. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
  60. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
  61. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
  62. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  63. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  64. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  65. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
  66. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/pyproject.toml +0 -0
  67. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
  68. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
  69. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
  70. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
  71. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
  72. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
  73. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
  74. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
  75. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
  76. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
  77. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
  78. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
  79. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
  80. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
  81. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
  82. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
  83. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
  84. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
  85. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
  86. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
  87. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
  88. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -0
  89. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
  90. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
  91. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
  92. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
  93. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
  94. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
  95. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
  96. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
  97. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
  98. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
  99. {wcgw-4.1.1 → wcgw-5.0.0}/src/mcp_wcgw_fork/uv.lock +0 -0
  100. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/__init__.py +0 -0
  101. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
  102. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
  103. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/common.py +0 -0
  104. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/diff-instructions.txt +0 -0
  105. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/encoder/__init__.py +0 -0
  106. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/file_ops/search_replace.py +0 -0
  107. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/mcp_server/Readme.md +0 -0
  108. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/mcp_server/__init__.py +0 -0
  109. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/mcp_server/server.py +0 -0
  110. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/memory.py +0 -0
  111. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  112. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/file_stats.py +0 -0
  113. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  114. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  115. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  116. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  117. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw/py.typed +0 -0
  118. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/__init__.py +0 -0
  119. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/__main__.py +0 -0
  120. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/anthropic_client.py +0 -0
  121. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/cli.py +0 -0
  122. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/openai_client.py +0 -0
  123. {wcgw-4.1.1 → wcgw-5.0.0}/src/wcgw_cli/openai_utils.py +0 -0
  124. {wcgw-4.1.1 → wcgw-5.0.0}/static/claude-ss.jpg +0 -0
  125. {wcgw-4.1.1 → wcgw-5.0.0}/static/computer-use.jpg +0 -0
  126. {wcgw-4.1.1 → wcgw-5.0.0}/static/example.jpg +0 -0
  127. {wcgw-4.1.1 → wcgw-5.0.0}/static/rocket-icon.png +0 -0
  128. {wcgw-4.1.1 → wcgw-5.0.0}/static/ss1.png +0 -0
  129. {wcgw-4.1.1 → wcgw-5.0.0}/static/workflow-demo.gif +0 -0
  130. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_bash_parser.py +0 -0
  131. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_bash_parser_complex.py +0 -0
  132. {wcgw-4.1.1 → wcgw-5.0.0}/tests/test_file_range_tracking.py +0 -0
  133. {wcgw-4.1.1 → wcgw-5.0.0}/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.1
4
- Summary: Shell and coding agent on claude and chatgpt
3
+ Version: 5.0.0
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
@@ -21,17 +21,18 @@ Requires-Dist: semantic-version>=2.10.0
21
21
  Requires-Dist: syntax-checker>=0.3.0
22
22
  Requires-Dist: tokenizers>=0.21.0
23
23
  Requires-Dist: toml>=0.10.2
24
+ Requires-Dist: tree-sitter-bash>=0.23.3
25
+ Requires-Dist: tree-sitter>=0.24.0
24
26
  Requires-Dist: typer>=0.12.5
25
27
  Requires-Dist: uvicorn>=0.31.0
26
28
  Requires-Dist: websockets>=13.1
27
29
  Description-Content-Type: text/markdown
28
30
 
29
- # Shell and Coding agent for Claude and Chatgpt
31
+ # Shell and Coding agent for Claude and other mcp clients
30
32
 
31
- Empowering chat applications to code, build and run on your local machine.
33
+ Empowering AI to code, build and run on your local machine.
32
34
 
33
- - Claude - MCP server with tightly integrated shell and code editing tools.
34
- - 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.
35
36
 
36
37
  ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
37
38
 
@@ -117,11 +118,9 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
117
118
  "args": [
118
119
  "tool",
119
120
  "run",
120
- "--from",
121
- "wcgw@latest",
122
121
  "--python",
123
122
  "3.12",
124
- "wcgw_mcp"
123
+ "wcgw@latest"
125
124
  ]
126
125
  }
127
126
  }
@@ -133,10 +132,10 @@ Then restart claude app.
133
132
  _If there's an error in setting up_
134
133
 
135
134
  - 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.
136
- - 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.
135
+ - 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.
137
136
  - Try removing ~/.cache/uv folder
138
137
  - Try using `uv` version `0.6.0` for which this tool was tested.
139
- - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
138
+ - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --python 3.12 wcgw@latest`
140
139
 
141
140
  ### Windows on wsl
142
141
 
@@ -155,11 +154,9 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
155
154
  "uv",
156
155
  "tool",
157
156
  "run",
158
- "--from",
159
- "wcgw@latest",
160
157
  "--python",
161
158
  "3.12",
162
- "wcgw_mcp"
159
+ "wcgw@latest"
163
160
  ]
164
161
  }
165
162
  }
@@ -219,10 +216,6 @@ Commands:
219
216
 
220
217
  - 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.
221
218
 
222
- ## Chatgpt Setup
223
-
224
- Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
225
-
226
219
  ## Examples
227
220
 
228
221
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
@@ -259,7 +252,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
259
252
 
260
253
  Then run
261
254
 
262
- `uvx --from wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
255
+ `uvx wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
263
256
 
264
257
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
265
258
 
@@ -269,7 +262,7 @@ Add `ANTHROPIC_API_KEY` env variable.
269
262
 
270
263
  Then run
271
264
 
272
- `uvx --from wcgw@latest wcgw_local --claude`
265
+ `uvx wcgw@latest wcgw_local --claude`
273
266
 
274
267
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
275
268
 
@@ -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
- Empowering chat applications to code, build and run on your local machine.
3
+ Empowering AI 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
 
@@ -89,11 +88,9 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
89
88
  "args": [
90
89
  "tool",
91
90
  "run",
92
- "--from",
93
- "wcgw@latest",
94
91
  "--python",
95
92
  "3.12",
96
- "wcgw_mcp"
93
+ "wcgw@latest"
97
94
  ]
98
95
  }
99
96
  }
@@ -105,10 +102,10 @@ Then restart claude app.
105
102
  _If there's an error in setting up_
106
103
 
107
104
  - 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.
105
+ - 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
106
  - Try removing ~/.cache/uv folder
110
107
  - 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`
108
+ - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --python 3.12 wcgw@latest`
112
109
 
113
110
  ### Windows on wsl
114
111
 
@@ -127,11 +124,9 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
127
124
  "uv",
128
125
  "tool",
129
126
  "run",
130
- "--from",
131
- "wcgw@latest",
132
127
  "--python",
133
128
  "3.12",
134
- "wcgw_mcp"
129
+ "wcgw@latest"
135
130
  ]
136
131
  }
137
132
  }
@@ -191,10 +186,6 @@ Commands:
191
186
 
192
187
  - 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
188
 
194
- ## Chatgpt Setup
195
-
196
- Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
197
-
198
189
  ## Examples
199
190
 
200
191
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
@@ -231,7 +222,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
231
222
 
232
223
  Then run
233
224
 
234
- `uvx --from wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
225
+ `uvx wcgw@latest wcgw_local --limit 0.1` # Cost limit $0.1
235
226
 
236
227
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
237
228
 
@@ -241,7 +232,7 @@ Add `ANTHROPIC_API_KEY` env variable.
241
232
 
242
233
  Then run
243
234
 
244
- `uvx --from wcgw@latest wcgw_local --claude`
235
+ `uvx wcgw@latest wcgw_local --claude`
245
236
 
246
237
  You can now directly write messages or press enter key to open vim for multiline message and text pasting.
247
238
 
@@ -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.1"
5
- description = "Shell and coding agent on claude and chatgpt"
4
+ version = "5.0.0"
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 = [
@@ -24,6 +24,8 @@ dependencies = [
24
24
  "pygit2>=1.16.0",
25
25
  "syntax-checker>=0.3.0",
26
26
  "psutil>=7.0.0",
27
+ "tree-sitter>=0.24.0",
28
+ "tree-sitter-bash>=0.23.3",
27
29
  ]
28
30
 
29
31
  [project.urls]
@@ -43,25 +45,30 @@ packages = ["src/wcgw", "src/mcp_wcgw_fork/src/mcp_wcgw", "src/wcgw_cli"]
43
45
 
44
46
  [project.scripts]
45
47
  wcgw_local = "wcgw_cli:app"
46
- wcgw = "wcgw:listen"
47
- wcgw_relay = "wcgw.relay.serve:run"
48
+ wcgw = "wcgw:mcp_server"
48
49
  wcgw_mcp = "wcgw:mcp_server"
49
50
 
50
51
  [tool.uv]
51
- dev-dependencies = [
52
+ default-groups = []
53
+
54
+ [dependency-groups]
55
+ types = [
52
56
  "mypy>=1.11.2",
53
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 = [
54
68
  "autoflake",
55
69
  "ipython>=8.12.3",
56
70
  "gunicorn>=23.0.0",
57
- "pytest>=8.0.0",
58
- "pytest-cov>=4.1.0",
59
71
  "line-profiler>=4.2.0",
60
- "pytest-asyncio>=0.25.3",
61
- "types-pexpect>=4.9.0.20241208",
62
- "types-psutil>=7.0.0.20250218",
63
- "tree-sitter>=0.24.0",
64
- "tree-sitter-bash>=0.23.3",
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
  ]