Skip to content

feat: add phase 1 Windows native support#227

Merged
sergio-sisternes-epam merged 17 commits intomicrosoft:mainfrom
sergio-sisternes-epam:feat/88-windows-native-support
Mar 13, 2026
Merged

feat: add phase 1 Windows native support#227
sergio-sisternes-epam merged 17 commits intomicrosoft:mainfrom
sergio-sisternes-epam:feat/88-windows-native-support

Conversation

@sergio-sisternes-epam
Copy link
Collaborator

Description

Add Phase 1 support for issue #88 by shipping a native Windows binary path without taking on runtime setup work yet.

This PR:

  • adds a Windows x86_64 build to the release workflow
  • adds a native PowerShell installer for Windows
  • makes apm update choose the correct installer per platform
  • adds targeted tests for platform-aware update behavior
  • updates docs and README for the Windows install/update story

Fixes #88

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

Local validation run:

  • uv sync --python 3.12 --extra dev --extra build
  • uv run --python 3.12 pytest tests/unit/test_update_command.py -q

@sergio-sisternes-epam sergio-sisternes-epam force-pushed the feat/88-windows-native-support branch from 70a75b7 to 1444ec6 Compare March 10, 2026 17:09
Copy link
Collaborator Author

@sergio-sisternes-epam sergio-sisternes-epam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP: Rebased branch updated from refactoring while it is merged.

@sergio-sisternes-epam sergio-sisternes-epam force-pushed the feat/88-windows-native-support branch from 1444ec6 to 496c9f1 Compare March 10, 2026 19:34
@sergio-sisternes-epam
Copy link
Collaborator Author

sergio-sisternes-epam commented Mar 10, 2026

Phase 3: Windows Package Manager Distribution — Setup Requirements

The CI pipeline includes disabled dispatch jobs for Scoop, Chocolatey, and winget (gated with if: false).
@danielmeppiel To enable each channel, the following infrastructure is needed:


Scoop

  • Create microsoft/scoop-apm repository (a Scoop bucket is just a Git repo with JSON manifests)
  • Add a repository_dispatch workflow listening for bucket-update events that updates the manifest version, URL, and hash
  • Ensure GH_PKG_PAT secret (in microsoft/apm) has repo scope for dispatch to the bucket repo

Ref: Scoop Wiki — Buckets · Consider using BucketTemplate for CI automation (checkver + autoupdate).


Chocolatey

  • Register a Chocolatey account at community.chocolatey.org
  • Obtain an API key from the account page
  • Create microsoft/chocolatey-apm repository with a repository_dispatch workflow listening for package-update events that runs choco pack + choco push --source https://push.chocolatey.org/
  • Store CHOCOLATEY_API_KEY as a secret in microsoft/chocolatey-apm
  • Ensure GH_PKG_PAT secret (in microsoft/apm) has repo scope for dispatch to the Chocolatey repo

Note: Packages go through Chocolatey's moderation review after push. Verified Publisher status is optional but expedites moderation.


winget

  • Create microsoft/winget-apm repository with a repository_dispatch workflow listening for manifest-update events that runs wingetcreate update --submit to auto-PR to microsoft/winget-pkgs
  • Store a GitHub PAT with public_repo scope as WINGET_CREATE_PAT in microsoft/winget-apm (needed by wingetcreate to open PRs against winget-pkgs)
  • Ensure GH_PKG_PAT secret (in microsoft/apm) has repo scope for dispatch to the winget repo

Ref: wingetcreate docs · See PowerToys workflow for a working example.


Enabling the Pipeline

Once the above is in place, remove the false && guard from each job's if: condition in build-release.yml (see TODO comments referencing #88).

@sergio-sisternes-epam
Copy link
Collaborator Author

Why Scoop?

Scoop is included specifically for enterprise developers without admin privileges — a common scenario and the exact use case that motivated #88. Unlike Chocolatey and winget, Scoop installs to ~/scoop with no elevation required, making it the only package manager option for locked-down corporate machines.

The maintenance cost is minimal: a Scoop bucket is a single Git repo with one JSON manifest file — no account registration, no moderation queue, no approval process. Built-in checkver + autoupdate support means the manifest can self-update.

While nobody has explicitly requested Scoop, this is a low-effort addition that covers an important gap in the distribution matrix:

Scenario winget Chocolatey Scoop
Standard Windows user
Enterprise with admin
Enterprise without admin

@sergio-sisternes-epam sergio-sisternes-epam self-assigned this Mar 11, 2026
@sergio-sisternes-epam
Copy link
Collaborator Author

PR Update: Windows native support — cross-platform validation on real Windows machine

Validated all changes on a native Windows 11 machine (Python 3.12, Windows cp1252 locale). This commit addresses every test failure found during that validation.

What changed (69 files, +1187 / -1030):

Source fixes:

  • Removed all non-ASCII characters (emojis, box-drawing, em dashes, etc.) from 38 source files — these caused charmap codec errors on Windows cp1252 terminals
  • Normalized path separators to forward slashes in link_resolver, context_optimizer, hook_integrator, _helpers, unpacker
  • GIT_CONFIG_GLOBAL now uses NUL on Windows instead of /dev/null
  • Git repo handles are explicitly closed before temp directory cleanup on Windows (prevents PermissionError on locked .git files)
  • NPM package version pinning fix in Codex adapter

Test fixes:

  • Wrapped TemporaryDirectory + os.chdir() patterns with try/finally to prevent PermissionError on Windows cleanup
  • Fixed path assertions to be cross-platform (.as_posix(), .endswith(), .replace("\\", "/"))
  • Fixed os.pathsep usage instead of hardcoded : in test_runtime_smoke.py
  • Added skipif(win32) for tests requiring bash, symlinks, or Unix file permissions (4 tests)
  • Updated emoji character assertions to match new ASCII replacements
  • Added new Windows-specific test cases for git environment config and version checker cache paths

Results on Windows:

  • 1828 passed, 102 skipped, 0 failures
  • Windows binary builds and runs (apm.exe --version, --help, init --yes all verified)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “phase 1” native Windows support by shipping a Windows x86_64 release artifact, introducing PowerShell-based installers/runtime setup scripts, and making update/install logic + tests platform-aware (plus ASCII-safe CLI output updates for Windows consoles).

Changes:

  • Add Windows release build (zip) + installer (install.ps1) and PowerShell runtime setup scripts.
  • Make apm update download/execute the correct installer per platform; add/update unit tests for platform branching.
  • Improve cross-platform behavior in core code/tests (path separators, NUL vs /dev/null, skip unsuitable integration tests on Windows) and replace emoji/status glyphs with ASCII-safe markers.

Reviewed changes

Copilot reviewed 83 out of 83 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/unit/test_version_checker.py Adds platform-specific cache-path tests.
tests/unit/test_update_command.py Adds tests ensuring apm update selects PS1 vs SH installer.
tests/unit/test_script_runner.py Normalizes path separators in assertion for Windows.
tests/unit/test_runtime_windows.py Adds Windows-specific RuntimeManager/ScriptRunner behavior tests.
tests/unit/test_runtime_factory.py Makes assertions more defensive via .get() (dict shape variability).
tests/unit/test_mcp_client_factory.py Updates expected warning output to ASCII-safe marker.
tests/unit/test_install_command.py Adds CWD restoration around temp dirs (but currently restores to test dir).
tests/unit/test_init_command.py Adds CWD restoration around temp dirs (but currently restores to test dir).
tests/unit/test_copilot_runtime.py Uses as_posix() for cross-platform path assertions.
tests/unit/test_auth_scoping.py Uses NUL on Windows for git env hardening test.
tests/unit/test_ado_path_structure.py Uses as_posix() to avoid Windows path separator issues.
tests/unit/integration/test_deployed_files_manifest.py Uses as_posix() for deployed file path assertions.
tests/test_runnable_prompts.py Normalizes \ to / for Windows-compatible assertions.
tests/test_github_downloader.py Updates progress/output expectations + adds Windows GIT_CONFIG_GLOBAL tests.
tests/test_apm_resolver.py Updates validity marker to ASCII-safe output.
tests/test_apm_package_models.py Updates validation summary markers to ASCII-safe output.
tests/integration/test_runtime_smoke.py Skips bash-based tests on Windows; uses os.pathsep.
tests/integration/test_plugin_e2e.py Skips symlink test on Windows (admin/privilege constraints).
tests/integration/test_multi_runtime_integration.py Uses .get() in runtime dict assertions.
tests/integration/test_compile_permission_denied.py Skips permission-denied behavior test on Windows.
src/apm_cli/utils/github_host.py Switches bullet formatting to ASCII *.
src/apm_cli/utils/console.py Replaces emoji STATUS_SYMBOLS and removes emoji from table/spinner titles.
src/apm_cli/runtime/manager.py Adds Windows script selection + PowerShell execution path.
src/apm_cli/registry/operations.py Updates env prompt output markers to ASCII-safe.
src/apm_cli/primitives/models.py Normalizes doc text arrows to ASCII.
src/apm_cli/output/script_formatters.py Replaces unicode tree/markers with ASCII-safe equivalents.
src/apm_cli/output/formatters.py Replaces unicode glyphs/arrows with ASCII-safe equivalents throughout output.
src/apm_cli/models/validation.py Updates summary strings + normalizes punctuation in docs/comments.
src/apm_cli/models/dependency.py Normalizes doc/comment arrows/punctuation to ASCII.
src/apm_cli/integration/skill_transformer.py Normalizes doc arrows to ASCII.
src/apm_cli/integration/skill_integrator.py Normalizes doc arrows/punctuation to ASCII.
src/apm_cli/integration/prompt_integrator.py Normalizes comment punctuation to ASCII.
src/apm_cli/integration/mcp_integrator.py Normalizes output markers/tree formatting to ASCII-safe.
src/apm_cli/integration/hook_integrator.py Normalizes comments + improves managed-file path normalization for Windows.
src/apm_cli/integration/base_integrator.py Normalizes comments + path normalization notes.
src/apm_cli/integration/agent_integrator.py Normalizes comment punctuation to ASCII.
src/apm_cli/deps/plugin_parser.py Normalizes docs/comments arrows to ASCII.
src/apm_cli/deps/lockfile.py Normalizes comments arrows to ASCII.
src/apm_cli/deps/github_downloader.py Uses NUL on Windows; adds Windows temp clone cleanup; removes emoji from progress.
src/apm_cli/deps/apm_resolver.py Updates resolution summary markers to ASCII-safe.
src/apm_cli/core/token_manager.py Normalizes docs arrows to ASCII.
src/apm_cli/core/target_detection.py Normalizes docs arrows to ASCII.
src/apm_cli/core/script_runner.py Adds Windows command splitting; normalizes output markers to ASCII-safe.
src/apm_cli/core/safe_installer.py Updates success/warn/error markers to ASCII-safe.
src/apm_cli/compilation/link_resolver.py Normalizes markdown link paths to forward slashes.
src/apm_cli/compilation/distributed_compiler.py Normalizes cleanup output markers to ASCII-safe.
src/apm_cli/compilation/context_optimizer.py Normalizes timing labels + path resolution for Windows.
src/apm_cli/compilation/agents_compiler.py Normalizes preview output glyphs to ASCII-safe.
src/apm_cli/commands/update.py Adds platform-aware installer URL/suffix and PowerShell execution path.
src/apm_cli/commands/uninstall.py Normalizes uninstall output markers to ASCII-safe.
src/apm_cli/commands/runtime.py Normalizes table titles/status output to ASCII-safe; updates arrows.
src/apm_cli/commands/run.py Normalizes panel titles/output glyphs to ASCII-safe.
src/apm_cli/commands/prune.py Normalizes prune output markers to ASCII-safe.
src/apm_cli/commands/pack.py Normalizes pack/unpack output glyphs to ASCII-safe.
src/apm_cli/commands/mcp.py Normalizes MCP command output glyphs to ASCII-safe.
src/apm_cli/commands/list_cmd.py Normalizes list output/table titles to ASCII-safe.
src/apm_cli/commands/init.py Normalizes init output/table content to ASCII-safe.
src/apm_cli/commands/deps.py Normalizes deps output/tree drawing to ASCII-safe; warning markers updated.
src/apm_cli/commands/config.py Normalizes config table title to ASCII-safe.
src/apm_cli/commands/compile.py Normalizes compile help/output bullets and error markers to ASCII-safe.
src/apm_cli/commands/_helpers.py Uses as_posix() for expected install path tracking.
src/apm_cli/cli.py Normalizes module doc punctuation to ASCII.
src/apm_cli/bundle/unpacker.py Tightens unsafe path checks when unpacking.
src/apm_cli/bundle/packer.py Normalizes error message punctuation to ASCII.
src/apm_cli/bundle/lockfile_enrichment.py Normalizes doc punctuation to ASCII.
src/apm_cli/adapters/client/vscode.py Normalizes comment punctuation to ASCII.
src/apm_cli/adapters/client/copilot.py Normalizes comment/output punctuation to ASCII.
src/apm_cli/adapters/client/codex.py Normalizes warning output; improves npm args to use versioned package name.
scripts/runtime/setup-llm.ps1 Adds Windows runtime setup for llm.
scripts/runtime/setup-copilot.ps1 Adds Windows runtime setup for Copilot CLI.
scripts/runtime/setup-common.ps1 Adds shared PowerShell helpers for runtime setup scripts.
scripts/runtime/setup-codex.ps1 Adds Windows runtime setup for Codex binary.
scripts/github-token-helper.ps1 Adds standalone PowerShell token helper with precedence rules.
install.ps1 Adds Windows installer that downloads/installs the Windows zip release (with pip fallback).
docs/getting-started.md Documents Windows install/update and runtime setup.
docs/cli-reference.md Updates install/update docs for Windows installer + manual download steps.
README.md Adds Windows PowerShell install snippet and notes Windows binaries.
.github/workflows/ci.yml Adds Windows PR test job; build waits on both Linux+Windows tests.
.github/workflows/build-release.yml Adds Windows build/test/release-validation + Windows zip packaging.
.github/instructions/cicd.instructions.md Updates CI/CD docs to reflect Windows coverage.

