wcgw 5.4.0__tar.gz → 5.4.2__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.4.0 → wcgw-5.4.2}/Dockerfile +3 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/PKG-INFO +1 -1
- {wcgw-5.4.0 → wcgw-5.4.2}/pyproject.toml +1 -1
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/diff-instructions.txt +1 -2
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/mcp_server/__init__.py +15 -2
- wcgw-5.4.2/src/wcgw/client/schema_generator.py +63 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/tool_prompts.py +7 -6
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/tools.py +8 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/types_.py +4 -2
- {wcgw-5.4.0 → wcgw-5.4.2}/uv.lock +1 -1
- {wcgw-5.4.0 → wcgw-5.4.2}/.github/workflows/python-publish.yml +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.github/workflows/python-tests.yml +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.github/workflows/python-types.yml +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.gitignore +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.gitmodules +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.python-version +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/.vscode/settings.json +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/CLAUDE.md +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/LICENSE +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/README.md +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/__init__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/__init__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/bash_state/bash_state.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/common.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/encoder/__init__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/file_ops/diff_edit.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/file_ops/extensions.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/file_ops/search_replace.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/mcp_server/server.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/memory.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/modes.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/display_tree.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/file_stats.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/path_prob.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/client/repo_ops/repo_context.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw/py.typed +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/__init__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/__main__.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/anthropic_client.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/cli.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/openai_client.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/src/wcgw_cli/openai_utils.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/claude-ss.jpg +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/computer-use.jpg +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/example.jpg +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/rocket-icon.png +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/ss1.png +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/static/workflow-demo.gif +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_bash_parser.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_bash_parser_complex.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_edit.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_file_range_tracking.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_mcp_server.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_readfiles.py +0 -0
- {wcgw-5.4.0 → wcgw-5.4.2}/tests/test_tools.py +0 -0
|
@@ -35,6 +35,9 @@ FROM python:3.12-slim-bookworm
|
|
|
35
35
|
|
|
36
36
|
RUN apt-get update && apt-get install -y screen && rm -rf /var/lib/apt/lists/*
|
|
37
37
|
|
|
38
|
+
# Create app user and group
|
|
39
|
+
RUN groupadd -r app && useradd -r -g app app
|
|
40
|
+
|
|
38
41
|
# Set the working directory in the container
|
|
39
42
|
WORKDIR /workspace
|
|
40
43
|
|
|
@@ -61,8 +61,7 @@ def call_hello_renamed():
|
|
|
61
61
|
# *SEARCH/REPLACE block* Rules:
|
|
62
62
|
|
|
63
63
|
- Every "SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, whitespaces, etc.
|
|
64
|
-
-
|
|
65
|
-
- An edit block can't edit over a previous edit in the same tool call.
|
|
64
|
+
- Use multiple search/replace blocks in a single FileWriteOrEdit tool call to edit in a single file in multiple places from top to bottom (separate calls are slower).
|
|
66
65
|
- Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
|
67
66
|
- Include enough and only enough lines in each SEARCH section to uniquely match each set of lines that need to change.
|
|
68
67
|
- Keep *SEARCH/REPLACE* blocks concise.
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
# mypy: disable-error-code="import-untyped"
|
|
2
|
-
from wcgw.client.mcp_server import server
|
|
3
2
|
import asyncio
|
|
3
|
+
import importlib
|
|
4
|
+
|
|
5
|
+
import typer
|
|
4
6
|
from typer import Typer
|
|
5
7
|
|
|
8
|
+
from wcgw.client.mcp_server import server
|
|
9
|
+
|
|
6
10
|
main = Typer()
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
@main.command()
|
|
10
|
-
def app(
|
|
14
|
+
def app(
|
|
15
|
+
version: bool = typer.Option(
|
|
16
|
+
False, "--version", "-v", help="Show version and exit"
|
|
17
|
+
),
|
|
18
|
+
) -> None:
|
|
11
19
|
"""Main entry point for the package."""
|
|
20
|
+
if version:
|
|
21
|
+
version_ = importlib.metadata.version("wcgw")
|
|
22
|
+
print(f"wcgw version: {version_}")
|
|
23
|
+
raise typer.Exit()
|
|
24
|
+
|
|
12
25
|
asyncio.run(server.main())
|
|
13
26
|
|
|
14
27
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom JSON schema generator to remove title fields from Pydantic models.
|
|
3
|
+
|
|
4
|
+
This module provides utilities to remove auto-generated title fields from JSON schemas,
|
|
5
|
+
making them more suitable for tool schemas where titles are not needed.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def recursive_purge_dict_key(d: Dict[str, Any], k: str) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Remove a key from a dictionary recursively, but only from JSON schema metadata.
|
|
15
|
+
|
|
16
|
+
This function removes the specified key from dictionaries that appear to be
|
|
17
|
+
JSON schema objects (have "type" or "$ref" or are property definitions).
|
|
18
|
+
This prevents removing legitimate data fields that happen to have the same name.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
d: The dictionary to clean
|
|
22
|
+
k: The key to remove (typically "title")
|
|
23
|
+
"""
|
|
24
|
+
if isinstance(d, dict):
|
|
25
|
+
# Only remove the key if this looks like a JSON schema object
|
|
26
|
+
# This includes objects with "type", "$ref", or if we're in a "properties" context
|
|
27
|
+
is_schema_object = (
|
|
28
|
+
"type" in d or
|
|
29
|
+
"$ref" in d or
|
|
30
|
+
any(schema_key in d for schema_key in ["properties", "items", "additionalProperties", "enum", "const", "anyOf", "allOf", "oneOf"])
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if is_schema_object and k in d:
|
|
34
|
+
del d[k]
|
|
35
|
+
|
|
36
|
+
# Recursively process all values, regardless of key names
|
|
37
|
+
# This ensures we catch all nested structures
|
|
38
|
+
for key, value in d.items():
|
|
39
|
+
if isinstance(value, dict):
|
|
40
|
+
recursive_purge_dict_key(value, k)
|
|
41
|
+
elif isinstance(value, list):
|
|
42
|
+
for item in value:
|
|
43
|
+
if isinstance(item, dict):
|
|
44
|
+
recursive_purge_dict_key(item, k)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def remove_titles_from_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
48
|
+
"""
|
|
49
|
+
Remove all 'title' keys from a JSON schema dictionary.
|
|
50
|
+
|
|
51
|
+
This function creates a copy of the schema and removes all title keys
|
|
52
|
+
recursively, making it suitable for use with APIs that don't need titles.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
schema: The JSON schema dictionary to clean
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
A new dictionary with all title keys removed
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
schema_copy = copy.deepcopy(schema)
|
|
62
|
+
recursive_purge_dict_key(schema_copy, "title")
|
|
63
|
+
return schema_copy
|
|
@@ -10,6 +10,7 @@ from ..types_ import (
|
|
|
10
10
|
ReadFiles,
|
|
11
11
|
ReadImage,
|
|
12
12
|
)
|
|
13
|
+
from .schema_generator import remove_titles_from_schema
|
|
13
14
|
|
|
14
15
|
with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f:
|
|
15
16
|
diffinstructions = f.read()
|
|
@@ -17,7 +18,7 @@ with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f
|
|
|
17
18
|
|
|
18
19
|
TOOL_PROMPTS = [
|
|
19
20
|
Tool(
|
|
20
|
-
inputSchema=Initialize.model_json_schema(),
|
|
21
|
+
inputSchema=remove_titles_from_schema(Initialize.model_json_schema()),
|
|
21
22
|
name="Initialize",
|
|
22
23
|
description="""
|
|
23
24
|
- Always call this at the start of the conversation before using any of the shell tools from wcgw.
|
|
@@ -34,7 +35,7 @@ TOOL_PROMPTS = [
|
|
|
34
35
|
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
35
36
|
),
|
|
36
37
|
Tool(
|
|
37
|
-
inputSchema=BashCommand.model_json_schema(),
|
|
38
|
+
inputSchema=remove_titles_from_schema(BashCommand.model_json_schema()),
|
|
38
39
|
name="BashCommand",
|
|
39
40
|
description="""
|
|
40
41
|
- Execute a bash command. This is stateful (beware with subsequent calls).
|
|
@@ -51,7 +52,7 @@ TOOL_PROMPTS = [
|
|
|
51
52
|
annotations=ToolAnnotations(destructiveHint=True, openWorldHint=True),
|
|
52
53
|
),
|
|
53
54
|
Tool(
|
|
54
|
-
inputSchema=ReadFiles.model_json_schema(),
|
|
55
|
+
inputSchema=remove_titles_from_schema(ReadFiles.model_json_schema()),
|
|
55
56
|
name="ReadFiles",
|
|
56
57
|
description="""
|
|
57
58
|
- Read full file content of one or more files.
|
|
@@ -62,13 +63,13 @@ TOOL_PROMPTS = [
|
|
|
62
63
|
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
63
64
|
),
|
|
64
65
|
Tool(
|
|
65
|
-
inputSchema=ReadImage.model_json_schema(),
|
|
66
|
+
inputSchema=remove_titles_from_schema(ReadImage.model_json_schema()),
|
|
66
67
|
name="ReadImage",
|
|
67
68
|
description="Read an image from the shell.",
|
|
68
69
|
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=False),
|
|
69
70
|
),
|
|
70
71
|
Tool(
|
|
71
|
-
inputSchema=FileWriteOrEdit.model_json_schema(),
|
|
72
|
+
inputSchema=remove_titles_from_schema(FileWriteOrEdit.model_json_schema()),
|
|
72
73
|
name="FileWriteOrEdit",
|
|
73
74
|
description="""
|
|
74
75
|
- Writes or edits a file based on the percentage of changes.
|
|
@@ -84,7 +85,7 @@ TOOL_PROMPTS = [
|
|
|
84
85
|
),
|
|
85
86
|
),
|
|
86
87
|
Tool(
|
|
87
|
-
inputSchema=ContextSave.model_json_schema(),
|
|
88
|
+
inputSchema=remove_titles_from_schema(ContextSave.model_json_schema()),
|
|
88
89
|
name="ContextSave",
|
|
89
90
|
description="""
|
|
90
91
|
Saves provided description and file contents of all the relevant file paths or globs in a single text file.
|
|
@@ -6,6 +6,7 @@ import mimetypes
|
|
|
6
6
|
import os
|
|
7
7
|
import subprocess
|
|
8
8
|
import traceback
|
|
9
|
+
import uuid
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from hashlib import sha256
|
|
11
12
|
from os.path import expanduser
|
|
@@ -34,6 +35,7 @@ from ..client.bash_state.bash_state import (
|
|
|
34
35
|
execute_bash,
|
|
35
36
|
generate_thread_id,
|
|
36
37
|
get_status,
|
|
38
|
+
get_tmpdir,
|
|
37
39
|
)
|
|
38
40
|
from ..client.repo_ops.file_stats import (
|
|
39
41
|
FileStats,
|
|
@@ -153,6 +155,12 @@ def initialize(
|
|
|
153
155
|
)
|
|
154
156
|
|
|
155
157
|
folder_to_start = None
|
|
158
|
+
if type == "first_call" and not any_workspace_path:
|
|
159
|
+
tmp_dir = get_tmpdir()
|
|
160
|
+
any_workspace_path = os.path.join(
|
|
161
|
+
tmp_dir, "claude-playground-" + uuid.uuid4().hex[:4]
|
|
162
|
+
)
|
|
163
|
+
|
|
156
164
|
if any_workspace_path:
|
|
157
165
|
if os.path.exists(any_workspace_path):
|
|
158
166
|
if os.path.isfile(any_workspace_path):
|
|
@@ -49,7 +49,9 @@ class Initialize(BaseModel):
|
|
|
49
49
|
"reset_shell",
|
|
50
50
|
"user_asked_change_workspace",
|
|
51
51
|
]
|
|
52
|
-
any_workspace_path: str
|
|
52
|
+
any_workspace_path: str = Field(
|
|
53
|
+
description="Workspce to initialise in. Don't use ~ by default, instead use empty string"
|
|
54
|
+
)
|
|
53
55
|
initial_files_to_read: list[str]
|
|
54
56
|
task_id_to_resume: str
|
|
55
57
|
mode_name: Literal["wcgw", "architect", "code_writer"]
|
|
@@ -87,7 +89,7 @@ class Command(BaseModel):
|
|
|
87
89
|
|
|
88
90
|
|
|
89
91
|
class StatusCheck(BaseModel):
|
|
90
|
-
status_check: Literal[True]
|
|
92
|
+
status_check: Literal[True] = True
|
|
91
93
|
type: Literal["status_check"] = "status_check"
|
|
92
94
|
|
|
93
95
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|