Skip to content

feat(cli): add repo rm, repo set, and repo group management verbs - #8790

Open
briancripe wants to merge 4 commits into
stablyai:mainfrom
briancripe:feat/cli-repo-group-management
Open

briancripe wants to merge 4 commits into
stablyai:mainfrom
briancripe:feat/cli-repo-group-management

Conversation

@briancripe

@briancripe briancripe commented Jul 15, 2026 •

Copy link
Copy Markdown

Summary

The orca CLI could register repos (repo add) but never remove them, and project groups — a first-class app feature with full projectGroup.* RPC support — had no CLI surface at all. This adds the missing management verbs as thin wrappers over the existing runtime RPCs, so orca-data.json stays owned by the app's Store (no new persistence, schema, or backend code):

  • orca repo rm --repo <selector> (aliases remove/delete, destructive): unregisters the repo from Orca. Files and git checkouts stay on disk; spec notes call out that Orca worktree metadata is dropped irreversibly.
  • orca repo set --repo <selector> [--group <selector>|--ungroup] [--display-name <name>] [--badge-color <hex>]: repo settings via the existing repo.update RPC. Group membership is modeled as a repo attribute, matching the UI ("Move to group"/"Remove from group" live on the project context menu).
  • orca repo group list|create|set|rm: project-group lifecycle — --parent-group nesting, rename, --color null clearing, and subtree delete (repos in deleted groups are kept and become ungrouped, matching the UI behavior).

Group selectors accept id:<groupId>, name:<name>, or a bare id/unique name, mirroring the existing repo-selector semantics. Resolution happens client-side before any mutating RPC because Store.updateRepo and Store.moveProjectToGroup silently normalize an unknown projectGroupId to null — without this guard a typo'd selector would silently ungroup a repo. --badge-color is likewise validated client-side (shared normalizeRepoBadgeColor) because the store silently drops unnormalizable colors, which would otherwise report a no-op success.

specs/core.ts repo specs moved to a new specs/repo.ts to stay under the max-lines limit (no suppressions added). Bundled skill guides (src/cli/bundled-skill-guides.ts, skills/orca-cli/SKILL.md) regenerated after updating skill-guides/orca-cli.md.

Screenshots

No visual change (CLI-only). Sample output:

$ orca repo group create --name cli-e2e-group
id: e64736eb-7669-4d1f-a15e-e93e5df77fe2
name: cli-e2e-group
...
$ orca repo set --repo name:cli-e2e-repo --group nope
No project group matches "nope".
Next step: Run `orca repo group list` to see saved groups.

Testing

  • pnpm lint
  • pnpm typecheck
  • pnpm test — 29,924 passed; the only 5 failures (config/scripts/publish-complete-draft-releases.test.mjs, config/scripts/release-rc-history.test.mjs, src/shared/posix-command-path-lookup.test.ts) fail identically on the base commit without this change (local git-tag state / local zsh PATH), confirmed by running them on the unmodified base
  • pnpm build
  • Added high-quality tests: project-group-selector.test.ts (id/name/bare/ambiguous/not-found resolution), handlers/repo-group.test.ts (asserts the mutating RPC is not issued when selector resolution fails — the silent-ungroup regression guard — plus flag-validation and vanished-group error paths), workspace-format.test.ts (formatters). Registry-parity and vocabulary-policy suites enforce the new specs/handlers/aliases automatically.

Verified end-to-end against a live dev app (orca-dev): add repo → group create → repo set --group → rename/recolor → nested --parent-group child → --ungroup → subtree group rm → repo rm (via the repo delete alias), confirming the scratch repo survived on disk and a bogus --group selector exits 1 without mutating anything.

AI Review Report

