Skip to content

/resume broken for non-GitHub (ADO) and non-git sessions - GitHub-only repo gates #4054

Description

@Fabi0San

Describe the bug

Summary

/resume (and the remote-task → local handoff behind it) is effectively unusable for two
overlapping classes of session:

  1. Non-GitHub repos (e.g. Azure DevOps / ADO). The resume git gates hard-code
    GitHub and reject any repo whose host is not github.
  2. Non-git sessions. A session created while the working directory was NOT a git
    repository stores an empty/'/' repository and can never satisfy the picker's git gate.
    Both funnel through the same root cause: the resume/handoff code assumes the repository is
    always GitHub-hosted.
    Cross-machine sessions also can't be recovered, and --connect
    silently starts an empty session instead of surfacing the problem.

Environment

Root cause (code-level, from the bundled app.js)

There are two independent GitHub-only gates. Stable string anchors are given so they can
be grepped across versions (minified identifiers are as of 1.0.71-0).
Gate A — repo/branch match on the remote-steerable / repo-scoped path.

// function Dbr(...) — remote session → local
let m = r.hostType==="github" && r.repository===l,   // r = your CURRENT checkout
    f = !c || r.branch===c;
if(!m || !f){ ... throw new hF(y,w) }                // hF.name = "ResumeRepoMismatchError"

m hard-codes hostType==="github". For an ADO checkout (hostType==="ado") m is always
false
, so it always throws ResumeRepoMismatchError — surfaced as
Repository mismatch … / --remote --resume must be run from … current checkout is ….
Gate B — the "Validating repository" step of the task → local handoff.

// handoff generator, step "validate-repo"
try { a = await this.handoffGitOperations.getRepositoryInfo(cwd); }
catch(f){ throw new Error(`Not in a git repository. Please navigate to your repository directory. ${Y(f)}`) }

getRepositoryInfo derives a GitHub owner/name from the git remotes:

if(!o) throw new Error("Could not determine GitHub repository from git remotes");

ADO remotes yield no GitHub identity → it throws, and the handoff reports the two errors seen in
the UI:

Error: Not in a git repository. Please navigate to your repository directory.
Error: Failed to get repository info: Could not determine GitHub repository from git remotes

Important: every other step of the handoff is plain git and is ADO-safe —
check-changes (git status), checkout-branch (git fetch origin <branch> + git checkout),
event replay, save. Only the GitHub-name validation blocks it. Softening Gate B lets an ADO
session complete the handoff and replay its full history (verified locally — see the workaround
comment below).

The catch-22 for non-git sessions

A session created outside a git repo has an empty/'/' repository (upstream cause: #2655
cwd/branch/repository not persisted). The picker then enforces two mutually exclusive things:

  1. Must be INSIDE a git repo, else Error: Not in a git repository. … (Gate B).
  2. The repo must EQUAL the session's stored repo ('/'), else
    Error: Repository mismatch: You are in 'owner/name' but the remote session is for '/'. (Gate A).
    No directory satisfies both.

Reproduction

ADO:

  1. From an ADO-cloned repo, start a session, exit.
  2. copilot/resume → pick it → "Validating repository" fails with
    "Not in a git repository / Could not determine GitHub repository from git remotes",
    even though you ARE in the correct repo.
    Non-git:
  3. Run copilot in a NON-git folder, hold a conversation, exit.
  4. From a git repo: /resume → "Repository mismatch … session is for '/'".
  5. From a non-git folder: /resume → "Not in a git repository."

Workarounds attempted (all fail without a patch)

  • copilot --resume=<id>No session, task, or name matched when the session originated on
    another machine (not in this machine's local store).
  • /resume from a non-git dir → "Not in a git repository."
  • copilot --connect=<id> → bypasses the git gate BUT starts a brand-new empty session
    (returns NO-HISTORY, emits a fresh --resume=<new-id>); original transcript not recovered.
    A tested binary patch that neutralizes Gate B (and Gate A) and restores ADO/non-git resume is
    in the comment below.

Impact

  • ADO / any non-GitHub host: remote sessions cannot be resumed locally at all.
  • Sessions created before a folder became a git repo are lost to /resume.
  • Cross-machine continuation is broken.
  • --connect failing silently (new empty session) hides the real problem.

Suggested fixes

  1. Don't require a GitHub identity to validate the working directory. When
    getRepositoryInfo can't derive a GitHub owner/name (ADO, or no remote), fall back to the
    remote session's own repository metadata and continue instead of throwing.
  2. Gate A: treat hostType!=="github" (and empty/'/' repository) as "unscoped" and SKIP the
    repository-match gate — allow resume from any directory, or match on the local git root rather
    than a GitHub owner/name.
  3. Don't hard-require a git repo to open the resume picker; git context should be optional
    metadata, not a precondition.
  4. When --connect can't attach to the requested session, error explicitly instead of spawning a
    new empty session.

Related finding (may deserve its own issue)

The /resume picker also hides recent remote sessions on Windows: GET /agents/tasks returns them (paged per_page=20; the CLI fetches ~30), but
enrichTasksWithDetails drops any task whose native shouldIncludeInSessionList flag is false
(if(!l.shouldIncludeInSessionList) continue;). Result: sessions visible in the GitHub mobile
app don't appear in the CLI picker. Happy to split this out if preferred.

Related issues

#3694 (repo-name mismatch, closed), #2655 (repo/cwd not persisted), #2446, #3671 (cloud-session
resume), #3908 (empty resume dir), #2836 (orphaned session folders), #1381 (rewind git gate),
#3931.

Affected version

GitHub Copilot CLI: 1.0.71-0 (and 1.0.69-x)

Expected behavior

Sessions on non-GitHub hosts (ADO) and non-git sessions should resume and replay their history.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sessionsSession management, resume, history, session picker, and session state

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions