wcgw 2.7.0__py3-none-any.whl → 2.7.1__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.

@@ -25,10 +25,10 @@ from typer import Typer
25
25
  from ..types_ import (
26
26
  BashCommand,
27
27
  BashInteraction,
28
+ ContextSave,
28
29
  FileEdit,
29
30
  GetScreenInfo,
30
31
  Keyboard,
31
- KnowledgeTransfer,
32
32
  Mouse,
33
33
  ReadFiles,
34
34
  ReadImage,
@@ -130,7 +130,12 @@ def loop(
130
130
  memory = None
131
131
  if resume:
132
132
  try:
133
- memory = load_memory(resume)
133
+ _, memory = load_memory(
134
+ resume,
135
+ 8000,
136
+ lambda x: default_enc.encode(x).ids,
137
+ lambda x: default_enc.decode(x),
138
+ )
134
139
  except OSError:
135
140
  if resume == "latest":
136
141
  resume_path = sorted(Path(".wcgw").iterdir(), key=os.path.getmtime)[-1]
@@ -215,22 +220,12 @@ def loop(
215
220
  """,
216
221
  ),
217
222
  ToolParam(
218
- input_schema=KnowledgeTransfer.model_json_schema(),
219
- name="KnowledgeTransfer",
223
+ input_schema=ContextSave.model_json_schema(),
224
+ name="ContextSave",
220
225
  description="""
221
- Write detailed description in order to do a KT, if the user asks for it.
222
- Save all information necessary for a person to understand the task and the problems.
223
-
224
- - `all_user_instructions` should contain all instructions user shared in the conversation.
225
- - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
226
- - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
227
- - Be very verbose in `all_issues_snippets` providing as much error context as possible.
228
- - Provide an id if the user hasn't provided one.
229
- - This tool will return a text file path where the information is saved.
230
- - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
231
- - Leave arguments as empty string if they aren't relevant.
232
- - This tool marks end of your conversation, do not run any further tools after calling this.
233
- - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
226
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
227
+ - Provide random unqiue id or whatever user provided.
228
+ - Leave project path as empty string if no project path
234
229
  """,
235
230
  ),
236
231
  ]
@@ -14,6 +14,7 @@ from mcp_wcgw.types import Tool as ToolParam
14
14
  from ...types_ import (
15
15
  BashCommand,
16
16
  BashInteraction,
17
+ ContextSave,
17
18
  FileEdit,
18
19
  GetScreenInfo,
19
20
  Initialize,
@@ -46,14 +47,47 @@ async def handle_read_resource(uri: AnyUrl) -> str:
46
47
 
47
48
  @server.list_prompts() # type: ignore
48
49
  async def handle_list_prompts() -> list[types.Prompt]:
49
- return []
50
+ return [
51
+ types.Prompt(
52
+ name="KnowledgeTransfer",
53
+ description="Prompt for invoking ContextSave tool in order to do a comprehensive knowledge transfer of a coding task. Prompts to save detailed error log and instructions.",
54
+ )
55
+ ]
50
56
 
51
57
 
52
58
  @server.get_prompt() # type: ignore
53
59
  async def handle_get_prompt(
54
60
  name: str, arguments: dict[str, str] | None
55
61
  ) -> types.GetPromptResult:
56
- return types.GetPromptResult(messages=[])
62
+ messages = []
63
+ if name == "KnowledgeTransfer":
64
+ messages = [
65
+ types.PromptMessage(
66
+ role="user",
67
+ content=types.TextContent(
68
+ type="text",
69
+ text="""Use `ContextSave` tool to do a knowledge transfer of the task in hand.
70
+ Write detailed description in order to do a KT.
71
+ Save all information necessary for a person to understand the task and the problems.
72
+
73
+ Format the `description` field using Markdown with the following sections.
74
+ - "# Objective" section containing project and task objective.
75
+ - "# All user instructions" section should be provided containing all instructions user shared in the conversation.
76
+ - "# Current status of the task" should be provided containing only what is already achieved, not what's remaining.
77
+ - "# All issues with snippets" section containing snippets of error, traceback, file snippets, commands, etc. But no comments or solutions.
78
+ - Be very verbose in the all issues with snippets section providing as much error context as possible.
79
+ - "# Build and development instructions" section containing instructions to build or run project or run tests, or envrionment related information. Only include what's known. Leave empty if unknown.
80
+ - After the tool completes succesfully, tell me the task id and the file path the tool generated (important!)
81
+ - This tool marks end of your conversation, do not run any further tools after calling this.
82
+
83
+ Provide all relevant file paths in order to understand and solve the the task. Err towards providing more file paths than fewer.
84
+
85
+ (Note to self: this conversation can then be resumed later asking "Resume `<generated id>`" which should call Initialize tool)
86
+ """,
87
+ ),
88
+ )
89
+ ]
90
+ return types.GetPromptResult(messages=messages)
57
91
 
58
92
 
59
93
  @server.list_tools() # type: ignore
@@ -153,24 +187,14 @@ async def handle_list_tools() -> list[types.Tool]:
153
187
  """
154
188
  + diffinstructions,
155
189
  ),
156
- # ToolParam(
157
- # inputSchema=KnowledgeTransfer.model_json_schema(),
158
- # name="KnowledgeTransfer",
159
- # description="""
160
- # Write detailed description in order to do a KT, if the user asks for it.
161
- # Save all information necessary for a person to understand the task and the problems.
162
- # - `all_user_instructions` should contain all instructions user shared in the conversation.
163
- # - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
164
- # - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
165
- # - Be very verbose in `all_issues_snippets` providing as much error context as possible.
166
- # - Provide an id if the user hasn't provided one.
167
- # - This tool will return a text file path where the information is saved.
168
- # - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
169
- # - Leave arguments as empty string if they aren't relevant.
170
- # - This tool marks end of your conversation, do not run any further tools after calling this.
171
- # - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
172
- # """,
173
- # ),
190
+ ToolParam(
191
+ inputSchema=ContextSave.model_json_schema(),
192
+ name="ContextSave",
193
+ description="""
194
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
195
+ - Provide random unqiue id or whatever user provided.
196
+ - Leave project path as empty string if no project path""",
197
+ ),
174
198
  ]
175
199
  if COMPUTER_USE_ON_DOCKER_ENABLED:
176
200
  tools += [
wcgw/client/memory.py CHANGED
@@ -1,6 +1,9 @@
1
1
  import os
2
+ import re
3
+ import shlex
4
+ from typing import Callable, Optional
2
5
 
3
- from ..types_ import KnowledgeTransfer
6
+ from ..types_ import ContextSave
4
7
 
5
8
 
6
9
  def get_app_dir_xdg() -> str:
@@ -8,19 +11,26 @@ def get_app_dir_xdg() -> str:
8
11
  return os.path.join(xdg_data_dir, "wcgw")
9
12
 
10
13
 
11
- def format_memory(task_memory: KnowledgeTransfer, relevant_files: str) -> str:
12
- memory_data = f"""# Goal: {task_memory.objective}\n\n
13
- # Instructions:\n{task_memory.all_user_instructions}\n\n
14
- # Current Status:\n{task_memory.current_status_of_the_task}\n\n
15
- # Pending Issues:\n{task_memory.all_issues_snippets}\n\n
16
- # Build Instructions:\n{task_memory.build_and_development_instructions}\n"""
14
+ def format_memory(task_memory: ContextSave, relevant_files: str) -> str:
15
+ memory_data = ""
16
+ if task_memory.project_root_path:
17
+ memory_data += (
18
+ f"# PROJECT ROOT = {shlex.quote(task_memory.project_root_path)}\n"
19
+ )
20
+ memory_data += task_memory.description
17
21
 
18
- memory_data += "\n# Relevant Files:\n" + relevant_files
22
+ memory_data += (
23
+ "\n\n"
24
+ + "# Relevant file paths\n"
25
+ + ", ".join(map(shlex.quote, task_memory.relevant_file_globs))
26
+ )
27
+
28
+ memory_data += "\n\n# Relevant Files:\n" + relevant_files
19
29
 
20
30
  return memory_data
21
31
 
22
32
 
23
- def save_memory(task_memory: KnowledgeTransfer, relevant_files: str) -> str:
33
+ def save_memory(task_memory: ContextSave, relevant_files: str) -> str:
24
34
  app_dir = get_app_dir_xdg()
25
35
  memory_dir = os.path.join(app_dir, "memory")
26
36
  os.makedirs(memory_dir, exist_ok=True)
@@ -30,23 +40,39 @@ def save_memory(task_memory: KnowledgeTransfer, relevant_files: str) -> str:
30
40
  raise Exception("Task id can not be empty")
31
41
  memory_data = format_memory(task_memory, relevant_files)
32
42
 
33
- memory_file = os.path.join(memory_dir, f"{task_id}.json")
34
43
  memory_file_full = os.path.join(memory_dir, f"{task_id}.txt")
35
44
 
36
45
  with open(memory_file_full, "w") as f:
37
46
  f.write(memory_data)
38
47
 
39
- with open(memory_file, "w") as f:
40
- f.write(task_memory.model_dump_json())
41
-
42
48
  return memory_file_full
43
49
 
44
50
 
45
- def load_memory(task_id: str) -> KnowledgeTransfer:
51
+ def load_memory[T](
52
+ task_id: str,
53
+ max_tokens: Optional[int],
54
+ encoder: Callable[[str], list[T]],
55
+ decoder: Callable[[list[T]], str],
56
+ ) -> tuple[str, str]:
46
57
  app_dir = get_app_dir_xdg()
47
58
  memory_dir = os.path.join(app_dir, "memory")
48
- memory_file = os.path.join(memory_dir, f"{task_id}.json")
59
+ memory_file = os.path.join(memory_dir, f"{task_id}.txt")
49
60
 
50
61
  with open(memory_file, "r") as f:
51
- task_save = KnowledgeTransfer.model_validate_json(f.read())
52
- return task_save
62
+ data = f.read()
63
+
64
+ if max_tokens:
65
+ toks = encoder(data)
66
+ if len(toks) > max_tokens:
67
+ toks = toks[: max(0, max_tokens - 10)]
68
+ data = decoder(toks)
69
+ data += "\n(... truncated)"
70
+
71
+ project_root_match = re.search(r"# PROJECT ROOT = \s*(.*?)\s*$", data, re.MULTILINE)
72
+ project_root_path = ""
73
+ if project_root_match:
74
+ matched_path = project_root_match.group(1)
75
+ parsed_ = shlex.split(matched_path)
76
+ if parsed_ and len(parsed_) == 1:
77
+ project_root_path = parsed_[0]
78
+ return project_root_path, data
@@ -26,8 +26,8 @@ from typer import Typer
26
26
  from ..types_ import (
27
27
  BashCommand,
28
28
  BashInteraction,
29
+ ContextSave,
29
30
  FileEdit,
30
- KnowledgeTransfer,
31
31
  ReadFiles,
32
32
  ReadImage,
33
33
  ResetShell,
@@ -39,6 +39,7 @@ from .openai_utils import get_input_cost, get_output_cost
39
39
  from .tools import (
40
40
  DoneFlag,
41
41
  ImageData,
42
+ default_enc,
42
43
  get_tool_output,
43
44
  initialize,
44
45
  which_tool,
@@ -124,7 +125,12 @@ def loop(
124
125
  memory = None
125
126
  if resume:
126
127
  try:
127
- memory = load_memory(resume)
128
+ _, memory = load_memory(
129
+ resume,
130
+ 8000,
131
+ lambda x: default_enc.encode(x).ids,
132
+ lambda x: default_enc.decode(x),
133
+ )
128
134
  except OSError:
129
135
  if resume == "latest":
130
136
  resume_path = sorted(Path(".wcgw").iterdir(), key=os.path.getmtime)[-1]
@@ -211,22 +217,12 @@ def loop(
211
217
  description="Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.",
212
218
  ),
213
219
  openai.pydantic_function_tool(
214
- KnowledgeTransfer,
220
+ ContextSave,
215
221
  description="""
216
- Write detailed description in order to do a KT, if the user asks for it.
217
- Save all information necessary for a person to understand the task and the problems.
218
-
219
- - `all_user_instructions` should contain all instructions user shared in the conversation.
220
- - `current_status_of_the_task` should contain only what is already achieved, not what's remaining.
221
- - `all_issues_snippets` should only contain snippets of error, traceback, file snippets, commands, etc., no comments or solutions (important!).
222
- - Be very verbose in `all_issues_snippets` providing as much error context as possible.
223
- - Provide an id if the user hasn't provided one.
224
- - This tool will return a text file path where the information is saved.
225
- - After the tool completes succesfully, tell the user the task id and the generate file path. (important!)
226
- - Leave arguments as empty string if they aren't relevant.
227
- - This tool marks end of your conversation, do not run any further tools after calling this.
228
- - Provide absolute file paths only in `relevant_file_paths` containing all relevant files.
229
- """,
222
+
223
+ Saves provided description and file contents of all the relevant file paths or globs in a single text file.
224
+ - Provide random unqiue id or whatever user provided.
225
+ - Leave project path as empty string if no project path""",
230
226
  ),
231
227
  ]
232
228
 
wcgw/client/tools.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import datetime
3
+ import glob
3
4
  import importlib.metadata
4
5
  import json
5
6
  import mimetypes
@@ -38,12 +39,12 @@ from websockets.sync.client import connect as syncconnect
38
39
  from ..types_ import (
39
40
  BashCommand,
40
41
  BashInteraction,
42
+ ContextSave,
41
43
  FileEdit,
42
44
  FileEditFindReplace,
43
45
  GetScreenInfo,
44
46
  Initialize,
45
47
  Keyboard,
46
- KnowledgeTransfer,
47
48
  Mouse,
48
49
  ReadFiles,
49
50
  ReadImage,
@@ -53,7 +54,7 @@ from ..types_ import (
53
54
  )
54
55
  from .computer_use import run_computer_tool
55
56
  from .file_ops.search_replace import search_replace_edit
56
- from .memory import format_memory, load_memory, save_memory
57
+ from .memory import load_memory, save_memory
57
58
  from .repo_ops.repo_context import get_repo_context
58
59
  from .sys_utils import command_run
59
60
 
@@ -307,16 +308,17 @@ def initialize(
307
308
  memory = ""
308
309
  if task_id_to_resume:
309
310
  try:
310
- task_mem = load_memory(task_id_to_resume)
311
- mem_files = task_mem.relevant_file_paths
312
- mem_files_read = read_files(mem_files, max_tokens)
313
- memory = "Following is the retrieved task:\n" + format_memory(
314
- task_mem, mem_files_read
311
+ project_root_path, task_mem = load_memory(
312
+ task_id_to_resume,
313
+ max_tokens,
314
+ lambda x: default_enc.encode(x).ids,
315
+ lambda x: default_enc.decode(x),
315
316
  )
317
+ memory = "Following is the retrieved task:\n" + task_mem
316
318
  if (
317
319
  not any_workspace_path or not os.path.exists(any_workspace_path)
318
- ) and os.path.exists(task_mem.project_root_path):
319
- any_workspace_path = task_mem.project_root_path
320
+ ) and os.path.exists(project_root_path):
321
+ any_workspace_path = project_root_path
320
322
  except Exception:
321
323
  memory = f'Error: Unable to load task with ID "{task_id_to_resume}" '
322
324
 
@@ -1003,7 +1005,7 @@ TOOLS = (
1003
1005
  | Keyboard
1004
1006
  | ScreenShot
1005
1007
  | GetScreenInfo
1006
- | KnowledgeTransfer
1008
+ | ContextSave
1007
1009
  )
1008
1010
 
1009
1011
 
@@ -1045,8 +1047,8 @@ def which_tool_name(name: str) -> Type[TOOLS]:
1045
1047
  return ScreenShot
1046
1048
  elif name == "GetScreenInfo":
1047
1049
  return GetScreenInfo
1048
- elif name == "KnowledgeTransfer":
1049
- return KnowledgeTransfer
1050
+ elif name == "ContextSave":
1051
+ return ContextSave
1050
1052
  else:
1051
1053
  raise ValueError(f"Unknown tool name: {name}")
1052
1054
 
@@ -1142,20 +1144,26 @@ def get_tool_output(
1142
1144
  )
1143
1145
  BASH_STATE.set_in_docker(arg.docker_image_id)
1144
1146
  return outputs, outputs_cost[1]
1145
- elif isinstance(arg, KnowledgeTransfer):
1147
+ elif isinstance(arg, ContextSave):
1146
1148
  console.print("Calling task memory tool")
1147
- relevant_files = arg.relevant_file_paths
1148
- for i, fpath in enumerate(relevant_files):
1149
- if not os.path.isabs(fpath):
1150
- relpath = os.path.join(arg.project_root_path, fpath)
1151
- if os.path.exists(relpath):
1152
- relevant_files[i] = relpath
1153
- else:
1154
- raise Exception(f"The file path {fpath} does not exist")
1155
- elif not os.path.exists(fpath):
1156
- raise Exception(f"The file path {fpath} does not exist")
1157
- relevant_files_data = read_files(relevant_files, None)
1158
- output = save_memory(arg, relevant_files_data), 0.0
1149
+ assert not BASH_STATE.is_in_docker, "KT not supported in docker"
1150
+ relevant_files = []
1151
+ warnings = ""
1152
+ for fglob in arg.relevant_file_globs:
1153
+ fglob = expand_user(fglob, None)
1154
+ if not os.path.isabs(fglob) and arg.project_root_path:
1155
+ fglob = os.path.join(arg.project_root_path, fglob)
1156
+ globs = glob.glob(fglob)
1157
+ relevant_files.extend(globs[:1000])
1158
+ if not globs:
1159
+ warnings += f"Warning: No files found for the glob: {fglob}\n"
1160
+ relevant_files_data = read_files(relevant_files[:10_000], None)
1161
+ output_ = save_memory(arg, relevant_files_data)
1162
+ if not relevant_files and arg.relevant_file_globs:
1163
+ output_ = f'Error: No files found for the given globs. Context file successfully saved at "{output_}", but please fix the error.'
1164
+ elif warnings:
1165
+ output_ = warnings + "\nContext file successfully saved at " + output_
1166
+ output = output_, 0.0
1159
1167
  else:
1160
1168
  raise ValueError(f"Unknown tool: {arg}")
1161
1169
  if isinstance(output[0], str):
@@ -1184,7 +1192,7 @@ class Mdata(BaseModel):
1184
1192
  | str
1185
1193
  | ReadFiles
1186
1194
  | Initialize
1187
- | KnowledgeTransfer
1195
+ | ContextSave
1188
1196
  )
1189
1197
 
1190
1198
 
wcgw/relay/serve.py CHANGED
@@ -16,10 +16,10 @@ from pydantic import BaseModel
16
16
  from ..types_ import (
17
17
  BashCommand,
18
18
  BashInteraction,
19
+ ContextSave,
19
20
  FileEdit,
20
21
  FileEditFindReplace,
21
22
  Initialize,
22
- KnowledgeTransfer,
23
23
  ReadFiles,
24
24
  ResetShell,
25
25
  WriteIfEmpty,
@@ -36,7 +36,7 @@ class Mdata(BaseModel):
36
36
  | FileEdit
37
37
  | ReadFiles
38
38
  | Initialize
39
- | KnowledgeTransfer
39
+ | ContextSave
40
40
  | str
41
41
  )
42
42
  user_id: UUID
@@ -317,13 +317,13 @@ async def initialize(initialize_data: InitializeWithUUID) -> str:
317
317
  raise fastapi.HTTPException(status_code=500, detail="Timeout error")
318
318
 
319
319
 
320
- class KTWithUUID(KnowledgeTransfer):
320
+ class ContextSaveWithUUID(ContextSave):
321
321
  user_id: UUID
322
322
 
323
323
 
324
- @app.post("/v1/knowledge_transfer")
325
- async def knowledge_transfer(knowledge_transfer_data: KTWithUUID) -> str:
326
- user_id = knowledge_transfer_data.user_id
324
+ @app.post("/v1/context_save")
325
+ async def context_save(context_save_data: ContextSaveWithUUID) -> str:
326
+ user_id = context_save_data.user_id
327
327
  if user_id not in clients:
328
328
  return "Failure: id not found, ask the user to check it."
329
329
 
@@ -335,7 +335,7 @@ async def knowledge_transfer(knowledge_transfer_data: KTWithUUID) -> str:
335
335
 
336
336
  gpts[user_id] = put_results
337
337
 
338
- await clients[user_id](Mdata(data=knowledge_transfer_data, user_id=user_id))
338
+ await clients[user_id](Mdata(data=context_save_data, user_id=user_id))
339
339
 
340
340
  start_time = time.time()
341
341
  while time.time() - start_time < 30:
wcgw/types_.py CHANGED
@@ -101,12 +101,8 @@ class Keyboard(BaseModel):
101
101
  text: str
102
102
 
103
103
 
104
- class KnowledgeTransfer(BaseModel):
104
+ class ContextSave(BaseModel):
105
105
  id: str
106
106
  project_root_path: str
107
- objective: str
108
- all_user_instructions: str
109
- current_status_of_the_task: str
110
- all_issues_snippets: str
111
- relevant_file_paths: list[str]
112
- build_and_development_instructions: str
107
+ description: str
108
+ relevant_file_globs: list[str]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.7.0
3
+ Version: 2.7.1
4
4
  Summary: Shell and coding agent on claude and chatgpt
5
5
  Project-URL: Homepage, https://github.com/rusiaaman/wcgw
6
6
  Author-email: Aman Rusia <gapypi@arcfu.com>
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
33
33
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
34
34
 
35
35
 
36
- ⚠️ Warning: do not use this repo if you aren't scared of "Autonomous shell command execution"
36
+ ⚠️ Warning: do not allow BashCommand tool without reviewing the command, it may result in data loss.
37
37
 
38
38
  [![Tests](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-tests.yml)
39
39
  [![Mypy strict](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml/badge.svg?branch=main)](https://github.com/rusiaaman/wcgw/actions/workflows/python-types.yml)
@@ -55,7 +55,18 @@ Description-Content-Type: text/markdown
55
55
  - ⚡ **Large file edit**: Supports large file incremental edits to avoid token limit issues. Faster than full file write.
56
56
  - ⚡ **Syntax checking on edits**: Reports feedback to the LLM if its edits have any syntax errors, so that it can redo it.
57
57
  - ⚡ **Interactive Command Handling**: Supports interactive commands using arrow keys, interrupt, and ansi escape sequences.
58
- - ⚡ **Full Shell Access**: No restrictions, complete control.
58
+ - ⚡ **File protections**:
59
+ - The AI needs to read a file at least once before it's allowed to edit or rewrite it. This avoids accidental overwrites.
60
+ - Avoids context filling up while reading very large files. Files get chunked based on token length.
61
+ - On initialisation the provided workspace's directory structure is returned after selecting important files (based on .gitignore as well as a statistical approach)
62
+ - File edit based on search-replace tries to find correct search block if it has multiple matches based on previous search blocks. Fails otherwise (for correctness).
63
+ - File edit has spacing tolerant matching, with warning on issues like indentation mismatch. If there's no match, the closest match is returned to the AI to fix its mistakes.
64
+ - Using Aider-like search and replace, which has better performance than tool call based search and replace.
65
+ - ⚡ **Shell optimisations**:
66
+ - Only one command is allowed to be run at a time, simplifying management and avoiding rogue processes. There's only single shell instance at any point of time.
67
+ - Current working directory is always returned after any shell command to prevent AI from getting lost.
68
+ - Command polling exits after a quick timeout to avoid slow feedback. However, status checking has wait tolerance based on fresh output streaming from a command. Both of these approach combined provides a good shell interaction experience.
69
+
59
70
 
60
71
  ## Top use cases examples
61
72
 
@@ -1,28 +1,28 @@
1
1
  wcgw/__init__.py,sha256=9K2QW7QuSLhMTVbKbBYd9UUp-ZyrfBrxcjuD_xk458k,118
2
- wcgw/types_.py,sha256=qSl3h1D2mAcKmW3jzEmD-jdMYP1DE1G3f5RzIEcXuHY,2090
2
+ wcgw/types_.py,sha256=6gqdwC0F_rAQ80uPQpTWnw7uUByAD9qPa6-hKFgxqUU,1946
3
3
  wcgw/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  wcgw/client/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
5
- wcgw/client/anthropic_client.py,sha256=U9uE9mBiaq01FnxFC6cBIIAeSpO16UxrZJKeVGqItiA,22135
5
+ wcgw/client/anthropic_client.py,sha256=p-QsqjTl5LJxCFL5GfPNlQCRa4Bh4XM6MWfkaYJj4qc,21439
6
6
  wcgw/client/cli.py,sha256=-z0kpDAW3mzfQrQeZfaVJhBCAQY3HXnt9GdgQ8s-u0Y,1003
7
7
  wcgw/client/common.py,sha256=OCH7Tx64jojz3M3iONUrGMadE07W21DiZs5sOxWX1Qc,1456
8
8
  wcgw/client/computer_use.py,sha256=35NKAlMrxwD0TBlMMRnbCwz4g8TBRGOlcy-cmS-yJ_A,15247
9
9
  wcgw/client/diff-instructions.txt,sha256=tmJ9Fu9XdO_72lYXQQNY9RZyx91bjxrXJf9d_KBz57k,1611
10
- wcgw/client/memory.py,sha256=wdsd_czb01XM6Gu80HRsLM-Ll5gJ4E7UEnkneh5sWFI,1704
11
- wcgw/client/openai_client.py,sha256=ONTbQAHvU2O0HxmYlqbVjXwsf4rvHfQvnNKSUEu4mXc,19013
10
+ wcgw/client/memory.py,sha256=x7AsZo2GwYyEmnxtTvmQJBlUxD_26LuENQbCbNhTGyY,2272
11
+ wcgw/client/openai_client.py,sha256=UCiamF27iVhYh5fI5Kpa1IIMMXI6R5uPtRDjdKyHhOQ,18340
12
12
  wcgw/client/openai_utils.py,sha256=KfMB1-p2zDiA7pPWwAVarochf7-qeL1UMgtlDV9DtKA,2662
13
13
  wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
14
- wcgw/client/tools.py,sha256=TM2wBGoi9C1BmbDY1GSl-T4T1soPBDuNm1PwmF1BlqA,44606
14
+ wcgw/client/tools.py,sha256=Cs3VnwlhYpYvLrq5Q0bYAvgRObne-UU3P6VcfgqK4_0,44914
15
15
  wcgw/client/file_ops/diff_edit.py,sha256=o0ucArVwn5p6QTDgYsjLfMy4TJXxUG3qcppFBNF3bbQ,16751
16
16
  wcgw/client/file_ops/search_replace.py,sha256=89ieDC9fTsIKPDx7CJwnwpX32dRdSlMKoBtKVXc7VWI,3971
17
17
  wcgw/client/mcp_server/Readme.md,sha256=I8N4dHkTUVGNQ63BQkBMBhCCBTgqGOSF_pUR6iOEiUk,2495
18
18
  wcgw/client/mcp_server/__init__.py,sha256=hyPPwO9cabAJsOMWhKyat9yl7OlSmIobaoAZKHu3DMc,381
19
- wcgw/client/mcp_server/server.py,sha256=yi5PXSa1FFam3BtkFKgvda6QcTcErFP7vDCRNQtyCl0,13883
19
+ wcgw/client/mcp_server/server.py,sha256=UWUHBlu7UllR4q3xgyHQLeoUSLKmtkGc9nNrZaoKYe4,14905
20
20
  wcgw/client/repo_ops/display_tree.py,sha256=5FD4hfMkM2cIZnXlu7WfJswJLthj0SkuHlkGH6dpWQU,4632
21
21
  wcgw/client/repo_ops/path_prob.py,sha256=SWf0CDn37rtlsYRQ51ufSxay-heaQoVIhr1alB9tZ4M,2144
22
22
  wcgw/client/repo_ops/paths_model.vocab,sha256=M1pXycYDQehMXtpp-qAgU7rtzeBbCOiJo4qcYFY0kqk,315087
23
23
  wcgw/client/repo_ops/paths_tokens.model,sha256=jiwwE4ae8ADKuTZISutXuM5Wfyc_FBmN5rxTjoNnCos,1569052
24
24
  wcgw/client/repo_ops/repo_context.py,sha256=5NqRxBY0K-SBFXJ0Ybt7llzYOBD8pRkTpruMMJHWxv4,4336
25
- wcgw/relay/serve.py,sha256=dWT2cmmjqEvh6dqGoI0zEpXxl0w7SVts5j1iIl7ycL4,9555
25
+ wcgw/relay/serve.py,sha256=Z5EwtaCAtKFBSnUw4mPYw0sze3Coc4Fa8gObRRG_bT0,9525
26
26
  wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
27
27
  mcp_wcgw/__init__.py,sha256=fKCgOdN7cn7gR3YGFaGyV5Goe8A2sEyllLcsRkN0i-g,2601
28
28
  mcp_wcgw/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -46,8 +46,8 @@ mcp_wcgw/shared/memory.py,sha256=dBsOghxHz8-tycdSVo9kSujbsC8xb_tYsGmuJobuZnw,281
46
46
  mcp_wcgw/shared/progress.py,sha256=ymxOsb8XO5Mhlop7fRfdbmvPodANj7oq6O4dD0iUcnw,1048
47
47
  mcp_wcgw/shared/session.py,sha256=e44a0LQOW8gwdLs9_DE9oDsxqW2U8mXG3d5KT95bn5o,10393
48
48
  mcp_wcgw/shared/version.py,sha256=d2LZii-mgsPIxpshjkXnOTUmk98i0DT4ff8VpA_kAvE,111
49
- wcgw-2.7.0.dist-info/METADATA,sha256=0qgZ9bqCnkUZNTKWAEbmxBq8xMHRZL-DKmikYxxIWfk,6979
50
- wcgw-2.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- wcgw-2.7.0.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
52
- wcgw-2.7.0.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
53
- wcgw-2.7.0.dist-info/RECORD,,
49
+ wcgw-2.7.1.dist-info/METADATA,sha256=XoEYy3PMfwJzhaSz8TcR2-yI_R7FgM141XVzaBVsHPU,8351
50
+ wcgw-2.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
+ wcgw-2.7.1.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
52
+ wcgw-2.7.1.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
53
+ wcgw-2.7.1.dist-info/RECORD,,
File without changes