commandmate 0.2.10 → 0.2.11

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 (62) hide show
  1. package/.env.example +2 -1
  2. package/.next/BUILD_ID +1 -1
  3. package/.next/app-build-manifest.json +12 -12
  4. package/.next/app-path-routes-manifest.json +1 -1
  5. package/.next/build-manifest.json +2 -2
  6. package/.next/cache/.tsbuildinfo +1 -1
  7. package/.next/cache/config.json +3 -3
  8. package/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/.next/cache/webpack/client-production/1.pack +0 -0
  10. package/.next/cache/webpack/client-production/2.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack +0 -0
  12. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  13. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  14. package/.next/cache/webpack/server-production/0.pack +0 -0
  15. package/.next/cache/webpack/server-production/index.pack +0 -0
  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/routes-manifest.json +1 -1
  20. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/app/update-check/route.js +1 -1
  22. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  23. package/.next/server/app/api/repositories/clone/route.js +1 -1
  24. package/.next/server/app/api/repositories/route.js +2 -2
  25. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  26. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  27. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  28. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  29. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  30. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  31. package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
  32. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -1
  33. package/.next/server/app/page_client-reference-manifest.js +1 -1
  34. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  35. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/worktrees/[id]/page.js +3 -3
  37. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app-paths-manifest.json +7 -7
  40. package/.next/server/chunks/5488.js +4 -4
  41. package/.next/server/chunks/8693.js +1 -0
  42. package/.next/server/chunks/9238.js +14 -14
  43. package/.next/server/chunks/9367.js +2 -2
  44. package/.next/server/functions-config-manifest.json +1 -1
  45. package/.next/server/pages/500.html +1 -1
  46. package/.next/server/server-reference-manifest.json +1 -1
  47. package/.next/static/chunks/5970-2e18108d0cabd8af.js +1 -0
  48. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-4a3c0861367e0391.js +1 -0
  49. package/.next/static/chunks/app/worktrees/[id]/page-dc0dde49ed95076f.js +1 -0
  50. package/.next/static/css/7c6675f6f65b4990.css +3 -0
  51. package/.next/trace +5 -5
  52. package/dist/server/src/lib/auto-yes-manager.js +114 -25
  53. package/dist/server/src/lib/claude-session.js +60 -21
  54. package/dist/server/src/lib/prompt-key.js +30 -0
  55. package/package.json +12 -1
  56. package/.next/server/chunks/667.js +0 -1
  57. package/.next/static/chunks/5970-dc8fb1c8c0217636.js +0 -1
  58. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-ce9ac3658f2b7d91.js +0 -1
  59. package/.next/static/chunks/app/worktrees/[id]/page-1b8e4c49fbaf3f99.js +0 -1
  60. package/.next/static/css/a69d9c70fce558b4.css +0 -3
  61. /package/.next/static/{NGcx1ej6oVBba0MO0bwCg → ZTtC8-q8xrYUSilnXmMHl}/_buildManifest.js +0 -0
  62. /package/.next/static/{NGcx1ej6oVBba0MO0bwCg → ZTtC8-q8xrYUSilnXmMHl}/_ssgManifest.js +0 -0
@@ -9,7 +9,7 @@
9
9
  * auto-yes responses when browser tabs are in background.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.THINKING_CHECK_LINE_COUNT = exports.MAX_CONCURRENT_POLLERS = exports.MAX_CONSECUTIVE_ERRORS = exports.MAX_BACKOFF_MS = exports.POLLING_INTERVAL_MS = void 0;
12
+ exports.THINKING_CHECK_LINE_COUNT = exports.MAX_CONCURRENT_POLLERS = exports.MAX_CONSECUTIVE_ERRORS = exports.MAX_BACKOFF_MS = exports.COOLDOWN_INTERVAL_MS = exports.POLLING_INTERVAL_MS = void 0;
13
13
  exports.isValidWorktreeId = isValidWorktreeId;
14
14
  exports.calculateBackoffInterval = calculateBackoffInterval;
15
15
  exports.isAutoYesExpired = isAutoYesExpired;
@@ -29,11 +29,14 @@ 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");
32
+ const prompt_key_1 = require("./prompt-key");
32
33
  // =============================================================================
33
34
  // Constants (Issue #138)
34
35
  // =============================================================================
35
36
  /** Polling interval in milliseconds */
36
37
  exports.POLLING_INTERVAL_MS = 2000;
38
+ /** Cooldown interval after successful response (milliseconds) (Issue #306) */
39
+ exports.COOLDOWN_INTERVAL_MS = 5000;
37
40
  /** Maximum backoff interval in milliseconds (60 seconds) */
38
41
  exports.MAX_BACKOFF_MS = 60000;
39
42
  /** Number of consecutive errors before applying backoff */
@@ -52,6 +55,16 @@ exports.MAX_CONCURRENT_POLLERS = 50;
52
55
  exports.THINKING_CHECK_LINE_COUNT = 50;
53
56
  /** Worktree ID validation pattern (security: prevent command injection) */
54
57
  const WORKTREE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
58
+ /**
59
+ * Extract error message from unknown error type.
60
+ * Provides consistent error message extraction across the module (DRY).
61
+ *
62
+ * @param error - Unknown error object
63
+ * @returns Error message string, or 'Unknown error' for non-Error values
64
+ */
65
+ function getErrorMessage(error) {
66
+ return error instanceof Error ? error.message : 'Unknown error';
67
+ }
55
68
  /** In-memory storage for auto-yes states (globalThis for hot reload persistence) */
56
69
  const autoYesStates = globalThis.__autoYesStates ??
57
70
  (globalThis.__autoYesStates = new Map());
@@ -62,8 +75,11 @@ const autoYesPollerStates = globalThis.__autoYesPollerStates ??
62
75
  // Utility Functions
63
76
  // =============================================================================
64
77
  /**
65
- * Validate worktree ID format (security measure)
78
+ * Validate worktree ID format (security measure).
66
79
  * Only allows alphanumeric characters, hyphens, and underscores.
80
+ *
81
+ * @param worktreeId - Worktree ID to validate
82
+ * @returns true if the ID matches the allowed pattern
67
83
  */
