wcgw 3.0.5__py3-none-any.whl → 3.0.7__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.
- wcgw/client/bash_state/bash_state.py +47 -25
- wcgw/client/tools.py +64 -10
- wcgw/relay/serve.py +2 -1
- {wcgw-3.0.5.dist-info → wcgw-3.0.7.dist-info}/METADATA +28 -1
- {wcgw-3.0.5.dist-info → wcgw-3.0.7.dist-info}/RECORD +10 -10
- wcgw_cli/anthropic_client.py +0 -11
- wcgw_cli/openai_client.py +0 -11
- {wcgw-3.0.5.dist-info → wcgw-3.0.7.dist-info}/WHEEL +0 -0
- {wcgw-3.0.5.dist-info → wcgw-3.0.7.dist-info}/entry_points.txt +0 -0
- {wcgw-3.0.5.dist-info → wcgw-3.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -78,7 +78,9 @@ def get_tmpdir() -> str:
|
|
|
78
78
|
|
|
79
79
|
def check_if_screen_command_available() -> bool:
|
|
80
80
|
try:
|
|
81
|
-
subprocess.run(
|
|
81
|
+
subprocess.run(
|
|
82
|
+
["which", "screen"], capture_output=True, check=True, timeout=0.2
|
|
83
|
+
)
|
|
82
84
|
return True
|
|
83
85
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
84
86
|
return False
|
|
@@ -137,7 +139,7 @@ def cleanup_all_screens_with_name(name: str, console: Console) -> None:
|
|
|
137
139
|
|
|
138
140
|
def start_shell(
|
|
139
141
|
is_restricted_mode: bool, initial_dir: str, console: Console, over_screen: bool
|
|
140
|
-
) -> tuple[pexpect.spawn, str]:
|
|
142
|
+
) -> tuple["pexpect.spawn[str]", str]:
|
|
141
143
|
cmd = "/bin/bash"
|
|
142
144
|
if is_restricted_mode:
|
|
143
145
|
cmd += " -r"
|
|
@@ -232,6 +234,7 @@ class BashState:
|
|
|
232
234
|
use_screen: bool,
|
|
233
235
|
whitelist_for_overwrite: Optional[set[str]] = None,
|
|
234
236
|
) -> None:
|
|
237
|
+
self._last_command: str = ""
|
|
235
238
|
self.console = console
|
|
236
239
|
self._cwd = working_dir or os.getcwd()
|
|
237
240
|
self._bash_command_mode: BashCommandMode = bash_command_mode or BashCommandMode(
|
|
@@ -253,13 +256,17 @@ class BashState:
|
|
|
253
256
|
output = self._shell.expect(pattern, timeout)
|
|
254
257
|
return output
|
|
255
258
|
|
|
256
|
-
def send(self, s: str | bytes) -> int:
|
|
259
|
+
def send(self, s: str | bytes, set_as_command: Optional[str]) -> int:
|
|
257
260
|
self.close_bg_expect_thread()
|
|
261
|
+
if set_as_command is not None:
|
|
262
|
+
self._last_command = set_as_command
|
|
258
263
|
output = self._shell.send(s)
|
|
259
264
|
return output
|
|
260
265
|
|
|
261
|
-
def sendline(self, s: str | bytes) -> int:
|
|
266
|
+
def sendline(self, s: str | bytes, set_as_command: Optional[str]) -> int:
|
|
262
267
|
self.close_bg_expect_thread()
|
|
268
|
+
if set_as_command is not None:
|
|
269
|
+
self._last_command = set_as_command
|
|
263
270
|
output = self._shell.sendline(s)
|
|
264
271
|
return output
|
|
265
272
|
|
|
@@ -273,7 +280,10 @@ class BashState:
|
|
|
273
280
|
|
|
274
281
|
@property
|
|
275
282
|
def before(self) -> Optional[str]:
|
|
276
|
-
|
|
283
|
+
before = self._shell.before
|
|
284
|
+
if before and before.startswith(self._last_command):
|
|
285
|
+
return before[len(self._last_command) :]
|
|
286
|
+
return before
|
|
277
287
|
|
|
278
288
|
def run_bg_expect_thread(self) -> None:
|
|
279
289
|
"""
|
|
@@ -333,11 +343,11 @@ class BashState:
|
|
|
333
343
|
def ensure_env_and_bg_jobs(self) -> Optional[int]:
|
|
334
344
|
quick_timeout = 0.2 if not self.over_screen else 1
|
|
335
345
|
# First reset the prompt in case venv was sourced or other reasons.
|
|
336
|
-
self.sendline(PROMPT_STATEMENT)
|
|
346
|
+
self.sendline(PROMPT_STATEMENT, set_as_command=PROMPT_STATEMENT)
|
|
337
347
|
self.expect(PROMPT_CONST, timeout=quick_timeout)
|
|
338
348
|
# Reset echo also if it was enabled
|
|
339
349
|
command = "jobs | wc -l"
|
|
340
|
-
self.sendline(command)
|
|
350
|
+
self.sendline(command, set_as_command=command)
|
|
341
351
|
before = ""
|
|
342
352
|
counts = 0
|
|
343
353
|
while not _is_int(before): # Consume all previous output
|
|
@@ -365,6 +375,7 @@ class BashState:
|
|
|
365
375
|
|
|
366
376
|
def _init_shell(self) -> None:
|
|
367
377
|
self._state: Literal["repl"] | datetime.datetime = "repl"
|
|
378
|
+
self._last_command = ""
|
|
368
379
|
# Ensure self._cwd exists
|
|
369
380
|
os.makedirs(self._cwd, exist_ok=True)
|
|
370
381
|
try:
|
|
@@ -404,6 +415,7 @@ class BashState:
|
|
|
404
415
|
def set_repl(self) -> None:
|
|
405
416
|
self._state = "repl"
|
|
406
417
|
self._pending_output = ""
|
|
418
|
+
self._last_command = ""
|
|
407
419
|
|
|
408
420
|
@property
|
|
409
421
|
def state(self) -> BASH_CLF_OUTPUT:
|
|
@@ -420,7 +432,7 @@ class BashState:
|
|
|
420
432
|
return PROMPT_CONST
|
|
421
433
|
|
|
422
434
|
def update_cwd(self) -> str:
|
|
423
|
-
self.sendline("pwd")
|
|
435
|
+
self.sendline("pwd", set_as_command="pwd")
|
|
424
436
|
self.expect(PROMPT_CONST, timeout=0.2)
|
|
425
437
|
before_val = self.before
|
|
426
438
|
if not isinstance(before_val, str):
|
|
@@ -505,8 +517,8 @@ class BashState:
|
|
|
505
517
|
|
|
506
518
|
|
|
507
519
|
WAITING_INPUT_MESSAGE = """A command is already running. NOTE: You can't run multiple shell sessions, likely a previous program hasn't exited.
|
|
508
|
-
1. Get its output using
|
|
509
|
-
2. Use `send_ascii` or `send_specials` to give inputs to the running program
|
|
520
|
+
1. Get its output using status check.
|
|
521
|
+
2. Use `send_ascii` or `send_specials` to give inputs to the running program OR
|
|
510
522
|
3. kill the previous program by sending ctrl+c first using `send_ascii` or `send_specials`
|
|
511
523
|
4. Interrupt and run the process in background by re-running it using screen
|
|
512
524
|
"""
|
|
@@ -538,6 +550,11 @@ def _incremental_text(text: str, last_pending_output: str) -> str:
|
|
|
538
550
|
# text = render_terminal_output(text[-100_000:])
|
|
539
551
|
text = text[-100_000:]
|
|
540
552
|
|
|
553
|
+
if not last_pending_output:
|
|
554
|
+
# This is the first call. We need to offset the position where this program
|
|
555
|
+
# is being rendered for the new screen versions
|
|
556
|
+
# Caveat: no difference in output between a program with leading whitespace and one without.
|
|
557
|
+
return rstrip(render_terminal_output(text)).lstrip()
|
|
541
558
|
last_rendered_lines = render_terminal_output(last_pending_output)
|
|
542
559
|
last_pending_output_rendered = "\n".join(last_rendered_lines)
|
|
543
560
|
if not last_rendered_lines:
|
|
@@ -580,7 +597,10 @@ def is_status_check(arg: BashCommand) -> bool:
|
|
|
580
597
|
isinstance(arg.action_json, SendSpecials)
|
|
581
598
|
and arg.action_json.send_specials == ["Enter"]
|
|
582
599
|
)
|
|
583
|
-
or (
|
|
600
|
+
or (
|
|
601
|
+
isinstance(arg.action_json, SendAscii)
|
|
602
|
+
and arg.action_json.send_ascii == [10]
|
|
603
|
+
)
|
|
584
604
|
)
|
|
585
605
|
|
|
586
606
|
|
|
@@ -632,8 +652,8 @@ def _execute_bash(
|
|
|
632
652
|
)
|
|
633
653
|
|
|
634
654
|
for i in range(0, len(command), 128):
|
|
635
|
-
bash_state.send(command[i : i + 128])
|
|
636
|
-
bash_state.send(bash_state.linesep)
|
|
655
|
+
bash_state.send(command[i : i + 128], set_as_command=None)
|
|
656
|
+
bash_state.send(bash_state.linesep, set_as_command=command)
|
|
637
657
|
|
|
638
658
|
elif isinstance(command_data, StatusCheck):
|
|
639
659
|
bash_state.console.print("Checking status")
|
|
@@ -646,8 +666,10 @@ def _execute_bash(
|
|
|
646
666
|
|
|
647
667
|
bash_state.console.print(f"Interact text: {command_data.send_text}")
|
|
648
668
|
for i in range(0, len(command_data.send_text), 128):
|
|
649
|
-
bash_state.send(
|
|
650
|
-
|
|
669
|
+
bash_state.send(
|
|
670
|
+
command_data.send_text[i : i + 128], set_as_command=None
|
|
671
|
+
)
|
|
672
|
+
bash_state.send(bash_state.linesep, set_as_command=None)
|
|
651
673
|
|
|
652
674
|
elif isinstance(command_data, SendSpecials):
|
|
653
675
|
if not command_data.send_specials:
|
|
@@ -658,15 +680,15 @@ def _execute_bash(
|
|
|
658
680
|
)
|
|
659
681
|
for char in command_data.send_specials:
|
|
660
682
|
if char == "Key-up":
|
|
661
|
-
bash_state.send("\033[A")
|
|
683
|
+
bash_state.send("\033[A", set_as_command=None)
|
|
662
684
|
elif char == "Key-down":
|
|
663
|
-
bash_state.send("\033[B")
|
|
685
|
+
bash_state.send("\033[B", set_as_command=None)
|
|
664
686
|
elif char == "Key-left":
|
|
665
|
-
bash_state.send("\033[D")
|
|
687
|
+
bash_state.send("\033[D", set_as_command=None)
|
|
666
688
|
elif char == "Key-right":
|
|
667
|
-
bash_state.send("\033[C")
|
|
689
|
+
bash_state.send("\033[C", set_as_command=None)
|
|
668
690
|
elif char == "Enter":
|
|
669
|
-
bash_state.send("\n")
|
|
691
|
+
bash_state.send("\n", set_as_command=None)
|
|
670
692
|
elif char == "Ctrl-c":
|
|
671
693
|
bash_state.sendintr()
|
|
672
694
|
is_interrupt = True
|
|
@@ -674,7 +696,7 @@ def _execute_bash(
|
|
|
674
696
|
bash_state.sendintr()
|
|
675
697
|
is_interrupt = True
|
|
676
698
|
elif char == "Ctrl-z":
|
|
677
|
-
bash_state.send("\x1a")
|
|
699
|
+
bash_state.send("\x1a", set_as_command=None)
|
|
678
700
|
else:
|
|
679
701
|
raise Exception(f"Unknown special character: {char}")
|
|
680
702
|
|
|
@@ -686,7 +708,7 @@ def _execute_bash(
|
|
|
686
708
|
f"Sending ASCII sequence: {command_data.send_ascii}"
|
|
687
709
|
)
|
|
688
710
|
for ascii_char in command_data.send_ascii:
|
|
689
|
-
bash_state.send(chr(ascii_char))
|
|
711
|
+
bash_state.send(chr(ascii_char), set_as_command=None)
|
|
690
712
|
if ascii_char == 3:
|
|
691
713
|
is_interrupt = True
|
|
692
714
|
else:
|
|
@@ -747,9 +769,9 @@ def _execute_bash(
|
|
|
747
769
|
incremental_text = (
|
|
748
770
|
incremental_text
|
|
749
771
|
+ """---
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
772
|
+
----
|
|
773
|
+
Failure interrupting.
|
|
774
|
+
You may want to try Ctrl-c again or program specific exit interactive commands.
|
|
753
775
|
"""
|
|
754
776
|
)
|
|
755
777
|
|
wcgw/client/tools.py
CHANGED
|
@@ -20,6 +20,7 @@ from typing import (
|
|
|
20
20
|
TypeVar,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
import rich
|
|
23
24
|
from openai.types.chat import (
|
|
24
25
|
ChatCompletionMessageParam,
|
|
25
26
|
)
|
|
@@ -31,6 +32,7 @@ from wcgw.client.bash_state.bash_state import get_status
|
|
|
31
32
|
from ..types_ import (
|
|
32
33
|
BashCommand,
|
|
33
34
|
CodeWriterMode,
|
|
35
|
+
Command,
|
|
34
36
|
Console,
|
|
35
37
|
ContextSave,
|
|
36
38
|
FileEdit,
|
|
@@ -195,7 +197,10 @@ def initialize(
|
|
|
195
197
|
if read_files_:
|
|
196
198
|
if folder_to_start:
|
|
197
199
|
read_files_ = [
|
|
198
|
-
|
|
200
|
+
# Expand the path before checking if it's absolute
|
|
201
|
+
os.path.join(folder_to_start, f)
|
|
202
|
+
if not os.path.isabs(expand_user(f))
|
|
203
|
+
else expand_user(f)
|
|
199
204
|
for f in read_files_
|
|
200
205
|
]
|
|
201
206
|
initial_files = read_files(read_files_, max_tokens, context)
|
|
@@ -362,9 +367,10 @@ def truncate_if_over(content: str, max_tokens: Optional[int]) -> str:
|
|
|
362
367
|
|
|
363
368
|
|
|
364
369
|
def read_image_from_shell(file_path: str, context: Context) -> ImageData:
|
|
365
|
-
# Expand the path
|
|
370
|
+
# Expand the path before checking if it's absolute
|
|
366
371
|
file_path = expand_user(file_path)
|
|
367
372
|
|
|
373
|
+
# If not absolute after expansion, join with current working directory
|
|
368
374
|
if not os.path.isabs(file_path):
|
|
369
375
|
file_path = os.path.join(context.bash_state.cwd, file_path)
|
|
370
376
|
|
|
@@ -400,10 +406,10 @@ def write_file(
|
|
|
400
406
|
max_tokens: Optional[int],
|
|
401
407
|
context: Context,
|
|
402
408
|
) -> str:
|
|
403
|
-
if
|
|
409
|
+
# Expand the path before checking if it's absolute
|
|
410
|
+
path_ = expand_user(writefile.file_path)
|
|
411
|
+
if not os.path.isabs(path_):
|
|
404
412
|
return f"Failure: file_path should be absolute path, current working directory is {context.bash_state.cwd}"
|
|
405
|
-
else:
|
|
406
|
-
path_ = expand_user(writefile.file_path)
|
|
407
413
|
|
|
408
414
|
error_on_exist_ = (
|
|
409
415
|
error_on_exist and path_ not in context.bash_state.whitelist_for_overwrite
|
|
@@ -452,6 +458,9 @@ def write_file(
|
|
|
452
458
|
syntax_errors = check.description
|
|
453
459
|
|
|
454
460
|
if syntax_errors:
|
|
461
|
+
if extension in {"tsx", "ts"}:
|
|
462
|
+
syntax_errors += "\nNote: Ignore if 'tagged template literals' are used, they may raise false positive errors in tree-sitter."
|
|
463
|
+
|
|
455
464
|
context_for_errors = get_context_for_errors(
|
|
456
465
|
check.errors, writefile.file_content, max_tokens
|
|
457
466
|
)
|
|
@@ -502,12 +511,12 @@ def do_diff_edit(fedit: FileEdit, max_tokens: Optional[int], context: Context) -
|
|
|
502
511
|
def _do_diff_edit(fedit: FileEdit, max_tokens: Optional[int], context: Context) -> str:
|
|
503
512
|
context.console.log(f"Editing file: {fedit.file_path}")
|
|
504
513
|
|
|
505
|
-
if
|
|
514
|
+
# Expand the path before checking if it's absolute
|
|
515
|
+
path_ = expand_user(fedit.file_path)
|
|
516
|
+
if not os.path.isabs(path_):
|
|
506
517
|
raise Exception(
|
|
507
518
|
f"Failure: file_path should be absolute path, current working directory is {context.bash_state.cwd}"
|
|
508
519
|
)
|
|
509
|
-
else:
|
|
510
|
-
path_ = expand_user(fedit.file_path)
|
|
511
520
|
|
|
512
521
|
# Validate using file_edit_mode
|
|
513
522
|
allowed_globs = context.bash_state.file_edit_mode.allowed_globs
|
|
@@ -548,11 +557,13 @@ def _do_diff_edit(fedit: FileEdit, max_tokens: Optional[int], context: Context)
|
|
|
548
557
|
context_for_errors = get_context_for_errors(
|
|
549
558
|
check.errors, apply_diff_to, max_tokens
|
|
550
559
|
)
|
|
560
|
+
if extension in {"tsx", "ts"}:
|
|
561
|
+
syntax_errors += "\nNote: Ignore if 'tagged template literals' are used, they may raise false positive errors in tree-sitter."
|
|
551
562
|
|
|
552
563
|
context.console.print(f"W: Syntax errors encountered: {syntax_errors}")
|
|
553
564
|
return f"""{comments}
|
|
554
565
|
---
|
|
555
|
-
|
|
566
|
+
Warning: tree-sitter reported syntax errors, please re-read the file and fix if there are any errors.
|
|
556
567
|
Syntax errors:
|
|
557
568
|
{syntax_errors}
|
|
558
569
|
|
|
@@ -698,9 +709,12 @@ def get_tool_output(
|
|
|
698
709
|
context.console.print("Calling task memory tool")
|
|
699
710
|
relevant_files = []
|
|
700
711
|
warnings = ""
|
|
712
|
+
# Expand user in project root path
|
|
701
713
|
arg.project_root_path = os.path.expanduser(arg.project_root_path)
|
|
702
714
|
for fglob in arg.relevant_file_globs:
|
|
715
|
+
# Expand user in glob pattern before checking if it's absolute
|
|
703
716
|
fglob = expand_user(fglob)
|
|
717
|
+
# If not absolute after expansion, join with project root path
|
|
704
718
|
if not os.path.isabs(fglob) and arg.project_root_path:
|
|
705
719
|
fglob = os.path.join(arg.project_root_path, fglob)
|
|
706
720
|
globs = glob.glob(fglob, recursive=True)
|
|
@@ -794,6 +808,46 @@ def read_file(
|
|
|
794
808
|
rest = save_out_of_context(
|
|
795
809
|
default_enc.decoder(tokens[max_tokens:]), Path(file_path).suffix
|
|
796
810
|
)
|
|
797
|
-
content += f"\n(...truncated)\n---\nI've saved the continuation in a new file.
|
|
811
|
+
content += f"\n(...truncated)\n---\nI've saved the continuation in a new file. You may want to read: `{rest}`"
|
|
798
812
|
truncated = True
|
|
799
813
|
return content, truncated, tokens_counts
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
if __name__ == "__main__":
|
|
817
|
+
with BashState(
|
|
818
|
+
rich.console.Console(style="blue", highlight=False, markup=False),
|
|
819
|
+
"",
|
|
820
|
+
None,
|
|
821
|
+
None,
|
|
822
|
+
None,
|
|
823
|
+
None,
|
|
824
|
+
True,
|
|
825
|
+
None,
|
|
826
|
+
) as BASH_STATE:
|
|
827
|
+
print(
|
|
828
|
+
get_tool_output(
|
|
829
|
+
Context(BASH_STATE, BASH_STATE.console),
|
|
830
|
+
Initialize(
|
|
831
|
+
type="first_call",
|
|
832
|
+
any_workspace_path="",
|
|
833
|
+
initial_files_to_read=[],
|
|
834
|
+
task_id_to_resume="",
|
|
835
|
+
mode_name="wcgw",
|
|
836
|
+
code_writer_config=None,
|
|
837
|
+
),
|
|
838
|
+
default_enc,
|
|
839
|
+
0,
|
|
840
|
+
lambda x, y: ("", 0),
|
|
841
|
+
None,
|
|
842
|
+
)
|
|
843
|
+
)
|
|
844
|
+
print(
|
|
845
|
+
get_tool_output(
|
|
846
|
+
Context(BASH_STATE, BASH_STATE.console),
|
|
847
|
+
BashCommand(action_json=Command(command="pwd")),
|
|
848
|
+
default_enc,
|
|
849
|
+
0,
|
|
850
|
+
lambda x, y: ("", 0),
|
|
851
|
+
None,
|
|
852
|
+
)
|
|
853
|
+
)
|
wcgw/relay/serve.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import os
|
|
2
3
|
import threading
|
|
3
4
|
import time
|
|
4
5
|
from importlib import metadata
|
|
@@ -281,7 +282,7 @@ async def context_save(context_save_data: ContextSaveWithUUID) -> str:
|
|
|
281
282
|
raise fastapi.HTTPException(status_code=500, detail="Timeout error")
|
|
282
283
|
|
|
283
284
|
|
|
284
|
-
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
285
|
+
app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "static")), name="static")
|
|
285
286
|
|
|
286
287
|
|
|
287
288
|
def run() -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wcgw
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.7
|
|
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>
|
|
@@ -204,6 +204,32 @@ Read here: https://github.com/rusiaaman/wcgw/blob/main/openai.md
|
|
|
204
204
|
|
|
205
205
|

