Skip to content

fix: Copilot runtime — model aliases, hooks support, auto-detect & folder trust#77

Merged
jayminwest merged 17 commits intomainfrom
copilot-runtime-fixes
Mar 23, 2026
Merged

fix: Copilot runtime — model aliases, hooks support, auto-detect & folder trust#77
jayminwest merged 17 commits intomainfrom
copilot-runtime-fixes

Conversation

@jayminwest
Copy link
Copy Markdown
Owner

Summary

Addresses three Copilot runtime issues reported by @karlis-balcers:

Changes

File What
src/runtimes/copilot.ts MODEL_MAP, expandModel(), prepareWorktree(), ensureCopilotTrustedFolders(), wired deployCopilotHooks() in deployConfig()
src/runtimes/types.ts Optional prepareWorktree() on AgentRuntime interface
src/commands/sling.ts Call prepareWorktree() before spawn, abort on waitForTuiReady failure
src/commands/init.ts detectDefaultRuntime() via which checks
src/agents/copilot-hooks-deployer.ts New — generates .github/hooks/hooks.json for Copilot
templates/copilot-hooks.json.tmpl New — Copilot hooks template
Tests 3 new/expanded test files with full coverage

⚠️ @karlis-balcers — needs your validation

I don't have a Copilot CLI subscription, so none of this has been tested against a real Copilot session. The implementation is based on your excellent reverse-engineering analysis in #74. Key things to verify:

  1. Model aliases — Does copilot --model claude-sonnet-4-6 actually work?
  2. Hooks file — Does Copilot pick up .github/hooks/hooks.json with the version: 1 schema?
  3. Trusted folders — Is ~/.config/github-copilot/config.json the right path, and does trustedFolders prevent the trust dialog?
  4. Phase 1 scope — Only lifecycle hooks (sessionStart) are deployed, no security guards yet. Guards are planned for a follow-up once the basics are validated.

Note on commit history

This was built by an agent swarm, so the history includes merge commits and sync noise. Happy to squash if preferred.

Test plan

  • bun test passes
  • Manual validation with Copilot CLI (needs @karlis-balcers)
  • Verify hooks are loaded on Copilot session start
  • Verify folder trust prevents interactive dialog

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator

@lucabarak lucabarak left a comment

Choose a reason for hiding this comment

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

Code looks clean — nice separation with the hooks deployer as its own module, and the ensureCopilotTrustedFolders tests are thorough (the invalid JSON recovery + dedup edge cases are great).

A couple small things:

  • The PR body doesn't include Fixes #72, Fixes #74, Fixes #76 — adding those would auto-close the issues on merge.

I don't have Copilot CLI installed to test the integration, so I can't validate the hook schema or config path against the real CLI. @karlis-balcers would be the one to confirm those.

jayminwest and others added 16 commits March 23, 2026 12:30
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add MODEL_MAP to copilot.ts mapping sonnet/opus/haiku to fully-qualified
  names (claude-sonnet-4-6, claude-opus-4-6, claude-haiku-4-5)
- Add expandModel() method applied in buildSpawnCommand() and buildPrintCommand()
- Check waitForTuiReady() return value in sling.ts; throw AgentError on
  timeout/dead pane instead of sending keys to a dead tmux session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-detects installed coding agent runtimes (claude, copilot, gemini,
opencode, sapling, pi) and sets runtime.default in generated config.yaml.
Falls back to 'claude' when nothing is detected. Uses existing Spawner
abstraction for testability. Adds 10 tests covering priority order,
fallback, and integration with initCommand.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add optional prepareWorktree?(worktreePath) to AgentRuntime interface
- Implement ensureCopilotTrustedFolders() in copilot.ts that writes
  worktree path to ~/.config/github-copilot/config.json trustedFolders
- Add CopilotRuntime.prepareWorktree() calling the above (non-fatal errors)
- Call runtime.prepareWorktree() in sling.ts after worktree creation
- Add 9 tests for ensureCopilotTrustedFolders and prepareWorktree

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-resolve merge dropped the MODEL_MAP constant, causing
expandModel() to reference an undefined variable. Restores the
mapping and fixes two pre-existing Biome formatting issues.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add templates/copilot-hooks.json.tmpl with onSessionStart hooks
  (ov prime + ov mail check --inject) using ENV_GUARD pattern
- Add src/agents/copilot-hooks-deployer.ts with deployCopilotHooks()
  that reads template, substitutes {{AGENT_NAME}}, prepends PATH_PREFIX,
  and writes to .github/hooks/hooks.json
- Wire CopilotRuntime.deployConfig() to call deployCopilotHooks()
- Add tests for deployer (template health, substitution, PATH_PREFIX,
  schema structure, directory creation)
- Add tests for deployConfig hooks.json output in copilot.test.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ment)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jayminwest jayminwest force-pushed the copilot-runtime-fixes branch from 83873f9 to c539686 Compare March 23, 2026 19:34
detectDefaultRuntime calls spawner(["which", ...]) which throws when
the spawner is broken (e.g. ENOENT). This broke the existing spawner
error resilience tests. Wrapping in try/catch with a "claude" fallback
matches the graceful degradation pattern used by ecosystem tool onboarding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jayminwest jayminwest merged commit c3d228c into main Mar 23, 2026
1 check passed
@jayminwest jayminwest deleted the copilot-runtime-fixes branch March 23, 2026 19:39
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.

2 participants