Skip to content

refactor(commands): route prs/issues/pr-create through the ForgeActions adapter instead of hand-branching on provider #1634

Description

@gfargo

The CLI command layer bypasses the forge adapter and branches on provider inline, contradicting the repo's own architecture rule and creating a second dispatch path that must be updated for every new forge (a direct tax on adding Gitea/Forgejo or any future forge). The workstation already does this correctly via useForgeAdapter. As of v0.81.0 (main @ 6de37e0).

AGENTS.md states the rule verbatim:

Forge work goes through the adapter. Add capabilities to the ForgeActions type in src/git/forgeActions.ts and implement for every provider (or return an explicit "unsupported on <forge>" result). Never branch on provider inside a surface.

Current state

  • src/commands/prCreate/handler.ts branches on provider directly at line 37 (if (provider !== 'github' && provider !== 'gitlab' && provider !== 'bitbucket')) and again at lines 162-182 for the create/open paths — despite createPullRequest and openPullRequest existing on ForgeActions (src/git/forgeActions.ts:148-149).
  • src/commands/prs/handler.ts and src/commands/issues/handler.ts hand-dispatch in their fetch lambdas: provider === 'gitlab' ? getMergeRequestList(...) : provider === 'bitbucket' ? getBitbucketPullRequestList(...) : getPullRequestList(...) — duplicating the dispatch that getPullRequestList/getIssueList on the adapter already encode (src/git/forgeActions.ts:117-118).
  • src/commands/utils/githubListCommand.ts:166 also special-cases gitlab for the noun label (arguably fine as presentation, but the label could come from the adapter/forge descriptor too).
  • The TUI-side precedent: src/workstation/runtime/hooks/useForgeAdapter.ts consumes getForgeActions and never sees provider ids.

Proposal

  • prCreate/handler.ts: replace the provider guards and per-provider create/open calls with getForgeActions(...)'s createPullRequest/openPullRequest; unsupported forges surface via the adapter's explicit unsupported result instead of an up-front allowlist.
  • prs/issues: change createGitHubListHandler's fetch contract to take the forge adapter (or move list-fetch dispatch fully behind getPullRequestList/getIssueList on the adapter) so the per-command spec only maps argv -> filter.
  • Optionally add a forge display descriptor (noun/labels) to the adapter so githubListCommand.ts drops its gitlab special case.
  • Adapter-dispatch coverage exists as a template: src/git/forgeDispatch.test.ts proves per-forge wiring — extend it for the command-layer paths.

Affected files

  • src/commands/prCreate/handler.ts
  • src/commands/prs/handler.ts, src/commands/issues/handler.ts
  • src/commands/utils/githubListCommand.ts
  • src/git/forgeActions.ts (possible descriptor addition)

Effort

M — the adapter methods already exist for all three forges; the work is inverting the command-layer call shape and preserving current error copy/exit codes.

Open questions

  • Should createGitHubListHandler receive the adapter object or just adapter-backed fetch functions?
  • Is the gitlab "merge request" noun a presentation concern (keep in commands) or a forge property (move to adapter)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions