ccmanager 1.4.3 → 1.4.5

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.
@@ -193,33 +193,6 @@ const App = ({ devcontainerConfig }) => {
193
193
  const handleCancelDeleteWorktree = () => {
194
194
  handleReturnToMenu();
195
195
  };
196
- const handleMergeWorktree = async (sourceBranch, targetBranch, deleteAfterMerge, useRebase) => {
197
- setView('merging-worktree');
198
- setError(null);
199
- // Perform the merge
200
- const mergeResult = worktreeService.mergeWorktree(sourceBranch, targetBranch, useRebase);
201
- if (mergeResult.success) {
202
- // If user wants to delete the merged branch
203
- if (deleteAfterMerge) {
204
- const deleteResult = worktreeService.deleteWorktreeByBranch(sourceBranch);
205
- if (!deleteResult.success) {
206
- setError(deleteResult.error || 'Failed to delete merged worktree');
207
- setView('merge-worktree');
208
- return;
209
- }
210
- }
211
- // Success - return to menu
212
- handleReturnToMenu();
213
- }
214
- else {
215
- // Show error
216
- setError(mergeResult.error || 'Failed to merge branches');
217
- setView('merge-worktree');
218
- }
219
- };
220
- const handleCancelMergeWorktree = () => {
221
- handleReturnToMenu();
222
- };
223
196
  if (view === 'menu') {
224
197
  return (React.createElement(Menu, { key: menuKey, sessionManager: sessionManager, onSelectWorktree: handleSelectWorktree, error: error, onDismissError: () => setError(null) }));
225
198
  }
@@ -262,11 +235,7 @@ const App = ({ devcontainerConfig }) => {
262
235
  React.createElement(Text, { color: "red" },
263
236
  "Error: ",
264
237
  error))),
265
- React.createElement(MergeWorktree, { onComplete: handleMergeWorktree, onCancel: handleCancelMergeWorktree })));
266
- }
267
- if (view === 'merging-worktree') {
268
- return (React.createElement(Box, { flexDirection: "column" },
269
- React.createElement(Text, { color: "green" }, "Merging worktrees...")));
238
+ React.createElement(MergeWorktree, { onComplete: handleReturnToMenu, onCancel: handleReturnToMenu })));
270
239
  }
271
240
  if (view === 'configuration') {
272
241
  return React.createElement(Configuration, { onComplete: handleReturnToMenu });
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  interface MergeWorktreeProps {
3
- onComplete: (sourceBranch: string, targetBranch: string, deleteAfterMerge: boolean, useRebase: boolean) => void;
3
+ onComplete: () => void;
4
4
  onCancel: () => void;
5
5
  }
6
6
  declare const MergeWorktree: React.FC<MergeWorktreeProps>;
@@ -9,10 +9,12 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
9
9
  const [sourceBranch, setSourceBranch] = useState('');
10
10
  const [targetBranch, setTargetBranch] = useState('');
11
11
  const [branchItems, setBranchItems] = useState([]);
12
+ const [originalBranchItems, setOriginalBranchItems] = useState([]);
12
13
  const [useRebase, setUseRebase] = useState(false);
13
14
  const [operationFocused, setOperationFocused] = useState(false);
15
+ const [mergeError, setMergeError] = useState(null);
16
+ const [worktreeService] = useState(() => new WorktreeService());
14
17
  useEffect(() => {
15
- const worktreeService = new WorktreeService();
16
18
  const loadedWorktrees = worktreeService.getWorktrees();
17
19
  // Create branch items for selection
18
20
  const items = loadedWorktrees.map(wt => ({
@@ -21,7 +23,8 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
21
23
  value: wt.branch ? wt.branch.replace('refs/heads/', '') : 'detached',
22
24
  }));
23
25
  setBranchItems(items);
24
- }, []);
26
+ setOriginalBranchItems(items);
27
+ }, [worktreeService]);
25
28
  useInput((input, key) => {
26
29
  if (shortcutManager.matchesShortcut('cancel', input, key)) {
27
30
  onCancel();
@@ -37,11 +40,15 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
37
40
  setStep('confirm-merge');
38
41
  }
39
42
  }
43
+ if (step === 'merge-error') {
44
+ // Any key press returns to menu
45
+ onCancel();
46
+ }
40
47
  });
41
48
  const handleSelectSource = (item) => {
42
49
  setSourceBranch(item.value);
43
50
  // Filter out the selected source branch for target selection
44
- const filteredItems = branchItems.filter(b => b.value !== item.value);
51
+ const filteredItems = originalBranchItems.filter(b => b.value !== item.value);
45
52
  setBranchItems(filteredItems);
46
53
  setStep('select-target');
47
54
  };
@@ -49,6 +56,24 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
49
56
  setTargetBranch(item.value);
50
57
  setStep('select-operation');
51
58
  };
