fix(hook): route annotate-last to the live Copilot CLI session - #1150
Merged
backnotprop merged 4 commits intoJul 30, 2026
Conversation
Copilot CLI exports no identifying environment variable, so nothing distinguishes a Copilot session from a plain shell. Match ancestor pids against session-state inuse locks to find the live session, and only accept a match when the lock owner still names a copilot process, since locks can outlive their session and pids get reused.
Under Copilot CLI, annotate-last silently fell back to the default transcript reader and annotated a message from a different tool. Take the Copilot branch when an ancestor process holds a session lock, or when PLANNOTATOR_ORIGIN=copilot-cli is set with the cwd heuristic as fallback, and report origin copilot-cli to the annotate server.
The cwd heuristic can pick a stale session when several exist for one repo. Resolve the session locked by an ancestor copilot process first and keep the heuristic as fallback.
The subcommand worked but was missing from the top-level usage and the per-subcommand help map.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fixes Issue #1149,
Under Copilot CLI,
plannotator last/annotate-lasthas no Copilot branch: the handler tries--stdin, Codex and droid, then falls through to the default transcript reader and silently annotates a message from an unrelated old session. The env check meant to catch Copilot (process.env.COPILOT_CLI) can never fire because Copilot CLI does not set that variable, and on a full install the sharedplannotator-lastskill shadows the Copilot plugin command, so this broken path is what/plannotator-lastactually runs.Approach
Copilot CLI leaves no env fingerprint, but every live session holds
$COPILOT_HOME/session-state/<uuid>/inuse.<pid>.lockwith the pid of its copilot process. The hook walks its ancestor pids (the existinggetAncestorPidsinsession-log.ts) and matches them against those locks, which resolves the exact session that spawned the hook instead of guessing by cwd and mtime. Two guards:ps -o comm=)psis unavailable (Windows), detection resolves nothing and behavior stays exactly as todayannotate-lasttakes the Copilot branch when a lock matches, or whenPLANNOTATOR_ORIGIN=copilot-cliis set (then with the existing cwd heuristic as fallback), reads messages through the existing reader incopilot-session.ts(getRecentCopilotMessages), and reports origincopilot-clito the annotate server. The stdin, Codex and droid branches keep priority and are untouched.copilot-lastprefers the lock match over its cwd heuristic. The global origin chain inindex.tsis deliberately not modified.Commits
copilot-session.ts, unit tests, and the staleCOPILOT_CLI=1header claim corrected.--help.Testing
13 new unit tests (
copilot-session.test.ts): lock match, no match, several live sessions, pid order in the chain, malformed lock names, stale lock skipped, pid-reuse guard, failing process name lookup,COPILOT_HOMEoverride.Full
bun test: no change against an untouched main checkout on my machine apart from the 13 new passing tests; the few suites that fail here fail identically before and after (environment related).End to end inside a real Copilot session (macOS 26.5.2, Copilot CLI 1.0.75) with
PLANNOTATOR_DEBUG=1:The resolved uuid is the invoking session: the same run's summary footer printed
copilot --resume=0782e7a1-e654-485f-b822-4e1618703d1b.Negative control from a terminal outside Copilot: no Copilot lines in the debug output, the default transcript resolution runs unchanged.
PLANNOTATOR_ORIGIN=copilot-clioutside Copilot: the Copilot branch is taken with no lock match and the session resolves via the cwd heuristic.Possible follow-up
The same lock detection could back the global origin chain in
index.tsso every mode gains Copilot awareness. Left out to keep this change scoped to the-lastflows.