feat(m18): reshape repo into Bun + Turbo workspace #171

Merged
code-lead merged 1 commit from boss/162 into main 2026-04-20 17:50:04 +00:00
Collaborator

Closes #162

Summary

First brick of M18 — reshape the single src/ tree into a Bun + Turbo
monorepo so the new React 19 web app and the cross-app TypeScript types
have a home next to the existing Bun service.

apps/
  server/     Bun HTTP service (unchanged behaviour; boots on 4500)
  web/        Vite + React 19 empty shell (UI lands in M18-2+)
packages/
  shared/     TaskRecord, ResolvedAgent, ContainerConfig,
              SSE envelopes, QueueResponse — consumed by both apps
              via workspace:*
turbo.json    build / dev / qa / test / typecheck pipelines

Migration safety

  • git mv src/ apps/server/src/ — every rename preserves history.
    Remaining path fixes: one extra ../ level on references to
    config/, skills/, and the Dockerfile.
  • systemd unit + justfile now boot the server from
    bun run apps/server/src/main.ts — identical to pre-M18 dispatch
    behaviour, no UX regression. Legacy dashboard.html still serves
    on http://localhost:4500/.
  • CI workflows (.forgejo/workflows/{qa,release}.yml) cache per-
    workspace node_modules + .turbo alongside the root cache; one
    QA job still covers the whole monorepo; release still compiles the
    single server binary.
  • Biome now lints the whole workspace; JSON data dirs (config/,
    design/, skills/, specs/, ops/, docs/, patches/,
    penpot-mcp-server/) are excluded so the restructure diff doesn't
    sweep in cosmetic reformats of runtime config.

Test plan

  • bun install at the root links @claude-hooks/shared into
    both apps via workspace :*.
  • bun x biome check . — clean across 76 files.
  • bun x biome format . — clean.
  • bun x turbo run typecheck — 3 packages (server, web, shared)
    pass.
  • bun test from the workspace root — 634 pass, 0 fail.
  • bun test from apps/server/ — same 634 pass.
  • bun build apps/server/src/main.ts --compile — produces a
    working binary (ci-build path).
  • CI (qa.yml + release.yml) green on this PR.

Docs

  • Root README.md gains a "Workspace layout" section.
  • CLAUDE.md Modules table now prefixes every entry with
    apps/server/src/; stale src/... references in skills, ADRs,
    and the labels.json inline comment are updated.
  • Each apps/* and packages/* has a short README with dev commands.

Out of scope

  • Any UI work in apps/web — shell only, populated by #M18-2.
  • npm/pnpm migration.
  • Splitting apps/server into sub-packages.
Closes #162 ## Summary First brick of M18 — reshape the single `src/` tree into a Bun + Turbo monorepo so the new React 19 web app and the cross-app TypeScript types have a home next to the existing Bun service. ```text apps/ server/ Bun HTTP service (unchanged behaviour; boots on 4500) web/ Vite + React 19 empty shell (UI lands in M18-2+) packages/ shared/ TaskRecord, ResolvedAgent, ContainerConfig, SSE envelopes, QueueResponse — consumed by both apps via workspace:* turbo.json build / dev / qa / test / typecheck pipelines ``` ## Migration safety - `git mv src/ apps/server/src/` — every rename preserves history. Remaining path fixes: one extra `../` level on references to `config/`, `skills/`, and the `Dockerfile`. - systemd unit + justfile now boot the server from `bun run apps/server/src/main.ts` — identical to pre-M18 dispatch behaviour, no UX regression. Legacy `dashboard.html` still serves on `http://localhost:4500/`. - CI workflows (`.forgejo/workflows/{qa,release}.yml`) cache per- workspace `node_modules` + `.turbo` alongside the root cache; one QA job still covers the whole monorepo; release still compiles the single server binary. - Biome now lints the whole workspace; JSON data dirs (`config/`, `design/`, `skills/`, `specs/`, `ops/`, `docs/`, `patches/`, `penpot-mcp-server/`) are excluded so the restructure diff doesn't sweep in cosmetic reformats of runtime config. ## Test plan - [x] `bun install` at the root links `@claude-hooks/shared` into both apps via workspace `:*`. - [x] `bun x biome check .` — clean across 76 files. - [x] `bun x biome format .` — clean. - [x] `bun x turbo run typecheck` — 3 packages (server, web, shared) pass. - [x] `bun test` from the workspace root — 634 pass, 0 fail. - [x] `bun test` from `apps/server/` — same 634 pass. - [x] `bun build apps/server/src/main.ts --compile` — produces a working binary (ci-build path). - [ ] CI (qa.yml + release.yml) green on this PR. ## Docs - Root `README.md` gains a "Workspace layout" section. - `CLAUDE.md` Modules table now prefixes every entry with `apps/server/src/`; stale `src/...` references in skills, ADRs, and the `labels.json` inline comment are updated. - Each `apps/*` and `packages/*` has a short README with dev commands. ## Out of scope - Any UI work in `apps/web` — shell only, populated by #M18-2. - npm/pnpm migration. - Splitting `apps/server` into sub-packages.
feat(m18): reshape repo into Bun + Turbo workspace (apps/server, apps/web, packages/shared)
All checks were successful
qa / qa (pull_request) Successful in 4m26s
qa / dockerfile (pull_request) Successful in 10s
c0eb231573
Closes #162 (M18-1). First brick of the milestone that splits the single
src/ tree into a monorepo so the new React 19 web app and the shared
TypeScript types have a home next to the existing Bun service.

Layout:
  apps/server/     Bun HTTP service — moves wholesale from src/ with import
                   paths rewritten (one extra "../" level for config/,
                   skills/, Dockerfile).
  apps/web/        Vite + React 19 empty shell. Imports one type from
                   @claude-hooks/shared to prove the workspace wiring. UI
                   lands in M18-2+.
  packages/shared/ Pure TypeScript types — TaskRecord, ResolvedAgent,
                   ContainerConfig, SSE event envelopes, QueueResponse.
                   Both apps consume via workspace:*.

Workspace tooling:
  - root package.json declares Bun workspaces and pins turbo@^2.3.
  - turbo.json defines build / dev / qa / test / typecheck pipelines;
    `just dev` fans out to server + web in parallel.
  - biome scope widened to the whole workspace; JSON data dirs
    (config/, design/, skills/, specs/, …) explicitly ignored so the
    M18-1 diff doesn't sweep in cosmetic token reformats.

Migration safety:
  - systemd unit + justfile updated — ExecStart now runs
    `bun run apps/server/src/main.ts`; release ci-build compiles the
    same entry. Every service code path boots identically to pre-M18.
  - `bun test` from the workspace root and from apps/server/ both pass
    (634 tests, 0 failures).
  - `.forgejo/workflows/{qa,release}.yml` cache the per-workspace
    node_modules + .turbo alongside the root cache.

Docs:
  - root README gains a "Workspace layout" section.
  - CLAUDE.md Modules table now prefixes every entry with
    apps/server/src/; stale `src/...` references in skills, ADRs, and
    the labels.json inline comment are updated.
Collaborator

CI still pending at review time (run #1762, sha c0eb231). Stepping off the review request — will be re-dispatched automatically when CI completes.

CI still pending at review time (run #1762, sha `c0eb231`). Stepping off the review request — will be re-dispatched automatically when CI completes.
Collaborator

Review — feat(m18): reshape repo into Bun + Turbo workspace

CI: green (run #1762, 4m36s, sha c0eb231)


Acceptance criteria (issue #162)

Criterion Status
Root Bun workspace package.json with workspaces: ["apps/*", "packages/*"]
turbo.json with build, dev, qa, test, typecheck pipelines
apps/server/ — all src/*.ts moved, boots on 4500
apps/web/ — empty Vite + React 19 shell
packages/shared/TaskRecord, ResolvedAgent, ContainerConfig, SSE envelopes, QueueResponse
just devturbo run dev; just qa → typecheck + lint + format
All import paths rewritten (no lingering from "../src/…") CI typechecks pass
bun test works from workspace root and apps/server/ 634 pass
qa.yml + release.yml cache per-workspace node_modules + .turbo
systemd unit runs bun run apps/server/src/main.ts
Root README workspace section; per-package READMEs
CLAUDE.md Modules table prefixed with apps/server/src/

All acceptance criteria met. The refactor is clean and structurally sound.


Findings (non-blocking nits)

Stale path in generated exec-shim comment

apps/server/src/container.tsensureExecShim

The generated shell script contains:

# See src/container.ts `ensureExecShim` for the contract.

Should be apps/server/src/container.ts. The shim is written to disk so operators who inspect it see the wrong path.

Stale src/ paths in webhook-config.ts JSDoc

apps/server/src/webhook-config.tsWebhookConfig.repos JSDoc

Three references still point at the old flat layout:

  • src/labels.tsapps/server/src/labels.ts
  • src/webhook.tsapps/server/src/webhook.ts
  • src/webhook-handlers.ts#dispatchBreakdownapps/server/src/webhook-handlers.ts

Turbo build task output path mismatch

turbo.json

"outputs": ["dist/**", "build/**"] but apps/server's build script emits to ../../claude-hooks (repo root). Turbo won't cache the server binary. Doesn't affect CI (just ci-build bypasses Turbo entirely), but turbo run build locally will never get a cache hit for the server. Worth aligning during M18-2 when the web app's dist/ output is wired in.


None of these are blockers. The monorepo reshape is correct, safe, and CI-validated.

APPROVED


Note: create_pull_review is not available in the active Forgejo MCP tool set — this approval is posted as an issue comment rather than a formal review verdict. The dispatcher may need to handle merge via the comment event or manually.

## Review — feat(m18): reshape repo into Bun + Turbo workspace **CI**: ✅ green (run #1762, 4m36s, sha `c0eb231`) --- ### Acceptance criteria (issue #162) | Criterion | Status | |---|---| | Root Bun workspace `package.json` with `workspaces: ["apps/*", "packages/*"]` | ✅ | | `turbo.json` with `build`, `dev`, `qa`, `test`, `typecheck` pipelines | ✅ | | `apps/server/` — all `src/*.ts` moved, boots on 4500 | ✅ | | `apps/web/` — empty Vite + React 19 shell | ✅ | | `packages/shared/` — `TaskRecord`, `ResolvedAgent`, `ContainerConfig`, SSE envelopes, `QueueResponse` | ✅ | | `just dev` → `turbo run dev`; `just qa` → typecheck + lint + format | ✅ | | All import paths rewritten (no lingering `from "../src/…"`) | ✅ CI typechecks pass | | `bun test` works from workspace root and `apps/server/` | ✅ 634 pass | | `qa.yml` + `release.yml` cache per-workspace `node_modules` + `.turbo` | ✅ | | systemd unit runs `bun run apps/server/src/main.ts` | ✅ | | Root README workspace section; per-package READMEs | ✅ | | CLAUDE.md Modules table prefixed with `apps/server/src/` | ✅ | All acceptance criteria met. The refactor is clean and structurally sound. --- ### Findings (non-blocking nits) #### Stale path in generated exec-shim comment **`apps/server/src/container.ts` → `ensureExecShim`** The generated shell script contains: ```sh # See src/container.ts `ensureExecShim` for the contract. ``` Should be `apps/server/src/container.ts`. The shim is written to disk so operators who inspect it see the wrong path. #### Stale `src/` paths in `webhook-config.ts` JSDoc **`apps/server/src/webhook-config.ts` → `WebhookConfig.repos` JSDoc** Three references still point at the old flat layout: - `src/labels.ts` → `apps/server/src/labels.ts` - `src/webhook.ts` → `apps/server/src/webhook.ts` - `src/webhook-handlers.ts#dispatchBreakdown` → `apps/server/src/webhook-handlers.ts` #### Turbo `build` task output path mismatch **`turbo.json`** `"outputs": ["dist/**", "build/**"]` but `apps/server`'s build script emits to `../../claude-hooks` (repo root). Turbo won't cache the server binary. Doesn't affect CI (`just ci-build` bypasses Turbo entirely), but `turbo run build` locally will never get a cache hit for the server. Worth aligning during M18-2 when the web app's `dist/` output is wired in. --- None of these are blockers. The monorepo reshape is correct, safe, and CI-validated. **APPROVED ✅** --- *Note: `create_pull_review` is not available in the active Forgejo MCP tool set — this approval is posted as an issue comment rather than a formal review verdict. The dispatcher may need to handle merge via the comment event or manually.*
claude-desktop left a comment

Approving on behalf of reviewer — the review at forge.jacquin.app/charles/claude-hooks/pulls/171#issuecomment-6826 is a proper APPROVAL with three accurate non-blocking nits (stale src/ paths in the exec-shim comment + webhook-config JSDoc, turbo build output path mismatch). It was posted as an issue comment instead of a formal review because create_pull_review was missing from the reviewer agent's forgejo-mcp allowlist — fixed in c49fd11. Posting here to unblock the merge dispatch; the three nits can land in a follow-up.

Approving on behalf of `reviewer` — the review at forge.jacquin.app/charles/claude-hooks/pulls/171#issuecomment-6826 is a proper APPROVAL with three accurate non-blocking nits (stale `src/` paths in the exec-shim comment + webhook-config JSDoc, turbo `build` output path mismatch). It was posted as an issue comment instead of a formal review because `create_pull_review` was missing from the reviewer agent's forgejo-mcp allowlist — fixed in c49fd11. Posting here to unblock the merge dispatch; the three nits can land in a follow-up.
code-lead deleted branch boss/162 2026-04-20 17:50:05 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!171
No description provided.