Fix Dispatch Flag Suggestion for Local Checkouts

can u review this trail? https://entire.io/gh/entireio/cli/trails/1489/dispatch-address-a-checkout-by-its-origin-s-forge-not
The change is sound and close to approvable. I found one real (but small) bug and a few minor issues. The affected tests pass locally (dispatch, search, and the wizard tests in cli). The trail shows CI green and the agent-findings gate passing; the only open gate is approvals.
What the PR does
Dispatch used to reject any non-GitHub origin. It now reads the origin through gitremote.ParseURL and keeps the forge the remote names, producing gh/… or et/…. Cloud mode sends that slug as-is. Local mode labels GitHub repos with their bare name as before and native repos with et/…, with no github.com link. Wizard discovery now includes native checkouts. The old GitHub-only parser in search is removed. Both callers move to the new helper, so nothing still uses the old one.
Findings
1. Local mode tells the user to pass --repos, which --local rejects (cmd/entire/cli/dispatch/mode_local.go:482, :485, :491)
resolveOriginRepoSlug is shared by cloud mode and local mode (enumerateRepoCandidates), and all three of its errors now say "pass --repos". But options.go:28 refuses that combination: --repos cannot be used with --local. So someone running entire dispatch --local in a GitLab checkout is pointed to a flag that is then refused. The old messages didn't suggest the flag, so this is new in the PR.
Fix: drop the hint from the shared helper and add it in runServer when it wraps the error, or make the message depend on the mode. OriginRepoSlug's own message ("expected gh/<owner>/<repo> or et/<project>/<repo>") reads fine in both modes.
2. Lost test coverage for paths with extra segments (origin_slug_test.go)
The deleted TestParseGitHubRemote_RejectsExtraPathSegments covered the strings.Contains(info.Repo, "/") branch. Nothing replaces it, so that branch in OriginRepoSlug is now untested. Suggested table rows:
https://github.com/acme/thing/extra.gitentire://cell/et/proj/repo/extra
The ssh://git@github.com/… form also lost its only test.
3. Nit: the origin slug isn't checked against the --repos grammar
OriginRepoSlug builds forge/owner/repo by hand. The round-trip test checks only two remotes against normalizeRepoSlug. A native project or repo name that repoNamePattern rejects (for example a leading _) would be sent by default but refused if typed explicitly. That is exactly what the round-trip test says must not happen. Running the result through SplitRepoSlug would make that rule hold for every input.
4. Nit: stale comment (repo_url.go:14-16)
It still says "the origin remote is GitHub by construction". The code still behaves correctly, because only gh slugs reach it bare, but the reasoning in the comment is no longer true.
5. The known follow-up is now more visible
The PR lists "authenticated repo list labels every row gh/" as out of scope. Now that disk discovery returns et/…, a native repo could appear as both et/x/y (from disk) and gh/x/y (from the server list) in the picker, if the server listing includes native repos. I didn't verify whether it does. It's fine to defer, but it's worth a tracked issue.
Verdict: approve once #1 is fixed. #2 is a quick addition, and #3–#5 are optional. I haven't posted anything on the trail; I can add these as trail comments or request changes if you want.
uhm,quick question. Why was it failing because of the forge? is it fetching remote changes?
No, it doesn't fetch anything. The failure happened locally, before any network call, while parsing the origin URL string.
Before this PR, dispatch's code that works out which repo you're in called search.ParseGitHubRemote(originURL), which accepted only remotes whose canonical host was github.com:
https://github.com/acme/thing→ hostgithub.com→ acceptedentire://cell/gh/acme/thing(a GitHub mirror) → theghtoken maps back togithub.com→ acceptedentire://aws-us-east-2.entire.io/et/entirehq/entire-api(native) →ethas no upstream host, soCanonicalHost()falls back to the cell hostaws-us-east-2.entire.io→ notgithub.com→ error: "dispatch currently supports GitHub origin remotes only"
That parsed name is only used to identify the repo:
- Cloud mode: it becomes the
reposvalue in the request to the Entire server, so the server knows which repo to summarize. A native checkout errored before the request was built. That's why--repos et/…already worked: passing it skips the origin lookup. - Local mode: it's just the label for the repo group. The checkpoints come from the local checkpoint store either way, so rejecting a native checkout there was purely the name lookup being too strict.
So "forge" here only means "which forge does the origin URL say this repo lives on." The PR stops assuming that's GitHub and keeps whatever forge the URL names (gh or et).
Yes, but only read-only, local git operations. Dispatch never fetches, pushes, or writes refs.
Cloud mode (the default) does one git-related thing: it opens the repo with go-git and reads the origin URL from the git config, which is what this PR changes. The summary itself is generated on the Entire server, which already has the checkpoints.
Local mode (--local) reads more:
git rev-parse --show-toplevelto find the repo root (mode_local.go:167).git log <range> --grep Entire-Checkpoint:to find checkpoint IDs reachable from the current branch (mode_local.go:369).git log --all --grep Entire-Checkpoint:to get commit subjects for those checkpoints (mode_local.go:543).git symbolic-ref refs/remotes/origin/HEAD,rev-parse --verifyandmerge-base --is-ancestorto work out the default branch and the commit range (mode_local.go:440-461).- A read of the checkpoint store,
checkpoint.OpenwithReadRemotes. That reads the local metadata branch and then the remote-tracking refs already on disk. It passes no fetchers, and the code comment atmode_local.go:293says it never touches the network. A checkpoint that hasn't been fetched yet falls back to its commit subject.
The wizard also runs git rev-parse --show-toplevel on candidate directories (dispatch_wizard.go:537).
So local mode's output is only as fresh as your last git fetch. If teammates' checkpoints haven't been fetched, you get the commit-subject fallback instead of the full session summary.
Side note: those exec.CommandContext(ctx, "git", …) calls predate this PR and run without the execx helpers. Dispatch runs as a user command rather than inside a hook, so the repo-override rule in CLAUDE.md doesn't strictly apply.
I fixed finding 1 on a new branch, dispatch-local-repos-hint, cut from the latest origin/main. Nothing is committed or pushed yet.
The change:
dispatch/mode_local.go:resolveOriginRepoSlugno longer mentions--reposin any of its three errors. That function is shared by both modes, and local mode refuses--repos. A short comment explains why.dispatch/mode_cloud.go: the cloud path adds the hint when it gets the error:… (or pass --repos gh/<owner>/<repo> or et/<project>/<repo> to name the repo). Cloud users see the same advice as before.dispatch/mode_local_test.go: a new test,TestLocalMode_UnknownOriginHostDoesNotSuggestRepos, runs local mode in a checkout whose origin is on gitlab.com. It checks that the error names the host and does not mention--repos. I confirmed it fails onmain(the error there says "pass --repos to name the repo") and passes with the fix.
Verification: mise run fmt changed nothing, mise run lint reports 0 issues, and the dispatch and cli package tests pass. The existing cloud test that requires the --repos hint still passes. I haven't run the full mise run check; CLAUDE.md requires it before committing, so I'll run it then.
Local mode's error still ends with "expected gh/<owner>/<repo> or et/<project>/<repo>", which comes from OriginRepoSlug. It describes what a valid origin looks like and doesn't name a flag, so I left it alone.
Should I run mise run check, commit, and open a PR?