Skip to content

Claude panel: Windows support and per-project chat history saved in the .kadr - #22

Open
dvgmdvgm wants to merge 2 commits into
HelpFreedom:mainfrom
dvgmdvgm:claude-panel-windows-and-chats
Open

dvgmdvgm wants to merge 2 commits into
HelpFreedom:mainfrom
dvgmdvgm:claude-panel-windows-and-chats

Conversation

@dvgmdvgm

Copy link
Copy Markdown

Two commits, reviewable separately.

1. Claude panel: run on Windows, paste into the terminal

The embedded session was POSIX-only (/bin/sh -c command -v, a /bin/bash watchdog, kill(-pgid)), so on Windows the panel failed at once with File not found.

  • the command is found with where, taking the first hit with a runnable extension — npm puts an extensionless sh shim next to claude.cmd, and CreateProcess cannot run it
  • claude runs directly in the pty (no bash, no process groups); a hard Electron death closes the pseudoconsole, which ends what is attached to it
  • closing kills the whole tree (shim → claude → MCP servers) with taskkill /t /f
  • Ctrl+V pastes instead of sending ^V, and right-click copies a selection or pastes (Electron has no context menu), as in Windows Terminal

2. Per-project chat history, saved inside the .kadr

Until now every panel open started a blank claude, so the assistant had no memory of the edits it had made. Now a project owns its chats:

  • Project.claudeChats holds the session ids. The panel resumes the newest one (--resume), or starts a new one with a known id (--session-id).
  • The header gets a chat picker (title + date) and a New chat button. The usage hint moves into the header's tooltip.
  • Save and autosave embed the transcripts into the project file as claudeTranscripts: {id: jsonl}. project:read takes them out again and keeps them in main, so they never reach the renderer, whose project is deep-copied on every edit.
  • Claude Code resumes only from <config>/projects/<slug of cwd>/<id>.jsonl, so right before a resume the longest known copy is written there. A chat begun in an unsaved project, in another folder or on another machine therefore still resumes.
  • A chat joins the project on the user's first keystroke or paste in it, as a new project object. The unsaved dot and autosave then see that the file's copy is behind, and opening and closing the panel leaves no empty chats.
  • Undo/redo carry the current chat list over, because a chat is not an edit. The panel is keyed by project id, so opening another project brings up its own chats. On Windows a close waits for taskkill, so a quick A→B→A switch never has two claudes writing one transcript.

Heads-up — privacy: a .kadr now carries its chat transcripts, so sharing the project file shares the conversations too.

Not tracked (documented in CLAUDE.md): a session switched inside the TUI (/clear, /resume) gets an id the panel never sees, so New chat is the supported way to start a new conversation. With an args override in claude-env.json no chat flags are added, because the override may run something that is not claude.

Checks

  • node scripts/check-chats.mjs (new; no app, no network, uses a temp CLAUDE_CONFIG_DIR) → 16/16 pass
  • the other four check-*.mjs pass; tsc is clean on both configs
  • Live walk over CDP on Windows 10 / Electron 42, using a crafted transcript so no tokens were spent → 14/14 pass:
    • save embeds the transcript; open keeps it out of the renderer
    • the panel lists and resumes the chat after Claude's own copy was deleted
    • the first key marks the project unsaved
    • New chat starts a new session, and it is recorded only after input
    • A→B→A leaves one claude; undo keeps the list
    • opening another project restarts the panel on that project's chats
    • nothing survives a close; autosave embeds too
  • Before the Windows fix the panel failed with File not found; after it, the TUI opens and the kadr MCP bridge answers kadr_state. Ctrl+V and right-click deliver the clipboard as a bracketed paste, where before they sent ^V and nothing.

Not run: the e2e*.mjs suites. They are Linux-oriented (/tmp, $HOME/.config/kadr, gen-test-media.sh) and were not run here.

🤖 Generated with Claude Code

dvgmdvgm and others added 2 commits September 18, 2026 12:56
The embedded Claude session was POSIX-only: the command was looked up with
/bin/sh, spawned through a /bin/bash watchdog and killed by process group.
On Windows the panel failed at once with "File not found".

- which(): `where` instead of `command -v`, keeping the first hit with a
  runnable extension - npm installs an extensionless sh shim next to
  claude.cmd, and CreateProcess cannot run it
- spawn claude directly in the pty (no bash, no process groups); a hard
  Electron death closes the pseudoconsole, which ends what is attached
- close kills the whole tree (shim -> claude -> MCP servers) with taskkill /t
- Ctrl+V pastes instead of sending ^V, right-click copies a selection or
  pastes (Electron has no context menu), as in Windows Terminal

Verified on Windows 10 with Electron 42: the panel opens the claude TUI,
arguments incl. the quoted system hint arrive intact through claude.cmd,
the kadr MCP bridge answers kadr_state, no process survives a close or a
hard kill, and Ctrl+V / right-click deliver the clipboard as bracketed paste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The embedded assistant forgot everything between panel sessions: every open
started a blank claude, and its transcripts lived only in Claude Code's own
folder for whatever cwd the panel happened to run in. The AI editor had no
memory of the edits it had made to the project.

Now a project owns its chats:

R-1 Project.claudeChats holds the Claude Code session ids; sanitizeProject
    cleans it, undo/redo carry the current list over (a chat is not an edit)
R-2 both writers (save and autosave) embed the transcripts into the file
    as claudeTranscripts: { id: jsonl }; ids with nothing to resume are
    dropped
R-3 project:read takes them out again and keeps them in main - they never
    reach the renderer, whose project is deep-copied on every edit
R-4 the panel resumes the newest chat (claude --resume), first writing the
    longest known copy to <config>/projects/<slug of cwd>/<id>.jsonl, where
    resume looks - so a chat begun in an unsaved project, in another
    folder or on another machine resumes; with no chats a new one starts
    with a known id (--session-id). A chat joins the project on the user's
    first key or paste, as a new project object, so the unsaved dot and
    autosave see that the file's transcript is behind - and a panel opened
    and closed again leaves no empty chat behind
R-5 the panel header gets a chat picker (title + date) and a New chat
    button; the usage hint moves into the header's tooltip. The panel is
    keyed by project id: opening another project brings up ITS chats.
    On Windows a close now waits for taskkill, so a quick A->B->A switch
    never has two claudes writing one transcript
R-6 electron/chats.ts, checked by scripts/check-chats.mjs (no app, no
    network, a temp CLAUDE_CONFIG_DIR)
R-8 CLAUDE.md documents it, together with the Windows notes of the
    previous commit

Not tracked, by design and documented: a session switched inside the TUI
(/clear, /resume) gets an id the panel never sees - New chat is the way.
An args override in claude-env.json gets no chat flags: it may run
something that is not claude.

Checks: node scripts/check-chats.mjs -> all passed (16); the other four
check-*.mjs pass; tsc on both configs clean. Live walk over CDP on Windows
with a crafted transcript (no tokens spent), 14/14: save embeds it, open
keeps it out of the renderer, the panel lists and resumes it after Claude's
own copy was deleted, the first key marks the project unsaved, New chat
starts --session-id and is recorded only after input, a quick A->B->A
switch leaves one claude, undo keeps the list, another project restarts
the panel on its own chats, nothing survives a close; autosave embeds too.

Co-Authored-By: Claude Opus 5 <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