|
| 1 | +# Project Plan: Resolve Open Issues 210, 211, 212 (2025-12-28) |
| 2 | + |
| 3 | +## Scope Overview |
| 4 | +This plan addresses three open issues in Latitudes-Dev/shuvcode: |
| 5 | +- #210: Local dev mode skips installing .opencode tool dependencies |
| 6 | +- #211: Add directory picker + name field to Create New project flow |
| 7 | +- #212: Archived sessions reappear due to client-side filtering gaps and unused pipe() result |
| 8 | + |
| 9 | +## Context & Decisions Captured |
| 10 | +### Issue 210: .opencode tool dependencies not installed in local dev |
| 11 | +- Root cause: `installDependencies()` in `packages/opencode/src/config/config.ts` returns early when `Installation.isLocal()` is true, so `@opencode-ai/plugin` is not installed for `.opencode/tool` in `bun dev`. |
| 12 | +- Production builds do install dependencies; local dev skips them, causing import errors in tool registry loading. |
| 13 | +- Acceptance criteria from issue: |
| 14 | + - Custom tools in `.opencode/tool/` load without errors when running `bun dev`. |
| 15 | + - Fix must not break production builds. |
| 16 | + - Dependencies should install for local dev without conflicting with global config. |
| 17 | + - Backward compatible with existing `.opencode` configs. |
| 18 | +- Options explicitly discussed in issue: |
| 19 | + - A) Remove local early return (simple; may cause repeated installs). |
| 20 | + - B) Add docs/setup script (manual, not automatic). |
| 21 | + - C) Bundle dependencies during local dev (extend plugin bundling pattern). |
| 22 | + - D) Install on first tool load failure and retry. |
| 23 | +- Decision: Align with upstream by implementing Option A (remove local early return) with a per-directory, concurrency-safe guard to avoid repeated installs while keeping behavior consistent. |
| 24 | +- Guard definition (required): |
| 25 | + - Use a deterministic marker file in each config dir (e.g., `.opencode/.deps-installed.json`) storing the installed version and timestamp. |
| 26 | + - Skip install when marker matches the expected version (`Installation.BASE_VERSION` for non-local, `latest` for local). |
| 27 | + - Serialize installs per directory to avoid concurrent `bun add` calls. |
| 28 | + |
| 29 | +### Issue 211: Add directory picker + name field to Create New flow |
| 30 | +- Current UI in `packages/app/src/components/dialog-create-project.tsx` has two tabs: Add Existing and Create New. Create New uses a single absolute path field and optional repo URL. |
| 31 | +- Desired behavior: |
| 32 | + - Three distinct flows: Add Existing, Create New, Git Clone. |
| 33 | + - Create New: pick parent directory + enter project name; show resolved path with validation; creates new folder. |
| 34 | + - Git Clone: repo URL + target folder picker; derive folder name from repo if blank; optional degit. |
| 35 | + - Add Existing stays unchanged. |
| 36 | +- API integration: `project.create` endpoint in `packages/opencode/src/server/project.ts` and `packages/opencode/src/project/project.ts` accepts `path`, optional `repo`, optional `degit`, optional `name`. |
| 37 | +- Critical semantic clarification: |
| 38 | + - The server does NOT build the directory path from `name`; it only uses `path` to create folders. |
| 39 | + - The client must construct the absolute `path` (parent + folder name) before calling `project.create`. |
| 40 | + - The `name` field is metadata only (display name) and must not be relied on for path composition. |
| 41 | +- Platform constraints: |
| 42 | + - `openDirectoryPickerDialog` is Tauri-only; web must use manual path input. |
| 43 | + - The UI must gate picker usage on availability and keep a text input fallback. |
| 44 | + |
| 45 | +### Issue 212: Archived sessions reappear |
| 46 | +- Root causes: |
| 47 | + - Client-side: `packages/app/src/context/sync.tsx` lacks archived filtering during initial session load and pagination fetch. |
| 48 | + - Server-side: `packages/opencode/src/server/server.ts` calls `pipe(...)` but discards its result, returning unfiltered sessions. |
| 49 | +- Upstream works due to `global-sync.tsx` filtering; fork uses `sync.tsx` without filtering. |
| 50 | +- Acceptance criteria: |
| 51 | + - Filter archived sessions in `sync.tsx` initial load and fetch. |
| 52 | + - Fix server endpoint to return filtered sessions. |
| 53 | + - Avoid duplicated listing and preserve intended sort order. |
| 54 | + |
| 55 | +## Code References (Internal) |
| 56 | +- Issue 210: |
| 57 | + - `packages/opencode/src/config/config.ts` |
| 58 | + - `packages/opencode/src/tool/registry.ts` |
| 59 | + - `packages/opencode/src/plugin/index.ts` |
| 60 | + - `packages/opencode/src/installation/index.ts` |
| 61 | +- Issue 211: |
| 62 | + - `packages/app/src/components/dialog-create-project.tsx` |
| 63 | + - `packages/opencode/src/server/project.ts` |
| 64 | + - `packages/opencode/src/project/project.ts` |
| 65 | + - `packages/app/src/context/platform.tsx` (for `openDirectoryPickerDialog` usage) |
| 66 | +- Issue 212: |
| 67 | + - `packages/app/src/context/sync.tsx` |
| 68 | + - `packages/opencode/src/server/server.ts` |
| 69 | + - `packages/app/src/context/global-sync.tsx` (existing filtering behavior) |
| 70 | + |
| 71 | +## External References (Git URLs) |
| 72 | +- Directory picker usage example (React/Web File System Access API): |
| 73 | + - https://github.com/dinoosauro/easy-backup/blob/a20006f442103b52521419255fe20331760b6d2e/src/App.tsx |
| 74 | +- Cross-runtime directory picker abstraction: |
| 75 | + - https://github.com/ayonli/jsext/blob/ccf374f99a190ad497b5cec974ea20badbe1c8de/dialog/file.ts |
| 76 | + |
| 77 | +## Technical Specifications |
| 78 | +### API Endpoints |
| 79 | +- `GET /project/browse` (browse directories) |
| 80 | +- `POST /project` (`project.create`) |
| 81 | +- `GET /session` (`session.list`) |
| 82 | + |
| 83 | +### Data Models |
| 84 | +- `Project.Create` request fields (from `Project.create.schema`): |
| 85 | + - `path: string` (absolute, required, client-composed from parent + folder name) |
| 86 | + - `name?: string` (display name only) |
| 87 | + - `repo?: string` |
| 88 | + - `degit?: boolean` |
| 89 | +- `Project.CreateResult`: |
| 90 | + - `project: Project.Info` |
| 91 | + - `created: boolean` |
| 92 | +- `Session.Info` includes `time.archived?: number` (used for filtering) |
| 93 | + |
| 94 | +### Configuration & Flags |
| 95 | +| Item | Location | Purpose | Notes | |
| 96 | +| --- | --- | --- | --- | |
| 97 | +| `Installation.isLocal()` | `packages/opencode/src/installation/index.ts` | Detect local dev channel | `OPENCODE_CHANNEL === "local"` | |
| 98 | +| `installDependencies()` | `packages/opencode/src/config/config.ts` | Adds `@opencode-ai/plugin` | Needs per-dir guard and concurrency control | |
| 99 | + |
| 100 | +## Milestones & Implementation Order |
| 101 | +### Milestone 1: Fix archived session filtering (Issue 212) |
| 102 | +- Rationale: Small, isolated change with clear acceptance criteria; reduces user-facing bug quickly. |
| 103 | + |
| 104 | +### Milestone 2: Update Add Project modal flows (Issue 211) |
| 105 | +- Rationale: Larger UI change with dependencies on picker behavior and validation; benefits from stable session list behavior. |
| 106 | + |
| 107 | +### Milestone 3: Fix local tool dependency install (Issue 210) |
| 108 | +- Rationale: Dev workflow improvement; can be implemented after UI work without impacting feature logic. |
| 109 | + |
| 110 | +## Detailed Task Breakdown |
| 111 | +### Issue 212: Archived sessions filtering |
| 112 | +- [x] Add `.filter((s) => !s.time.archived)` to initial session load in `packages/app/src/context/sync.tsx`. |
| 113 | +- [x] Add `.filter((s) => !s.time.archived)` to `fetch` in `packages/app/src/context/sync.tsx`. |
| 114 | +- [x] Fix server-side filtering to return filtered sessions by assigning `pipe(...)` result to `sessions` in `packages/opencode/src/server/server.ts`. |
| 115 | +- [x] Remove duplicate `Session.list()` call and preserve intended sort order (use the filtered list). |
| 116 | +- [x] Add/adjust tests in `packages/opencode/test/` to ensure archived sessions are excluded from list responses. |
| 117 | +- [x] Validate UI list no longer shows archived sessions when reloading or paginating. |
| 118 | + |
| 119 | +### Issue 211: Add Project modal flows |
| 120 | +- [x] Expand tab model to three states: `existing`, `create`, `clone` in `packages/app/src/components/dialog-create-project.tsx`. |
| 121 | +- [x] Extract shared path preview/validation helper for Create New + Git Clone where feasible. |
| 122 | +- [x] Create New flow: |
| 123 | + - [x] Add parent directory picker using `platform.openDirectoryPickerDialog` when available; otherwise use text input. |
| 124 | + - [x] Add required project name input. |
| 125 | + - [x] Compute and display resolved path (`parentDir + projectName`) on the client. |
| 126 | + - [x] Validate name/path (non-empty; no path separators; no traversal; resolved path absolute) and show inline errors. |
| 127 | +- [x] Git Clone flow: |
| 128 | + - [x] Add repo URL input. |
| 129 | + - [x] Add parent directory picker with fallback text input. |
| 130 | + - [x] Add optional project name; derive from repo URL when empty (no path separators). |
| 131 | + - [x] Add optional degit toggle. |
| 132 | + - [x] Show resolved target path before submission. |
| 133 | +- [x] Wire Create New and Git Clone to `globalSDK.client.project.create({ path, repo?, degit?, name? })`. |
| 134 | + - `path` must be fully composed on the client; `name` is display-only metadata. |
| 135 | +- [x] Ensure Add Existing flow behavior remains unchanged. |
| 136 | +- [x] Add/adjust tests in `packages/opencode/test/` covering `project.create` path composition and validation for create/clone scenarios. |
| 137 | +- [x] Smoke test all three flows: Add Existing, Create New, Git Clone. |
| 138 | + |
| 139 | +### Issue 210: Local dev tool dependency install |
| 140 | +- [x] Modify `installDependencies()` in `packages/opencode/src/config/config.ts` to allow local install with a per-directory guard (align with upstream behavior). |
| 141 | +- [x] Implement a deterministic marker file (e.g., `.opencode/.deps-installed.json`) storing installed version and timestamp; skip when valid. |
| 142 | +- [x] Serialize installs per directory to avoid concurrent `bun add` when multiple config directories load in parallel. |
| 143 | +- [x] Ensure `.opencode/tool` installs do not affect global config. |
| 144 | +- [x] Add/adjust tests in `packages/opencode/test/` to verify tool loading works in local dev mode without manual install. |
| 145 | + - Avoid network-dependent installs; mock or stub install paths where needed. |
| 146 | +- [x] Update any dev docs if required (only if solution adds a manual step). |
| 147 | + |
| 148 | +## Validation Criteria |
| 149 | +### Functional Validation |
| 150 | +- Issue 212: |
| 151 | + - Archived sessions never appear in session list after load or fetch. |
| 152 | + - Server `/session` returns filtered (and sorted) list without duplicate listing. |
| 153 | +- Issue 211: |
| 154 | + - Create New builds correct path from parent + name and creates directory. |
| 155 | + - Git Clone derives folder name from repo URL when blank. |
| 156 | + - Name input rejects path separators and traversal sequences. |
| 157 | + - Add Existing is unchanged and still works. |
| 158 | +- Issue 210: |
| 159 | + - Running `bun dev` in repo loads `.opencode/tool` without import errors. |
| 160 | + - Install guard prevents repeated installs on subsequent config loads. |
| 161 | + - Production build behavior unaffected. |
| 162 | + |
| 163 | +### Test Execution (Required) |
| 164 | +- [x] Add tests for new/changed behaviors in `packages/opencode/test/`. |
| 165 | +- [x] Run tests before committing: |
| 166 | + - `bun test` in `packages/opencode` (preferred for targeted tests) |
| 167 | + - or `bun turbo test` at repo root |
| 168 | + |
| 169 | +## Open Questions / Decisions Needed |
| 170 | +- None. Decisions locked: Issue 210 uses Option A with guard; Issue 211 composes `path` in the client and uses `name` as metadata; Issue 212 includes server-side filtering and removes duplicate listing. |
| 171 | + |
| 172 | +(End of file) |
0 commit comments