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

|
|
@@ -259,7 +252,7 @@ Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
|
|
|
259
252
|
|
|
260
253
|
Then run
|
|
261
254
|
|
|
262
|
-
`uvx
|
|
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
|
|
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
|
|
1
|
+
# Shell and Coding agent for Claude and other mcp clients
|
|
2
2
|
|
|
3
|
-
Empowering
|
|
3
|
+
Empowering AI 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
|
|
|
@@ -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
|
-
"
|
|
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 --
|
|
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 --
|
|
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
|
-
"
|
|
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
|

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