Skip to content

Add nested repo group imports - #2866

Merged
brennanb2025 merged 23 commits into
mainfrom
brennanb2025/folder-setup
May 27, 2026
Merged

brennanb2025 merged 23 commits into
mainfrom
brennanb2025/folder-setup

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Import nested repositories as recursive project groups instead of one flat group.
  • Support local, runtime RPC, and SSH remote nested scans/imports with validation and sanitized error handling.
  • Harden project group persistence/state cleanup, runtime switching, grouped project ordering, and multi-repo worktree hydration.

Design

  • Design doc: tmp/folder-setup-design.md.
  • Design review completed clean after tightening the plan around SSH support, runtime parity, recursive deletion, and import-time re-scan safety.
  • Self-check completed before implementation reconciliation.

Review

  • Implementation/completeness pass found and fixed recursive group delete behavior.
  • Code-review loop ran until clean.
  • Key fixes from review:
    • Fetch worktrees for every imported repo.
    • Disable stale global repo drag ordering when project groups are present.
    • Reject local/runtime relative nested import paths.
    • Pass connectionId through SSH remote add-project nested imports.
    • Sanitize unexpected per-repo import errors.
    • Clear project groups on runtime switch.
    • Sanitize invalid persisted project group updates.

Tests

  • pnpm run typecheck
  • pnpm run lint
  • git diff --check
  • pnpm vitest run --config config/vitest.config.ts src/main/ipc/runtime.test.ts src/main/project-groups/nested-repo-discovery.test.ts src/main/project-groups/nested-repo-import.test.ts src/shared/project-groups.test.ts src/main/ipc/repos-remote.test.ts src/main/runtime/rpc/methods/repo.test.ts src/renderer/src/store/slices/repos-project-groups.test.ts src/renderer/src/components/sidebar/worktree-list-groups.test.ts src/renderer/src/components/onboarding/RepoStep.test.tsx
    • 9 files passed, 118 tests.
  • pnpm run test:e2e -- tests/e2e/folder-setup.spec.ts
    • 1 passed.

Manual Validation

  • Launched the exact PR worktree in Electron dev with CDP and verified identity:
    • Orca: brennanb2025/folder-setup
    • /Users/thebr/orca/workspaces/orca/folder-setup
  • Local realistic microservices parent folder under /Users/thebr/source/repos/Stably/orca-setup-script-cases/microservices-platform:
    • Found apps/web, packages/sdk, services/api, services/billing.
    • Skipped a real git repo under node_modules/ignored-git-repo.
    • Imported 4 repos into recursive groups microservices-platform, apps, packages, services with expected project-group ordering.
  • Direct git repo selection:
    • Scanning setup-demo-has-orca-setup returned selectedPathKind: git_repo and no nested repo import candidates.
  • Import separately flow via IPC:
    • Imported temp admin and worker repos without project-group membership and with no group delta.
  • Runtime RPC live path:
    • window.api.runtime.call({ method: 'projectGroup.scanNested' }) found temp gateway and jobs repos.
    • projectGroup.importNested imported both into runtime-platform with orders [0, 1].
  • Added focused runtime IPC regression coverage for projectGroup.list through runtime:call.

SSH Validation

  • pnpm build:relay
  • Used a throwaway Linux Docker SSH target, not ssh localhost.
  • Connected Orca to the target via key-based SSH and verified ssh:connect reached connected.
  • Remote target shape:
    • Ubuntu 24.04 container
    • installed openssh-server, git, nodejs, npm
    • key-based SSH as root on a host-mapped localhost port
  • Remote nested repo fixture:
    • /work/platform/apps/web
    • /work/platform/services/api
    • /work/platform/services/billing
    • /work/platform/node_modules/ignored
    • all initialized as real git repos with committed README files.
  • SSH nested scan/import via window.api.projectGroups.scanNested/importNested with connectionId:
    • Found web, api, billing.
    • Skipped the real git repo under /work/platform/node_modules/ignored.
    • Imported 3 SSH repos with the same connectionId into recursive groups remote-platform, apps, services and expected orders [0], [0, 1].
  • Remote backing proof:
    • find /work/platform -maxdepth 4 -name .git showed all remote fixture repos, including the ignored repo.
    • git status --short --branch returned ## master for apps/web, services/api, and services/billing.
  • Relay/app log evidence:
    • remote platform detected as Linux
    • relay uploaded/installed
    • relay launched successfully
  • Cleanup:
    • throwaway container removed
    • temp keys, temp repos, temp user-data, and dev app processes removed