You can also share your feedback on Copilot code review. Take the survey.

@sergio-sisternes-epam
Copy link
Collaborator Author

@copilot open a new pull request to apply changes based on the comments in this thread

sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 11, 2026
- Fix CWD restoration in test_init_command.py and test_install_command.py
  to use self.original_dir instead of __file__ directory (19 occurrences)
- Remove unsupported UseBasicParsing from Invoke-RestMethod in setup-codex.ps1
- Fix uv PATH in build-release.yml build job: .cargo\bin -> .local\bin
  to match other Windows jobs in the workflow
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 87 out of 87 changed files in this pull request and generated 4 comments.


You can also share your feedback on Copilot code review. Take the survey.

sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 11, 2026
- Fix CWD restoration in test_init_command.py and test_install_command.py
  to use self.original_dir instead of __file__ directory (19 occurrences)
- Remove unsupported UseBasicParsing from Invoke-RestMethod in setup-codex.ps1
- Fix uv PATH in build-release.yml build job: .cargo\bin -> .local\bin
  to match other Windows jobs in the workflow
@sergio-sisternes-epam sergio-sisternes-epam force-pushed the feat/88-windows-native-support branch from ef6de06 to 155fd8f Compare March 11, 2026 19:06
sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 12, 2026
- Fix CWD restoration in test_init_command.py and test_install_command.py
  to use self.original_dir instead of __file__ directory (19 occurrences)
- Remove unsupported UseBasicParsing from Invoke-RestMethod in setup-codex.ps1
- Fix uv PATH in build-release.yml build job: .cargo\bin -> .local\bin
  to match other Windows jobs in the workflow
@sergio-sisternes-epam sergio-sisternes-epam force-pushed the feat/88-windows-native-support branch from 398b3be to 8645de8 Compare March 12, 2026 09:42
Copy link
Collaborator

@danielmeppiel danielmeppiel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Windows Native Support (Phase 1)

