From 47554beb6c7c226c48dfd316b4fd9c4f80f719c3 Mon Sep 17 00:00:00 2001 From: Daniel Meppiel Date: Wed, 20 May 2026 08:22:49 +0200 Subject: [PATCH 1/3] chore(release): bump to v0.14.1 - Move Unreleased entries into [0.14.1] - 2026-05-20. - Add user-facing entries for #1408 (Windows Defender AV detection) and #1390 (AppLocker/WDAC install survival). - Bump pyproject.toml version 0.14.0 -> 0.14.1. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 12 ++++++++---- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f4e8eb64..e95665437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,19 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.14.1] - 2026-05-20 + ### Added -- **Experimental:** `copilot-app` target deploys prompts (with optional workflow frontmatter) directly into the GitHub Copilot desktop App's `~/.copilot/data.db` workflows table. Gated behind `apm experimental enable copilot-app`; works in both project scope (`apm install --target copilot-app` from a project's `apm.yml`) and user scope (`--global`). Workflows always install disabled (`enabled = 0`); user opts in from the App. No new CLI surface — `apm install / update / uninstall / list` cover the lifecycle. See [Copilot App integration](https://microsoft.github.io/apm/integrations/copilot-app/). +- **Experimental:** `copilot-app` target deploys prompts (with optional workflow frontmatter) directly into the GitHub Copilot desktop App's `~/.copilot/data.db` workflows table. Gated behind `apm experimental enable copilot-app`; works in both project scope (`apm install --target copilot-app` from a project's `apm.yml`) and user scope (`--global`). Workflows always install disabled (`enabled = 0`); user opts in from the App. No new CLI surface — `apm install / update / uninstall / list` cover the lifecycle. See [Copilot App integration](https://microsoft.github.io/apm/integrations/copilot-app/). (#1405) ### Changed -- **Experimental (`copilot-app`):** workflow prompts now use flat top-level frontmatter keys. Only `interval`, `schedule_hour`, `schedule_day` mark a `.prompt.md` as a workflow (dispatched to the Copilot App SQLite store); `mode`, `model`, `reasoning_effort` remain optional fields on a workflow but are NOT shape markers because they overload with plain VSCode / Copilot slash-command prompts. Plain prompts (no workflow keys) continue to deploy to slash-command targets only. `interval` defaults to `manual` when omitted. The redesign collapses what looked like two primitives (prompt vs scheduled prompt) into one shape-dispatched `.prompt.md`. Breaking only for users of the unreleased experimental target. +- **Experimental (`copilot-app`):** workflow prompts now use flat top-level frontmatter keys. Only `interval`, `schedule_hour`, `schedule_day` mark a `.prompt.md` as a workflow (dispatched to the Copilot App SQLite store); `mode`, `model`, `reasoning_effort` remain optional fields on a workflow but are NOT shape markers because they overload with plain VSCode / Copilot slash-command prompts. Plain prompts (no workflow keys) continue to deploy to slash-command targets only. `interval` defaults to `manual` when omitted. The redesign collapses what looked like two primitives (prompt vs scheduled prompt) into one shape-dispatched `.prompt.md`. Breaking only for users of the unreleased experimental target. (#1405) ### Fixed -- **Experimental (`copilot-app`):** workflow-shape `.prompt.md` files no longer leak to slash-command targets. Previously a single scheduled prompt would deploy to the Copilot App DB row AND to `.claude/commands/`, `.cursor/commands/`, `.copilot/prompts/`, and `.gemini/commands/`. Now each prompt belongs to exactly one surface based on frontmatter shape. -- **Experimental (`copilot-app`):** pointing a plain `.prompt.md` (no workflow frontmatter) at `--target copilot-app` is now a hard error with an actionable diagnostic telling the author to add `interval: manual` or unset the target, rather than silently skipping. +- **Experimental (`copilot-app`):** workflow-shape `.prompt.md` files no longer leak to slash-command targets. Previously a single scheduled prompt would deploy to the Copilot App DB row AND to `.claude/commands/`, `.cursor/commands/`, `.copilot/prompts/`, and `.gemini/commands/`. Now each prompt belongs to exactly one surface based on frontmatter shape. (#1405) +- **Experimental (`copilot-app`):** pointing a plain `.prompt.md` (no workflow frontmatter) at `--target copilot-app` is now a hard error with an actionable diagnostic telling the author to add `interval: manual` or unset the target, rather than silently skipping. (#1405) - `apm install` honors the SSH user portion of dependency URLs (`ssh://user@host/...` and scp shorthand `user@host:org/repo`) instead of hardcoding `git@`; unblocks EMU accounts and other non-`git` SSH identities. User values are validated against a strict allowlist before composing the clone URL. (#1385, closes #1383) +- Windows installer and `apm self-update` detect Windows Defender / antivirus blocks (HRESULT `0x800700E1`, PUA messages) instead of falling through to a generic "failed to run" and a pip fallback that itself dies on unsupported Python; surfaces three actionable recovery options (`Add-MpPreference -ExclusionPath`, `pip --user`, false-positive submission URL). (#1408) +- Windows installer and `apm self-update` survive AppLocker / App Control for Business (WDAC) policies by staging the release into the allow-listed per-user install root **before** running the `apm.exe --version` smoke test, instead of testing from user-writable `%TEMP%` and hitting `0x80070005` Access Denied. Adds a hardened `Get-Sha256Hex` helper that works under restricted PowerShell sessions, and emits AppLocker-specific guidance on access-denied. (#1390, closes #1389) ## [0.14.0] - 2026-05-18 diff --git a/pyproject.toml b/pyproject.toml index c3113013f..7ce890297 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "apm-cli" -version = "0.14.0" +version = "0.14.1" description = "MCP configuration tool" readme = "README.md" requires-python = ">=3.10" From fc0ca68098f65cd557c712f9f0f66941f1fa8005 Mon Sep 17 00:00:00 2001 From: Daniel Meppiel Date: Wed, 20 May 2026 08:35:38 +0200 Subject: [PATCH 2/3] test(install): restore CWD via monkeypatch.chdir to prevent pollution test_download_callback_includes_chain_in_error used raw os.chdir(tmp_path) without try/finally, leaving CWD pointing at a tmp dir whose apm.yml declared acme/root-pkg. Later in the same pytest worker, test_project_scope_now_supported (added by PR #1405) inherited that polluted CWD and tried to clone real GitHub repos, failing on missing auth in CI. monkeypatch.chdir auto-restores on teardown. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/unit/test_install_command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_install_command.py b/tests/unit/test_install_command.py index 3160a29a0..f2267251f 100644 --- a/tests/unit/test_install_command.py +++ b/tests/unit/test_install_command.py @@ -494,7 +494,7 @@ def test_get_ancestor_chain_root_node(self): ) assert node.get_ancestor_chain() == "acme/root-pkg" - def test_download_callback_includes_chain_in_error(self, tmp_path): + def test_download_callback_includes_chain_in_error(self, tmp_path, monkeypatch): """When a transitive dep download fails, the error message includes the parent chain breadcrumb for debugging. @@ -553,7 +553,7 @@ def tracking_callback(dep_ref, mods_dir, parent_chain="", parent_pkg=None): download_callback=tracking_callback, ) - os.chdir(tmp_path) + monkeypatch.chdir(tmp_path) resolver.resolve_dependencies(tmp_path) # The callback should have been called for leaf-pkg From dea22977a60e3e8b94fff5b367e5da4bf6e1b30d Mon Sep 17 00:00:00 2001 From: Daniel Meppiel Date: Wed, 20 May 2026 08:44:51 +0200 Subject: [PATCH 3/3] chore(changelog): collapse to one entry per PR for v0.14.1 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e95665437..0f1b9f544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,19 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- **Experimental:** `copilot-app` target deploys prompts (with optional workflow frontmatter) directly into the GitHub Copilot desktop App's `~/.copilot/data.db` workflows table. Gated behind `apm experimental enable copilot-app`; works in both project scope (`apm install --target copilot-app` from a project's `apm.yml`) and user scope (`--global`). Workflows always install disabled (`enabled = 0`); user opts in from the App. No new CLI surface — `apm install / update / uninstall / list` cover the lifecycle. See [Copilot App integration](https://microsoft.github.io/apm/integrations/copilot-app/). (#1405) - -### Changed - -- **Experimental (`copilot-app`):** workflow prompts now use flat top-level frontmatter keys. Only `interval`, `schedule_hour`, `schedule_day` mark a `.prompt.md` as a workflow (dispatched to the Copilot App SQLite store); `mode`, `model`, `reasoning_effort` remain optional fields on a workflow but are NOT shape markers because they overload with plain VSCode / Copilot slash-command prompts. Plain prompts (no workflow keys) continue to deploy to slash-command targets only. `interval` defaults to `manual` when omitted. The redesign collapses what looked like two primitives (prompt vs scheduled prompt) into one shape-dispatched `.prompt.md`. Breaking only for users of the unreleased experimental target. (#1405) +- **Experimental:** `copilot-app` target deploys prompts (with optional workflow frontmatter) directly into the GitHub Copilot desktop App's `~/.copilot/data.db` workflows table; shape-dispatched `.prompt.md` (workflow keys `interval` / `schedule_hour` / `schedule_day` route to the App, plain prompts route to slash-command targets) so each prompt lands on exactly one surface. Gated behind `apm experimental enable copilot-app`; works in project (`apm install --target copilot-app`) and user (`--global`) scope; workflows install disabled, user opts in from the App. See [Copilot App integration](https://microsoft.github.io/apm/integrations/copilot-app/). (#1405) ### Fixed -- **Experimental (`copilot-app`):** workflow-shape `.prompt.md` files no longer leak to slash-command targets. Previously a single scheduled prompt would deploy to the Copilot App DB row AND to `.claude/commands/`, `.cursor/commands/`, `.copilot/prompts/`, and `.gemini/commands/`. Now each prompt belongs to exactly one surface based on frontmatter shape. (#1405) -- **Experimental (`copilot-app`):** pointing a plain `.prompt.md` (no workflow frontmatter) at `--target copilot-app` is now a hard error with an actionable diagnostic telling the author to add `interval: manual` or unset the target, rather than silently skipping. (#1405) -- `apm install` honors the SSH user portion of dependency URLs (`ssh://user@host/...` and scp shorthand `user@host:org/repo`) instead of hardcoding `git@`; unblocks EMU accounts and other non-`git` SSH identities. User values are validated against a strict allowlist before composing the clone URL. (#1385, closes #1383) -- Windows installer and `apm self-update` detect Windows Defender / antivirus blocks (HRESULT `0x800700E1`, PUA messages) instead of falling through to a generic "failed to run" and a pip fallback that itself dies on unsupported Python; surfaces three actionable recovery options (`Add-MpPreference -ExclusionPath`, `pip --user`, false-positive submission URL). (#1408) -- Windows installer and `apm self-update` survive AppLocker / App Control for Business (WDAC) policies by staging the release into the allow-listed per-user install root **before** running the `apm.exe --version` smoke test, instead of testing from user-writable `%TEMP%` and hitting `0x80070005` Access Denied. Adds a hardened `Get-Sha256Hex` helper that works under restricted PowerShell sessions, and emits AppLocker-specific guidance on access-denied. (#1390, closes #1389) +- `apm install` honors the SSH user portion of dependency URLs (`ssh://user@host/...` and scp shorthand `user@host:org/repo`) instead of hardcoding `git@`; unblocks EMU accounts and other non-`git` SSH identities. (#1385, closes #1383) +- Windows installer and `apm self-update` detect Windows Defender / antivirus blocks (HRESULT `0x800700E1`, PUA messages) and surface three actionable recovery options (`Add-MpPreference -ExclusionPath`, `pip --user`, false-positive submission URL) instead of falling through to a generic "failed to run" and a pip fallback that itself dies on unsupported Python. (#1408) +- Windows installer and `apm self-update` survive AppLocker / App Control for Business (WDAC) policies by staging the release into the allow-listed per-user install root before running the `apm.exe --version` smoke test, and emit AppLocker-specific guidance on `0x80070005` Access Denied instead of silently falling back to pip. (#1390, closes #1389) ## [0.14.0] - 2026-05-18