Reviewed with Claude Code. Checks and outcomes:

  • Cross-platform (macOS/Linux/Windows): the change is pure TypeScript string/flag handling in src/cli; no keyboard shortcuts, labels, shell invocations, or filesystem paths were added. The only path-handling call sites (repo add) are untouched. The CLI transport (unix socket / named pipe) is unchanged.
  • SSH/remote/local: all new mutating verbs go through the runtime RPC client, so they work identically against local and remote (--environment) runtimes; group-selector resolution uses the same projectGroup.list RPC channel. No local-only assumptions introduced.
  • Agent/integration compatibility: verbs follow the CLI vocabulary policy (rm canonical with remove/delete aliases, show/set conventions); destructive: true is set so typo-recovery never steers agents into removal; agent-context schema output is generated from the specs automatically. No git-provider-specific behavior.
  • Performance: group-selector resolution adds one projectGroup.list RPC before a mutating call; group lists are small and these are interactive one-shot commands. No hot paths touched.
  • Flagged and fixed during review: (1) Store.updateRepo/moveProjectToGroup silently null unknown group ids → client-side resolution that fails loudly, with tests asserting no mutating RPC is issued on failure; (2) projectGroup.update/delete return {group: null}/{deleted: false} instead of errors for unknown ids → handlers convert these to explicit failures; (3) invalid badge colors are silently dropped by the store → client-side validation.

Security Audit

  • Input handling: all new flag values are validated client-side (selector resolution, hex-color normalization via the shared normalizeRepoBadgeColor, at-least-one-update-flag and mutually-exclusive-flag checks); server-side Zod schemas on the existing RPCs are unchanged and remain the trust boundary.
  • Command execution: none — no child processes, no shell interpolation.
  • Path handling: none added; repo rm deletes no files by design (unregister only), which the spec notes state explicitly.
  • Auth/secrets/IPC: no new RPC methods, no changes to the runtime auth/transport layer, no secrets touched. The new verbs only call pre-existing, already-exposed RPC methods that the renderer UI has used all along.
  • Destructive-operation safety: repo rm and repo group rm are marked destructive (excluded from typo-suggestion recovery) and their specs document exactly what is and is not removed.

Notes

  • No platform-specific, provider-specific, or agent-specific behavior; nothing SSH-specific beyond inheriting the existing remote RPC path.
  • On CodeRabbit's Docstring Coverage warning: this follows the repo's documented comment convention (AGENTS.md — brief "why-only" comments, don't restate what the code does). The existing CLI modules carry no docstrings, so new handlers/formatters match that style; the non-obvious constraints (silent-ungroup guard, badge-color normalization) are documented with // Why: comments in the repo's idiom.

X handle: @BrianCripe

ELI5

CLI can unregister repos and manage project groups (repo rm, repo set, group verbs). Headless workflows match more of what the desktop app already could do.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds CLI support for repository grouping and project-group management. The change defines command specifications, parses group-related flags, resolves groups by ID or name, formats group results, and registers new handlers. It adds repo set, repo rm, and repo group operations for listing, creating, updating, and removing groups. Runtime and RPC operations support connection-scoped repository and project-group resolution. Help text and bundled guides document the commands. Tests cover selector resolution, formatting, validation, RPC payloads, and host-scoped runtime behavior.

Merge Risk: ⚪ Minimal · up to e6dae

The CLI adds repository and project-group management through existing runtime operations, with no actionable merge-blocking risk remaining after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the implementation and testing well, but it omits required template sections such as Linked Issue, Review, Agent skill boundary, and Checklist. Use the repository template headings, add a linked issue, state the visual-proof result as N/A with a reason, complete the required checkboxes, and include the remaining review sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the added repository removal, repository update, and project-group management commands.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 59d906fb-d040-4493-8ddd-268d8ac0652f

📥 Commits

Reviewing files that changed from the base of the PR and between a03377f and ee7d7dc.

📒 Files selected for processing (16)
  • skill-guides/orca-cli.md
  • skills/orca-cli/SKILL.md
  • src/cli/args.ts
  • src/cli/bundled-skill-guides.ts
  • src/cli/dispatch.ts
  • src/cli/format.ts
  • src/cli/handlers/repo-group.test.ts
  • src/cli/handlers/repo-group.ts
  • src/cli/handlers/repo.ts
  • src/cli/help.ts
  • src/cli/project-group-selector.test.ts
  • src/cli/project-group-selector.ts
  • src/cli/specs/core.ts
  • src/cli/specs/repo.ts
  • src/cli/workspace-format.test.ts
  • src/cli/workspace-format.ts

Comment thread src/cli/handlers/repo.ts Resolved
Comment thread src/cli/project-group-selector.test.ts Resolved
@nwparker nwparker added the enhancement New feature or request label Jul 27, 2026
@nwparker
nwparker force-pushed the feat/cli-repo-group-management branch from 5378808 to c1cd913 Compare August 23, 2026 22:10
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@nwparker
nwparker force-pushed the feat/cli-repo-group-management branch from cc241f0 to ac5f80d Compare August 23, 2026 23:54
@nwparker

nwparker commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

Readiness verdict: code-ready; GitHub status remains a merge blocker

Rebased and force-pushed with exact leases onto current origin/main (0a613d5fed77); final head is 04c396c0da9. Final settlement confirms 0 behind / 4 ahead, a clean worktree, and content-level GitHub mergeability.

Findings

  • P0: none.
  • P1 fixed: duplicate repo IDs across execution hosts could make repo.update persist to the wrong row. Updates now retain the resolved host identity (src/main/runtime/orca-runtime.ts:21535, :21566).
  • P1 fixed: direct-SSH repo/project-group mutations could reach local or sibling-host records. Trusted SSH scope now flows through CLI selection and optional backward-compatible RPC fields, with runtime enforcement (src/cli/project-group-selector.ts:10, src/cli/handlers/repo-group.ts:15, src/cli/handlers/repo.ts:36, src/main/runtime/rpc/methods/repo.ts:12, src/main/runtime/orca-runtime.ts:20747, :21582). Cross-host repo/group assignment is rejected (src/main/runtime/orca-runtime.ts:21552).
  • P2 fixed: repo group set --color accepted arbitrary strings despite documenting hex. It now normalizes 3/6-digit hex and rejects invalid input (src/cli/handlers/repo-group.ts:51).

Reviewed crash/cast/retry/unbounded-growth, security/supply-chain, performance/resources, functional correctness, backward compatibility/data loss/mobile impact, folder workspaces, SSH ownership, mixed-version remote wire behavior, GitHub/GitLab neutrality, and macOS/Linux/Windows. No remaining proven P0/P1/P2 finding.

Tests by machine

macOS local

  • Final head: pnpm run typecheck:cli and 4 critical suites — 59 passed.
  • Immediately preceding conflict-free base rebase: 16 touched suites — 236 passed; pnpm run typecheck; pnpm run lint; pnpm run build:cli; pnpm run verify:built-skills-cli — all passed.
  • Earlier full pnpm run build passed across desktop, relays including win32 x64/arm64, CLI, Electron/main/preload/renderer, web projection, and native macOS.
  • Full-suite attempt under shared-host saturation hit three unrelated timing-sensitive tests; two passed alone. The remaining isolated src/shared/remote-runtime-shared-control-connection.test.ts deadline miss is in an unchanged file. Touched suites are green.

Windows awin, Orca 1.4.186-hourly.202608200132, exact final head 04c396c0da9

  • pnpm run build:cli and pnpm run typecheck:cli — passed.
  • 4 critical suites — 59 passed (the preceding conflict-free rebase also passed 6 suites / 97 tests).
  • Real node out/cli/index.js workflow passed on the final head: scratch repo registration; root/nested group creation; group assignment; display-name and badge-color normalization; bogus group selector exited 1 with unchanged state; repo show; ungroup; 369 normalized to #336699; group deletion; repo deregistration; .git remained; all unique scratch state cleaned.

Visual proof

N/A — CLI/runtime-only change; no rendered UI changed.

Residual risk / exact merge blocker

GitHub still reports mergeable: MERGEABLE but mergeStateStatus: UNSTABLE, with no checks reported after the final force-push. Merge should wait for required GitHub checks to materialize and pass, or for a maintainer to confirm none are required. CodeRabbit full re-review remains rate-limited; its latest completed review reported no new actionable comments.

@nwparker
nwparker force-pushed the feat/cli-repo-group-management branch from ac5f80d to 04c396c Compare August 23, 2026 23:58
briancripe and others added 4 commits August 23, 2026 17:58
The CLI could add repos but not remove them, and project groups had no
CLI surface at all despite full projectGroup.* RPC support in the
runtime. Adds thin wrappers over the existing RPCs so orca-data.json
stays owned by the app's Store:

- repo rm (aliases remove/delete): unregister a repo from Orca;
  files and checkouts stay on disk
- repo set: --group/--ungroup membership via repo.update, plus
  --display-name and --badge-color (validated client-side because the
  store silently drops unnormalizable colors)
- repo group list/create/set/rm: group lifecycle including
  --parent-group nesting, rename, --color null clearing, and
  subtree delete

Group selectors (id:/name:/bare) resolve client-side before any
mutating call because Store.updateRepo and moveProjectToGroup silently
null unknown group ids - a typo'd selector must fail loudly instead of
silently ungrouping a repo. Repo specs move from specs/core.ts to a new
specs/repo.ts to stay under the max-lines limit.
The handler printed the success message regardless of the removed flag.
The current runtime throws repo_not_found instead of returning false,
but handle the degenerate response the same way repo group rm handles
deleted: false so an older or future runtime cannot read as success.
Without expect.unreachable the catch body never runs on a regression
that resolves a duplicated bare name, letting the test pass vacuously.
@nwparker
nwparker force-pushed the feat/cli-repo-group-management branch from 04c396c to e6dae3a Compare August 24, 2026 01:03
@nwparker

Copy link
Copy Markdown
Contributor

Readiness verdict — PR #8790

Verdict: code-ready; CI pending. Final head e6dae3abd5cacdc5fbb67036fcd5d40886785fbc is rebased onto current origin/main, conflict-free, and GitHub reports MERGEABLE/UNSTABLE while required workflows queue. The rebase preserved main's newer help text and the PR's repo/group commands. Focused CLI/runtime gates and the previously completed real Windows awin validation cover the changed behavior; no P0/P1/P2 remains. Do not merge until the required workflows pass.

@nwparker

Copy link
Copy Markdown
Contributor

Readiness verdict: ready to merge on content — head e6dae3ab, MERGEABLE, CI not yet queued

Re-based onto current origin/main (5bcbafff537 — docs(cli): document worktree rm branch cleanup (#16167)), conflicts resolved, focused gates re-run green, pushed with an exact lease. GitHub now reports MERGEABLE / UNSTABLE at exact head e6dae3abd5cacdc5fbb67036fcd5d40886785fbc; the previous CONFLICTING / DIRTY state is cleared.

Rebase and conflict resolution

  • Prior head 04c396c0da9 → new head e6dae3abd5c. Pushed with --force-with-lease=refs/heads/feat/cli-repo-group-management:04c396c0da95a66e66994a2812278371b99b86a6 (exact prior head, not a bare lease).
  • Exactly one conflict: src/cli/help.ts, the --force entry in formatFlagHelp. src/cli/specs/core.ts auto-merged cleanly.
  • Resolution preserves both sides:
    • main's clarified text — --force Force worktree removal when supported; does not force branch deletion
    • this PR's five new flag entries — --group, --parent-group, --ungroup, --color, --badge-color
    • main's two worktree rm notes (archive hooks + branch-cleanup retention) intact alongside this PR's ...REPO_COMMAND_SPECS extraction.
  • Proof no PR behavior was lost: git diff <pre-rebase head> <post-rebase head> yields only the two hunks from main's commit (help.ts --force line, specs/core.ts notes) and nothing else. The PR's own diff against the new base is byte-for-byte the same shape as before: 22 files, +1207 / −56.

Gates re-run on the exact new head (macOS local, clean worktree)

Gate Result
oxfmt --check on help.ts, specs/core.ts, specs/repo.ts pass
oxlint src/cli src/main/runtime --deny-warnings pass
pnpm run typecheck:cli pass
vitest run src/cli 93 files / 937 tests passed
vitest run src/main/runtime/runtime-repo-group-host-scope.test.ts src/main/runtime/rpc/methods 96 files / 959 tests passed
pnpm run verify:bundled-skill-guides pass
pnpm run build:cli pass (verify-cli-bin OK)

Real built-CLI smoke on the rebased head confirms both sides survived the merge:

  • node out/cli/index.js repo group --help lists set, rm, group list, group create, group set, group rm.
  • node out/cli/index.js worktree rm --help renders main's new --force … does not force branch deletion text and both branch-cleanup notes.

Windows awin evidence

Carried forward from the prior review of 04c396c0da9, and still valid: the rebased tree differs from that Windows-validated head only by main's own two documentation hunks in help.ts / specs/core.ts. No CLI repo/group code path, runtime host-scope check, RPC field, or handler changed in the rebase. The previously recorded Windows run on awin (Orca 1.4.186-hourly.202608200132) — build:cli, typecheck:cli, 4 critical suites / 59 tests, plus the end-to-end node out/cli/index.js workflow covering repo registration, root/nested group create, assignment, display-name and badge-color normalization (369 → #336699), bogus-selector exit 1 with unchanged state, ungroup, group deletion, and repo deregistration with .git preserved — therefore still describes this head's behavior.

Findings

  • P0: none.
  • P1: none unresolved. Both previously reported P1s (cross-host repo.update row targeting; direct-SSH mutations reaching sibling/local records) remain fixed and their regression tests pass on this head.
  • P2: none unresolved. repo group set --color hex normalization remains in place and covered.

No new finding was introduced by the rebase; the resolution is documentation text only.

Remaining blocker

Not a code blocker — CI has not queued yet. statusCheckRollup is empty ~5 minutes after the force-push, which is why mergeStateStatus reads UNSTABLE rather than CLEAN. This is a fork-PR workflow-authorization/queue delay, not a failure. Once required checks run and pass, the PR should reach CLEAN with no further changes needed.

Visual proof

N/A — CLI/runtime-only change; no rendered UI changed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/runtime/orca-runtime.ts (1)

20749-20788: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the connection-scoped project-group lookup into one helper.

updateProjectGroup and deleteProjectGroup both re-implement the same lookup: find the group by id, compare candidate.connectionId?.trim() || null against the caller-supplied connectionId, and bail out if it does not match. createProjectGroup normalizes a parent group's connectionId the same way a few lines above.

Keep this normalization in one place. A future edit to one of the three call sites (for example, a change to how empty strings are treated) can silently diverge from the other two and reopen the host-mismatch class of bug this PR fixes.

Extract a private helper, for example findProjectGroupForConnection(groupId, connectionId), and call it from updateProjectGroup, deleteProjectGroup, and createProjectGroup's parent lookup.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7450d063-506c-4f71-8780-0b5f549038f6

📥 Commits

Reviewing files that changed from the base of the PR and between c1cd91373534d746a7407f5acc356b9e1457976d and e6dae3a.

📒 Files selected for processing (16)
  • src/cli/dispatch.ts
  • src/cli/handlers/core.test.ts
  • src/cli/handlers/repo-group.test.ts
  • src/cli/handlers/repo-group.ts
  • src/cli/handlers/repo.ts
  • src/cli/help.ts
  • src/cli/index.ts
  • src/cli/project-group-selector.test.ts
  • src/cli/project-group-selector.ts
  • src/cli/skills.test.ts
  • src/cli/specs/core.ts
  • src/cli/workspace-format.test.ts
  • src/cli/workspace-format.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/methods/repo.ts
  • src/main/runtime/runtime-repo-group-host-scope.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/cli/help.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 1 remains after this review.

@CristianDeluxe

Copy link
Copy Markdown

+1 on getting this merged. Concrete case: I have 118 repos registered in Orca 1.4.215 on one Mac, and the only structure the sidebar offers is Project Groups, which today exist only as manual UI actions (right-click, "New group from project" / "Move to group").

What I actually want is to let an agent do the organizing, not do it by hand. I already drive Orca from Claude Code and Codex through orca ... --json (worktrees, terminals, handoffs), so the natural next step is "group these repos by client, move the finished ones to an Archive group, drop the ones that no longer exist on disk" as one prompt. Right now that stops at the group boundary: orca project list --json does not report a project's group, there is no project group / repo rm verb, and badgeColor is read-only. The agent can register repos but cannot tidy the result, so 118 flat entries stay flat.

Since the last readiness verdict on this PR was "ready to merge on content, CI pending" a month ago, is there anything blocking it beyond CI? Happy to rebase-test the branch locally against current main if that helps.

@oliver-mee

Copy link
Copy Markdown
Contributor

Supporting this from an agent-orchestration workflow. We can register repos and launch workers from the CLI, but cannot finish organising those repos into their existing project groups. That leaves a manual desktop step in an otherwise headless workflow; putting the preference in an agent skill does not help when the command is missing.

The group listing and assignment commands here would cover that gap. Resolving group selectors before mutation, especially rejecting an unknown group without silently ungrouping the repo, is particularly useful for agents. Related use case: #8766. I have checked the missing surface in the installed CLI, but have not tested this PR's current head.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants