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

@@ -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")
@@ -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,5 +1,5 @@
1
- import re
2
1
  from typing import Literal, Optional, Sequence
2
+
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
@@ -53,6 +53,8 @@ class FileEdit(BaseModel):
53
53
 
54
54
  class Initialize(BaseModel):
55
55
  type: Literal["Initialize"]
56
+ any_workspace_path: str
57
+ initial_files_to_read: list[str]
56
58
 
57
59
 
58
60
  class GetScreenInfo(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.5.0
3
+ Version: 2.6.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>
@@ -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,6 +38,7 @@ 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
42
44
 
@@ -48,12 +50,11 @@ Description-Content-Type: text/markdown
48
50
 
49
51
  ## 🚀 Highlights
50
52
 
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
53
  - ⚡ **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
54
  - ⚡ **Large file edit**: Supports large file incremental edits to avoid token limit issues. Faster than full file write.
55
+ - ⚡ **Syntax checking on edits**: Reports feedback to the LLM if its edits have any syntax errors, so that it can redo it.
55
56
  - ⚡ **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.
57
+ - ⚡ **Full Shell Access**: No restrictions, complete control.
57
58
 
58
59
  ## Top use cases examples
59
60
 
@@ -70,9 +71,11 @@ Description-Content-Type: text/markdown
70
71
  - 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
72
  - 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
73
 
73
- ## Claude Setup
74
+ ## Claude setup (using mcp)
74
75
 
75
- First install `uv` https://docs.astral.sh/uv/getting-started/installation/#installation-methods
76
+ First install `uv` using homebrew `brew install uv`
77
+
78
+ (**Important:** use homebrew to install uv. Otherwise make sure `uv` is present in a global location like /usr/bin/)
76
79
 
77
80
  Then update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json)
78
81
 
@@ -99,53 +102,21 @@ Then restart claude app.
99
102
 
100
103
  _If there's an error in setting up_
101
104
 
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
105
+ - 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
106
  - 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
107
  - Debug the mcp server using `npx @modelcontextprotocol/inspector@0.1.7 uv tool run --from wcgw@latest --python 3.12 wcgw_mcp`
106
108
 
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
- ```
109
+ ### Alternative configuration using smithery (npx required)
110
+ [![smithery badge](https://smithery.ai/badge/wcgw)](https://smithery.ai/server/wcgw)
130
111
 
131
- Claude will be able to connect to any docker container with linux environment. Native system control isn't supported outside docker.
112
+ You need to first install uv using homebrew. `brew install uv`
132
113
 
133
- You'll need to run a docker image with desktop and optional VNC connection. Here's a demo image:
114
+ Then to configure wcgw for Claude Desktop automatically via [Smithery](https://smithery.ai/server/wcgw):
134
115
 
135
- ```sh
136
- docker run -p 6080:6080 ghcr.io/anthropics/anthropic-quickstarts:computer-use-demo-latest
116
+ ```bash
117
+ npx -y @smithery/cli install wcgw --client claude
137
118
  ```
138
119
 
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
120
  ### Usage
150
121
 
151
122
  Wait for a few seconds. You should be able to see this icon if everything goes right.
@@ -157,8 +128,6 @@ over here
157
128
 
158
129
  Then ask claude to execute shell commands, read files, edit files, run your code, etc.
159
130
 
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
131
 
163
132
  ### [Optional] Vs code extension
164
133
  https://marketplace.visualstudio.com/items?itemName=AmanRusia.wcgw
@@ -172,12 +141,6 @@ Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
172
141
 
173
142
  ## Examples
174
143
 
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
144
  ![example](https://github.com/rusiaaman/wcgw/blob/main/static/example.jpg?raw=true)
182
145
 
183
146
  ## [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=PJpnzF_TJ_L-AhruPlfD-zkGYj0_YEUAXTbvOtb_Zpo,1891
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=oJ9Zg03CEbzMh8NXQc1lfZQv8C46jQ24PRXGYMiHJ9k,47987
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.1.dist-info/METADATA,sha256=AY-QOt4XUDIE6Pd7axFCXgSj25XkI9k9gsJCz3LHxjM,6762
47
+ wcgw-2.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
+ wcgw-2.6.1.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
49
+ wcgw-2.6.1.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
50
+ wcgw-2.6.1.dist-info/RECORD,,