Thanks for the solid work on Windows support, Sergio. The architectural approach is right — PyInstaller binary, PowerShell installer at %LOCALAPPDATA%\Programs\apm, platform-aware update routing, .ps1/.sh script selection in the runtime manager. These are good design decisions.

After a thorough review across CI/CD, PowerShell scripts, core source, and tests, there are a few items that need to be addressed before this can merge.


1. Windows must NOT be in PR CI — follow the macOS precedent

Files: ci.yml, ci-integration.yml

Our established philosophy is Linux-only for PR CI (fast, cheap feedback) with full platform coverage only in build-release.yml on release. macOS has zero presence in ci.yml or ci-integration.yml — Windows must follow the same pattern.

Currently, this PR adds test-windows and build-windows jobs to ci.yml, and 3 Windows jobs to ci-integration.yml. This doubles PR CI time and cost, and creates a coupling where a Windows test failure blocks the Linux binary build (needs: [test, test-windows]).

What to do:

  • Remove all Windows jobs from ci.yml and ci-integration.yml
  • Add windows-latest as a matrix entry in build-release.yml alongside the existing 4 platforms (ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-latest)
  • Follow the exact pattern macOS uses: Windows builds and tests run post-merge on push to main and on tag releases

This keeps PR feedback fast (~3 min, Linux-only) while ensuring Windows is validated on every push to main and every release.


2. STATUS_SYMBOLS inconsistency after Unicode replacement

File: src/apm_cli/utils/console.py

The Unicode→ASCII replacement is accepted as in-scope, but it creates an inconsistency: STATUS_SYMBOLS still contains emojis (, 🚀, ⚙️, 💡, ⚠️, , etc.) which are used by _rich_echo(), _rich_info(), _rich_warning(), and other helpers. Meanwhile, inline emojis in ~40 other files have been replaced with ASCII brackets ([+], [!], etc.) or removed entirely.

Post-merge, _rich_info("message", symbol="info") would print 💡 message while a direct click.echo() next to it would print [i] message. This is visually incoherent.

What to do: Update STATUS_SYMBOLS to use the same ASCII bracket notation used everywhere else, or better yet, make the symbols conditional on terminal capability (Rich already does this). The key requirement is internal consistency.


3. for_allinstruction typo in context_optimizer.py

File: src/apm_cli/compilation/context_optimizer.py

The (for-all) symbol was replaced with for_all but the space between it and the next word was lost:

# Current (broken):
"subject to: for_allinstruction -> existsplacement"

# Should be:
"subject to: for_all instruction -> exists placement"

Same issue with exists. Small fix but ships a visible bug in compile verbose output.


4. Checksum verification missing from install.ps1

File: install.ps1

The build pipeline generates .sha256 sidecar files for every release artifact, but the installer downloads and extracts the zip without verifying the checksum. The Bash installer has the same gap, but since we are writing a new installer from scratch, we should do it right.

What to do: After downloading apm-windows-x86_64.zip, also download apm-windows-x86_64.zip.sha256, verify with Get-FileHash, and fail with a clear error if the hashes don't match. This is ~5 lines of PowerShell:

$expectedHash = (Invoke-RestMethod -Uri $sha256Url).Split(" ")[0]
$actualHash = (Get-FileHash -Path $zipPath -Algorithm SHA256).Hash
if ($actualHash -ne $expectedHash) {
    Write-ErrorText "Checksum verification failed. Download may be corrupted."
    exit 1
}

5. $LASTEXITCODE lost after pipe in install.ps1

File: install.ps1, around the pip fallback logic

& $pipCmd install --user apm-cli 2>&1 | Write-Host
if ($LASTEXITCODE -ne 0) { ... }

Piping to Write-Host overwrites $LASTEXITCODE with the pipeline's result, masking pip failures. Fix:

$output = & $pipCmd install --user apm-cli 2>&1
$pipExit = $LASTEXITCODE
$output | Write-Host
if ($pipExit -ne 0) { ... }

6. Unrelated functional change in codex.py

File: src/apm_cli/adapters/client/codex.py

This change adds NPM versioned package name support (package@version):

version = package.get("version", "")
versioned_name = f"{package_name}@{version}" if version else package_name

