fix: use POSIX paths in auto-discovery CLI output for Windows compat#1018
Conversation
On Windows, Path.__str__() produces backslash separators, causing format_auto_discovery_message and the script_runner print statement to output paths like 'prompts\hello.md' instead of 'prompts/hello.md'. This broke two tests in test_script_formatters.py on the Windows CI job. Use Path.as_posix() in all three f-string interpolation sites in script_formatters.py and the direct print in script_runner.py to ensure consistent forward-slash output across all platforms. Fixes CI/CD Pipeline failure on windows-latest (run 25036652822). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Normalizes auto-discovery path rendering in CLI output to be stable across platforms (notably Windows), addressing unit test failures caused by backslash path separators.
Changes:
- Switched auto-discovery message formatting to use
Path.as_posix()instead of implicitstr(Path)inScriptExecutionFormatter. - Switched the early auto-discovery
print()inScriptRunner.run_script()to useas_posix()for consistent forward-slash output.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/apm_cli/output/script_formatters.py | Ensures auto-discovery messages render prompt paths with POSIX separators in both rich and fallback branches. |
| src/apm_cli/core/script_runner.py | Ensures the early auto-discovery print uses POSIX separators for Windows-compatible output and tests. |
APM Review Panel VerdictDisposition: APPROVE (with one minor pre-merge action: CHANGELOG entry) Per-persona findingsPython Architect: This is a routine bug-fix PR (4 lines changed, no new abstractions). One class diagram + one execution-flow diagram apply. 1. OO / class diagram classDiagram
direction LR
class ScriptRunner {
<<IOBoundary>>
+run_script(script_name, params) bool
-_discover_prompt_file(name) Path
-_detect_installed_runtime() str
-_generate_runtime_command(runtime, path) str
-_execute_script_command(command, params) bool
}
class ScriptFormatter {
<<Pure>>
+format_auto_discovery_message(name, prompt_file, runtime) str
-_styled(text, style) str
+use_color bool
+console Console
}
class Path {
<<ValueObject>>
+as_posix() str
}
ScriptRunner ..> Path : uses (discovered_prompt)
ScriptRunner ..> ScriptFormatter : delegates formatting
ScriptFormatter ..> Path : formats for display
class ScriptRunner:::touched
class ScriptFormatter:::touched
classDef touched fill:#fff3b0,stroke:#d47600
2. Execution flow diagram flowchart TD
A([apm run SCRIPT_NAME]) --> B[ScriptRunner.run_script]
B --> C{script in apm.yml?}
C -- yes --> D[_execute_script_command]
C -- no --> E["[FS] _discover_prompt_file(name)"]
E --> F{prompt found?}
F -- no --> G[auto-install or error]
F -- yes --> H["print: [i] Auto-discovered: path.as_posix()"]
H --> I[_detect_installed_runtime]
I --> J[_generate_runtime_command]
J --> D
D --> K([exit])
L([format_auto_discovery_message]) --> M{use_color and Rich?}
M -- yes --> N["Rich Text with prompt_file.as_posix()"]
N --> O{Rich exception?}
O -- yes --> P["f-string fallback: prompt_file.as_posix()"]
O -- no --> Q([return formatted string])
M -- no --> P
P --> Q
3. Design patterns
CLI Logging Expert: The DevX UX Expert: Windows CLI output showing backslash paths ( Supply Chain Security Expert: Auth Expert: Not activated -- the two changed files ( OSS Growth Hacker: This fix protects the "first 5 minutes" funnel for Windows users. Garbled backslash paths on a first CEO arbitrationAll five mandatory specialists APPROVE unanimously; there are no disagreements to arbitrate. The fix is a correct, minimal, surgical response to a real Windows CI failure with no behavioral regressions across architecture, output UX, developer ergonomics, or security. The OSS Growth Hacker is right that Windows first-run is a concrete conversion surface worth protecting. One required pre-merge action: add a CHANGELOG entry under Required actions before merge
Optional follow-ups
|
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore(release): cut 0.11.0 Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): tighten 0.11.0 entries to lead with user impact Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): move Dev Container Feature to Maintainer tooling (not yet published) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): de-dupe within 0.11.0 (combine #722 Removed bullets, drop #820 Fixed pointer) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Problem
The CI/CD Pipeline is broken on Windows (run 25036652822). Two unit tests in
test_script_formatters.pyfail becausePath.__str__()uses backslash separators on Windows:Fix
Use
Path.as_posix()instead ofstr(path)/f"{path}"in three sites withinscript_formatters.pyand one inscript_runner.py. This ensures consistent forward-slash output regardless of platform.Files changed
src/apm_cli/output/script_formatters.py-- 3 interpolation sites informat_auto_discovery_messagesrc/apm_cli/core/script_runner.py-- 1 print statement inexecuteValidation
6,627 unit tests pass locally (macOS). The fix is a minimal, surgical change with no behavioural impact beyond normalising path display.