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

@@ -0,0 +1,148 @@
1
+ import os
2
+ from collections import deque
3
+ from pathlib import Path # Still needed for other parts
4
+ from typing import Optional
5
+
6
+ from pygit2 import GitError, Repository
7
+
8
+ from .display_tree import DirectoryTree
9
+ from .path_prob import FastPathAnalyzer
10
+
11
+ curr_folder = Path(__file__).parent
12
+ vocab_file = curr_folder / "paths_model.vocab"
13
+ model_file = curr_folder / "paths_tokens.model"
14
+ PATH_SCORER = FastPathAnalyzer(str(model_file), str(vocab_file))
15
+
16
+
17
+ def find_ancestor_with_git(path: Path) -> Optional[Repository]:
18
+ if path.is_file():
19
+ path = path.parent
20
+
21
+ try:
22
+ return Repository(str(path))
23
+ except GitError:
24
+ return None
25
+
26
+
27
+ MAX_ENTRIES_CHECK = 100_000
28
+
29
+
30
+ def get_all_files_max_depth(
31
+ abs_folder: str,
32
+ max_depth: int,
33
+ repo: Optional[Repository],
34
+ ) -> list[str]:
35
+ """BFS implementation using deque that maintains relative paths during traversal.
36
+ Returns (files_list, total_files_found) to track file count."""
37
+ all_files = []
38
+ # Queue stores: (folder_path, depth, rel_path_prefix)
39
+ queue = deque([(abs_folder, 0, "")])
40
+ entries_check = 0
41
+ while queue and entries_check < MAX_ENTRIES_CHECK:
42
+ current_folder, depth, prefix = queue.popleft()
43
+
44
+ if depth > max_depth:
45
+ continue
46
+
47
+ try:
48
+ entries = list(os.scandir(current_folder))
49
+ except PermissionError:
50
+ continue
51
+ except OSError:
52
+ continue
53
+ # Split into files and folders with single scan
54
+ files = []
55
+ folders = []
56
+ for entry in entries:
57
+ entries_check += 1
58
+ try:
59
+ is_file = entry.is_file(follow_symlinks=False)
60
+ except OSError:
61
+ continue
62
+ name = entry.name
63
+ rel_path = f"{prefix}{name}" if prefix else name
64
+
65
+ if repo and repo.path_is_ignored(rel_path):
66
+ continue
67
+
68
+ if is_file:
69
+ files.append(rel_path)
70
+ else:
71
+ folders.append((entry.path, rel_path))
72
+
73
+ # Process files first (maintain priority)
74
+ chunk = files[: min(10_000, max(0, MAX_ENTRIES_CHECK - entries_check))]
75
+ all_files.extend(chunk)
76
+
77
+ # Add folders to queue for BFS traversal
78
+ for folder_path, folder_rel_path in folders:
79
+ next_prefix = f"{folder_rel_path}/"
80
+ queue.append((folder_path, depth + 1, next_prefix))
81
+
82
+ return all_files
83
+
84
+
85
+ def get_repo_context(file_or_repo_path: str, max_files: int) -> tuple[str, Path]:
86
+ file_or_repo_path_ = Path(file_or_repo_path).absolute()
87
+
88
+ repo = find_ancestor_with_git(file_or_repo_path_)
89
+
90
+ if repo is not None:
91
+ context_dir = Path(repo.path).parent
92
+ else:
93
+ if file_or_repo_path_.is_file():
94
+ context_dir = file_or_repo_path_.parent
95
+ else:
96
+ context_dir = file_or_repo_path_
97
+
98
+ all_files = get_all_files_max_depth(str(context_dir), 10, repo)
99
+
100
+ # Calculate probabilities in batch
101
+ path_scores = PATH_SCORER.calculate_path_probabilities_batch(all_files)
102
+
103
+ # Create list of (path, score) tuples and sort by score
104
+ path_with_scores = list(zip(all_files, (score[0] for score in path_scores)))
105
+ sorted_files = [
106
+ path for path, _ in sorted(path_with_scores, key=lambda x: x[1], reverse=True)
107
+ ]
108
+
109
+ top_files = sorted_files[:max_files]
110
+
111
+ directory_printer = DirectoryTree(context_dir, max_files=max_files)
112
+ for file in top_files:
113
+ directory_printer.expand(file)
114
+
115
+ return directory_printer.display(), context_dir
116
+
117
+
118
+ if __name__ == "__main__":
119
+ import cProfile
120
+ import pstats
121
+ import sys
122
+
123
+ from line_profiler import LineProfiler
124
+
125
+ folder = sys.argv[1]
126
+
127
+ # Profile using cProfile for overall function statistics
128
+ profiler = cProfile.Profile()
129
+ profiler.enable()
130
+ result = get_repo_context(folder, 200)[0]
131
+ profiler.disable()
132
+
133
+ # Print cProfile stats
134
+ stats = pstats.Stats(profiler)
135
+ stats.sort_stats("cumulative")
136
+ print("\n=== Function-level profiling ===")
137
+ stats.print_stats(20) # Print top 20 functions
138
+
139
+ # Profile using line_profiler for line-by-line statistics
140
+ lp = LineProfiler()
141
+ lp_wrapper = lp(get_repo_context)
142
+ lp_wrapper(folder, 200)
143
+
144
+ print("\n=== Line-by-line profiling ===")
145
+ lp.print_stats()
146
+
147
+ print("\n=== Result ===")
148
+ print(result)
wcgw/client/tools.py CHANGED
@@ -1,61 +1,57 @@
1
1
  import base64
2
2
  import datetime
3
+ import importlib.metadata
3
4
  import json
4
5
  import mimetypes
5
- from pathlib import Path
6
+ import os
6
7
  import re
7
8
  import shlex
8
- import importlib.metadata
9
9
  import time
10
10
  import traceback
11
+ import uuid
12
+ from difflib import SequenceMatcher
13
+ from pathlib import Path
11
14
  from tempfile import NamedTemporaryFile, TemporaryDirectory
12
15
  from typing import (
13
16
  Callable,
14
- DefaultDict,
15
17
  Literal,
16
18
  Optional,
17
19
  ParamSpec,
18
20
  Type,
19
21
  TypeVar,
20
22
  )
21
- import uuid
22
23
 
23
- from pydantic import BaseModel, TypeAdapter
24
- import typer
25
- from .computer_use import run_computer_tool
26
- from websockets.sync.client import connect as syncconnect
27
-
28
- import os
29
- import tokenizers # type: ignore
30
24
  import pexpect
31
- from typer import Typer
32
- import websockets
33
-
34
- import rich
35
25
  import pyte
36
-
37
- from syntax_checker import check_syntax
26
+ import rich
27
+ import tokenizers # type: ignore
28
+ import typer
29
+ import websockets
38
30
  from openai.types.chat import (
39
31
  ChatCompletionMessageParam,
40
32
  )
41
- from difflib import SequenceMatcher
33
+ from pydantic import BaseModel, TypeAdapter
34
+ from syntax_checker import check_syntax
35
+ from typer import Typer
36
+ from websockets.sync.client import connect as syncconnect
42
37
 
43
38
  from ..types_ import (
44
39
  BashCommand,
45
40
  BashInteraction,
46
- WriteIfEmpty,
47
- FileEditFindReplace,
48
41
  FileEdit,
42
+ FileEditFindReplace,
43
+ GetScreenInfo,
49
44
  Initialize,
45
+ Keyboard,
46
+ Mouse,
50
47
  ReadFiles,
51
48
  ReadImage,
52
49
  ResetShell,
53
- Mouse,
54
- Keyboard,
55
50
  ScreenShot,
56
- GetScreenInfo,
51
+ WriteIfEmpty,
57
52
  )
58
-
53
+ from .computer_use import run_computer_tool
54
+ from .repo_ops.repo_context import get_repo_context
59
55
  from .sys_utils import command_run
60
56
 
61
57
 
@@ -178,19 +174,23 @@ def _ensure_env_and_bg_jobs(shell: pexpect.spawn) -> Optional[int]: # type: ign
178
174
  shell.expect(PROMPT, timeout=0.2)
179
175
  shell.sendline("jobs | wc -l")
180
176
  before = ""
177
+
181
178
  while not _is_int(before): # Consume all previous output
182
179
  try:
183
180
  shell.expect(PROMPT, timeout=0.2)
184
181
  except pexpect.TIMEOUT:
185
182
  console.print(f"Couldn't get exit code, before: {before}")
186
183
  raise
187
- assert isinstance(shell.before, str)
188
- # Render because there could be some anscii escape sequences still set like in google colab env
189
- before_lines = render_terminal_output(shell.before)
184
+
185
+ before_val = shell.before
186
+ if not isinstance(before_val, str):
187
+ before_val = str(before_val)
188
+ assert isinstance(before_val, str)
189
+ before_lines = render_terminal_output(before_val)
190
190
  before = "\n".join(before_lines).strip()
191
191
 
192
192
  try:
193
- return int((before))
193
+ return int(before)
194
194
  except ValueError:
195
195
  raise ValueError(f"Malformed output: {before}")
196
196
 
@@ -244,10 +244,12 @@ class BashState:
244
244
  return self._cwd
245
245
 
246
246
  def update_cwd(self) -> str:
247
- BASH_STATE.shell.sendline("pwd")
248
- BASH_STATE.shell.expect(PROMPT, timeout=0.2)
249
- assert isinstance(BASH_STATE.shell.before, str)
250
- before_lines = render_terminal_output(BASH_STATE.shell.before)
247
+ self.shell.sendline("pwd")
248
+ self.shell.expect(PROMPT, timeout=0.2)
249
+ before_val = self.shell.before
250
+ if not isinstance(before_val, str):
251
+ before_val = str(before_val)
252
+ before_lines = render_terminal_output(before_val)
251
253
  current_dir = "\n".join(before_lines).strip()
252
254
  self._cwd = current_dir
253
255
  return current_dir
@@ -287,20 +289,42 @@ class BashState:
287
289
  BASH_STATE = BashState()
288
290
 
289
291
 
290
- def initialize(workspace_dir: str = "") -> str:
292
+ def initialize(
293
+ any_workspace_path: str, read_files_: list[str], max_tokens: Optional[int]
294
+ ) -> str:
291
295
  reset_shell()
292
- if workspace_dir:
293
- BASH_STATE.shell.sendline(f"cd {shlex.quote(workspace_dir)}")
294
- BASH_STATE.shell.expect(PROMPT, timeout=0.2)
295
- BASH_STATE.update_cwd()
296
+
297
+ repo_context = ""
298
+
299
+ if any_workspace_path:
300
+ if os.path.exists(any_workspace_path):
301
+ repo_context, folder_to_start = get_repo_context(any_workspace_path, 200)
302
+
303
+ BASH_STATE.shell.sendline(f"cd {shlex.quote(str(folder_to_start))}")
304
+ BASH_STATE.shell.expect(PROMPT, timeout=0.2)
305
+ BASH_STATE.update_cwd()
306
+
307
+ repo_context = f"---\n# Workspace structure\n{repo_context}\n---\n"
308
+ else:
309
+ return f"\nInfo: Workspace path {any_workspace_path} does not exist\n"
310
+
311
+ initial_files_context = ""
312
+ if read_files_:
313
+ initial_files = read_files(read_files_, max_tokens)
314
+ initial_files_context = f"---\n# Requested files\n{initial_files}\n---\n"
296
315
 
297
316
  uname_sysname = os.uname().sysname
298
317
  uname_machine = os.uname().machine
299
318
 
300
319
  output = f"""
320
+ # Environment
301
321
  System: {uname_sysname}
302
322
  Machine: {uname_machine}
303
323
  Current working directory: {BASH_STATE.cwd}
324
+
325
+ {repo_context}
326
+
327
+ {initial_files_context}
304
328
  """
305
329
 
306
330
  return output
@@ -567,7 +591,9 @@ def execute_bash(
567
591
 
568
592
  return incremental_text, 0
569
593
 
570
- assert isinstance(BASH_STATE.shell.before, str)
594
+ if not isinstance(BASH_STATE.shell.before, str):
595
+ BASH_STATE.shell.before = str(BASH_STATE.shell.before)
596
+
571
597
  output = _incremental_text(BASH_STATE.shell.before, BASH_STATE.pending_output)
572
598
  BASH_STATE.set_repl()
573
599
 
@@ -578,7 +604,7 @@ def execute_bash(
578
604
  try:
579
605
  exit_status = get_status()
580
606
  output += exit_status
581
- except ValueError as e:
607
+ except ValueError:
582
608
  console.print(output)
583
609
  console.print(traceback.format_exc())
584
610
  console.print("Malformed output, restarting shell", style="red")
@@ -1101,7 +1127,7 @@ TOOLS = (
1101
1127
 
1102
1128
 
1103
1129
  def which_tool(args: str) -> TOOLS:
1104
- adapter = TypeAdapter[TOOLS](TOOLS)
1130
+ adapter = TypeAdapter[TOOLS](TOOLS, config={"extra": "forbid"})
1105
1131
  return adapter.validate_python(json.loads(args))
1106
1132
 
1107
1133
 
@@ -1154,7 +1180,7 @@ def get_tool_output(
1154
1180
  ) -> tuple[list[str | ImageData | DoneFlag], float]:
1155
1181
  global IS_IN_DOCKER, TOOL_CALLS
1156
1182
  if isinstance(args, dict):
1157
- adapter = TypeAdapter[TOOLS](TOOLS)
1183
+ adapter = TypeAdapter[TOOLS](TOOLS, config={"extra": "forbid"})
1158
1184
  arg = adapter.validate_python(args)
1159
1185
  else:
1160
1186
  arg = args
@@ -1189,7 +1215,10 @@ def get_tool_output(
1189
1215
  output = reset_shell(), 0.0
1190
1216
  elif isinstance(arg, Initialize):
1191
1217
  console.print("Calling initial info tool")
1192
- output = initialize(), 0.0
1218
+ output = (
1219
+ initialize(arg.any_workspace_path, arg.initial_files_to_read, max_tokens),
1220
+ 0.0,
1221
+ )
1193
1222
  elif isinstance(arg, (Mouse, Keyboard, ScreenShot, GetScreenInfo)):
1194
1223
  console.print(f"Calling {type(arg).__name__} tool")
1195
1224
  outputs_cost = run_computer_tool(arg), 0.0
@@ -1331,7 +1360,7 @@ def read_files(file_paths: list[str], max_tokens: Optional[int]) -> str:
1331
1360
  for i, file in enumerate(file_paths):
1332
1361
  try:
1333
1362
  content, truncated, tokens = read_file(file, max_tokens)
1334
- except ValueError as e:
1363
+ except Exception as e:
1335
1364
  message += f"\n{file}: {str(e)}\n"
1336
1365
  continue
1337
1366
 
wcgw/types_.py CHANGED
@@ -1,6 +1,14 @@
1
- import re
2
1
  from typing import Literal, Optional, Sequence
3
- from pydantic import BaseModel
2
+
3
+ from pydantic import BaseModel as PydanticBaseModel
4
+
5
+
6
+ class NoExtraArgs(PydanticBaseModel):
7
+ class Config:
8
+ extra = "forbid"
9
+
10
+
11
+ BaseModel = NoExtraArgs
4
12
 
5
13
 
6
14
  class BashCommand(BaseModel):
@@ -14,7 +22,6 @@ Specials = Literal[
14
22
 
15
23
 
16
24
  class BashInteraction(BaseModel):
17
- type: Literal["BashInteraction"]
18
25
  send_text: Optional[str] = None
19
26
  send_specials: Optional[Sequence[Specials]] = None
20
27
  send_ascii: Optional[Sequence[int]] = None
@@ -23,7 +30,6 @@ class BashInteraction(BaseModel):
23
30
 
24
31
  class ReadImage(BaseModel):
25
32
  file_path: str
26
- type: Literal["ReadImage"]
27
33
 
28
34
 
29
35
  class WriteIfEmpty(BaseModel):
@@ -33,7 +39,6 @@ class WriteIfEmpty(BaseModel):
33
39
 
34
40
  class ReadFiles(BaseModel):
35
41
  file_paths: list[str]
36
- type: Literal["ReadFiles"]
37
42
 
38
43
 
39
44
  class FileEditFindReplace(BaseModel):
@@ -52,16 +57,15 @@ class FileEdit(BaseModel):
52
57
 
53
58
 
54
59
  class Initialize(BaseModel):
55
- type: Literal["Initialize"]
60
+ any_workspace_path: str
61
+ initial_files_to_read: list[str]
56
62
 
57
63
 
58
64
  class GetScreenInfo(BaseModel):
59
- type: Literal["GetScreenInfo"]
60
65
  docker_image_id: str
61
66
 
62
67
 
63
68
  class ScreenShot(BaseModel):
64
- type: Literal["ScreenShot"]
65
69
  take_after_delay_seconds: int
66
70
 
67
71
 
@@ -69,7 +73,6 @@ class MouseMove(BaseModel):
69
73
  x: int
70
74
  y: int
71
75
  do_left_click_on_move: bool
72
- type: Literal["MouseMove"]
73
76
 
74
77
 
75
78
  class LeftClickDrag(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.5.0
3
+ Version: 2.6.2
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>
@@ -12,6 +12,7 @@ Requires-Dist: openai>=1.46.0
12
12
  Requires-Dist: petname>=2.6
13
13
  Requires-Dist: pexpect>=4.9.0
14
14
  Requires-Dist: pydantic>=2.9.2
15
+ Requires-Dist: pygit2>=1.16.0
15
16
  Requires-Dist: pyte>=0.8.2
16
17
  Requires-Dist: python-dotenv>=1.0.1
17
18
  Requires-Dist: rich>=13.8.1
@@ -28,7 +29,7 @@ Description-Content-Type: text/markdown
28
29
 
29
30
  # Shell and Coding agent for Claude and Chatgpt
30
31
 
31
- - Claude - An MCP server on claude desktop for autonomous shell, coding and desktop control agent. (mac only)
32
+ - Claude - An MCP server on claude desktop for autonomous shell and coding agent. (mac only)
32
33
  - Chatgpt - Allows custom gpt to talk to your shell via a relay server. (linux or mac)
33
34
 
34
35
 
@@ -37,8 +38,10 @@ Description-Content-Type: text/markdown
37
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)
38
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)
39
40
  [![Build](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml/badge.svg)](https://github.com/rusiaaman/wcgw/actions/workflows/python-publish.yml)
41
+ [![codecov](https://codecov.io/gh/rusiaaman/wcgw/graph/badge.svg)](https://codecov.io/gh/rusiaaman/wcgw)
40
42
 
41
43
  ## Updates
44
+ - [29 Dec 2024] Syntax checking on file writing and edits is now stable. Made `initialize` tool call useful; sending smart repo structure to claude if any repo is referenced. Large file handling is also now improved.
42
45
 
43
46
  - [9 Dec 2024] [Vscode extension to paste context on Claude app](https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw)
44
47
 
@@ -48,12 +51,11 @@ Description-Content-Type: text/markdown
48
51
 
49
52
  ## 🚀 Highlights
50
53
 
51
- - ⚡ **Full Shell Access**: No restrictions, complete control.
52
- - ⚡ **Desktop control on Claude**: Screen capture, mouse control, keyboard control on claude desktop (on mac with docker linux)
53
54
  - ⚡ **Create, Execute, Iterate**: Ask claude to keep running compiler checks till all errors are fixed, or ask it to keep checking for the status of a long running command till it's done.
54
55
  - ⚡ **Large file edit**: Supports large file incremental edits to avoid token limit issues. Faster than full file write.
56
+ - ⚡ **Syntax checking on edits**: Reports feedback to the LLM if its edits have any syntax errors, so that it can redo it.
55
57
  - ⚡ **Interactive Command Handling**: Supports interactive commands using arrow keys, interrupt, and ansi escape sequences.
56
- - ⚡ **REPL support**: [beta] Supports python/node and other REPL execution.
58
+ - ⚡ **Full Shell Access**: No restrictions, complete control.
57
59
 
58
60
  ## Top use cases examples
59
61
 
@@ -70,9 +72,11 @@ Description-Content-Type: text/markdown
70
72
  - Using 'screen' run my server in background instead, then run another api server in bg, finally run the frontend build. Keep checking logs for any issues in all three
71
73
  - Create repo wide unittest cases. Keep iterating through files and creating cases. Also keep running the tests after each update. Do not modify original code.
72
74
 
73
- ## Claude Setup
75
+ ## Claude setup (using mcp)
74
76
 
75
- First install `uv` https://docs.astral.sh/uv/getting-started/installation/#installation-methods
77
+ First install `uv` using homebrew `brew install uv`
78
+
79
+ (**Important:** use homebrew to install uv. Otherwise make sure `uv` is present in a global location like /usr/bin/)
76
80
 
77
81
  Then update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json)
78
82
 
@@ -99,53 +103,21 @@ Then restart claude app.
99
103
 
100
104
  _If there's an error in setting up_
101
105
 
102
- - Make sure `uv` in the system PATH by running `uv --version` and also ensure `uv tool run wcgw --version` works globally.
103
- Otherwise, re-install uv and follow instructions to add it into your .zshrc or .bashrc
106
+ - If there's an error like "uv ENOENT", make sure `uv` is installed. Then run 'which uv' in the terminal, and use its output in place of "uv" in the configuration.
104
107
  - If there's still an issue, check that `uv tool run --from wcgw@latest --python 3.12 wcgw_mcp` runs in your terminal. It should have no output and shouldn't exit.
105
108
  - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
106
109
 
107
- ### [Optional] Computer use support using desktop on docker
108
-
109
- Computer use is disabled by default. Add `--computer-use` to enable it. This will add necessary tools to Claude including ScreenShot, Mouse and Keyboard control.
110
-
111
- ```json
112
- {
113
- "mcpServers": {
114
- "wcgw": {
115
- "command": "uv",
116
- "args": [
117
- "tool",
118
- "run",
119
- "--from",
120
- "wcgw@latest",
121
- "--python",
122
- "3.12",
123
- "wcgw_mcp",
124
- "--computer-use"
125
- ]
126
- }
127
- }
128
- }
129
- ```
110
+ ### Alternative configuration using smithery (npx required)
111
+ [![smithery badge](https://smithery.ai/badge/wcgw)](https://smithery.ai/server/wcgw)
130
112
 
131
- Claude will be able to connect to any docker container with linux environment. Native system control isn't supported outside docker.
113
+ You need to first install uv using homebrew. `brew install uv`
132
114
 
133
- You'll need to run a docker image with desktop and optional VNC connection. Here's a demo image:
115
+ Then to configure wcgw for Claude Desktop automatically via [Smithery](https://smithery.ai/server/wcgw):
134
116
 
135
- ```sh
136
- docker run -p 6080:6080 ghcr.io/anthropics/anthropic-quickstarts:computer-use-demo-latest
117
+ ```bash
118
+ npx -y @smithery/cli install wcgw --client claude
137
119
  ```
138
120
 
139
- Then ask claude desktop app to control the docker os. It'll connect to the docker container and control it.
140
-
141
- Connect to `http://localhost:6080/vnc.html` for desktop view (VNC) of the system running in the docker.
142
-
143
- The following requirements should be installed and working in the linux docker image:
144
-
145
- 1. Needs `xdotool` to execute commands on the desktop.
146
- 2. Needs `scrot` to take screenshots.
147
- 3. Needs `convert` from imagemagick to convert images.
148
-
149
121
  ### Usage
150
122
 
151
123
  Wait for a few seconds. You should be able to see this icon if everything goes right.
@@ -157,8 +129,6 @@ over here
157
129
 
158
130
  Then ask claude to execute shell commands, read files, edit files, run your code, etc.
159
131
 
160
- If you've run the docker for LLM to access, you can ask it to control the "docker os". If you don't provide the docker container id to it, it'll try to search for available docker using `docker ps` command.
161
-
162
132
 
163
133
  ### [Optional] Vs code extension
164
134
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -172,12 +142,6 @@ Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
172
142
 
173
143
  ## Examples
174
144
 
175
- ### Computer use example
176
-
177
- ![computer-use](https://github.com/rusiaaman/wcgw/blob/main/static/computer-use.jpg?raw=true)
178
-
179
- ### Shell example
180
-
181
145
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
182
146
 
183
147
  ## [Optional] Local shell access with openai API key or anthropic API key
@@ -1,5 +1,5 @@
1
1
  wcgw/__init__.py,sha256=9K2QW7QuSLhMTVbKbBYd9UUp-ZyrfBrxcjuD_xk458k,118
2
- wcgw/types_.py,sha256=NDWBfzmR89-L7rFuf-9PeCF3jZuQ-WWMLbRVP-qlnJw,1835
2
+ wcgw/types_.py,sha256=pi976GyRLBKeCcpqNmVm5tI0iXO4okkkUGDa41ITr50,1792
3
3
  wcgw/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  wcgw/client/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
5
5
  wcgw/client/anthropic_client.py,sha256=kmS93LEVwXCppfbgCsfWe_SVmTAtsI3x8PrP8DJDYMY,21041
@@ -7,13 +7,18 @@ 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=s5AJKG23JsjwRYhFZFQVvwDpF67vElawrmdXwvukR1A,1683
10
- wcgw/client/openai_client.py,sha256=hAoUF4wcD0LqqX9MjqWZux12_HH0EdVognNcRLG6pew,17903
10
+ wcgw/client/openai_client.py,sha256=AP0B-fKNNlYCAEL0MrT3UxeCcvca7jJZp9kYkinUqSM,17706
11
11
  wcgw/client/openai_utils.py,sha256=KfMB1-p2zDiA7pPWwAVarochf7-qeL1UMgtlDV9DtKA,2662
12
12
  wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
13
- wcgw/client/tools.py,sha256=HO4xO0D7oxYJGeof0O-GIADc9UkoPwRbmyh9SgAWTMw,47079
13
+ wcgw/client/tools.py,sha256=JU-bZSJlqYapguXqA2sTamgTefmMYP3HpUTI2yXoqKU,48043
14
14
  wcgw/client/mcp_server/Readme.md,sha256=I8N4dHkTUVGNQ63BQkBMBhCCBTgqGOSF_pUR6iOEiUk,2495
15
15
  wcgw/client/mcp_server/__init__.py,sha256=hyPPwO9cabAJsOMWhKyat9yl7OlSmIobaoAZKHu3DMc,381
16
- wcgw/client/mcp_server/server.py,sha256=d8fegYsneGnmzwqCCL1vkHD_DuB2uQGyg24P_KvAK-A,12024
16
+ wcgw/client/mcp_server/server.py,sha256=bhswcJQt2jWIwVcQRrEaa9E6LkuE_vK7fNG51bsV4hw,12414
17
+ wcgw/client/repo_ops/display_tree.py,sha256=5FD4hfMkM2cIZnXlu7WfJswJLthj0SkuHlkGH6dpWQU,4632
18
+ wcgw/client/repo_ops/path_prob.py,sha256=SWf0CDn37rtlsYRQ51ufSxay-heaQoVIhr1alB9tZ4M,2144
19
+ wcgw/client/repo_ops/paths_model.vocab,sha256=M1pXycYDQehMXtpp-qAgU7rtzeBbCOiJo4qcYFY0kqk,315087
20
+ wcgw/client/repo_ops/paths_tokens.model,sha256=jiwwE4ae8ADKuTZISutXuM5Wfyc_FBmN5rxTjoNnCos,1569052
21
+ wcgw/client/repo_ops/repo_context.py,sha256=5NqRxBY0K-SBFXJ0Ybt7llzYOBD8pRkTpruMMJHWxv4,4336
17
22
  wcgw/relay/serve.py,sha256=CYY0mAAzR6nXkdGqLA9dXkgBcMCKPXEAmBcDyutUnjQ,8769
18
23
  wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
19
24
  mcp_wcgw/__init__.py,sha256=fKCgOdN7cn7gR3YGFaGyV5Goe8A2sEyllLcsRkN0i-g,2601
@@ -38,8 +43,8 @@ mcp_wcgw/shared/memory.py,sha256=dBsOghxHz8-tycdSVo9kSujbsC8xb_tYsGmuJobuZnw,281
38
43
  mcp_wcgw/shared/progress.py,sha256=ymxOsb8XO5Mhlop7fRfdbmvPodANj7oq6O4dD0iUcnw,1048
39
44
  mcp_wcgw/shared/session.py,sha256=e44a0LQOW8gwdLs9_DE9oDsxqW2U8mXG3d5KT95bn5o,10393
40
45
  mcp_wcgw/shared/version.py,sha256=d2LZii-mgsPIxpshjkXnOTUmk98i0DT4ff8VpA_kAvE,111
41
- wcgw-2.5.0.dist-info/METADATA,sha256=D16uxd1XiajjITvdEIdE2b4MI9gYepkor39zOkOQvFI,7924
42
- wcgw-2.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- wcgw-2.5.0.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
44
- wcgw-2.5.0.dist-info/licenses/LICENSE,sha256=SDdQZzFz8ehsr0m87ZmC3LL82leZdULi2yJ-XGGuqac,13417
45
- wcgw-2.5.0.dist-info/RECORD,,
46
+ wcgw-2.6.2.dist-info/METADATA,sha256=o8ZxaCTFXNBmv11mIMW5t0IS5s0GTYD_Hl7u_bzYZoU,6979
47
+ wcgw-2.6.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
+ wcgw-2.6.2.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
49
+ wcgw-2.6.2.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
50
+ wcgw-2.6.2.dist-info/RECORD,,