59
+ // Execute the merge operation when step changes to executing-merge
60
+ useEffect(() => {
61
+ if (step !== 'executing-merge')
62
+ return;
63
+ const performMerge = async () => {
64
+ const result = worktreeService.mergeWorktree(sourceBranch, targetBranch, useRebase);
65
+ if (result.success) {
66
+ // Merge successful, ask about deleting source branch
67
+ setStep('delete-confirm');
68
+ }
69
+ else {
70
+ // Merge failed, show error
71
+ setMergeError(result.error || 'Merge operation failed');
72
+ setStep('merge-error');
73
+ }
74
+ };
75
+ performMerge();
76
+ }, [step, sourceBranch, targetBranch, useRebase, worktreeService]);
52
77
  if (step === 'select-source') {
53
78
  return (React.createElement(Box, { flexDirection: "column" },
54
79
  React.createElement(Box, { marginBottom: 1 },
@@ -124,7 +149,24 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
124
149
  ' ',
125
150
  React.createElement(Text, { color: "yellow" }, targetBranch),
126
151
  "?")));
127
- return (React.createElement(Confirmation, { message: confirmMessage, onConfirm: () => setStep('delete-confirm'), onCancel: onCancel }));
152
+ return (React.createElement(Confirmation, { message: confirmMessage, onConfirm: () => setStep('executing-merge'), onCancel: onCancel }));
153
+ }
154
+ if (step === 'executing-merge') {
155
+ return (React.createElement(Box, { flexDirection: "column" },
156
+ React.createElement(Text, { color: "green" },
157
+ useRebase ? 'Rebasing' : 'Merging',
158
+ " branches...")));
159
+ }
160
+ if (step === 'merge-error') {
161
+ return (React.createElement(Box, { flexDirection: "column" },
162
+ React.createElement(Box, { marginBottom: 1 },
163
+ React.createElement(Text, { bold: true, color: "red" },
164
+ useRebase ? 'Rebase' : 'Merge',
165
+ " Failed")),
166
+ React.createElement(Box, { marginBottom: 1 },
167
+ React.createElement(Text, { color: "red" }, mergeError)),
168
+ React.createElement(Box, { marginTop: 1 },
169
+ React.createElement(Text, { dimColor: true }, "Press any key to return to menu"))));
128
170
  }
129
171
  if (step === 'delete-confirm') {
130
172
  const deleteMessage = (React.createElement(Box, { flexDirection: "column" },
@@ -135,7 +177,19 @@ const MergeWorktree = ({ onComplete, onCancel, }) => {
135
177
  React.createElement(Text, { color: "yellow" }, sourceBranch),
136
178
  ' ',
137
179
  "and its worktree?")));
138
- return (React.createElement(Confirmation, { message: deleteMessage, onConfirm: () => onComplete(sourceBranch, targetBranch, true, useRebase), onCancel: () => onComplete(sourceBranch, targetBranch, false, useRebase) }));
180
+ return (React.createElement(Confirmation, { message: deleteMessage, onConfirm: () => {
181
+ const deleteResult = worktreeService.deleteWorktreeByBranch(sourceBranch);
182
+ if (deleteResult.success) {
183
+ onComplete();
184
+ }
185
+ else {
186
+ setMergeError(deleteResult.error || 'Failed to delete worktree');
187
+ setStep('merge-error');
188
+ }
189
+ }, onCancel: () => {
190
+ // Skip deletion and complete
191
+ onComplete();
192
+ } }));
139
193
  }
140
194
  return null;
141
195
  };
@@ -73,20 +73,10 @@ const Session = ({ session, sessionManager, onReturnToMenu, }) => {
73
73
  const handleResize = () => {
74
74
  const cols = process.stdout.columns || 80;
75
75
  const rows = process.stdout.rows || 24;
76
- try {
77
- session.process.resize(cols, rows);
78
- // Also resize the virtual terminal
79
- if (session.terminal) {
80
- try {
81
- session.terminal.resize(cols, rows);
82
- }
83
- catch {
84
- // Suppress xterm.js parsing errors
85
- }
86
- }
87
- }
88
- catch {
89
- // Suppress PTY resize errors
76
+ session.process.resize(cols, rows);
77
+ // Also resize the virtual terminal
78
+ if (session.terminal) {
79
+ session.terminal.resize(cols, rows);
90
80
  }
91
81
  };
92
82
  stdout.on('resize', handleResize);
@@ -55,6 +55,7 @@ export class SessionManager extends EventEmitter {
55
55
  cols: process.stdout.columns || 80,
56
56
  rows: process.stdout.rows || 24,
57
57
  allowProposedApi: true,
58
+ logLevel: 'off',
58
59
  });
59
60
  }
60
61
  async createSessionInternal(worktreePath, ptyProcess, commandConfig, options = {}) {
@@ -109,13 +110,8 @@ export class SessionManager extends EventEmitter {
109
110
  setupDataHandler(session) {
110
111
  // This handler always runs for all data
111
112
  session.process.onData((data) => {
112
- // Write data to virtual terminal with error suppression
113
- try {
114
- session.terminal.write(data);
115
- }
116
- catch {
117
- // Suppress xterm.js parsing errors
118
- }
113
+ // Write data to virtual terminal
114
+ session.terminal.write(data);
119
115
  // Store in output history as Buffer
120
116
  const buffer = Buffer.from(data, 'utf8');
121
117
  session.outputHistory.push(buffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "TUI application for managing multiple Claude Code sessions across Git worktrees",
5
5
  "license": "MIT",
6
6
  "author": "Kodai Kabasawa",