Skip to content

1xbet India Forebet Player Tashan From Malaysia Rewarding Broker Gambling

We1win Casino South Betr Rewards Final Verdict Football Packed Pagcor licensed bulletproof gli audited platform endorsed by celebrity sportsman derek ramsay winzir trusted by over 1m philippine bettors winzir is a pagcor licensed online casino and sports betting site in the philippines winzir offer a wide variety of games including classic table games live dealer options and sports betting.

Winbet bg is a platform offering various promotions and betting opportunities for registered users, online sports betting odds uk football f1 more, live 2026 midterm election predictions and odds for senate house and governor races trade real time markets on the world s largest prediction market. 1xbet Betting Philippines Aviator Sports The 1win Easily Positive

1xbet Betting Company Winzir Alphawin Platform Winwin Bet The Alphawin Ecosystem

Betting on sports games is a hobby for many and most people just consider it to be a fun and friendly past time but there are ways to consistently make money on sports betting and the tricks are understanding betting strategy and the We1win Online Casino Desktop Best Elevate Your Sports Llc Best Licensed different types of bets you can make understanding the odds making smart bets and walking away from bad bets it s also important to remember that making.

We1win a malaysian trusted casino online has emerged as the most trusted online gambling platform for bettors we have set up 1win Casino Africa 1win Aviator App Brings Curaçao Range ourselves as a top preference of casino games for all malaysians, how to self exclude from gambling in south africa step by step for every major operator national register and what to expect free and confidential.

Alphawin 2023 Sites Website Betting On Sports Across Global

Onyx odds odds on everything, top 20 betting sites uk 2026 best bookmakers tested and ranked, we1win sports football malaysian sports betting, 1win 1win Aviator Mathematical Bonus We1win2 Verified List Bti Consistently Place token overview a promising digital asset on the rise.

Bet small win big online sports betting, politics prediction markets odds, 1xbet fixed odds sports betting free bets 1win Aviator App Company 1win Sunbet Verified List Afl Rewarding online high odds 24 hour customer service best betting site 1xbet com.

1xbet betting company ᐉ online 1xbet India Online Video Speeds Tashan Win Users Media sports betting 1xbet, we1win is malaysia s most trusted online betting platform play baccarat live poker and slots join now claim your welcome bonus and pay easily with touch n go ewallet, south africa s trusted home for tote betting on horseracing soccer and selected sports play official pools back your favourites and feel the thrill of every win you can bet on us.

Online Sports Betting Tested Deposit Find Some Kalshi Big

We1win malaysia malaysia s 1 online gaming platform play Self Exclusion Deposit Sunbet Online South Africa Speed Sunbet Also 2 000 games including live casino slots sports betting poker claim 200 welcome bonus up to myr 1 000 join free now, sports betting and online sportsbook at fanduel sportsbook.

Browse files
committed
fix(windows): split server commands with Windows rules; export hashes what it writes
shlex.split treats a backslash as an escape, so on Windows a server command like C:\Python312\python.exe -m server lost every backslash and failed to start. split_command uses the CommandLineToArgvW rules there (the inverse of subprocess.list2cmdline), and join_command builds lines it splits back exactly. toolscore export wrote CRLF on Windows after hashing LF text, so the manifest's sha256 did not match the file. The suite passes natively on Windows (1,441 tests).
1 parent 602b26f commit 8d4dd83

14 files changed

Lines changed: 157 additions & 20 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ Toolscore 1.11 speaks the current MCP revision (2026-07-28) and tests remote ser
169169
- The release workflow moves the `v1` tag to each release, so `uses: yotambraun/toolscore@v1` resolves, and is ready for PyPI Trusted Publishing (one line to delete once the publisher is added on PyPI).
170170

171171
### Fixed
172+
- Windows: a server command such as `C:\Python312\python.exe -m server` is split with Windows rules (the inverse of `subprocess.list2cmdline`), where POSIX splitting dropped every backslash; `toolscore export` writes `\n` line endings so the manifest's sha256 matches the file; the fault-injection examples quote their command for the platform.
172173