This is a functional change unrelated to Windows support. It should either be extracted to its own PR with tests, or at minimum called out in the PR description so reviewers can evaluate it independently.


Non-blocking observations (for follow-up)

These are fine to address in subsequent PRs:

  • Old release versions accumulateinstall.ps1 creates releases\v1.0.0\, releases\v1.1.0\ etc. but never cleans up previous versions. Consider adding cleanup after successful install.
  • No UPX compression for Windows — Linux/macOS install UPX; Windows binaries will be ~50% larger. Add choco install upx or download from GitHub in the build step if desired.
  • ARM64 inconsistency — Installer hardcodes x86_64 (fine, emulation works), but setup-codex.ps1 maps ARM64 to aarch64-pc-windows-msvc. Align the story.
  • Temp file collision in test scriptstest-release-validation.ps1 uses fixed temp file names without PID/GUID suffix. Low risk but worth fixing.
  • Chocolatey/Scoop/winget stubs — The if: false gated stubs follow the Homebrew dispatch pattern correctly. Recommend shipping Scoop first (lowest friction), then winget, then Chocolatey. Note that winget's standard flow is PRs to microsoft/winget-pkgs — clarify if the dispatch approach targets a custom manifest repo or automates those PRs.

Summary

The Windows platform architecture is sound. The six items above are the delta between a good PR and a great one. Items 1–5 are required changes; item 6 is a strong recommendation. Looking forward to the next iteration.

@danielmeppiel danielmeppiel added the priority/high Ships in current or next milestone label Mar 12, 2026
@danielmeppiel
Copy link
Collaborator

One more thing on the package manager stubs:

Please remove the Chocolatey and winget jobs entirely. We will only ship Scoop for Windows package management.

Reasoning: Chocolatey requires community moderation (days for approval on each release — we do not control our own release cadence). winget requires PRs to microsoft/winget-pkgs or a custom manifest repo. Both create dependencies on external repos approving our releases, which is unacceptable for a fast-iterating project.

Scoop is self-hosted (we own microsoft/scoop-apm), the bucket update is a simple JSON file push via repository-dispatch, and it follows the exact same pattern as our Homebrew tap. One repo, no external approval gates.

What to do:

  • Keep the update-scoop job (currently gated with if: false — fine)
  • Remove the update-chocolatey and update-winget jobs
  • Remove the Chocolatey and winget install snippets from the docs/installation page
  • Keep the Scoop install snippet

We can revisit Chocolatey/winget later if there is community demand, but we are not taking on that operational overhead now.

sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 12, 2026
- Remove Windows jobs from PR CI (ci.yml): drop test-windows and build-windows
- Remove Windows jobs from ci-integration.yml: drop smoke-test-windows,
  integration-tests-windows, release-validation-windows; update report-status
- Remove Chocolatey and winget dispatch jobs from build-release.yml (keep Scoop)
- Remove Chocolatey/winget from installation docs, simplify to Scoop-only
- Fix STATUS_SYMBOLS in console.py: use bracket notation to match codebase
- Fix typo in context_optimizer.py: for_allinstruction -> for_all instruction
- Add SHA256 checksum verification to install.ps1 after zip download
- Fix $LASTEXITCODE lost in pipe to Write-Host in install.ps1 pip fallback
- Revert unrelated NPM versioned package name change in codex.py
@sergio-sisternes-epam
Copy link
Collaborator Author

Thanks for the thorough review, @danielmeppiel! Really appreciate the detailed feedback — all items addressed in ea13e63:

  1. Removed Windows from PR CI — dropped test-windows and build-windows from ci.yml, and all three Windows jobs (smoke-test-windows, integration-tests-windows, release-validation-windows) from ci-integration.yml. Updated report-status accordingly. Windows coverage stays in build-release.yml post-merge.
  2. Removed Chocolatey & winget — deleted both dispatch jobs from build-release.yml and their install snippets from the docs. Scoop is the only Windows package manager for now; we've created separate sub-tasks to add Chocolatey and winget support once the downstream repos and secrets are ready.
  3. STATUS_SYMBOLS — switched to bracket notation ([+], [!], [i], etc.) to match the convention used across ~40 other files.
  4. for_allinstruction typo — fixed the missing spaces in the docstring.
  5. install.ps1 hardening — added SHA256 checksum verification after the zip download, and fixed $LASTEXITCODE being lost by the pipe to Write-Host (now captured before piping).
  6. codex.py — reverted the unrelated NPM versioned package name change; will handle that in a separate PR.

All 1,457 tests passing. Ready for another look when you get a chance!

…ft#88)

- RuntimeManager: platform-aware script selection, PowerShell execution
- ScriptRunner: platform-aware command parsing for Windows
- PowerShell runtime scripts with PSScriptAnalyzer-clean verb naming
- install.ps1: hardened with download fallback, pip fallback, binary test
- Release validation: full test-release-validation.ps1 port
- CI: Windows added to test, integration, release-validation matrices
- Tests: 19 new unit tests for Windows platform support
- Docs: updated getting-started and cli-reference for Windows
…, winget)

- Add disabled CI dispatch jobs for Scoop, Chocolatey, and winget
- Remove Windows checksums from Homebrew update job
- Add Windows package manager install commands to getting-started.md

Part of microsoft#88
Use [INFO], [OK], [WARN], [ERROR] instead of emoji characters for
cross-platform terminal compatibility.
Windows builds use PowerShell in CI; bash script is not needed for Windows.
- Remove all non-ASCII characters from source (fixes cp1252 charmap encoding errors)
- Fix path separator issues: normalize to forward slashes in link_resolver, context_optimizer, hook_integrator, _helpers, unpacker
- Fix GIT_CONFIG_GLOBAL to use NUL on Windows instead of /dev/null
- Fix git repo handle cleanup on Windows (explicit close + gc.collect before temp dir removal)
- Fix TemporaryDirectory cleanup in tests (try/finally for os.chdir patterns)
- Fix PATH separator in test_runtime_smoke.py (os.pathsep instead of hardcoded ':')
- Fix path assertions in tests to be cross-platform (.as_posix(), .endswith(), .replace)
- Add platform skip decorators for bash-only, symlink, and chmod tests
- Add Windows-specific tests for git env, version checker cache path
- All 1828 tests pass on Windows (102 skipped)
- Add test-windows job running on windows-latest in parallel with Linux
- Uses PowerShell uv installer and Windows-appropriate cache paths
- Build job now depends on both test and test-windows passing
- Catches path separator, encoding, and platform-specific issues before merge
- Fix CWD restoration in test_init_command.py and test_install_command.py
  to use self.original_dir instead of __file__ directory (19 occurrences)
- Remove unsupported UseBasicParsing from Invoke-RestMethod in setup-codex.ps1
- Fix uv PATH in build-release.yml build job: .cargo\bin -> .local\bin
  to match other Windows jobs in the workflow
- ci.yml: add build-windows job (binary build + artifact upload)
- ci-integration.yml: add smoke-test-windows, integration-tests-windows,
  release-validation-windows jobs mirroring Linux pipeline
- build-release.yml: include dependency integration scripts in artifacts
- New: scripts/test-integration.ps1 (PowerShell integration test runner)
- New: scripts/test-dependency-integration.ps1 (dependency integration tests)
- Update report-status to depend on all 6 jobs (Linux + Windows)
- New: scripts/build-binary.ps1 (PowerShell equivalent of build-binary.sh)
- ci.yml: build-windows job now uses build-binary.ps1 instead of bash
- build-release.yml: split build step into Unix/Windows variants

Fixes CI failure from shell: bash on Windows runners.
- build-binary.ps1: Rename-Item expects just the new name, not a full path
- ci.yml: add shell: pwsh and PATH export for uv in test-windows job
- script_runner.py: use shlex.split(posix=False) on Windows to handle
  quoted arguments (e.g., paths with spaces, --model "gpt-4o mini")
- manager.py: translate --vanilla to -Vanilla and positional version to
  -Version when calling PowerShell setup scripts
- build-binary.ps1: show actual binary output on test failure instead of
  swallowing it with 2>&1; relax ErrorActionPreference for native command
