chore: archive final 4 completed OpenSpec changes

Move the following completed changes from openspec/changes/ to
openspec/changes/archive/2026-06-12-completed-changes-archive/:
- multi-session-terminal-ux
- reorganize-long-files
- working-copies
- workspace-first-ui

Update parent and archive .pi-map*.md indexes to reflect the move and
remove the transient active-changes-archive grouping.

openspec/changes/ now contains only the archive/ directory.
This commit is contained in:
Developer
2026-06-12 21:11:11 +00:00
parent 43f3865f69
commit 8c1948d226
41 changed files with 176 additions and 145 deletions
@@ -0,0 +1,4 @@
name: reorganize-long-files
status: completed
started_at: 2026-05-28
completed_at: 2026-06-12
@@ -0,0 +1,22 @@
# archive/2026-06-12-active-changes-archive/reorganize-long-files (index)
dir: archive/2026-06-12-active-changes-archive/reorganize-long-files
## role
Contains archived planning documents for a completed structural refactoring initiative that split monolithic frontend pages and backend routers into thinner, more modular components and services.
## parent
index: archive/2026-06-12-active-changes-archive/.pi-map.index.md
map: archive/2026-06-12-active-changes-archive/.pi-map.md
## children
-
## files
- .openspec.yaml
- proposal.md
- spec.md
- tasks.md
## links
index: archive/2026-06-12-active-changes-archive/reorganize-long-files/.pi-map.index.md
map: archive/2026-06-12-active-changes-archive/reorganize-long-files/.pi-map.md
## workflows
-
## dirty
-
@@ -0,0 +1,22 @@
# archive/2026-06-12-active-changes-archive/reorganize-long-files
dir: archive/2026-06-12-active-changes-archive/reorganize-long-files
index: archive/2026-06-12-active-changes-archive/reorganize-long-files/.pi-map.index.md
## role
Contains archived planning documents for a completed structural refactoring initiative that split monolithic frontend pages and backend routers into thinner, more modular components and services.
## files
- .openspec.yaml | Configuration file tracking a completed project task for reorganizing long files
- proposal.md | Proposes a structural refactoring to split monolithic frontend pages and backend routers into thinner orchestrators with extracted components/services, restoring a thin-page/thin-router/fat-component pattern. | dep: React components, FastAPI routers, WebSocket, Docker, git services
- spec.md | A specification document defining a pure structural refactoring to split monolithic frontend pages/backend routers and CSS into smaller, focused components and services without changing any behavior or API contracts. | dep: React, CSS Modules, WebSocket, FastAPI/Flask routers, TypeScript, Vite
- tasks.md | Tracks the completion status of a codebase reorganization initiative to slim long files by extracting components and services into dedicated modules.
## arch
Documentation-driven refactoring using specification-proposal-task workflow with a thin-page/thin-router/fat-component pattern, emphasizing pure structural decomposition without behavioral changes.
## tags
components, services, long, .openspec, structural, refactoring, split, monolithic
## symbols
-
## workflows
-
## dirty
-
@@ -0,0 +1,73 @@
## Why
After the backend-frontend refactoring (commits `0591b00` through `8c7affc`), the codebase gained proper directory structure but several files grew into monoliths. The `main` branch (pre-refactor baseline at `5ed5e1c`) kept pages thin by delegating to extracted components. On `dev`, new features were added inline, causing pages and routers to absorb responsibilities that belong in components or services.
### Problem Files (Frontend)
| File | Lines | Problem |
|------|-------|---------|
| `pages/ToolWorkshopPage.tsx` | **1,269** | Merged 3 tab components inline (ToolTypes, ToolConfigs, ConfigFolders) |
| `pages/ConfigProfilesPage.tsx` | **1,611** | List, detail, edit, create, and mobile views all in one file |
| `pages/TerminalPage.tsx` | **571** | Session tabs, keyboard shortcuts, fullscreen, mobile overlay, special keys all inline |
| `pages/RepoWorkspacePage.tsx` | **505** | File editor, git toolbar, workspace header, sidebar logic inline |
| `pages/SettingsPage.tsx` | **284** | Settings nav + multiple setting sections inline |
| `pages/SshKeysPage.tsx` | **277** | List and create inline |
### Problem Files (Backend)
| File | Lines | Problem |
|------|-------|---------|
| `api/tool/tool_instances.py` | **2,900** | CRUD, Docker lifecycle, WebSocket proxy, terminal sessions, instance proxy all in one router |
| `api/project/git_repositories.py` | **1,588** | HTTP endpoints mixed with git command orchestration |
| `api/config/config_profiles.py` | **842** | CRUD + validation + resolver + mount/include management |
### What `main` Did Differently
`main` at `5ed5e1c`:
- `ToolWorkshopPage.tsx` = **77 lines** (just a tab switcher, tabs imported from `features/tool-workshop/`)
- `TerminalPage.tsx` = **38 lines** (just a wrapper around `TerminalComponent`)
- `api/tool_instances.py` = **284 lines** (HTTP endpoints only)
- `api/terminal.py` = **158 lines** (separate WebSocket router)
## What Changes
Restore the **thin-page / thin-router / fat-component** pattern from `main`, adapted to current `dev` features:
1. **Frontend page extraction** — Split monolithic pages into:
- Page shell (orchestrator, 50-150 lines)
- Tab components (for tabbed pages)
- List / Detail / Edit / Create components (for CRUD pages)
- Mobile-specific views (extracted, not inline)
2. **Backend router slimming** — Split `tool_instances.py` into:
- `tool_instances.py` — CRUD endpoints only
- `tool_lifecycle.py` — Start/stop/restart/delete logic
- Move terminal WebSocket back to dedicated `terminal.py`
3. **Git repository router** — Extract git command orchestration into `services/git/`
## Capabilities
### New Capabilities
- None (pure structural refactor)
### Modified Capabilities
- `frontend-structure`: Pages become orchestrators; components carry the UI logic
- `backend-structure`: Routers become HTTP-only; services carry business logic
## Impact
- **Frontend**: New `features/tool-workshop/` tab components, new `features/config-profiles/` components, `features/terminal/` session manager, etc.
- **Backend**: New `api/tool/tool_lifecycle.py`, `api/tool/terminal.py`, slimmer `api/tool/tool_instances.py`
- **Tests**: Test files may need import path updates (component moved → test follows)
## Exclusions (Already Done / Out of Scope)
- Directory structure already exists (`features/`, `services/`, etc.)
- Schema extraction already done (`schemas/` subpackages)
- Model subpackages already done (`models/` subpackages)
- API router subpackages already done (`api/tool/`, `api/project/`, etc.)
- File naming already done (kebab-case APIs, PascalCase pages)
- No behavioral changes to any endpoint or UI flow
- No database schema changes
- No new features
@@ -0,0 +1,128 @@
## Scope
This change is a **pure structural refactoring** to split monolithic pages and routers into focused components and services. No API contracts, database schemas, or user-facing behaviors change.
### In Scope
#### 1. Frontend Page Extraction
Split the following pages into a thin page shell + extracted components:
**`pages/ToolWorkshopPage.tsx` (1,269 → ~80 lines)**
- Extract `ToolTypesTab``components/features/tool-workshop/ToolTypesTab.tsx`
- Extract `ToolConfigsTab``components/features/tool-workshop/ToolConfigsTab.tsx`
- Extract `ConfigFoldersTab``components/features/tool-workshop/ConfigFoldersTab.tsx`
- Page becomes: tab switcher only, imports the 3 tabs
**`pages/ConfigProfilesPage.tsx` (1,611 → ~80 lines)**
- Extract `ConfigProfileListView` → list view + mobile list view
- Extract `ConfigProfileDetailView` → detail view with edit toggle
- Extract `ConfigProfileEditForm` → edit/create form
- Extract `ConfigProfileMobileView` → mobile view state machine wrapper
- Page becomes: router between list/detail/edit views
**`pages/TerminalPage.tsx` (571 → ~80 lines)**
- Extract `TerminalSessionManager` → session tabs + auto-create logic
- Extract `TerminalKeyboardShortcuts` → shortcut handler hook (already exists, just use it)
- Extract `MobileTerminalOverlay` → mobile overlay toolbar + tabs
- Page becomes: choose between desktop (`TerminalComponent` + `TerminalSessionTabs`) and mobile (`MobileTerminalOverlay` + `TerminalComponent`) wrappers
**`pages/SettingsPage.tsx` (284 → ~80 lines)**
- Extract `SettingsNavigation` → settings nav sidebar
- Extract `GeneralSettingsTab`, `SSHKeysTab` (already separate pages, but move sections into components if inline)
- Page becomes: nav + `<Outlet>` for nested routes
**`pages/SshKeysPage.tsx` (277 → ~80 lines)**
- Extract `SSHKeyList` → list with actions
- Extract `SSHKeyCreateForm` → create form
- Page becomes: layout wrapper + conditionally render list or form
**`pages/RepoWorkspacePage.tsx` (505 → ~150 lines)**
- Extract `WorkspaceLayout` → sidebar + main content layout
- Page becomes: data loader + layout wrapper
**`pages/ProjectsPage.tsx` (433 → ~100 lines)**
- Extract `ProjectList` → list with cards
- Extract `ProjectCreateDialog` → create form in dialog
- Extract `ProjectEditDialog` → edit form in dialog
- Page becomes: data loader + layout + dialog state manager
#### 2. CSS Reorganization
**`styles.css` (5,683 lines → deleted)**
- Restore `styles/` directory with extracted files:
- `styles/tokens.css` — CSS custom properties (colors, spacing, typography)
- `styles/global.css` — global reset, body, shell layout
- `styles/utilities.css` — utility classes (.stack, .card, .muted, etc.)
- `styles/syntax-highlight.css` — code highlighting
- Restore `styles/pages/*.css` — page-specific styles:
- `styles/pages/dashboard.css`
- `styles/pages/projects.css`
- `styles/pages/sessions.css`
- `styles/pages/settings.css`
- `styles/pages/ssh-keys.css`
- `styles/pages/git-history.css`
- `styles/pages/repo-workspace.css`
- Restore component CSS modules:
- `components/features/terminal/TerminalComponent.module.css`
- `components/features/git/GitToolbar.module.css`
- `components/features/git/CommitDialog.module.css`
- `components/features/git/MergeDialog.module.css`
- `components/features/git/FileEditor.module.css`
- `components/features/git/FileBrowser.module.css`
- `components/features/git/FileViewer.module.css`
- `components/features/git/CommitPanel.module.css`
- `components/features/session/InstanceList.module.css`
- `components/features/settings/SettingsTabLayout.module.css`
- `components/layout/AppShell.module.css`
- Update all component imports to use `import styles from './ComponentName.module.css'`
- Update `main.tsx` to import `styles/tokens.css`, `styles/global.css`, `styles/utilities.css`, `styles/syntax-highlight.css`
- Update each page to import its `styles/pages/*.css`
- Delete monolithic `styles.css`
#### 3. Backend Router Slimming
**`api/tool/tool_instances.py` (2,900 → ~300 lines)**
- Extract terminal WebSocket handlers → `api/tool/terminal.py` (~400 lines)
- Extract instance lifecycle (create/start/stop/delete/restart) → `api/tool/tool_lifecycle.py` (~600 lines)
- Keep in `tool_instances.py`: CRUD endpoints (GET list, GET detail, POST, PATCH, DELETE) + instance proxy endpoint
**`api/project/git_repositories.py` (1,588 → ~300 lines)**
- Extract git command orchestration into `services/git/operations.py`
- Router keeps: auth, parameter validation, response building, error handling
- Service functions: `clone_repo`, `fetch_repo`, `pull_repo`, `push_repo`, `merge_repo`, etc.
**`api/config/config_profiles.py` (842 → ~200 lines)**
- Extract resolver orchestration into `services/config/resolver_service.py`
- Extract CRUD helpers into `services/config/crud_service.py`
- Router keeps: endpoint definitions, auth, input validation
### Out of Scope
- Any new features or behavioral changes
- Database schema changes (no migrations)
- API contract changes (same endpoints, same request/response shapes)
- Frontend UI behavior changes (same components, same interactions)
- Moving existing `features/` components (already organized)
- Renaming files (naming already done)
- Changing any CSS rules (only moving them)
## Acceptance Criteria
1. All pages ≤ 150 lines (except `RepoWorkspacePage` which may stay at ~150)
2. All API routers ≤ 400 lines
3. No monolithic `styles.css` — all CSS in `styles/` directory or `.module.css` files
4. All existing tests pass without modification (behavior unchanged)
5. All existing API endpoints return identical responses
6. Frontend `npm run typecheck` passes
7. Frontend `npm run build` passes
8. Backend `py_compile` passes on all files
9. No import errors in browser console
10. File count increases (more files, smaller files)
## Preconditions
- `dev` branch is stable (all fixes from this session are committed)
- Backend compiles (`py_compile` pass)
- Frontend typechecks and builds (`tsc`, `vite build` pass)
- Current tests pass (or known failures are documented)
@@ -0,0 +1,87 @@
# Tasks: Reorganize Long Files
## Status
| Field | Value |
|---|---|
| Phase | **Tasks** |
| Based on | [Spec](spec.md) |
| Next | Apply → Verify → Sync |
## Summary of Work
This change was partially implemented incrementally across other features (`workspace-first-ui`, `tool-session-progress-and-updates`, etc.). This final pass completes the remaining high-value extractions and updates the spec to reflect the current codebase.
### Backend — Router Slimming
| # | Task | Status |
|---|---|---|
| 1.1 | Terminal WebSocket extraction from `api/tool/tool_instances.py` | Already extracted to `api/system/terminal.py` in prior work |
| 1.2 | Instance lifecycle extraction into `api/tool/tool_lifecycle.py` | **Completed** |
| 1.3 | Git operations service extraction | Already exists as `services/git/operations.py` |
| 1.4 | Config profile service extraction | Already exists as `services/config/crud_service.py` and `services/config/resolver_service.py` |
### Frontend — Page/Component Slimming
| # | Task | Status |
|---|---|---|
| 3.13.6 | Tool Workshop page tabs | `pages/ToolWorkshopPage.tsx` is already ~60 lines; tabs extracted in prior work |
| 4.14.7 | Config Profiles views | `pages/ConfigProfilesPage.tsx` is ~177 lines; list/detail/edit views already extracted as `ConfigProfileListSidebar`, `ConfigProfileEditorPanel`, `ConfigProfilesMobileView` |
| 5.15.6 | Terminal page manager | `pages/TerminalPage.tsx` is ~100 lines; terminal UI already in `components/features/terminal/` |
| 6.16.6 | Settings / SSH Keys navigation | `SSHKeyList` already extracted; settings nav simple enough |
| 7.17.4 | Projects page list | `ProjectCard` already extracted; page is ~294 lines |
| 7.57.6 | Repo Workspace page | Page and layout were removed in `workspace-first-ui`; N/A |
| — | Workspace detail page extraction | **Completed**: extracted `workspace-detail-header`, `workspace-tab-bar`, `workspace-file-panel`, `workspace-git-panel`, `workspace-tools-panel`, `workspace-settings-panel`; `pages/WorkspaceDetailPage.tsx` slimmed from ~446 to ~62 lines |
### CSS Reorganization
| # | Task | Status |
|---|---|---|
| 2.1 | `styles/` directory with tokens/global/utilities/syntax-highlight | Already done |
| 2.2 | Page-specific CSS files | Already done; `styles.css` monolith does not exist |
| 2.3 | CSS Modules for every component | Deferred — global CSS files are already split by page/feature; converting every component to CSS Modules is a large, risky visual refactor beyond the current scope |
| 2.4 | Delete `styles.css` | Already done |
## Completed This Pass
- [x] Extract start/stop/restart/delete lifecycle endpoints from `api/tool/tool_instances.py` into `api/tool/tool_lifecycle.py`
- [x] Register `tool_lifecycle_router` in `main.py`
- [x] Extract `WorkspaceDetailPage` inline components into `components/features/workspace/`
- `workspace-detail-header.tsx`
- `workspace-tab-bar.tsx` (shared `WorkspaceTab` type)
- `workspace-file-panel.tsx`
- `workspace-git-panel.tsx`
- `workspace-tools-panel.tsx`
- `workspace-settings-panel.tsx`
- [x] Slim `pages/WorkspaceDetailPage.tsx` to ~62 lines
- [x] Verify backend `py_compile` passes
- [x] Verify frontend `npm run typecheck` passes
- [x] Verify frontend `npm run lint` passes
- [x] Verify frontend tests pass
## Acceptance Criteria
- [x] No `styles.css` monolith exists
- [x] Backend routers are ≤ 400 lines (`tool_instances.py` reduced to ~419 lines)
- [x] `WorkspaceDetailPage` is ≤ 150 lines (~62 lines)
- [x] Lifecycle endpoints moved to dedicated router
- [x] All typecheck, lint, and test gates pass
- [ ] Full CSS Modules conversion — deferred
- [ ] Every frontend page ≤ 150 lines — partially met; remaining pages are within reasonable bounds and use extracted components
## Verification Steps
```bash
cd apps/api
python3 -m py_compile src/api/tool/tool_instances.py src/api/tool/tool_lifecycle.py src/main.py src/api/tool/__init__.py
cd apps/web
npm run typecheck
npm run lint
npm test -- --run
```
## Notes
- Several originally planned extractions were already completed in earlier feature branches or became obsolete when `RepoWorkspacePage` and its related components were removed during `workspace-first-ui`.
- The remaining meaningful structural win was extracting the monolithic `WorkspaceDetailPage` and the backend lifecycle endpoints.