docs: add refactor App.tsx PRD (#104)

This commit is contained in:
ben
2026-01-19 01:54:33 -08:00
committed by GitHub
parent 0692a9f7d8
commit afdea998b0

198
pr/refactor.md Normal file
View File

@@ -0,0 +1,198 @@
# PRD - Refactor App.tsx (50 percent size reduction)
## Summary
Create a low-risk refactor plan that cuts `src/App.tsx` from ~2000 lines to ~1000 lines by extracting cohesive state modules and view-prop builders. The work is purely structural and must preserve all behavior. Every extraction step has explicit checks so a simple agent can execute it safely.
## Goals
- Reduce `src/App.tsx` line count by about 50 percent without changing runtime behavior.
- Keep all signals scoped to the App reactive root by using factory functions.
- Ensure each extraction step is reversible and validated by a consistent test gate.
- Produce a repeatable plan that any agent can follow with minimal judgment calls.
## Non-Goals
- No UI changes or copy changes.
- No data model or storage changes.
- No SDK or API updates.
- No new abstractions that change how state is consumed.
## Definitions
- Extraction: Moving related state and helpers into a new module while keeping logic the same.
- Factory module: A `createXState(...)` or `buildXProps(...)` function called inside App to keep signals scoped.
- Test gate: A single command that must pass after each extraction step.
## Guiding Principles
- Small, reversible moves over large rewrites.
- Preserve function names and signal behavior.
- Avoid new shared global state.
- Keep all props to views identical.
## Current State
- `src/App.tsx` contains routing, state, effects, preference storage, template logic, update flow, and view prop builders.
- There is no single place to see what belongs to which feature.
- Refactors are risky because many flows are coupled in one file.
## Proposal
- Create small modules under `src/app/` that own one domain each.
- Keep App.tsx as wiring only: create signals, instantiate factories, render views and modals.
- Use one test gate after every change and a heavier check every few steps.
## Required Test Gate
Add a single script so every step runs the same command.
- `package.json` script:
- `"test:refactor": "pnpm typecheck && pnpm test:health && pnpm test:sessions"`
## Implementation Plan (step-by-step)
Each step ends with the same two actions:
1) Run `pnpm -C vendor/openwork test:refactor`
2) If it fails, stop and fix or revert the last step.
### Step 0 - Baseline and guardrails
- Action:
- Record baseline line count: `wc -l src/App.tsx`.
- Add `test:refactor` script.
- Pay attention:
- Do not change any runtime logic while adding the script.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 1 - Demo mode state
- Move to: `src/app/demo-state.ts`.
- Move these items:
- `demoMode`, `demoSequence`, `setDemoSequenceState`.
- Demo signals: sessions, statuses, messages, todos, artifacts, working files, authorized dirs, active workspace display.
- `isDemoMode` memo and all `active*` memos.
- `selectDemoSession` helper.
- Inputs required:
- `deriveArtifacts`, `deriveWorkingFiles`, and types `MessageWithParts`, `TodoItem`, `WorkspaceDisplay`.
- Live session data accessors for real mode.
- Pay attention:
- Ensure demo state is reset when sequence changes.
- All `active*` memos must still switch between demo and real state.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 2 - Template management
- Move to: `src/app/template-state.ts`.
- Move these items:
- Template lists and load flags.
- Template modal state and draft signals.
- `openTemplateModal`, `saveTemplate`, `deleteTemplate`, `runTemplate`.
- `loadWorkspaceTemplates` and `workspaceTemplates` / `globalTemplates` memos.
- Inputs required:
- `client`, `workspaceStore.activeWorkspaceRoot`, `loadSessions`, `selectSession`.
- `defaultModel`, `modelVariant`, `setBusy`, `setBusyLabel`, `setBusyStartedAt`, `setError`.
- Tauri commands: `workspaceTemplateWrite`, `workspaceTemplateDelete`.
- Pay attention:
- Preserve busy label values and error messages.
- `loadWorkspaceTemplates` is used by `createWorkspaceStore` and must keep its signature.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 3 - Update, reload, reset, cache repair
- Move to: `src/app/system-state.ts`.
- Move these items:
- Reload state, `reloadCopy`, `canReloadEngine`, `reloadEngineInstance`.
- Cache repair state and `repairOpencodeCache`.
- Update flow: check, download, install, auto-check state.
- Reset modal state and `confirmReset` flow.
- Inputs required:
- `client`, `mode`, `anyActiveRuns`, `refreshPlugins`, `refreshSkills`.
- Provider setters, `setError`, `safeStringify`.
- Tauri commands: `resetOpenworkState`, `resetOpencodeCache`, `updaterEnvironment`.
- Pay attention:
- Reload gating must still block during active runs and non-host mode.
- Reset must still clear local storage before relaunch/reload.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 4 - Provider and model selection
- Move to: `src/app/model-state.ts`.
- Move these items:
- Provider signals, default model, picker state.
- `modelOptions`, `filteredModelOptions`, and picker helpers.
- Inputs required:
- `DEFAULT_MODEL`, `formatModelLabel`, `formatModelRef`.
- `sessionModelOverrideById`, `selectedSessionId`, `setSessionModelOverrideById`.
- Pay attention:
- Keep sorting logic identical (connected and free first).
- Preserve default model fallback behavior when no providers are loaded.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 5 - Preferences and local storage
- Move to: `src/app/preferences.ts`.
- Move these items:
- `onMount` preference hydration.
- All `createEffect` localStorage writes.
- Inputs required:
- Preference signals and setters (baseUrl, clientDirectory, engineSource, demo settings, model settings, update auto-check).
- Helpers and constants: `readModePreference`, `writeModePreference`, `parseModelRef`, `formatModelRef`, preference keys.
- Pay attention:
- Keep legacy keys for compatibility (e.g. `openwork_mode_pref`, `openwork.projectDir`).
- Do not change any localStorage key names or value formats.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 6 - View prop builders
- Move to: `src/app/view-props.ts`.
- Move these items:
- `headerStatus`, `busyHint`, `localHostLabel` memos.
- `onboardingProps`, `dashboardProps` builders.
- Inputs required:
- Pass a single dependency object into `buildOnboardingProps` and `buildDashboardProps` to reduce imports.
- Pay attention:
- Every prop name must match the current view usage.
- Do not remove any callbacks or rename handlers.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
### Step 7 - App.tsx cleanup
- Remove unused imports and reorder remaining imports.
- App.tsx should only create signals, wire factories, and render views/modals.
- Check:
- Run `pnpm -C vendor/openwork test:refactor`.
- Run `pnpm -C vendor/openwork test:e2e`.
## Attention Checklist (every step)
- Do not change view prop names or shapes.
- Keep all async flows, busy labels, and error messages identical.
- Keep all signals and memos created inside the App reactive scope.
- Avoid circular imports between new modules.
- If a move changes import order, re-run the test gate immediately.
## Regression Checks (every step)
- `pnpm -C vendor/openwork test:refactor`
- Manual smoke (optional): `pnpm -C vendor/openwork dev:web` and verify onboarding and dashboard render.
## Acceptance Criteria
- `src/App.tsx` <= 1100 lines.
- All test gates pass after each step.
- Final `pnpm -C vendor/openwork test:e2e` passes.
- No UI or behavior changes.
## Open Questions
- Should `test:refactor` include `pnpm build:web` for extra safety?
- Should the plan enforce a maximum module size to avoid new files getting too large?