ccmanager 0.1.14 → 0.1.15

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.
@@ -1,31 +1,32 @@
1
1
  import React, { useState } from 'react';
2
- import { Box, Text } from 'ink';
2
+ import { Box, Text, useInput } from 'ink';
3
3
  import SelectInput from 'ink-select-input';
4
4
  import ConfigureShortcuts from './ConfigureShortcuts.js';
5
5
  import ConfigureHooks from './ConfigureHooks.js';
6
6
  import ConfigureWorktree from './ConfigureWorktree.js';
7
7
  import ConfigureCommand from './ConfigureCommand.js';
8
+ import { shortcutManager } from '../services/shortcutManager.js';
8
9
  const Configuration = ({ onComplete }) => {
9
10
  const [view, setView] = useState('menu');
10
11
  const menuItems = [
11
12
  {
12
- label: '⌨ Configure Shortcuts',
13
+ label: 'S ⌨ Configure Shortcuts',
13
14
  value: 'shortcuts',
14
15
  },
15
16
  {
16
- label: '🔧 Configure Status Hooks',
17
+ label: 'H 🔧 Configure Status Hooks',
17
18
  value: 'hooks',
18
19
  },
19
20
  {
20
- label: '📁 Configure Worktree Settings',
21
+ label: 'W 📁 Configure Worktree Settings',
21
22
  value: 'worktree',
22
23
  },
23
24
  {
24
- label: '🚀 Configure Command',
25
+ label: 'C 🚀 Configure Command',
25
26
  value: 'command',
26
27
  },
27
28
  {
28
- label: '← Back to Main Menu',
29
+ label: 'B ← Back to Main Menu',
29
30
  value: 'back',
30
31
  },
31
32
  ];
@@ -49,6 +50,33 @@ const Configuration = ({ onComplete }) => {
49
50
  const handleSubMenuComplete = () => {
50
51
  setView('menu');
51
52
  };
53
+ // Handle hotkeys (only when in menu view)
54
+ useInput((input, key) => {
55
+ if (view !== 'menu')
56
+ return; // Only handle hotkeys in menu view
57
+ const keyPressed = input.toLowerCase();
58
+ switch (keyPressed) {
59
+ case 's':
60
+ setView('shortcuts');
61
+ break;
62
+ case 'h':
63
+ setView('hooks');
64
+ break;
65
+ case 'w':
66
+ setView('worktree');
67
+ break;
68
+ case 'c':
69
+ setView('command');
70
+ break;
71
+ case 'b':
72
+ onComplete();
73
+ break;
74
+ }
75
+ // Handle escape key
76
+ if (shortcutManager.matchesShortcut('cancel', input, key)) {
77
+ onComplete();
78
+ }
79
+ });
52
80
  if (view === 'shortcuts') {
53
81
  return React.createElement(ConfigureShortcuts, { onComplete: handleSubMenuComplete });
54
82
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import { Box, Text } from 'ink';
2
+ import { Box, Text, useInput } from 'ink';
3
3
  import SelectInput from 'ink-select-input';
4
4
  import { WorktreeService } from '../services/worktreeService.js';
5
5
  import { STATUS_ICONS, STATUS_LABELS, MENU_ICONS, getStatusDisplay, } from '../constants/statusIcons.js';
@@ -35,7 +35,7 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
35
35
  }, [sessionManager]);
36
36
  useEffect(() => {
37
37
  // Build menu items
38
- const menuItems = worktrees.map(wt => {
38
+ const menuItems = worktrees.map((wt, index) => {
39
39
  const session = sessions.find(s => s.worktreePath === wt.path);
40
40
  let status = '';
41
41
  if (session) {
@@ -45,8 +45,10 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
45
45
  ? wt.branch.replace('refs/heads/', '')
46
46
  : 'detached';
47
47
  const isMain = wt.isMainWorktree ? ' (main)' : '';
48
+ // Only show numbers for first 10 worktrees (0-9)
49
+ const numberPrefix = index < 10 ? `${index} ❯ ` : '❯ ';
48
50
  return {
49
- label: `${branchName}${isMain}${status}`,
51
+ label: `${numberPrefix}${branchName}${isMain}${status}`,
50
52
  value: wt.path,
51
53
  worktree: wt,
52
54
  };
@@ -57,27 +59,87 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
57
59
  value: 'separator',
58
60
  });
59
61
  menuItems.push({
60
- label: `${MENU_ICONS.NEW_WORKTREE} New Worktree`,
62
+ label: `N ${MENU_ICONS.NEW_WORKTREE} New Worktree`,
61
63
  value: 'new-worktree',
62
64
  });
63
65
  menuItems.push({
64
- label: `${MENU_ICONS.MERGE_WORKTREE} Merge Worktree`,
66
+ label: `M ${MENU_ICONS.MERGE_WORKTREE} Merge Worktree`,
65
67
  value: 'merge-worktree',
66
68
  });
67
69
  menuItems.push({
68
- label: `${MENU_ICONS.DELETE_WORKTREE} Delete Worktree`,
70
+ label: `D ${MENU_ICONS.DELETE_WORKTREE} Delete Worktree`,
69
71
  value: 'delete-worktree',
70
72
  });
71
73
  menuItems.push({
72
- label: `${MENU_ICONS.CONFIGURE_SHORTCUTS} Configuration`,
74
+ label: `C ${MENU_ICONS.CONFIGURE_SHORTCUTS} Configuration`,
73
75
  value: 'configuration',
74
76
  });
75
77
  menuItems.push({
76
- label: `${MENU_ICONS.EXIT} Exit`,
78
+ label: `Q ${MENU_ICONS.EXIT} Exit`,
77
79
  value: 'exit',
78
80
  });
79
81
  setItems(menuItems);
80
82
  }, [worktrees, sessions]);
83
+ // Handle hotkeys
84
+ useInput((input, _key) => {
85
+ const keyPressed = input.toLowerCase();
86
+ // Handle number keys 0-9 for worktree selection (first 10 only)
87
+ if (/^[0-9]$/.test(keyPressed)) {
88
+ const index = parseInt(keyPressed);
89
+ if (index < Math.min(10, worktrees.length) && worktrees[index]) {
90
+ onSelectWorktree(worktrees[index]);
91
+ }
92
+ return;
93
+ }
94
+ switch (keyPressed) {
95
+ case 'n':
96
+ // Trigger new worktree action
97
+ onSelectWorktree({
98
+ path: '',
99
+ branch: '',
100
+ isMainWorktree: false,
101
+ hasSession: false,
102
+ });
103
+ break;
104
+ case 'm':
105
+ // Trigger merge worktree action
106
+ onSelectWorktree({
107
+ path: 'MERGE_WORKTREE',
108
+ branch: '',
109
+ isMainWorktree: false,
110
+ hasSession: false,
111
+ });
112
+ break;
113
+ case 'd':
114
+ // Trigger delete worktree action
115
+ onSelectWorktree({
116
+ path: 'DELETE_WORKTREE',
117
+ branch: '',
118
+ isMainWorktree: false,
119
+ hasSession: false,
120
+ });
121
+ break;
122
+ case 'c':
123
+ // Trigger configuration action
124
+ onSelectWorktree({
125
+ path: 'CONFIGURATION',
126
+ branch: '',
127
+ isMainWorktree: false,
128
+ hasSession: false,
129
+ });
130
+ break;
131
+ case 'q':
132
+ case 'x':
133
+ // Trigger exit action
134
+ onSelectWorktree({
135
+ path: 'EXIT_APPLICATION',
136
+ branch: '',
137
+ isMainWorktree: false,
138
+ hasSession: false,
139
+ });
140
+ break;
141
+ }
142
+ });
81
143
  const handleSelect = (item) => {
82
144
  if (item.value === 'separator') {
83
145
  // Do nothing for separator
@@ -151,6 +213,6 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
151
213
  STATUS_ICONS.IDLE,
152
214
  ' ',
153
215
  STATUS_LABELS.IDLE),
154
- React.createElement(Text, { dimColor: true }, "Controls: \u2191\u2193 Navigate Enter Select"))));
216
+ React.createElement(Text, { dimColor: true }, "Controls: \u2191\u2193 Navigate Enter Select | Hotkeys: 0-9 Quick Select (first 10) N-New M-Merge D-Delete C-Config Q-Quit"))));
155
217
  };
156
218
  export default Menu;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "TUI application for managing multiple Claude Code sessions across Git worktrees",
5
5
  "license": "MIT",
6
6
  "author": "Kodai Kabasawa",