Commit 2d3701b
authored
fix(learn): decode directory names with spaces in Windows project paths (headroomlabs-ai#997) (headroomlabs-ai#1027)
## Description
`headroom learn --apply` crashes with `FileNotFoundError` when the
project lives in a Windows directory whose name contains spaces (e.g.
`C:\Users\user\Desktop\Claude Code Projects`).
Claude Code encodes that path as
`-C-Users-user-Desktop-Claude-Code-Projects`, using `-` for both path
separators *and* spaces. The greedy path decoder walks the real
filesystem to reconstruct the original components, but
`_component_tokenizations()` never tried splitting on spaces — so it
couldn't match `Claude Code Projects` against tokens `["Claude", "Code",
"Projects"]`.
Closes headroomlabs-ai#997
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
## Changes Made
- Added `" "` (space) to the explicit separator list in
`_component_tokenizations()`
- Updated the catch-all regex from `[-._]` to `[-.\s_]` so the combined
split also covers whitespace
- Same change in the hidden-component (dotfile) branch
## Testing
- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] New tests added for new functionality
### Test Output
```text
tests/test_learn/test_scanner.py::TestGreedyPathDecode::test_single_space_in_dirname PASSED
tests/test_learn/test_scanner.py::TestGreedyPathDecode::test_multiple_spaces_in_dirname PASSED
tests/test_learn/test_scanner.py::TestGreedyPathDecode::test_space_nested_path PASSED
tests/test_learn/test_scanner.py::TestDecodeProjectPath::test_windows_path_with_spaces_decoded_via_greedy PASSED
4 passed in 0.64s
```
## Real Behavior Proof
- Environment: Windows 11 Home 10.0.26200, Python 3.10.18
- Exact command / steps: Ran `python -m pytest
tests/test_learn/test_scanner.py -v` on Windows after applying the fix.
Also verified `_component_tokenizations("Claude Code Projects")` returns
`[['Claude Code Projects'], ['Claude', 'Code', 'Projects']]`. The
integration test creates a real temp directory with spaces and asserts
`_decode_project_path()` resolves it correctly.
- Observed result: All 4 new tests pass on Windows. All 34 scanner tests
pass. Ruff check clean.
- Not tested: No manual `headroom learn --apply` end-to-end run, but the
integration test exercises the same `_decode_project_path` code path
with a real temp directory on disk.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
## Additional Notes
The fix follows the exact same pattern used for underscores (issue headroomlabs-ai#159)
and dots (issue headroomlabs-ai#47) — extending the separator list. Spaces are the last
common character that Claude Code flattens to `-` but the decoder didn't
know about.1 parent e616dcf commit 2d3701b
2 files changed
Lines changed: 50 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
397 | 397 | | |
398 | 398 | | |
399 | 399 | | |
400 | | - | |
| 400 | + | |
401 | 401 | | |
402 | | - | |
| 402 | + | |
403 | 403 | | |
404 | 404 | | |
405 | 405 | | |
406 | 406 | | |
407 | 407 | | |
408 | 408 | | |
409 | 409 | | |
410 | | - | |
| 410 | + | |
411 | 411 | | |
412 | | - | |
| 412 | + | |
413 | 413 | | |
414 | 414 | | |
415 | 415 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
107 | 127 | | |
108 | 128 | | |
109 | 129 | | |
| |||
332 | 352 | | |
333 | 353 | | |
334 | 354 | | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
335 | 381 | | |
336 | 382 | | |
337 | 383 | | |
| |||
0 commit comments