Initial Commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-20
|
||||
135
openspec/changes/restructure-packages-by-category/design.md
Normal file
135
openspec/changes/restructure-packages-by-category/design.md
Normal file
@@ -0,0 +1,135 @@
|
||||
## Context
|
||||
|
||||
`packages/` currently holds 41 sibling folders at depth 2 (`packages/<plugin>/<pkg>/`). Three plugins (`geo`, `i18n`, `r3f`) collide with same-named packages they contain, producing `packages/geo/geo/`, `packages/i18n/i18n/`, `packages/r3f/r3f/`. A 4th catch-all (`platform/`) groups unrelated packages, and `STATUS.md` admits an implicit `unknown/` bucket. The user wrote `PROPOSED_STRUCTURE.md` with 18 stable category names; this design turns that into an executable migration.
|
||||
|
||||
The user's first-draft mechanic was a `packages_temp/` swap. That breaks Git rename detection for files whose containing directory is recreated mid-operation. `git mv` per plugin folder is strictly better — same end-state, full rename detection, single atomic commit.
|
||||
|
||||
Constraints: no public surface change, no version bump, no code edits in the rename commit, `genesis` branch only.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
|
||||
- One canonical home for every package, enforceable by a CI gate.
|
||||
- Eliminate same-name nesting (`geo/geo` etc.) and the `platform/` catch-all.
|
||||
- Preserve `git log --follow` history across the move.
|
||||
- Update every workspace-glob, turbo, vitest, tsup, biome, and script reference in lockstep so `bun install && bunx turbo build` works immediately after the commit.
|
||||
- Refresh `MANIFEST.md`, `CLAUDE.md`, `STATUS.md`, `assignment.yml` to describe the 3-level layout.
|
||||
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Renaming any `@suaveplan/<pkg>` import path. Only filesystem paths change.
|
||||
- Splitting or merging packages. Code is byte-identical post-move.
|
||||
- Touching archived OpenSpec changes' content (paths quoted inside archives stay frozen).
|
||||
- Adopting forward-looking categories for packages that do not yet exist (e.g. `video`, `store`, `logistics`, `gtap`, `vatdash` named in `PROPOSED_STRUCTURE.md`); those land when those packages land.
|
||||
- Bumping any package version.
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Three-level layout: `packages/<category>/<plugin>/<pkg>/`
|
||||
|
||||
**Chosen:** keep the existing `<plugin>/<pkg>/` pair and add `<category>/` above it.
|
||||
|
||||
|
||||
**Alternatives:**
|
||||
|
||||
- *Drop the plugin level* (`packages/<category>/<pkg>/`): cleaner tree but loses the suaveplan-skills plugin grouping that `assignment.yml` depends on, and forces a flat list of ~270 package folders inside large categories like `react/` and `games/`.
|
||||
- *Flatten same-name pairs* (hoist `geo/geo/` → `geo/`): solves nesting but creates an inconsistent depth (some packages at 2 levels, others at 3) that breaks every workspace glob.
|
||||
|
||||
Three-level is the only option that keeps glob-depth uniform AND preserves the plugin grouping.
|
||||
|
||||
### 2. `git mv` per plugin folder, one commit
|
||||
|
||||
|
||||
**Chosen:** for each of the 41 plugin folders, run `git mv packages/<plugin> packages/<category>/<plugin>` (creating the category directory first). Squash into a single rename commit.
|
||||
|
||||
**Alternatives:**
|
||||
|
||||
- *`packages_temp/` swap* (user's draft): breaks rename detection on files whose directory is recreated; reviewers see add+delete, not rename. Rejected.
|
||||
- *Script-driven from `assignment.yml`*: still uses `git mv` internally, but the script becomes a single point of failure. We do the moves by hand from a checklist for auditability; the script lives in `tasks.md` as a documented helper.
|
||||
|
||||
### 3. Path-shape CI gate
|
||||
|
||||
|
||||
**Chosen:** add a small script (`scripts/lint/check-package-paths.ts`) that walks `packages/`, asserts every `package.json` is at depth 3 (category/plugin/pkg), and asserts the category segment is in the canonical 18-name list. Wire it into `turbo lint`.
|
||||
|
||||
**Alternatives:**
|
||||
|
||||
- *Enforce only via `package.json` workspaces glob*: Bun silently ignores unmatched folders, so a stray two-level package becomes invisible rather than an error. Rejected.
|
||||
- *No gate*: relies on convention drift; the original two-level layout is itself evidence that convention without enforcement decays.
|
||||
|
||||
|
||||
### 4. Canonical 18-category list from `PROPOSED_STRUCTURE.md`
|
||||
|
||||
**Chosen:** adopt the 18 categories as the closed vocabulary. `assignment.yml` maps every current plugin to exactly one. Adding a 19th requires a new OpenSpec change that modifies the `monorepo-layout` spec.
|
||||
|
||||
**Alternatives:**
|
||||
|
||||
- *Open vocabulary*: invites the same drift that produced `platform/` and `unknown/`. Rejected.
|
||||
|
||||
### 5. Plugin-to-category assignments (binding)
|
||||
|
||||
From `PROPOSED_STRUCTURE.md`, the 41 existing plugin folders map as follows:
|
||||
|
||||
| Category | Plugin folders moving in |
|
||||
|---|---|
|
||||
| `foundation/` | `core`, `data`, `random`, `timing`, `bitpacker`, `barcode`, `flow` |
|
||||
| `persistence/` | `database`, `storage`, `cache` |
|
||||
| `network/` | `network`, `drive`, `events` |
|
||||
| `communication/` | `messaging`, `emails` |
|
||||
| `api/` | `api` |
|
||||
| `auth/` | `auth` |
|
||||
| `security/` | `security`, `crypto` |
|
||||
| `monitor/` | `monitor` |
|
||||
| `media/` | `audio`, `audio-fx`, `audio-ir`, `image`, `fonts` |
|
||||
| `react/` | `react`, `forms` |
|
||||
| `r3f/` | `r3f` |
|
||||
| `i18n/` | `i18n` |
|
||||
| `geo/` | `geo` |
|
||||
| `finance/` | `finance`, `payment` |
|
||||
| `commerce/` | `booking`, `contacts` |
|
||||
| `testing/` | `testing` |
|
||||
| `tooling/` | `tooling`, `docs`, `docker` |
|
||||
| `games/` | `games` |
|
||||
|
||||
The `platform/` plugin folder is split: its contents are inspected and each child plugin moves to the category that fits (most candidates: `foundation/`, `api/`, `communication/`, `monitor/`). The exact per-package decomposition is in `tasks.md` step 3.
|
||||
|
||||
|
||||
### 6. Workspace-glob change
|
||||
|
||||
**Chosen:** root `package.json` workspaces glob becomes `["packages/*/*/*"]` (single line). No transitional dual-glob.
|
||||
|
||||
**Alternatives:**
|
||||
|
||||
- *Dual glob* (`packages/*/*` + `packages/*/*/*`) during transition: encourages partial migrations and delays the path-shape gate. Rejected — we move everything in one commit, no transition window.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **Risk:** turbo cache misses for the whole repo on the first build after the move. **Mitigation:** acceptable one-time cost; cache rebuilds in one `bunx turbo build` run. Run it locally before pushing.
|
||||
- **Risk:** a hard-coded `packages/<plugin>/<pkg>` path is missed in a vitest config, tsup config, or doc snippet, breaking that package's gate. **Mitigation:** `tasks.md` includes a `rg -n 'packages/[a-z][a-z0-9-]+/[a-z][a-z0-9-]+'` sweep across the repo to find every literal occurrence before commit, plus a green `bunx turbo lint typecheck test` gate post-move.
|
||||
- **Risk:** archived OpenSpec changes quote old paths; rewriting them violates the archive's frozen-content rule. **Mitigation:** archives are explicitly out of scope; readers see the old paths in archived deltas and the new paths in current docs. `CLAUDE.md` notes this.
|
||||
- **Risk:** IDEs and `find` shortcuts that assume 2-level depth break for users. **Mitigation:** announce the change in the commit message; the path-shape CI gate makes the new convention discoverable.
|
||||
- **Trade-off:** small categories (`auth/`, `monitor/`, `i18n/`, `geo/`, `r3f/`, `testing/`, `games/`) each hold a single plugin folder. Accepted because uniform depth beats variable depth — every glob, every script, every readme can assume 3 levels.
|
||||
- **Trade-off:** `git mv` 41 folders is mechanical and tedious. Acceptable for a one-shot reorg; `tasks.md` lists every command verbatim.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. **Branch:** `chore/restructure-packages-by-category` off `genesis`.
|
||||
2. **Pre-flight:** clean working tree in every worktree (`git worktree list`); turbo cache cleared; `MANIFEST.md` snapshot saved for post-move diff.
|
||||
3. **Move:** run the 41 `git mv` commands from `tasks.md` step 4 in order. Create each `packages/<category>/` directory just before the first `git mv` into it.
|
||||
4. **Decompose `platform/`:** per-package, choose target category, `git mv`. Remove the empty `platform/` directory.
|
||||
5. **Update configs:** root `package.json` workspaces glob; `turbo.json`; any `tsconfig*.json` paths; `scripts/folder-reorg/generate-manifest.ts`; `scripts/folder-reorg/assignment.yml`; `scripts/publish.ts`; `scripts/lint/check-test-runner-imports.ts`; any `vitest.config.*` / `vite.config.*` / `tsup.config.*` that hard-codes `packages/`.
|
||||
6. **Add path-shape gate:** create `scripts/lint/check-package-paths.ts` and wire it into the root `lint` script.
|
||||
7. **Regenerate manifest:** `bun scripts/folder-reorg/generate-manifest.ts`. Diff against the pre-move snapshot — only path columns and the category column should change.
|
||||
8. **Update docs:** `CLAUDE.md` Layout section, `STATUS.md`, `PROPOSED_STRUCTURE.md` (mark as adopted).
|
||||
9. **Verify:** `bun install && bunx turbo lint typecheck test` green end-to-end. `git log --follow` spot-check on three packages (one from `geo/`, one from `core/`, one from the old `platform/`).
|
||||
10. **Commit:** single squash commit titled `chore(repo): restructure packages under 18 categories`.
|
||||
11. **Rollback:** if step 9 fails, `git reset --hard origin/genesis` (with explicit user approval — see CLAUDE.md git-safety rules). No partial restructure is shipped.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- **Q1: Does the `platform/` decomposition need its own follow-up OpenSpec change?** Tentative answer: no — its packages are catalogued in `tasks.md` step 3 and the per-package category assignment is mechanical given the 18-category vocabulary. Promote to a follow-up only if any platform sub-package's category is genuinely contested.
|
||||
- **Q2: Do we add a `packages/<category>/README.md` per category?** Tentative answer: no for now (CLAUDE.md rule: one README at package root only). Revisit if scanning a category's plugins becomes painful.
|
||||
- **Q3: Do we re-fold archived OpenSpec changes' quoted paths?** Tentative answer: no — archives stay frozen; that is the whole point of the archive.
|
||||
@@ -0,0 +1,33 @@
|
||||
## Why
|
||||
|
||||
`packages/` has 41 sibling top-level folders with no semantic grouping, making the repo hard to scan and forcing same-name nested folders like `packages/geo/geo`, `packages/i18n/i18n`, `packages/r3f/r3f` that confuse tooling, IDE navigation, and `git mv` rename heuristics. The `platform/` catch-all and the implicit `unknown/` bucket in `STATUS.md` further dilute the layout. Grouping current plugin folders under 18 stable category folders (per `PROPOSED_STRUCTURE.md`) gives every package one obvious home and eliminates the duplicate-name nesting.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **BREAKING (filesystem only — no public API change):** introduce a category level so the layout becomes `packages/<category>/<plugin>/<pkg>/`, where `<category>` is one of 18 fixed names: `foundation`, `persistence`, `network`, `communication`, `api`, `auth`, `security`, `monitor`, `media`, `react`, `r3f`, `i18n`, `geo`, `finance`, `commerce`, `testing`, `tooling`, `games`.
|
||||
- Move all 41 current plugin folders under their assigned category using `git mv` so history is preserved (no `packages_temp` swap — that breaks rename detection for some files).
|
||||
- Eliminate `packages/platform/` by splitting its contents into `foundation/`, `api/`, `communication/`, `monitor/` per `PROPOSED_STRUCTURE.md`.
|
||||
- Update every workspace reference to the old paths: `package.json` workspaces glob, `turbo.json`, `tsconfig.*` paths, `vitest`/`vite` configs, `scripts/folder-reorg/assignment.yml`, `MANIFEST.md`, `STATUS.md`, OpenSpec archives that quote paths, CLAUDE.md package-listing snippets, and any internal docs that hard-code `packages/<plugin>/`.
|
||||
- Regenerate `MANIFEST.md` via `bun scripts/folder-reorg/generate-manifest.ts` after the move and update `scripts/folder-reorg/generate-manifest.ts` itself if it assumes the 2-level layout.
|
||||
- Update the **CLAUDE.md** "Layout" section to document the 3-level `packages/<category>/<plugin>/<pkg>/` convention and the canonical 18-category list.
|
||||
- Verify the move in a single commit on a dedicated branch so reviewers see one atomic rename; no package code or version is touched.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `monorepo-layout`: Canonical 3-level `packages/<category>/<plugin>/<pkg>/` filesystem convention, the fixed 18-category vocabulary, the assignment rules (which plugin lives under which category), and the invariants enforced by `scripts/folder-reorg/generate-manifest.ts` and CI path-shape checks.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
<!-- None. No package-level capability spec changes behaviour; this is a pure filesystem reorganisation. Per-package specs in openspec/specs/<pkg>/ continue to describe runtime behaviour unchanged. -->
|
||||
|
||||
## Impact
|
||||
|
||||
- **Filesystem:** every package under `packages/` moves one level deeper. No file contents change.
|
||||
- **Workspaces:** Bun workspaces glob in root `package.json` widens from `packages/*/*` to `packages/*/*/*` (or equivalent). Turbo, Biome, Vitest, Playwright, tsup, Vite configs that hard-code paths must be updated.
|
||||
- **Tooling scripts:** `scripts/folder-reorg/generate-manifest.ts`, `scripts/folder-reorg/assignment.yml`, `scripts/publish.ts`, and any lint scripts that walk `packages/` need path-depth fixes.
|
||||
- **Docs:** `CLAUDE.md`, `MANIFEST.md`, `STATUS.md`, `PROPOSED_STRUCTURE.md`, and archived OpenSpec changes that quote `packages/<plugin>/<pkg>/` paths are updated for the new convention (archived specs only at quoted-path level — content stays frozen).
|
||||
- **No public surface change:** `@suaveplan/<pkg>` import paths, package versions, and exports are untouched.
|
||||
- **Git history:** preserved per file via `git mv`; one squash-friendly commit captures the entire move.
|
||||
- **CI:** turbo cache is invalidated once; subsequent builds benefit from stable cache keys under the new paths.
|
||||
@@ -0,0 +1,113 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Three-Level Package Path Convention
|
||||
|
||||
Every workspace package SHALL live at `packages/<category>/<plugin>/<pkg>/`, where `<category>` is one of the 18 canonical category names defined in this spec, `<plugin>` is the suaveplan-skills plugin slug, and `<pkg>` is the package directory whose `package.json` declares `@suaveplan/<pkg>`. No package SHALL exist directly under `packages/<plugin>/<pkg>/` (the legacy two-level layout) or at `packages/<pkg>/`.
|
||||
|
||||
#### Scenario: Valid package path
|
||||
|
||||
|
||||
- **WHEN** a developer creates `packages/foundation/core/error/` containing a `package.json` with `"name": "@suaveplan/error"`
|
||||
- **THEN** the path-shape CI gate accepts it because the depth is exactly 3 segments under `packages/` and `foundation` is a canonical category
|
||||
|
||||
|
||||
#### Scenario: Legacy two-level path rejected
|
||||
|
||||
- **WHEN** a `package.json` is found at `packages/core/error/package.json` (no category level)
|
||||
- **THEN** the path-shape CI gate fails with an error naming the missing category segment and the package
|
||||
|
||||
|
||||
#### Scenario: Unknown category rejected
|
||||
|
||||
- **WHEN** a `package.json` is found at `packages/misc/core/error/package.json`
|
||||
- **THEN** the path-shape CI gate fails because `misc` is not in the canonical 18-category list
|
||||
|
||||
### Requirement: Canonical Category Vocabulary
|
||||
|
||||
|
||||
The set of allowed `<category>` segment names SHALL be exactly: `foundation`, `persistence`, `network`, `communication`, `api`, `auth`, `security`, `monitor`, `media`, `react`, `r3f`, `i18n`, `geo`, `finance`, `commerce`, `testing`, `tooling`, `games`. Adding, removing, or renaming a category SHALL require a new OpenSpec change that modifies this requirement.
|
||||
|
||||
#### Scenario: Lint script enumerates categories
|
||||
|
||||
|
||||
- **WHEN** `scripts/folder-reorg/generate-manifest.ts` runs
|
||||
- **THEN** it reads the 18 category names from a single source-of-truth constant whose values match this requirement exactly
|
||||
|
||||
#### Scenario: New top-level folder under packages/ is rejected
|
||||
|
||||
- **WHEN** a developer adds `packages/experiments/foo/bar/` without an OpenSpec change updating this requirement
|
||||
- **THEN** the path-shape CI gate fails because `experiments` is not in the canonical list
|
||||
|
||||
|
||||
### Requirement: Plugin-to-Category Assignment Is Stable
|
||||
|
||||
Each plugin folder SHALL belong to exactly one category. The assignment SHALL be recorded in `scripts/folder-reorg/assignment.yml` and reflected in `MANIFEST.md`. Moving a plugin between categories SHALL require a new OpenSpec change documenting the rationale and the migration steps.
|
||||
|
||||
|
||||
#### Scenario: Plugin appears in exactly one category
|
||||
|
||||
- **WHEN** the manifest generator walks `packages/`
|
||||
- **THEN** it finds the `geo` plugin folder at exactly one path (`packages/geo/geo/`) and no other category contains a folder named `geo`
|
||||
|
||||
#### Scenario: Manifest matches filesystem
|
||||
|
||||
- **WHEN** `bun scripts/folder-reorg/generate-manifest.ts --check` runs in CI
|
||||
|
||||
- **THEN** it exits zero only if every plugin folder on disk matches its `assignment.yml` category entry
|
||||
|
||||
### Requirement: Workspace Glob Matches Three-Level Layout
|
||||
|
||||
|
||||
The root `package.json` `workspaces` field SHALL include a glob that matches `packages/*/*/*` (three segments) and SHALL NOT include `packages/*/*` (the legacy two-level glob) unless that glob is required for a documented transitional package.
|
||||
|
||||
#### Scenario: Bun resolves all packages
|
||||
|
||||
- **WHEN** `bun install` runs at the repo root after restructure
|
||||
- **THEN** every `@suaveplan/<pkg>` workspace dependency resolves without `workspace package not found` errors
|
||||
|
||||
#### Scenario: Turbo discovers all packages
|
||||
|
||||
|
||||
- **WHEN** `bunx turbo ls` runs at the repo root
|
||||
- **THEN** the package count matches the count of `package.json` files found by `find packages -mindepth 3 -maxdepth 3 -name package.json`
|
||||
|
||||
|
||||
### Requirement: Move Preserves Git History
|
||||
|
||||
The filesystem reorganisation SHALL use `git mv` (one invocation per plugin folder) so that Git's rename detection links the old and new paths. The reorganisation commit SHALL NOT touch package source code, versions, or exports — it is a pure rename commit.
|
||||
|
||||
#### Scenario: git log --follow traces a moved file
|
||||
|
||||
- **WHEN** `git log --follow packages/foundation/core/error/src/error.ts` runs after the restructure commit
|
||||
- **THEN** the log includes commits made before the restructure that touched `packages/core/error/src/error.ts`
|
||||
|
||||
|
||||
#### Scenario: Restructure commit changes no file contents
|
||||
|
||||
- **WHEN** `git show --stat <restructure-commit>` is inspected
|
||||
- **THEN** every line is a rename (R100 in `git show --raw -M`) and no line shows insertions or deletions outside path changes
|
||||
|
||||
### Requirement: No `packages_temp` Swap
|
||||
|
||||
|
||||
The restructure SHALL NOT use a temporary sibling directory (e.g. `packages_temp/`) that is later renamed to `packages/`. Such a swap defeats Git rename detection for files whose containing directory is created and destroyed during the operation.
|
||||
|
||||
#### Scenario: No transient packages_temp directory in history
|
||||
|
||||
|
||||
- **WHEN** `git log --all --diff-filter=A --name-only` is inspected for the restructure branch
|
||||
- **THEN** no commit adds a `packages_temp/` path
|
||||
|
||||
### Requirement: Documentation Reflects New Layout
|
||||
|
||||
`CLAUDE.md`, `MANIFEST.md`, `STATUS.md`, and `scripts/folder-reorg/assignment.yml` SHALL describe the three-level `packages/<category>/<plugin>/<pkg>/` convention and enumerate the 18 canonical categories. Archived OpenSpec change folders SHALL retain their original content; only the live root-level docs are rewritten.
|
||||
|
||||
#### Scenario: CLAUDE.md layout section updated
|
||||
|
||||
- **WHEN** a reader opens `CLAUDE.md` after the restructure
|
||||
- **THEN** the "Layout" subsection of "Packages" describes the `packages/<category>/<plugin>/<pkg>/` convention and lists all 18 categories
|
||||
|
||||
#### Scenario: MANIFEST.md regenerated
|
||||
|
||||
- **WHEN** `bun scripts/folder-reorg/generate-manifest.ts` runs after the restructure
|
||||
- **THEN** every package entry in `MANIFEST.md` shows the three-level path and the category column is populated from `assignment.yml`
|
||||
102
openspec/changes/restructure-packages-by-category/tasks.md
Normal file
102
openspec/changes/restructure-packages-by-category/tasks.md
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
|
||||
## 0. Pre-flight (non-negotiable)
|
||||
|
||||
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
|
||||
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
|
||||
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
|
||||
|
||||
## 1. Pre-flight
|
||||
|
||||
- [ ] 1.1 Create branch `chore/restructure-packages-by-category` off `genesis`.
|
||||
- [ ] 1.2 Run `git worktree list` and confirm every worktree is clean (`git status` in each). Abort and reconcile if anything is dirty.
|
||||
- [ ] 1.3 Snapshot current `MANIFEST.md` as `MANIFEST.before.md` (not committed; used for post-move diff).
|
||||
- [ ] 1.4 Snapshot current `bunx turbo ls --json` output for the same purpose.
|
||||
- [ ] 1.5 Audit `packages/platform/` and decide a target category for every sub-package (record decisions inline in this tasks file under §3).
|
||||
|
||||
## 2. Authoritative assignment file
|
||||
|
||||
- [ ] 2.1 Update `scripts/folder-reorg/assignment.yml` so each plugin entry includes a `category:` field with one of the 18 canonical names: `foundation`, `persistence`, `network`, `communication`, `api`, `auth`, `security`, `monitor`, `media`, `react`, `r3f`, `i18n`, `geo`, `finance`, `commerce`, `testing`, `tooling`, `games`.
|
||||
- [ ] 2.2 Commit the YAML update on the restructure branch *before* doing any `git mv`, so the rename commit and the assignment metadata stay in lockstep on review.
|
||||
|
||||
## 3. Decompose `packages/platform/`
|
||||
|
||||
- [ ] 3.1 List every sub-package under `packages/platform/` (`ls packages/platform`).
|
||||
- [ ] 3.2 For each, record `<pkg> → <category>` in this checklist (e.g. `webhook-client → communication`). Use only the 18 canonical categories.
|
||||
- [ ] 3.3 Confirm no platform sub-package needs to be split across multiple categories. If one does, raise it as an open question on the OpenSpec proposal before proceeding.
|
||||
|
||||
## 4. Move plugin folders with `git mv` (one commit, one folder at a time)
|
||||
|
||||
Run commands from the repo root. Create the category directory just before the first `git mv` into it.
|
||||
|
||||
- [ ] 4.1 `foundation/`: `mkdir -p packages/foundation && git mv packages/core packages/foundation/core && git mv packages/data packages/foundation/data && git mv packages/random packages/foundation/random && git mv packages/timing packages/foundation/timing && git mv packages/bitpacker packages/foundation/bitpacker && git mv packages/barcode packages/foundation/barcode && git mv packages/flow packages/foundation/flow`.
|
||||
- [ ] 4.2 `persistence/`: `mkdir -p packages/persistence && git mv packages/database packages/persistence/database && git mv packages/storage packages/persistence/storage && git mv packages/cache packages/persistence/cache`.
|
||||
- [ ] 4.3 `network/`: `mkdir -p packages/network-cat && git mv packages/network packages/network-cat/network && git mv packages/drive packages/network-cat/drive && git mv packages/events packages/network-cat/events && mv packages/network-cat packages/network` (use the temp-name swap *only* at the category level to avoid colliding with the existing `packages/network/` plugin folder; the `git mv` of the inner `network` plugin is what Git tracks, the final `mv` of the empty category folder is content-free).
|
||||
- [ ] 4.4 `communication/`: `mkdir -p packages/communication && git mv packages/messaging packages/communication/messaging && git mv packages/emails packages/communication/emails`.
|
||||
- [ ] 4.5 `api/`: `mkdir -p packages/api-cat && git mv packages/api packages/api-cat/api && mv packages/api-cat packages/api` (same category/plugin name collision dance as `network`).
|
||||
- [ ] 4.6 `auth/`: `mkdir -p packages/auth-cat && git mv packages/auth packages/auth-cat/auth && mv packages/auth-cat packages/auth`.
|
||||
- [ ] 4.7 `security/`: `mkdir -p packages/security-cat && git mv packages/security packages/security-cat/security && git mv packages/crypto packages/security-cat/crypto && mv packages/security-cat packages/security`.
|
||||
- [ ] 4.8 `monitor/`: `mkdir -p packages/monitor-cat && git mv packages/monitor packages/monitor-cat/monitor && mv packages/monitor-cat packages/monitor`.
|
||||
- [ ] 4.9 `media/`: `mkdir -p packages/media && git mv packages/audio packages/media/audio && git mv packages/audio-fx packages/media/audio-fx && git mv packages/audio-ir packages/media/audio-ir && git mv packages/image packages/media/image && git mv packages/fonts packages/media/fonts`.
|
||||
- [ ] 4.10 `react/`: `mkdir -p packages/react-cat && git mv packages/react packages/react-cat/react && git mv packages/forms packages/react-cat/forms && mv packages/react-cat packages/react`.
|
||||
- [ ] 4.11 `r3f/`: `mkdir -p packages/r3f-cat && git mv packages/r3f packages/r3f-cat/r3f && mv packages/r3f-cat packages/r3f`.
|
||||
- [ ] 4.12 `i18n/`: `mkdir -p packages/i18n-cat && git mv packages/i18n packages/i18n-cat/i18n && mv packages/i18n-cat packages/i18n`.
|
||||
- [ ] 4.13 `geo/`: `mkdir -p packages/geo-cat && git mv packages/geo packages/geo-cat/geo && mv packages/geo-cat packages/geo`.
|
||||
- [ ] 4.14 `finance/`: `mkdir -p packages/finance-cat && git mv packages/finance packages/finance-cat/finance && git mv packages/payment packages/finance-cat/payment && mv packages/finance-cat packages/finance`.
|
||||
- [ ] 4.15 `commerce/`: `mkdir -p packages/commerce && git mv packages/booking packages/commerce/booking && git mv packages/contacts packages/commerce/contacts`.
|
||||
- [ ] 4.16 `testing/`: `mkdir -p packages/testing-cat && git mv packages/testing packages/testing-cat/testing && mv packages/testing-cat packages/testing`.
|
||||
- [ ] 4.17 `tooling/`: `mkdir -p packages/tooling-cat && git mv packages/tooling packages/tooling-cat/tooling && git mv packages/docs packages/tooling-cat/docs && git mv packages/docker packages/tooling-cat/docker && mv packages/tooling-cat packages/tooling`.
|
||||
- [ ] 4.18 `games/`: `mkdir -p packages/games-cat && git mv packages/games packages/games-cat/games && mv packages/games-cat packages/games`.
|
||||
- [ ] 4.19 Decompose `packages/platform/` per §3 decisions: one `git mv packages/platform/<pkg> packages/<category>/<plugin>/<pkg>` per sub-package (or to its parent plugin folder if it belongs there). Remove the now-empty `packages/platform/` directory with `rmdir packages/platform`.
|
||||
- [ ] 4.20 Verify: `find packages -mindepth 1 -maxdepth 1 -type d | sort` returns exactly the 18 canonical category names and nothing else.
|
||||
- [ ] 4.21 Verify: `find packages -mindepth 3 -maxdepth 3 -name package.json | wc -l` equals the count of `@suaveplan/*` packages from the pre-flight snapshot.
|
||||
|
||||
## 5. Update workspace and tooling configuration
|
||||
|
||||
- [ ] 5.1 Root `package.json`: change `workspaces` from `["packages/*/*"]` (or whatever the current glob is) to `["packages/*/*/*"]`. Verify no other glob is needed.
|
||||
- [ ] 5.2 Root `turbo.json`: scan for any hard-coded `packages/<plugin>/...` paths and update to three-level.
|
||||
- [ ] 5.3 Root `tsconfig*.json`: update any `paths` mappings that reference `packages/<plugin>/<pkg>` to `packages/<category>/<plugin>/<pkg>`.
|
||||
- [ ] 5.4 `scripts/folder-reorg/generate-manifest.ts`: update path-walking logic to assume three levels under `packages/`; load category list from the YAML constant.
|
||||
- [ ] 5.5 `scripts/publish.ts`: update any path-resolution code that walks `packages/`.
|
||||
- [ ] 5.6 `scripts/lint/check-test-runner-imports.ts`: update its `packages/<plugin>/<pkg>` glob to three levels.
|
||||
- [ ] 5.7 Per-package configs: `rg -n "packages/[a-z][a-z0-9-]+/[a-z][a-z0-9-]+(/|['\")\\\\])" --type-add 'cfg:*.{json,ts,js,mjs,cjs,yml,yaml,toml}' -tcfg` and audit every hit. Update each to the three-level form (or to a category-agnostic resolution if better).
|
||||
- [ ] 5.8 `biome.json` (and any per-package `biome.json`): update path globs.
|
||||
- [ ] 5.9 `playwright.config.*` (root and per-package): update path globs.
|
||||
|
||||
## 6. Add path-shape CI gate
|
||||
|
||||
- [ ] 6.1 Create `scripts/lint/check-package-paths.ts` that walks `packages/`, asserts every `package.json` is at depth 3 segments under `packages/`, and asserts the category segment is in the canonical 18-name list (loaded from `scripts/folder-reorg/assignment.yml`).
|
||||
- [ ] 6.2 Add it to the root `lint` script and to `turbo.json` `lint` task pipeline.
|
||||
- [ ] 6.3 Run it locally; confirm it exits zero.
|
||||
|
||||
## 7. Regenerate manifest
|
||||
|
||||
- [ ] 7.1 Run `bun scripts/folder-reorg/generate-manifest.ts`.
|
||||
- [ ] 7.2 Diff the new `MANIFEST.md` against `MANIFEST.before.md`: only path strings and the new category column should differ. No package additions, removals, or version changes.
|
||||
- [ ] 7.3 Stage `MANIFEST.md`.
|
||||
|
||||
## 8. Documentation updates
|
||||
|
||||
- [ ] 8.1 `CLAUDE.md` "Layout (`packages/<plugin>/<pkg>/`)" section: rewrite the heading to `Layout (packages/<category>/<plugin>/<pkg>/)`, document the 18-category vocabulary, and reference `scripts/folder-reorg/assignment.yml` as the source of truth.
|
||||
- [ ] 8.2 `STATUS.md`: replace the implicit `unknown/` bucket with category headers; reflect the new paths.
|
||||
- [ ] 8.3 `PROPOSED_STRUCTURE.md`: add a one-line note at the top — `Status: adopted via openspec/changes/restructure-packages-by-category` — and leave the rationale intact for historical context.
|
||||
- [ ] 8.4 Spot-check root-level `README.md` for `packages/<plugin>` references; update.
|
||||
- [ ] 8.5 Do NOT modify any file under `openspec/archive/` even if it quotes old paths.
|
||||
|
||||
## 9. Verification gate
|
||||
|
||||
- [ ] 9.1 `bun install` at repo root succeeds with no `workspace package not found` errors.
|
||||
- [ ] 9.2 `bunx turbo ls` lists the same package count as the pre-flight snapshot.
|
||||
- [ ] 9.3 `bunx turbo lint typecheck` green across the whole monorepo.
|
||||
- [ ] 9.4 `bunx turbo test` green across the whole monorepo (allow expected DB-integration skips per CLAUDE.md).
|
||||
- [ ] 9.5 `bun scripts/lint/check-package-paths.ts` exits zero.
|
||||
- [ ] 9.6 `git log --follow packages/foundation/core/error/src/error.ts` (or another sample file) shows pre-restructure history.
|
||||
- [ ] 9.7 `git show --stat HEAD` of the restructure commit shows only renames, zero content edits.
|
||||
|
||||
## 10. Commit and ship
|
||||
|
||||
- [ ] 10.1 Squash all step-4/5/6/7/8 work into one commit:
|
||||
`chore(repo): restructure packages under 18 categories`
|
||||
- [ ] 10.2 Push branch; confirm CI green.
|
||||
- [ ] 10.3 Open PR to `genesis` with the proposal, design, and tasks linked from the description.
|
||||
- [ ] 10.4 After merge, fold the spec delta into `openspec/specs/monorepo-layout/spec.md` and archive `openspec/changes/restructure-packages-by-category/` to `openspec/archive/<yyyy-mm-dd>-restructure-packages-by-category/`.
|
||||
Reference in New Issue
Block a user