ccmanager 3.2.8 → 3.2.10

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.
@@ -405,7 +405,7 @@ const App = ({ devcontainerConfig, multiProject }) => {
405
405
  React.createElement(Text, { color: "red" },
406
406
  "Error: ",
407
407
  error))),
408
- React.createElement(DeleteWorktree, { onComplete: handleDeleteWorktrees, onCancel: handleCancelDeleteWorktree })));
408
+ React.createElement(DeleteWorktree, { projectPath: selectedProject?.path, onComplete: handleDeleteWorktrees, onCancel: handleCancelDeleteWorktree })));
409
409
  }
410
410
  if (view === 'deleting-worktree') {
411
411
  // Compose message based on loading context
@@ -121,7 +121,7 @@ const ConfigureStatusHooks = ({ onComplete, }) => {
121
121
  React.createElement(Box, { marginTop: 1 },
122
122
  React.createElement(Text, { dimColor: true }, "Environment variables available: CCMANAGER_OLD_STATE, CCMANAGER_NEW_STATE,")),
123
123
  React.createElement(Box, null,
124
- React.createElement(Text, { dimColor: true }, "CCMANAGER_WORKTREE, CCMANAGER_WORKTREE_BRANCH, CCMANAGER_SESSION_ID")),
124
+ React.createElement(Text, { dimColor: true }, `CCMANAGER_WORKTREE_PATH, CCMANAGER_WORKTREE_BRANCH, CCMANAGER_SESSION_ID`)),
125
125
  React.createElement(Box, { marginTop: 1 },
126
126
  React.createElement(Text, { dimColor: true }, "Press Enter to save, Tab to toggle enabled, Esc to cancel"))));
127
127
  }
@@ -96,7 +96,7 @@ const ConfigureWorktreeHooks = ({ onComplete, }) => {
96
96
  currentEnabled ? '✓' : '✗',
97
97
  " (Press Tab to toggle)")),
98
98
  React.createElement(Box, { marginTop: 1 },
99
- React.createElement(Text, { dimColor: true }, "Environment variables available: CCMANAGER_WORKTREE, CCMANAGER_WORKTREE_BRANCH,")),
99
+ React.createElement(Text, { dimColor: true }, "Environment variables available: CCMANAGER_WORKTREE_PATH, CCMANAGER_WORKTREE_BRANCH,")),
100
100
  React.createElement(Box, null,
101
101
  React.createElement(Text, { dimColor: true }, "CCMANAGER_BASE_BRANCH, CCMANAGER_GIT_ROOT")),
102
102
  React.createElement(Box, { marginTop: 1 },
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  interface DeleteWorktreeProps {
3
+ projectPath?: string;
3
4
  onComplete: (worktreePaths: string[], deleteBranch: boolean) => void;
4
5
  onCancel: () => void;
5
6
  }
@@ -5,7 +5,7 @@ import { Effect } from 'effect';
5
5
  import { WorktreeService } from '../services/worktreeService.js';
6
6
  import DeleteConfirmation from './DeleteConfirmation.js';
7
7
  import { shortcutManager } from '../services/shortcutManager.js';
8
- const DeleteWorktree = ({ onComplete, onCancel, }) => {
8
+ const DeleteWorktree = ({ projectPath, onComplete, onCancel, }) => {
9
9
  const [worktrees, setWorktrees] = useState([]);
10
10
  const [selectedIndices, setSelectedIndices] = useState(new Set());
11
11
  const [confirmMode, setConfirmMode] = useState(false);
@@ -15,7 +15,7 @@ const DeleteWorktree = ({ onComplete, onCancel, }) => {
15
15
  useEffect(() => {
16
16
  let cancelled = false;
17
17
  const loadWorktrees = async () => {
18
- const worktreeService = new WorktreeService();
18
+ const worktreeService = new WorktreeService(projectPath);
19
19
  try {
20
20
  const allWorktrees = await Effect.runPromise(worktreeService.getWorktreesEffect());
21
21
  if (!cancelled) {
@@ -36,7 +36,7 @@ const DeleteWorktree = ({ onComplete, onCancel, }) => {
36
36
  return () => {
37
37
  cancelled = true;
38
38
  };
39
- }, []);
39
+ }, [projectPath]);
40
40
  // Create menu items from worktrees
41
41
  const menuItems = worktrees.map((worktree, index) => {
42
42
  const branchName = worktree.branch
@@ -40,6 +40,57 @@ describe('DeleteWorktree - Effect Integration', () => {
40
40
  beforeEach(() => {
41
41
  vi.clearAllMocks();
42
42
  });
43
+ it('should pass projectPath to WorktreeService when provided', async () => {
44
+ // GIVEN: projectPath is provided
45
+ const projectPath = '/test/project';
46
+ const mockWorktrees = [
47
+ {
48
+ path: '/test/project/wt1',
49
+ branch: 'feature-1',
50
+ isMainWorktree: false,
51
+ hasSession: false,
52
+ },
53
+ ];
54
+ const mockEffect = Effect.succeed(mockWorktrees);
55
+ vi.mocked(WorktreeService).mockImplementation(function () {
56
+ return {
57
+ getWorktreesEffect: vi.fn(() => mockEffect),
58
+ };
59
+ });
60
+ const onComplete = vi.fn();
61
+ const onCancel = vi.fn();
62
+ // WHEN: Component renders with projectPath
63
+ render(React.createElement(DeleteWorktree, { projectPath: projectPath, onComplete: onComplete, onCancel: onCancel }));
64
+ // Wait for Effect to execute
65
+ await new Promise(resolve => setTimeout(resolve, 50));
66
+ // THEN: WorktreeService was called with projectPath
67
+ expect(WorktreeService).toHaveBeenCalledWith(projectPath);
68
+ });
69
+ it('should use undefined when projectPath not provided', async () => {
70
+ // GIVEN: No projectPath
71
+ const mockWorktrees = [
72
+ {
73
+ path: '/test/wt1',
74
+ branch: 'feature-1',
75
+ isMainWorktree: false,
76
+ hasSession: false,
77
+ },
78
+ ];
79
+ const mockEffect = Effect.succeed(mockWorktrees);
80
+ vi.mocked(WorktreeService).mockImplementation(function () {
81
+ return {
82
+ getWorktreesEffect: vi.fn(() => mockEffect),
83
+ };
84
+ });
85
+ const onComplete = vi.fn();
86
+ const onCancel = vi.fn();
87
+ // WHEN: Component renders without projectPath
88
+ render(React.createElement(DeleteWorktree, { onComplete: onComplete, onCancel: onCancel }));
89
+ // Wait for Effect to execute
90
+ await new Promise(resolve => setTimeout(resolve, 50));
91
+ // THEN: WorktreeService was called with undefined (defaults to cwd)
92
+ expect(WorktreeService).toHaveBeenCalledWith(undefined);
93
+ });
43
94
  it('should load worktrees using Effect-based method', async () => {
44
95
  // GIVEN: Mock worktrees returned by Effect
45
96
  const mockWorktrees = [
@@ -27,7 +27,7 @@ const NewWorktree = ({ projectPath, onComplete, onCancel, }) => {
27
27
  // Initialize worktree service and load branches using Effect
28
28
  useEffect(() => {
29
29
  let cancelled = false;
30
- const service = new WorktreeService();
30
+ const service = new WorktreeService(projectPath);
31
31
  const loadBranches = async () => {
32
32
  // Use Effect.all to load branches and defaultBranch in parallel
33
33
  const workflow = Effect.all([service.getAllBranchesEffect(), service.getDefaultBranchEffect()], { concurrency: 2 });
@@ -63,7 +63,7 @@ const NewWorktree = ({ projectPath, onComplete, onCancel, }) => {
63
63
  return () => {
64
64
  cancelled = true;
65
65
  };
66
- }, []);
66
+ }, [projectPath]);
67
67
  // Create branch items with default branch first (memoized)
68
68
  const allBranchItems = useMemo(() => [
69
69
  { label: `${defaultBranch} (default)`, value: defaultBranch },
@@ -17,7 +17,8 @@ export class ClaudeStateDetector extends BaseStateDetector {
17
17
  return 'waiting_input';
18
18
  }
19
19
  // Check for busy state
20
- if (lowerContent.includes('esc to interrupt')) {
20
+ if (lowerContent.includes('esc to interrupt') ||
21
+ lowerContent.includes('ctrl+c to interrupt')) {
21
22
  return 'busy';
22
23
  }
23
24
  // Otherwise idle
@@ -30,6 +30,17 @@ describe('ClaudeStateDetector', () => {
30
30
  // Assert
31
31
  expect(state).toBe('busy');
32
32
  });
33
+ it('should detect busy when "ctrl+c to interrupt" is present (web search)', () => {
34
+ // Arrange
35
+ terminal = createMockTerminal([
36
+ 'Googling. (ctrl+c to interrupt',
37
+ 'Searching for relevant information...',
38
+ ]);
39
+ // Act
40
+ const state = detector.detectState(terminal, 'idle');
41
+ // Assert
42
+ expect(state).toBe('busy');
43
+ });
33
44
  it('should detect idle when no specific patterns are found', () => {
34
45
  // Arrange
35
46
  terminal = createMockTerminal([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "3.2.8",
3
+ "version": "3.2.10",
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": "3.2.8",
45
- "@kodaikabasawa/ccmanager-darwin-x64": "3.2.8",
46
- "@kodaikabasawa/ccmanager-linux-arm64": "3.2.8",
47
- "@kodaikabasawa/ccmanager-linux-x64": "3.2.8",
48
- "@kodaikabasawa/ccmanager-win32-x64": "3.2.8"
44
+ "@kodaikabasawa/ccmanager-darwin-arm64": "3.2.10",
45
+ "@kodaikabasawa/ccmanager-darwin-x64": "3.2.10",
46
+ "@kodaikabasawa/ccmanager-linux-arm64": "3.2.10",
47
+ "@kodaikabasawa/ccmanager-linux-x64": "3.2.10",
48
+ "@kodaikabasawa/ccmanager-win32-x64": "3.2.10"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@eslint/js": "^9.28.0",