wcgw 4.1.0__tar.gz → 4.1.1__tar.gz
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-4.1.0 → wcgw-4.1.1}/PKG-INFO +2 -1
- {wcgw-4.1.0 → wcgw-4.1.1}/pyproject.toml +5 -1
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/bash_state/bash_state.py +134 -3
- wcgw-4.1.1/src/wcgw/client/bash_state/parser/__init__.py +7 -0
- wcgw-4.1.1/src/wcgw/client/bash_state/parser/bash_statement_parser.py +181 -0
- wcgw-4.1.1/tests/test_bash_parser.py +80 -0
- wcgw-4.1.1/tests/test_bash_parser_complex.py +84 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/tests/test_tools.py +18 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/uv.lock +77 -1
- {wcgw-4.1.0 → wcgw-4.1.1}/.github/workflows/python-publish.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.github/workflows/python-tests.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.github/workflows/python-types.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.gitignore +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.gitmodules +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.python-version +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/.vscode/settings.json +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/CLAUDE.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/Dockerfile +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/LICENSE +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/gpt_action_json_schema.json +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/gpt_instructions.txt +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/openai.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.git +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.gitignore +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/.python-version +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/LICENSE +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/RELEASE.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/SECURITY.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/pyproject.toml +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/uv.lock +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/common.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/diff-instructions.txt +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/encoder/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/file_ops/diff_edit.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/file_ops/search_replace.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/mcp_server/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/mcp_server/server.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/memory.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/modes.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/display_tree.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/file_stats.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/path_prob.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/repo_ops/repo_context.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/tool_prompts.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/client/tools.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/py.typed +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/relay/client.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/relay/serve.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw/types_.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/__init__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/__main__.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/anthropic_client.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/cli.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/openai_client.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/src/wcgw_cli/openai_utils.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/claude-ss.jpg +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/computer-use.jpg +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/example.jpg +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/rocket-icon.png +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/ss1.png +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/static/workflow-demo.gif +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/tests/test_edit.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/tests/test_file_range_tracking.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/tests/test_mcp_server.py +0 -0
- {wcgw-4.1.0 → wcgw-4.1.1}/tests/test_readfiles.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wcgw
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.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>
|
|
@@ -11,6 +11,7 @@ Requires-Dist: fastapi>=0.115.0
|
|
|
11
11
|
Requires-Dist: openai>=1.46.0
|
|
12
12
|
Requires-Dist: petname>=2.6
|
|
13
13
|
Requires-Dist: pexpect>=4.9.0
|
|
14
|
+
Requires-Dist: psutil>=7.0.0
|
|
14
15
|
Requires-Dist: pydantic>=2.9.2
|
|
15
16
|
Requires-Dist: pygit2>=1.16.0
|
|
16
17
|
Requires-Dist: pyte>=0.8.2
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
|
|
3
3
|
name = "wcgw"
|
|
4
|
-
version = "4.1.
|
|
4
|
+
version = "4.1.1"
|
|
5
5
|
description = "Shell and coding agent on claude and chatgpt"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.11"
|
|
@@ -23,6 +23,7 @@ dependencies = [
|
|
|
23
23
|
"tokenizers>=0.21.0",
|
|
24
24
|
"pygit2>=1.16.0",
|
|
25
25
|
"syntax-checker>=0.3.0",
|
|
26
|
+
"psutil>=7.0.0",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[project.urls]
|
|
@@ -58,6 +59,9 @@ dev-dependencies = [
|
|
|
58
59
|
"line-profiler>=4.2.0",
|
|
59
60
|
"pytest-asyncio>=0.25.3",
|
|
60
61
|
"types-pexpect>=4.9.0.20241208",
|
|
62
|
+
"types-psutil>=7.0.0.20250218",
|
|
63
|
+
"tree-sitter>=0.24.0",
|
|
64
|
+
"tree-sitter-bash>=0.23.3",
|
|
61
65
|
]
|
|
62
66
|
|
|
63
67
|
[tool.pytest.ini_options]
|
|
@@ -16,6 +16,7 @@ from typing import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
import pexpect
|
|
19
|
+
import psutil
|
|
19
20
|
import pyte
|
|
20
21
|
|
|
21
22
|
from ...types_ import (
|
|
@@ -30,6 +31,7 @@ from ...types_ import (
|
|
|
30
31
|
)
|
|
31
32
|
from ..encoder import EncoderDecoder
|
|
32
33
|
from ..modes import BashCommandMode, FileEditMode, WriteIfEmptyMode
|
|
34
|
+
from .parser.bash_statement_parser import BashStatementParser
|
|
33
35
|
|
|
34
36
|
PROMPT_CONST = "wcgw→" + " "
|
|
35
37
|
PROMPT_STATEMENT = "export GIT_PAGER=cat PAGER=cat PROMPT_COMMAND= PS1='wcgw→'' '"
|
|
@@ -87,6 +89,116 @@ def check_if_screen_command_available() -> bool:
|
|
|
87
89
|
return False
|
|
88
90
|
|
|
89
91
|
|
|
92
|
+
def get_wcgw_screen_sessions() -> list[str]:
|
|
93
|
+
"""
|
|
94
|
+
Get a list of all WCGW screen session IDs.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
List of screen session IDs that match the wcgw pattern.
|
|
98
|
+
"""
|
|
99
|
+
screen_sessions = []
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
# Get list of all screen sessions
|
|
103
|
+
result = subprocess.run(
|
|
104
|
+
["screen", "-ls"],
|
|
105
|
+
capture_output=True,
|
|
106
|
+
text=True,
|
|
107
|
+
check=False, # Don't raise exception on non-zero exit code
|
|
108
|
+
timeout=0.5,
|
|
109
|
+
)
|
|
110
|
+
output = result.stdout or result.stderr or ""
|
|
111
|
+
|
|
112
|
+
# Parse screen output to get session IDs
|
|
113
|
+
for line in output.splitlines():
|
|
114
|
+
line = line.strip()
|
|
115
|
+
if not line or not line[0].isdigit():
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
# Extract session info (e.g., "1234.wcgw.123456 (Detached)")
|
|
119
|
+
session_parts = line.split()
|
|
120
|
+
if not session_parts:
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
session_id = session_parts[0].strip()
|
|
124
|
+
|
|
125
|
+
# Check if it's a WCGW session
|
|
126
|
+
if ".wcgw." in session_id:
|
|
127
|
+
screen_sessions.append(session_id)
|
|
128
|
+
except Exception:
|
|
129
|
+
# If anything goes wrong, just return empty list
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
return screen_sessions
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_orphaned_wcgw_screens() -> list[str]:
|
|
136
|
+
"""
|
|
137
|
+
Identify orphaned WCGW screen sessions where the parent process has PID 1
|
|
138
|
+
or doesn't exist.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
List of screen session IDs that are orphaned and match the wcgw pattern.
|
|
142
|
+
"""
|
|
143
|
+
orphaned_screens = []
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
# Get list of all WCGW screen sessions
|
|
147
|
+
screen_sessions = get_wcgw_screen_sessions()
|
|
148
|
+
|
|
149
|
+
for session_id in screen_sessions:
|
|
150
|
+
# Extract PID from session ID (first part before the dot)
|
|
151
|
+
try:
|
|
152
|
+
pid = int(session_id.split(".")[0])
|
|
153
|
+
|
|
154
|
+
# Check if process exists and if its parent is PID 1
|
|
155
|
+
try:
|
|
156
|
+
process = psutil.Process(pid)
|
|
157
|
+
parent_pid = process.ppid()
|
|
158
|
+
|
|
159
|
+
if parent_pid == 1:
|
|
160
|
+
# This is an orphaned process
|
|
161
|
+
orphaned_screens.append(session_id)
|
|
162
|
+
except psutil.NoSuchProcess:
|
|
163
|
+
# Process doesn't exist anymore, consider it orphaned
|
|
164
|
+
orphaned_screens.append(session_id)
|
|
165
|
+
except (ValueError, IndexError):
|
|
166
|
+
# Couldn't parse PID, skip
|
|
167
|
+
continue
|
|
168
|
+
except Exception:
|
|
169
|
+
# If anything goes wrong, just return empty list
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
return orphaned_screens
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def cleanup_orphaned_wcgw_screens(console: Console) -> None:
|
|
176
|
+
"""
|
|
177
|
+
Clean up all orphaned WCGW screen sessions.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
console: Console for logging.
|
|
181
|
+
"""
|
|
182
|
+
orphaned_sessions = get_orphaned_wcgw_screens()
|
|
183
|
+
|
|
184
|
+
if not orphaned_sessions:
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
console.log(
|
|
188
|
+
f"Found {len(orphaned_sessions)} orphaned WCGW screen sessions to clean up"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
for session in orphaned_sessions:
|
|
192
|
+
try:
|
|
193
|
+
subprocess.run(
|
|
194
|
+
["screen", "-S", session, "-X", "quit"],
|
|
195
|
+
check=False,
|
|
196
|
+
timeout=CONFIG.timeout,
|
|
197
|
+
)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
console.log(f"Failed to kill orphaned screen session: {session}\n{e}")
|
|
200
|
+
|
|
201
|
+
|
|
90
202
|
def cleanup_all_screens_with_name(name: str, console: Console) -> None:
|
|
91
203
|
"""
|
|
92
204
|
There could be in worst case multiple screens with same name, clear them if any.
|
|
@@ -269,6 +381,8 @@ class BashState:
|
|
|
269
381
|
self.close_bg_expect_thread()
|
|
270
382
|
if set_as_command is not None:
|
|
271
383
|
self._last_command = set_as_command
|
|
384
|
+
# if s == "\n":
|
|
385
|
+
# return self._shell.sendcontrol("m")
|
|
272
386
|
output = self._shell.send(s)
|
|
273
387
|
return output
|
|
274
388
|
|
|
@@ -387,6 +501,11 @@ class BashState:
|
|
|
387
501
|
self._last_command = ""
|
|
388
502
|
# Ensure self._cwd exists
|
|
389
503
|
os.makedirs(self._cwd, exist_ok=True)
|
|
504
|
+
|
|
505
|
+
# Clean up orphaned WCGW screen sessions
|
|
506
|
+
if check_if_screen_command_available():
|
|
507
|
+
cleanup_orphaned_wcgw_screens(self.console)
|
|
508
|
+
|
|
390
509
|
try:
|
|
391
510
|
self._shell, self._shell_id = start_shell(
|
|
392
511
|
self._bash_command_mode.bash_mode == "restricted_mode",
|
|
@@ -817,10 +936,22 @@ def _execute_bash(
|
|
|
817
936
|
raise ValueError(WAITING_INPUT_MESSAGE)
|
|
818
937
|
|
|
819
938
|
command = command_data.command.strip()
|
|
939
|
+
|
|
940
|
+
# Check for multiple statements using the bash statement parser
|
|
820
941
|
if "\n" in command:
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
942
|
+
try:
|
|
943
|
+
parser = BashStatementParser()
|
|
944
|
+
statements = parser.parse_string(command)
|
|
945
|
+
if len(statements) > 1:
|
|
946
|
+
return (
|
|
947
|
+
"Error: Command contains multiple statements. Please run only one bash statement at a time.",
|
|
948
|
+
0.0,
|
|
949
|
+
)
|
|
950
|
+
except Exception:
|
|
951
|
+
# Fall back to simple newline check if something goes wrong
|
|
952
|
+
raise ValueError(
|
|
953
|
+
"Command should not contain newline character in middle. Run only one command at a time."
|
|
954
|
+
)
|
|
824
955
|
|
|
825
956
|
for i in range(0, len(command), 128):
|
|
826
957
|
bash_state.send(command[i : i + 128], set_as_command=None)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Bash Statement Parser
|
|
4
|
+
|
|
5
|
+
This script parses bash scripts and identifies individual statements using tree-sitter.
|
|
6
|
+
It correctly handles multi-line strings, command chains with && and ||, and semicolon-separated statements.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import Any, List, Optional
|
|
12
|
+
|
|
13
|
+
import tree_sitter_bash
|
|
14
|
+
from tree_sitter import Language, Parser
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class Statement:
|
|
19
|
+
"""A bash statement with its source code and position information."""
|
|
20
|
+
|
|
21
|
+
text: str
|
|
22
|
+
start_line: int
|
|
23
|
+
end_line: int
|
|
24
|
+
start_byte: int
|
|
25
|
+
end_byte: int
|
|
26
|
+
node_type: str
|
|
27
|
+
parent_type: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
def __str__(self) -> str:
|
|
30
|
+
return self.text.strip()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BashStatementParser:
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
# Use the precompiled bash language
|
|
36
|
+
self.language = Language(tree_sitter_bash.language())
|
|
37
|
+
self.parser = Parser(self.language)
|
|
38
|
+
|
|
39
|
+
def parse_file(self, file_path: str) -> List[Statement]:
|
|
40
|
+
"""Parse a bash script file and return a list of statements."""
|
|
41
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
42
|
+
content = f.read()
|
|
43
|
+
return self.parse_string(content)
|
|
44
|
+
|
|
45
|
+
def parse_string(self, content: str) -> List[Statement]:
|
|
46
|
+
"""Parse a string containing bash script and return a list of statements."""
|
|
47
|
+
tree = self.parser.parse(bytes(content, "utf-8"))
|
|
48
|
+
root_node = tree.root_node
|
|
49
|
+
|
|
50
|
+
# For debugging: Uncomment to print the tree structure
|
|
51
|
+
# self._print_tree(root_node, content)
|
|
52
|
+
|
|
53
|
+
statements: List[Statement] = []
|
|
54
|
+
self._extract_statements(root_node, content, statements, None)
|
|
55
|
+
|
|
56
|
+
# Post-process statements to handle multi-line statements correctly
|
|
57
|
+
return self._post_process_statements(statements, content)
|
|
58
|
+
|
|
59
|
+
def _print_tree(self, node: Any, content: str, indent: str = "") -> None:
|
|
60
|
+
"""Debug helper to print the entire syntax tree."""
|
|
61
|
+
node_text = content[node.start_byte : node.end_byte]
|
|
62
|
+
if len(node_text) > 40:
|
|
63
|
+
node_text = node_text[:37] + "..."
|
|
64
|
+
print(f"{indent}{node.type}: {repr(node_text)}")
|
|
65
|
+
for child in node.children:
|
|
66
|
+
self._print_tree(child, content, indent + " ")
|
|
67
|
+
|
|
68
|
+
def _extract_statements(
|
|
69
|
+
self,
|
|
70
|
+
node: Any,
|
|
71
|
+
content: str,
|
|
72
|
+
statements: List[Statement],
|
|
73
|
+
parent_type: Optional[str],
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Recursively extract statements from the syntax tree."""
|
|
76
|
+
# Node types that represent bash statements
|
|
77
|
+
statement_node_types = {
|
|
78
|
+
# Basic statements
|
|
79
|
+
"command",
|
|
80
|
+
"variable_assignment",
|
|
81
|
+
"declaration_command",
|
|
82
|
+
"unset_command",
|
|
83
|
+
# Control flow statements
|
|
84
|
+
"for_statement",
|
|
85
|
+
"c_style_for_statement",
|
|
86
|
+
"while_statement",
|
|
87
|
+
"if_statement",
|
|
88
|
+
"case_statement",
|
|
89
|
+
# Function definition
|
|
90
|
+
"function_definition",
|
|
91
|
+
# Command chains and groups
|
|
92
|
+
"pipeline", # For command chains with | and |&
|
|
93
|
+
"list", # For command chains with && and ||
|
|
94
|
+
"compound_statement",
|
|
95
|
+
"subshell",
|
|
96
|
+
"redirected_statement",
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Create a Statement object for this node if it's a recognized statement type
|
|
100
|
+
if node.type in statement_node_types:
|
|
101
|
+
# Get the text of this statement
|
|
102
|
+
start_byte = node.start_byte
|
|
103
|
+
end_byte = node.end_byte
|
|
104
|
+
statement_text = content[start_byte:end_byte]
|
|
105
|
+
|
|
106
|
+
# Get line numbers
|
|
107
|
+
start_line = (
|
|
108
|
+
node.start_point[0] + 1
|
|
109
|
+
) # tree-sitter uses 0-indexed line numbers
|
|
110
|
+
end_line = node.end_point[0] + 1
|
|
111
|
+
|
|
112
|
+
statements.append(
|
|
113
|
+
Statement(
|
|
114
|
+
text=statement_text,
|
|
115
|
+
start_line=start_line,
|
|
116
|
+
end_line=end_line,
|
|
117
|
+
start_byte=start_byte,
|
|
118
|
+
end_byte=end_byte,
|
|
119
|
+
node_type=node.type,
|
|
120
|
+
parent_type=parent_type,
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Update parent type for children
|
|
125
|
+
parent_type = node.type
|
|
126
|
+
|
|
127
|
+
# Recursively process all children
|
|
128
|
+
for child in node.children:
|
|
129
|
+
self._extract_statements(child, content, statements, parent_type)
|
|
130
|
+
|
|
131
|
+
def _post_process_statements(
|
|
132
|
+
self, statements: List[Statement], content: str
|
|
133
|
+
) -> List[Statement]:
|
|
134
|
+
if not statements:
|
|
135
|
+
return []
|
|
136
|
+
|
|
137
|
+
# Filter out list statements that have been split
|
|
138
|
+
top_statements = []
|
|
139
|
+
for stmt in statements:
|
|
140
|
+
# Skip statements that are contained within others
|
|
141
|
+
is_contained = False
|
|
142
|
+
for other in statements:
|
|
143
|
+
if other is stmt:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# Check if completely contained (except for lists we've split)
|
|
147
|
+
if other.node_type != "list" or ";" not in other.text:
|
|
148
|
+
if (
|
|
149
|
+
other.start_line <= stmt.start_line
|
|
150
|
+
and other.end_line >= stmt.end_line
|
|
151
|
+
and len(other.text) > len(stmt.text)
|
|
152
|
+
and stmt.text in other.text
|
|
153
|
+
):
|
|
154
|
+
is_contained = True
|
|
155
|
+
break
|
|
156
|
+
|
|
157
|
+
if not is_contained:
|
|
158
|
+
top_statements.append(stmt)
|
|
159
|
+
|
|
160
|
+
# Sort by position in file for consistent output
|
|
161
|
+
top_statements.sort(key=lambda s: (s.start_line, s.text))
|
|
162
|
+
|
|
163
|
+
return top_statements
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def main() -> None:
|
|
167
|
+
if len(sys.argv) < 2:
|
|
168
|
+
print("Usage: python bash_statement_parser.py <bash_script_file>")
|
|
169
|
+
sys.exit(1)
|
|
170
|
+
|
|
171
|
+
parser = BashStatementParser()
|
|
172
|
+
statements = parser.parse_file(sys.argv[1])
|
|
173
|
+
|
|
174
|
+
print(f"Found {len(statements)} statements:")
|
|
175
|
+
for i, stmt in enumerate(statements, 1):
|
|
176
|
+
print(f"\n--- Statement {i} (Lines {stmt.start_line}-{stmt.end_line}) ---")
|
|
177
|
+
print(stmt)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
if __name__ == "__main__":
|
|
181
|
+
main()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for the bash statement parser.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
from wcgw.client.bash_state.parser.bash_statement_parser import BashStatementParser
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_bash_statement_parser_basic():
|
|
12
|
+
"""Test basic statement parsing."""
|
|
13
|
+
parser = BashStatementParser()
|
|
14
|
+
|
|
15
|
+
# Test single statement
|
|
16
|
+
statements = parser.parse_string("echo hello")
|
|
17
|
+
assert len(statements) == 1
|
|
18
|
+
assert statements[0].text == "echo hello"
|
|
19
|
+
|
|
20
|
+
# Test command with newlines inside string
|
|
21
|
+
statements = parser.parse_string('echo "hello\nworld"')
|
|
22
|
+
assert len(statements) == 1
|
|
23
|
+
|
|
24
|
+
# Test command with && chain
|
|
25
|
+
statements = parser.parse_string("echo hello && echo world")
|
|
26
|
+
assert len(statements) == 1
|
|
27
|
+
|
|
28
|
+
# Test command with || chain
|
|
29
|
+
statements = parser.parse_string("echo hello || echo world")
|
|
30
|
+
assert len(statements) == 1
|
|
31
|
+
|
|
32
|
+
# Test command with pipe
|
|
33
|
+
statements = parser.parse_string("echo hello | grep hello")
|
|
34
|
+
assert len(statements) == 1
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_bash_statement_parser_multiple():
|
|
38
|
+
"""Test multiple statement detection."""
|
|
39
|
+
parser = BashStatementParser()
|
|
40
|
+
|
|
41
|
+
# Test multiple statements on separate lines
|
|
42
|
+
statements = parser.parse_string("echo hello\necho world")
|
|
43
|
+
assert len(statements) == 2
|
|
44
|
+
|
|
45
|
+
# Test multiple statements with semicolons
|
|
46
|
+
statements = parser.parse_string("echo hello; echo world")
|
|
47
|
+
assert len(statements) == 2
|
|
48
|
+
|
|
49
|
+
# Test more complex case
|
|
50
|
+
statements = parser.parse_string("echo hello; echo world && echo again")
|
|
51
|
+
assert len(statements) == 2
|
|
52
|
+
|
|
53
|
+
# Test mixed separation
|
|
54
|
+
statements = parser.parse_string("echo a; echo b\necho c")
|
|
55
|
+
assert len(statements) == 3
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_bash_statement_parser_complex():
|
|
59
|
+
"""Test complex statement handling."""
|
|
60
|
+
parser = BashStatementParser()
|
|
61
|
+
|
|
62
|
+
# Test subshell
|
|
63
|
+
statements = parser.parse_string("(echo hello; echo world)")
|
|
64
|
+
assert len(statements) == 1
|
|
65
|
+
|
|
66
|
+
# Test braces
|
|
67
|
+
statements = parser.parse_string("{ echo hello; echo world; }")
|
|
68
|
+
assert len(statements) == 1
|
|
69
|
+
|
|
70
|
+
# Test semicolons in strings
|
|
71
|
+
statements = parser.parse_string('echo "hello;world"')
|
|
72
|
+
assert len(statements) == 1
|
|
73
|
+
|
|
74
|
+
# Test escaped semicolons
|
|
75
|
+
statements = parser.parse_string('echo hello\\; echo world')
|
|
76
|
+
assert len(statements) == 1
|
|
77
|
+
|
|
78
|
+
# Test quoted semicolons
|
|
79
|
+
statements = parser.parse_string("echo 'hello;world'")
|
|
80
|
+
assert len(statements) == 1
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests specifically for complex bash parsing scenarios.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from wcgw.client.bash_state.parser.bash_statement_parser import BashStatementParser
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_semicolon_lists():
|
|
9
|
+
"""Test parsing of semicolon-separated commands."""
|
|
10
|
+
parser = BashStatementParser()
|
|
11
|
+
|
|
12
|
+
# Simple case: two commands separated by semicolon
|
|
13
|
+
statements = parser.parse_string("echo a; echo b")
|
|
14
|
+
assert len(statements) == 2
|
|
15
|
+
assert statements[0].text.strip() == "echo a"
|
|
16
|
+
assert statements[1].text.strip() == "echo b"
|
|
17
|
+
|
|
18
|
+
# Multiple semicolons
|
|
19
|
+
statements = parser.parse_string("echo a; echo b; echo c")
|
|
20
|
+
assert len(statements) == 3
|
|
21
|
+
assert statements[0].text.strip() == "echo a"
|
|
22
|
+
assert statements[1].text.strip() == "echo b"
|
|
23
|
+
assert statements[2].text.strip() == "echo c"
|
|
24
|
+
|
|
25
|
+
# Semicolons with whitespace
|
|
26
|
+
statements = parser.parse_string("echo a ; echo b")
|
|
27
|
+
assert len(statements) == 2
|
|
28
|
+
assert statements[0].text.strip() == "echo a"
|
|
29
|
+
assert statements[1].text.strip() == "echo b"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_bash_command_with_semicolons_in_quotes():
|
|
33
|
+
"""Test that semicolons inside quotes don't split statements."""
|
|
34
|
+
parser = BashStatementParser()
|
|
35
|
+
|
|
36
|
+
# Semicolon in single quotes
|
|
37
|
+
statements = parser.parse_string("echo 'a;b'")
|
|
38
|
+
assert len(statements) == 1
|
|
39
|
+
|
|
40
|
+
# Semicolon in double quotes
|
|
41
|
+
statements = parser.parse_string('echo "a;b"')
|
|
42
|
+
assert len(statements) == 1
|
|
43
|
+
|
|
44
|
+
# Mixed quotes
|
|
45
|
+
statements = parser.parse_string("echo \"a;b\" ; echo 'c;d'")
|
|
46
|
+
assert len(statements) == 2
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_complex_commands():
|
|
50
|
+
"""Test complex command scenarios."""
|
|
51
|
+
parser = BashStatementParser()
|
|
52
|
+
|
|
53
|
+
# Command with redirection and semicolon
|
|
54
|
+
statements = parser.parse_string("cat > file.txt << EOF\ntest\nEOF\n; echo done")
|
|
55
|
+
assert len(statements) == 2
|
|
56
|
+
|
|
57
|
+
# Command with subshell and semicolon
|
|
58
|
+
statements = parser.parse_string("(cd /tmp && echo 'in tmp'); echo 'outside'")
|
|
59
|
+
assert len(statements) == 2
|
|
60
|
+
|
|
61
|
+
# Command with braces and semicolon
|
|
62
|
+
statements = parser.parse_string("{ echo a; echo b; }; echo c")
|
|
63
|
+
assert len(statements) == 2
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_command_chaining():
|
|
67
|
+
"""Test command chains are treated as a single statement."""
|
|
68
|
+
parser = BashStatementParser()
|
|
69
|
+
|
|
70
|
+
# AND chaining
|
|
71
|
+
statements = parser.parse_string("echo a && echo b")
|
|
72
|
+
assert len(statements) == 1
|
|
73
|
+
|
|
74
|
+
# OR chaining
|
|
75
|
+
statements = parser.parse_string("echo a || echo b")
|
|
76
|
+
assert len(statements) == 1
|
|
77
|
+
|
|
78
|
+
# Pipe chaining
|
|
79
|
+
statements = parser.parse_string("echo a | grep a")
|
|
80
|
+
assert len(statements) == 1
|
|
81
|
+
|
|
82
|
+
# Mixed chaining
|
|
83
|
+
statements = parser.parse_string("echo a && echo b || echo c")
|
|
84
|
+
assert len(statements) == 1
|
|
@@ -306,6 +306,24 @@ def test_bash_command(context: Context, temp_dir: str) -> None:
|
|
|
306
306
|
assert isinstance(outputs[0], str)
|
|
307
307
|
assert "hello world" in outputs[0]
|
|
308
308
|
|
|
309
|
+
# Test multiline
|
|
310
|
+
cmd = BashCommand(action_json=Command(command="echo 'hello \nworld'"))
|
|
311
|
+
outputs, _ = get_tool_output(
|
|
312
|
+
context, cmd, default_enc, 1.0, lambda x, y: ("", 0.0), None
|
|
313
|
+
)
|
|
314
|
+
assert len(outputs) == 1
|
|
315
|
+
assert isinstance(outputs[0], str)
|
|
316
|
+
assert "hello\nworld" in outputs[0]
|
|
317
|
+
|
|
318
|
+
# Multiple commands should raise exception
|
|
319
|
+
cmd = BashCommand(action_json=Command(command="echo 'hello'\necho world'"))
|
|
320
|
+
outputs, _ = get_tool_output(
|
|
321
|
+
context, cmd, default_enc, 1.0, lambda x, y: ("", 0.0), None
|
|
322
|
+
)
|
|
323
|
+
assert len(outputs) == 1
|
|
324
|
+
assert isinstance(outputs[0], str)
|
|
325
|
+
assert "Error: Command contains multiple statements" in outputs[0]
|
|
326
|
+
|
|
309
327
|
|
|
310
328
|
def test_interaction_commands(context: Context, temp_dir: str) -> None:
|
|
311
329
|
"""Test the various interaction command types."""
|
|
@@ -645,6 +645,21 @@ wheels = [
|
|
|
645
645
|
{ url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 },
|
|
646
646
|
]
|
|
647
647
|
|
|
648
|
+
[[package]]
|
|
649
|
+
name = "psutil"
|
|
650
|
+
version = "7.0.0"
|
|
651
|
+
source = { registry = "https://pypi.org/simple" }
|
|
652
|
+
sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003 }
|
|
653
|
+
wheels = [
|
|
654
|
+
{ url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051 },
|
|
655
|
+
{ url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535 },
|
|
656
|
+
{ url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004 },
|
|
657
|
+
{ url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986 },
|
|
658
|
+
{ url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544 },
|
|
659
|
+
{ url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053 },
|
|
660
|
+
{ url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 },
|
|
661
|
+
]
|
|
662
|
+
|
|
648
663
|
[[package]]
|
|
649
664
|
name = "ptyprocess"
|
|
650
665
|
version = "0.7.0"
|
|
@@ -1104,6 +1119,50 @@ wheels = [
|
|
|
1104
1119
|
{ url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 },
|
|
1105
1120
|
]
|
|
1106
1121
|
|
|
1122
|
+
[[package]]
|
|
1123
|
+
name = "tree-sitter"
|
|
1124
|
+
version = "0.24.0"
|
|
1125
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1126
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a7/a2/698b9d31d08ad5558f8bfbfe3a0781bd4b1f284e89bde3ad18e05101a892/tree-sitter-0.24.0.tar.gz", hash = "sha256:abd95af65ca2f4f7eca356343391ed669e764f37748b5352946f00f7fc78e734", size = 168304 }
|
|
1127
|
+
wheels = [
|
|
1128
|
+
{ url = "https://files.pythonhosted.org/packages/66/08/82aaf7cbea7286ee2a0b43e9b75cb93ac6ac132991b7d3c26ebe5e5235a3/tree_sitter-0.24.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de0fb7c18c6068cacff46250c0a0473e8fc74d673e3e86555f131c2c1346fb13", size = 140733 },
|
|
1129
|
+
{ url = "https://files.pythonhosted.org/packages/8c/bd/1a84574911c40734d80327495e6e218e8f17ef318dd62bb66b55c1e969f5/tree_sitter-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a7c9c89666dea2ce2b2bf98e75f429d2876c569fab966afefdcd71974c6d8538", size = 134243 },
|
|
1130
|
+
{ url = "https://files.pythonhosted.org/packages/46/c1/c2037af2c44996d7bde84eb1c9e42308cc84b547dd6da7f8a8bea33007e1/tree_sitter-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddb113e6b8b3e3b199695b1492a47d87d06c538e63050823d90ef13cac585fd", size = 562030 },
|
|
1131
|
+
{ url = "https://files.pythonhosted.org/packages/4c/aa/2fb4d81886df958e6ec7e370895f7106d46d0bbdcc531768326124dc8972/tree_sitter-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ea01a7003b88b92f7f875da6ba9d5d741e0c84bb1bd92c503c0eecd0ee6409", size = 575585 },
|
|
1132
|
+
{ url = "https://files.pythonhosted.org/packages/e3/3c/5f997ce34c0d1b744e0f0c0757113bdfc173a2e3dadda92c751685cfcbd1/tree_sitter-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:464fa5b2cac63608915a9de8a6efd67a4da1929e603ea86abaeae2cb1fe89921", size = 578203 },
|
|
1133
|
+
{ url = "https://files.pythonhosted.org/packages/d5/1f/f2bc7fa7c3081653ea4f2639e06ff0af4616c47105dbcc0746137da7620d/tree_sitter-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:3b1f3cbd9700e1fba0be2e7d801527e37c49fc02dc140714669144ef6ab58dce", size = 120147 },
|
|
1134
|
+
{ url = "https://files.pythonhosted.org/packages/c0/4c/9add771772c4d72a328e656367ca948e389432548696a3819b69cdd6f41e/tree_sitter-0.24.0-cp311-cp311-win_arm64.whl", hash = "sha256:f3f08a2ca9f600b3758792ba2406971665ffbad810847398d180c48cee174ee2", size = 108302 },
|
|
1135
|
+
{ url = "https://files.pythonhosted.org/packages/e9/57/3a590f287b5aa60c07d5545953912be3d252481bf5e178f750db75572bff/tree_sitter-0.24.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:14beeff5f11e223c37be7d5d119819880601a80d0399abe8c738ae2288804afc", size = 140788 },
|
|
1136
|
+
{ url = "https://files.pythonhosted.org/packages/61/0b/fc289e0cba7dbe77c6655a4dd949cd23c663fd62a8b4d8f02f97e28d7fe5/tree_sitter-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:26a5b130f70d5925d67b47db314da209063664585a2fd36fa69e0717738efaf4", size = 133945 },
|
|
1137
|
+
{ url = "https://files.pythonhosted.org/packages/86/d7/80767238308a137e0b5b5c947aa243e3c1e3e430e6d0d5ae94b9a9ffd1a2/tree_sitter-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fc5c3c26d83c9d0ecb4fc4304fba35f034b7761d35286b936c1db1217558b4e", size = 564819 },
|
|
1138
|
+
{ url = "https://files.pythonhosted.org/packages/bf/b3/6c5574f4b937b836601f5fb556b24804b0a6341f2eb42f40c0e6464339f4/tree_sitter-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:772e1bd8c0931c866b848d0369b32218ac97c24b04790ec4b0e409901945dd8e", size = 579303 },
|
|
1139
|
+
{ url = "https://files.pythonhosted.org/packages/0a/f4/bd0ddf9abe242ea67cca18a64810f8af230fc1ea74b28bb702e838ccd874/tree_sitter-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:24a8dd03b0d6b8812425f3b84d2f4763322684e38baf74e5bb766128b5633dc7", size = 581054 },
|
|
1140
|
+
{ url = "https://files.pythonhosted.org/packages/8c/1c/ff23fa4931b6ef1bbeac461b904ca7e49eaec7e7e5398584e3eef836ec96/tree_sitter-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:f9e8b1605ab60ed43803100f067eed71b0b0e6c1fb9860a262727dbfbbb74751", size = 120221 },
|
|
1141
|
+
{ url = "https://files.pythonhosted.org/packages/b2/2a/9979c626f303177b7612a802237d0533155bf1e425ff6f73cc40f25453e2/tree_sitter-0.24.0-cp312-cp312-win_arm64.whl", hash = "sha256:f733a83d8355fc95561582b66bbea92ffd365c5d7a665bc9ebd25e049c2b2abb", size = 108234 },
|
|
1142
|
+
{ url = "https://files.pythonhosted.org/packages/61/cd/2348339c85803330ce38cee1c6cbbfa78a656b34ff58606ebaf5c9e83bd0/tree_sitter-0.24.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d4a6416ed421c4210f0ca405a4834d5ccfbb8ad6692d4d74f7773ef68f92071", size = 140781 },
|
|
1143
|
+
{ url = "https://files.pythonhosted.org/packages/8b/a3/1ea9d8b64e8dcfcc0051028a9c84a630301290995cd6e947bf88267ef7b1/tree_sitter-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0992d483677e71d5c5d37f30dfb2e3afec2f932a9c53eec4fca13869b788c6c", size = 133928 },
|
|
1144
|
+
{ url = "https://files.pythonhosted.org/packages/fe/ae/55c1055609c9428a4aedf4b164400ab9adb0b1bf1538b51f4b3748a6c983/tree_sitter-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57277a12fbcefb1c8b206186068d456c600dbfbc3fd6c76968ee22614c5cd5ad", size = 564497 },
|
|
1145
|
+
{ url = "https://files.pythonhosted.org/packages/ce/d0/f2ffcd04882c5aa28d205a787353130cbf84b2b8a977fd211bdc3b399ae3/tree_sitter-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25fa22766d63f73716c6fec1a31ee5cf904aa429484256bd5fdf5259051ed74", size = 578917 },
|
|
1146
|
+
{ url = "https://files.pythonhosted.org/packages/af/82/aebe78ea23a2b3a79324993d4915f3093ad1af43d7c2208ee90be9273273/tree_sitter-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7d5d9537507e1c8c5fa9935b34f320bfec4114d675e028f3ad94f11cf9db37b9", size = 581148 },
|
|
1147
|
+
{ url = "https://files.pythonhosted.org/packages/a1/b4/6b0291a590c2b0417cfdb64ccb8ea242f270a46ed429c641fbc2bfab77e0/tree_sitter-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:f58bb4956917715ec4d5a28681829a8dad5c342cafd4aea269f9132a83ca9b34", size = 120207 },
|
|
1148
|
+
{ url = "https://files.pythonhosted.org/packages/a8/18/542fd844b75272630229c9939b03f7db232c71a9d82aadc59c596319ea6a/tree_sitter-0.24.0-cp313-cp313-win_arm64.whl", hash = "sha256:23641bd25dcd4bb0b6fa91b8fb3f46cc9f1c9f475efe4d536d3f1f688d1b84c8", size = 108232 },
|
|
1149
|
+
]
|
|
1150
|
+
|
|
1151
|
+
[[package]]
|
|
1152
|
+
name = "tree-sitter-bash"
|
|
1153
|
+
version = "0.23.3"
|
|
1154
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1155
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7b/e0/1e73a17c5427dc62fc42e29f1e58b3a3c95a8fa314983a37f25a0c15be1f/tree_sitter_bash-0.23.3.tar.gz", hash = "sha256:7b15ed89a1ea8e3e3c2399758746413e464d4c1c3a6d3b75d643ae2bc2fb356b", size = 420078 }
|
|
1156
|
+
wheels = [
|
|
1157
|
+
{ url = "https://files.pythonhosted.org/packages/99/4d/c3a1105be2386fd68f1fe8ab9dac5d0d24011d610af2904f48a836525a73/tree_sitter_bash-0.23.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c1ee7a46fcbfca9937d01056be756631762f53c5afdb8c4ab64eb9fed060896b", size = 194714 },
|
|
1158
|
+
{ url = "https://files.pythonhosted.org/packages/3c/d0/e87e4569a82a29037c06694ed0116c60368edef2d7b822a38514e95360d8/tree_sitter_bash-0.23.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a090118e887bf667d82ae445794906186216f5500e0d2cd58eb499f7502dc57", size = 204226 },
|
|
1159
|
+
{ url = "https://files.pythonhosted.org/packages/c5/a2/216ae6fffbcb0fb831865477f53115930dae5ad1b5a16ed12259c8aaecea/tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4b5dde719291eea3a81b1f9ece6afeee2deadc2b2f769bee92f955da7595cf", size = 265254 },
|
|
1160
|
+
{ url = "https://files.pythonhosted.org/packages/2e/89/5031979dc0be9946e999f790b4ceef42810a819508f77fa4017aad0dd5e2/tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff7bffc3d594e7f1054de051e19df1b24082963598a175dda64083c6b3eea1a", size = 242476 },
|
|
1161
|
+
{ url = "https://files.pythonhosted.org/packages/52/0a/af4df04efbf253a93cc869f710a351ab2462f218135277268865eb599f5d/tree_sitter_bash-0.23.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4427baccbd7549a2ebb1859b6d42cdab0739c05d53c2b3daad9cadc069a7b3f6", size = 230285 },
|
|
1162
|
+
{ url = "https://files.pythonhosted.org/packages/46/86/b1ecfe46a4dbae96a6900a3aa19ceb8d15815b29d924d36f02026780c719/tree_sitter_bash-0.23.3-cp39-abi3-win_amd64.whl", hash = "sha256:525c5cce28a7c5624fb016ac8f3ae33d32968567b718f7878c6351229d2e8394", size = 196940 },
|
|
1163
|
+
{ url = "https://files.pythonhosted.org/packages/e2/1e/cab42516fc72c136d388bfbefe34be9fc109ff5a1fbba3c30209970cd57e/tree_sitter_bash-0.23.3-cp39-abi3-win_arm64.whl", hash = "sha256:1f703d1bf6235355f6c900be64bf9f61fc4b1d0cfed6829b4eeb74a6b41ea910", size = 191919 },
|
|
1164
|
+
]
|
|
1165
|
+
|
|
1107
1166
|
[[package]]
|
|
1108
1167
|
name = "typer"
|
|
1109
1168
|
version = "0.15.1"
|
|
@@ -1128,6 +1187,15 @@ wheels = [
|
|
|
1128
1187
|
{ url = "https://files.pythonhosted.org/packages/37/c6/14c23e04bae6a83e051da86c1670684e59acadab333a8497384aa201defd/types_pexpect-4.9.0.20241208-py3-none-any.whl", hash = "sha256:1928f478528454f0fea3495c16cf1ee2e67fca5c9fe97d60b868ac48c1fd5633", size = 17085 },
|
|
1129
1188
|
]
|
|
1130
1189
|
|
|
1190
|
+
[[package]]
|
|
1191
|
+
name = "types-psutil"
|
|
1192
|
+
version = "7.0.0.20250218"
|
|
1193
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1194
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b5/7c/145600d30456e7ccbb499abcf718aab2bd830e604a0ae8eb32b67cd346a6/types_psutil-7.0.0.20250218.tar.gz", hash = "sha256:1e642cdafe837b240295b23b1cbd4691d80b08a07d29932143cbbae30eb0db9c", size = 19828 }
|
|
1195
|
+
wheels = [
|
|
1196
|
+
{ url = "https://files.pythonhosted.org/packages/50/c8/f4365293408da4a9bcb1849d3efd8c60427cffff68cbb98ab1b81851d8bb/types_psutil-7.0.0.20250218-py3-none-any.whl", hash = "sha256:1447a30c282aafefcf8941ece854e1100eee7b0296a9d9be9977292f0269b121", size = 22763 },
|
|
1197
|
+
]
|
|
1198
|
+
|
|
1131
1199
|
[[package]]
|
|
1132
1200
|
name = "types-toml"
|
|
1133
1201
|
version = "0.10.8.20240310"
|
|
@@ -1170,7 +1238,7 @@ wheels = [
|
|
|
1170
1238
|
|
|
1171
1239
|
[[package]]
|
|
1172
1240
|
name = "wcgw"
|
|
1173
|
-
version = "4.1.
|
|
1241
|
+
version = "4.1.1"
|
|
1174
1242
|
source = { editable = "." }
|
|
1175
1243
|
dependencies = [
|
|
1176
1244
|
{ name = "anthropic" },
|
|
@@ -1178,6 +1246,7 @@ dependencies = [
|
|
|
1178
1246
|
{ name = "openai" },
|
|
1179
1247
|
{ name = "petname" },
|
|
1180
1248
|
{ name = "pexpect" },
|
|
1249
|
+
{ name = "psutil" },
|
|
1181
1250
|
{ name = "pydantic" },
|
|
1182
1251
|
{ name = "pygit2" },
|
|
1183
1252
|
{ name = "pyte" },
|
|
@@ -1202,7 +1271,10 @@ dev = [
|
|
|
1202
1271
|
{ name = "pytest" },
|
|
1203
1272
|
{ name = "pytest-asyncio" },
|
|
1204
1273
|
{ name = "pytest-cov" },
|
|
1274
|
+
{ name = "tree-sitter" },
|
|
1275
|
+
{ name = "tree-sitter-bash" },
|
|
1205
1276
|
{ name = "types-pexpect" },
|
|
1277
|
+
{ name = "types-psutil" },
|
|
1206
1278
|
{ name = "types-toml" },
|
|
1207
1279
|
]
|
|
1208
1280
|
|
|
@@ -1213,6 +1285,7 @@ requires-dist = [
|
|
|
1213
1285
|
{ name = "openai", specifier = ">=1.46.0" },
|
|
1214
1286
|
{ name = "petname", specifier = ">=2.6" },
|
|
1215
1287
|
{ name = "pexpect", specifier = ">=4.9.0" },
|
|
1288
|
+
{ name = "psutil", specifier = ">=7.0.0" },
|
|
1216
1289
|
{ name = "pydantic", specifier = ">=2.9.2" },
|
|
1217
1290
|
{ name = "pygit2", specifier = ">=1.16.0" },
|
|
1218
1291
|
{ name = "pyte", specifier = ">=0.8.2" },
|
|
@@ -1237,7 +1310,10 @@ dev = [
|
|
|
1237
1310
|
{ name = "pytest", specifier = ">=8.0.0" },
|
|
1238
1311
|
{ name = "pytest-asyncio", specifier = ">=0.25.3" },
|
|
1239
1312
|
{ name = "pytest-cov", specifier = ">=4.1.0" },
|
|
1313
|
+
{ name = "tree-sitter", specifier = ">=0.24.0" },
|
|
1314
|
+
{ name = "tree-sitter-bash", specifier = ">=0.23.3" },
|
|
1240
1315
|
{ name = "types-pexpect", specifier = ">=4.9.0.20241208" },
|
|
1316
|
+
{ name = "types-psutil", specifier = ">=7.0.0.20250218" },
|
|
1241
1317
|
{ name = "types-toml", specifier = ">=0.10.8.20240310" },
|
|
1242
1318
|
]
|
|
1243
1319
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py
RENAMED
|
File without changes
|
{wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py
RENAMED
|
File without changes
|
{wcgw-4.1.0 → wcgw-4.1.1}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|