wcgw 5.3.1__py3-none-any.whl → 5.4.0__py3-none-any.whl

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.

@@ -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()
wcgw/client/tools.py CHANGED
@@ -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
  )
@@ -266,6 +264,13 @@ def initialize(
266
264
  # Check for global CLAUDE.md and workspace CLAUDE.md
267
265
  alignment_context = ""
268
266
 
267
+ # Check if ripgrep is available and add instruction if it is
268
+ try:
269
+ subprocess.run(["which", "rg"], timeout=1, capture_output=True, check=True)
270
+ alignment_context += "---\n# Available commands\n\n- Use ripgrep `rg` command instead of `grep` because it's much much faster.\n\n---\n\n"
271
+ except Exception:
272
+ pass
273
+
269
274
  # First check for global CLAUDE.md in ~/.wcgw/CLAUDE.md
270
275
  global_alignment_file_path = os.path.join(expanduser("~"), ".wcgw", "CLAUDE.md")
271
276
  if os.path.exists(global_alignment_file_path):
@@ -812,16 +817,8 @@ def _is_edit(content: str, percentage: int) -> bool:
812
817
  if not lines:
813
818
  return False
814
819
  line = lines[0]
815
- if SEARCH_MARKER.match(line):
820
+ if SEARCH_MARKER.match(line) or (0 < percentage <= 50):
816
821
  return True
817
- if percentage <= 50:
818
- for line in lines:
819
- if (
820
- SEARCH_MARKER.match(line)
821
- or DIVIDER_MARKER.match(line)
822
- or REPLACE_MARKER.match(line)
823
- ):
824
- return True
825
822
  return False
826
823
 
827
824
 
wcgw/types_.py CHANGED
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 5.3.1
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,14 +1,14 @@
1
1
  wcgw/__init__.py,sha256=JgAY25VsA208v8E7QTIU0E50nsk-TCJ4FWTEHmnssYU,127
2
2
  wcgw/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- wcgw/types_.py,sha256=9cK7ooTbGK3QaBNJCFZLnrezfpFUSNkA8S02JCHCl6c,8174
3
+ wcgw/types_.py,sha256=92uLRuW4CI8p7LJctW3WDuzVOYLsBmbjpjpzTqtwnQA,9487
4
4
  wcgw/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  wcgw/client/common.py,sha256=OCH7Tx64jojz3M3iONUrGMadE07W21DiZs5sOxWX1Qc,1456
6
6
  wcgw/client/diff-instructions.txt,sha256=a-UeK9VEHJlwffAzZ-I1OiUkeMOuGU8zj3By-_STy28,1866
7
7
  wcgw/client/memory.py,sha256=U2Nw2si3Zg7n_RhNAuaYcmrrDtZ_Mooi-kfAOKflT-I,3079
8
8
  wcgw/client/modes.py,sha256=roH6SPBokJMr5IzAlccdI-vJyvyS5vqSMMyth7TE86A,10315
9
9
  wcgw/client/tool_prompts.py,sha256=7tq9ijSo4CznVlMFcWpauELfCT_QAqwi8Chsl3SRfBY,4539
10
- wcgw/client/tools.py,sha256=YNxXmNj2-rhCPZ12wmfMBsAXn0_nQnCPs1OTudEh5wM,49026
11
- wcgw/client/bash_state/bash_state.py,sha256=b-Zo6pO3psfxu9TA0uw1ZZAa6bLmDPxbl7277fZfmrM,41862
10
+ wcgw/client/tools.py,sha256=WAVnSqisV4hw4mPhbCzDDZy2gFkxXwTfzAajLPciCSw,49107
11
+ wcgw/client/bash_state/bash_state.py,sha256=U-h9uqEcJbZGIVle6vZKYmlLHNO91zvqaUe6zlvLMl4,41876
12
12
  wcgw/client/bash_state/parser/__init__.py,sha256=AnlNSmoQTSoqqlLOLX4P1uXfzc5VGeCGJsGgtisq2zE,207
13
13
  wcgw/client/bash_state/parser/bash_statement_parser.py,sha256=9a8vPO1r3_tXmaAcubTQ5UY-NseWlalgm8LZA17LXuY,6058
14
14
  wcgw/client/encoder/__init__.py,sha256=Y-8f43I6gMssUCWpX5rLYiAFv3D-JPRs4uNEejPlke8,1514
@@ -17,7 +17,7 @@ wcgw/client/file_ops/extensions.py,sha256=CmfD7ON6SY24Prh2tRZdV9KbhuOrWqqk8qL1Vt
17
17
  wcgw/client/file_ops/search_replace.py,sha256=5LFg-_U_ijnNrkYei4SWCPGKPGgDzJs49EDsIBzLmuY,6822
18
18
  wcgw/client/mcp_server/Readme.md,sha256=2Z88jj1mf9daYGW1CWaldcJ0moy8owDumhR2glBY3A8,109
19
19
  wcgw/client/mcp_server/__init__.py,sha256=mm7xhBIPwJpRT3u-Qsj4cKVMpVyucJoKRlbMP_gRRB0,343
20
- wcgw/client/mcp_server/server.py,sha256=jjwrmZZ8X0tXD0rsPZ9fKjEpdXpXCfdhEsN3Ho_tC8I,4989
20
+ wcgw/client/mcp_server/server.py,sha256=RgsMDmNuYyg4VT1KorcLzh1Xfv49QASi0-FTLz_tlIo,5525
21
21
  wcgw/client/repo_ops/display_tree.py,sha256=g282qCKLCwo8O9NHUBnkG_NkIusroVzz3NZi8VIcmAI,4066
22
22
  wcgw/client/repo_ops/file_stats.py,sha256=AUA0Br7zFRpylWFYZPGMeGPJy3nWp9e2haKi34JptHE,4887
23
23
  wcgw/client/repo_ops/path_prob.py,sha256=SWf0CDn37rtlsYRQ51ufSxay-heaQoVIhr1alB9tZ4M,2144
@@ -30,8 +30,8 @@ wcgw_cli/anthropic_client.py,sha256=8bjDY59-aioyTJgpB-NBHZNhZaq6rqcTJcOf81kzCyA,
30
30
  wcgw_cli/cli.py,sha256=-7FBe_lahKyUOhf65iurTA1M1gXXXAiT0OVKQVcZKKo,948
31
31
  wcgw_cli/openai_client.py,sha256=GOqoSFazTV-cFjpdZGPM0DIwec8Up2TEcKUbsN40AGY,15990
32
32
  wcgw_cli/openai_utils.py,sha256=xGOb3W5ALrIozV7oszfGYztpj0FnXdD7jAxm5lEIVKY,2439
33
- wcgw-5.3.1.dist-info/METADATA,sha256=PPBEAE1xpGfRsX8I5nZuTKnQLIZnWBXzPc96CQtyhFs,15679
34
- wcgw-5.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
- wcgw-5.3.1.dist-info/entry_points.txt,sha256=UnjK-MAH4Qssh0tGJDMeij1oi-oRKokItkknP_BwShE,94
36
- wcgw-5.3.1.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
37
- wcgw-5.3.1.dist-info/RECORD,,
33
+ wcgw-5.4.0.dist-info/METADATA,sha256=-rpByDzouo2dElBlIvjO2r0lsWlXyRaF4xggMQXZK1A,15679
34
+ wcgw-5.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
+ wcgw-5.4.0.dist-info/entry_points.txt,sha256=UnjK-MAH4Qssh0tGJDMeij1oi-oRKokItkknP_BwShE,94
36
+ wcgw-5.4.0.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
37
+ wcgw-5.4.0.dist-info/RECORD,,
File without changes