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
4 changes: 2 additions & 2 deletions .claude/commands/code-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ Cross-reference both reports. For each finding:
- Re-run linting to verify fixes compile
- Append findings to `docs/audits/dev.md`

### Step 5: Converge (only if invoked with `converge`)
### Step 5: Converge (only if invoked with `--converge`)

If the user ran `/code-audit converge`:
If the user ran `/code-audit --converge`:

Repeat steps 1-4 until a round finds **zero confirmed issues**. Each round:
1. Re-run both auditor agents (they must re-read the code — previous fixes may have introduced new issues)
Expand Down
4 changes: 2 additions & 2 deletions .claude/commands/ui-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Perform a pedantic UI design and accessibility audit. Act as a senior UI designe
4. Run `bunx biome check --write` and `bun run test` to verify
5. Update `docs/audits/ui.md` with findings

### Converge (only if invoked with `converge`)
### Converge (only if invoked with `--converge`)

If the user ran `/ui-audit converge`:
If the user ran `/ui-audit --converge`:

Repeat steps 1-5 until a round finds **zero issues**. Each round:
1. Re-read all files (previous fixes may have introduced new issues)
Expand Down
83 changes: 82 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,94 @@ src-tauri/src/commands.rs Tauri IPC commands (themes, windows, sound)
src-tauri/src/metadata.rs Local metadata store (rename, archive, delete)
```

## Activity detection & dock badge

Session activity is tracked via Claude Code hooks and PTY events. This system has been
through multiple iterations — do not simplify without understanding the full state machine.
Full details in `docs/activity-detection.md`.

### New session creation

`handleNewSession` spawns a PTY with a temporary ID (`new-{timestamp}`), renders it
immediately via `TerminalPane`, then rekeys to the real session UUID once the backend
discovers the JSONL file. The `pendingPty` state tracks the temp ID, cwd, and a snapshot
of existing session IDs (used to match the new session by cwd basename exclusion).
The rekey effect polls at 200ms until discovery, then calls `pty_rekey` which atomically
updates the reader thread's event prefix via a shared `Arc<Mutex<String>>`.

### State machine (`usePtyActivity.ts`) — XState

Each session gets an independent XState actor. The machine has 5 states:

```
idle ──PROMPT──→ computing ──STOP(no agents)──→ draining ──1.5s──→ waiting
│ │
├──STOP(agents>0)──→ agentWait │
│ │ │
├──60s idle──→ waiting ├──AGENT_DONE(count=0)──→ draining
│ ├──PTY_DATA/STOP (reenter)│
└──PTY_DATA──→ computing (reenter, resets timer) │
waiting ──PROMPT──→ computing │
* ──EXIT──→ idle │
```

Key design decisions:
- `draining` state: after a non-agent Stop, PTY_DATA is IGNORED (no transition).
This prevents streaming output from re-entering computing and fighting the timer.
- `agentWait` state: tracks running agent count via PreToolUse(Agent/Task) increments
and SubagentStop decrements. Only transitions to draining when count reaches 0.
PTY_DATA and STOP reenter (no-op, keeps state alive).
- `computing` reenter on PTY_DATA: resets the idle timeout timer.
- `hasRunningAgents` guard: checked via a mutable Map<id, count> outside the machine.
- Agent count is cleared on EXIT to prevent stale counts affecting future sessions.

The `toActivityState` mapper collapses internal states for the UI:
- computing, draining, agentWait → "computing" (snake border)
- waiting → "waiting" (green dot)
- idle → null (no entry in activityMap)

### Cleanup effect (`App.tsx`)

Removes stale session IDs from group slots when the session list changes. Builds a
valid ID set from discovered sessions + pending PTY temp ID, then nulls slots with
unknown IDs. Protects against archived/deleted sessions lingering in groups.

### Unread tracking (`App.tsx`)

A session becomes "unread" when it transitions computing→waiting AND:
- It is not the currently selected session, OR
- The window is not focused (`windowFocusedRef.current === false`)

The second condition is critical — without it, the focused session never becomes
unread when the user Cmd+Tabs away, so the dock badge never shows.

### Dock badge (`App.tsx` + `commands.rs`)

- Uses macOS Cocoa API via `objc2` crate (`NSDockTile.setBadgeLabel`)
- Must run on main thread (`app.run_on_main_thread`)
- Window focus tracked via Tauri's `onFocusChanged` (not DOM focus/blur — those
fire on webview-internal focus changes, causing visual glitches)
- On focus regained: badge cleared AND selected session marked as read
- `unreadCountRef` (not state) used in focus handler to avoid re-renders

### Computing border animation (`index.css`)

Uses conic-gradient rotation on a real `<div>` element (not `::before`).
The mask-composite CSS technique does NOT work in Tauri's WKWebView.
Instead, the gradient div extends 4px outside the pane (`inset: -4px`,
`border-radius: 10px`) and the inner pane's solid background covers
the center. The `@property --cm-angle` must use the `--cm-` prefix
to avoid collision with Tailwind v4's `@property` fallback layer.

## Code style — TypeScript

- All `if` statements must use curly braces, even single-line
- Biome handles formatting (tabs, double quotes, 100 char width) and linting
- Run `bunx biome check --write` to format
- Pure logic belongs in `sidebarUtils.ts` or `groupOps.ts`, not in components
- Inline styles, not CSS classes (except index.css for global/keyframe rules)
- Tailwind utility classes for layout (flex, grid, padding, etc.); inline styles for dynamic/theme values
- index.css for global/keyframe rules only
- No `any` types. Prefer `unknown` and narrow.
- Tests go next to source files (`foo.test.ts` alongside `foo.ts`)

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The session manager for Claude Code. Manage multiple sessions in one window with live status, named groups, and persistent workspaces.

> Not affiliated with or endorsed by Anthropic. Claude is a trademark of Anthropic PBC.

## Why Claude Manager?

**Organise by role.** Name sessions "planner", "implementer", "reviewer" and group them together. Drag to rearrange, switch between project contexts in one click.
Expand Down Expand Up @@ -150,6 +152,8 @@ Right-click a session in the sidebar to access these actions:
### Groups and tiling

- Drag sessions onto a group header to add them. If the group is full, it auto-expands to the next enabled tiling layout.
- Drag a group header onto another group to reorder them. A line shows the insertion point.
- Drag a grouped session onto the sessions list to ungroup it.
- Change tiling layouts from the group header in the sidebar.
- Enable/disable layouts in Settings > Preferences > Tiling Layouts.

Expand Down
10 changes: 10 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading