commandmate 0.2.9 → 0.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.
Files changed (49) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +3 -3
  3. package/.next/app-path-routes-manifest.json +1 -1
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/cache/config.json +3 -3
  7. package/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/.next/cache/webpack/client-production/2.pack +0 -0
  10. package/.next/cache/webpack/client-production/index.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  12. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  13. package/.next/cache/webpack/server-production/0.pack +0 -0
  14. package/.next/cache/webpack/server-production/index.pack +0 -0
  15. package/.next/next-minimal-server.js.nft.json +1 -1
  16. package/.next/next-server.js.nft.json +1 -1
  17. package/.next/prerender-manifest.json +1 -1
  18. package/.next/required-server-files.json +1 -1
  19. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/app/update-check/route.js +1 -1
  21. package/.next/server/app/api/repositories/route.js +10 -10
  22. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  23. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  24. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  25. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  26. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  27. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  28. package/.next/server/app/page_client-reference-manifest.js +1 -1
  29. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  30. package/.next/server/app/worktrees/[id]/page.js +3 -3
  31. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  32. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  33. package/.next/server/app-paths-manifest.json +7 -7
  34. package/.next/server/chunks/667.js +1 -0
  35. package/.next/server/chunks/7536.js +1 -1
  36. package/.next/server/chunks/9238.js +5 -5
  37. package/.next/server/functions-config-manifest.json +1 -1
  38. package/.next/server/pages/500.html +1 -1
  39. package/.next/server/server-reference-manifest.json +1 -1
  40. package/.next/static/chunks/{5970-9e999084275f2995.js → 5970-dc8fb1c8c0217636.js} +1 -1
  41. package/.next/static/chunks/app/worktrees/[id]/{page-5abc1e9b59430db1.js → page-1b8e4c49fbaf3f99.js} +1 -1
  42. package/.next/trace +5 -5
  43. package/README.md +232 -46
  44. package/dist/server/src/lib/auto-yes-manager.js +10 -59
  45. package/dist/server/src/lib/prompt-answer-sender.js +89 -0
  46. package/dist/server/src/lib/prompt-detector.js +9 -0
  47. package/package.json +1 -1
  48. /package/.next/static/{5sR3jeFe8ymnzcEan6Rdt → NGcx1ej6oVBba0MO0bwCg}/_buildManifest.js +0 -0
  49. /package/.next/static/{5sR3jeFe8ymnzcEan6Rdt → NGcx1ej6oVBba0MO0bwCg}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -1,26 +1,156 @@
1
1
  # CommandMate
2
2
 
3
+ ![npm version](https://img.shields.io/npm/v/commandmate)
4
+ ![npm downloads](https://img.shields.io/npm/dm/commandmate)
5
+ ![license](https://img.shields.io/github/license/Kewton/CommandMate)
6
+ ![CI](https://img.shields.io/github/actions/workflow/status/Kewton/CommandMate/ci-pr.yml)
7
+ **Status: Beta**
8
+
3
9
  [English](./README.md) | [日本語](./docs/ja/README.md)
4
10
 
5
- > "Never miss a prompt your development companion."
6
- > "Lightweight. Self-contained. Run Claude Code from anywhere."
11
+ <!-- TODO: Add a 30-second demo GIF here to boost adoption -->
12
+ <!-- Example: ![CommandMate Demo](./docs/assets/demo.gif) -->
13
+
14
+ > **Your AI coding companion — never miss a prompt, work from anywhere.**
15
+
16
+ - **Detect prompt/confirmation state** in real-time
17
+ - **Send instructions from mobile or desktop** — no need to sit at your PC
18
+ - **Manage sessions per Git worktree** — run parallel tasks with ease
19
+
20
+ ```bash
21
+ npm install -g commandmate
22
+ ```
7
23
 
8
24
  ![Desktop view](./docs/images/screenshot-desktop.png)
9
25
 
26
+ ## Table of Contents
27
+
28
+ - [What is this?](#what-is-this)
29
+ - [Who is this for?](#who-is-this-for)
30
+ - [What makes it unique?](#what-makes-it-unique)
31
+ - [Quick Start](#quick-start-3-steps)
32
+ - [Troubleshooting](#troubleshooting)
33
+ - [How it works](#how-it-works)
34
+ - [Key Features](#key-features)
35
+ - [Use Cases](#use-cases)
36
+ - [Security](#security)
37
+ - [CLI Commands](#cli-commands)
38
+ - [Developer Setup](#developer-setup)
39
+ - [FAQ](#faq)
40
+ - [Documentation](#documentation)
41
+ - [Contributing](#contributing)
42
+
43
+ ---
44
+
10
45
  ## What is this?
11
46
 
12
47
  A development companion tool that manages Claude Code sessions per Git worktree and lets you send instructions from your browser.
13
48
 
14
49
  During your commute, childcare breaks, or lunch — send the next instruction as easily as replying to an email, and keep your side projects moving forward.
15
50
 
16
- ## What it is NOT
51
+ ## Who is this for?
52
+
53
+ **Great fit:**
54
+ - Developers juggling childcare, commutes, or meetings — can't sit at the PC all day
55
+ - Users who miss Claude Code's input prompts and lose flow
56
+ - Teams using Git worktree for parallel development but finding tmux management tedious
57
+
58
+ **Not ideal for:**
59
+ - GUI IDE-only workflows (CommandMate is terminal/CLI-based)
60
+ - Multi-user SaaS expectations (CommandMate is designed for local, individual use)
61
+
62
+ ## What makes it unique?
63
+
64
+ CommandMate is not a terminal replacement. It **complements** Claude Code by focusing on three things:
65
+
66
+ - **Prompt detection** — know instantly when Claude Code needs your input
67
+ - **Response UI** — reply from any browser, including your phone
68
+ - **Worktree organization** — manage multiple sessions in one place
69
+
70
+ Supports **Claude Code**, **Codex CLI**, and **Gemini CLI**. Built with the Strategy pattern for extensibility — adding new CLI tools is straightforward.
71
+
72
+ ---
73
+
74
+ ## Quick Start (3 Steps)
75
+
76
+ **Prerequisites:** macOS / Linux, Node.js v20+, npm, git, tmux, openssl
77
+
78
+ > Windows is not supported due to the tmux dependency. WSL2 has not been tested.
79
+
80
+ ```bash
81
+ # 1. Install
82
+ npm install -g commandmate
83
+
84
+ # 2. Initialize (dependency check, environment setup, DB init)
85
+ commandmate init
86
+
87
+ # 3. Start
88
+ commandmate start --daemon
89
+ ```
90
+
91
+ Open http://localhost:3000 in your browser.
92
+
93
+ **Useful commands:**
94
+
95
+ ```bash
96
+ commandmate status # Check server status
97
+ commandmate stop # Stop the server
98
+ ```
99
+
100
+ See the [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) for details.
101
+
102
+ ---
103
+
104
+ ## Troubleshooting
105
+
106
+ **Claude CLI not found / path changed?**
107
+ If you switch between npm and standalone versions of Claude CLI, the path may change. CommandMate auto-detects the new path on the next session start. To set a custom path, add `CLAUDE_PATH=/path/to/claude` to `.env`.
108
+
109
+ **Port conflict?**
110
+ ```bash
111
+ commandmate start -p 3001
112
+ ```
113
+
114
+ **Session stuck or not responding?**
115
+ Check tmux sessions directly. CommandMate manages sessions with the naming format `mcbd-{tool}-{worktree}`:
116
+
117
+ ```bash
118
+ # List all CommandMate sessions
119
+ tmux list-sessions | grep mcbd
120
+
121
+ # View session output (without attaching)
122
+ tmux capture-pane -t "mcbd-claude-feature-123" -p
123
+
124
+ # Attach to inspect (detach with Ctrl+b then d)
125
+ tmux attach -t "mcbd-claude-feature-123"
17
126
 
18
- - It is not a terminal replacement. It **complements** Claude Code
19
- - It does not replicate all CLI features — it specializes in "never missing a prompt/confirmation and responding immediately"
127
+ # Kill a broken session
128
+ tmux kill-session -t "mcbd-claude-feature-123"
129
+ ```
130
+
131
+ > **Note:** When attached, avoid typing directly into the session — this can interfere with CommandMate's session management. Use `Ctrl+b` then `d` to detach and operate through the CommandMate UI instead.
132
+
133
+ **Sessions fail when launching from within Claude Code?**
134
+ Claude Code sets `CLAUDECODE=1` to prevent nesting. CommandMate removes this automatically, but if it persists, run: `tmux set-environment -g -u CLAUDECODE`
20
135
 
21
- ## Target Users
136
+ ---
22
137
 
23
- Developers with Claude Code experience who want to continue personal projects alongside their day job.
138
+ ## How it works
139
+
140
+ CommandMate treats Claude Code (CLI) as a managed "execution session", making its state (running / waiting for input / idle) visible through a web UI.
141
+
142
+ ```mermaid
143
+ flowchart LR
144
+ A["Browser / Phone"] -->|HTTP| B["CommandMate Server"]
145
+ B --> C["Session Manager"]
146
+ C -->|"spawn / attach"| D["tmux sessions<br/>(per worktree)"]
147
+ D --> E["Claude Code CLI"]
148
+ C <-->|"read / write"| F[("Local DB<br/>& State")]
149
+ ```
150
+
151
+ Each Git worktree gets its own tmux session, so you can run multiple tasks in parallel without interference.
152
+
153
+ ---
24
154
 
25
155
  ## Key Features
26
156
 
@@ -31,11 +161,14 @@ Developers with Claude Code experience who want to continue personal projects al
31
161
  - **File viewer** — Browse worktree files from the browser with file operations (move, copy, delete)
32
162
  - **File timestamps** — Display file creation time in the file tree
33
163
  - **Auto Yes mode** — Control automatic approval with a confirmation dialog
34
- - **Repository removal** — Remove repositories from app management (actual files are not deleted)
164
+ - **Repository management** — Remove repositories from app management (actual files are not deleted)
35
165
  - **Clone URL registration** — Clone and register repositories by specifying HTTPS/SSH URLs
36
- - **Claude Code optimized** — Optimized for Claude Code session management
166
+ - **Multi-CLI support** — Optimized for Claude Code, with Codex CLI and Gemini CLI support
37
167
  - **Responsive UI** — Two-column layout on desktop, tab-based layout on mobile
38
168
 
169
+ <details>
170
+ <summary>Screenshots</summary>
171
+
39
172
  ### Worktree Detail View (Message / Console / History)
40
173
 
41
174
  | Desktop | Mobile (History) | Mobile (Terminal) |
@@ -46,45 +179,106 @@ Developers with Claude Code experience who want to continue personal projects al
46
179
 
47
180
  ![Mobile view](./docs/images/screenshot-mobile.png)
48
181
 
49
- ## Quick Start
182
+ </details>
50
183
 
51
- ### Prerequisites
184
+ ---
52
185
 
53
- - macOS / Linux (Windows not supported due to tmux dependency)
54
- - Node.js v20+, npm, git, tmux, openssl
55
- - Claude CLI (optional)
186
+ ## Use Cases
56
187
 
57
- ### Installation
188
+ ### 1. Commute — pick up where you left off
58
189
 
59
- ```bash
60
- npm install -g commandmate
61
- ```
190
+ - **Morning:** Kick off a task with Claude Code before leaving
191
+ - **Commute:** Check status on your phone, send the next instruction
192
+ - **Evening:** Review the results and merge when you get home
62
193
 
63
- ### Setup and Launch
194
+ ### 2. Childcare — 5-minute windows add up
64
195
 
65
- ```bash
66
- commandmate init # Dependency check, environment setup, DB initialization
67
- commandmate start --daemon # Start in background
68
- ```
196
+ - Split tasks across worktrees so each runs independently
197
+ - Check which sessions are waiting via CommandMate
198
+ - In a 5-minute break, send the next instruction and keep things moving
69
199
 
70
- Open http://localhost:3000 in your browser.
200
+ ### 3. Parallel development — one UI for all your worktrees
201
+
202
+ - No need to juggle tmux panes manually
203
+ - See status of all worktrees at a glance in the sidebar
204
+ - Focus on decisions, not terminal management
205
+
206
+ ---
207
+
208
+ ## Security
209
+
210
+ CommandMate runs **entirely locally** — the app, database, and sessions all stay on your machine. The only external communication is Claude CLI's own API calls.
211
+
212
+ **Recommended setup:**
213
+ - Use on `localhost` or within the same LAN
214
+ - For remote access, use a VPN or authenticated reverse proxy (Basic Auth, OIDC, etc.)
215
+ - Enabling external access via `commandmate init` sets `CM_BIND=0.0.0.0` — access from the same LAN at `http://<your-PC-IP>:3000`
216
+
217
+ **Do NOT:**
218
+ - Expose to the internet without authentication (never bind `0.0.0.0` without a reverse proxy)
219
+
220
+ See the [Security Guide](./docs/security-guide.md) and [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) for details.
71
221
 
72
- ### CLI Commands
222
+ ---
223
+
224
+ ## CLI Commands
225
+
226
+ ### Basic
73
227
 
74
228
  | Command | Description |
75
229
  |---------|-------------|
76
230
  | `commandmate init` | Initial setup (interactive) |
77
231
  | `commandmate init --defaults` | Initial setup (default values) |
232
+ | `commandmate init --force` | Overwrite existing configuration |
233
+ | `commandmate start` | Start the server (foreground) |
78
234
  | `commandmate start --daemon` | Start in background |
235
+ | `commandmate start --dev` | Start in development mode |
79
236
  | `commandmate start -p 3001` | Start on a specific port |
80
237
  | `commandmate stop` | Stop the server |
238
+ | `commandmate stop --force` | Force stop (SIGKILL) |
81
239
  | `commandmate status` | Check status |
82
240
 
83
- See the [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) for details.
241
+ ### Worktree Parallel Development
84
242
 
85
- ### Mobile Access
243
+ Run separate servers per Issue/worktree with automatic port allocation.
244
+
245
+ | Command | Description |
246
+ |---------|-------------|
247
+ | `commandmate start --issue 123` | Start server for Issue #123 worktree |
248
+ | `commandmate start --issue 123 --auto-port` | Start with automatic port allocation |
249
+ | `commandmate start --issue 123 -p 3123` | Start on a specific port |
250
+ | `commandmate stop --issue 123` | Stop server for Issue #123 |
251
+ | `commandmate status --issue 123` | Check status for Issue #123 |
252
+ | `commandmate status --all` | Check status for all servers |
86
253
 
87
- Enabling external access via `commandmate init` sets `CM_BIND=0.0.0.0`. Access from the same LAN at `http://<your PC's IP>:3000`. For external access, we recommend authentication via a reverse proxy. See the [Security Guide](./docs/en/security-guide.md) for details.
254
+ ### GitHub Issue Management
255
+
256
+ Requires [gh CLI](https://cli.github.com/) to be installed.
257
+
258
+ | Command | Description |
259
+ |---------|-------------|
260
+ | `commandmate issue create` | Create a new issue |
261
+ | `commandmate issue create --bug` | Create with bug report template |
262
+ | `commandmate issue create --feature` | Create with feature request template |
263
+ | `commandmate issue create --question` | Create with question template |
264
+ | `commandmate issue create --title <title>` | Specify issue title |
265
+ | `commandmate issue create --body <body>` | Specify issue body |
266
+ | `commandmate issue create --labels <labels>` | Add labels (comma-separated) |
267
+ | `commandmate issue search <query>` | Search issues |
268
+ | `commandmate issue list` | List issues |
269
+
270
+ ### Documentation
271
+
272
+ | Command | Description |
273
+ |---------|-------------|
274
+ | `commandmate docs` | Show documentation |
275
+ | `commandmate docs -s <section>` | Show a specific section |
276
+ | `commandmate docs -q <query>` | Search documentation |
277
+ | `commandmate docs --all` | List all available sections |
278
+
279
+ See `commandmate --help` for all options.
280
+
281
+ ---
88
282
 
89
283
  ## Developer Setup
90
284
 
@@ -96,7 +290,8 @@ cd CommandMate
96
290
  ./scripts/setup.sh # Auto-runs dependency check, env setup, build, and launch
97
291
  ```
98
292
 
99
- ### Manual Setup (for customization)
293
+ <details>
294
+ <summary>Manual Setup (for customization)</summary>
100
295
 
101
296
  ```bash
102
297
  git clone https://github.com/Kewton/CommandMate.git
@@ -113,31 +308,22 @@ npm start
113
308
 
114
309
  > **Note**: Legacy environment variable names (`MCBD_*`) are still supported for backward compatibility, but using the new names (`CM_*`) is recommended.
115
310
 
116
- ## FAQ
117
-
118
- **Q: Does everything run locally?**
119
- A: The app, database, and sessions all run entirely locally. The only external communication is the Claude CLI's own API calls.
311
+ </details>
120
312
 
121
- **Q: How do I access it from my phone outside the house?**
122
- A: You can use tunneling services like Cloudflare Tunnel. Within your home, simply connect your phone to the same Wi-Fi as your PC.
313
+ ---
123
314
 
124
- **Q: What about Claude Code's permissions?**
125
- A: Claude Code's own permission settings apply as-is. This tool does not expand permissions. See [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) for details.
315
+ ## FAQ
126
316
 
127
- **Q: Does it work on Windows?**
128
- A: Not currently supported. macOS / Linux is required due to the tmux dependency. WSL2 has not been tested.
317
+ **Q: Is tmux required?**
318
+ A: CommandMate uses tmux internally to manage CLI sessions. You don't need to operate tmux directly — CommandMate handles it for you. If something goes wrong, you can inspect sessions via tmux commands (see [Troubleshooting](#troubleshooting)).
129
319
 
130
- **Q: Does it support CLI tools other than Claude Code?**
131
- A: It supports Claude Code and Codex CLI. Thanks to the extensible Strategy pattern design, additional tools can be added in the future.
320
+ **Q: What about Claude Code's permissions?**
321
+ A: Claude Code's own permission settings apply as-is. CommandMate does not expand permissions. See [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) for details.
132
322
 
133
323
  **Q: Can multiple people use it?**
134
324
  A: Currently designed for individual use. Simultaneous multi-user access is not supported.
135
325
 
136
- **Q: Session start fails after updating Claude CLI. What should I do?**
137
- A: If you switch between npm and standalone versions of Claude CLI, the path may change. CommandMate will automatically detect the new path on the next session start attempt. If you want to specify a custom path, set the `CLAUDE_PATH` environment variable in `.env` (e.g., `CLAUDE_PATH=/opt/homebrew/bin/claude`).
138
-
139
- **Q: Sessions fail to start when launching CommandMate from within Claude Code. Why?**
140
- A: Claude Code sets the `CLAUDECODE=1` environment variable to prevent nested sessions. CommandMate automatically removes this variable from tmux sessions, so sessions should start normally. If the issue persists, manually run `tmux set-environment -g -u CLAUDECODE` to clear it from tmux's global environment.
326
+ ---
141
327
 
142
328
  ## Documentation
143
329
 
@@ -25,7 +25,7 @@ exports.stopAllAutoYesPolling = stopAllAutoYesPolling;
25
25
  const cli_session_1 = require("./cli-session");
26
26
  const prompt_detector_1 = require("./prompt-detector");
27
27
  const auto_yes_resolver_1 = require("./auto-yes-resolver");
28
- const tmux_1 = require("./tmux");
28
+ const prompt_answer_sender_1 = require("./prompt-answer-sender");
29
29
  const manager_1 = require("./cli-tools/manager");
30
30
  const cli_patterns_1 = require("./cli-patterns");
31
31
  const auto_yes_config_1 = require("../config/auto-yes-config");
@@ -261,64 +261,15 @@ async function pollAutoYes(worktreeId, cliToolId) {
261
261
  const manager = manager_1.CLIToolManager.getInstance();
262
262
  const cliTool = manager.getTool(cliToolId);
263
263
  const sessionName = cliTool.getSessionName(worktreeId);
264
- // Issue #193: Claude Code AskUserQuestion uses cursor-based navigation
265
- // (Arrow/Space/Enter), not number input. Detect multi-choice and send
266
- // appropriate key sequence instead of typing the number.
267
- const isClaudeMultiChoice = cliToolId === 'claude'
268
- && promptDetection.promptData?.type === 'multiple_choice'
269
- && /^\d+$/.test(answer);
270
- if (isClaudeMultiChoice && promptDetection.promptData?.type === 'multiple_choice') {
271
- const targetNum = parseInt(answer, 10);
272
- const mcOptions = promptDetection.promptData.options;
273
- const defaultOption = mcOptions.find(o => o.isDefault);
274
- const defaultNum = defaultOption?.number ?? 1;
275
- const offset = targetNum - defaultNum;
276
- // Detect multi-select (checkbox) prompts by checking for [ ] in option labels.
277
- const isMultiSelect = mcOptions.some(o => /^\[[ x]\] /.test(o.label));
278
- if (isMultiSelect) {
279
- // Multi-select: toggle checkbox, then navigate to "Next" and submit
280
- const checkboxCount = mcOptions.filter(o => /^\[[ x]\] /.test(o.label)).length;
281
- const keys = [];
282
- // 1. Navigate to target option
283
- if (offset > 0) {
284
- for (let i = 0; i < offset; i++)
285
- keys.push('Down');
286
- }
287
- else if (offset < 0) {
288
- for (let i = 0; i < Math.abs(offset); i++)
289
- keys.push('Up');
290
- }
291
- // 2. Space to toggle checkbox
292
- keys.push('Space');
293
- // 3. Navigate to "Next" button (positioned right after all checkbox options)
294
- const downToNext = checkboxCount - targetNum + 1;
295
- for (let i = 0; i < downToNext; i++)
296
- keys.push('Down');
297
- // 4. Enter to submit
298
- keys.push('Enter');
299
- await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
300
- }
301
- else {
302
- // Single-select: navigate and Enter to select
303
- const keys = [];
304
- if (offset > 0) {
305
- for (let i = 0; i < offset; i++)
306
- keys.push('Down');
307
- }
308
- else if (offset < 0) {
309
- for (let i = 0; i < Math.abs(offset); i++)
310
- keys.push('Up');
311
- }
312
- keys.push('Enter');
313
- await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
314
- }
315
- }
316
- else {
317
- // Standard CLI prompt: send text + Enter (y/n, Approve?, etc.)
318
- await (0, tmux_1.sendKeys)(sessionName, answer, false);
319
- await new Promise(resolve => setTimeout(resolve, 100));
320
- await (0, tmux_1.sendKeys)(sessionName, '', true);
321
- }
264
+ // Issue #287 Bug2: Uses shared sendPromptAnswer() to unify logic
265
+ // with route.ts, including cursor-key navigation for Claude Code
266
+ // multiple-choice prompts and fallback handling.
267
+ await (0, prompt_answer_sender_1.sendPromptAnswer)({
268
+ sessionName,
269
+ answer,
270
+ cliToolId,
271
+ promptData: promptDetection.promptData,
272
+ });
322
273
  // 6. Update timestamp
323
274
  updateLastServerResponseTimestamp(worktreeId, Date.now());
324
275
  // 7. Reset error count on success
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /**
3
+ * Shared prompt answer sender for cursor-key and text-based tmux input.
4
+ *
5
+ * Issue #287 Bug2: Extracted from route.ts and auto-yes-manager.ts to
6
+ * eliminate code duplication and ensure consistent behavior (including
7
+ * the promptType/defaultOptionNumber fallback introduced in Bug1).
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.sendPromptAnswer = sendPromptAnswer;
11
+ const tmux_1 = require("./tmux");
12
+ /** Regex pattern to detect checkbox-style multi-select options */
13
+ const CHECKBOX_OPTION_PATTERN = /^\[[ x]\] /;
14
+ /**
15
+ * Build navigation key array for cursor movement.
16
+ * @param offset - positive = Down, negative = Up
17
+ */
18
+ function buildNavigationKeys(offset) {
19
+ if (offset === 0)
20
+ return [];
21
+ const direction = offset > 0 ? 'Down' : 'Up';
22
+ return Array.from({ length: Math.abs(offset) }, () => direction);
23
+ }
24
+ /**
25
+ * Send an answer to a tmux session, using cursor-key navigation for
26
+ * Claude Code multiple-choice prompts and text input for everything else.
27
+ *
28
+ * This function unifies the logic previously duplicated in:
29
+ * - src/app/api/worktrees/[id]/prompt-response/route.ts (L114-187)
30
+ * - src/lib/auto-yes-manager.ts (L340-399)
31
+ */
32
+ async function sendPromptAnswer(params) {
33
+ const { sessionName, answer, cliToolId, promptData, fallbackPromptType, fallbackDefaultOptionNumber } = params;
34
+ // Determine if this is a Claude Code multiple-choice prompt requiring cursor navigation
35
+ const isClaudeMultiChoice = cliToolId === 'claude'
36
+ && (promptData?.type === 'multiple_choice' || fallbackPromptType === 'multiple_choice')
37
+ && /^\d+$/.test(answer);
38
+ if (isClaudeMultiChoice) {
39
+ const targetNum = parseInt(answer, 10);
40
+ let defaultNum;
41
+ let mcOptions = null;
42
+ if (promptData?.type === 'multiple_choice') {
43
+ // Primary path: use fresh promptData
44
+ mcOptions = promptData.options;
45
+ const defaultOption = mcOptions.find(o => o.isDefault);
46
+ defaultNum = defaultOption?.number ?? 1;
47
+ }
48
+ else {
49
+ // Fallback path (Issue #287): promptData is undefined or type mismatch, use fallback fields
50
+ defaultNum = fallbackDefaultOptionNumber ?? 1;
51
+ }
52
+ const offset = targetNum - defaultNum;
53
+ // Detect multi-select (checkbox) prompts by checking for [ ] in option labels.
54
+ // Multi-select prompts require: Space to toggle checkbox -> navigate to "Next" -> Enter.
55
+ // Single-select prompts require: navigate to option -> Enter.
56
+ // Note: multi-select detection is only possible when promptData succeeded (mcOptions available).
57
+ const isMultiSelect = mcOptions !== null && mcOptions.some(o => CHECKBOX_OPTION_PATTERN.test(o.label));
58
+ if (isMultiSelect && mcOptions !== null) {
59
+ // Multi-select: toggle checkbox, then navigate to "Next" and submit
60
+ const checkboxCount = mcOptions.filter(o => CHECKBOX_OPTION_PATTERN.test(o.label)).length;
61
+ const keys = [
62
+ ...buildNavigationKeys(offset), // 1. Navigate to target option
63
+ 'Space', // 2. Toggle checkbox
64
+ ];
65
+ // 3. Navigate to "Next" button (positioned right after all checkbox options)
66
+ const downToNext = checkboxCount - targetNum + 1;
67
+ keys.push(...buildNavigationKeys(downToNext));
68
+ // 4. Enter to submit
69
+ keys.push('Enter');
70
+ await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
71
+ }
72
+ else {
73
+ // Single-select: navigate and Enter to select
74
+ const keys = [
75
+ ...buildNavigationKeys(offset),
76
+ 'Enter',
77
+ ];
78
+ await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
79
+ }
80
+ }
81
+ else {
82
+ // Standard CLI prompt: send text + Enter (y/n, Approve?, etc.)
83
+ await (0, tmux_1.sendKeys)(sessionName, answer, false);
84
+ // Wait a moment for the input to be processed
85
+ await new Promise(resolve => setTimeout(resolve, 100));
86
+ // Send Enter
87
+ await (0, tmux_1.sendKeys)(sessionName, '', true);
88
+ }
89
+ }
@@ -561,6 +561,15 @@ function detectMultipleChoicePrompt(output, options) {
561
561
  collectedOptions.unshift({ number, label, isDefault: false });
562
562
  continue;
563
563
  }
564
+ // [Issue #287 Bug3] User input prompt barrier:
565
+ // When no options have been collected yet and the line starts with ❯ (U+276F)
566
+ // but did NOT match DEFAULT_OPTION_PATTERN above, this line is a Claude Code
567
+ // user input prompt (e.g., "❯ 1", "❯ /command") or idle prompt ("❯").
568
+ // Anything above this line in the scrollback is historical conversation text,
569
+ // not an active prompt. Stop scanning to prevent false positives.
570
+ if (collectedOptions.length === 0 && line.startsWith('\u276F')) {
571
+ return noPromptResult(output);
572
+ }
564
573
  // Non-option line handling
565
574
  if (collectedOptions.length > 0 && line && !SEPARATOR_LINE_PATTERN.test(line)) {
566
575
  // [MF-001 / Issue #256] Check if line is a question-like line BEFORE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Git worktree management with Claude CLI and tmux sessions",
5
5
  "repository": {
6
6
  "type": "git",