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.
- {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-tests.yml +1 -2
- {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-types.yml +1 -2
- {wcgw-4.1.2 → wcgw-5.0.1}/PKG-INFO +12 -19
- {wcgw-4.1.2 → wcgw-5.0.1}/README.md +10 -17
- {wcgw-4.1.2 → wcgw-5.0.1}/pyproject.toml +17 -10
- wcgw-5.0.1/src/wcgw/__init__.py +4 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/bash_state.py +107 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/file_ops/diff_edit.py +1 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/modes.py +1 -8
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/tool_prompts.py +1 -1
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/tools.py +84 -42
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/types_.py +6 -1
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_edit.py +14 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_mcp_server.py +8 -2
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_tools.py +76 -25
- {wcgw-4.1.2 → wcgw-5.0.1}/uv.lock +17 -7
- wcgw-4.1.2/gpt_action_json_schema.json +0 -577
- wcgw-4.1.2/gpt_instructions.txt +0 -113
- wcgw-4.1.2/openai.md +0 -71
- wcgw-4.1.2/src/wcgw/__init__.py +0 -2
- wcgw-4.1.2/src/wcgw/relay/client.py +0 -95
- wcgw-4.1.2/src/wcgw/relay/serve.py +0 -261
- wcgw-4.1.2/src/wcgw/relay/static/privacy.txt +0 -7
- {wcgw-4.1.2 → wcgw-5.0.1}/.github/workflows/python-publish.yml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/.gitignore +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/.gitmodules +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/.python-version +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/.vscode/settings.json +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/CLAUDE.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/Dockerfile +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/LICENSE +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.git +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.gitignore +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/.python-version +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/LICENSE +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/README.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/RELEASE.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/SECURITY.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/README.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/pyproject.toml +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/mcp_wcgw_fork/uv.lock +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/common.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/diff-instructions.txt +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/encoder/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/file_ops/search_replace.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/mcp_server/server.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/memory.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/display_tree.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/file_stats.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/path_prob.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/client/repo_ops/repo_context.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw/py.typed +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/__init__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/__main__.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/anthropic_client.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/cli.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/openai_client.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/src/wcgw_cli/openai_utils.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/claude-ss.jpg +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/computer-use.jpg +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/example.jpg +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/rocket-icon.png +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/ss1.png +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/static/workflow-demo.gif +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_bash_parser.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_bash_parser_complex.py +0 -0
- {wcgw-4.1.2 → wcgw-5.0.1}/tests/test_file_range_tracking.py +0 -0
- {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
|
-
Summary: Shell and coding agent
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
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 --
|
|
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 --
|
|
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
|
-
"
|
|
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
|

|
|
@@ -261,7 +254,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
|
|
|
261
254
|
|
|
262
255
|
Then run
|
|
263
256
|
|
|
264
|
-
`uvx
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
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 --
|
|
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 --
|
|
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
|
-
"
|
|
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
|

|
|
@@ -231,7 +224,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
|
|
|
231
224
|
|
|
232
225
|
Then run
|
|
233
226
|
|
|
234
|
-
`uvx
|
|
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
|
|
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 = "
|
|
5
|
-
description = "Shell and coding agent
|
|
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:
|
|
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
|
-
|
|
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]
|
|
@@ -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
|
]
|