rename tasks to chats and add an image viewer - #242
Conversation
The dock's "task" vocabulary was the OS-level word leaking into chat UI. Rename every user-visible mention to "chat" — dock header, popovers, agent panel, transcript, console runtime pages, and the gateway's chat-title strings. Identifiers, routes, and `proc delegate`'s separate "delegated task" concept keep the old name. Chat surfaces: - Meta-row buttons open the chat list and start a new chat. Both boxes are odd-sized: a 1px glyph stroke only lands on whole pixels when the box centring it is odd, so the even box snapped them off-centre. - TaskListGlyph's bullets were zero-length round-cap strokes, which drop out under shape-rendering: crispEdges — they are rects now, so the glyph reads as a list instead of a right-shifted hamburger. - The chats popover puts its count beside the title and a + in the corner (new PopoverMenu header action), leaving one VIEW ALL row at the bottom. - Hovering a message timestamp shows the full date and time, via a new opt-in single-line Hint. Image viewer (ImageLightbox): click a chat image to open it full-screen — click to zoom at that point and again to fit, wheel and pinch zoom anchored at the pointer, drag to pan, download, Escape or backdrop to close. The toolbar carries the filename and, quieter beside it, when the image was sent. Zoom and pan maths lives in imageLightboxGeometry with tests. Also: the MCP add-server form placeholders Linear rather than GitHub.
|
@codex review pls |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 181d3c46fe
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| useEffect(() => { | ||
| const previous = document.activeElement as HTMLElement | null; | ||
| closeRef.current?.focus(); | ||
| return () => previous?.focus?.(); |
There was a problem hiding this comment.
Trap keyboard focus inside the image viewer
When a keyboard user tabs forward from the Close button—or backward from the first enabled toolbar control—focus wraps into the chat behind this aria-modal dialog because this effect only sets the initial focus. Those hidden controls can then be activated while the viewer remains open; contain Tab navigation within the lightbox as the existing Dialog and ConfirmModal components do.
Useful? React with 👍 / 👎.
| .gsv-lightbox-caption { | ||
| flex: none; | ||
| margin: 0; |
There was a problem hiding this comment.
Bound long captions so the image remains visible
When a model-provided image description is tall enough to exceed the viewport, this non-shrinking caption consumes its full intrinsic height in the fixed full-screen flex column, reducing the image stage to zero height and overflowing content that cannot be reached because body scrolling is disabled. Give the caption a bounded, scrollable height or otherwise allow it to shrink.
Useful? React with 👍 / 👎.
Trap Tab inside the lightbox. It is aria-modal, but only the initial focus was set, so tabbing off the close button walked into the transcript behind it, where a control is invisible and still activatable. Same trap Dialog and ConfirmModal use, disabled-filter included: zoom out is disabled at fit, so wrapping onto it would drop focus out of the viewer. Bound the caption. A long image description took its full intrinsic height in the fixed flex column, squeezing the stage to nothing and overflowing off a page that cannot scroll. It now shrinks, caps at a third of the screen, and scrolls its own overflow. Give the delivery-notice tombstone test a real timeout. It walks 257 notices, each awaiting a proc.changed signal, which lands near the 5s default locally and over it on a loaded CI runner.
|
@codex review pls |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf2f0e60de
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const TASK_TITLE_GENERATION_TIMEOUT_MS = 20_000; | ||
| const TASK_TITLE_SYSTEM_PROMPT = [ | ||
| "Write a concise task title in the same language as the message.", | ||
| "Write a concise chat title in the same language as the message.", |
There was a problem hiding this comment.
Move the title prompt under prompt ownership
This introduces production system-prompt text directly in the process runtime, even though the repository contract centralizes production prompts in gateway/src/prompts/**. Keeping the title-generation prompt here splits prompt ownership and bypasses the repository's protected prompt review boundary; move the prompt to the owning prompts module and import it here.
AGENTS.md reference: AGENTS.md:L108-L110
Useful? React with 👍 / 👎.
| <a | ||
| class="gsv-lightbox-btn" | ||
| href={src} | ||
| download={filename || alt || "image"} |
There was a problem hiding this comment.
Prevent remote downloads from replacing the app
When an image media record supplies a cross-origin HTTP(S) URL—which chatMediaSource explicitly accepts—the browser ignores the download attribute. Because this anchor neither converts the response to a blob nor opens a separate target, clicking Download navigates the current GSV tab to the image and tears down the active chat UI instead of downloading the file.
Useful? React with 👍 / 👎.
Move the chat-title system prompt into gateway/src/prompts/, which AGENTS.md makes the owner of production prompt text. It sat in process/do.ts, next to the runtime knobs that drive it; the compaction prompt already shows the shape. Text unchanged. Fetch a cross-origin image into a blob before downloading it. chatMediaSource accepts remote http(s) URLs, and there the browser ignores the anchor's download attribute and navigates instead — in a single-page app that replaces the running chat with the image. Same-origin and blob: sources still download straight from the anchor; a host that refuses the fetch falls back to opening the image in its own tab, which at least leaves the chat standing.
|
@codex review svp |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0375d3b3c1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| void downloadViaBlob(src, downloadName).then((downloaded) => { | ||
| if (!downloaded) { | ||
| window.open(src, "_blank", "noopener,noreferrer"); |
There was a problem hiding this comment.
Open the download fallback during user activation
When a cross-origin image host does not provide CORS headers—which is valid for an image displayed via <img>—downloadViaBlob resolves false and this new fallback invokes window.open asynchronously after the fetch. For a slow request, the click's transient user activation has expired by then, so popup blocking leaves the Download action producing neither a file nor a fallback tab; reserve the tab synchronously in the click handler or expose a user-activated fallback link.
Useful? React with 👍 / 👎.
A host may serve an image to <img> and still refuse a cors fetch of it. The fetch has to fail before we know that, and by then the click's transient user activation is spent, so the window.open fallback was liable to be swallowed by the popup blocker — leaving Download with nothing to show for it. Show a notice with a plain link instead. The reader's click on it carries its own activation, so the tab always opens, and the failure is now visible rather than silent.
|
@codex review aub |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8f8bba18b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| [`${statusForProcess(process).toLowerCase()} chat`, owner, process.profile, process.cwd], | ||
| "Process-backed chat with durable history and runtime controls.", |
There was a problem hiding this comment.
Preserve process labels for non-chat runtimes
When proc.list includes a scheduled process.spawn or another interactive: false process, RuntimePage passes it here without filtering, so this function now describes that background process as a chat and the detail page offers labels such as “RESET CHAT” and “OPEN CHAT.” iconForProcess already distinguishes these noninteractive entries; keep generic process/runtime wording for them or apply chat terminology only when process.interactive is true.
AGENTS.md reference: AGENTS.md:L36-L38
Useful? React with 👍 / 👎.
proc.list carries every process, so the runtime pages also list scheduled spawns and other interactive: false entries. The rename described those as chats too, and offered them RESET CHAT and OPEN CHAT — for something nobody ever chatted with. A new processNoun() picks the word from process.interactive, and the detail page's labels, confirmations and blurb follow it. Collection labels (the CHATS list, its NEW CHAT and the breadcrumb back to it) stay as they are: they name the surface, not a single row. Also bottom-align the dock's context reading with the model row and drop the box around it, and take the header's action buttons down to 27px. Mobile keeps its boxed 44px context cell.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c853a51694
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| } | ||
| if (running) { | ||
| const openLabel = openCount === 1 ? "1 open task" : `${openCount} open tasks`; | ||
| const openLabel = openCount === 1 ? "1 open chat" : `${openCount} open chats`; |
There was a problem hiding this comment.
Exclude background processes from open-chat counts
When an account owns a running scheduled or otherwise interactive: false process, ownedProcesses and openCount still include it, so the crew card can report “1 open chat” even when the only activity is a background process. The current revision’s fresh evidence is that processNoun now explicitly recognizes this distinction, but this overview count remains unfiltered; count only interactive processes here or describe the value as process activity.
AGENTS.md reference: AGENTS.md:L36-L38
Useful? React with 👍 / 👎.
A stroke is centred on its path, so the 1px bars of a 24-unit plus always landed half on one pixel and half on the next: the renderer either blurred them or snapped one a whole pixel sideways, leaving the crossing off centre. Round caps on all four arms did the rest, and it read as a cross. It is two filled rects on whole coordinates now. The box and the bar are both odd, so the arms are equal by construction at any size, and they inset two pixels so the glyph matches the weight of the list icon it sits beside. MinusGlyph shares the geometry — the two are a pair in the image viewer.
The crew card counted every process an account owns, so a running scheduled spawn reported "1 open chat" for a conversation nobody ever had. Count the interactive ones for that label, and when an account is running only background work, say that instead of claiming a chat. The other readings on this card — queued, needs review — are process-level facts and stay as they are.
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
The dock's "task" vocabulary was the OS-level word leaking into chat UI. Rename every user-visible mention to "chat" — dock header, popovers, agent panel, transcript, console runtime pages, and the gateway's chat-title strings. Identifiers, routes, and
proc delegate's separate "delegated task" concept keep the old name.Chat surfaces:
Image viewer (ImageLightbox): click a chat image to open it full-screen — click to zoom at that point and again to fit, wheel and pinch zoom anchored at the pointer, drag to pan, download, Escape or backdrop to close. The toolbar carries the filename and, quieter beside it, when the image was sent. Zoom and pan maths lives in imageLightboxGeometry with tests.
Also: the MCP add-server form placeholders Linear rather than GitHub.