68
84
  function isValidWorktreeId(worktreeId) {
69
85
  if (!worktreeId || worktreeId.length === 0)
@@ -71,7 +87,12 @@ function isValidWorktreeId(worktreeId) {
71
87
  return WORKTREE_ID_PATTERN.test(worktreeId);
72
88
  }
73
89
  /**
74
- * Calculate backoff interval based on consecutive errors
90
+ * Calculate backoff interval based on consecutive errors.
91
+ * Returns the normal polling interval when errors are below the threshold,
92
+ * and applies exponential backoff (capped at MAX_BACKOFF_MS) above it.
93
+ *
94
+ * @param consecutiveErrors - Number of consecutive errors encountered
95
+ * @returns Polling interval in milliseconds
75
96
  */
76
97
  function calculateBackoffInterval(consecutiveErrors) {
77
98
  if (consecutiveErrors < exports.MAX_CONSECUTIVE_ERRORS) {
@@ -89,14 +110,21 @@ function calculateBackoffInterval(consecutiveErrors) {
89
110
  // Auto-Yes State Management (Existing)
90
111
  // =============================================================================
91
112
  /**
92
- * Check if an auto-yes state has expired
113
+ * Check if an auto-yes state has expired.
114
+ * Compares current time against the expiresAt timestamp.
115
+ *
116
+ * @param state - Auto-yes state to check
117
+ * @returns true if the current time is past the expiration time
93
118
  */
94
119
  function isAutoYesExpired(state) {
95
120
  return Date.now() > state.expiresAt;
96
121
  }
97
122
  /**
98
- * Get the auto-yes state for a worktree
99
- * Returns null if no state exists or if expired (auto-disables on expiry)
123
+ * Get the auto-yes state for a worktree.
124
+ * Returns null if no state exists. If expired, auto-disables and returns the disabled state.
125
+ *
126
+ * @param worktreeId - Worktree identifier
127
+ * @returns Current auto-yes state, or null if no state exists
100
128
  */
101
129
  function getAutoYesState(worktreeId) {
102
130
  const state = autoYesStates.get(worktreeId);
@@ -142,7 +170,8 @@ function setAutoYesEnabled(worktreeId, enabled, duration) {
142
170
  }
143
171
  }
144
172
  /**
145
- * Clear all auto-yes states (for testing)
173
+ * Clear all auto-yes states.
174
+ * @internal Exported for testing purposes only.
146
175
  */
147
176
  function clearAllAutoYesStates() {
148
177
  autoYesStates.clear();
@@ -151,28 +180,38 @@ function clearAllAutoYesStates() {
151
180
  // Server-side Polling (Issue #138)
152
181
  // =============================================================================
153
182
  /**
154
- * Get the number of active pollers
183
+ * Get the number of active pollers.
184
+ *
185
+ * @returns Count of currently active polling instances
155
186
  */
156
187
  function getActivePollerCount() {
157
188
  return autoYesPollerStates.size;
158
189
  }
159
190
  /**
160
- * Clear all poller states (for testing)
191
+ * Clear all poller states.
192
+ * Stops all active pollers before clearing state.
193
+ * @internal Exported for testing purposes only.
161
194
  */
162
195
  function clearAllPollerStates() {
163
196
  stopAllAutoYesPolling();
164
197
  autoYesPollerStates.clear();
165
198
  }
166
199
  /**
167
- * Get the last server response timestamp for a worktree
168
- * Used by clients to prevent duplicate responses
200
+ * Get the last server response timestamp for a worktree.
201
+ * Used by clients to prevent duplicate responses.
202
+ *
203
+ * @param worktreeId - Worktree identifier
204
+ * @returns Timestamp (Date.now()) of the last server response, or null if none
169
205
  */
170
206
  function getLastServerResponseTimestamp(worktreeId) {
171
207
  const pollerState = autoYesPollerStates.get(worktreeId);
172
208
  return pollerState?.lastServerResponseTimestamp ?? null;
173
209
  }
174
210
  /**
175
- * Update the last server response timestamp
211
+ * Update the last server response timestamp.
212
+ *
213
+ * @param worktreeId - Worktree identifier
214
+ * @param timestamp - Timestamp value (Date.now())
176
215
  */
177
216
  function updateLastServerResponseTimestamp(worktreeId, timestamp) {
178
217
  const pollerState = autoYesPollerStates.get(worktreeId);
@@ -181,7 +220,9 @@ function updateLastServerResponseTimestamp(worktreeId, timestamp) {
181
220
  }
182
221
  }
183
222
  /**
184
- * Reset error count for a poller
223
+ * Reset error count for a poller and restore the default polling interval.
224
+ *
225
+ * @param worktreeId - Worktree identifier
185
226
  */
186
227
  function resetErrorCount(worktreeId) {
187
228
  const pollerState = autoYesPollerStates.get(worktreeId);
@@ -191,7 +232,9 @@ function resetErrorCount(worktreeId) {
191
232
  }
192
233
  }
193
234
  /**
194
- * Increment error count and apply backoff if needed
235
+ * Increment error count and apply backoff if the threshold is exceeded.
236
+ *
237
+ * @param worktreeId - Worktree identifier
195
238
  */
196
239
  function incrementErrorCount(worktreeId) {
197
240
  const pollerState = autoYesPollerStates.get(worktreeId);
@@ -201,7 +244,26 @@ function incrementErrorCount(worktreeId) {
201
244
  }
202
245
  }
203
246
  /**
204
- * Internal polling function (setTimeout recursive)
247
+ * Check if the given prompt has already been answered.
248
+ * Extracted from pollAutoYes() to reduce responsibility concentration (F005/SRP).
249
+ *
250
+ * @param pollerState - Current poller state containing the last answered prompt key
251
+ * @param promptKey - Composite key of the current prompt (generated by generatePromptKey)
252
+ * @returns true if the prompt key matches the last answered prompt key
253
+ */
254
+ function isDuplicatePrompt(pollerState, promptKey) {
255
+ return pollerState.lastAnsweredPromptKey === promptKey;
256
+ }
257
+ /**
258
+ * Internal polling function that recursively schedules itself via setTimeout.
259
+ * Captures tmux output, detects prompts, and sends auto-responses when appropriate.
260
+ *
261
+ * Includes duplicate prevention (Issue #306): skips prompts that have already
262
+ * been answered (tracked via lastAnsweredPromptKey) and applies a cooldown
263
+ * interval (COOLDOWN_INTERVAL_MS) after successful responses.
264
+ *
265
+ * @param worktreeId - Worktree identifier
266
+ * @param cliToolId - CLI tool type being polled
205
267
  */
206
268
  async function pollAutoYes(worktreeId, cliToolId) {
207
269
  // Check if poller was stopped
@@ -224,7 +286,7 @@ async function pollAutoYes(worktreeId, cliToolId) {
224
286
  // while Claude is actively processing (thinking/planning).
225
287
  //
226
288
  // Issue #191: Apply windowing to detectThinking() to prevent stale thinking
227
- // summary lines (e.g., "· Simmering") from blocking prompt detection.
289
+ // summary lines (e.g., "· Simmering...") from blocking prompt detection.
228
290
  // Window size matches detectPrompt()'s multiple_choice scan range (50 lines).
229
291
  //
230
292
  // Safety: Claude CLI does not emit prompts during thinking, so narrowing
@@ -246,7 +308,14 @@ async function pollAutoYes(worktreeId, cliToolId) {
246
308
  const promptOptions = (0, cli_patterns_1.buildDetectPromptOptions)(cliToolId);
247
309
  const promptDetection = (0, prompt_detector_1.detectPrompt)(cleanOutput, promptOptions);
248
310
  if (!promptDetection.isPrompt || !promptDetection.promptData) {
249
- // No prompt detected, schedule next poll
311
+ // No prompt detected - reset lastAnsweredPromptKey (Issue #306)
312
+ pollerState.lastAnsweredPromptKey = null;
313
+ scheduleNextPoll(worktreeId, cliToolId);
314
+ return;
315
+ }
316
+ // Issue #306: Check for duplicate prompt before responding
317
+ const promptKey = (0, prompt_key_1.generatePromptKey)(promptDetection.promptData);
318
+ if (isDuplicatePrompt(pollerState, promptKey)) {
250
319
  scheduleNextPoll(worktreeId, cliToolId);
251
320
  return;
252
321
  }
@@ -274,32 +343,47 @@ async function pollAutoYes(worktreeId, cliToolId) {
274
343
  updateLastServerResponseTimestamp(worktreeId, Date.now());
275
344
  // 7. Reset error count on success
276
345
  resetErrorCount(worktreeId);
346
+ // Issue #306: Record answered prompt key and apply cooldown
347
+ pollerState.lastAnsweredPromptKey = promptKey;
277
348
  // Log success (without sensitive content)
278
349
  console.info(`[Auto-Yes Poller] Sent response for worktree: ${worktreeId}`);
350
+ // Issue #306: Apply cooldown interval after successful response (early return)
351
+ scheduleNextPoll(worktreeId, cliToolId, exports.COOLDOWN_INTERVAL_MS);
352
+ return;
279
353
  }
280
354
  catch (error) {
281
355
  // Increment error count on failure
282
356
  incrementErrorCount(worktreeId);
283
357
  // Log error (without sensitive details)
284
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
285
- console.warn(`[Auto-Yes Poller] Error for worktree ${worktreeId}: ${errorMessage}`);
358
+ console.warn(`[Auto-Yes Poller] Error for worktree ${worktreeId}: ${getErrorMessage(error)}`);
286
359
  }
287
- // Schedule next poll
360
+ // Schedule next poll (catch block fallthrough or other paths)
288
361
  scheduleNextPoll(worktreeId, cliToolId);
289
362
  }
290
363
  /**
291
364
  * Schedule the next polling iteration
365
+ * @param overrideInterval - Optional interval in milliseconds (S2-F009: type definition).
366
+ * When provided (e.g., COOLDOWN_INTERVAL_MS), overrides pollerState.currentInterval.
367
+ * Type: number | undefined (optional parameter).
292
368
  */
293
- function scheduleNextPoll(worktreeId, cliToolId) {
369
+ function scheduleNextPoll(worktreeId, cliToolId, overrideInterval) {
294
370
  const pollerState = autoYesPollerStates.get(worktreeId);
295
371
  if (!pollerState)
296
372
  return;
373
+ // S4-F003: Floor guard - polling interval must not be below POLLING_INTERVAL_MS
374
+ const interval = Math.max(overrideInterval ?? pollerState.currentInterval, exports.POLLING_INTERVAL_MS);
297
375
  pollerState.timerId = setTimeout(() => {
298
376
  pollAutoYes(worktreeId, cliToolId);
299
- }, pollerState.currentInterval);
377
+ }, interval);
300
378
  }
301
379
  /**
302
- * Start server-side auto-yes polling for a worktree
380
+ * Start server-side auto-yes polling for a worktree.
381
+ * Validates the worktree ID, checks auto-yes state, enforces concurrent poller limits,
382
+ * and begins the polling loop.
383
+ *
384
+ * @param worktreeId - Worktree identifier (must match WORKTREE_ID_PATTERN)
385
+ * @param cliToolId - CLI tool type to poll for
386
+ * @returns Result indicating whether the poller was started, with reason if not
303
387
  */
304
388
  function startAutoYesPolling(worktreeId, cliToolId) {
305
389
  // Validate worktree ID (security)
@@ -328,6 +412,7 @@ function startAutoYesPolling(worktreeId, cliToolId) {
328
412
  consecutiveErrors: 0,
329
413
  currentInterval: exports.POLLING_INTERVAL_MS,
330
414
  lastServerResponseTimestamp: null,
415
+ lastAnsweredPromptKey: null, // S2-F003: initialized to null
331
416
  };
332
417
  autoYesPollerStates.set(worktreeId, pollerState);
333
418
  // Start polling immediately
@@ -338,7 +423,10 @@ function startAutoYesPolling(worktreeId, cliToolId) {
338
423
  return { started: true };
339
424
  }
340
425
  /**
341
- * Stop server-side auto-yes polling for a worktree
426
+ * Stop server-side auto-yes polling for a worktree.
427
+ * Clears the timer and removes the poller state.
428
+ *
429
+ * @param worktreeId - Worktree identifier
342
430
  */
343
431
  function stopAutoYesPolling(worktreeId) {
344
432
  const pollerState = autoYesPollerStates.get(worktreeId);
@@ -353,7 +441,8 @@ function stopAutoYesPolling(worktreeId) {
353
441
  console.info(`[Auto-Yes Poller] Stopped for worktree: ${worktreeId}`);
354
442
  }
355
443
  /**
356
- * Stop all server-side auto-yes polling (graceful shutdown)
444
+ * Stop all server-side auto-yes polling (graceful shutdown).
445
+ * Clears all timers and removes all poller states.
357
446
  */
358
447
  function stopAllAutoYesPolling() {
359
448
  for (const [worktreeId, pollerState] of autoYesPollerStates.entries()) {
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.CLAUDE_PROMPT_POLL_INTERVAL = exports.CLAUDE_SEND_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_POST_PROMPT_DELAY = exports.CLAUDE_INIT_POLL_INTERVAL = exports.CLAUDE_INIT_TIMEOUT = void 0;
8
8
  exports.clearCachedClaudePath = clearCachedClaudePath;
9
+ exports.isSessionHealthy = isSessionHealthy;
9
10
  exports.getSessionName = getSessionName;
10
11
  exports.isClaudeInstalled = isClaudeInstalled;
11
12
  exports.isClaudeRunning = isClaudeRunning;
@@ -124,6 +125,17 @@ exports.CLAUDE_SEND_PROMPT_WAIT_TIMEOUT = 10000;
124
125
  * 200ms provides quick response while minimizing CPU usage.
125
126
  */
126
127
  exports.CLAUDE_PROMPT_POLL_INTERVAL = 200;
128
+ /**
129
+ * Maximum expected length of a shell prompt line (characters)
130
+ *
131
+ * Shell prompts are typically under 40 characters (e.g., "user@host:~/project$" ~30 chars).
132
+ * Lines at or above this threshold are not considered shell prompts, preventing
133
+ * false positives from Claude CLI output that happens to end with $, %, or #.
134
+ *
135
+ * Used by isSessionHealthy() to distinguish shell prompts from CLI output.
136
+ * 40 is an empirical threshold with safety margin.
137
+ */
138
+ const MAX_SHELL_PROMPT_LENGTH = 40;
127
139
  /**
128
140
  * Cached Claude CLI path
129
141
  */
@@ -229,45 +241,69 @@ async function getCleanPaneOutput(sessionName, lines = 50) {
229
241
  const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -lines });
230
242
  return (0, cli_patterns_1.stripAnsi)(output);
231
243
  }
232
- // ----- Health Check Functions (Bug 2) -----
233
244
  /**
234
245
  * Verify that Claude CLI is actually running inside a tmux session
235
246
  * Detects broken sessions where tmux exists but Claude failed to start
236
247
  *
248
+ * @internal Exported for testing purposes only.
249
+ * Follows clearCachedClaudePath() precedent (L148-156).
250
+ *
237
251
  * @param sessionName - tmux session name
238
- * @returns true if Claude CLI is responsive (prompt detected or initializing)
252
+ * @returns HealthCheckResult with healthy status and optional reason
239
253
  */
240
254
  async function isSessionHealthy(sessionName) {
241
255
  try {
242
256
  // SF-001: Use shared helper instead of inline capturePane + stripAnsi
243
257
  const cleanOutput = await getCleanPaneOutput(sessionName);
244
- // MF-001: Check error patterns from cli-patterns.ts (SRP - pattern management centralized)
245
- for (const pattern of cli_patterns_1.CLAUDE_SESSION_ERROR_PATTERNS) {
246
- if (cleanOutput.includes(pattern)) {
247
- return false;
248
- }
249
- }
250
- for (const regex of cli_patterns_1.CLAUDE_SESSION_ERROR_REGEX_PATTERNS) {
251
- if (regex.test(cleanOutput)) {
252
- return false;
253
- }
254
- }
255
258
  // MF-002: Check shell prompt endings from extensible array (OCP)
256
259
  const trimmed = cleanOutput.trim();
260
+ // S2-F010: Empty output judgment (HealthCheckResult format)
257
261
  // C-S2-001: Empty output means tmux session exists but Claude CLI has no output.
258
262
  // This is treated as unhealthy because a properly running Claude CLI always
259
263
  // produces output (prompt, spinner, or response). An empty pane indicates
260
264
  // the CLI process has exited or failed to start.
261
265
  if (trimmed === '') {
262
- return false;
266
+ return { healthy: false, reason: 'empty output' };
263
267
  }
264
- if (SHELL_PROMPT_ENDINGS.some(ending => trimmed.endsWith(ending))) {
265
- return false;
268
+ // S2-F010: Error pattern detection (HealthCheckResult format)
269
+ // MF-001: Check error patterns from cli-patterns.ts (SRP - pattern management centralized)
270
+ for (const pattern of cli_patterns_1.CLAUDE_SESSION_ERROR_PATTERNS) {
271
+ if (trimmed.includes(pattern)) {
272
+ return { healthy: false, reason: `error pattern: ${pattern}` };
273
+ }
266
274
  }
267
- return true;
275
+ for (const regex of cli_patterns_1.CLAUDE_SESSION_ERROR_REGEX_PATTERNS) {
276
+ if (regex.test(trimmed)) {
277
+ return { healthy: false, reason: `error pattern: ${regex.source}` };
278
+ }
279
+ }
280
+ // S2-F002: Extract last line after empty line filtering
281
+ const lines = trimmed.split('\n').filter(line => line.trim() !== '');
282
+ const lastLine = lines[lines.length - 1]?.trim() ?? '';
283
+ // F006: Line length check BEFORE SHELL_PROMPT_ENDINGS check (early return)
284
+ if (lastLine.length >= MAX_SHELL_PROMPT_LENGTH) {
285
+ // Long lines are not shell prompts -> treat as healthy (early return)
286
+ return { healthy: true };
287
+ }
288
+ // F003: Individual pattern exclusions for SHELL_PROMPT_ENDINGS
289
+ // NOTE(F003): If new false positive patterns are found in the future,
290
+ // consider refactoring to a structure that associates exclusionPattern
291
+ // with each SHELL_PROMPT_ENDINGS entry. Currently only % needs exclusion (YAGNI).
292
+ if (SHELL_PROMPT_ENDINGS.some(ending => {
293
+ if (!lastLine.endsWith(ending))
294
+ return false;
295
+ // Exclude N% pattern (e.g., "Context left until auto-compact: 7%")
296
+ if (ending === '%' && /\d+%$/.test(lastLine))
297
+ return false;
298
+ return true;
299
+ })) {
300
+ return { healthy: false, reason: `shell prompt ending detected: ${lastLine}` };
301
+ }
302
+ return { healthy: true };
268
303
  }
269
304
  catch {
270
- return false;
305
+ // S3-F001: Catch block also returns HealthCheckResult format
306
+ return { healthy: false, reason: 'capture error' };
271
307
  }
272
308
  }
273
309
  /**
@@ -279,8 +315,9 @@ async function isSessionHealthy(sessionName) {
279
315
  * @returns true if session is healthy and can be reused, false if it was killed
280
316
  */
281
317
  async function ensureHealthySession(sessionName) {
282
- const healthy = await isSessionHealthy(sessionName);
283
- if (!healthy) {
318
+ const result = await isSessionHealthy(sessionName);
319
+ if (!result.healthy) {
320
+ console.warn(`[health-check] Session ${sessionName} unhealthy: ${result.reason}`);
284
321
  await (0, tmux_1.killSession)(sessionName);
285
322
  return false;
286
323
  }
@@ -376,7 +413,9 @@ async function isClaudeRunning(worktreeId) {
376
413
  return false;
377
414
  }
378
415
  // MF-S3-001: Verify session health to avoid reporting broken sessions as running
379
- return isSessionHealthy(sessionName);
416
+ // S2-F001: await + extract .healthy to maintain boolean return type
417
+ const result = await isSessionHealthy(sessionName);
418
+ return result.healthy;
380
419
  }
381
420
  /**
382
421
  * Get Claude session state
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generatePromptKey = generatePromptKey;
4
+ /**
5
+ * Generate a composite key for prompt deduplication.
6
+ *
7
+ * Used by both client-side (useAutoYes.ts) and server-side (auto-yes-manager.ts)
8
+ * to ensure consistent prompt identification across the duplicate prevention system.
9
+ *
10
+ * The key format is `{type}:{question}`, which uniquely identifies a prompt
11
+ * by combining its type and question text.
12
+ *
13
+ * @param promptData - Prompt data containing type and question fields
14
+ * @returns Composite key string in the format "type:question"
15
+ *
16
+ * @internal Used for in-memory comparison only. Do NOT use for logging,
17
+ * persistence, or external output. If the return value is ever used in
18
+ * log output, DB storage, or HTML rendering, apply appropriate sanitization
19
+ * (CR/LF escaping, prepared statements, HTML escaping respectively).
20
+ * See SEC: S4-F001.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const key = generatePromptKey({ type: 'yes_no', question: 'Continue?' });
25
+ * // Returns 'yes_no:Continue?'
26
+ * ```
27
+ */
28
+ function generatePromptKey(promptData) {
29
+ return `${promptData.type}:${promptData.question}`;
30
+ }
package/package.json CHANGED
@@ -1,7 +1,18 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Git worktree management with Claude CLI and tmux sessions",
5
+ "keywords": [
6
+ "claude-code",
7
+ "codex-cli",
8
+ "terminal",
9
+ "session-manager",
10
+ "tmux",
11
+ "git-worktree",
12
+ "ai-coding",
13
+ "cli",
14
+ "developer-tools"
15
+ ],
5
16
  "repository": {
6
17
  "type": "git",
7
18
  "url": "https://github.com/Kewton/CommandMate.git"
@@ -1 +0,0 @@
1
- "use strict";exports.id=667,exports.ids=[667],exports.modules={87946:(e,t,r)=>{r.d(t,{Ad:()=>l,l1:()=>o});let n=[36e5,108e5,288e5],l=36e5;function o(e){return"number"==typeof e&&n.includes(e)}},60667:(e,t,r)=>{r.d(t,{bq:()=>m,gf:()=>w,m$:()=>p,bY:()=>g,w:()=>v,Qz:()=>A});var n=r(89194),l=r(63661),o=r(49528),s=r(43839),i=r(19377),a=r(87946);let u=/^[a-zA-Z0-9_-]+$/,c=globalThis.__autoYesStates??(globalThis.__autoYesStates=new Map),f=globalThis.__autoYesPollerStates??(globalThis.__autoYesPollerStates=new Map);function p(e){return!!e&&0!==e.length&&u.test(e)}function d(e){return Date.now()>e.expiresAt}function m(e){let t=c.get(e);if(!t)return null;if(d(t)){let r={...t,enabled:!1};return c.set(e,r),r}return t}function g(e,t,r){if(t){let t=Date.now(),n={enabled:!0,enabledAt:t,expiresAt:t+(r??a.Ad)};return c.set(e,n),n}{let t=c.get(e),r={enabled:!1,enabledAt:t?.enabledAt??0,expiresAt:t?.expiresAt??0};return c.set(e,r),r}}function w(e){let t=f.get(e);return t?.lastServerResponseTimestamp??null}async function b(e,t){if(!f.get(e))return;let r=m(e);if(!r?.enabled||d(r)){A(e);return}try{let r=await (0,n.NA)(e,t,5e3),a=(0,i.vp)(r),u=a.split("\n").slice(-50).join("\n");if((0,i.Wg)(t,u)){h(e,t);return}let c=(0,i.Sg)(t),p=(0,l.F)(a,c);if(!p.isPrompt||!p.promptData){h(e,t);return}let d=function(e){if("yes_no"===e.type)return"y";if("multiple_choice"===e.type){let t=e.options.find(e=>e.isDefault)??e.options[0];return!t||t.requiresTextInput?null:t.number.toString()}return null}(p.promptData);if(null===d){h(e,t);return}let m=s.g.getInstance().getTool(t).getSessionName(e);await (0,o.z)({sessionName:m,answer:d,cliToolId:t,promptData:p.promptData}),function(e,t){let r=f.get(e);r&&(r.lastServerResponseTimestamp=t)}(e,Date.now()),function(e){let t=f.get(e);t&&(t.consecutiveErrors=0,t.currentInterval=2e3)}(e),console.info(`[Auto-Yes Poller] Sent response for worktree: ${e}`)}catch(r){!function(e){let t=f.get(e);if(t){var r;t.consecutiveErrors++,t.currentInterval=(r=t.consecutiveErrors)<5?2e3:Math.min(2e3*Math.pow(2,r-5+1),6e4)}}(e);let t=r instanceof Error?r.message:"Unknown error";console.warn(`[Auto-Yes Poller] Error for worktree ${e}: ${t}`)}h(e,t)}function h(e,t){let r=f.get(e);r&&(r.timerId=setTimeout(()=>{b(e,t)},r.currentInterval))}function v(e,t){if(!p(e))return{started:!1,reason:"invalid worktree ID"};let r=m(e);if(!r?.enabled)return{started:!1,reason:"auto-yes not enabled"};let n=f.has(e);if(!n&&f.size>=50)return{started:!1,reason:"max concurrent pollers reached"};n&&A(e);let l={timerId:null,cliToolId:t,consecutiveErrors:0,currentInterval:2e3,lastServerResponseTimestamp:null};return f.set(e,l),l.timerId=setTimeout(()=>{b(e,t)},2e3),console.info(`[Auto-Yes Poller] Started for worktree: ${e}, cliTool: ${t}`),{started:!0}}function A(e){let t=f.get(e);t&&(t.timerId&&clearTimeout(t.timerId),f.delete(e),console.info(`[Auto-Yes Poller] Stopped for worktree: ${e}`))}},49528:(e,t,r)=>{r.d(t,{z:()=>s});var n=r(10927);let l=/^\[[ x]\] /;function o(e){if(0===e)return[];let t=e>0?"Down":"Up";return Array.from({length:Math.abs(e)},()=>t)}async function s(e){let{sessionName:t,answer:r,cliToolId:s,promptData:i,fallbackPromptType:a,fallbackDefaultOptionNumber:u}=e;if("claude"===s&&(i?.type==="multiple_choice"||"multiple_choice"===a)&&/^\d+$/.test(r)){let e;let s=parseInt(r,10),a=null;if(i?.type==="multiple_choice"){let t=(a=i.options).find(e=>e.isDefault);e=t?.number??1}else e=u??1;let c=s-e;if(null!==a&&a.some(e=>l.test(e.label))&&null!==a){let e=a.filter(e=>l.test(e.label)).length,r=[...o(c),"Space"];r.push(...o(e-s+1)),r.push("Enter"),await (0,n.hL)(t,r)}else{let e=[...o(c),"Enter"];await (0,n.hL)(t,e)}}else await (0,n.Is)(t,r,!1),await new Promise(e=>setTimeout(e,100)),await (0,n.Is)(t,"",!0)}}};
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5970],{20318:function(e,t,n){n.d(t,{Ix:function(){return u},pm:function(){return x}});var r=n(57437),a=n(2265),s=n(41671),l=n(99388),o=n(33245),i=n(32489);function c(e){let{type:t,iconColor:n}=e,a="h-5 w-5 ".concat(n);switch(t){case"success":return(0,r.jsx)(s.Z,{className:a,"data-testid":"toast-icon-success"});case"error":return(0,r.jsx)(l.Z,{className:a,"data-testid":"toast-icon-error"});default:return(0,r.jsx)(o.Z,{className:a,"data-testid":"toast-icon-info"})}}function d(e){let{id:t,message:n,type:s,onClose:l,duration:o=3e3}=e,d=(0,a.useRef)(null),u=function(e){switch(e){case"success":return{bgColor:"bg-green-50",borderColor:"border-green-200",textColor:"text-green-800",iconColor:"text-green-500"};case"error":return{bgColor:"bg-red-50",borderColor:"border-red-200",textColor:"text-red-800",iconColor:"text-red-500"};default:return{bgColor:"bg-blue-50",borderColor:"border-blue-200",textColor:"text-blue-800",iconColor:"text-blue-500"}}}(s);(0,a.useEffect)(()=>(o>0&&(d.current=setTimeout(()=>{l(t)},o)),()=>{d.current&&clearTimeout(d.current)}),[t,o,l]);let x=(0,a.useCallback)(()=>{d.current&&clearTimeout(d.current),l(t)},[t,l]);return(0,r.jsxs)("div",{"data-testid":"toast-".concat(t),role:"alert",className:"\n ".concat(u.bgColor,"\n ").concat(u.borderColor,"\n ").concat(u.textColor,"\n border rounded-lg shadow-lg p-4 min-w-[300px] max-w-[400px]\n flex items-start gap-3\n animate-slide-in\n "),children:[(0,r.jsx)(c,{type:s,iconColor:u.iconColor}),(0,r.jsx)("p",{className:"flex-1 text-sm font-medium",children:n}),(0,r.jsx)("button",{"data-testid":"toast-close-button",onClick:x,"aria-label":"Close notification",className:"\n ".concat(u.textColor,"\n hover:opacity-70\n focus:outline-none focus:ring-2 focus:ring-offset-2\n transition-opacity\n "),children:(0,r.jsx)(i.Z,{className:"h-4 w-4"})})]})}function u(e){let{toasts:t,onClose:n}=e;return(0,r.jsx)("div",{"data-testid":"toast-container","aria-live":"polite",className:"fixed bottom-4 right-4 z-50 flex flex-col gap-2",children:t.map(e=>(0,r.jsx)(d,{id:e.id,message:e.message,type:e.type,onClose:n,duration:e.duration},e.id))})}function x(){let[e,t]=(0,a.useState)([]),n=(0,a.useRef)(0);return{toasts:e,showToast:(0,a.useCallback)(function(e){let r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"info",a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3,s="toast-".concat(++n.current,"-").concat(Date.now()),l={id:s,message:e,type:r,duration:a};return t(e=>[...e,l]),s},[]),removeToast:(0,a.useCallback)(e=>{t(t=>t.filter(t=>t.id!==e))},[]),clearToasts:(0,a.useCallback)(()=>{t([])},[])}}},21221:function(e,t,n){n.d(t,{Vw:function(){return S}});var r=n(57437),a=n(2265);n(27648);var s=n(43241),l=n(58819),o=n(99376),i=n(34021),c=n(8672);function d(e){let{status:t,label:n}=e,a=c.F4[t],s="".concat(n,": ").concat(a.label);return"spinner"===a.type?(0,r.jsx)("span",{className:"w-2 h-2 rounded-full flex-shrink-0 border-2 border-t-transparent animate-spin ".concat(a.className),title:s,"aria-label":s}):(0,r.jsx)("span",{className:"w-2 h-2 rounded-full flex-shrink-0 ".concat(a.className),title:s,"aria-label":s})}let u=(0,a.memo)(function(e){let{branch:t,isSelected:n,onClick:a}=e;return(0,r.jsxs)("button",{"data-testid":"branch-list-item",onClick:a,"aria-current":n?"true":void 0,className:"\n w-full px-4 py-3 flex flex-col gap-1\n hover:bg-gray-800 transition-colors\n focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500\n ".concat(n?"bg-gray-700 border-l-2 border-blue-500":"border-l-2 border-transparent","\n "),children:[(0,r.jsxs)("div",{className:"flex items-center gap-3 w-full",children:[t.cliStatus&&(0,r.jsxs)("div",{className:"flex items-center gap-1 flex-shrink-0","aria-label":"CLI tool status",children:[(0,r.jsx)(d,{status:t.cliStatus.claude,label:"Claude"}),(0,r.jsx)(d,{status:t.cliStatus.codex,label:"Codex"})]}),(0,r.jsxs)("div",{className:"flex-1 min-w-0 text-left",children:[(0,r.jsx)("p",{className:"text-sm font-medium text-white truncate",children:t.name}),(0,r.jsx)("p",{className:"text-xs text-gray-400 truncate",children:t.repositoryName})]}),t.hasUnread&&(0,r.jsx)("span",{"data-testid":"unread-indicator",className:"w-2 h-2 rounded-full bg-blue-500 flex-shrink-0","aria-label":"Has unread messages"})]}),t.description&&(0,r.jsx)("div",{"data-testid":"branch-description",className:"pl-6 pr-2 mt-1 text-left",children:(0,r.jsx)("p",{className:"text-xs text-gray-400 line-clamp-2",children:t.description})})]})}),x=[{key:"updatedAt",label:"Updated"},{key:"repositoryName",label:"Repository"},{key:"branchName",label:"Branch"},{key:"status",label:"Status"}],m=(0,a.memo)(function(){var e;let{sortKey:t,sortDirection:n,setSortKey:l,setSortDirection:o}=(0,s.Sz)(),[i,c]=(0,a.useState)(!1),d=(0,a.useRef)(null);(0,a.useEffect)(()=>{function e(e){d.current&&!d.current.contains(e.target)&&c(!1)}if(i)return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[i]),(0,a.useEffect)(()=>{function e(e){"Escape"===e.key&&c(!1)}if(i)return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[i]);let u=(0,a.useCallback)(()=>{c(e=>!e)},[]),m=(0,a.useCallback)(e=>{e===t?o("asc"===n?"desc":"asc"):(l(e),o("updatedAt"===e?"desc":"asc")),c(!1)},[t,n,l,o]),p=(0,a.useCallback)(()=>{o("asc"===n?"desc":"asc")},[n,o]),b=(null===(e=x.find(e=>e.key===t))||void 0===e?void 0:e.label)||"Sort";return(0,r.jsxs)("div",{ref:d,className:"relative","data-testid":"sort-selector",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1",children:[(0,r.jsxs)("button",{type:"button",onClick:u,"aria-expanded":i,"aria-haspopup":"listbox","aria-label":"Sort by ".concat(b),className:" flex items-center gap-1 px-2 py-1 rounded text-xs text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors ",children:[(0,r.jsx)(h,{className:"w-3 h-3"}),(0,r.jsx)("span",{className:"hidden sm:inline",children:b})]}),(0,r.jsx)("button",{type:"button",onClick:p,"aria-label":"asc"===n?"Sort ascending":"Sort descending",className:" p-1 rounded text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors ",children:"asc"===n?(0,r.jsx)(f,{className:"w-3 h-3"}):(0,r.jsx)(g,{className:"w-3 h-3"})})]}),i&&(0,r.jsx)("div",{role:"listbox","aria-label":"Sort options",className:" absolute right-0 top-full mt-1 z-50 min-w-[140px] py-1 rounded-md shadow-lg bg-gray-800 border border-gray-600 ",children:x.map(e=>(0,r.jsxs)("button",{type:"button",role:"option","aria-selected":t===e.key,onClick:()=>m(e.key),className:"\n w-full px-3 py-2 text-left text-sm\n flex items-center justify-between\n hover:bg-gray-700 transition-colors\n ".concat(t===e.key?"text-blue-400":"text-gray-300","\n "),children:[(0,r.jsx)("span",{children:e.label}),t===e.key&&(0,r.jsx)("span",{className:"text-xs",children:"asc"===n?"ASC":"DESC"})]},e.key))})]})});function h(e){let{className:t}=e;return(0,r.jsx)("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"})})}function f(e){let{className:t}=e;return(0,r.jsx)("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"})})}function g(e){let{className:t}=e;return(0,r.jsx)("svg",{className:t,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})}var p=n(69234);let b=["en","ja"],y={en:"English",ja:"日本語"};function v(){let{currentLocale:e,switchLocale:t}={currentLocale:(0,p.bU)(),switchLocale:e=>{b.includes(e)&&(!function(e){let t="https:"===window.location.protocol;document.cookie="".concat("locale","=").concat(e,";path=/;max-age=").concat(31536e3,";SameSite=Lax").concat(t?";Secure":"")}(e),localStorage.setItem("locale",e),window.location.reload())}};return(0,r.jsx)("select",{value:e,onChange:e=>t(e.target.value),"aria-label":"Language",className:" w-full px-3 py-2 rounded-md bg-gray-800 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm ",children:b.map(e=>(0,r.jsx)("option",{value:e,children:y[e]},e))})}var w=n(47712);let j={waiting:0,ready:1,running:2,generating:3,idle:4},N=(0,a.memo)(function(){let e=(0,o.useRouter)(),{worktrees:t,selectedWorktreeId:n,selectWorktree:l}=(0,i.Mu)(),{closeMobileDrawer:c,sortKey:d,sortDirection:x}=(0,s.Sz)(),[h,f]=(0,a.useState)(""),g=(0,a.useMemo)(()=>{let e=t.map(w.I_),n=e;if(h.trim()){let t=h.toLowerCase();n=e.filter(e=>e.name.toLowerCase().includes(t)||e.repositoryName.toLowerCase().includes(t))}return function(e,t,n){let r=[...e];return r.sort((e,r)=>{let a=0;switch(t){case"updatedAt":{let t=e=>e?e instanceof Date?e.getTime():new Date(e).getTime():0,n=t(e.lastActivity);a=t(r.lastActivity)-n;break}case"repositoryName":{let t=e.repositoryName.toLowerCase(),n=r.repositoryName.toLowerCase();a=t.localeCompare(n);break}case"branchName":{let t=e.name.toLowerCase(),n=r.name.toLowerCase();a=t.localeCompare(n);break}case"status":a=j[e.status]-j[r.status]}return("updatedAt"===t?"desc"===n:"asc"===n)?a:-a}),r}(n,d,x)},[t,h,d,x]),p=t=>{l(t),e.push("/worktrees/".concat(t)),c()};return(0,r.jsxs)("nav",{"data-testid":"sidebar","aria-label":"Branch navigation",className:"h-full flex flex-col bg-gray-900 text-white",role:"navigation",children:[(0,r.jsx)("div",{"data-testid":"sidebar-header",className:"flex-shrink-0 px-4 py-4 border-b border-gray-700",children:(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)("h2",{className:"text-lg font-semibold text-white",children:"Branches"}),(0,r.jsx)(m,{})]})}),(0,r.jsx)("div",{className:"flex-shrink-0 px-4 py-3 border-b border-gray-700",children:(0,r.jsx)("input",{type:"text",placeholder:"Search branches...",value:h,onChange:e=>f(e.target.value),className:" w-full px-3 py-2 rounded-md bg-gray-800 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent "})}),(0,r.jsx)("div",{"data-testid":"branch-list",className:"flex-1 overflow-y-auto",children:0===g.length?(0,r.jsx)("div",{className:"px-4 py-8 text-center text-gray-400",children:h?"No branches found":"No branches available"}):g.map(e=>(0,r.jsx)(u,{branch:e,isSelected:e.id===n,onClick:()=>p(e.id)},e.id))}),(0,r.jsx)("div",{className:"flex-shrink-0 px-4 py-3 border-t border-gray-700",children:(0,r.jsx)(v,{})})]})});var k=n(3468);let C="transform transition-transform duration-300 ease-out",S=(0,a.memo)(function(e){let{children:t}=e,{isOpen:n,isMobileDrawerOpen:a,closeMobileDrawer:o}=(0,s.Sz)();return(0,l.d)()?(0,r.jsxs)("div",{"data-testid":"app-shell",className:"h-screen flex flex-col",children:[a&&(0,r.jsx)("div",{"data-testid":"drawer-overlay",className:"fixed inset-0 bg-black/50 z-40",onClick:o,"aria-hidden":"true"}),(0,r.jsx)("aside",{"data-testid":"sidebar-container",className:"\n fixed left-0 top-0 h-full w-72 z-50\n ".concat(C,"\n ").concat(a?"translate-x-0":"-translate-x-full","\n "),role:"complementary",children:(0,r.jsx)(N,{})}),(0,r.jsx)("main",{className:"flex-1 min-h-0 overflow-hidden",role:"main",children:t})]}):(0,r.jsxs)("div",{"data-testid":"app-shell",className:"h-screen flex",children:[(0,r.jsx)("aside",{"data-testid":"sidebar-container",className:"\n fixed left-0 top-0 h-full w-72\n ".concat(C,"\n ").concat(n?"translate-x-0":"-translate-x-full","\n "),style:{zIndex:k.k.SIDEBAR},role:"complementary","aria-hidden":!n,children:(0,r.jsx)(N,{})}),(0,r.jsx)("main",{className:"\n flex-1 min-w-0 h-full overflow-hidden\n transition-[padding] duration-300 ease-out\n ".concat(n?"md:pl-72":"md:pl-0","\n "),role:"main",children:t})]})})},98702:function(e,t,n){n.d(t,{u:function(){return l}});var r=n(57437),a=n(2265),s=n(54887);function l(e){let{isOpen:t,onClose:n,title:l,children:o,size:i="lg",showCloseButton:c=!0,disableClose:d=!1}=e,u=(0,a.useRef)(null);return((0,a.useEffect)(()=>{if(d)return;let e=e=>{"Escape"===e.key&&t&&n()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[t,n,d]),(0,a.useEffect)(()=>(t?document.body.style.overflow="hidden":document.body.style.overflow="unset",()=>{document.body.style.overflow="unset"}),[t]),t)?(0,s.createPortal)((0,r.jsxs)("div",{className:"fixed inset-0 z-[9999] overflow-y-auto",children:[(0,r.jsx)("div",{className:"fixed inset-0 bg-black bg-opacity-50 transition-opacity",onClick:d?void 0:n}),(0,r.jsx)("div",{className:"relative flex min-h-full items-center justify-center p-2 sm:p-4",children:(0,r.jsxs)("div",{ref:u,className:"relative w-full ".concat({sm:"max-w-[calc(100vw-2rem)] sm:max-w-md",md:"max-w-[calc(100vw-2rem)] sm:max-w-2xl",lg:"max-w-[calc(100vw-2rem)] sm:max-w-4xl",xl:"max-w-[calc(100vw-2rem)] sm:max-w-6xl",full:"max-w-[calc(100vw-2rem)] sm:max-w-[95vw]"}[i]," max-h-[calc(100vh-1rem)] sm:max-h-[calc(100vh-2rem)] flex flex-col bg-white rounded-lg shadow-xl transform transition-all"),children:[(l||c)&&(0,r.jsxs)("div",{className:"flex items-center justify-between px-4 sm:px-6 py-3 sm:py-4 border-b border-gray-200 flex-shrink-0",children:[(0,r.jsx)("h3",{className:"text-base sm:text-lg font-semibold text-gray-900 truncate pr-2",children:l}),c&&(0,r.jsx)("button",{onClick:n,className:"text-gray-400 hover:text-gray-600 transition-colors flex-shrink-0",children:(0,r.jsx)("svg",{className:"w-5 h-5 sm:w-6 sm:h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),(0,r.jsx)("div",{className:"px-4 sm:px-6 py-3 sm:py-4 overflow-y-auto flex-1 min-h-0",children:o})]})})]}),document.body):null}},10789:function(e,t,n){n.d(t,{Ct:function(){return c},zx:function(){return a},Zb:function(){return s},aY:function(){return i},Ol:function(){return l},ll:function(){return o},u_:function(){return d.u}});var r=n(57437);function a(e){let{variant:t="primary",size:n="md",fullWidth:a=!1,loading:s=!1,disabled:l,className:o="",children:i,...c}=e,d=["btn",{primary:"btn-primary",secondary:"btn-secondary",danger:"btn-danger",ghost:"bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-500"}[t],{sm:"btn-sm",md:"",lg:"btn-lg"}[n],a?"w-full":"",l||s?"opacity-50 cursor-not-allowed":"",o].filter(Boolean).join(" ");return(0,r.jsxs)("button",{className:d,disabled:l||s,...c,children:[s&&(0,r.jsxs)("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,r.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,r.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),i]})}function s(e){let{hover:t=!1,padding:n="md",className:a="",children:s,...l}=e,o=["card",t?"card-hover":"",{none:"",sm:"p-3",md:"p-4",lg:"p-6"}[n],a].filter(Boolean).join(" ");return(0,r.jsx)("div",{className:o,...l,children:s})}function l(e){let{className:t="",children:n,...a}=e;return(0,r.jsx)("div",{className:"mb-3 ".concat(t),...a,children:n})}function o(e){let{className:t="",children:n,...a}=e;return(0,r.jsx)("h3",{className:"text-lg font-semibold text-gray-900 ".concat(t),...a,children:n})}function i(e){let{className:t="",children:n,...a}=e;return(0,r.jsx)("div",{className:t,...a,children:n})}function c(e){let{variant:t="gray",dot:n=!1,className:a="",children:s,...l}=e,o=["badge",{success:"badge-success",warning:"badge-warning",error:"badge-error",info:"badge-info",gray:"badge-gray"}[t],a].filter(Boolean).join(" ");return(0,r.jsxs)("span",{className:o,...l,children:[n&&(0,r.jsx)("span",{className:"mr-1.5 inline-block h-2 w-2 rounded-full ".concat({success:"bg-green-600",warning:"bg-yellow-600",error:"bg-red-600",info:"bg-blue-600",gray:"bg-gray-600"}[t]),"aria-hidden":"true"}),s]})}n(2265);var d=n(98702)},43616:function(e,t,n){n.d(t,{n:function(){return d}});var r=n(57437),a=n(2265),s=n(10789),l=n(20318),o=n(3227),i=n(32636),c=n(93448);function d(e){let{worktreeId:t}=e,[n,d]=(0,a.useState)([]),[u,x]=(0,a.useState)(null),[m,h]=(0,a.useState)(null),[f,g]=(0,a.useState)(!0),[p,b]=(0,a.useState)(null),[y,v]=(0,a.useState)(""),[w,j]=(0,a.useState)(0),[N,k]=(0,a.useState)("all"),[C,S]=(0,a.useState)(!1),{toasts:E,showToast:L,removeToast:z}=(0,l.pm)();(0,a.useEffect)(()=>{(async()=>{try{g(!0),b(null);let e=await o.Iv.getLogs(t);d(e)}catch(e){b((0,o.zG)(e))}finally{g(!1)}})()},[t]);let M=(0,a.useMemo)(()=>"all"===N?n:n.filter(e=>e.toLowerCase().includes(N)),[n,N]),T=async e=>{try{g(!0),b(null);let n=await o.Iv.getLogFile(t,e);h(n.content),x(e),v(""),j(0)}catch(e){b((0,o.zG)(e))}finally{g(!1)}},I=(0,a.useCallback)(async()=>{if(u)try{S(!0);let e=await o.Iv.getLogFile(t,u,{sanitize:!0});await (0,i.v)(e.content),L("Log copied to clipboard (sanitized)","success")}catch(e){L("Failed to export log: ".concat((0,o.zG)(e)),"error")}finally{S(!1)}},[t,u,L]),A=(0,a.useMemo)(()=>{let e;if(!y||!m)return[];let t=RegExp((0,c.hr)(y),"gi"),n=[];for(;null!==(e=t.exec(m));)n.push({index:e.index,length:e[0].length});return n},[y,m]);(0,a.useEffect)(()=>{j(0)},[y]);let B=()=>{A.length>0&&j(e=>(e+1)%A.length)},D=()=>{A.length>0&&j(e=>(e-1+A.length)%A.length)},R=(0,a.useMemo)(()=>{if(!m||!y||0===A.length)return m;let e="",t=0;return A.forEach((n,r)=>{e+=(0,c.Xv)(m.substring(t,n.index));let a=m.substring(n.index,n.index+n.length),s=r===w;e+='<mark class="'.concat(s?"bg-yellow-400 text-black":"bg-yellow-200 text-black",'" data-match-index="').concat(r,'">').concat((0,c.Xv)(a),"</mark>"),t=n.index+n.length}),e+=(0,c.Xv)(m.substring(t))},[m,y,A,w]);return(0,a.useEffect)(()=>{A.length>0&&w>=0&&setTimeout(()=>{let e=document.querySelector('mark[data-match-index="'.concat(w,'"]'));e&&e.scrollIntoView({behavior:"smooth",block:"center"})},100)},[w,A.length]),(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsxs)(s.Zb,{padding:"md",children:[(0,r.jsx)(s.Ol,{children:(0,r.jsxs)("div",{className:"space-y-3",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)(s.ll,{children:"Log Files"}),(0,r.jsx)(s.Ct,{variant:"gray",children:M.length})]}),(0,r.jsxs)("div",{className:"flex gap-2 flex-wrap",children:[(0,r.jsxs)(s.zx,{variant:"all"===N?"primary":"ghost",size:"sm",onClick:()=>k("all"),children:["All (",n.length,")"]}),(0,r.jsxs)(s.zx,{variant:"claude"===N?"primary":"ghost",size:"sm",onClick:()=>k("claude"),children:["Claude (",n.filter(e=>e.toLowerCase().includes("claude")).length,")"]}),(0,r.jsxs)(s.zx,{variant:"codex"===N?"primary":"ghost",size:"sm",onClick:()=>k("codex"),children:["Codex (",n.filter(e=>e.toLowerCase().includes("codex")).length,")"]}),(0,r.jsxs)(s.zx,{variant:"gemini"===N?"primary":"ghost",size:"sm",onClick:()=>k("gemini"),children:["Gemini (",n.filter(e=>e.toLowerCase().includes("gemini")).length,")"]})]})]})}),(0,r.jsxs)(s.aY,{children:[f&&0===n.length&&(0,r.jsx)("div",{className:"text-center py-4",children:(0,r.jsx)("div",{className:"inline-block animate-spin rounded-full h-6 w-6 border-4 border-gray-300 border-t-blue-600"})}),p&&(0,r.jsx)("div",{className:"p-3 bg-red-50 border border-red-200 rounded text-sm text-red-800",children:p}),!f&&0===M.length&&!p&&(0,r.jsx)("p",{className:"text-sm text-gray-600 text-center py-4",children:"all"===N?"No log files found":"No ".concat(N," log files found")}),M.length>0&&(0,r.jsx)("div",{className:"space-y-2",children:M.map(e=>(0,r.jsx)("button",{onClick:()=>T(e),className:"w-full text-left px-3 py-2 rounded text-sm font-mono transition-colors ".concat(u===e?"bg-blue-50 text-blue-700 border border-blue-200":"hover:bg-gray-50 border border-transparent"),children:e},e))})]})]}),u&&(0,r.jsxs)(s.Zb,{padding:"md",children:[(0,r.jsx)(s.Ol,{children:(0,r.jsxs)("div",{className:"flex flex-col gap-3",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)(s.ll,{className:"font-mono text-base",children:u}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(s.zx,{variant:"ghost",size:"sm",onClick:I,disabled:!u||C,title:"Copy sanitized log to clipboard",children:C?"Exporting...":"Export"}),(0,r.jsx)(s.zx,{variant:"ghost",size:"sm",onClick:()=>{x(null),h(null),v(""),j(0)},children:"Close"})]})]}),(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsxs)("div",{className:"relative flex-1",children:[(0,r.jsx)("input",{type:"text",value:y,onChange:e=>v(e.target.value),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),e.shiftKey?D():B())},placeholder:"Search in log file...",className:"input w-full pr-20"}),A.length>0&&(0,r.jsxs)("div",{className:"absolute right-2 top-1/2 -translate-y-1/2 text-xs text-gray-500",children:[w+1," / ",A.length]})]}),A.length>0&&(0,r.jsxs)("div",{className:"flex gap-1",children:[(0,r.jsx)(s.zx,{variant:"ghost",size:"sm",onClick:D,disabled:0===A.length,title:"Previous match (Shift+Enter)",children:"↑"}),(0,r.jsx)(s.zx,{variant:"ghost",size:"sm",onClick:B,disabled:0===A.length,title:"Next match (Enter)",children:"↓"})]})]})]})}),(0,r.jsxs)(s.aY,{children:[f&&(0,r.jsx)("div",{className:"text-center py-8",children:(0,r.jsx)("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-4 border-gray-300 border-t-blue-600"})}),!f&&m&&(0,r.jsx)("div",{className:"bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto max-h-[500px] scrollbar-thin",children:y&&A.length>0?(0,r.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap",dangerouslySetInnerHTML:{__html:R||""}}):(0,r.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap",children:m})}),!f&&y&&0===A.length&&m&&(0,r.jsxs)("div",{className:"text-center py-4 text-sm text-gray-500",children:['No matches found for "',y,'"']})]})]}),(0,r.jsx)(l.Ix,{toasts:E,onClose:z})]})}},6940:function(e,t,n){n.d(t,{R:function(){return x}});var r=n(57437),a=n(2265),s=n(3227);function l(e,t){if(!t.trim())return e;let n=t.toLowerCase();return e.map(e=>({...e,commands:e.commands.filter(e=>{let t=e.name.toLowerCase().includes(n),r=e.description.toLowerCase().includes(n);return t||r})})).filter(e=>e.commands.length>0)}function o(e){let{groups:t,onSelect:n,highlightedIndex:a=-1,className:s=""}=e,l=0;return 0===t.length?(0,r.jsx)("div",{className:"text-sm text-gray-500 p-4 text-center ".concat(s),children:"No commands available"}):(0,r.jsx)("div",{className:"overflow-y-auto ".concat(s),children:t.map(e=>(0,r.jsxs)("div",{className:"mb-2",children:[(0,r.jsx)("div",{className:"px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider bg-gray-50",children:e.label}),(0,r.jsx)("div",{children:e.commands.map(e=>{let t=l;l++;let s=t===a;return(0,r.jsxs)("button",{type:"button","data-command-item":!0,"data-highlighted":s,onClick:()=>n(e),className:"w-full px-3 py-2 text-left flex items-start gap-2 hover:bg-blue-50 transition-colors ".concat(s?"bg-blue-100":""),children:[(0,r.jsxs)("span",{className:"text-blue-600 font-mono text-sm flex-shrink-0",children:["/",e.name]}),(0,r.jsx)("span",{className:"text-gray-600 text-sm truncate",children:e.description})]},e.name)})})]},e.category))})}function i(e){let{isOpen:t,groups:n,onSelect:s,onClose:i,isMobile:c=!1,position:d,onFreeInput:u}=e,[x,m]=(0,a.useState)(""),[h,f]=(0,a.useState)(0),g=(0,a.useRef)(null),p=(0,a.useMemo)(()=>l(n,x),[n,x]),b=(0,a.useMemo)(()=>p.flatMap(e=>e.commands),[p]);(0,a.useEffect)(()=>{t&&(m(""),f(0),setTimeout(()=>{var e;null===(e=g.current)||void 0===e||e.focus()},50))},[t]);let y=(0,a.useCallback)(e=>{s(e),i()},[s,i]),v=(0,a.useCallback)(e=>{if(t)switch(e.key){case"Escape":e.preventDefault(),i();break;case"ArrowDown":e.preventDefault(),f(e=>Math.min(e+1,b.length-1));break;case"ArrowUp":e.preventDefault(),f(e=>Math.max(e-1,0));break;case"Enter":e.preventDefault(),b[h]&&y(b[h])}},[t,b,h,i,y]);return((0,a.useEffect)(()=>{if(t)return document.addEventListener("keydown",v),()=>{document.removeEventListener("keydown",v)}},[t,v]),t)?c?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("div",{className:"fixed inset-0 bg-black/50 z-40",onClick:i,"aria-hidden":"true"}),(0,r.jsxs)("div",{"data-testid":"slash-command-bottom-sheet",className:"fixed bottom-0 left-0 right-0 bg-white rounded-t-xl z-50 max-h-[70vh] flex flex-col shadow-xl",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 border-b border-gray-200",children:[(0,r.jsx)("h2",{className:"text-lg font-semibold",children:"Commands"}),(0,r.jsx)("button",{type:"button",onClick:i,"aria-label":"Close",className:"p-2 rounded-full hover:bg-gray-100",children:(0,r.jsx)("svg",{className:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),(0,r.jsx)("div",{className:"px-4 py-2 border-b border-gray-100",children:(0,r.jsx)("input",{ref:g,type:"text",value:x,onChange:e=>m(e.target.value),placeholder:"Search commands...",className:"w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"})}),u&&(0,r.jsxs)("button",{type:"button","data-testid":"free-input-button",onClick:()=>u(x),className:"w-full px-4 py-3 text-left border-b border-gray-100 flex items-center gap-2 hover:bg-blue-50 transition-colors",children:[(0,r.jsx)("span",{className:"text-blue-600",children:(0,r.jsx)("svg",{className:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"})})}),(0,r.jsx)("span",{className:"text-gray-600",children:"Enter custom command..."})]}),(0,r.jsx)(o,{groups:p,onSelect:y,highlightedIndex:h,className:"flex-1 overflow-y-auto pb-20"})]})]}):(0,r.jsxs)("div",{role:"listbox",className:"absolute bg-white border border-gray-200 rounded-lg shadow-lg z-50 w-80 max-h-96 flex flex-col",style:d?{top:d.top,left:d.left}:{bottom:"100%",left:0,marginBottom:"4px"},children:[(0,r.jsx)("div",{className:"px-3 py-2 border-b border-gray-100",children:(0,r.jsx)("input",{ref:g,type:"text",value:x,onChange:e=>m(e.target.value),placeholder:"Search commands...",className:"w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500"})}),u&&(0,r.jsxs)("button",{type:"button","data-testid":"free-input-button",onClick:()=>u(x),className:"w-full px-3 py-2 text-left border-b border-gray-100 flex items-center gap-2 hover:bg-blue-50 transition-colors text-sm",children:[(0,r.jsx)("span",{className:"text-blue-600",children:(0,r.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"})})}),(0,r.jsx)("span",{className:"text-gray-600",children:"Enter custom command..."})]}),(0,r.jsx)(o,{groups:p,onSelect:y,highlightedIndex:h,className:"flex-1 overflow-y-auto"}),(0,r.jsxs)("div",{className:"px-3 py-1.5 border-t border-gray-100 text-xs text-gray-400 flex gap-3",children:[(0,r.jsxs)("span",{children:[(0,r.jsx)("kbd",{className:"px-1 py-0.5 bg-gray-100 rounded",children:"Enter"})," select"]}),(0,r.jsxs)("span",{children:[(0,r.jsx)("kbd",{className:"px-1 py-0.5 bg-gray-100 rounded",children:"Esc"})," close"]})]})]}):null}function c(e){let{worktreeId:t,cliToolId:n,disabled:s=!1,onInterrupt:l}=e,[o,i]=(0,a.useState)(!1),c=(0,a.useRef)(0),u=(0,a.useCallback)(async()=>{let e=Date.now();if(!(e-c.current<1e3)){c.current=e,i(!0);try{let e=await fetch("/api/worktrees/".concat(t,"/interrupt"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cliToolId:n})});if(e.ok)null==l||l();else{let t=await e.json().catch(()=>({}));console.error("[InterruptButton] Failed to send interrupt:",t.error||e.statusText)}}catch(e){console.error("[InterruptButton] Error sending interrupt:",e)}finally{i(!1)}}},[t,n,l]);return(0,r.jsx)("button",{type:"button",onClick:u,disabled:s||o,className:"flex-shrink-0 p-2 text-orange-600 hover:bg-orange-50 rounded-full transition-colors disabled:text-gray-300 disabled:hover:bg-transparent","aria-label":"Stop processing","data-testid":"interrupt-button",children:o?(0,r.jsxs)("svg",{className:"animate-spin h-5 w-5",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,r.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,r.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}):(0,r.jsx)(d,{})})}function d(){return(0,r.jsx)("svg",{className:"h-5 w-5",fill:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2"})})}var u=n(58819);function x(e){let{worktreeId:t,onMessageSent:n,cliToolId:o,isSessionRunning:d=!1}=e,[x,m]=(0,a.useState)(""),[h,f]=(0,a.useState)(!1),[g,p]=(0,a.useState)(null),[b,y]=(0,a.useState)(!1),[v,w]=(0,a.useState)(!1),[j,N]=(0,a.useState)(!1),k=(0,a.useRef)(null),C=(0,a.useRef)(null),S=(0,a.useRef)(!1),E=(0,a.useRef)(null),L=(0,u.d)(),{groups:z}=function(e,t){let[n,r]=(0,a.useState)([]),[o,i]=(0,a.useState)(!0),[c,d]=(0,a.useState)(null),[u,x]=(0,a.useState)(""),[m,h]=(0,a.useState)(t||"claude"),f=(0,a.useCallback)(async()=>{try{i(!0),d(null);let n=e?"/api/worktrees/".concat(e,"/slash-commands"):"/api/slash-commands";t&&(n+="?cliTool=".concat(t));let a=await fetch(n);if(!a.ok)throw Error("HTTP error ".concat(a.status));let s=await a.json();r(s.groups),h(s.cliTool||t||"claude")}catch(e){d((0,s.zG)(e)),r([])}finally{i(!1)}},[e,t]);(0,a.useEffect)(()=>{f()},[f]);let g=(0,a.useMemo)(()=>n.flatMap(e=>e.commands),[n]),p=(0,a.useMemo)(()=>l(n,u),[n,u]);return{groups:n,filteredGroups:p,allCommands:g,loading:o,error:c,filter:u,setFilter:x,refresh:(0,a.useCallback)(()=>{f()},[f]),cliTool:m}}(t,o);(0,a.useEffect)(()=>{let e=k.current;e&&(x?(e.style.height="auto",e.style.height="".concat(Math.min(e.scrollHeight,160),"px")):e.style.height="24px")},[x]);let M=async()=>{if(!b&&x.trim()&&!h)try{f(!0),p(null);let e=o||"claude";await s.Iv.sendMessage(t,x.trim(),e),m(""),N(!1),null==n||n(e)}catch(e){p((0,s.zG)(e))}finally{f(!1)}},T=async e=>{e.preventDefault(),await M()},I=()=>{var e;w(!1),N(!1),null===(e=k.current)||void 0===e||e.focus()};return(0,r.jsxs)("div",{ref:E,className:"space-y-2 relative",children:[g&&(0,r.jsx)("div",{className:"p-2 bg-red-50 border border-red-200 rounded text-sm text-red-800",children:g}),(0,r.jsxs)("form",{onSubmit:T,className:"flex items-end gap-2 bg-white border border-gray-300 rounded-lg px-4 py-2 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500",children:[L&&(0,r.jsx)("button",{type:"button",onClick:()=>{j&&N(!1),w(!0)},className:"flex-shrink-0 p-2 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded-full transition-colors","aria-label":"Show slash commands","data-testid":"mobile-command-button",children:(0,r.jsx)("svg",{className:"h-5 w-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M7 20l4-16m2 16l4-16M6 9h14M4 15h14"})})}),(0,r.jsx)("textarea",{ref:k,value:x,onChange:e=>{let t=e.target.value;if(m(t),""===t){N(!1),w(!1);return}j||("/"===t||t.startsWith("/")&&!t.includes(" ")?w(!0):w(!1))},onKeyDown:e=>{let{keyCode:t}=e.nativeEvent;if(229!==t){if("Escape"===e.key&&v){e.preventDefault(),I();return}if(S.current&&"Enter"===e.key){S.current=!1;return}if("Enter"===e.key&&!b&&(!v||j)){if(L)return;e.shiftKey||(e.preventDefault(),M())}}},onCompositionStart:()=>{y(!0),S.current=!1,C.current&&clearTimeout(C.current)},onCompositionEnd:()=>{y(!1),S.current=!0,C.current&&clearTimeout(C.current),C.current=setTimeout(()=>{S.current=!1},300)},placeholder:L?"Type your message...":"Type your message... (/ for commands, Shift+Enter for line break)",disabled:h,rows:1,className:"flex-1 outline-none bg-transparent resize-none py-1 overflow-y-auto scrollbar-thin",style:{minHeight:"24px",maxHeight:"160px"}}),(0,r.jsx)(c,{worktreeId:t,cliToolId:o||"claude",disabled:!d}),(0,r.jsx)("button",{type:"submit",disabled:!x.trim()||h,className:"flex-shrink-0 p-2 text-blue-600 hover:bg-blue-50 rounded-full transition-colors disabled:text-gray-300 disabled:hover:bg-transparent","aria-label":"Send message",children:h?(0,r.jsxs)("svg",{className:"animate-spin h-5 w-5",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,r.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,r.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}):(0,r.jsx)("svg",{className:"h-5 w-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 19l9 2-9-18-9 18 9-2zm0 0v-8"})})})]}),(0,r.jsx)(i,{isOpen:v,groups:z,onSelect:e=>{var t;m("/".concat(e.name," ")),w(!1),null===(t=k.current)||void 0===t||t.focus()},onClose:I,isMobile:L,onFreeInput:e=>{w(!1),N(!0),m(e?"/".concat(e):"/"),setTimeout(()=>{var e;null===(e=k.current)||void 0===e||e.focus()},50)}})]})}},8672:function(e,t,n){n.d(t,{F4:function(){return i},Ie:function(){return d},xh:function(){return c}});let r="bg-gray-500",a="bg-green-500",s="border-blue-500",l="bg-yellow-500",o="bg-red-500",i={idle:{className:r,label:"Idle",type:"dot"},ready:{className:a,label:"Ready",type:"dot"},running:{className:s,label:"Running",type:"spinner"},waiting:{className:l,label:"Waiting for response",type:"dot"},generating:{className:s,label:"Generating",type:"spinner"}},c={idle:{className:r,label:"Idle",type:"dot"},ready:{className:a,label:"Ready",type:"dot"},running:{className:s,label:"Running",type:"spinner"},waiting:{className:l,label:"Waiting for response",type:"dot"},error:{className:o,label:"Error",type:"dot"}},d={idle:{className:r,label:"Idle - No active session",type:"dot"},ready:{className:a,label:"Ready - Waiting for input",type:"dot"},running:{className:s,label:"Running - Processing",type:"spinner"},waiting:{className:l,label:"Waiting - User input required",type:"dot"},error:{className:o,label:"Error",type:"dot"}}},3468:function(e,t,n){n.d(t,{k:function(){return r}});let r={DROPDOWN:10,SIDEBAR:30,MODAL:50,MAXIMIZED_EDITOR:55,TOAST:60,CONTEXT_MENU:70}},58819:function(e,t,n){n.d(t,{d:function(){return a}});var r=n(2265);function a(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{breakpoint:t=768}=e,[n,a]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{let e=()=>window.innerWidth<t;a(e());let n=()=>{a(e())};return window.addEventListener("resize",n),()=>{window.removeEventListener("resize",n)}},[t]),n}},32636:function(e,t,n){n.d(t,{v:function(){return a}});let r=/\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\[[0-9;]*m/g;async function a(e){if(!e||0===e.trim().length)return;let t=e.replace(r,"");await navigator.clipboard.writeText(t)}},98408:function(e,t,n){n.d(t,{G:function(){return l}});var r=n(69073),a=n(8854);let s={en:a._,ja:r.ja};function l(e){var t;return null!==(t=s[e])&&void 0!==t?t:a._}},93448:function(e,t,n){function r(e,t){let n=null;return function(){for(var r=arguments.length,a=Array(r),s=0;s<r;s++)a[s]=arguments[s];n&&clearTimeout(n),n=setTimeout(()=>{e(...a),n=null},t)}}function a(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function s(e){let t=new Set;for(let n of e){t.add(n);let e=n.split("/"),r="";for(let n=0;n<e.length-1;n++)r=r?"".concat(r,"/").concat(e[n]):e[n],t.add(r)}return t}function l(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:30;return e.length<=t?e:"".concat(e.substring(0,t-3),"...")}function o(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}n.d(t,{Ds:function(){return r},Ps:function(){return s},Xv:function(){return o},aS:function(){return l},hr:function(){return a}})},47712:function(e,t,n){function r(e){return e?e.isWaitingForResponse?"waiting":e.isProcessing?"running":e.isRunning?"ready":"idle":"idle"}function a(e){var t,n;let a=!!e.lastAssistantMessageAt&&(!e.lastViewedAt||new Date(e.lastAssistantMessageAt)>new Date(e.lastViewedAt));return{id:e.id,name:e.name,repositoryName:e.repositoryName,status:"idle",hasUnread:a,lastActivity:e.updatedAt,description:e.description,cliStatus:{claude:r(null===(t=e.sessionStatusByCli)||void 0===t?void 0:t.claude),codex:r(null===(n=e.sessionStatusByCli)||void 0===n?void 0:n.codex)}}}n.d(t,{He:function(){return r},I_:function(){return a}})}}]);
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5441],{20084:function(e,r,s){Promise.resolve().then(s.bind(s,50653))},50653:function(e,r,s){"use strict";s.r(r),s.d(r,{default:function(){return m}});var n=s(57437),t=s(2265),a=s(99376),o=s(38706),l=s(10789),c=s(53012),i=s(23260),d=s(12158);function m(){let e=(0,a.useRouter)(),r=(0,a.useParams)(),s=(0,o.T)("common"),m=r.id,x=r.path.join("/"),[u,h]=(0,t.useState)(null),[p,b]=(0,t.useState)(!0),[g,f]=(0,t.useState)(null),y=(null==u?void 0:u.extension)==="md"||(null==u?void 0:u.extension)==="markdown";return(0,t.useEffect)(()=>{(async()=>{b(!0),f(null);try{let e=await fetch("/api/worktrees/".concat(m,"/files/").concat(x));if(!e.ok){let r=await e.json();throw Error(r.error||"Failed to load file")}let r=await e.json();h(r)}catch(e){f(e instanceof Error?e.message:"Failed to load file")}finally{b(!1)}})()},[m,x]),(0,n.jsxs)("div",{className:"min-h-screen bg-gray-50",children:[(0,n.jsx)("div",{className:"sticky top-0 z-10 bg-white border-b border-gray-200 shadow-sm",children:(0,n.jsxs)("div",{className:"max-w-7xl mx-auto px-4 py-3 flex items-center gap-3",children:[(0,n.jsxs)("button",{onClick:()=>e.back(),className:"flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors","aria-label":s("back"),children:[(0,n.jsx)("svg",{className:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 19l-7-7m0 0l7-7m-7 7h18"})}),(0,n.jsx)("span",{className:"hidden sm:inline",children:s("back")})]}),(0,n.jsx)("div",{className:"flex-1 min-w-0",children:(0,n.jsx)("h1",{className:"text-lg font-semibold text-gray-900 truncate",children:x})})]})}),(0,n.jsxs)("div",{className:"max-w-7xl mx-auto px-4 py-6",children:[p&&(0,n.jsx)(l.Zb,{padding:"lg",children:(0,n.jsxs)("div",{className:"flex items-center justify-center py-12",children:[(0,n.jsx)("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-4 border-gray-300 border-t-blue-600"}),(0,n.jsx)("p",{className:"ml-3 text-gray-600",children:"Loading file..."})]})}),g&&(0,n.jsx)(l.Zb,{padding:"lg",children:(0,n.jsx)("div",{className:"bg-red-50 border border-red-200 rounded-lg p-4",children:(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("svg",{className:"w-5 h-5 text-red-600 flex-shrink-0",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})}),(0,n.jsx)("p",{className:"text-sm text-red-800",children:g})]})})}),u&&!p&&!g&&(0,n.jsxs)(l.Zb,{padding:"none",children:[(0,n.jsx)("div",{className:"bg-gray-100 px-4 py-3 border-b border-gray-200",children:(0,n.jsxs)("p",{className:"text-xs text-gray-600 font-mono break-all",children:[u.worktreePath,"/",u.path]})}),(0,n.jsx)("div",{className:"p-6 sm:p-8 bg-white",children:y?(0,n.jsx)("div",{className:"prose prose-slate max-w-none prose-headings:font-semibold prose-h1:text-3xl prose-h1:border-b prose-h1:pb-2 prose-h2:text-2xl prose-h2:border-b prose-h2:pb-2 prose-h3:text-xl prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-pre:bg-gray-100 prose-pre:border prose-pre:border-gray-200 prose-code:text-sm prose-code:bg-gray-100 prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:before:content-none prose-code:after:content-none prose-img:rounded-lg prose-img:shadow-md",children:(0,n.jsx)(c.UG,{remarkPlugins:[i.Z],rehypePlugins:[d.Z],components:{code:e=>{let{inline:r,className:s,children:t,...a}=e;return r?(0,n.jsx)("code",{className:"bg-gray-100 text-gray-800 px-1.5 py-0.5 rounded text-sm font-mono",...a,children:t}):(0,n.jsx)("code",{className:s,...a,children:t})},pre:e=>{let{children:r}=e;return(0,n.jsx)("pre",{className:"bg-gray-50 border border-gray-200 rounded-md p-4 overflow-x-auto",children:r})},table:e=>{let{children:r}=e;return(0,n.jsx)("div",{className:"overflow-x-auto",children:(0,n.jsx)("table",{className:"border-collapse border border-gray-300",children:r})})},th:e=>{let{children:r}=e;return(0,n.jsx)("th",{className:"border border-gray-300 bg-gray-100 px-4 py-2 text-left font-semibold",children:r})},td:e=>{let{children:r}=e;return(0,n.jsx)("td",{className:"border border-gray-300 px-4 py-2",children:r})},blockquote:e=>{let{children:r}=e;return(0,n.jsx)("blockquote",{className:"border-l-4 border-gray-300 pl-4 italic text-gray-700",children:r})}},children:u.content})}):(0,n.jsx)("pre",{className:"bg-gray-50 border border-gray-200 rounded-md p-4 overflow-x-auto text-sm",children:(0,n.jsx)("code",{className:"language-".concat(u.extension),children:u.content})})})]})]})]})}},98702:function(e,r,s){"use strict";s.d(r,{u:function(){return o}});var n=s(57437),t=s(2265),a=s(54887);function o(e){let{isOpen:r,onClose:s,title:o,children:l,size:c="lg",showCloseButton:i=!0,disableClose:d=!1}=e,m=(0,t.useRef)(null);return((0,t.useEffect)(()=>{if(d)return;let e=e=>{"Escape"===e.key&&r&&s()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[r,s,d]),(0,t.useEffect)(()=>(r?document.body.style.overflow="hidden":document.body.style.overflow="unset",()=>{document.body.style.overflow="unset"}),[r]),r)?(0,a.createPortal)((0,n.jsxs)("div",{className:"fixed inset-0 z-[9999] overflow-y-auto",children:[(0,n.jsx)("div",{className:"fixed inset-0 bg-black bg-opacity-50 transition-opacity",onClick:d?void 0:s}),(0,n.jsx)("div",{className:"relative flex min-h-full items-center justify-center p-2 sm:p-4",children:(0,n.jsxs)("div",{ref:m,className:"relative w-full ".concat({sm:"max-w-[calc(100vw-2rem)] sm:max-w-md",md:"max-w-[calc(100vw-2rem)] sm:max-w-2xl",lg:"max-w-[calc(100vw-2rem)] sm:max-w-4xl",xl:"max-w-[calc(100vw-2rem)] sm:max-w-6xl",full:"max-w-[calc(100vw-2rem)] sm:max-w-[95vw]"}[c]," max-h-[calc(100vh-1rem)] sm:max-h-[calc(100vh-2rem)] flex flex-col bg-white rounded-lg shadow-xl transform transition-all"),children:[(o||i)&&(0,n.jsxs)("div",{className:"flex items-center justify-between px-4 sm:px-6 py-3 sm:py-4 border-b border-gray-200 flex-shrink-0",children:[(0,n.jsx)("h3",{className:"text-base sm:text-lg font-semibold text-gray-900 truncate pr-2",children:o}),i&&(0,n.jsx)("button",{onClick:s,className:"text-gray-400 hover:text-gray-600 transition-colors flex-shrink-0",children:(0,n.jsx)("svg",{className:"w-5 h-5 sm:w-6 sm:h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,n.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),(0,n.jsx)("div",{className:"px-4 sm:px-6 py-3 sm:py-4 overflow-y-auto flex-1 min-h-0",children:l})]})})]}),document.body):null}},10789:function(e,r,s){"use strict";s.d(r,{Ct:function(){return i},zx:function(){return t},Zb:function(){return a},aY:function(){return c},Ol:function(){return o},ll:function(){return l},u_:function(){return d.u}});var n=s(57437);function t(e){let{variant:r="primary",size:s="md",fullWidth:t=!1,loading:a=!1,disabled:o,className:l="",children:c,...i}=e,d=["btn",{primary:"btn-primary",secondary:"btn-secondary",danger:"btn-danger",ghost:"bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-500"}[r],{sm:"btn-sm",md:"",lg:"btn-lg"}[s],t?"w-full":"",o||a?"opacity-50 cursor-not-allowed":"",l].filter(Boolean).join(" ");return(0,n.jsxs)("button",{className:d,disabled:o||a,...i,children:[a&&(0,n.jsxs)("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,n.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,n.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),c]})}function a(e){let{hover:r=!1,padding:s="md",className:t="",children:a,...o}=e,l=["card",r?"card-hover":"",{none:"",sm:"p-3",md:"p-4",lg:"p-6"}[s],t].filter(Boolean).join(" ");return(0,n.jsx)("div",{className:l,...o,children:a})}function o(e){let{className:r="",children:s,...t}=e;return(0,n.jsx)("div",{className:"mb-3 ".concat(r),...t,children:s})}function l(e){let{className:r="",children:s,...t}=e;return(0,n.jsx)("h3",{className:"text-lg font-semibold text-gray-900 ".concat(r),...t,children:s})}function c(e){let{className:r="",children:s,...t}=e;return(0,n.jsx)("div",{className:r,...t,children:s})}function i(e){let{variant:r="gray",dot:s=!1,className:t="",children:a,...o}=e,l=["badge",{success:"badge-success",warning:"badge-warning",error:"badge-error",info:"badge-info",gray:"badge-gray"}[r],t].filter(Boolean).join(" ");return(0,n.jsxs)("span",{className:l,...o,children:[s&&(0,n.jsx)("span",{className:"mr-1.5 inline-block h-2 w-2 rounded-full ".concat({success:"bg-green-600",warning:"bg-yellow-600",error:"bg-red-600",info:"bg-blue-600",gray:"bg-gray-600"}[r]),"aria-hidden":"true"}),a]})}s(2265);var d=s(98702)}},function(e){e.O(0,[9234,1038,2971,2117,1744],function(){return e(e.s=20084)}),_N_E=e.O()}]);