Skip to content

assistant-api + ui: manage a workspace's repositories (multi-repo workspaces)#595

Merged
ExtraToast merged 3 commits into
mainfrom
feat/workspace-repo-management
Jun 6, 2026
Merged

assistant-api + ui: manage a workspace's repositories (multi-repo workspaces)#595
ExtraToast merged 3 commits into
mainfrom
feat/workspace-repo-management

Conversation

@jorisjonkers-dev-agents

Copy link
Copy Markdown
Contributor

What

A workspace could only clone one repository — the workspace_repositories junction, attach/detach commands, and REPO_URLS orchestrator injection existed (#590), but nothing populated the junction or exposed it, so multi-repo workspaces were unreachable and invisible. This makes them real and manageable from the UI.

Backend

  • CreateWorkspaceCommandHandler seeds workspace_repositories on create: the workspace's own repo as is_primary=true, and — when a projectId is present — the project's linked repositories as additional members. So the orchestrator emits REPO_URLS and the runner clones every repo.
  • New endpoints dispatch the existing commands: POST /api/v1/workspaces/{id}/repositories (attach, 204) and DELETE /api/v1/workspaces/{id}/repositories/{repositoryId} (detach, 204; primary refused).
  • GET /api/v1/workspaces/{id} returns the workspace's repositories (id, name, repoUrl, isPrimary) via a detail envelope; list/create keep the existing summary shape.

Frontend

  • The workspace view lists its repositories (primary marked), adds/removes them through the new endpoints, and a split-guidance panel assembles the council split --path <p> --dest <owner>/<name> command and explains registering + linking the new repo afterward.

How it was built

Planned and implemented entirely through the council with codex — codex as both planners, consolidator, workers, and verifier (claude cost reported $0.00). 6-task DAG fanned out across codex workers in isolated worktrees.

Verification (this sandbox, no Docker)

  • Backend: :services:assistant-api:test284 unit tests pass (incl. the new handler/controller/query tests); compileIntegrationTestKotlin passes (new Testcontainers flow test compiles; CI runs it); ktlintCheck clean; jOOQ regenerates.
  • Frontend: typecheck clean, eslint . clean, 53 vitest tests pass.

⚠️ One operator step before CI is fully green

This changes the assistant-api HTTP contract (new endpoints + the repositories field), so the pinned spec + generated client must be regenerated where the app can run (your env / docker-compose) — they are intentionally NOT hand-edited here:

./gradlew :services:assistant-api:exportOpenApiSpec
pnpm --filter @personal-stack/assistant-ui contract:generate

Until then CI's Validate OpenAPI Contract will be red; everything else is green. The frontend uses local pre-regeneration types that can switch to the generated aliases after.

A workspace could only ever clone one repository: the workspace_repositories
junction, the attach/detach commands, and the REPO_URLS orchestrator
injection all existed (#590) but nothing populated the junction or exposed
it, so multi-repo workspaces were unreachable and invisible.

Backend:
- CreateWorkspaceCommandHandler seeds workspace_repositories when a
  repo-backed workspace is created: the workspace's own repository as
  is_primary=true, and — when a projectId is present — the project's linked
  repositories as additional members, so the orchestrator emits REPO_URLS and
  the runner clones them all.
- POST /api/v1/workspaces/{id}/repositories and
  DELETE /api/v1/workspaces/{id}/repositories/{repositoryId} dispatch the
  existing attach/detach commands (204).
- GET /api/v1/workspaces/{id} now returns the workspace's repositories
  (id, name, repoUrl, isPrimary) via a detail envelope; list/create keep the
  existing summary response shape.

Frontend:
- The workspace view shows its repositories (primary marked), adds/removes
  repositories through the new endpoints, and a split-guidance panel assembles
  the `council split` command for extracting a path into a new repo and
  explains registering + linking it afterward.

Built via the council with codex (planners, consolidator, workers, verifier).
The OpenAPI contract changes (new endpoints + repositories field), so
services/assistant-api/openapi.json and services/assistant-ui/src/api/generated.ts
must be regenerated by the operator with
`./gradlew :services:assistant-api:exportOpenApiSpec` and
`pnpm --filter @personal-stack/assistant-ui contract:generate` — not hand-edited.
@jorisjonkers-dev-agents jorisjonkers-dev-agents Bot added the enhancement New feature or request label Jun 6, 2026
ExtraToast and others added 2 commits June 6, 2026 14:36
The wrapped `??` expression tripped style/operator-linebreak: eslint wants
the operator at the line start, prettier moves it to the line end, and the
pre-commit hook (eslint --fix then prettier) left prettier's form, which CI's
eslint then rejected. Rewrite the computed to keep the `??` chain on one short
line via an intermediate, so eslint and prettier agree.
Regenerated after adding workspace repository management endpoints
and the repositories field to the workspace contract.
@ExtraToast ExtraToast merged commit d2e6503 into main Jun 6, 2026
42 checks passed
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.

1 participant