wcgw 5.0.2__tar.gz → 5.1.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-5.0.2 → wcgw-5.1.1}/.github/workflows/python-tests.yml +1 -1
- {wcgw-5.0.2 → wcgw-5.1.1}/.github/workflows/python-types.yml +1 -1
- {wcgw-5.0.2 → wcgw-5.1.1}/Dockerfile +4 -12
- {wcgw-5.0.2 → wcgw-5.1.1}/PKG-INFO +6 -18
- {wcgw-5.0.2 → wcgw-5.1.1}/README.md +4 -17
- {wcgw-5.0.2 → wcgw-5.1.1}/pyproject.toml +3 -3
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/bash_state/bash_state.py +2 -2
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/file_ops/diff_edit.py +14 -2
- wcgw-5.1.1/src/wcgw/client/file_ops/extensions.py +137 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/file_ops/search_replace.py +1 -2
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/mcp_server/server.py +10 -18
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/memory.py +4 -1
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/display_tree.py +4 -4
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/tool_prompts.py +16 -15
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/tools.py +95 -38
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/anthropic_client.py +8 -4
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/openai_client.py +7 -3
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_edit.py +15 -15
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_file_range_tracking.py +3 -2
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_mcp_server.py +4 -4
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_tools.py +82 -78
- wcgw-5.1.1/uv.lock +1503 -0
- wcgw-5.0.2/.gitmodules +0 -3
- wcgw-5.0.2/src/mcp_wcgw_fork/.git +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -11
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -55
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -8
- wcgw-5.0.2/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -69
- wcgw-5.0.2/src/mcp_wcgw_fork/.gitignore +0 -162
- wcgw-5.0.2/src/mcp_wcgw_fork/.python-version +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -128
- wcgw-5.0.2/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -56
- wcgw-5.0.2/src/mcp_wcgw_fork/LICENSE +0 -21
- wcgw-5.0.2/src/mcp_wcgw_fork/README.md +0 -342
- wcgw-5.0.2/src/mcp_wcgw_fork/RELEASE.md +0 -15
- wcgw-5.0.2/src/mcp_wcgw_fork/SECURITY.md +0 -14
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/README.md +0 -5
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -55
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -5
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -130
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -47
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -48
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -5
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -86
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -47
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -48
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -1
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -5
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -100
- wcgw-5.0.2/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -47
- wcgw-5.0.2/src/mcp_wcgw_fork/pyproject.toml +0 -75
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -114
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -79
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -234
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -142
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -128
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -514
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -50
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -16
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -288
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -178
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -83
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -61
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -14
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -9
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -87
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -40
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -288
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -3
- wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -1060
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/__init__.py +0 -0
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/client/test_session.py +0 -98
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -38
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/conftest.py +0 -29
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/server/test_session.py +0 -100
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -68
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -28
- wcgw-5.0.2/src/mcp_wcgw_fork/tests/test_types.py +0 -29
- wcgw-5.0.2/src/mcp_wcgw_fork/uv.lock +0 -621
- wcgw-5.0.2/src/wcgw/client/__init__.py +0 -0
- wcgw-5.0.2/src/wcgw/py.typed +0 -0
- wcgw-5.0.2/uv.lock +0 -1379
- {wcgw-5.0.2 → wcgw-5.1.1}/.github/workflows/python-publish.yml +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/.gitignore +0 -0
- /wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py → /wcgw-5.1.1/.gitmodules +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/.python-version +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/.vscode/settings.json +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/CLAUDE.md +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/LICENSE +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/__init__.py +0 -0
- {wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw/shared → wcgw-5.1.1/src/wcgw/client}/__init__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/common.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/diff-instructions.txt +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/encoder/__init__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/mcp_server/__init__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/modes.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/file_stats.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/path_prob.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/client/repo_ops/repo_context.py +0 -0
- {wcgw-5.0.2/src/mcp_wcgw_fork/src/mcp_wcgw → wcgw-5.1.1/src/wcgw}/py.typed +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw/types_.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/__init__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/__main__.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/cli.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/src/wcgw_cli/openai_utils.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/claude-ss.jpg +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/computer-use.jpg +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/example.jpg +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/rocket-icon.png +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/ss1.png +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/static/workflow-demo.gif +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_bash_parser.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_bash_parser_complex.py +0 -0
- {wcgw-5.0.2 → wcgw-5.1.1}/tests/test_readfiles.py +0 -0
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
pip install uv
|
|
28
28
|
- name: Run tests with coverage
|
|
29
29
|
run: |
|
|
30
|
-
uv run --group tests --python "${{ matrix.python-version }}" pytest --cov=wcgw --cov-report=xml --cov-report=term-missing
|
|
30
|
+
uv run --frozen --group tests --python "${{ matrix.python-version }}" pytest --cov=wcgw --cov-report=xml --cov-report=term-missing
|
|
31
31
|
- name: Upload coverage reports to Codecov
|
|
32
32
|
uses: codecov/codecov-action@v4
|
|
33
33
|
if: success()
|
|
@@ -14,8 +14,8 @@ COPY README.md /app/
|
|
|
14
14
|
ENV UV_COMPILE_BYTECODE=1
|
|
15
15
|
ENV UV_LINK_MODE=copy
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
RUN apt-get update &&
|
|
17
|
+
# No need for git as we don't need to clone submodules anymore
|
|
18
|
+
RUN apt-get update && rm -rf /var/lib/apt/lists/*
|
|
19
19
|
|
|
20
20
|
# Install dependencies
|
|
21
21
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
@@ -24,14 +24,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|
|
24
24
|
# Copy the entire project into the container
|
|
25
25
|
COPY src /app/src
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
RUN if [ ! -d "/app/src/mcp_wcgw_fork" ] || [ -z "$(ls -A /app/src/mcp_wcgw_fork)" ]; then \
|
|
29
|
-
mkdir -p /app/src/mcp_wcgw_fork && \
|
|
30
|
-
git clone https://github.com/rusiaaman/python-sdk.git /app/src/mcp_wcgw_fork && \
|
|
31
|
-
echo "Repository cloned successfully"; \
|
|
32
|
-
else \
|
|
33
|
-
echo "src/mcp_wcgw_fork already exists and is not empty"; \
|
|
34
|
-
fi
|
|
27
|
+
# No need to clone the submodule as it has been removed
|
|
35
28
|
|
|
36
29
|
# Install the project
|
|
37
30
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
@@ -47,8 +40,7 @@ WORKDIR /workspace
|
|
|
47
40
|
|
|
48
41
|
# Copy the installed application from the previous stage
|
|
49
42
|
COPY --from=uv --chown=app:app /app/.venv /app/.venv
|
|
50
|
-
#
|
|
51
|
-
COPY --from=uv --chown=app:app /app/src/mcp_wcgw_fork /app/src/mcp_wcgw_fork
|
|
43
|
+
# No need to copy the submodule as it has been removed
|
|
52
44
|
|
|
53
45
|
# Add the virtual environment to the PATH
|
|
54
46
|
ENV PATH="/app/.venv/bin:$PATH"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wcgw
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.1.1
|
|
4
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>
|
|
@@ -8,6 +8,7 @@ License-File: LICENSE
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Requires-Dist: anthropic>=0.39.0
|
|
10
10
|
Requires-Dist: fastapi>=0.115.0
|
|
11
|
+
Requires-Dist: mcp>=1.7.0
|
|
11
12
|
Requires-Dist: openai>=1.46.0
|
|
12
13
|
Requires-Dist: petname>=2.6
|
|
13
14
|
Requires-Dist: pexpect>=4.9.0
|
|
@@ -117,13 +118,7 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
|
|
|
117
118
|
"mcpServers": {
|
|
118
119
|
"wcgw": {
|
|
119
120
|
"command": "uv",
|
|
120
|
-
"args": [
|
|
121
|
-
"tool",
|
|
122
|
-
"run",
|
|
123
|
-
"--python",
|
|
124
|
-
"3.12",
|
|
125
|
-
"wcgw@latest"
|
|
126
|
-
]
|
|
121
|
+
"args": ["tool", "run", "--python", "3.12", "wcgw@latest"]
|
|
127
122
|
}
|
|
128
123
|
}
|
|
129
124
|
}
|
|
@@ -152,14 +147,7 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
|
|
|
152
147
|
"mcpServers": {
|
|
153
148
|
"wcgw": {
|
|
154
149
|
"command": "wsl.exe",
|
|
155
|
-
"args": [
|
|
156
|
-
"uv",
|
|
157
|
-
"tool",
|
|
158
|
-
"run",
|
|
159
|
-
"--python",
|
|
160
|
-
"3.12",
|
|
161
|
-
"wcgw@latest"
|
|
162
|
-
]
|
|
150
|
+
"args": ["uv", "tool", "run", "--python", "3.12", "wcgw@latest"]
|
|
163
151
|
}
|
|
164
152
|
}
|
|
165
153
|
}
|
|
@@ -231,7 +219,7 @@ Then you can update `/Users/username/Library/Application Support/Claude/claude_d
|
|
|
231
219
|
```
|
|
232
220
|
{
|
|
233
221
|
"mcpServers": {
|
|
234
|
-
"
|
|
222
|
+
"wcgw": {
|
|
235
223
|
"command": "docker",
|
|
236
224
|
"args": [
|
|
237
225
|
"run",
|
|
@@ -239,7 +227,7 @@ Then you can update `/Users/username/Library/Application Support/Claude/claude_d
|
|
|
239
227
|
"--rm",
|
|
240
228
|
"--mount",
|
|
241
229
|
"type=bind,src=/Users/username/Desktop,dst=/workspace/Desktop",
|
|
242
|
-
"wcgw"
|
|
230
|
+
"wcgw"
|
|
243
231
|
]
|
|
244
232
|
}
|
|
245
233
|
}
|
|
@@ -87,13 +87,7 @@ Then create or update `claude_desktop_config.json` (~/Library/Application Suppor
|
|
|
87
87
|
"mcpServers": {
|
|
88
88
|
"wcgw": {
|
|
89
89
|
"command": "uv",
|
|
90
|
-
"args": [
|
|
91
|
-
"tool",
|
|
92
|
-
"run",
|
|
93
|
-
"--python",
|
|
94
|
-
"3.12",
|
|
95
|
-
"wcgw@latest"
|
|
96
|
-
]
|
|
90
|
+
"args": ["tool", "run", "--python", "3.12", "wcgw@latest"]
|
|
97
91
|
}
|
|
98
92
|
}
|
|
99
93
|
}
|
|
@@ -122,14 +116,7 @@ Then add or update the claude config file `%APPDATA%\Claude\claude_desktop_confi
|
|
|
122
116
|
"mcpServers": {
|
|
123
117
|
"wcgw": {
|
|
124
118
|
"command": "wsl.exe",
|
|
125
|
-
"args": [
|
|
126
|
-
"uv",
|
|
127
|
-
"tool",
|
|
128
|
-
"run",
|
|
129
|
-
"--python",
|
|
130
|
-
"3.12",
|
|
131
|
-
"wcgw@latest"
|
|
132
|
-
]
|
|
119
|
+
"args": ["uv", "tool", "run", "--python", "3.12", "wcgw@latest"]
|
|
133
120
|
}
|
|
134
121
|
}
|
|
135
122
|
}
|
|
@@ -201,7 +188,7 @@ Then you can update `/Users/username/Library/Application Support/Claude/claude_d
|
|
|
201
188
|
```
|
|
202
189
|
{
|
|
203
190
|
"mcpServers": {
|
|
204
|
-
"
|
|
191
|
+
"wcgw": {
|
|
205
192
|
"command": "docker",
|
|
206
193
|
"args": [
|
|
207
194
|
"run",
|
|
@@ -209,7 +196,7 @@ Then you can update `/Users/username/Library/Application Support/Claude/claude_d
|
|
|
209
196
|
"--rm",
|
|
210
197
|
"--mount",
|
|
211
198
|
"type=bind,src=/Users/username/Desktop,dst=/workspace/Desktop",
|
|
212
|
-
"wcgw"
|
|
199
|
+
"wcgw"
|
|
213
200
|
]
|
|
214
201
|
}
|
|
215
202
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
|
|
3
3
|
name = "wcgw"
|
|
4
|
-
version = "5.
|
|
4
|
+
version = "5.1.1"
|
|
5
5
|
description = "Shell and coding agent for Claude and other mcp clients"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.11"
|
|
@@ -26,6 +26,7 @@ dependencies = [
|
|
|
26
26
|
"psutil>=7.0.0",
|
|
27
27
|
"tree-sitter>=0.24.0",
|
|
28
28
|
"tree-sitter-bash>=0.23.3",
|
|
29
|
+
"mcp>=1.7.0",
|
|
29
30
|
]
|
|
30
31
|
|
|
31
32
|
[project.urls]
|
|
@@ -36,10 +37,9 @@ requires = ["hatchling"]
|
|
|
36
37
|
build-backend = "hatchling.build"
|
|
37
38
|
|
|
38
39
|
[tool.hatch.build.targets.wheel]
|
|
39
|
-
packages = ["src/wcgw", "src/
|
|
40
|
+
packages = ["src/wcgw", "src/wcgw_cli"]
|
|
40
41
|
|
|
41
42
|
[tool.hatch.build.targets.wheel.sources]
|
|
42
|
-
"src/mcp_wcgw_fork/src/mcp_wcgw" = "mcp_wcgw"
|
|
43
43
|
"src/wcgw" = "wcgw"
|
|
44
44
|
"src/wcgw_cli" = "wcgw_cli"
|
|
45
45
|
|
|
@@ -996,7 +996,7 @@ def execute_bash(
|
|
|
996
996
|
bash_state: BashState,
|
|
997
997
|
enc: EncoderDecoder[int],
|
|
998
998
|
bash_arg: BashCommand,
|
|
999
|
-
max_tokens: Optional[int],
|
|
999
|
+
max_tokens: Optional[int], # This will be noncoding_max_tokens
|
|
1000
1000
|
timeout_s: Optional[float],
|
|
1001
1001
|
) -> tuple[str, float]:
|
|
1002
1002
|
try:
|
|
@@ -1026,7 +1026,7 @@ def _execute_bash(
|
|
|
1026
1026
|
bash_state: BashState,
|
|
1027
1027
|
enc: EncoderDecoder[int],
|
|
1028
1028
|
bash_arg: BashCommand,
|
|
1029
|
-
max_tokens: Optional[int],
|
|
1029
|
+
max_tokens: Optional[int], # This will be noncoding_max_tokens
|
|
1030
1030
|
timeout_s: Optional[float],
|
|
1031
1031
|
) -> tuple[str, float]:
|
|
1032
1032
|
try:
|
|
@@ -46,10 +46,13 @@ class FileEditOutput:
|
|
|
46
46
|
last_idx = 0
|
|
47
47
|
errors = []
|
|
48
48
|
warnings = set[str]()
|
|
49
|
+
info = set[str]()
|
|
50
|
+
score = 0.0
|
|
49
51
|
for (span, tolerances, replace_with), search_ in zip(
|
|
50
52
|
self.edited_with_tolerances, self.orig_search_blocks
|
|
51
53
|
):
|
|
52
54
|
for tol in tolerances:
|
|
55
|
+
score += tol.count * tol.score_multiplier
|
|
53
56
|
if tol.count > 0:
|
|
54
57
|
if tol.severity_cat == "WARNING":
|
|
55
58
|
warnings.add(tol.error_name)
|
|
@@ -66,6 +69,8 @@ Error:
|
|
|
66
69
|
{tol.error_name}
|
|
67
70
|
---
|
|
68
71
|
""")
|
|
72
|
+
else:
|
|
73
|
+
info.add(tol.error_name)
|
|
69
74
|
if len(errors) >= max_errors:
|
|
70
75
|
raise SearchReplaceMatchError("\n".join(errors))
|
|
71
76
|
if last_idx < span.start:
|
|
@@ -80,12 +85,19 @@ Error:
|
|
|
80
85
|
if errors:
|
|
81
86
|
raise SearchReplaceMatchError("\n".join(errors))
|
|
82
87
|
|
|
88
|
+
if score > 1000:
|
|
89
|
+
display = (list(warnings) + list(info))[:max_errors]
|
|
90
|
+
raise SearchReplaceMatchError(
|
|
91
|
+
"Too many warnings generated, not apply the edits\n"
|
|
92
|
+
+ "\n".join(display)
|
|
93
|
+
)
|
|
94
|
+
|
|
83
95
|
return new_lines, set(warnings)
|
|
84
96
|
|
|
85
97
|
@staticmethod
|
|
86
98
|
def get_best_match(
|
|
87
99
|
outputs: list["FileEditOutput"],
|
|
88
|
-
) ->
|
|
100
|
+
) -> list["FileEditOutput"]:
|
|
89
101
|
best_hits: list[FileEditOutput] = []
|
|
90
102
|
best_score = float("-inf")
|
|
91
103
|
assert outputs
|
|
@@ -103,7 +115,7 @@ Error:
|
|
|
103
115
|
best_score = hit_score
|
|
104
116
|
elif abs(hit_score - best_score) < 1e-3:
|
|
105
117
|
best_hits.append(output)
|
|
106
|
-
return best_hits
|
|
118
|
+
return best_hits
|
|
107
119
|
|
|
108
120
|
|
|
109
121
|
def line_process_max_space_tolerance(line: str) -> str:
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File with definitions of known source code file extensions.
|
|
3
|
+
Used to determine the appropriate context length for files.
|
|
4
|
+
Supports selecting between coding_max_tokens and noncoding_max_tokens
|
|
5
|
+
based on file extensions.
|
|
6
|
+
"""
|
|
7
|
+
from typing import Dict, Optional, Set
|
|
8
|
+
|
|
9
|
+
# Set of file extensions considered to be source code
|
|
10
|
+
# Each extension should be listed without the dot (e.g., 'py' not '.py')
|
|
11
|
+
SOURCE_CODE_EXTENSIONS: Set[str] = {
|
|
12
|
+
# Python
|
|
13
|
+
'py', 'pyx', 'pyi', 'pyw',
|
|
14
|
+
|
|
15
|
+
# JavaScript and TypeScript
|
|
16
|
+
'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs',
|
|
17
|
+
|
|
18
|
+
# Web
|
|
19
|
+
'html', 'htm', 'xhtml', 'css', 'scss', 'sass', 'less',
|
|
20
|
+
|
|
21
|
+
# C and C++
|
|
22
|
+
'c', 'h', 'cpp', 'cxx', 'cc', 'hpp', 'hxx', 'hh', 'inl',
|
|
23
|
+
|
|
24
|
+
# C#
|
|
25
|
+
'cs', 'csx',
|
|
26
|
+
|
|
27
|
+
# Java
|
|
28
|
+
'java', 'scala', 'kt', 'kts', 'groovy',
|
|
29
|
+
|
|
30
|
+
# Go
|
|
31
|
+
'go', 'mod',
|
|
32
|
+
|
|
33
|
+
# Rust
|
|
34
|
+
'rs', 'rlib',
|
|
35
|
+
|
|
36
|
+
# Swift
|
|
37
|
+
'swift',
|
|
38
|
+
|
|
39
|
+
# Ruby
|
|
40
|
+
'rb', 'rake', 'gemspec',
|
|
41
|
+
|
|
42
|
+
# PHP
|
|
43
|
+
'php', 'phtml', 'phar', 'phps',
|
|
44
|
+
|
|
45
|
+
# Shell
|
|
46
|
+
'sh', 'bash', 'zsh', 'fish',
|
|
47
|
+
|
|
48
|
+
# PowerShell
|
|
49
|
+
'ps1', 'psm1', 'psd1',
|
|
50
|
+
|
|
51
|
+
# SQL
|
|
52
|
+
'sql', 'ddl', 'dml',
|
|
53
|
+
|
|
54
|
+
# Markup and config
|
|
55
|
+
'xml', 'json', 'yaml', 'yml', 'toml', 'ini', 'cfg', 'conf',
|
|
56
|
+
|
|
57
|
+
# Documentation
|
|
58
|
+
'md', 'markdown', 'rst', 'adoc', 'tex',
|
|
59
|
+
|
|
60
|
+
# Build and dependency files
|
|
61
|
+
'Makefile', 'Dockerfile', 'Jenkinsfile',
|
|
62
|
+
|
|
63
|
+
# Haskell
|
|
64
|
+
'hs', 'lhs',
|
|
65
|
+
|
|
66
|
+
# Lisp family
|
|
67
|
+
'lisp', 'cl', 'el', 'clj', 'cljs', 'edn', 'scm',
|
|
68
|
+
|
|
69
|
+
# Erlang and Elixir
|
|
70
|
+
'erl', 'hrl', 'ex', 'exs',
|
|
71
|
+
|
|
72
|
+
# Dart and Flutter
|
|
73
|
+
'dart',
|
|
74
|
+
|
|
75
|
+
# Objective-C
|
|
76
|
+
'm', 'mm',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Context length limits based on file type (in tokens)
|
|
80
|
+
CONTEXT_LENGTH_LIMITS: Dict[str, int] = {
|
|
81
|
+
'source_code': 24000, # For known source code files
|
|
82
|
+
'default': 8000, # For all other files
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
def is_source_code_file(filename: str) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
Determine if a file is a source code file based on its extension.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
filename: The name of the file to check
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
True if the file has a recognized source code extension, False otherwise
|
|
94
|
+
"""
|
|
95
|
+
# Extract extension (without the dot)
|
|
96
|
+
parts = filename.split('.')
|
|
97
|
+
if len(parts) > 1:
|
|
98
|
+
ext = parts[-1].lower()
|
|
99
|
+
return ext in SOURCE_CODE_EXTENSIONS
|
|
100
|
+
|
|
101
|
+
# Files without extensions (like 'Makefile', 'Dockerfile')
|
|
102
|
+
# Case-insensitive match for files without extensions
|
|
103
|
+
return filename.lower() in {ext.lower() for ext in SOURCE_CODE_EXTENSIONS}
|
|
104
|
+
|
|
105
|
+
def get_context_length_for_file(filename: str) -> int:
|
|
106
|
+
"""
|
|
107
|
+
Get the appropriate context length limit for a file based on its extension.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
filename: The name of the file to check
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
The context length limit in tokens
|
|
114
|
+
"""
|
|
115
|
+
if is_source_code_file(filename):
|
|
116
|
+
return CONTEXT_LENGTH_LIMITS['source_code']
|
|
117
|
+
return CONTEXT_LENGTH_LIMITS['default']
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def select_max_tokens(filename: str, coding_max_tokens: Optional[int], noncoding_max_tokens: Optional[int]) -> Optional[int]:
|
|
121
|
+
"""
|
|
122
|
+
Select the appropriate max_tokens limit based on file type.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
filename: The name of the file to check
|
|
126
|
+
coding_max_tokens: Maximum tokens for source code files
|
|
127
|
+
noncoding_max_tokens: Maximum tokens for non-source code files
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
The appropriate max_tokens limit for the file
|
|
131
|
+
"""
|
|
132
|
+
if coding_max_tokens is None and noncoding_max_tokens is None:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
if is_source_code_file(filename):
|
|
136
|
+
return coding_max_tokens
|
|
137
|
+
return noncoding_max_tokens
|
|
@@ -155,7 +155,7 @@ def edit_with_individual_fallback(
|
|
|
155
155
|
original_lines: list[str], search_replace_blocks: list[tuple[list[str], list[str]]]
|
|
156
156
|
) -> tuple[list[str], set[str]]:
|
|
157
157
|
outputs = FileEditInput(original_lines, 0, search_replace_blocks, 0).edit_file()
|
|
158
|
-
best_matches
|
|
158
|
+
best_matches = FileEditOutput.get_best_match(outputs)
|
|
159
159
|
|
|
160
160
|
try:
|
|
161
161
|
edited_content, comments_ = best_matches[0].replace_or_throw(3)
|
|
@@ -171,7 +171,6 @@ def edit_with_individual_fallback(
|
|
|
171
171
|
all_comments |= comments_
|
|
172
172
|
return running_lines, all_comments
|
|
173
173
|
raise
|
|
174
|
-
assert not is_error
|
|
175
174
|
|
|
176
175
|
if len(best_matches) > 1:
|
|
177
176
|
# Find the first block that differs across matches
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Optional
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from mcp_wcgw.types import Tool as ToolParam
|
|
6
|
+
import mcp.server.stdio
|
|
7
|
+
import mcp.types as types
|
|
8
|
+
from mcp.server import NotificationOptions, Server
|
|
9
|
+
from mcp.server.models import InitializationOptions
|
|
11
10
|
from pydantic import AnyUrl
|
|
12
11
|
|
|
13
12
|
from wcgw.client.modes import KTS
|
|
@@ -25,7 +24,7 @@ from ..tools import (
|
|
|
25
24
|
which_tool_name,
|
|
26
25
|
)
|
|
27
26
|
|
|
28
|
-
server = Server("wcgw")
|
|
27
|
+
server: Server[Any] = Server("wcgw")
|
|
29
28
|
|
|
30
29
|
# Log only time stamp
|
|
31
30
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s: %(message)s")
|
|
@@ -89,15 +88,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
|
89
88
|
Each tool specifies its arguments using JSON Schema validation.
|
|
90
89
|
"""
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
ToolParam(
|
|
94
|
-
inputSchema=tool.inputSchema,
|
|
95
|
-
name=tool.name,
|
|
96
|
-
description=tool.description,
|
|
97
|
-
)
|
|
98
|
-
for tool in TOOL_PROMPTS
|
|
99
|
-
]
|
|
100
|
-
return tools_
|
|
91
|
+
return TOOL_PROMPTS
|
|
101
92
|
|
|
102
93
|
|
|
103
94
|
@server.call_tool() # type: ignore
|
|
@@ -119,7 +110,8 @@ async def handle_call_tool(
|
|
|
119
110
|
default_enc,
|
|
120
111
|
0.0,
|
|
121
112
|
lambda x, y: ("", 0),
|
|
122
|
-
|
|
113
|
+
24000, # coding_max_tokens
|
|
114
|
+
8000, # noncoding_max_tokens
|
|
123
115
|
)
|
|
124
116
|
|
|
125
117
|
except Exception as e:
|
|
@@ -165,7 +157,7 @@ async def main() -> None:
|
|
|
165
157
|
) as BASH_STATE:
|
|
166
158
|
BASH_STATE.console.log("wcgw version: " + version)
|
|
167
159
|
# Run the server using stdin/stdout streams
|
|
168
|
-
async with
|
|
160
|
+
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
|
|
169
161
|
await server.run(
|
|
170
162
|
read_stream,
|
|
171
163
|
write_stream,
|
|
@@ -64,7 +64,8 @@ T = TypeVar("T")
|
|
|
64
64
|
|
|
65
65
|
def load_memory(
|
|
66
66
|
task_id: str,
|
|
67
|
-
|
|
67
|
+
coding_max_tokens: Optional[int],
|
|
68
|
+
noncoding_max_tokens: Optional[int],
|
|
68
69
|
encoder: Callable[[str], list[T]],
|
|
69
70
|
decoder: Callable[[list[T]], str],
|
|
70
71
|
) -> tuple[str, str, Optional[dict[str, Any]]]:
|
|
@@ -75,6 +76,8 @@ def load_memory(
|
|
|
75
76
|
with open(memory_file, "r") as f:
|
|
76
77
|
data = f.read()
|
|
77
78
|
|
|
79
|
+
# Memory files are considered non-code files for token limits
|
|
80
|
+
max_tokens = noncoding_max_tokens
|
|
78
81
|
if max_tokens:
|
|
79
82
|
toks = encoder(data)
|
|
80
83
|
if len(toks) > max_tokens:
|
|
@@ -15,7 +15,7 @@ class DirectoryTree:
|
|
|
15
15
|
self.root = root
|
|
16
16
|
self.max_files = max_files
|
|
17
17
|
self.expanded_files: Set[Path] = set()
|
|
18
|
-
self.expanded_dirs = set
|
|
18
|
+
self.expanded_dirs: Set[Path] = set()
|
|
19
19
|
|
|
20
20
|
if not self.root.exists():
|
|
21
21
|
raise ValueError(f"Root path {root} does not exist")
|
|
@@ -77,11 +77,11 @@ class DirectoryTree:
|
|
|
77
77
|
def _display_recursive(
|
|
78
78
|
current_path: Path, indent: int = 0, depth: int = 0
|
|
79
79
|
) -> None:
|
|
80
|
-
# Print current directory name
|
|
80
|
+
# Print current directory name with a trailing slash for directories
|
|
81
81
|
if current_path == self.root:
|
|
82
|
-
writer.write(f"{current_path}
|
|
82
|
+
writer.write(f"{current_path}/\n")
|
|
83
83
|
else:
|
|
84
|
-
writer.write(f"{' ' * indent}{current_path.name}
|
|
84
|
+
writer.write(f"{' ' * indent}{current_path.name}/\n")
|
|
85
85
|
|
|
86
86
|
# Don't recurse beyond depth 1 unless path contains expanded files
|
|
87
87
|
if depth > 0 and current_path not in self.expanded_dirs:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
-
|
|
3
|
-
from
|
|
2
|
+
|
|
3
|
+
from mcp.types import Tool, ToolAnnotations
|
|
4
4
|
|
|
5
5
|
from ..types_ import (
|
|
6
6
|
BashCommand,
|
|
@@ -15,15 +15,8 @@ with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f
|
|
|
15
15
|
diffinstructions = f.read()
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
@dataclass
|
|
19
|
-
class Prompts:
|
|
20
|
-
inputSchema: dict[str, Any]
|
|
21
|
-
name: str
|
|
22
|
-
description: str
|
|
23
|
-
|
|
24
|
-
|
|
25
18
|
TOOL_PROMPTS = [
|
|
26
|
-
|
|
19
|
+
Tool(
|
|
27
20
|
inputSchema=Initialize.model_json_schema(),
|
|
28
21
|
name="Initialize",
|
|
29
22
|
description="""
|
|
@@ -38,8 +31,9 @@ TOOL_PROMPTS = [
|
|
|
38
31
|
- Use type="reset_shell" if in a conversation shell is not working after multiple tries.
|
|
39
32
|
- Use type="user_asked_change_workspace" if in a conversation user asked to change workspace
|
|
40
33
|
""",
|
|
34
|
+
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
41
35
|
),
|
|
42
|
-
|
|
36
|
+
Tool(
|
|
43
37
|
inputSchema=BashCommand.model_json_schema(),
|
|
44
38
|
name="BashCommand",
|
|
45
39
|
description="""
|
|
@@ -54,8 +48,9 @@ TOOL_PROMPTS = [
|
|
|
54
48
|
- Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again.
|
|
55
49
|
- Do not send Ctrl-c before checking for status till 10 minutes or whatever is appropriate for the program to finish.
|
|
56
50
|
""",
|
|
51
|
+
annotations=ToolAnnotations(destructiveHint=True, openWorldHint=True),
|
|
57
52
|
),
|
|
58
|
-
|
|
53
|
+
Tool(
|
|
59
54
|
inputSchema=ReadFiles.model_json_schema(),
|
|
60
55
|
name="ReadFiles",
|
|
61
56
|
description="""
|
|
@@ -65,13 +60,15 @@ TOOL_PROMPTS = [
|
|
|
65
60
|
- You may populate "show_line_numbers_reason" with your reason, by default null/empty means no line numbers are shown.
|
|
66
61
|
- You may extract a range of lines. E.g., `/path/to/file:1-10` for lines 1-10. You can drop start or end like `/path/to/file:1-` or `/path/to/file:-10`
|
|
67
62
|
""",
|
|
63
|
+
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
68
64
|
),
|
|
69
|
-
|
|
65
|
+
Tool(
|
|
70
66
|
inputSchema=ReadImage.model_json_schema(),
|
|
71
67
|
name="ReadImage",
|
|
72
68
|
description="Read an image from the shell.",
|
|
69
|
+
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
73
70
|
),
|
|
74
|
-
|
|
71
|
+
Tool(
|
|
75
72
|
inputSchema=FileWriteOrEdit.model_json_schema(),
|
|
76
73
|
name="FileWriteOrEdit",
|
|
77
74
|
description="""
|
|
@@ -85,13 +82,17 @@ TOOL_PROMPTS = [
|
|
|
85
82
|
|
|
86
83
|
"""
|
|
87
84
|
+ diffinstructions,
|
|
85
|
+
annotations=ToolAnnotations(
|
|
86
|
+
destructiveHint=True, idempotentHint=True, openWorldHint=False
|
|
87
|
+
),
|
|
88
88
|
),
|
|
89
|
-
|
|
89
|
+
Tool(
|
|
90
90
|
inputSchema=ContextSave.model_json_schema(),
|
|
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
94
|
- Provide random 3 word unqiue id or whatever user provided.
|
|
95
95
|
- Leave project path as empty string if no project path""",
|
|
96
|
+
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
96
97
|
),
|
|
97
98
|
]
|