Skip to content

Add Copilot agent support#417

Draft
gtrrz-victor wants to merge 3 commits intomainfrom
gtrrz-victor/github-copilot-support
Draft

Add Copilot agent support#417
gtrrz-victor wants to merge 3 commits intomainfrom
gtrrz-victor/github-copilot-support

Conversation

@gtrrz-victor
Copy link
Contributor

Entire-Checkpoint: c74816392558

Entire-Checkpoint: c74816392558
Copilot AI review requested due to automatic review settings February 19, 2026 03:28
@cursor
Copy link

cursor bot commented Feb 19, 2026

PR Summary

Medium Risk
Touches hook dispatch/uninstall behavior and transcript summarization, which can affect automation flows across agents, but changes are additive and covered by extensive unit tests.

Overview
Adds a new preview github-copilot agent integration, including hook installation/uninstallation via .github/hooks/copilot-setup.json, hook input parsing, session transcript discovery under ~/.copilot/session-state, and lifecycle event normalization for session/turn/subagent boundaries.

Extends transcript analysis and summarization to understand Copilot’s events.jsonl format (condensing user/assistant messages and tool calls, extracting prompts/summary/modified files, and supporting chunking/reassembly). Updates hook command routing and uninstall flow to work generically across all hook-capable agents (including Copilot), and registers the new agent for hook and strategy tests.

Written by Cursor Bugbot for commit a189b2e. Configure here.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds GitHub Copilot CLI as a new (preview) agent integration in Entire CLI, aligning Copilot’s hook/transcript formats with the existing agent abstraction so sessions can be checkpointed and summarized consistently.

Changes:

  • Introduces a new agent/copilot implementation (hook installation, lifecycle parsing, transcript parsing, tests).
  • Extends summarization to support Copilot events.jsonl transcripts.
  • Updates setup/uninstall and hook command registration to include Copilot alongside existing agents.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
copilot-integration.md Implementation plan/spec for Copilot agent integration and hook mapping.
cmd/entire/cli/summarize/summarize.go Adds Copilot transcript parsing path for condensed transcript generation.
cmd/entire/cli/strategy/rewind_test.go Registers Copilot agent for rewind strategy tests via blank import.
cmd/entire/cli/setup_test.go Registers Copilot agent for setup tests via blank import.
cmd/entire/cli/setup.go Updates uninstall flow to enumerate/remove hooks for any installed agent (incl. Copilot).
cmd/entire/cli/hooks_cmd.go Ensures Copilot agent is registered so hook subcommands can be generated.
cmd/entire/cli/hook_registry.go Categorizes Copilot hook verbs into tool/subagent types for hook logging.
cmd/entire/cli/agent/registry.go Adds AgentNameCopilot / AgentTypeCopilot constants.
cmd/entire/cli/agent/copilot/types.go Defines Copilot hook-config types, hook stdin structs, and events.jsonl transcript structs/constants.
cmd/entire/cli/agent/copilot/copilot.go Implements the Copilot agent (identity, detection, legacy hook/session APIs).
cmd/entire/cli/agent/copilot/lifecycle.go Implements Copilot hook → normalized lifecycle event translation + transcript analyzer methods.
cmd/entire/cli/agent/copilot/hooks.go Installs/uninstalls Copilot hooks in .github/hooks/copilot-setup.json.
cmd/entire/cli/agent/copilot/transcript.go Parses Copilot events.jsonl and extracts prompts/summary/modified files.
cmd/entire/cli/agent/copilot/*_test.go Adds unit tests for Copilot agent behavior, hooks, lifecycle parsing, and transcript parsing.
Comments suppressed due to low confidence (1)

cmd/entire/cli/agent/copilot/hooks.go:60

  • The InstallHooks() docstring says existing Entire hooks are removed only when force=true, but the implementation removes existing Entire hook entries unconditionally (after the early idempotency return). Either update the comment to match the behavior, or gate the removal logic behind force if that was the intent.
// InstallHooks installs Copilot hooks in .github/hooks/copilot-setup.json.
// If force is true, removes existing Entire hooks before installing.
// Returns the number of hooks installed.

Comment on lines 155 to 163
raw, err := agent.ReadAndParseHookInput[userPromptRaw](stdin)
if err != nil {
return nil, err
}
return &agent.Event{
Type: agent.TurnStart,
Prompt: raw.Prompt,
Timestamp: time.Now(),
}, nil
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

TurnStart events require a non-empty SessionID in the lifecycle dispatcher, but Copilot's user-prompt-submitted hook parsing currently emits agent.TurnStart with an empty SessionID/SessionRef. This will cause DispatchLifecycleEvent to return an error ("no session_id in TurnStart"), potentially breaking Copilot hook execution. Consider treating this hook as pass-through (return nil) until sessionId/transcriptPath are available, or populate SessionID via another reliable mechanism before emitting TurnStart.

Suggested change
raw, err := agent.ReadAndParseHookInput[userPromptRaw](stdin)
if err != nil {
return nil, err
}
return &agent.Event{
Type: agent.TurnStart,
Prompt: raw.Prompt,
Timestamp: time.Now(),
}, nil
// We intentionally treat this hook as a pass-through because it does not
// provide sessionId or transcriptPath. Emitting a TurnStart event without
// a SessionID would cause DispatchLifecycleEvent to fail.
_, err := agent.ReadAndParseHookInput[userPromptRaw](stdin)
if err != nil {
return nil, err
}
return nil, nil

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +105
configKey := hookNameToConfigKey[HookNameSessionStart]
expectedCmd := cmdPrefix + HookNameSessionStart
if entries, ok := config.Hooks[configKey]; ok {
for _, entry := range entries {
if entry.Bash == expectedCmd {
return 0, nil // Already installed with same mode
}
}
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

InstallHooks()'s idempotency check only verifies that the expected command exists under the sessionStart config key. If some of the other 7 hooks are missing/misconfigured, this will incorrectly return 0 (no-op) and leave the installation in a partially broken state. Consider validating that all required hook keys contain an entry matching the expected command for the current mode before returning 0.

Suggested change
configKey := hookNameToConfigKey[HookNameSessionStart]
expectedCmd := cmdPrefix + HookNameSessionStart
if entries, ok := config.Hooks[configKey]; ok {
for _, entry := range entries {
if entry.Bash == expectedCmd {
return 0, nil // Already installed with same mode
}
}
}
allHooksPresent := true
for _, hookName := range c.HookNames() {
configKey, ok := hookNameToConfigKey[hookName]
if !ok {
// Skip hook names that don't have a corresponding config key,
// matching the behavior used during installation below.
continue
}
expectedCmd := cmdPrefix + hookName
entries, exists := config.Hooks[configKey]
if !exists {
allHooksPresent = false
break
}
found := false
for _, entry := range entries {
if entry.Bash == expectedCmd {
found = true
break
}
}
if !found {
allHooksPresent = false
break
}
}
if allHooksPresent {
return 0, nil // Already installed with same mode for all hooks
}

Copilot uses AI. Check for mistakes.
Comment on lines 146 to 149
return &agent.Event{
Type: agent.SessionStart,
Timestamp: time.Now(),
}, nil
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Copilot's session-start hook parsing returns an agent.SessionStart event without a SessionID/SessionRef. The lifecycle dispatcher rejects SessionStart events with an empty session_id (it returns an error), which will make the entire hooks github-copilot session-start command fail whenever Copilot fires this hook. Since Copilot doesn't provide sessionId/transcriptPath here, this hook should likely return a nil event (no lifecycle action) or otherwise derive/populate a stable SessionID before emitting SessionStart.

Suggested change
return &agent.Event{
Type: agent.SessionStart,
Timestamp: time.Now(),
}, nil
// Copilot does not provide a stable session identifier here, and the lifecycle
// dispatcher rejects SessionStart events with an empty SessionID. Treat this
// hook as "no lifecycle action" by returning a nil event.
return nil, nil

Copilot uses AI. Check for mistakes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

result[i] = string(s)
}
return result
}
Copy link

Choose a reason for hiding this comment

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

Unused production functions only called from tests

Low Severity

sliceFromLine and its helper byteSlicesToStrings are dead production code — they are defined in transcript.go but only ever called from transcript_test.go, never from any production code path. These functions add maintenance burden without providing value. If they're intended for future use, they could be added when that usage materializes.

Fix in Cursor Fix in Web

Type: agent.SessionStart,
Timestamp: time.Now(),
}, nil
}
Copy link

Choose a reason for hiding this comment

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

Copilot lifecycle events fail due to missing SessionID

High Severity

parseSessionStart and parseTurnStart return non-nil lifecycle events with empty SessionID, but the downstream handlers handleLifecycleSessionStart and handleLifecycleTurnStart in lifecycle.go both return a hard error when event.SessionID == "". Since Copilot's sessionStart and userPromptSubmitted hooks don't include sessionId in their stdin, these two lifecycle events will always fail at runtime, preventing session initialization, pre-prompt state capture, and banner display for every Copilot session.

Additional Locations (1)

Fix in Cursor Fix in Web

Type string `json:"type"`
Bash string `json:"bash"`
TimeoutSec int `json:"timeoutSec,omitempty"`
}
Copy link

Choose a reason for hiding this comment

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

Config round-trip silently drops user hook fields

High Severity

The hookConfig and hookEntry structs use typed fields, so when InstallHooks or UninstallHooks reads, modifies, and writes back copilot-setup.json, any unrecognized JSON keys are silently dropped. The official Copilot hooks schema includes powershell and cwd fields on entries that this struct doesn't capture, so user hooks with those fields lose them on round-trip. The Gemini agent avoids this by using map[string]json.RawMessage to preserve unknown keys. Since this file lives in .github/hooks/ (version-controlled), the data loss persists and can break teammates' hooks.

Additional Locations (1)

Fix in Cursor Fix in Web

Entire-Checkpoint: 772a648155b3
Entire-Checkpoint: 64b9c3ca5735
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments