ccmanager 4.2.1 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -54,7 +54,7 @@ npm install -g ccmanager
54
54
 
55
55
  ```bash
56
56
  npm install
57
- npm run build
57
+ bun run build
58
58
  npm start
59
59
  ```
60
60
 
@@ -353,17 +353,17 @@ For complete setup instructions and troubleshooting, see [docs/git-worktree-conf
353
353
  npm install
354
354
 
355
355
  # Run in development mode
356
- npm run dev
356
+ bun run dev
357
357
 
358
358
  # Build
359
- npm run build
359
+ bun run build
360
360
 
361
361
  # Run tests
362
362
  npm test
363
363
 
364
364
  # Run linter
365
- npm run lint
365
+ bun run lint
366
366
 
367
367
  # Run type checker
368
- npm run typecheck
368
+ bun run typecheck
369
369
  ```
@@ -39,7 +39,10 @@ const Menu = ({ sessionManager, worktreeService, initialSnapshot, onSnapshotChan
39
39
  loadError: initialSnapshot?.loadError ?? null,
40
40
  });
41
41
  const worktrees = useGitStatus(baseWorktrees, defaultBranch);
42
- const [sessions, setSessions] = useState([]);
42
+ // Seed from the in-memory session list so the cached snapshot renders with its
43
+ // sessions attached. Waiting for the async git load would leave every row
44
+ // session-less for that window, disabling the Space session-actions shortcut.
45
+ const [sessions, setSessions] = useState(() => sessionManager.getAllSessions());
43
46
  const [items, setItems] = useState([]);
44
47
  const [recentProjects, setRecentProjects] = useState([]);
45
48
  const [highlightedWorktreePath, setHighlightedWorktreePath] = useState(null);
@@ -1,9 +1,29 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { render } from 'ink-testing-library';
3
+ import { useInput } from 'ink';
3
4
  import Menu from './Menu.js';
4
5
  import { SessionManager } from '../services/sessionManager.js';
5
6
  import { WorktreeService } from '../services/worktreeService.js';
6
7
  import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ const makeKey = (overrides = {}) => ({
9
+ upArrow: false,
10
+ downArrow: false,
11
+ leftArrow: false,
12
+ rightArrow: false,
13
+ pageDown: false,
14
+ pageUp: false,
15
+ home: false,
16
+ end: false,
17
+ return: false,
18
+ escape: false,
19
+ ctrl: false,
20
+ shift: false,
21
+ tab: false,
22
+ backspace: false,
23
+ delete: false,
24
+ meta: false,
25
+ ...overrides,
26
+ });
7
27
  // Mock bunTerminal to avoid native module issues in tests
8
28
  vi.mock('../services/bunTerminal.js', () => ({
9
29
  spawn: vi.fn(function () {
@@ -216,8 +236,9 @@ describe('Menu component Effect-based error handling', () => {
216
236
  expect(lastFrame()).toContain('cached-branch');
217
237
  expect(getDefaultBranchSpy).toHaveBeenCalled();
218
238
  resolveWorktrees([refreshedWorktree]);
219
- await new Promise(resolve => setTimeout(resolve, 20));
220
- expect(lastFrame()).toContain('refreshed-branch');
239
+ await vi.waitFor(() => {
240
+ expect(lastFrame()).toContain('refreshed-branch');
241
+ });
221
242
  expect(onSnapshotChange).toHaveBeenCalledWith({
222
243
  worktrees: [refreshedWorktree],
223
244
  defaultBranch: 'main',
@@ -253,6 +274,55 @@ describe('Menu component Effect-based error handling', () => {
253
274
  loadError: expect.stringContaining('temporary failure'),
254
275
  });
255
276
  });
277
+ it('should handle the Space session-actions shortcut on a cached snapshot before the refresh completes', async () => {
278
+ const { Effect } = await import('effect');
279
+ const cachedWorktree = {
280
+ path: '/test/cached',
281
+ branch: 'cached-branch',
282
+ isMainWorktree: true,
283
+ hasSession: true,
284
+ };
285
+ const cachedSession = {
286
+ id: 'session-cached',
287
+ worktreePath: '/test/cached',
288
+ lastAccessedAt: 1,
289
+ stateMutex: {
290
+ getSnapshot: () => ({
291
+ state: 'idle',
292
+ backgroundTaskCount: 0,
293
+ teamMemberCount: 0,
294
+ }),
295
+ },
296
+ };
297
+ vi.spyOn(sessionManager, 'getAllSessions').mockReturnValue([cachedSession]);
298
+ // Never resolve the refresh, so only the cached snapshot is on screen.
299
+ vi.spyOn(worktreeService, 'getWorktreesEffect').mockReturnValue(Effect.promise(() => new Promise(() => { })));
300
+ vi.spyOn(worktreeService, 'getDefaultBranchEffect').mockReturnValue(Effect.succeed('main'));
301
+ const onMenuAction = vi.fn();
302
+ vi.mocked(useInput).mockClear();
303
+ render(_jsx(Menu, { sessionManager: sessionManager, worktreeService: worktreeService, initialSnapshot: {
304
+ worktrees: [cachedWorktree],
305
+ defaultBranch: 'main',
306
+ }, onMenuAction: onMenuAction, version: "test" }));
307
+ await new Promise(resolve => setTimeout(resolve, 0));
308
+ // Menu's hotkey handler bails out when raw mode is unavailable.
309
+ const origSetRawMode = process.stdin.setRawMode;
310
+ process.stdin.setRawMode = vi.fn();
311
+ try {
312
+ const calls = vi.mocked(useInput).mock.calls;
313
+ const handler = calls[calls.length - 1]?.[0];
314
+ expect(handler).toBeDefined();
315
+ handler(' ', makeKey());
316
+ }
317
+ finally {
318
+ process.stdin.setRawMode = origSetRawMode;
319
+ }
320
+ expect(onMenuAction).toHaveBeenCalledWith({
321
+ type: 'sessionActions',
322
+ session: cachedSession,
323
+ worktreePath: '/test/cached',
324
+ });
325
+ });
256
326
  });
257
327
  describe('Menu component rendering', () => {
258
328
  let sessionManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "description": "TUI application for managing multiple Claude Code sessions across Git worktrees",
5
5
  "license": "MIT",
6
6
  "author": "Kodai Kabasawa",
@@ -41,11 +41,11 @@
41
41
  "bin"
42
42
  ],
43
43
  "optionalDependencies": {
44
- "@kodaikabasawa/ccmanager-darwin-arm64": "4.2.1",
45
- "@kodaikabasawa/ccmanager-darwin-x64": "4.2.1",
46
- "@kodaikabasawa/ccmanager-linux-arm64": "4.2.1",
47
- "@kodaikabasawa/ccmanager-linux-x64": "4.2.1",
48
- "@kodaikabasawa/ccmanager-win32-x64": "4.2.1"
44
+ "@kodaikabasawa/ccmanager-darwin-arm64": "4.2.2",
45
+ "@kodaikabasawa/ccmanager-darwin-x64": "4.2.2",
46
+ "@kodaikabasawa/ccmanager-linux-arm64": "4.2.2",
47
+ "@kodaikabasawa/ccmanager-linux-x64": "4.2.2",
48
+ "@kodaikabasawa/ccmanager-win32-x64": "4.2.2"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@eslint/js": "^9.28.0",