Skip to content

feat: drag-to-split, queue reorder, Cmd+Shift+T, PR auto-refresh#26

Merged
aletc1 merged 1 commit intodevfrom
claude/sad-jang-6f9b13
Apr 18, 2026
Merged

feat: drag-to-split, queue reorder, Cmd+Shift+T, PR auto-refresh#26
aletc1 merged 1 commit intodevfrom
claude/sad-jang-6f9b13

Conversation

@aletc1
Copy link
Copy Markdown
Owner

@aletc1 aletc1 commented Apr 18, 2026

Summary

  • Drag-to-split — drag any sub-chat from the sidebar onto the main chat area to create or extend the split view. DndContext lifted from the sidebar to a shared parent so the drag can cross components; DragOverlay renders a portal-mounted preview so the sidebar's scroll-container overflow can't clip the dragged row. Drop zones disable themselves when the drop would no-op (dragging the active chat in solo mode, already a split pane, or split at max) so no misleading hover highlight appears.
  • Queue drag-reorder — drag pending messages in the queue indicator to reprioritize. Items with status === "processing" are undraggable so the processor and the user don't fight over ordering.
  • Cmd+Shift+T (or Opt+Cmd+Shift+T on web) — creates a new sub-chat and opens it in split view alongside the previously active chat. The + button tooltip now shows both Cmd+T ("New chat") and Cmd+Shift+T ("New in split").
  • PR status auto-refresh — after a stream ends, extractGitActivity scans message parts for a commit/push/PR; if found, chats.getPrStatus and changes.getGitHubStatus are invalidated so the PR badge updates immediately instead of waiting for the 30s poll. messages kept out of the effect deps (read via ref) so the effect only fires on the stream-end transition.
  • Per-pane close button — small X inline with each split pane's title (flex sibling of ChatTitleEditor). Persistent so it doesn't vanish mid-hover; tooltip switches between "Remove from split" and "Close split view" (last pair).
  • Fix: removeFromSplit now shifts activeSubChatId to an adjacent remaining pane when the removed pane was active — previously the UI kept pointing at the just-closed chat, making it look like the wrong pane closed.
  • Chore: hide the Background (Soon) work-mode option until it's wired up; commented out in place for easy rollback.

Test plan

  • Drag a pinned sub-chat from the sidebar onto the main chat area (solo mode) → creates a 2-pane split.
  • Drag any other sub-chat onto an existing split → appends up to 4 panes, no-op at max.
  • Drag the active sub-chat onto the main area → no hover highlight, no drop.
  • Sidebar reorder (pinned and unpinned sections) still works.
  • Queue 3+ messages, drag to reorder; processing item has no drag handle.
  • Cmd+T creates a normal new sub-chat (no split). Cmd+Shift+T creates one in split view.
  • + button tooltip shows both shortcuts.
  • Ask Claude to git commit or git push — PR badge state refreshes right after the stream ends (not 30s later). No spurious refresh after non-git tool calls.
  • Click the X on a split pane — that specific pane closes; the remaining pane stays visible. Works for both left and right panes and for the active pane.
  • New Chat form's work-mode selector shows only Local and Worktree.
  • Existing right-click context-menu options (Open in Split, Remove from Split, Close Split View) still work; divider resize still smooth with 350px min pane width.

🤖 Generated with Claude Code

Adds drag-and-drop to create/extend the split view by dragging sub-chats
from the sidebar, drag reordering for queued messages, a Cmd+Shift+T
shortcut (and tooltip) that opens a new sub-chat directly in split view,
and PR status auto-refresh on git commit/push. Also adds a per-pane close
button inline with the title, hides the Background/sandbox option, and
lifts the sidebar's DndContext to a shared parent so drag can cross from
sidebar to main content without overflow clipping (DragOverlay portals the
preview at document root).

Fix: `removeFromSplit` now shifts `activeSubChatId` when the removed pane
was active so the correct pane stays visible after close.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aletc1 aletc1 merged commit 4178b94 into dev Apr 18, 2026
@aletc1 aletc1 deleted the claude/sad-jang-6f9b13 branch April 18, 2026 16:33
aletc1 added a commit that referenced this pull request Apr 18, 2026
Adds the user-visible features shipped since the README was last touched
(commits #18 through #26) and groups the fork additions into four
sections for readability: Workflow & UI, Git/PRs/Worktrees, Models, and
Stability & Polish.

Highlights surfaced: split view with drag-to-split, Cmd+Shift+T, sortable
sidebar, draggable tabs, queue reorder, copy popover, PR widget +
branch switcher, two-column commit diff, Pull & Push recovery dialog,
worktree deletion safety, Sonnet 4.6 1M context + recovery action,
GPT-5.4, rich tool rendering, stream wedge timeout, and crash
auto-recovery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aletc1 added a commit that referenced this pull request Apr 18, 2026
…esh (#27)

* fix(security,perf): audit-driven hardening of main process

Addresses critical findings from a security/correctness/performance audit.

Security (P0):
- voice.ts, claude/env.ts: replace `execSync(${shell} -ilc '...')` with
  `execFileSync(shell, ['-ilc', ...])` and add a safe-shell allowlist to
  block `$SHELL=` command-injection via template interpolation.
- claude-token.ts: remove `shell: true` from the `claude setup-token`
  spawn and resolve the CLI to an absolute path via `which`/`where`
  before invoking, so metacharacters in PATH can't be interpreted.
- auth-manager.ts + index.ts: the `/auth` deep-link handler now requires
  an in-flight OAuth flow initiated by `startAuthFlow()`. A per-flow
  `state` nonce is generated, attached to the auth URL, and verified
  with constant-time compare on callback. Unsolicited deep links (drive-
  by CSRF via `twentyfirst-agents://auth?code=...`) are rejected.

Performance (P1):
- db/index.ts: add `PRAGMA synchronous = NORMAL` under WAL to reduce
  fsync load during high-frequency message persistence.
- db/schema/index.ts + drizzle/0009_*: add indexes on `chats.project_id`,
  `sub_chats.chat_id`, and `sub_chats.stream_id` (previously full-table
  scans on hot FK lookups).
- claude.ts: coalesce `text-delta` chunks in a 24ms buffer keyed by
  text id. Non-delta chunks flush the buffer first to preserve ordering.
  Cuts tRPC/IPC chatter during long streaming responses.

Robustness (P2):
- db/index.ts: migration failures now quarantine the DB file to
  `agents.db.broken-<timestamp>` and start fresh instead of crashing
  the app on every launch.
- index.ts: bound `cleanupGitWatchers()` in `before-quit` to 1.5s so a
  hung chokidar instance can't block app quit indefinitely.

Dismissed during verification:
- `sandbox: false` in webPreferences is intentional for electron-trpc;
  contextIsolation remains enabled.
- `activeSessions` map cleanup is already wired on unsubscribe and in
  the stream's finally block.
- The stream's async IIFE is wrapped in try/catch/finally; no
  unhandled rejection.
- Project deletion is atomic under FK cascade with `foreign_keys=ON`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: refresh fork additions section with recent features

Adds the user-visible features shipped since the README was last touched
(commits #18 through #26) and groups the fork additions into four
sections for readability: Workflow & UI, Git/PRs/Worktrees, Models, and
Stability & Polish.

Highlights surfaced: split view with drag-to-split, Cmd+Shift+T, sortable
sidebar, draggable tabs, queue reorder, copy popover, PR widget +
branch switcher, two-column commit diff, Pull & Push recovery dialog,
worktree deletion safety, Sonnet 4.6 1M context + recovery action,
GPT-5.4, rich tool rendering, stream wedge timeout, and crash
auto-recovery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant