Add GitHub Copilot CLI support#275
Conversation
umputun
left a comment
There was a problem hiding this comment.
the wrapper approach is correct and follows the existing pattern well. a few things to address:
-
pkg/progress/progress_test.gochange is unrelated to copilot support. if it was an intentional fix, pls split it into a separate PR -
the main loop forks 3-4
jqprocesses per JSONL line (validate, extract type, extract content, extract text). the codex wrapper does the entire translation in a singlejq -cpipeline per line. not a blocker but worth optimizing - copilot can produce a lot of events -
shell tests use macOS-only commands -
stat -f '%m',date -v-1H,grep -P. these won't run on linux, which means they can't run in CI or docker. the other wrapper tests avoid platform-specific commands, would be good to follow the same pattern -
minor -
grep -oE 'docs/plans/[^ ]*\.md'for plan path extraction is fragile if the model formats the path differently. thefindfallback helps but the grep could silently grab wrong text
f01da94 to
46b9614
Compare
|
Thank you for the review. All comments were addressed. |
umputun
left a comment
There was a problem hiding this comment.
thx for addressing the previous comments. most things look solid now, tests pass (59+25 shell, all Go tests, lint clean).
I haven't tried it with an actual copilot cli, so assuming you got it working end-to-end. the questions below are more theoretical than practical.
a few things after deeper review:
-
jq forks - down to 2/line from 3-4, which is better. the single-pipeline approach doesn't really work here because of per-line flow control decisions (plan boundaries, turn tracking), so I can live with this
-
plan boundary handling (lines 127-267) - none of the other wrappers (codex, gemini, opencode) implement plan signal parsing. I get why - copilot's autopilot mode runs multiple turns, so the wrapper needs to stop at boundaries. but does copilot cli have smth like
--max-turns 1or similar flag that would make this unnecessary? if the tool itself can limit to single-turn mode, ~90 lines of boundary extraction could go away -
touch_existing_plan_for_ready(lines 242-267) - this is coupling between the shell wrapper and Go internals (FindRecentmtime behavior). ifFindRecentchanges its lookup strategy, this breaks silently. at minimum add a comment explaining why the touch is needed and which Go function depends on it -
review adapter size - ~800 chars with a "FORMATTING RULE (strict)" section vs ~350 chars in codex adapter. is the markdown suppression rule actually needed for copilot, or is it defensive? if copilot consistently wraps output in markdown, then fine, but if not, trim it
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The skipIfClaudeNotAvailable change was unrelated to Copilot support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
umputun
left a comment
There was a problem hiding this comment.
thx, all prior comments addressed cleanly:
- progress_test.go reverted
- jq forks stable at 2/line
- macOS-only commands gone from tests
- plan path extraction replaced with content-compare (marker file +
cmp -s), no more fragile grep touch_existing_plan_for_readyremoved entirely -plan_written_since_startuses a script-internal marker instead of coupling to GoFindRecent- plan-boundary comment at
copilot-as-claude.sh:135-138explains clearly why--max-turnswouldn't help (multiple signals in a single assistant.message, not across turns) - review adapter size justified by the copilot markdown-default behavior, comment at
:122-124makes it discoverable
shell tests 83/83 + 29/29, go test clean, lint clean, shellcheck clean.
lgtm.
|
@umputun, thank you for reviewing it again. Honestly, I'm not completely satisfied by the fact the script is too bloated (in comparison to others) due to Copilot CLI quirks. While I see some room for improvements - it does the thing end-to-end. I will continue revising it when time allows and get back with a clean up PR soon. |
Summary
This PR adds first-class GitHub Copilot CLI support to ralphex without changing the existing claude_command / claude_args integration path.
It introduces a wrapper that runs Copilot CLI, translates its JSONL stream into the Claude stream-json format expected by ralphex, and keeps the existing
plan / task / review flows working with minimal executor changes.
What Changed
Why
Copilot CLI is close enough to use as an alternative provider, but its native streaming and autonomy model does not match ralphex’s control flow out of the
box.
Without this wrapper:
This PR makes Copilot behave closely enough to the Codex/Claude path that ralphex can drive it safely.
Validation
Ran:
bash scripts/copilot-as-claude/copilot-as-claude_test.sh
bash scripts/copilot-as-claude/copilot-as-claude_docs_test.sh
bash -n scripts/copilot-as-claude/copilot-as-claude.sh
Notes
This is intentionally a wrapper-level integration. It keeps the current executor architecture intact and avoids introducing Copilot-specific logic into the Go task runner.