- apm.spec: bundle github-token-helper.ps1 alongside .sh version
- tests: add quoted-arg test, platform-aware arg translation tests
GNU strip corrupts Windows PE/COFF binaries (LoadLibrary: Invalid access
to memory location). Conditionally disable strip when sys.platform == win32.
Strip still runs on Linux/macOS for smaller binaries.
- Remove Windows jobs from PR CI (ci.yml): drop test-windows and build-windows
- Remove Windows jobs from ci-integration.yml: drop smoke-test-windows,
  integration-tests-windows, release-validation-windows; update report-status
- Remove Chocolatey and winget dispatch jobs from build-release.yml (keep Scoop)
- Remove Chocolatey/winget from installation docs, simplify to Scoop-only
- Fix STATUS_SYMBOLS in console.py: use bracket notation to match codebase
- Fix typo in context_optimizer.py: for_allinstruction -> for_all instruction
- Add SHA256 checksum verification to install.ps1 after zip download
- Fix $LASTEXITCODE lost in pipe to Write-Host in install.ps1 pip fallback
- Revert unrelated NPM versioned package name change in codex.py
… README update

- installation.md: Replace duplicated Windows Quick Install with actual manual
  download steps (Invoke-WebRequest, Expand-Archive, PATH setup)
- installation.md: Remove experimental runtime setup section (belongs on
  dedicated runtime page)
- cli-commands.md: Add Linux/macOS and Windows platform labels in Quick Install,
  Manual Download, and apm update Manual Update sections
- scripts/: Move all .ps1 files to scripts/windows/ for clear platform separation
- build-release.yml: Update all .ps1 references to scripts/windows/
- README.md: Add platform labels in Get Started section and split Other install
  methods into Linux/macOS (Homebrew, pip) and Windows (Scoop, pip)
@sergio-sisternes-epam sergio-sisternes-epam force-pushed the feat/88-windows-native-support branch from 0f35a80 to 5016794 Compare March 13, 2026 08:32
The PyInstaller spec was unconditionally bundling github-token-helper.ps1,
which fails on Linux/macOS since the file was moved to scripts/windows/.
Now .ps1 is bundled only on Windows and .sh only on Unix.
@sergio-sisternes-epam sergio-sisternes-epam merged commit 0cfe820 into microsoft:main Mar 13, 2026
9 checks passed
@sergio-sisternes-epam sergio-sisternes-epam deleted the feat/88-windows-native-support branch March 13, 2026 09:19
@danielmeppiel
Copy link
Collaborator

as a follow up we should probably add to copilot-instructions that unicode characters not handled by Windows are banned. Great work @sergio-sisternes-epam !

Copilot AI added a commit that referenced this pull request Mar 13, 2026
…ring)

Main branch (PR #227, Windows native support) standardized docstring arrows
from '→' to '->' across the codebase. Our branch had added a local path
line using '→'. Resolution: adopt main's '->' style for all arrows and
keep our local path documentation line.

The only conflict was in to_canonical() docstring in dependency.py.
All other files auto-merged cleanly.

Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 13, 2026
PR microsoft#227 replaced emoji characters with ASCII equivalents for Windows
console compatibility. The integration test was still checking for
'✨ Package installed and ready to run' which no longer matches the
actual output '* Package installed and ready to run', causing the
early-termination sentinel and execution_started assertion to fail.

Replace all 4 emoji-dependent checks with the stable substring
'Package installed and ready to run' (no emoji dependency).
sergio-sisternes-epam added a commit to sergio-sisternes-epam/apm that referenced this pull request Mar 13, 2026
…ix emoji assertions

- Extract duplicated try/finally CWD-restore into _chdir_tmp() context manager
  (addresses Copilot review feedback)
- Fix integration test emoji assertions: replace emoji-dependent
  '✨ Package installed and ready to run' checks with the stable
  'Package installed and ready to run' substring after PR microsoft#227
  replaced emoji with ASCII in CLI output

Fixes Windows PermissionError [WinError 32] when TemporaryDirectory
cleanup runs while the process CWD is inside the temp dir.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/high Ships in current or next milestone

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Windows Native Support

3 participants