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:
+4
@@ -0,0 +1,4 @@
|
||||
name: reorganize-long-files
|
||||
status: completed
|
||||
started_at: 2026-05-28
|
||||
completed_at: 2026-06-12
|
||||
+22
@@ -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
|
||||
-
|
||||
+22
@@ -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
|
||||
-
|
||||
+73
@@ -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
|
||||
+128
@@ -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)
|
||||
+87
@@ -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.1–3.6 | Tool Workshop page tabs | `pages/ToolWorkshopPage.tsx` is already ~60 lines; tabs extracted in prior work |
|
||||
| 4.1–4.7 | Config Profiles views | `pages/ConfigProfilesPage.tsx` is ~177 lines; list/detail/edit views already extracted as `ConfigProfileListSidebar`, `ConfigProfileEditorPanel`, `ConfigProfilesMobileView` |
|
||||
| 5.1–5.6 | Terminal page manager | `pages/TerminalPage.tsx` is ~100 lines; terminal UI already in `components/features/terminal/` |
|
||||
| 6.1–6.6 | Settings / SSH Keys navigation | `SSHKeyList` already extracted; settings nav simple enough |
|
||||
| 7.1–7.4 | Projects page list | `ProjectCard` already extracted; page is ~294 lines |
|
||||
| 7.5–7.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.
|
||||
Reference in New Issue
Block a user