wcgw 5.3.2__tar.gz → 5.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wcgw might be problematic. Click here for more details.

Files changed (59) hide show
  1. {wcgw-5.3.2 → wcgw-5.4.0}/PKG-INFO +1 -1
  2. {wcgw-5.3.2 → wcgw-5.4.0}/pyproject.toml +1 -1
  3. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/bash_state/bash_state.py +1 -1
  4. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/mcp_server/server.py +13 -2
  5. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/tools.py +1 -11
  6. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/types_.py +36 -0
  7. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_mcp_server.py +9 -7
  8. {wcgw-5.3.2 → wcgw-5.4.0}/uv.lock +1 -1
  9. {wcgw-5.3.2 → wcgw-5.4.0}/.github/workflows/python-publish.yml +0 -0
  10. {wcgw-5.3.2 → wcgw-5.4.0}/.github/workflows/python-tests.yml +0 -0
  11. {wcgw-5.3.2 → wcgw-5.4.0}/.github/workflows/python-types.yml +0 -0
  12. {wcgw-5.3.2 → wcgw-5.4.0}/.gitignore +0 -0
  13. {wcgw-5.3.2 → wcgw-5.4.0}/.gitmodules +0 -0
  14. {wcgw-5.3.2 → wcgw-5.4.0}/.python-version +0 -0
  15. {wcgw-5.3.2 → wcgw-5.4.0}/.vscode/settings.json +0 -0
  16. {wcgw-5.3.2 → wcgw-5.4.0}/CLAUDE.md +0 -0
  17. {wcgw-5.3.2 → wcgw-5.4.0}/Dockerfile +0 -0
  18. {wcgw-5.3.2 → wcgw-5.4.0}/LICENSE +0 -0
  19. {wcgw-5.3.2 → wcgw-5.4.0}/README.md +0 -0
  20. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/__init__.py +0 -0
  21. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/__init__.py +0 -0
  22. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/bash_state/parser/__init__.py +0 -0
  23. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/bash_state/parser/bash_statement_parser.py +0 -0
  24. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/common.py +0 -0
  25. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/diff-instructions.txt +0 -0
  26. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/encoder/__init__.py +0 -0
  27. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/file_ops/diff_edit.py +0 -0
  28. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/file_ops/extensions.py +0 -0
  29. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/file_ops/search_replace.py +0 -0
  30. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/mcp_server/Readme.md +0 -0
  31. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/mcp_server/__init__.py +0 -0
  32. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/memory.py +0 -0
  33. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/modes.py +0 -0
  34. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/display_tree.py +0 -0
  35. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/file_stats.py +0 -0
  36. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/path_prob.py +0 -0
  37. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
  38. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
  39. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/repo_ops/repo_context.py +0 -0
  40. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/client/tool_prompts.py +0 -0
  41. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw/py.typed +0 -0
  42. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/__init__.py +0 -0
  43. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/__main__.py +0 -0
  44. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/anthropic_client.py +0 -0
  45. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/cli.py +0 -0
  46. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/openai_client.py +0 -0
  47. {wcgw-5.3.2 → wcgw-5.4.0}/src/wcgw_cli/openai_utils.py +0 -0
  48. {wcgw-5.3.2 → wcgw-5.4.0}/static/claude-ss.jpg +0 -0
  49. {wcgw-5.3.2 → wcgw-5.4.0}/static/computer-use.jpg +0 -0
  50. {wcgw-5.3.2 → wcgw-5.4.0}/static/example.jpg +0 -0
  51. {wcgw-5.3.2 → wcgw-5.4.0}/static/rocket-icon.png +0 -0
  52. {wcgw-5.3.2 → wcgw-5.4.0}/static/ss1.png +0 -0
  53. {wcgw-5.3.2 → wcgw-5.4.0}/static/workflow-demo.gif +0 -0
  54. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_bash_parser.py +0 -0
  55. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_bash_parser_complex.py +0 -0
  56. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_edit.py +0 -0
  57. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_file_range_tracking.py +0 -0
  58. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_readfiles.py +0 -0
  59. {wcgw-5.3.2 → wcgw-5.4.0}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 5.3.2
3
+ Version: 5.4.0
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>
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
3
3
  name = "wcgw"
4
- version = "5.3.2"
4
+ version = "5.4.0"
5
5
  description = "Shell and coding agent for Claude and other mcp clients"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.11"
@@ -87,7 +87,7 @@ def check_if_screen_command_available() -> bool:
87
87
  ["which", "screen"], capture_output=True, check=True, timeout=0.2
88
88
  )
89
89
  return True
90
- except (subprocess.CalledProcessError, FileNotFoundError):
90
+ except (subprocess.CalledProcessError, FileNotFoundError, TimeoutError):
91
91
  return False
92
92
 
93
93
 
@@ -121,11 +121,18 @@ async def handle_call_tool(
121
121
  for output_or_done in output_or_dones:
122
122
  if isinstance(output_or_done, str):
123
123
  if issubclass(tool_type, Initialize):
124
- output_or_done += """
124
+ # Prepare the original hardcoded message
125
+ original_message = """
125
126
  - Additional important note: as soon as you encounter "The user has chosen to disallow the tool call.", immediately stop doing everything and ask user for the reason.
126
127
 
127
128
  Initialize call done.
128
129
  """
130
+
131
+ # If custom instructions exist, prepend them to the original message
132
+ if CUSTOM_INSTRUCTIONS:
133
+ output_or_done += f"\n{CUSTOM_INSTRUCTIONS}\n{original_message}"
134
+ else:
135
+ output_or_done += original_message
129
136
 
130
137
  content.append(types.TextContent(type="text", text=output_or_done))
131
138
  else:
@@ -141,12 +148,16 @@ Initialize call done.
141
148
 
142
149
 
143
150
  BASH_STATE = None
151
+ CUSTOM_INSTRUCTIONS = None
144
152
 
145
153
 
146
154
  async def main() -> None:
147
- global BASH_STATE
155
+ global BASH_STATE, CUSTOM_INSTRUCTIONS
148
156
  CONFIG.update(3, 55, 5)
149
157
  version = str(importlib.metadata.version("wcgw"))
158
+
159
+ # Read custom instructions from environment variable
160
+ CUSTOM_INSTRUCTIONS = os.getenv("WCGW_SERVER_INSTRUCTIONS")
150
161
 
151
162
  # starting_dir is inside tmp dir
152
163
  tmp_dir = get_tmpdir()
@@ -58,8 +58,6 @@ from ..types_ import (
58
58
  from .encoder import EncoderDecoder, get_default_encoder
59
59
  from .file_ops.extensions import select_max_tokens
60
60
  from .file_ops.search_replace import (
61
- DIVIDER_MARKER,
62
- REPLACE_MARKER,
63
61
  SEARCH_MARKER,
64
62
  search_replace_edit,
65
63
  )
@@ -819,16 +817,8 @@ def _is_edit(content: str, percentage: int) -> bool:
819
817
  if not lines:
820
818
  return False
821
819
  line = lines[0]
822
- if SEARCH_MARKER.match(line):
820
+ if SEARCH_MARKER.match(line) or (0 < percentage <= 50):
823
821
  return True
824
- if percentage <= 50:
825
- for line in lines:
826
- if (
827
- SEARCH_MARKER.match(line)
828
- or DIVIDER_MARKER.match(line)
829
- or REPLACE_MARKER.match(line)
830
- ):
831
- return True
832
822
  return False
833
823
 
834
824
 
@@ -83,14 +83,17 @@ class Initialize(BaseModel):
83
83
 
84
84
  class Command(BaseModel):
85
85
  command: str
86
+ type: Literal["command"] = "command"
86
87
 
87
88
 
88
89
  class StatusCheck(BaseModel):
89
90
  status_check: Literal[True]
91
+ type: Literal["status_check"] = "status_check"
90
92
 
91
93
 
92
94
  class SendText(BaseModel):
93
95
  send_text: str
96
+ type: Literal["send_text"] = "send_text"
94
97
 
95
98
 
96
99
  Specials = Literal[
@@ -100,10 +103,39 @@ Specials = Literal[
100
103
 
101
104
  class SendSpecials(BaseModel):
102
105
  send_specials: Sequence[Specials]
106
+ type: Literal["send_specials"] = "send_specials"
103
107
 
104
108
 
105
109
  class SendAscii(BaseModel):
106
110
  send_ascii: Sequence[int]
111
+ type: Literal["send_ascii"] = "send_ascii"
112
+
113
+
114
+ class ActionJsonSchema(BaseModel):
115
+ type: Literal[
116
+ "command", "status_check", "send_text", "send_specials", "send_ascii"
117
+ ] = Field(description="type of action.")
118
+ command: Optional[str] = Field(
119
+ default=None, description='Set only if type="command"'
120
+ )
121
+ status_check: Optional[Literal[True]] = Field(
122
+ default=None, description='Set only if type="status_check"'
123
+ )
124
+ send_text: Optional[str] = Field(
125
+ default=None, description='Set only if type="send_text"'
126
+ )
127
+ send_specials: Optional[Sequence[Specials]] = Field(
128
+ default=None, description='Set only if type="send_specials"'
129
+ )
130
+ send_ascii: Optional[Sequence[int]] = Field(
131
+ default=None, description='Set only if type="send_ascii"'
132
+ )
133
+
134
+
135
+ class BashCommandOverride(BaseModel):
136
+ action_json: ActionJsonSchema
137
+ wait_for_seconds: Optional[float] = None
138
+ thread_id: str
107
139
 
108
140
 
109
141
  class BashCommand(BaseModel):
@@ -111,6 +143,10 @@ class BashCommand(BaseModel):
111
143
  wait_for_seconds: Optional[float] = None
112
144
  thread_id: str
113
145
 
146
+ @staticmethod
147
+ def model_json_schema(*args, **kwargs) -> dict[str, Any]: # type: ignore
148
+ return BashCommandOverride.model_json_schema(*args, **kwargs)
149
+
114
150
 
115
151
  class ReadImage(BaseModel):
116
152
  file_path: str
@@ -142,14 +142,16 @@ async def test_handle_list_tools():
142
142
  assert "action_json" in properties
143
143
  assert "wait_for_seconds" in properties
144
144
  # Check type field has all the command types
145
- type_properties = properties["action_json"]["anyOf"]
146
- type_refs = set(p["$ref"].split("/")[-1] for p in type_properties)
145
+ type_properties = tool.inputSchema["$defs"]["ActionJsonSchema"][
146
+ "properties"
147
+ ]
148
+ type_refs = set(type_properties)
147
149
  required_types = {
148
- "Command",
149
- "StatusCheck",
150
- "SendText",
151
- "SendSpecials",
152
- "SendAscii",
150
+ "command",
151
+ "status_check",
152
+ "send_text",
153
+ "send_specials",
154
+ "send_ascii",
153
155
  }
154
156
  assert required_types.issubset(type_refs)
155
157
  elif tool.name == "FileWriteOrEdit":
@@ -1398,7 +1398,7 @@ wheels = [
1398
1398
 
1399
1399
  [[package]]
1400
1400
  name = "wcgw"
1401
- version = "5.3.1"
1401
+ version = "5.4.0"
1402
1402
  source = { editable = "." }
1403
1403
  dependencies = [
1404
1404
  { name = "anthropic" },
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