Gaps

  • No known blocking validation gaps.

brennanb2025 and others added 20 commits May 25, 2026 14:42
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
…etup

# Conflicts:
#	src/renderer/src/components/onboarding/OnboardingFlow.tsx
#	src/renderer/src/components/onboarding/use-onboarding-flow.ts
#	src/renderer/src/components/sidebar/WorktreeList.tsx
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
…etup

# Conflicts:
#	src/renderer/src/components/floating-terminal/FloatingTerminalPanel.tsx
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
@brennanb2025
brennanb2025 force-pushed the brennanb2025/folder-setup branch from 6a68d47 to fab3701 Compare May 27, 2026 22:55
…etup

# Conflicts:
#	.github/workflows/pr.yml
@brennanb2025 brennanb2025 reopened this May 27, 2026
…etup

# Conflicts:
#	src/main/ipc/repos.ts
#	src/main/persistence.ts
#	src/main/runtime/orca-runtime.ts
#	src/main/runtime/rpc/methods/repo.ts
#	src/preload/api-types.ts
#	src/renderer/src/store/slices/repos.ts
#	src/shared/types.ts
…etup

# Conflicts:
#	config/scripts/install-electron-package-binary.mjs
@brennanb2025
brennanb2025 merged commit 76ae675 into main May 27, 2026
1 check failed
@brennanb2025
brennanb2025 deleted the brennanb2025/folder-setup branch May 27, 2026 23:22
brennanb2025 added a commit that referenced this pull request Aug 19, 2026
) (#15404)

* fix(sidebar): render folder workspaces under every Group by mode (#15362)

Folder-workspace rows were emitted in exactly one place, inside the
repo-grouping branch of buildRows, so switching the sidebar to Status,
PR status or None dropped them from every lane.

Membership is now decided once, above the groupBy switch; a mode only
chooses which lane a workspace lands in. Lane assignment is an exhaustive
WorktreeGroupBy switch with no default clause, so a future grouping mode
is a compile error here rather than a silent regression.

Not a regression: the groupBy !== 'repo' gate predates folder workspaces
by two weeks (#2866), and #5172 added folder-workspace emission below it,
unreachable for non-repo grouping from its first commit.

Also fixes four further paths where the same row kind went missing:

- Flat mode gated its whole section on worktree count, so an account with
  only folder workspaces rendered nothing at all.
- A collapsed folder-only lane header rendered globally instead of under
  its host section, because empty worktree lists yield undefined host
  counts. Host id maps now carry explicit empty arrays so the host
  fallback cannot leak global worktree ids.
- Reveal resolved folder workspaces to project-group header keys only, so
  revealing one inside a collapsed lane never expanded it. Reveal now
  reuses the same lane function as grouping, expands the host header, and
  covers the agent-send path and the host-qualified row lookup.
- The Clear Filters empty state ignored folder workspaces, so a
  folder-only account lost them whenever any filter was active. This one
  reproduced under Project grouping too.

Behaviour deliberately unchanged: archived folder workspaces are still
not filtered, matching current behaviour rather than making membership
mode-dependent. Pinned folder workspaces still render in their natural
lane rather than the Pinned section, now uniformly across modes.

* fix(sidebar): count folder workspaces in host badges
paidaxingyo666 pushed a commit to paidaxingyo666/Manta that referenced this pull request Aug 21, 2026
…blyai#15362) (stablyai#15404)

* fix(sidebar): render folder workspaces under every Group by mode (stablyai#15362)

Folder-workspace rows were emitted in exactly one place, inside the
repo-grouping branch of buildRows, so switching the sidebar to Status,
PR status or None dropped them from every lane.

Membership is now decided once, above the groupBy switch; a mode only
chooses which lane a workspace lands in. Lane assignment is an exhaustive
WorktreeGroupBy switch with no default clause, so a future grouping mode
is a compile error here rather than a silent regression.

Not a regression: the groupBy !== 'repo' gate predates folder workspaces
by two weeks (stablyai#2866), and stablyai#5172 added folder-workspace emission below it,
unreachable for non-repo grouping from its first commit.

Also fixes four further paths where the same row kind went missing:

- Flat mode gated its whole section on worktree count, so an account with
  only folder workspaces rendered nothing at all.
- A collapsed folder-only lane header rendered globally instead of under
  its host section, because empty worktree lists yield undefined host
  counts. Host id maps now carry explicit empty arrays so the host
  fallback cannot leak global worktree ids.
- Reveal resolved folder workspaces to project-group header keys only, so
  revealing one inside a collapsed lane never expanded it. Reveal now
  reuses the same lane function as grouping, expands the host header, and
  covers the agent-send path and the host-qualified row lookup.
- The Clear Filters empty state ignored folder workspaces, so a
  folder-only account lost them whenever any filter was active. This one
  reproduced under Project grouping too.

Behaviour deliberately unchanged: archived folder workspaces are still
not filtered, matching current behaviour rather than making membership
mode-dependent. Pinned folder workspaces still render in their natural
lane rather than the Pinned section, now uniformly across modes.

* fix(sidebar): count folder workspaces in host badges
dallascrilley pushed a commit to dallascrilley/orca that referenced this pull request Aug 27, 2026
…blyai#15362) (stablyai#15404)

* fix(sidebar): render folder workspaces under every Group by mode (stablyai#15362)

Folder-workspace rows were emitted in exactly one place, inside the
repo-grouping branch of buildRows, so switching the sidebar to Status,
PR status or None dropped them from every lane.

Membership is now decided once, above the groupBy switch; a mode only
chooses which lane a workspace lands in. Lane assignment is an exhaustive
WorktreeGroupBy switch with no default clause, so a future grouping mode
is a compile error here rather than a silent regression.

Not a regression: the groupBy !== 'repo' gate predates folder workspaces
by two weeks (stablyai#2866), and stablyai#5172 added folder-workspace emission below it,
unreachable for non-repo grouping from its first commit.

Also fixes four further paths where the same row kind went missing:

- Flat mode gated its whole section on worktree count, so an account with
  only folder workspaces rendered nothing at all.
- A collapsed folder-only lane header rendered globally instead of under
  its host section, because empty worktree lists yield undefined host
  counts. Host id maps now carry explicit empty arrays so the host
  fallback cannot leak global worktree ids.
- Reveal resolved folder workspaces to project-group header keys only, so
  revealing one inside a collapsed lane never expanded it. Reveal now
  reuses the same lane function as grouping, expands the host header, and
  covers the agent-send path and the host-qualified row lookup.
- The Clear Filters empty state ignored folder workspaces, so a
  folder-only account lost them whenever any filter was active. This one
  reproduced under Project grouping too.

Behaviour deliberately unchanged: archived folder workspaces are still
not filtered, matching current behaviour rather than making membership
mode-dependent. Pinned folder workspaces still render in their natural
lane rather than the Pinned section, now uniformly across modes.

* fix(sidebar): count folder workspaces in host badges
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
Co-authored-by: Orca <help@stably.ai>
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…blyai#15362) (stablyai#15404)

* fix(sidebar): render folder workspaces under every Group by mode (stablyai#15362)

Folder-workspace rows were emitted in exactly one place, inside the
repo-grouping branch of buildRows, so switching the sidebar to Status,
PR status or None dropped them from every lane.

Membership is now decided once, above the groupBy switch; a mode only
chooses which lane a workspace lands in. Lane assignment is an exhaustive
WorktreeGroupBy switch with no default clause, so a future grouping mode
is a compile error here rather than a silent regression.

Not a regression: the groupBy !== 'repo' gate predates folder workspaces
by two weeks (stablyai#2866), and stablyai#5172 added folder-workspace emission below it,
unreachable for non-repo grouping from its first commit.

Also fixes four further paths where the same row kind went missing:

- Flat mode gated its whole section on worktree count, so an account with
  only folder workspaces rendered nothing at all.
- A collapsed folder-only lane header rendered globally instead of under
  its host section, because empty worktree lists yield undefined host
  counts. Host id maps now carry explicit empty arrays so the host
  fallback cannot leak global worktree ids.
- Reveal resolved folder workspaces to project-group header keys only, so
  revealing one inside a collapsed lane never expanded it. Reveal now
  reuses the same lane function as grouping, expands the host header, and
  covers the agent-send path and the host-qualified row lookup.
- The Clear Filters empty state ignored folder workspaces, so a
  folder-only account lost them whenever any filter was active. This one
  reproduced under Project grouping too.

Behaviour deliberately unchanged: archived folder workspaces are still
not filtered, matching current behaviour rather than making membership
mode-dependent. Pinned folder workspaces still render in their natural
lane rather than the Pinned section, now uniformly across modes.

* fix(sidebar): count folder workspaces in host badges
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant