Web dashboard: Chat tab + hash deep-linking#21
Conversation
PR 2 of chat→web. Adds a Chat tab to the dashboard backed by the daemon chat_* actions (PR1): - index.html: Chat tab + panel (thread-list sidebar, transcript pane, input, "Ground answers in my notes" toggle, New/Delete). - app.js: loadChat/loadChatThreads/openChatThread/sendChat/newChat/ deleteChatThread. Optimistic user-message render + "Thinking…" while the blocking model call runs; "📚 Grounded in: …" when notes context was used. On open, chat_take_staged picks up a Ctrl+Shift+A selection (read-and-clear) and prefills the box. All DOM via textContent/createElement (no innerHTML). - location.hash tab routing: `/#chat` (or any tab id) selects that tab, so a hotkey/tray can open the dashboard straight to Chat. Clicks update the hash. - styles.css: chat layout (reuses theme variables). The tkinter popup still exists (retired in the next PR). node --check clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bfc88595a6
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| chatThreadId = res.thread_id || chatThreadId; | ||
| const reply = document.createElement("div"); | ||
| reply.className = "chat-msg chat-msg-assistant"; | ||
| reply.textContent = res.reply || "(no reply)"; | ||
| box.append(reply); |
There was a problem hiding this comment.
Prevent stale chat sends from mutating active transcript
When a local model call is pending, only the Send button is disabled; the sidebar/New Chat controls remain active and Ctrl+Enter can still invoke sendChat. Because this continuation writes through the mutable global chatThreadId and the shared #chat-transcript, if the user opens another conversation or starts a new one before chat_send returns, the late response resets the active thread and appends the assistant reply into whichever transcript is currently rendered. Capture the request's thread/render token or block navigation/resubmission while a send is in flight.
Useful? React with 👍 / 👎.
PR 2 of chat→web. A Chat tab backed by the PR1 daemon
chat_*actions:thread-list sidebar, transcript, input, "Ground in my notes" toggle, New/Delete.
Optimistic user message + "Thinking…" during the blocking model call; cites
📚 Grounded in: …when notes context was injected.chat_take_stagedprefillsa Ctrl+Shift+A selection on open.
location.hashrouting (/#chat) so ahotkey/tray can open straight to Chat. All DOM via textContent (no innerHTML).
Popup still present (retired next PR).
node --checkclean.