|
|
206
206
|
|
|
207
|
+
|
|
208
|
+
## Using mcp server over docker
|
|
209
|
+
|
|
210
|
+
First build the docker image `docker build -t wcgw https://github.com/rusiaaman/wcgw.git`
|
|
211
|
+
|
|
212
|
+
Then you can update `/Users/username/Library/Application Support/Claude/claude_desktop_config.json` to have
|
|
213
|
+
```
|
|
214
|
+
{
|
|
215
|
+
"mcpServers": {
|
|
216
|
+
"filesystem": {
|
|
217
|
+
"command": "docker",
|
|
218
|
+
"args": [
|
|
219
|
+
"run",
|
|
220
|
+
"-i",
|
|
221
|
+
"--rm",
|
|
222
|
+
"--mount",
|
|
223
|
+
"type=bind,src=/Users/username/Desktop,dst=/workspace/Desktop",
|
|
224
|
+
"wcgw",
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
207
233
|
## [Optional] Local shell access with openai API key or anthropic API key
|
|
208
234
|
|
|
209
235
|
### Openai
|
|
@@ -255,3 +281,4 @@ The server provides the following MCP tools:
|
|
|
255
281
|
- Parameters: `id` (string), `project_root_path` (string), `description` (string), `relevant_file_globs` (string[])
|
|
256
282
|
|
|
257
283
|
All tools support absolute paths and include built-in protections against common errors. See the [MCP specification](https://modelcontextprotocol.io/) for detailed protocol information.
|
|
284
|
+
|
|
@@ -7,8 +7,8 @@ wcgw/client/diff-instructions.txt,sha256=tmJ9Fu9XdO_72lYXQQNY9RZyx91bjxrXJf9d_KB
|
|
|
7
7
|
wcgw/client/memory.py,sha256=8LdYsOhvCOoC1kfvDr85kNy07WnhPMvE6B2FRM2w85Y,2902
|
|
8
8
|
wcgw/client/modes.py,sha256=FjIQOjT5oI7dk9VG0oRemN1A6EHBvHnuSQGKuRbguJI,10352
|
|
9
9
|
wcgw/client/tool_prompts.py,sha256=H36Sr3yH2YuHZTc08Y6rTUWlYWjKMFtIGP6vbAVNwZo,3988
|
|
10
|
-
wcgw/client/tools.py,sha256=
|
|
11
|
-
wcgw/client/bash_state/bash_state.py,sha256=
|
|
10
|
+
wcgw/client/tools.py,sha256=rboKbRHtIl_4Mhypc23CrDaswXOHjyovyxWkwbXswXk,27387
|
|
11
|
+
wcgw/client/bash_state/bash_state.py,sha256=aY_hW9y7TyPWHR5799v6rxzuWb1VzgjiGjA4K0cpGjE,27287
|
|
12
12
|
wcgw/client/encoder/__init__.py,sha256=Y-8f43I6gMssUCWpX5rLYiAFv3D-JPRs4uNEejPlke8,1514
|
|
13
13
|
wcgw/client/file_ops/diff_edit.py,sha256=sIwXSSkWYff_Dp3oHfefqtSuFqLrxbhKvzkCoLuLqDE,18679
|
|
14
14
|
wcgw/client/file_ops/search_replace.py,sha256=Napa7IWaYPGMNdttunKyRDkb90elZE7r23B_o_htRxo,5585
|
|
@@ -21,13 +21,13 @@ wcgw/client/repo_ops/paths_model.vocab,sha256=M1pXycYDQehMXtpp-qAgU7rtzeBbCOiJo4
|
|
|
21
21
|
wcgw/client/repo_ops/paths_tokens.model,sha256=jiwwE4ae8ADKuTZISutXuM5Wfyc_FBmN5rxTjoNnCos,1569052
|
|
22
22
|
wcgw/client/repo_ops/repo_context.py,sha256=5NqRxBY0K-SBFXJ0Ybt7llzYOBD8pRkTpruMMJHWxv4,4336
|
|
23
23
|
wcgw/relay/client.py,sha256=BUeEKUsWts8RpYxXwXcyFyjBJhOCS-CxThAlL_-VCOI,3618
|
|
24
|
-
wcgw/relay/serve.py,sha256=
|
|
24
|
+
wcgw/relay/serve.py,sha256=UFaRlGTfeD9Oc2AcPF8rIdTRwROBKoT2HglOKrc-aoo,7947
|
|
25
25
|
wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
|
|
26
26
|
wcgw_cli/__init__.py,sha256=TNxXsTPgb52OhakIda9wTRh91cqoBqgQRx5TxjzQQFU,21
|
|
27
27
|
wcgw_cli/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
28
|
-
wcgw_cli/anthropic_client.py,sha256
|
|
28
|
+
wcgw_cli/anthropic_client.py,sha256=-rfnw_tIx1VjhzOsPeTZkoF0VAXhRC9zBW2oLMFJcxg,19624
|
|
29
29
|
wcgw_cli/cli.py,sha256=-7FBe_lahKyUOhf65iurTA1M1gXXXAiT0OVKQVcZKKo,948
|
|
30
|
-
wcgw_cli/openai_client.py,sha256=
|
|
30
|
+
wcgw_cli/openai_client.py,sha256=4NFv-d7u6B7vMD_w3Qqr-564ZcdvfBUGowUmQ6idglE,15758
|
|
31
31
|
wcgw_cli/openai_utils.py,sha256=xGOb3W5ALrIozV7oszfGYztpj0FnXdD7jAxm5lEIVKY,2439
|
|
32
32
|
mcp_wcgw/__init__.py,sha256=fKCgOdN7cn7gR3YGFaGyV5Goe8A2sEyllLcsRkN0i-g,2601
|
|
33
33
|
mcp_wcgw/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -51,8 +51,8 @@ mcp_wcgw/shared/memory.py,sha256=dBsOghxHz8-tycdSVo9kSujbsC8xb_tYsGmuJobuZnw,281
|
|
|
51
51
|
mcp_wcgw/shared/progress.py,sha256=ymxOsb8XO5Mhlop7fRfdbmvPodANj7oq6O4dD0iUcnw,1048
|
|
52
52
|
mcp_wcgw/shared/session.py,sha256=e44a0LQOW8gwdLs9_DE9oDsxqW2U8mXG3d5KT95bn5o,10393
|
|
53
53
|
mcp_wcgw/shared/version.py,sha256=d2LZii-mgsPIxpshjkXnOTUmk98i0DT4ff8VpA_kAvE,111
|
|
54
|
-
wcgw-3.0.
|
|
55
|
-
wcgw-3.0.
|
|
56
|
-
wcgw-3.0.
|
|
57
|
-
wcgw-3.0.
|
|
58
|
-
wcgw-3.0.
|
|
54
|
+
wcgw-3.0.7.dist-info/METADATA,sha256=EUfU99SQ5awMMfYVqCS969KEJ_4sWvcd8Jn9DkbVq0s,14549
|
|
55
|
+
wcgw-3.0.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
56
|
+
wcgw-3.0.7.dist-info/entry_points.txt,sha256=vd3tj1_Kzfp55LscJ8-6WFMM5hm9cWTfNGFCrWBnH3Q,124
|
|
57
|
+
wcgw-3.0.7.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
|
|
58
|
+
wcgw-3.0.7.dist-info/RECORD,,
|
wcgw_cli/anthropic_client.py
CHANGED
|
@@ -227,17 +227,6 @@ def loop(
|
|
|
227
227
|
mode="wcgw",
|
|
228
228
|
)
|
|
229
229
|
|
|
230
|
-
with open(
|
|
231
|
-
os.path.join(
|
|
232
|
-
os.path.dirname(__file__),
|
|
233
|
-
"..",
|
|
234
|
-
"wcgw",
|
|
235
|
-
"client",
|
|
236
|
-
"diff-instructions.txt",
|
|
237
|
-
)
|
|
238
|
-
) as f:
|
|
239
|
-
system += f.read()
|
|
240
|
-
|
|
241
230
|
if history:
|
|
242
231
|
if (
|
|
243
232
|
(last_msg := history[-1])["role"] == "user"
|
wcgw_cli/openai_client.py
CHANGED
|
@@ -191,17 +191,6 @@ def loop(
|
|
|
191
191
|
mode="wcgw",
|
|
192
192
|
)
|
|
193
193
|
|
|
194
|
-
with open(
|
|
195
|
-
os.path.join(
|
|
196
|
-
os.path.dirname(__file__),
|
|
197
|
-
"..",
|
|
198
|
-
"wcgw",
|
|
199
|
-
"client",
|
|
200
|
-
"diff-instructions.txt",
|
|
201
|
-
)
|
|
202
|
-
) as f:
|
|
203
|
-
system += f.read()
|
|
204
|
-
|
|
205
194
|
if not history:
|
|
206
195
|
history = [{"role": "system", "content": system}]
|
|
207
196
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|