claude-remote-cli 2.2.0 → 2.2.2

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.
@@ -47,3 +47,12 @@ export function writeMeta(configPath, meta) {
47
47
  ensureMetaDir(configPath);
48
48
  fs.writeFileSync(fp, JSON.stringify(meta, null, 2), 'utf8');
49
49
  }
50
+ export function deleteMeta(configPath, worktreePath) {
51
+ const fp = metaFilePath(configPath, worktreePath);
52
+ try {
53
+ fs.unlinkSync(fp);
54
+ }
55
+ catch (_) {
56
+ // File may not exist; ignore
57
+ }
58
+ }
@@ -8,7 +8,7 @@ import { execFile } from 'node:child_process';
8
8
  import { promisify } from 'node:util';
9
9
  import express from 'express';
10
10
  import cookieParser from 'cookie-parser';
11
- import { loadConfig, saveConfig, DEFAULTS, readMeta, writeMeta, ensureMetaDir } from './config.js';
11
+ import { loadConfig, saveConfig, DEFAULTS, readMeta, writeMeta, deleteMeta, ensureMetaDir } from './config.js';
12
12
  import * as auth from './auth.js';
13
13
  import * as sessions from './sessions.js';
14
14
  import { setupWebSocket } from './ws.js';
@@ -340,8 +340,18 @@ async function main() {
340
340
  await execFileAsync('git', ['worktree', 'remove', worktreePath], { cwd: repoPath });
341
341
  }
342
342
  catch (err) {
343
- res.status(500).json({ error: execErrorMessage(err, 'Failed to remove worktree') });
344
- return;
343
+ // If git worktree remove fails, the directory may be an orphaned worktree
344
+ // that git no longer tracks. Try to remove the directory directly.
345
+ if (fs.existsSync(worktreePath)) {
346
+ try {
347
+ fs.rmSync(worktreePath, { recursive: true });
348
+ }
349
+ catch (rmErr) {
350
+ res.status(500).json({ error: execErrorMessage(rmErr, 'Failed to remove worktree directory') });
351
+ return;
352
+ }
353
+ }
354
+ // If directory doesn't exist, the worktree is already gone — continue to cleanup
345
355
  }
346
356
  try {
347
357
  // Prune stale worktree refs
@@ -359,6 +369,8 @@ async function main() {
359
369
  // Non-fatal: branch may not exist or may be checked out elsewhere
360
370
  }
361
371
  }
372
+ // Clean up metadata file
373
+ deleteMeta(CONFIG_PATH, worktreePath);
362
374
  res.json({ ok: true });
363
375
  });
364
376
  // POST /sessions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-remote-cli",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "Remote web interface for Claude Code CLI sessions",
5
5
  "type": "module",
6
6
  "main": "dist/server/index.js",
package/public/app.js CHANGED
@@ -1356,6 +1356,22 @@
1356
1356
  if (e.key === 'Enter') addRootBtn.click();
1357
1357
  });
1358
1358
 
1359
+ var settingsDevtools = document.getElementById('settings-devtools');
1360
+
1361
+ // Initialize developer tools toggle from localStorage
1362
+ var devtoolsEnabled = localStorage.getItem('devtools-enabled') === 'true';
1363
+ settingsDevtools.checked = devtoolsEnabled;
1364
+
1365
+ settingsDevtools.addEventListener('change', function () {
1366
+ devtoolsEnabled = settingsDevtools.checked;
1367
+ localStorage.setItem('devtools-enabled', devtoolsEnabled ? 'true' : 'false');
1368
+ // Update debug toggle visibility immediately
1369
+ var debugToggle = document.getElementById('debug-toggle');
1370
+ if (debugToggle) {
1371
+ debugToggle.style.display = devtoolsEnabled ? '' : 'none';
1372
+ }
1373
+ });
1374
+
1359
1375
  settingsClose.addEventListener('click', function () {
1360
1376
  settingsDialog.close();
1361
1377
  loadRepos();
@@ -1565,6 +1581,10 @@
1565
1581
  debugToggle.id = 'debug-toggle';
1566
1582
  debugToggle.textContent = 'dbg';
1567
1583
  debugToggle.style.cssText = 'position:fixed;bottom:60px;right:8px;z-index:10000;background:#333;color:#0f0;border:1px solid #0f0;border-radius:6px;font:12px monospace;padding:6px 10px;opacity:0.5;min-width:44px;min-height:44px;';
1584
+ // Hide debug toggle unless developer tools are enabled in settings
1585
+ if (localStorage.getItem('devtools-enabled') !== 'true') {
1586
+ debugToggle.style.display = 'none';
1587
+ }
1568
1588
  document.body.appendChild(debugToggle);
1569
1589
 
1570
1590
  var debugVisible = false;
@@ -1724,6 +1744,24 @@
1724
1744
  mobileInput.flushComposedText = flushComposedText;
1725
1745
  mobileInput.clearInput = clearInput;
1726
1746
 
1747
+ // ── Form submit handler for reliable Enter on mobile ──
1748
+ // On Android Chrome with Gboard, keydown fires with key="Unidentified" and
1749
+ // keyCode=229 during active composition/prediction (which is nearly always).
1750
+ // Wrapping the input in a <form> ensures the browser fires a "submit" event
1751
+ // when Enter is pressed, regardless of composition state.
1752
+ var inputForm = document.getElementById('mobile-input-form');
1753
+ if (inputForm) {
1754
+ inputForm.addEventListener('submit', function (e) {
1755
+ e.preventDefault();
1756
+ dbg('FORM_SUBMIT composing=' + isComposing + ' val="' + mobileInput.value + '"');
1757
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
1758
+ flushComposedText();
1759
+ ws.send('\r');
1760
+ mobileInput.value = '';
1761
+ lastInputValue = '';
1762
+ });
1763
+ }
1764
+
1727
1765
  // Handle text input with autocorrect
1728
1766
  var clearTimer = null;
1729
1767
  mobileInput.addEventListener('beforeinput', function (e) {
package/public/index.html CHANGED
@@ -70,7 +70,9 @@
70
70
  <button id="menu-btn" class="icon-btn" aria-label="Open sessions menu">&#9776;</button>
71
71
  <span id="session-title" class="mobile-title">No session</span>
72
72
  </div>
73
- <input type="text" id="mobile-input" dir="ltr" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-label="Terminal input" />
73
+ <form id="mobile-input-form" action="javascript:void(0)">
74
+ <input type="text" id="mobile-input" dir="ltr" autocomplete="off" enterkeyhint="send" aria-label="Terminal input" />
75
+ </form>
74
76
  <div id="terminal-container"></div>
75
77
  <div id="terminal-scrollbar"><div id="terminal-scrollbar-thumb"></div></div>
76
78
  <div id="no-session-msg">No active session. Create or select a session to begin.</div>
@@ -182,6 +184,13 @@
182
184
  <button id="add-root-btn" class="btn-accent">Add</button>
183
185
  </div>
184
186
  </div>
187
+ <div class="settings-section">
188
+ <label class="settings-label">Developer</label>
189
+ <label class="settings-checkbox">
190
+ <input type="checkbox" id="settings-devtools" />
191
+ <span>Show developer tools button</span>
192
+ </label>
193
+ </div>
185
194
  <div class="dialog-actions">
186
195
  <button id="settings-close">Done</button>
187
196
  </div>
package/public/style.css CHANGED
@@ -931,6 +931,26 @@ dialog#settings-dialog h2 {
931
931
  margin-bottom: 1rem;
932
932
  }
933
933
 
934
+ .settings-checkbox {
935
+ display: flex;
936
+ align-items: center;
937
+ gap: 8px;
938
+ font-size: 0.85rem;
939
+ color: var(--text);
940
+ cursor: pointer;
941
+ }
942
+
943
+ .settings-checkbox input[type="checkbox"] {
944
+ width: 18px;
945
+ height: 18px;
946
+ accent-color: var(--accent);
947
+ cursor: pointer;
948
+ }
949
+
950
+ #mobile-input-form {
951
+ display: contents;
952
+ }
953
+
934
954
  .btn-accent {
935
955
  background: var(--accent) !important;
936
956
  border-color: var(--accent) !important;