ssmforge 0.2.2__tar.gz → 0.2.3__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.
- {ssmforge-0.2.2/src/ssmforge.egg-info → ssmforge-0.2.3}/PKG-INFO +72 -2
- {ssmforge-0.2.2 → ssmforge-0.2.3}/README.md +71 -1
- {ssmforge-0.2.2 → ssmforge-0.2.3}/pyproject.toml +1 -1
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/__init__.py +1 -1
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/cli.py +177 -9
- {ssmforge-0.2.2 → ssmforge-0.2.3/src/ssmforge.egg-info}/PKG-INFO +72 -2
- {ssmforge-0.2.2 → ssmforge-0.2.3}/LICENSE +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/MANIFEST.in +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/docs/DEPLOY.md +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/docs/INSTALL.md +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/docs/quickstart.md +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/setup.cfg +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/__init__.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/diff.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/graph.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/markdown_render.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/report.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/state_dict_scan.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge/analyze/summary.py +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge.egg-info/SOURCES.txt +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge.egg-info/dependency_links.txt +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge.egg-info/entry_points.txt +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge.egg-info/requires.txt +0 -0
- {ssmforge-0.2.2 → ssmforge-0.2.3}/src/ssmforge.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssmforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Standalone HF architecture analyzer (`ssmforge arch`). Inspects any HuggingFace model and reports architectural quirks — attention biases, fused QKV/gate-up, tied embeddings, GQA, MQA, MoE, sliding window, LayerScale, soft-capping, partial RoPE, MLP type, norm type. Outputs structured JSON + human-readable summary.
|
|
5
5
|
Author: SSMForge Contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -82,6 +82,28 @@ visible *before* you spend the next hour finding out the hard way.
|
|
|
82
82
|
It does **not** modify the model. It does **not** run inference. It only
|
|
83
83
|
inspects.
|
|
84
84
|
|
|
85
|
+
### What's new in 0.2.3
|
|
86
|
+
|
|
87
|
+
| Fix | What was broken |
|
|
88
|
+
|-----|-----------------|
|
|
89
|
+
| `--output` on Git Bash + Windows with unquoted backslash paths | Git Bash strips backslashes from unquoted args, so `--output C:\Users\foo\out.md` reached Python as `C:Usersfooout.md` — silently writing a single literal-named file in the cwd. Pre-parse guard now catches this BEFORE argparse runs and exits 1 with a clear "wrap in double quotes or use forward slashes" hint. |
|
|
90
|
+
| `C:Usersnetge...` (bash-mangled, no separators) detected | The post-write `_check_output_path` was too late. The pre-parse guard catches the mangled pattern early and tells you exactly what bash did to your argument. |
|
|
91
|
+
|
|
92
|
+
**Quote your paths from now on.** Or use forward slashes — they work on both Windows and POSIX.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# ✅ Recommended — works everywhere
|
|
96
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ~/Desktop/report.md
|
|
97
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ./report.md
|
|
98
|
+
python -m ssmforge.cli arch X --graph --format markdown --output "C:/Users/me/Desktop/report.md"
|
|
99
|
+
|
|
100
|
+
# ❌ These will now fail with a clear error:
|
|
101
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:\Users\me\Desktop\report.md
|
|
102
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:UsersmeDesktopreport.md
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Plus 9 new tests (174 total).
|
|
106
|
+
|
|
85
107
|
### What's new in 0.2.2
|
|
86
108
|
|
|
87
109
|
| Fix | What was broken |
|
|
@@ -1400,7 +1422,55 @@ install.
|
|
|
1400
1422
|
|
|
1401
1423
|
## 16. Update log
|
|
1402
1424
|
|
|
1403
|
-
### v0.2.
|
|
1425
|
+
### v0.2.3 (current) — 2026-09-23
|
|
1426
|
+
|
|
1427
|
+
**Bug fix: Git Bash strips backslashes from unquoted `--output` args**
|
|
1428
|
+
|
|
1429
|
+
When you run on Git Bash + Windows and pass an unquoted Windows path:
|
|
1430
|
+
```bash
|
|
1431
|
+
python -m ssmforge.cli arch X --graph --format markdown \
|
|
1432
|
+
--output C:\Users\netge\Desktop\report.md
|
|
1433
|
+
```
|
|
1434
|
+
|
|
1435
|
+
Git Bash sees the backslashes as path separators and strips them
|
|
1436
|
+
**before** passing the argument to Python. Python receives:
|
|
1437
|
+
```
|
|
1438
|
+
--output C:UsersnetgeDesktopreport.md
|
|
1439
|
+
```
|
|
1440
|
+
which is interpreted as a single literal filename containing no
|
|
1441
|
+
separators. The CLI then writes a file named
|
|
1442
|
+
`./C:UsersnetgeDesktopreport.md` in the current directory — totally
|
|
1443
|
+
wrong, and v0.2.2 didn't catch it.
|
|
1444
|
+
|
|
1445
|
+
**v0.2.3 fixes this with a pre-parse guard** that runs before argparse
|
|
1446
|
+
and checks for:
|
|
1447
|
+
|
|
1448
|
+
1. **Literal backslash paths** (`C:\\file.md`) — caught with hint to
|
|
1449
|
+
use forward slashes or wrap in quotes.
|
|
1450
|
+
2. **Bash-mangled paths** (`C:UsersnetgeDesktop.md`) — caught with
|
|
1451
|
+
hint explaining what bash did to the argument.
|
|
1452
|
+
|
|
1453
|
+
The error fires immediately, before any model is loaded:
|
|
1454
|
+
|
|
1455
|
+
```
|
|
1456
|
+
Error: --output value looks like a bash-mangled Windows path.
|
|
1457
|
+
Got: 'C:UsersnetgeDesktopreport.md'
|
|
1458
|
+
Git Bash strips backslashes from unquoted arguments.
|
|
1459
|
+
Wrap the value in double quotes, e.g.:
|
|
1460
|
+
--output "C:\Users\netge\Desktop\report.md"
|
|
1461
|
+
Or use forward slashes (works on both Windows and POSIX):
|
|
1462
|
+
--output C:/Users/netge/Desktop/report.md
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
**Recommended from v0.2.3 onward:** quote all `--output` paths, or
|
|
1466
|
+
use forward slashes.
|
|
1467
|
+
|
|
1468
|
+
Tests: 174 passed (was 165). 9 new tests for the pre-parse guard
|
|
1469
|
+
covering bash-mangled separate-args, bash-mangled equals-form,
|
|
1470
|
+
backslash-only paths, plain POSIX paths, forward-slash Windows paths,
|
|
1471
|
+
and bare drive-letter patterns.
|
|
1472
|
+
|
|
1473
|
+
### v0.2.2 — 2026-09-23
|
|
1404
1474
|
|
|
1405
1475
|
**Bug fix: `--output PATH` directory validation**
|
|
1406
1476
|
|
|
@@ -59,6 +59,28 @@ visible *before* you spend the next hour finding out the hard way.
|
|
|
59
59
|
It does **not** modify the model. It does **not** run inference. It only
|
|
60
60
|
inspects.
|
|
61
61
|
|
|
62
|
+
### What's new in 0.2.3
|
|
63
|
+
|
|
64
|
+
| Fix | What was broken |
|
|
65
|
+
|-----|-----------------|
|
|
66
|
+
| `--output` on Git Bash + Windows with unquoted backslash paths | Git Bash strips backslashes from unquoted args, so `--output C:\Users\foo\out.md` reached Python as `C:Usersfooout.md` — silently writing a single literal-named file in the cwd. Pre-parse guard now catches this BEFORE argparse runs and exits 1 with a clear "wrap in double quotes or use forward slashes" hint. |
|
|
67
|
+
| `C:Usersnetge...` (bash-mangled, no separators) detected | The post-write `_check_output_path` was too late. The pre-parse guard catches the mangled pattern early and tells you exactly what bash did to your argument. |
|
|
68
|
+
|
|
69
|
+
**Quote your paths from now on.** Or use forward slashes — they work on both Windows and POSIX.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# ✅ Recommended — works everywhere
|
|
73
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ~/Desktop/report.md
|
|
74
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ./report.md
|
|
75
|
+
python -m ssmforge.cli arch X --graph --format markdown --output "C:/Users/me/Desktop/report.md"
|
|
76
|
+
|
|
77
|
+
# ❌ These will now fail with a clear error:
|
|
78
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:\Users\me\Desktop\report.md
|
|
79
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:UsersmeDesktopreport.md
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Plus 9 new tests (174 total).
|
|
83
|
+
|
|
62
84
|
### What's new in 0.2.2
|
|
63
85
|
|
|
64
86
|
| Fix | What was broken |
|
|
@@ -1377,7 +1399,55 @@ install.
|
|
|
1377
1399
|
|
|
1378
1400
|
## 16. Update log
|
|
1379
1401
|
|
|
1380
|
-
### v0.2.
|
|
1402
|
+
### v0.2.3 (current) — 2026-09-23
|
|
1403
|
+
|
|
1404
|
+
**Bug fix: Git Bash strips backslashes from unquoted `--output` args**
|
|
1405
|
+
|
|
1406
|
+
When you run on Git Bash + Windows and pass an unquoted Windows path:
|
|
1407
|
+
```bash
|
|
1408
|
+
python -m ssmforge.cli arch X --graph --format markdown \
|
|
1409
|
+
--output C:\Users\netge\Desktop\report.md
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
Git Bash sees the backslashes as path separators and strips them
|
|
1413
|
+
**before** passing the argument to Python. Python receives:
|
|
1414
|
+
```
|
|
1415
|
+
--output C:UsersnetgeDesktopreport.md
|
|
1416
|
+
```
|
|
1417
|
+
which is interpreted as a single literal filename containing no
|
|
1418
|
+
separators. The CLI then writes a file named
|
|
1419
|
+
`./C:UsersnetgeDesktopreport.md` in the current directory — totally
|
|
1420
|
+
wrong, and v0.2.2 didn't catch it.
|
|
1421
|
+
|
|
1422
|
+
**v0.2.3 fixes this with a pre-parse guard** that runs before argparse
|
|
1423
|
+
and checks for:
|
|
1424
|
+
|
|
1425
|
+
1. **Literal backslash paths** (`C:\\file.md`) — caught with hint to
|
|
1426
|
+
use forward slashes or wrap in quotes.
|
|
1427
|
+
2. **Bash-mangled paths** (`C:UsersnetgeDesktop.md`) — caught with
|
|
1428
|
+
hint explaining what bash did to the argument.
|
|
1429
|
+
|
|
1430
|
+
The error fires immediately, before any model is loaded:
|
|
1431
|
+
|
|
1432
|
+
```
|
|
1433
|
+
Error: --output value looks like a bash-mangled Windows path.
|
|
1434
|
+
Got: 'C:UsersnetgeDesktopreport.md'
|
|
1435
|
+
Git Bash strips backslashes from unquoted arguments.
|
|
1436
|
+
Wrap the value in double quotes, e.g.:
|
|
1437
|
+
--output "C:\Users\netge\Desktop\report.md"
|
|
1438
|
+
Or use forward slashes (works on both Windows and POSIX):
|
|
1439
|
+
--output C:/Users/netge/Desktop/report.md
|
|
1440
|
+
```
|
|
1441
|
+
|
|
1442
|
+
**Recommended from v0.2.3 onward:** quote all `--output` paths, or
|
|
1443
|
+
use forward slashes.
|
|
1444
|
+
|
|
1445
|
+
Tests: 174 passed (was 165). 9 new tests for the pre-parse guard
|
|
1446
|
+
covering bash-mangled separate-args, bash-mangled equals-form,
|
|
1447
|
+
backslash-only paths, plain POSIX paths, forward-slash Windows paths,
|
|
1448
|
+
and bare drive-letter patterns.
|
|
1449
|
+
|
|
1450
|
+
### v0.2.2 — 2026-09-23
|
|
1381
1451
|
|
|
1382
1452
|
**Bug fix: `--output PATH` directory validation**
|
|
1383
1453
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ssmforge"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.3"
|
|
8
8
|
description = "Standalone HF architecture analyzer (`ssmforge arch`). Inspects any HuggingFace model and reports architectural quirks — attention biases, fused QKV/gate-up, tied embeddings, GQA, MQA, MoE, sliding window, LayerScale, soft-capping, partial RoPE, MLP type, norm type. Outputs structured JSON + human-readable summary."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -290,22 +290,67 @@ def _check_output_path(output_path: str | None) -> tuple[Path | None, str | None
|
|
|
290
290
|
- ``(parent_dir, None)`` when the directory exists and is writable.
|
|
291
291
|
- ``(parent_dir, error_message)`` when the path can't be written.
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
Detects two common Windows-MINGW64 traps:
|
|
294
|
+
1. Literal backslash paths (`C:\\file.md` unquoted) — POSIX `Path`
|
|
295
|
+
treats them as single-component filenames. Hint: quote it.
|
|
296
|
+
2. Bash-mangled paths (`C:UsersnetgeDesktop.md`) — when Git Bash
|
|
297
|
+
strips backslashes from an unquoted argument, the resulting
|
|
298
|
+
string looks like a Windows drive path with no separators. Hint:
|
|
299
|
+
quote the argument or use forward slashes.
|
|
296
300
|
"""
|
|
297
301
|
if not output_path or output_path == "-":
|
|
298
302
|
return None, None
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
+
|
|
304
|
+
raw = output_path
|
|
305
|
+
bs = chr(92)
|
|
306
|
+
fs = "/"
|
|
307
|
+
|
|
308
|
+
# Trap 1: Literal backslashes without forward slashes — POSIX `Path`
|
|
309
|
+
# will treat this as a single filename, not a path.
|
|
310
|
+
if bs in raw and fs not in raw:
|
|
311
|
+
return None, (
|
|
312
|
+
f"Error: output path uses backslashes without forward slashes.\n"
|
|
313
|
+
f" Got: {raw!r}\n"
|
|
314
|
+
f" On Git Bash + Windows, backslash paths must be quoted:\n"
|
|
315
|
+
f" --output \"{raw}\" # wrap in double quotes\n"
|
|
316
|
+
f" Or use forward slashes (work on both Windows and POSIX):\n"
|
|
317
|
+
f" --output {raw.replace(bs, fs)}"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
# Trap 2: Bash-mangled Windows path — `C:` followed by a sequence of
|
|
321
|
+
# identifiers concatenated without separators. Real Windows paths
|
|
322
|
+
# always contain separators between components.
|
|
323
|
+
if (
|
|
324
|
+
len(raw) >= 3
|
|
325
|
+
and raw[1] == ":"
|
|
326
|
+
and raw[0].isalpha()
|
|
327
|
+
and fs not in raw
|
|
328
|
+
and bs not in raw
|
|
329
|
+
and len(raw) > 2
|
|
330
|
+
):
|
|
331
|
+
# Looks like `C:UsersnetgeDesktop` (bash mangled) instead of
|
|
332
|
+
# `C:/Users/netge/Desktop` (real path).
|
|
333
|
+
return None, (
|
|
334
|
+
f"Error: output path looks like a Windows path with all separators stripped.\n"
|
|
335
|
+
f" Got: {raw!r}\n"
|
|
336
|
+
f" Git Bash strips backslashes from unquoted arguments. Wrap in quotes:\n"
|
|
337
|
+
f" --output \"C:{bs}Users{bs}netge{bs}Desktop{bs}report.md\"\n"
|
|
338
|
+
f" Or use forward slashes (POSIX-style, works on Windows):\n"
|
|
339
|
+
f" --output C:/Users/netge/Desktop/report.md"
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
# Use os.path for parent resolution to match what write_text will do.
|
|
343
|
+
abs_target = os.path.abspath(raw)
|
|
344
|
+
parent_str = os.path.dirname(abs_target) or "."
|
|
345
|
+
parent = Path(parent_str)
|
|
346
|
+
|
|
303
347
|
# Case 1: parent doesn't exist
|
|
304
348
|
if not parent.exists():
|
|
305
349
|
return parent, (
|
|
306
350
|
f"Error: output directory does not exist: {parent}\n"
|
|
307
351
|
f" Hint: create the directory first, or use a writable location.\n"
|
|
308
|
-
f" Try: --output ./report.md (current working directory)"
|
|
352
|
+
f" Try: --output ./report.md (current working directory)\n"
|
|
353
|
+
f" --output ~/report.md (your home directory)"
|
|
309
354
|
)
|
|
310
355
|
# Case 2: parent exists but is a file (not a dir)
|
|
311
356
|
if parent.is_file():
|
|
@@ -325,12 +370,105 @@ def _check_output_path(output_path: str | None) -> tuple[Path | None, str | None
|
|
|
325
370
|
return parent, None
|
|
326
371
|
|
|
327
372
|
|
|
373
|
+
def _looks_like_bash_mangled_path(value: str) -> bool:
|
|
374
|
+
"""Detect a string that's likely been mangled by Git Bash.
|
|
375
|
+
|
|
376
|
+
Patterns detected:
|
|
377
|
+
- Drive letter + no separators: 'C:UsersnetgeDesktop.md'
|
|
378
|
+
- Drive letter + backslashes only: 'C:\\\\Users\\\\...'
|
|
379
|
+
|
|
380
|
+
Returns True if the value looks like a Windows path whose separators
|
|
381
|
+
have been stripped. Returns False for plain POSIX paths or quoted
|
|
382
|
+
Windows paths (which contain forward slashes or backslashes that
|
|
383
|
+
survived quoting).
|
|
384
|
+
"""
|
|
385
|
+
if len(value) < 3:
|
|
386
|
+
return False
|
|
387
|
+
# Must start with drive letter + colon
|
|
388
|
+
if not (value[0].isalpha() and value[1] == ":"):
|
|
389
|
+
return False
|
|
390
|
+
# Must have no separators (the mangling signature)
|
|
391
|
+
if "/" in value or "\\" in value:
|
|
392
|
+
return False
|
|
393
|
+
# Drive + filename only (`C:foo.md`) is ambiguous on Windows and
|
|
394
|
+
# almost certainly unintended — flag it.
|
|
395
|
+
return True
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _pre_parse_path_guard(argv: list[str]) -> None:
|
|
399
|
+
"""Pre-parse guard: detect bash-mangled --output values BEFORE argparse.
|
|
400
|
+
|
|
401
|
+
Runs before argparse consumes the args. If `--output VALUE` has a
|
|
402
|
+
mangled VALUE, prints a clear error and exits 1 — so the user sees
|
|
403
|
+
the issue immediately rather than after the model loads.
|
|
404
|
+
|
|
405
|
+
Also detects bare backslash paths (with backslashes intact) which
|
|
406
|
+
POSIX Python interprets as literal filenames.
|
|
407
|
+
"""
|
|
408
|
+
bs = chr(92)
|
|
409
|
+
fs = "/"
|
|
410
|
+
i = 0
|
|
411
|
+
while i < len(argv):
|
|
412
|
+
arg = argv[i]
|
|
413
|
+
# --output VALUE (separate args)
|
|
414
|
+
if arg == "--output" or arg == "-o":
|
|
415
|
+
if i + 1 < len(argv):
|
|
416
|
+
value = argv[i + 1]
|
|
417
|
+
if _looks_like_bash_mangled_path(value):
|
|
418
|
+
print(
|
|
419
|
+
f"Error: --output value looks like a bash-mangled Windows path.\n"
|
|
420
|
+
f" Got: {value!r}\n"
|
|
421
|
+
f" Git Bash strips backslashes from unquoted arguments.\n"
|
|
422
|
+
f" Wrap the value in double quotes, e.g.:\n"
|
|
423
|
+
f" --output \"C:{bs}Users{bs}netge{bs}Desktop{bs}report.md\"\n"
|
|
424
|
+
f" Or use forward slashes (works on both Windows and POSIX):\n"
|
|
425
|
+
f" --output C:/Users/netge/Desktop/report.md",
|
|
426
|
+
file=sys.stderr,
|
|
427
|
+
)
|
|
428
|
+
sys.exit(1)
|
|
429
|
+
if bs in value and fs not in value:
|
|
430
|
+
print(
|
|
431
|
+
f"Error: --output uses backslashes without forward slashes.\n"
|
|
432
|
+
f" Got: {value!r}\n"
|
|
433
|
+
f" Wrap in double quotes:\n"
|
|
434
|
+
f" --output \"{value}\"\n"
|
|
435
|
+
f" Or use forward slashes:\n"
|
|
436
|
+
f" --output {value.replace(bs, fs)}",
|
|
437
|
+
file=sys.stderr,
|
|
438
|
+
)
|
|
439
|
+
sys.exit(1)
|
|
440
|
+
i += 2
|
|
441
|
+
continue
|
|
442
|
+
# --output=VALUE (combined) or --output=anything
|
|
443
|
+
if arg.startswith("--output=") or arg.startswith("-o="):
|
|
444
|
+
value = arg.split("=", 1)[1]
|
|
445
|
+
if _looks_like_bash_mangled_path(value):
|
|
446
|
+
print(
|
|
447
|
+
f"Error: --output value looks like a bash-mangled Windows path.\n"
|
|
448
|
+
f" Got: {value!r}\n"
|
|
449
|
+
f" Wrap the value in double quotes or use forward slashes.",
|
|
450
|
+
file=sys.stderr,
|
|
451
|
+
)
|
|
452
|
+
sys.exit(1)
|
|
453
|
+
if bs in value and fs not in value:
|
|
454
|
+
print(
|
|
455
|
+
f"Error: --output uses backslashes without forward slashes.\n"
|
|
456
|
+
f" Got: {value!r}",
|
|
457
|
+
file=sys.stderr,
|
|
458
|
+
)
|
|
459
|
+
sys.exit(1)
|
|
460
|
+
i += 1
|
|
461
|
+
|
|
462
|
+
|
|
328
463
|
def _write_or_print(text: str, output_path: str | None) -> None:
|
|
329
464
|
"""Write text to a file if path given, else print to stdout.
|
|
330
465
|
|
|
331
466
|
Special-case: if output_path is '-', print to stdout (Unix convention).
|
|
332
467
|
Pre-flight checks the parent directory exists and is writable; on
|
|
333
468
|
failure prints a friendly hint and exits 1.
|
|
469
|
+
After writing, verifies the file exists on disk (defends against
|
|
470
|
+
silently-successful-to-nowhere writes on Windows MINGW64 where
|
|
471
|
+
backslash paths can be misinterpreted as relative filenames).
|
|
334
472
|
"""
|
|
335
473
|
if output_path and output_path != "-":
|
|
336
474
|
parent, err = _check_output_path(output_path)
|
|
@@ -347,7 +485,30 @@ def _write_or_print(text: str, output_path: str | None) -> None:
|
|
|
347
485
|
file=sys.stderr,
|
|
348
486
|
)
|
|
349
487
|
sys.exit(1)
|
|
350
|
-
|
|
488
|
+
# Post-write verification: catch the case where Python writes to a
|
|
489
|
+
# path on disk that the user didn't intend (e.g., a literal
|
|
490
|
+
# 'C:\nope.md' filename in the current directory on POSIX).
|
|
491
|
+
resolved = p.resolve()
|
|
492
|
+
if not resolved.exists():
|
|
493
|
+
print(
|
|
494
|
+
f"Error: write appeared to succeed but file not found.\n"
|
|
495
|
+
f" Target: {resolved}\n"
|
|
496
|
+
f" Hint: try a relative path like --output ./report.md",
|
|
497
|
+
file=sys.stderr,
|
|
498
|
+
)
|
|
499
|
+
sys.exit(1)
|
|
500
|
+
# If the user gave a Windows-style absolute path with backslashes
|
|
501
|
+
# but it landed in the current directory as a literal filename,
|
|
502
|
+
# warn them.
|
|
503
|
+
bs = chr(92)
|
|
504
|
+
if bs in str(output_path) and "/" not in str(output_path) and resolved.parent == Path(".").resolve():
|
|
505
|
+
print(
|
|
506
|
+
f"Warning: wrote to a literal filename {resolved!r}\n"
|
|
507
|
+
f" Did you mean a Windows-style path? On Git Bash + Windows,\n"
|
|
508
|
+
f" use forward slashes: --output {str(output_path).replace(bs, '/')}",
|
|
509
|
+
file=sys.stderr,
|
|
510
|
+
)
|
|
511
|
+
print(f"Report written to {resolved}", file=sys.stderr)
|
|
351
512
|
else:
|
|
352
513
|
print(text)
|
|
353
514
|
|
|
@@ -656,6 +817,13 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
656
817
|
"can use it in scripts.",
|
|
657
818
|
)
|
|
658
819
|
|
|
820
|
+
# Pre-parse guard: catch common path-mangling issues from Git Bash on
|
|
821
|
+
# Windows BEFORE argparse consumes the args. Without this, an unquoted
|
|
822
|
+
# `--output C:\Users\foo\out.md` becomes `C:Usersfooout.md` after bash
|
|
823
|
+
# strips the backslashes, then argparse accepts the garbage silently.
|
|
824
|
+
if argv:
|
|
825
|
+
_pre_parse_path_guard(argv)
|
|
826
|
+
|
|
659
827
|
args = parser.parse_args(argv)
|
|
660
828
|
|
|
661
829
|
if args.command == "arch":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssmforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Standalone HF architecture analyzer (`ssmforge arch`). Inspects any HuggingFace model and reports architectural quirks — attention biases, fused QKV/gate-up, tied embeddings, GQA, MQA, MoE, sliding window, LayerScale, soft-capping, partial RoPE, MLP type, norm type. Outputs structured JSON + human-readable summary.
|
|
5
5
|
Author: SSMForge Contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -82,6 +82,28 @@ visible *before* you spend the next hour finding out the hard way.
|
|
|
82
82
|
It does **not** modify the model. It does **not** run inference. It only
|
|
83
83
|
inspects.
|
|
84
84
|
|
|
85
|
+
### What's new in 0.2.3
|
|
86
|
+
|
|
87
|
+
| Fix | What was broken |
|
|
88
|
+
|-----|-----------------|
|
|
89
|
+
| `--output` on Git Bash + Windows with unquoted backslash paths | Git Bash strips backslashes from unquoted args, so `--output C:\Users\foo\out.md` reached Python as `C:Usersfooout.md` — silently writing a single literal-named file in the cwd. Pre-parse guard now catches this BEFORE argparse runs and exits 1 with a clear "wrap in double quotes or use forward slashes" hint. |
|
|
90
|
+
| `C:Usersnetge...` (bash-mangled, no separators) detected | The post-write `_check_output_path` was too late. The pre-parse guard catches the mangled pattern early and tells you exactly what bash did to your argument. |
|
|
91
|
+
|
|
92
|
+
**Quote your paths from now on.** Or use forward slashes — they work on both Windows and POSIX.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# ✅ Recommended — works everywhere
|
|
96
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ~/Desktop/report.md
|
|
97
|
+
python -m ssmforge.cli arch X --graph --format markdown --output ./report.md
|
|
98
|
+
python -m ssmforge.cli arch X --graph --format markdown --output "C:/Users/me/Desktop/report.md"
|
|
99
|
+
|
|
100
|
+
# ❌ These will now fail with a clear error:
|
|
101
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:\Users\me\Desktop\report.md
|
|
102
|
+
python -m ssmforge.cli arch X --graph --format markdown --output C:UsersmeDesktopreport.md
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Plus 9 new tests (174 total).
|
|
106
|
+
|
|
85
107
|
### What's new in 0.2.2
|
|
86
108
|
|
|
87
109
|
| Fix | What was broken |
|
|
@@ -1400,7 +1422,55 @@ install.
|
|
|
1400
1422
|
|
|
1401
1423
|
## 16. Update log
|
|
1402
1424
|
|
|
1403
|
-
### v0.2.
|
|
1425
|
+
### v0.2.3 (current) — 2026-09-23
|
|
1426
|
+
|
|
1427
|
+
**Bug fix: Git Bash strips backslashes from unquoted `--output` args**
|
|
1428
|
+
|
|
1429
|
+
When you run on Git Bash + Windows and pass an unquoted Windows path:
|
|
1430
|
+
```bash
|
|
1431
|
+
python -m ssmforge.cli arch X --graph --format markdown \
|
|
1432
|
+
--output C:\Users\netge\Desktop\report.md
|
|
1433
|
+
```
|
|
1434
|
+
|
|
1435
|
+
Git Bash sees the backslashes as path separators and strips them
|
|
1436
|
+
**before** passing the argument to Python. Python receives:
|
|
1437
|
+
```
|
|
1438
|
+
--output C:UsersnetgeDesktopreport.md
|
|
1439
|
+
```
|
|
1440
|
+
which is interpreted as a single literal filename containing no
|
|
1441
|
+
separators. The CLI then writes a file named
|
|
1442
|
+
`./C:UsersnetgeDesktopreport.md` in the current directory — totally
|
|
1443
|
+
wrong, and v0.2.2 didn't catch it.
|
|
1444
|
+
|
|
1445
|
+
**v0.2.3 fixes this with a pre-parse guard** that runs before argparse
|
|
1446
|
+
and checks for:
|
|
1447
|
+
|
|
1448
|
+
1. **Literal backslash paths** (`C:\\file.md`) — caught with hint to
|
|
1449
|
+
use forward slashes or wrap in quotes.
|
|
1450
|
+
2. **Bash-mangled paths** (`C:UsersnetgeDesktop.md`) — caught with
|
|
1451
|
+
hint explaining what bash did to the argument.
|
|
1452
|
+
|
|
1453
|
+
The error fires immediately, before any model is loaded:
|
|
1454
|
+
|
|
1455
|
+
```
|
|
1456
|
+
Error: --output value looks like a bash-mangled Windows path.
|
|
1457
|
+
Got: 'C:UsersnetgeDesktopreport.md'
|
|
1458
|
+
Git Bash strips backslashes from unquoted arguments.
|
|
1459
|
+
Wrap the value in double quotes, e.g.:
|
|
1460
|
+
--output "C:\Users\netge\Desktop\report.md"
|
|
1461
|
+
Or use forward slashes (works on both Windows and POSIX):
|
|
1462
|
+
--output C:/Users/netge/Desktop/report.md
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
**Recommended from v0.2.3 onward:** quote all `--output` paths, or
|
|
1466
|
+
use forward slashes.
|
|
1467
|
+
|
|
1468
|
+
Tests: 174 passed (was 165). 9 new tests for the pre-parse guard
|
|
1469
|
+
covering bash-mangled separate-args, bash-mangled equals-form,
|
|
1470
|
+
backslash-only paths, plain POSIX paths, forward-slash Windows paths,
|
|
1471
|
+
and bare drive-letter patterns.
|
|
1472
|
+
|
|
1473
|
+
### v0.2.2 — 2026-09-23
|
|
1404
1474
|
|
|
1405
1475
|
**Bug fix: `--output PATH` directory validation**
|
|
1406
1476
|
|
|
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
|