Skip to content

[fix] use target.root_dir for copilot hook deployment at user scope (#565)#570

Closed
edenfunf wants to merge 1 commit into
microsoft:mainfrom
edenfunf:fix/copilot-user-scope-hooks-565
Closed

[fix] use target.root_dir for copilot hook deployment at user scope (#565)#570
edenfunf wants to merge 1 commit into
microsoft:mainfrom
edenfunf:fix/copilot-user-scope-hooks-565

Conversation

@edenfunf

@edenfunf edenfunf commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

What

integrate_package_hooks hardcoded ".github" as the hooks root directory, ignoring the scope-resolved target.root_dir. At user scope the Copilot target resolves to root_dir=".copilot" (via TargetProfile.for_scope()), but hooks always landed in ~/.github/hooks/ instead of ~/.copilot/hooks/. The same bug applied to the script paths written inside the deployed hook JSON files.

Fixes #565.

Why

TargetProfile.for_scope(user_scope=True) returns a copy of the profile with root_dir already overridden to user_root_dir (".copilot" for Copilot). All other integrators (InstructionIntegrator, AgentIntegrator, etc.) read target.root_dir directly after scope resolution. HookIntegrator.integrate_package_hooks was the only one that ignored it.

How

  • Added target=None parameter to integrate_package_hooks. When provided, target.root_dir is used as hook_root; otherwise falls back to ".github" (backward-compatible, all existing call sites without target continue to work).
  • Threaded hook_root through _rewrite_hooks_data_rewrite_command_for_target so that script paths embedded in the deployed JSON also reference the correct root.
  • integrate_hooks_for_target now passes target=target to integrate_package_hooks for the "copilot" branch, matching the pattern used by every other integrate_*_for_target dispatcher.

No changes outside hook_integrator.py. No new abstractions.

Test

Added test_integrate_package_hooks_user_scope_uses_copilot_root to TestVSCodeIntegration:

  • Constructs a mock target with root_dir=".copilot" (mirrors what for_scope(user_scope=True) returns for Copilot)
  • Asserts hook JSON lands in .copilot/hooks/, not .github/hooks/
  • Asserts script paths inside the deployed JSON reference .copilot/, not .github/
  • Asserts scripts are copied under .copilot/hooks/scripts/

All 71 existing tests continue to pass.

When apm install --global is run, the Copilot target is scope-resolved
to root_dir=".copilot" via TargetProfile.for_scope(). However,
integrate_package_hooks ignored the resolved target and hardcoded
".github" for both the hooks directory and the script paths written
inside hook JSON files. Hooks therefore always landed in ~/.github/hooks/
instead of ~/.copilot/hooks/ at user scope.

Pass the scope-resolved target through integrate_hooks_for_target into
integrate_package_hooks, which now derives hook_root from target.root_dir
(defaulting to ".github" for callers that don't supply a target). Thread
hook_root through _rewrite_hooks_data and _rewrite_command_for_target so
that script paths embedded in the deployed JSON also reference the correct
root directory.

Fixes microsoft#565
@edenfunf edenfunf requested a review from danielmeppiel as a code owner April 4, 2026 06:19
@edenfunf

edenfunf commented Apr 4, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #566 which fixes the same bug with a more complete implementation — it also patches sync_integration() to recognize .copilot/hooks/ during uninstall and threads target through all four dispatcher backends. Good catch on this one.

@edenfunf edenfunf closed this Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Global hook deployment writes to ~/.github/hooks/ instead of ~/.copilot/hooks/

1 participant