Skip to content

feat: add GitHub Copilot CLI backend#42

Merged
Cannon07 merged 3 commits intomainfrom
feat/copilot-cli-backend
Apr 25, 2026
Merged

feat: add GitHub Copilot CLI backend#42
Cannon07 merged 3 commits intomainfrom
feat/copilot-cli-backend

Conversation

@Cannon07
Copy link
Copy Markdown
Owner

@Cannon07 Cannon07 commented Apr 25, 2026

Summary

  • Adds GitHub Copilot CLI as the third supported AI backend alongside Claude Code and OpenCode.
  • Install writes a standalone .github/hooks/code-preview.json, matching Copilot's auto-discovered multi-file hook contract — sibling user hooks are never touched.
  • Co-discovered fixes: *** Delete File: extraction in the post-tool path extractor (delete-diff tabs were lingering after mixed update+delete patches), and a stray empty hunk when GPT's *** Add File: shape coincided with @@.

What's included

Backend

  • backends/copilot/{code-preview-diff,code-close-diff}.sh — translate Copilot's {toolName, cwd, toolArgs} payload to the normalized format consumed by bin/core-{pre,post}-tool.sh. Handles apply_patch (raw patch text), edit/str_replace, create/write, and bash. Noise tools (view, glob, report_intent, …) exit early before any RPC.
  • lua/code-preview/backends/copilot.lua — install/uninstall + an is_our_config helper that grep-matches the adapter path. Uninstall refuses to delete a code-preview.json we didn't write; status reports "installed" only for files we own.
  • :CodePreviewInstall/UninstallCopilotCliHooks commands; Copilot row in :CodePreviewStatus and :checkhealth.

Hardening

  • arg() in both adapters binds the jq lookup key via --arg instead of interpolating into the program text.
  • Pre-adapter skips cleanly on malformed payloads (empty path for edit/create, empty command for bash) rather than pushing empty-path diffs downstream.
  • .gitignore narrowed from .github/ to .github/hooks/code-preview.json so workflows / FUNDING.yml / future repo-conventions files aren't hidden.
  • Comments in bin/core-{pre,post}-tool.sh clarified to document CODE_PREVIEW_BACKEND's actual gating role and list all three backends.

Bug fixes

  • bin/core-post-tool.sh: extractor regex now matches *** Delete File: alongside Update/Add — delete diffs now close on accept.
  • bin/apply-patch.lua: lazy-create the hunk for *** Add File: so GPT's no-@@ shape captures content lines without producing a stray empty leading hunk when @@ does appear.

Tests

15 new tests, 45 total passing (bash tests/run.sh all):

  • tests/backends/copilot/test_install.sh — install file layout, idempotency, sibling-file preservation, foreign-file uninstall guard.
  • tests/backends/copilot/test_edit.sh — edit, create, bash rm, relative path, str_replace alias, noise-tool skip, malformed-payload skip.
  • tests/backends/copilot/test_apply_patch.sh — Update, Add, mixed Update+Add+Delete with full close-cycle assertions.
  • tests/core/test_post_tool_patch_paths.sh — unit-boundary regression for the patch-path extractor (stubs close_for_file).
  • tests/backends/opencode/test_apply_patch.sh — adds the GPT-style no-@@ Add File parser case.
  • tests/run.sh extended with core filter; all now picks up tests/core/ alongside tests/backends/.

Test plan

  • bash tests/run.sh all — 45 tests pass locally
  • Install/uninstall cycle in a real Copilot CLI session
  • Mixed Update + Add + Delete patch — all diff tabs open on pre, all close on accept
  • Manual edit/create/bash via Copilot with both GPT-5 and Claude Sonnet

Cannon07 and others added 3 commits April 25, 2026 16:27
Copilot becomes the third supported AI backend alongside Claude Code and
OpenCode. The integration follows Copilot's auto-discovered .github/hooks/*.json
contract, so install writes a standalone code-preview.json rather than merging
into a shared settings file.

Backend
- backends/copilot/{code-preview-diff,code-close-diff}.sh — pre/post hook
  adapters that translate Copilot's {toolName, cwd, toolArgs} payload into the
  normalized {tool_name, cwd, tool_input} shape consumed by bin/core-{pre,post}-tool.sh.
  Handles GPT-style apply_patch (raw patch text) and Claude-style edit/create/bash.
- lua/code-preview/backends/copilot.lua — install/uninstall + is_our_config
  helper that grep-matches our adapter path so uninstall refuses to delete
  user-owned files that share the name.
- :CodePreviewInstall/UninstallCopilotCliHooks commands and a Copilot row in
  :CodePreviewStatus + :checkhealth.

Co-discovered fixes
- bin/core-post-tool.sh: extractor now matches *** Delete File: alongside
  Update/Add, so delete-action diffs close on accept (regression: tabs
  lingered after mixed update+delete patches).
- bin/apply-patch.lua: lazy-create the hunk for *** Add File: instead of
  pre-creating, so GPT's no-@@ shape captures content lines without leaving
  a stray empty leading hunk when @@ is also present.
- backends/copilot adapters bind jq lookup keys via --arg (no shell-string
  interpolation) and skip cleanly on malformed payloads with empty path/command
  rather than pushing empty-path diffs downstream.
- .gitignore narrowed from .github/ to .github/hooks/code-preview.json to
  avoid hiding workflows / FUNDING.yml / future repo-conventions files.

Tests (+15 new, 45 total passing)
- tests/backends/copilot/{test_install,test_edit,test_apply_patch}.sh — full
  E2E coverage parallel to claudecode/opencode: install layout, sibling-file
  preservation, foreign-file uninstall guard, edit/create/bash/str_replace/
  apply_patch lifecycles, malformed-payload skip, mixed Update+Add+Delete close.
- tests/core/test_post_tool_patch_paths.sh — focused regression for the
  Delete File extractor at the unit boundary (stubs close_for_file).
- tests/backends/opencode/test_apply_patch.sh — adds the GPT-style
  no-@@ Add File parser test.
- tests/run.sh — discovers tests/core/ alongside tests/backends/.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
vim.json.encode escapes forward slashes on some Neovim builds (CI) but
not others (local), so substring assertions for paths like "src/new.lua"
matched against "src\/new.lua" intermittently failed in CI while passing
locally. Switch to table.concat with a delimiter — same intent, no
encoding-dependent behavior.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Add Demo section entry + gif for GitHub Copilot CLI.
- Rename docs/claude-preview-*.gif to docs/code-preview-*.gif so the
  asset filenames match the post-rename plugin name. The Claude Code
  gif specifically becomes code-preview-claudecode.gif to disambiguate
  from the other backends now that there's more than one.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@Cannon07 Cannon07 merged commit 9ec3a33 into main Apr 25, 2026
2 checks passed
@Cannon07 Cannon07 deleted the feat/copilot-cli-backend branch April 26, 2026 04:54
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.

1 participant