173174
-**Claude Agent SDK messages yielded no calls.** The SDK's `ToolUseBlock` and `ToolResultBlock` dataclasses carry no `type` field, so `from_claude_agent_sdk()` and auto-detection returned nothing for the messages `query()` yields. Blocks are recognized by class, tool results are paired to their calls (`is_error` makes a call failed), and the `ResultMessage` text is the final answer.
174175
- A `claimed-success` finding said a failed call "was not retried" when a later call to the same tool failed too; it now says "no later call to it succeeded".

‎examples/fault_injection/scripted_agent.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@
2525
fromtoolscore.mcpimportMCPStdioClient
2626

2727
HERE=Path(__file__).resolve().parent
28-
SERVER=shlex.join([sys.executable, "-m", "toolscore.mcp.sample_server"])
28+
# one command line for the platform: Windows quoting on Windows, POSIX elsewhere
29+
SERVER= (
30+
subprocess.list2cmdline([sys.executable, "-m", "toolscore.mcp.sample_server"])
31+
ifsys.platform=="win32"
32+
elseshlex.join([sys.executable, "-m", "toolscore.mcp.sample_server"])
33+
)
2934

3035

3136
defmain() ->int:

‎examples/fault_injection/scripted_injection.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
fromtoolscore.mcpimportMCPStdioClient
2929

3030
HERE=Path(__file__).resolve().parent
31-
SERVER=shlex.join([sys.executable, "-m", "toolscore.mcp.sample_server"])
31+
# one command line for the platform: Windows quoting on Windows, POSIX elsewhere
32+
SERVER= (
33+
subprocess.list2cmdline([sys.executable, "-m", "toolscore.mcp.sample_server"])
34+
ifsys.platform=="win32"
35+
elseshlex.join([sys.executable, "-m", "toolscore.mcp.sample_server"])
36+
)
3237

3338

3439
defmain() ->int:

‎tests/unit/test_cli.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
"""Unit tests for CLI commands."""
22

33
importjson
4-
importshlex
54
importsys
65
frompathlibimportPath
76

87
importpytest
98
fromclick.testingimportCliRunner
109

10+
fromtoolscore._cmdlineimportjoin_command
1111
fromtoolscore.cliimportmain
1212

1313
FIXTURE_SERVER=Path(__file__).resolve().parents[1] /"fixtures"/"fake_mcp_server.py"
@@ -16,7 +16,7 @@
1616
def_fake_server_arg(*extra: str) ->str:
1717
"""Return a single shell-quoted command string launching the fake server."""
1818
parts= [sys.executable, str(FIXTURE_SERVER), *extra]
19-
returnshlex.join(parts)
19+
returnjoin_command(parts)
2020

2121

2222
@pytest.fixture

‎tests/unit/test_cmdline.py‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""split_command: POSIX rules, Windows rules on Windows."""
2+
3+
from __future__ importannotations
4+
5+
importsubprocess
6+
importsys
7+
8+
importpytest
9+
10+
fromtoolscore._cmdlineimport_split_windows, join_command, split_command
11+
12+
CASES= [
13+
["C:\\Python312\\python.exe", "-m", "toolscore.mcp.sample_server"],
14+
["C:\\Program Files\\node\\node.exe", "server.js", "--root", "C:\\data dir\\"],
15+
["python", "server.py", "--instructions", "Always use 'missing_tool' first."],
16+
["tool", 'say "hi"', "a\\\\b", "trailing\\", ""],
17+
]
18+
19+
20+
@pytest.mark.parametrize("argv", CASES)
21+
deftest_windows_split_inverts_list2cmdline(argv: list[str]) ->None:
22+
assert_split_windows(subprocess.list2cmdline(argv)) ==argv
23+
24+
25+
deftest_unquoted_windows_paths_keep_their_backslashes() ->None:
26+
assert_split_windows("C:\\Python312\\python.exe -m pkg") == [
27+
"C:\\Python312\\python.exe",
28+
"-m",
29+
"pkg",
30+
]
31+
32+
33+
@pytest.mark.skipif(sys.platform=="win32", reason="POSIX rules")
34+
deftest_posix_rules_elsewhere() ->None:
35+
assertsplit_command("npx -y '@scope/server' --dir \"a b\"") == [
36+
"npx",
37+
"-y",
38+
"@scope/server",
39+
"--dir",
40+
"a b",
41+
]
42+
43+
44+
@pytest.mark.parametrize("argv", CASES)
45+
deftest_join_and_split_round_trip_on_this_platform(argv: list[str]) ->None:
46+
assertsplit_command(join_command(argv)) ==argv

‎tests/unit/test_config_lint.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ def test_discovers_instruction_files_and_host_configs(tmp_path: Path) -> None:
4545
path.parent.mkdir(parents=True, exist_ok=True)
4646
path.write_text("{}"ifname.endswith(".json") else"# x\n", encoding="utf-8")
4747
instructions, configs=discover_files([tmp_path])
48-
rel=sorted(str(p.relative_to(tmp_path)) forpininstructions)
48+
rel=sorted(p.relative_to(tmp_path).as_posix() forpininstructions)
4949
assertrel==sorted(files[:9])
50-
assertsorted(str(p.relative_to(tmp_path)) forpinconfigs) ==sorted(files[9:13])
50+
assertsorted(p.relative_to(tmp_path).as_posix() forpinconfigs) ==sorted(files[9:13])
5151
# an explicitly named Markdown file is always read
5252
assertdiscover_files([tmp_path/"README.md"])[0] == [tmp_path/"README.md"]
5353

‎tests/unit/test_mcp_proxy.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
importio
66
importjson
7-
importshlex
87
importsys
98
fromtypingimportTYPE_CHECKING
109

1110
importpytest
1211

12+
fromtoolscore._cmdlineimportjoin_command
1313
fromtoolscore.coreimportload_trace
1414
fromtoolscore.mcpimportMCPRecorder, MCPStdioClient, MCPTimeoutError
1515
fromtoolscore.mcp.faultsimport (
@@ -36,7 +36,7 @@ def _proxy(output: Path, spec: Path) -> list[str]:
3636
"from toolscore.cli import main; main()",
3737
"mcp",
3838
"proxy",
39-
shlex.join(SAMPLE),
39+
join_command(SAMPLE),
4040
"--inject",
4141
str(spec),
4242
"-o",
@@ -247,7 +247,7 @@ def test_cli_proxy_without_inject_only_records(tmp_path: Path) -> None:
247247
"from toolscore.cli import main; main()",
248248
"mcp",
249249
"proxy",
250-
shlex.join(SAMPLE),
250+
join_command(SAMPLE),
251251
"-o",
252252
str(out),
253253
]

‎tests/unit/test_mcp_record.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
importio
1010
importjson
1111
importos
12-
importshlex
1312
importsys
1413
importthreading
1514
frompathlibimportPath
1615

1716
fromtoolscoreimportevaluate
17+
fromtoolscore._cmdlineimportjoin_command
1818
fromtoolscore.coreimportload_trace
1919
fromtoolscore.mcpimportMCPRecorder, MCPStdioClient
2020

2121
FIXTURE_SERVER=Path(__file__).resolve().parents[1] /"fixtures"/"fake_mcp_server.py"
2222

2323

2424
def_recorder(output: Path, *server_flags: str) ->list[str]:
25-
server=shlex.join([sys.executable, str(FIXTURE_SERVER), *server_flags])
25+
server=join_command([sys.executable, str(FIXTURE_SERVER), *server_flags])
2626
return [
2727
sys.executable,
2828
"-c",

‎tests/unit/test_sessions.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def test_honesty_and_eval_read_session_files_directly() -> None:
250250

251251
def_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) ->tuple[Path, Path]:
252252
monkeypatch.setenv("HOME", str(tmp_path))
253+
monkeypatch.setenv("USERPROFILE", str(tmp_path)) # Path.home() on Windows
253254
monkeypatch.delenv("CLAUDE_CONFIG_DIR", raising=False)
254255
monkeypatch.delenv("CODEX_HOME", raising=False)
255256
claude=_write_jsonl(
@@ -287,6 +288,7 @@ def test_find_and_summarize_sessions(tmp_path: Path, monkeypatch: pytest.MonkeyP
287288

288289
deftest_config_dir_overrides(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) ->None:
289290
monkeypatch.setenv("HOME", str(tmp_path/"nowhere"))
291+
monkeypatch.setenv("USERPROFILE", str(tmp_path/"nowhere")) # Path.home() on Windows
290292
monkeypatch.setenv("CLAUDE_CONFIG_DIR", str(tmp_path/"cc"))
291293
monkeypatch.setenv("CODEX_HOME", str(tmp_path/"cx"))
292294
a=_write_jsonl(tmp_path/"cc"/"projects"/"p"/"a.jsonl", _claude_session())

‎toolscore/_cmdline.py‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""Split a command line the way the user's platform does."""
2+
3+
from __future__ importannotations
4+
5+
importshlex
6+
importsubprocess
7+
importsys
8+
9+
__all__= ["join_command", "split_command"]
10+
11+
12+
defsplit_command(command: str) ->list[str]:
13+
"""Tokens of ``command``: POSIX shell rules, or Windows rules on Windows.
14+
15+
``shlex.split`` treats a backslash as an escape, which turns a Windows path
16+
such as ``C:\\Python\\python.exe`` into ``C:Pythonpython.exe``. On Windows the
17+
line is split as ``CommandLineToArgvW`` does, the inverse of
18+
``subprocess.list2cmdline``.
19+
"""
20+
ifsys.platform!="win32":
21+
returnshlex.split(command)
22+
return_split_windows(command)
23+
24+
25+
defjoin_command(argv: list[str]) ->str:
26+
"""One command line for ``argv`` that :func:`split_command` splits back into ``argv``."""
27+
returnsubprocess.list2cmdline(argv) ifsys.platform=="win32"elseshlex.join(argv)
28+
29+
30+
def_split_windows(command: str) ->list[str]:
31+
tokens: list[str] = []
32+
current: list[str] = []
33+
in_token=in_quotes=False
34+
i, n=0, len(command)
35+
whilei<n:
36+
ch=command[i]
37+
ifch=="\\":
38+
j=i
39+
whilej<nandcommand[j] =="\\":
40+
j+=1
41+
count=j-i
42+
ifj<nandcommand[j] =='"':
43+
# 2k backslashes + quote: k backslashes, the quote toggles; 2k+1: k and a literal quote
44+
current.append("\\"* (count//2))
45+
ifcount%2:
46+
current.append('"')
47+
j+=1
48+
i=j
49+
else:
50+
current.append("\\"*count)
51+
i=j
52+
in_token=True
53+
continue
54+
ifch=='"':
55+
ifin_quotesandi+1<nandcommand[i+1] =='"':
56+
current.append('"') # "" inside quotes is a literal quote
57+
i+=2
58+
continue
59+
in_quotes=notin_quotes
60+
in_token=True
61+
i+=1
62+
continue
63+
ifchin" \t"andnotin_quotes:
64+
ifin_token:
65+
tokens.append("".join(current))
66+
current, in_token= [], False
67+
i+=1
68+
continue
69+
current.append(ch)
70+
in_token=True
71+
i+=1
72+
ifin_token:
73+
tokens.append("".join(current))
74+
returntokens

0 commit comments

Comments
 (0)