Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ file is the human-readable summary of what changed and why.
from today, now framed by the sidebar. The **Recents** header is itself a
toggle — clicking it folds the section down to just its title, the chevron
beside it shows which way it is, and the choice is remembered for next launch;
**New session** stays one click away in the titlebar while it is folded. Below
a narrow window width the sidebar hides and the home screen keeps its previous
stacked layout. Two buttons join the titlebar: the leftmost hides and restores
**New session** stays one click away in the titlebar while it is folded. Above
Recents sits a **Pinned** section for the sessions you keep coming back to:
pinning one moves it out of the chronological list into Pinned, where it stays
put. Pinned is exactly as tall as its rows so Recents keeps its space, scrolls
rather than growing once you pass five pins, and folds and remembers that
independently of Recents; its header is there from the start, with nothing
under it until you pin something. Pins are remembered per server, and deleting
a session drops its pin. The **View all** screen grows a matching **Pinned**
group above Today. Below a narrow
window width the sidebar hides and the home screen keeps its previous stacked
layout. Two buttons join the titlebar: the leftmost hides and restores
the sidebar, so a session can have the full window width, and it remembers the
choice — note that Projects live only in the sidebar, so switching project
means opening it again — while the second, next to Home, opens the
Expand All @@ -37,20 +45,22 @@ file is the human-readable summary of what changed and why.
command it dispatches was only ever registered by the old one. Every session
row, in Recents and on **View all**, carries a vertical three-dot button at
its right edge, appearing on hover, which opens the same menu the ⋯ button
beside a session title opens: **Rename**, **Share…** (only where sharing is
enabled), **Archive** and **Delete** — the last in red, and without a trailing
ellipsis in either menu. Renaming edits the row's label in place, Enter saves
and Esc cancels, instead of taking you into the session first; deleting still
asks for confirmation and takes the session's children with it; sharing from a
row opens the session and its share popover, because the share state is not
carried by the list. Previously the only way to rename, archive or delete was
to open the session and use the menu next to its title.
beside a session title opens: **Pin** (**Unpin** once set), **Rename**,
**Share…** (only where sharing is enabled), **Archive** and **Delete** — the
last in red, and without a trailing ellipsis in either menu. Renaming edits
the row's label in place, Enter saves and Esc cancels, instead of taking you
into the session first; deleting still asks for confirmation and takes the
session's children with it; sharing from a row opens the session and its share
popover, because the share state is not carried by the list. Previously the
only way to rename, archive or delete was to open the session and use the menu
next to its title.
([#173](https://github.com/quickbeard/codev-code/pull/173),
[#175](https://github.com/quickbeard/codev-code/pull/175),
[#179](https://github.com/quickbeard/codev-code/pull/179),
[#183](https://github.com/quickbeard/codev-code/pull/183),
[#184](https://github.com/quickbeard/codev-code/pull/184),
[#185](https://github.com/quickbeard/codev-code/pull/185))
[#185](https://github.com/quickbeard/codev-code/pull/185),
[#189](https://github.com/quickbeard/codev-code/pull/189))

### Agent

Expand Down
1 change: 1 addition & 0 deletions DIVERGENCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ from the squash message first, or use a plain merge.
| `packages/app/src/pages/session/timeline/message-timeline.tsx` | **Session actions menu extracted.** The ⋯ menu beside the session title — both renderings, the legacy `DropdownMenu` and the v2 `MenuV2`, ~145 lines — and the `DialogDeleteSession` closure move to the fork-only `packages/app/src/components/session-actions-menu.tsx` (verbatim at extraction; the v2 Delete item has since dropped its ellipsis and taken the danger colour, so do not diff the two expecting a match), and this file renders `<SessionActionsMenu>` instead, passing its existing `openTitleEditor` / share / `archiveSession` / `deleteSession` as callbacks and its trigger element out through `triggerRef` (the share popover still anchors to it). The extracted dialog takes a resolved `title` and an `onConfirm` rather than a `sessionID`, so the caller supplies `sessionTitle(sync().session.get(id)?.title)`. The `title` store loses `pendingRename`/`pendingShare`: deferring Rename and Share until the menu's `onCloseAutoFocus` is now the component's job, since every caller needs it (a list row's inline editor is blurred by the returning focus exactly as the header's was). Also gains one fork-only `createEffect` that consumes `consumeSessionShareRequest(sessionID())` and opens the share popover — the session rows' Share routes through it. | The sidebar's Recents rows and the home session list open the same menu; three copies of four items would drift. Only this file rendered the menu, so extraction is the smallest way to share it. | Keep the extraction. On conflict, take upstream's `message-timeline.tsx` wholesale and re-apply: delete both inline menu blocks and the local `DialogDeleteSession`, mount `<SessionActionsMenu>` with the same callbacks, drop the two `pending*` store fields, and re-add the share-request effect. If upstream adds a menu item, add it to `session-actions-menu.tsx` (both variants) rather than back here. Do not "simplify" the component's deferred rename/share into a plain `onSelect` — focus return is what it exists to survive. |
| `packages/app/src/pages/home.tsx` | `HomeSessionRow` gains the same `<SessionActionsMenu>` (hover/focus/menu-open revealed, vertical dots) and inline rename: while renaming, the row renders a `div` with `InlineEditor` instead of the `button`, because an input inside a button is invalid markup and swallows keystrokes into the open-session handler. `NewHome` holds one `createInlineEditorController()` for the list and passes it plus the model down. Its local `archiveSession` is deleted — `createHomeModel()` owns `archiveSession`/`renameSession`/`deleteSession` now, so the sidebar and this screen run one implementation (extends the "state both screens need moves to home-model.tsx" split in the persistent-sidebar row above); the call site becomes `model.archiveSession`. Upstream's `SHOW_HOME_SESSION_ARCHIVE` block is left exactly as-is — the flag is `false`, so it renders nothing, and touching it would widen the diff for no gain. `data-component="home-session-row"` and every other selector are untouched (`packages/app/e2e` binds to them); the menu adds `data-action="session-menu"`. | The Recents rows and "View all" are the same list at two sizes; a menu on one and not the other makes "View all" a dead end. | Keep our row structure. On conflict take upstream's row and re-apply the menu, the editing branch, and the `model.*` action wiring. Never let a `data-component`/`data-action` hook drift. If upstream re-enables `SHOW_HOME_SESSION_ARCHIVE`, drop that block instead — its absolutely-positioned archive button would sit on top of the menu. |
| `packages/app/src/pages/home.tsx` (again) | **Session lists keyed by id.** The "View all" list iterates `groups().map((group) => group.id)` and, within each group, `group.sessions.map((record) => record.session.id)`, resolving each back through a `createMemo` + `<Show>` rather than handing the objects to `<For>`. `groupSessions` mints new group objects on every call and `createHomeModel`'s records memo mints a new `{session, project, projectName}` wrapper per session on every recompute — the `projects` memo alone returns a fresh array on a pointerdown — and `<For>` keys on reference, so the rows were torn down and rebuilt on recomputes that changed nothing visible. When that landed between a pointerdown and its mouseup the browser had no surviving common ancestor to fire `click` on, so a row's ⋮ menu ignored its first click; the same rebuild could close an open menu or drop an in-progress rename. `data-component="home-session-row"`, `data-action="session-menu"` and the group header refs / opacity keys are unchanged. The fork-only `packages/app/src/components/app-sidebar.tsx` carries the same shape for the Recents list. | A menu that swallows the first click reads as broken, and the cause is structural rather than incidental: any refresh of the session index rebuilt every row. | Keep the id keying. On conflict take upstream's list body and re-apply both `<For>` wrappers. Do not "simplify" back to `<For each={groups()}>` / `<For each={group.sessions}>` — that is the bug. If upstream ever makes groups or records referentially stable this can go, but prove it with `packages/app/e2e/regression/home-session-menu-first-click.spec.ts` before removing it. |
| Pinned sessions: `packages/app/src/pages/home.tsx`, `packages/app/src/pages/session/timeline/message-timeline.tsx`, `packages/app/src/pages/layout-new.tsx`, `packages/app/src/i18n/{en,es}.ts` | **Pin a session to a sidebar section of its own.** The fork-only `src/context/pinned-sessions.tsx` holds the pinned ids — one `Persist.global("sidebar.pinned")` record keyed by `ServerConnection.Key`, newest pin first — and `layout-new.tsx` mounts its provider inside `AppSidebarProvider`; that is the nearest point covering all three surfaces, since `NewAppLayout` is the router root. It has to be context rather than state in `createHomeModel()`: the sidebar and the home screen each hold their own model, so two `persisted` stores over one key would write the same storage without sharing memory and a pin would not cross between them until a reload — the same reason the project selection lives in `useLayout()`. `home-model.tsx` (fork-only) derives `pinnedRecords()` / `recentRecords()` from it and `deleteSession` drops the pins of the whole deleted subtree. In `home.tsx`, `groupSessions` takes the pinned records and emits a leading `pinned` group, and pinned sessions are filtered out of the today/yesterday/older groups so they appear once; `HomeSessionRow` passes `pinned`/`onPin` into `<SessionActionsMenu>`. `message-timeline.tsx` passes the same pair, resolving the server the pin belongs to as `params.serverKey ? requireServerKey(params.serverKey) : useServer().key` — it must match what the sidebar's selection resolves to or the header would toggle a pin the sidebar cannot see. New i18n keys `common.pin`, `common.unpin`, `sidebar.pinned`, `home.sessions.group.pinned` in `en` + `es`. Every `data-component`/`data-action` hook is untouched; the new ones are `data-section="pinned"` and `data-slot="sidebar-pinned-list"`. The Pinned list is keyed by session id for the same reason the row above keys the View all lists — it renders the same rebuilt record wrappers. | A purely chronological Recents buries the handful of sessions someone actually returns to, and "View all" is the only way back. Pinning is the smallest fix, and it has to be offered wherever a session's menu is or it is undiscoverable. | Keep our structure. On conflict take upstream's `home.tsx` / `message-timeline.tsx` wholesale and re-apply: the `pinned` group id and its filter in `groupSessions`, the `pinnedRecords` argument at the `groups` memo, and the two `pinned`/`onPin` props. If upstream adds its own grouping ahead of Today, fold the pinned group in above it rather than replacing it. Never resolve the header's server key differently from the sidebar's — mismatched keys silently split one user's pins in two. |
| `packages/app/e2e/regression/remote-session-settings.spec.ts` | Both tests pick the settings-shortcut modifier by asking the page — `/(Mac|iPod|iPhone|iPad)/.test(navigator.platform)` — through a local `openSettingsDialog(page)` helper, instead of branching on the Node-side `process.platform`. | Upstream's version pressed `Meta+,` whenever the *host* was macOS, but the app resolves `mod` from `navigator.platform` (`IS_MAC` in `src/context/command.tsx`) and Playwright's `devices["Desktop Chrome"]` profile ships a Windows user agent, so the page always reports `Win32`. On a macOS machine the suite therefore pressed Meta while the app listened for Control: the settings dialog never opened and both tests failed, while Linux CI stayed green because there the host branch happened to pick Control anyway. A real macOS browser reports `MacIntel`, so the app is right and only the test was wrong. | Keep our helper. On conflict take upstream's spec and re-apply it. If upstream fixes this itself, drop the row. Worth submitting upstream — it breaks the suite for every macOS developer. |
| `packages/desktop/icons/{dev,beta,prod}/` (all PNGs, `icon.icns`, `icon.ico`, `dock.png`), `packages/desktop/icons/README.md` | Regenerated from the fork-only `packages/desktop/icons/icon.svg` by the fork-only `packages/desktop/scripts/generate-icons.ts`: the brand-red `#ee0033` CoDev "C" — the `--mini` splash badge glyph, at the VS Code extension icon's proportions (unit = 120/1024, mark 480x600 centered) — on a white tile, replacing upstream's black/blueprint "o" mark. All three channels are byte-identical for now (chosen deliberately over upstream's per-channel treatments); the generator still writes them separately so a channel can diverge later. `icon.icns` members and `dock.png` use the macOS Big Sur grid (824/1024 inset + drop shadow); Windows, Linux and Store assets stay full-bleed. README rewritten from the Tauri-CLI + Image2Icon recipe to the generator. The stale Tauri-era `android/` and `ios/` subfolders are left untouched — nothing in the Electron build reads them. | Closes the "desktop app icons need design assets" rebrand gap: the Dock/taskbar icon was still upstream's mark. | Keep our assets and README (binary: take ours wholesale). Regenerate via the script rather than hand-editing; if upstream adds an icon size, add it to `FLAT_PNGS`/`ICONSET` and rerun. |
| `packages/tui/src/theme/assets/codev.json` (new file), `packages/tui/src/theme/index.ts`, `packages/tui/src/context/theme.tsx` | Added the `codev` theme — upstream's `opencode.json` palette with `darkSecondary` → `#0891b2` (brand teal) — registered it in the theme index, and made it the default/fallback theme (`"opencode"` → `"codev"` in the store default, kv fallback, and load-failure fallbacks). `theme/assets/opencode.json` itself matches upstream again. | Brand accent lives in a fork-owned theme instead of edits to upstream's palette; the default theme carries the brand. | Keep our theme file, its index registration, and the fallback strings; when upstream changes the opencode palette, mirror it into `codev.json` (keeping our `darkSecondary`). |
Expand Down
Loading
Loading