From 7ff4783eb885c7fae2c87d442e06eb224888cac0 Mon Sep 17 00:00:00 2001 From: Jeffrey Wardman <23271678+JeffreyWardman@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:52:59 +1000 Subject: [PATCH 01/10] style: formatting fixes --- .github/workflows/ci.yml | 1 - CLAUDE.md | 9 ++++-- biome.json | 2 +- package.json | 4 ++- src-tauri/Cargo.toml | 3 ++ src-tauri/src/pty_manager.rs | 1 + src/App.tsx | 32 ++++++++++----------- src/components/CommandPalette.tsx | 6 ++++ src/components/GridLayout.tsx | 6 ++-- src/components/NewSessionModal.tsx | 13 ++++++++- src/components/Settings.tsx | 28 +++++++++++++++---- src/components/Sidebar.tsx | 45 +++++++++++++++++++++++++----- src/components/TerminalPane.tsx | 3 +- src/hooks/useFocusTrap.ts | 1 + 14 files changed, 114 insertions(+), 40 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f51b16f..35a3029 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,6 @@ name: CI on: pull_request: - branches: [main] jobs: check: diff --git a/CLAUDE.md b/CLAUDE.md index 0e8cf1d..87e697a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,9 +59,12 @@ src-tauri/src/metadata.rs Local metadata store (rename, archive, delete) ## Linting -- Frontend: `bunx biome check` (0 errors, warnings acceptable for exhaustive deps and a11y click handlers) -- Backend: `cargo fmt -- --check && cargo clippy` -- CI runs both on PR +- `bun run check` — runs full CI pipeline: `tsc`, `biome check`, `vitest`, `cargo fmt --check`, `cargo clippy` +- `bun run fmt` — auto-format both frontend (biome) and backend (rustfmt) +- `bun run clippy` — run clippy standalone +- Frontend: `bunx biome check` (0 errors, 0 warnings) +- Backend: `cargo fmt -- --check && cargo clippy -D warnings` +- CI runs on all PRs and must pass before merge ## Documentation diff --git a/biome.json b/biome.json index 6ee7a72..ae46e59 100644 --- a/biome.json +++ b/biome.json @@ -30,7 +30,7 @@ "a11y": { "useKeyWithClickEvents": "warn", "noStaticElementInteractions": "warn", - "useSemanticElements": "warn", + "useSemanticElements": "off", "useValidAnchor": "warn", "noSvgWithoutTitle": "off" } diff --git a/package.json b/package.json index b9d43e1..15d9834 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "test:watch": "vitest", "lint": "biome check .", "format": "biome check --write .", - "check": "tsc --noEmit && biome check . && vitest run" + "check": "tsc --noEmit && biome check . && vitest run && cargo fmt --manifest-path src-tauri/Cargo.toml -- --check && cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings", + "fmt": "biome check --write . && cargo fmt --manifest-path src-tauri/Cargo.toml", + "clippy": "cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings" }, "dependencies": { "@tauri-apps/api": "^2", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 15033c8..d5c14fc 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -31,3 +31,6 @@ portable-pty = "0.8" base64 = "0.22" shell-escape = "0.1.5" +[profile.release] +strip = true +lto = true diff --git a/src-tauri/src/pty_manager.rs b/src-tauri/src/pty_manager.rs index 079ad97..9a27295 100644 --- a/src-tauri/src/pty_manager.rs +++ b/src-tauri/src/pty_manager.rs @@ -65,6 +65,7 @@ impl PtyState { } #[tauri::command] +#[allow(clippy::too_many_arguments)] pub fn pty_spawn( id: String, cwd: String, diff --git a/src/App.tsx b/src/App.tsx index e175556..bf2d9b0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -213,7 +213,19 @@ function AppInner() { setActiveGroupId(null); localStorage.removeItem(activeGroupKey(configDir)); } - }, [groups, activeGroupId]); + }, [groups, activeGroupId, configDir]); + + const persistGroups = useCallback((next: PaneGroup[]) => { + setGroups(next); + localStorage.setItem(groupsKey(configDirRef.current), JSON.stringify(next)); + }, []); + + const activateGroup = useCallback((id: string) => { + setActiveGroupId(id); + localStorage.setItem(activeGroupKey(configDirRef.current), id); + setFocusedSlotIdx(0); + setStandaloneSelectedId(null); + }, []); // Keep focusedSlotIdx in bounds useEffect(() => { @@ -239,18 +251,6 @@ function AppInner() { } }, [sessions, groups, persistGroups]); - function persistGroups(next: PaneGroup[]) { - setGroups(next); - localStorage.setItem(groupsKey(configDir), JSON.stringify(next)); - } - - function activateGroup(id: string) { - setActiveGroupId(id); - localStorage.setItem(activeGroupKey(configDir), id); - setFocusedSlotIdx(0); - setStandaloneSelectedId(null); - } - const handleActivateGroupAtSlot = useCallback((groupId: string, slotIdx: number) => { setActiveGroupId(groupId); localStorage.setItem(activeGroupKey(configDirRef.current), groupId); @@ -278,9 +278,9 @@ function AppInner() { const newActive = next[0]?.id ?? null; setActiveGroupId(newActive); if (newActive) { - localStorage.setItem(activeGroupKey(configDir), newActive); + localStorage.setItem(activeGroupKey(configDirRef.current), newActive); } else { - localStorage.removeItem(activeGroupKey(configDir)); + localStorage.removeItem(activeGroupKey(configDirRef.current)); } } }, @@ -420,7 +420,7 @@ function AppInner() { } // Session not in any group — just visually select it setActiveGroupId(null); - localStorage.removeItem(activeGroupKey(configDir)); + localStorage.removeItem(activeGroupKey(configDirRef.current)); setFocusedSlotIdx(0); setStandaloneSelectedId(s.session_id); }, diff --git a/src/components/CommandPalette.tsx b/src/components/CommandPalette.tsx index b942fd3..fe685cd 100644 --- a/src/components/CommandPalette.tsx +++ b/src/components/CommandPalette.tsx @@ -113,9 +113,15 @@ export function CommandPalette({ aria-label="Command palette" style={modalBackdropStyle} onClick={onClose} + onKeyDown={(e) => { + if (e.key === "Escape") { + onClose(); + } + }} >
~/.config/claude-manager/themes/. See
the{" "}
- {
- e.preventDefault();
+ {" "}
+ {" "}
for the full JSON schema.
)}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index beb4781..02140ee 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,5 +1,5 @@
import { invoke } from "@tauri-apps/api/core";
-import { useEffect, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { SLOT_COUNTS } from "../groupOps";
import type { ActivityState } from "../hooks/usePtyActivity";
import type { SortMode } from "../sidebarUtils";
@@ -391,6 +391,12 @@ export function Sidebar({
: filteredSessions.filter((s) => matchSession(s, searchQuery))
: filteredSessions;
+ const startRename = useCallback((session: ClaudeSession) => {
+ setRenamingId(session.session_id);
+ setRenameValue(session.display_name ?? session.project_name);
+ setContextMenu(null);
+ }, []);
+
useEffect(() => {
const handleKey = (e: KeyboardEvent) => {
if (renamingId || renamingGroupId) {
@@ -432,12 +438,6 @@ export function Sidebar({
return () => window.removeEventListener("keydown", handleKey);
}, [sessions, selectedId, onSelect, renamingId, renamingGroupId, filteredSessions, startRename]);
- function startRename(session: ClaudeSession) {
- setRenamingId(session.session_id);
- setRenameValue(session.display_name ?? session.project_name);
- setContextMenu(null);
- }
-
async function commitRename(sessionId: string) {
try {
const trimmed = renameValue.trim();
@@ -638,6 +638,7 @@ export function Sidebar({
{filterDropdownOpen && (
A desktop app for managing multiple Claude Code sessions side by side.
From ecc3bedff91f3c0b63d310b76f1f70ac0543c3b4 Mon Sep 17 00:00:00 2001
From: Jeffrey Wardman <23271678+JeffreyWardman@users.noreply.github.com>
Date: Fri, 17 Apr 2026 22:42:29 +1000
Subject: [PATCH 04/10] add check if first tag
---
.github/workflows/release.yml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 168723a..fb8c99b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -34,7 +34,12 @@ jobs:
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
LATEST_VERSION=${LATEST_TAG#v}
- if [ -n "$LATEST_TAG" ] && [ "$CURRENT" != "$LATEST_VERSION" ]; then
+ if [ -z "$LATEST_TAG" ] && [ "$CURRENT" != "0.0.0" ]; then
+ echo "First release: $CURRENT (no existing tags)"
+ echo "bumped=true" >> "$GITHUB_OUTPUT"
+ echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
+ echo "pre_bumped=true" >> "$GITHUB_OUTPUT"
+ elif [ -n "$LATEST_TAG" ] && [ "$CURRENT" != "$LATEST_VERSION" ]; then
echo "Version already bumped to $CURRENT (latest tag: $LATEST_TAG)"
echo "bumped=true" >> "$GITHUB_OUTPUT"
echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
From da93451a94523940c719e748ffeb39bdcfb098ad Mon Sep 17 00:00:00 2001
From: Jeffrey Wardman <23271678+JeffreyWardman@users.noreply.github.com>
Date: Fri, 17 Apr 2026 22:45:43 +1000
Subject: [PATCH 05/10] release fix
---
.github/workflows/release.yml | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fb8c99b..1d4e5f8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -34,17 +34,27 @@ jobs:
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
LATEST_VERSION=${LATEST_TAG#v}
- if [ -z "$LATEST_TAG" ] && [ "$CURRENT" != "0.0.0" ]; then
- echo "First release: $CURRENT (no existing tags)"
- echo "bumped=true" >> "$GITHUB_OUTPUT"
- echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
- echo "pre_bumped=true" >> "$GITHUB_OUTPUT"
- elif [ -n "$LATEST_TAG" ] && [ "$CURRENT" != "$LATEST_VERSION" ]; then
+ if [ -z "$LATEST_TAG" ]; then
+ # First release — no existing tags
+ if [ "$CURRENT" != "0.0.0" ]; then
+ echo "First release: $CURRENT (pre-bumped, no existing tags)"
+ echo "bumped=true" >> "$GITHUB_OUTPUT"
+ echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
+ echo "pre_bumped=true" >> "$GITHUB_OUTPUT"
+ else
+ cz bump --yes --increment MINOR
+ VERSION=$(cz version --project)
+ echo "First release: $VERSION"
+ echo "bumped=true" >> "$GITHUB_OUTPUT"
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+ echo "pre_bumped=false" >> "$GITHUB_OUTPUT"
+ fi
+ elif [ "$CURRENT" != "$LATEST_VERSION" ]; then
echo "Version already bumped to $CURRENT (latest tag: $LATEST_TAG)"
echo "bumped=true" >> "$GITHUB_OUTPUT"
echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
echo "pre_bumped=true" >> "$GITHUB_OUTPUT"
- elif cz bump --dry-run 2>/dev/null; then
+ elif cz bump --yes --dry-run 2>/dev/null; then
cz bump --yes
VERSION=$(cz version --project)
echo "bumped=true" >> "$GITHUB_OUTPUT"
From 3215a27b54b4949b0167547a6553f6adc107abe4 Mon Sep 17 00:00:00 2001
From: Jeffrey Wardman <23271678+JeffreyWardman@users.noreply.github.com>
Date: Fri, 17 Apr 2026 22:47:31 +1000
Subject: [PATCH 06/10] git config in cicd
---
.github/workflows/release.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1d4e5f8..22431ed 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -24,6 +24,10 @@ jobs:
- run: pip install commitizen
+ - run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+
- id: bump
run: |
CURRENT=$(python3 -c "
From 4a39d9f6a34306adb3f732fef4c42d4b90b2b4fe Mon Sep 17 00:00:00 2001
From: Jeffrey Wardman <23271678+JeffreyWardman@users.noreply.github.com>
Date: Fri, 17 Apr 2026 23:02:00 +1000
Subject: [PATCH 07/10] push to head
---
.github/workflows/release.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 22431ed..b0f696b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -164,7 +164,7 @@ jobs:
git add -A
git commit -m "bump: v${{ needs.bump.outputs.version }}"
git tag "v${{ needs.bump.outputs.version }}"
- git push origin main --follow-tags
+ git push origin HEAD --follow-tags
- name: Tag pre-bumped version
if: needs.bump.outputs.pre_bumped == 'true'
From 17b74663f3d5ac439565272fa97422db345a70f3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"