@co0ontty/wand 1.1.4 → 1.1.7

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.
@@ -435,12 +435,11 @@ export class ClaudePtyBridge extends EventEmitter {
435
435
  /\bgrant\b.*\bpermission\b/i.test(normalized) ||
436
436
  /\bhaven't granted\b/i.test(normalized) ||
437
437
  /\benter to confirm\b/i.test(normalized) ||
438
- /\bwould you like to proceed\b/i.test(normalized) ||
439
- /❯/.test(normalized));
438
+ /\bwould you like to proceed\b/i.test(normalized));
440
439
  }
441
440
  extractPromptText(normalized) {
442
441
  // Return a snippet around the permission prompt
443
- const match = normalized.match(/.{0,100}(?:do you want to|permission|grant|enter to confirm|would you like to proceed|❯).{0,100}/i);
442
+ const match = normalized.match(/.{0,100}(?:do you want to|permission|grant|enter to confirm|would you like to proceed).{0,100}/i);
444
443
  return match?.[0] ?? normalized.slice(-100);
445
444
  }
446
445
  extractPermissionTarget(normalized) {
@@ -40,8 +40,7 @@ const PROMPT_PATTERNS = [
40
40
  /\bwould you like to\b/i,
41
41
  /\bshall i\b/i,
42
42
  /\bcan i\b/i,
43
- /\bgrant\b.*\bpermission\b/i,
44
- /❯/
43
+ /\bgrant\b.*\bpermission\b/i
45
44
  ];
46
45
  const REAL_CONVERSATION_MIN_LINES = 2;
47
46
  const REAL_CONVERSATION_MIN_MESSAGES = 2;
@@ -1143,16 +1142,14 @@ export class ProcessManager extends EventEmitter {
1143
1142
  continue;
1144
1143
  const jsonlPath = path.join(getClaudeProjectDir(cwd), `${claudeSessionId}.jsonl`);
1145
1144
  try {
1146
- if (existsSync(jsonlPath)) {
1147
- unlinkSync(jsonlPath);
1148
- deleted++;
1149
- }
1145
+ unlinkSync(jsonlPath);
1146
+ deleted++;
1150
1147
  }
1151
1148
  catch {
1152
- // Best-effort — Claude cache cleanup is non-critical
1149
+ // Best-effort — file may already be gone
1153
1150
  }
1154
1151
  }
1155
- if (deleted > 0) {
1152
+ if (sessions.length > 0) {
1156
1153
  this.claudeHistoryCache = null;
1157
1154
  }
1158
1155
  return deleted;
package/dist/server.js CHANGED
@@ -481,9 +481,15 @@ export async function startServer(config, configPath) {
481
481
  res.status(500).json({ error: getErrorMessage(error, "检查更新失败。") });
482
482
  }
483
483
  });
484
+ let updateInFlight = false;
484
485
  app.post("/api/update", async (_req, res) => {
486
+ if (updateInFlight) {
487
+ res.status(409).json({ error: "更新正在进行中,请稍候。" });
488
+ return;
489
+ }
490
+ updateInFlight = true;
485
491
  try {
486
- const { updateAvailable, latest } = await checkNpmLatestVersion();
492
+ const { updateAvailable, latest } = await checkNpmLatestVersion(true);
487
493
  if (!updateAvailable) {
488
494
  res.json({ ok: true, message: "已经是最新版本。" });
489
495
  return;
@@ -494,6 +500,9 @@ export async function startServer(config, configPath) {
494
500
  catch (error) {
495
501
  res.status(500).json({ error: getErrorMessage(error, "更新失败。") });
496
502
  }
503
+ finally {
504
+ updateInFlight = false;
505
+ }
497
506
  });
498
507
  app.get("/api/sessions", (_req, res) => {
499
508
  res.json(processes.list());
@@ -165,6 +165,14 @@
165
165
  }
166
166
  }
167
167
 
168
+ function getConfigCwd() {
169
+ return (state.config && state.config.defaultCwd) || "/tmp";
170
+ }
171
+
172
+ function getEffectiveCwd() {
173
+ return state.workingDir || getConfigCwd();
174
+ }
175
+
168
176
  // PWA install prompt handling
169
177
  window.addEventListener('beforeinstallprompt', function(e) {
170
178
  e.preventDefault();
@@ -464,14 +472,14 @@
464
472
  '</div>' +
465
473
  '<div class="file-side-panel-body">' +
466
474
  '<div class="file-explorer-header">' +
467
- '<span class="file-explorer-path" id="file-explorer-cwd">' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : (state.config && state.config.defaultCwd ? state.config.defaultCwd : "")) + '</span>' +
475
+ '<span class="file-explorer-path" id="file-explorer-cwd">' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '</span>' +
468
476
  '<button class="file-explorer-refresh" id="file-explorer-refresh" title="刷新" aria-label="刷新文件列表">↻</button>' +
469
477
  '</div>' +
470
478
  '<div class="file-search-box">' +
471
479
  '<input type="text" id="file-search-input" class="file-search-input" placeholder="搜索文件..." autocomplete="off" />' +
472
480
  '<button class="file-search-clear" id="file-search-clear" type="button" aria-label="清除搜索">×</button>' +
473
481
  '</div>' +
474
- '<div class="file-explorer" id="file-explorer">' + renderFileExplorer(selectedSession && selectedSession.cwd ? selectedSession.cwd : (state.config && state.config.defaultCwd ? state.config.defaultCwd : "")) + '</div>' +
482
+ '<div class="file-explorer" id="file-explorer">' + renderFileExplorer(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '</div>' +
475
483
  '</div>' +
476
484
  '</div>' +
477
485
  '<div id="output" class="terminal-container' + (state.selectedId ? "" : " hidden") + ' active">' +
@@ -498,7 +506,7 @@
498
506
  '<div class="blank-chat-cwd-wrap">' +
499
507
  '<div class="blank-chat-cwd" id="blank-chat-cwd" role="button" tabindex="0" title="点击切换工作目录">' +
500
508
  '<span class="blank-chat-cwd-icon">📁</span>' +
501
- '<span class="blank-chat-cwd-path" id="blank-chat-cwd-path">' + escapeHtml(state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp")) + '</span>' +
509
+ '<span class="blank-chat-cwd-path" id="blank-chat-cwd-path">' + escapeHtml(getEffectiveCwd()) + '</span>' +
502
510
  '<span class="blank-chat-cwd-arrow" id="blank-chat-cwd-arrow">▼</span>' +
503
511
  '</div>' +
504
512
  '<div class="blank-chat-cwd-dropdown hidden" id="blank-chat-cwd-dropdown"></div>' +
@@ -1103,7 +1111,7 @@
1103
1111
  function updateFilePanelCwd(session) {
1104
1112
  var cwdEl = document.getElementById("file-explorer-cwd");
1105
1113
  if (!cwdEl) return;
1106
- var cwd = session && session.cwd ? session.cwd : (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
1114
+ var cwd = session && session.cwd ? session.cwd : getConfigCwd();
1107
1115
  cwdEl.textContent = cwd;
1108
1116
  }
1109
1117
 
@@ -1142,7 +1150,7 @@
1142
1150
  }
1143
1151
 
1144
1152
  function renderFileExplorer(cwd) {
1145
- var root = cwd || (state.config && state.config.defaultCwd) || "";
1153
+ var root = cwd || getConfigCwd();
1146
1154
  if (!root) {
1147
1155
  return '<div class="file-explorer empty">No working directory configured.</div>';
1148
1156
  }
@@ -1161,8 +1169,8 @@
1161
1169
  var session = state.sessions.find(function(s) { return s.id === state.selectedId; });
1162
1170
  if (session) cwd = session.cwd || "";
1163
1171
  }
1164
- if (!cwd && state.config && state.config.defaultCwd) {
1165
- cwd = state.config.defaultCwd;
1172
+ if (!cwd) {
1173
+ cwd = getConfigCwd();
1166
1174
  }
1167
1175
  if (!cwd) {
1168
1176
  explorer.innerHTML = '<div class="file-explorer empty">No working directory.</div>';
@@ -1504,7 +1512,7 @@
1504
1512
  }
1505
1513
 
1506
1514
  function renderFolderPicker(state) {
1507
- var currentDir = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp");
1515
+ var currentDir = getEffectiveCwd();
1508
1516
 
1509
1517
  // 如果有选中的会话,不显示单独的工作目录标签(已嵌入输入框内部)
1510
1518
  if (state.selectedId) {
@@ -1530,7 +1538,7 @@
1530
1538
 
1531
1539
  // 渲染内嵌到输入框的工作目录指示器
1532
1540
  function renderWorkingDirIndicator(state) {
1533
- var currentDir = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp");
1541
+ var currentDir = getEffectiveCwd();
1534
1542
  var displayDir = currentDir;
1535
1543
 
1536
1544
  // 如果有选中的会话,使用会话的工作目录
@@ -1653,7 +1661,7 @@
1653
1661
  '<div class="field">' +
1654
1662
  '<label class="field-label" for="cwd">工作目录</label>' +
1655
1663
  '<div class="suggestions-wrap">' +
1656
- '<input id="cwd" type="text" class="field-input" autocomplete="off" placeholder="' + escapeHtml(state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp")) + '" />' +
1664
+ '<input id="cwd" type="text" class="field-input" autocomplete="off" placeholder="' + escapeHtml(getEffectiveCwd()) + '" />' +
1657
1665
  '<div id="cwd-suggestions" class="suggestions hidden"></div>' +
1658
1666
  '</div>' +
1659
1667
  '<p class="field-hint">留空则使用上方目录,支持路径自动补全。</p>' +
@@ -2221,7 +2229,7 @@
2221
2229
 
2222
2230
  if (folderPickerInput) {
2223
2231
  // Load initial folders from saved or default path
2224
- var initialPath = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp");
2232
+ var initialPath = getEffectiveCwd();
2225
2233
  loadFolderSuggestions(initialPath);
2226
2234
 
2227
2235
  folderPickerInput.addEventListener("focus", function() {
@@ -2397,16 +2405,14 @@
2397
2405
  folderPickerModal.classList.remove("hidden");
2398
2406
  // Set initial path in input
2399
2407
  if (folderPickerInput) {
2400
- folderPickerInput.value = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp");
2408
+ folderPickerInput.value = getEffectiveCwd();
2401
2409
  }
2402
2410
  // Load initial folders
2403
- var initialPath = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp");
2411
+ var initialPath = getEffectiveCwd();
2404
2412
  loadFolderSuggestions(initialPath);
2405
2413
  renderBreadcrumb(initialPath);
2406
2414
  }
2407
2415
 
2408
- // Welcome screen folder button (legacy, now handled by initBlankChatCwd)
2409
-
2410
2416
  if (closeFolderPicker && folderPickerModal) {
2411
2417
  closeFolderPicker.addEventListener("click", function() {
2412
2418
  folderPickerModal.classList.add("hidden");
@@ -2426,6 +2432,16 @@
2426
2432
  setupVisualViewportHandlers();
2427
2433
  }
2428
2434
 
2435
+ function activateSessionItem(sessionId) {
2436
+ var session = state.sessions.find(function(s) { return s.id === sessionId; });
2437
+ if (session && session.status !== "running") {
2438
+ resumeSessionFromList(sessionId);
2439
+ } else {
2440
+ selectSession(sessionId);
2441
+ }
2442
+ closeSessionsDrawer();
2443
+ }
2444
+
2429
2445
  function handleSessionItemClick(event) {
2430
2446
  var target = event.target;
2431
2447
  if (!target || !(target instanceof Element)) return;
@@ -2502,13 +2518,22 @@
2502
2518
  }
2503
2519
  if (_swipeState) return;
2504
2520
  if (item.dataset.sessionId) {
2505
- var clickedSession = state.sessions.find(function(s) { return s.id === item.dataset.sessionId; });
2506
- if (clickedSession && clickedSession.status !== "running") {
2507
- resumeSessionFromList(item.dataset.sessionId);
2508
- } else {
2509
- selectSession(item.dataset.sessionId);
2510
- }
2511
- closeSessionsDrawer();
2521
+ activateSessionItem(item.dataset.sessionId);
2522
+ } else if (item.dataset.claudeHistoryId) {
2523
+ var claudeSessionId = item.dataset.claudeHistoryId;
2524
+ var cwd = item.dataset.cwd;
2525
+ resumeClaudeHistorySession(claudeSessionId, cwd)
2526
+ .then(function(data) {
2527
+ if (data && data.id) {
2528
+ state.selectedId = data.id;
2529
+ persistSelectedId();
2530
+ state.drafts[data.id] = "";
2531
+ loadSessions().then(function() {
2532
+ selectSession(data.id);
2533
+ closeSessionsDrawer();
2534
+ });
2535
+ }
2536
+ });
2512
2537
  }
2513
2538
  }
2514
2539
  }
@@ -2527,13 +2552,22 @@
2527
2552
  return;
2528
2553
  }
2529
2554
  if (item.dataset.sessionId) {
2530
- var keySession = state.sessions.find(function(s) { return s.id === item.dataset.sessionId; });
2531
- if (keySession && keySession.status !== "running") {
2532
- resumeSessionFromList(item.dataset.sessionId);
2533
- } else {
2534
- selectSession(item.dataset.sessionId);
2535
- }
2536
- closeSessionsDrawer();
2555
+ activateSessionItem(item.dataset.sessionId);
2556
+ } else if (item.dataset.claudeHistoryId) {
2557
+ var claudeSessionId = item.dataset.claudeHistoryId;
2558
+ var cwd = item.dataset.cwd;
2559
+ resumeClaudeHistorySession(claudeSessionId, cwd)
2560
+ .then(function(data) {
2561
+ if (data && data.id) {
2562
+ state.selectedId = data.id;
2563
+ persistSelectedId();
2564
+ state.drafts[data.id] = "";
2565
+ loadSessions().then(function() {
2566
+ selectSession(data.id);
2567
+ closeSessionsDrawer();
2568
+ });
2569
+ }
2570
+ });
2537
2571
  }
2538
2572
  }
2539
2573
 
@@ -2968,15 +3002,9 @@
2968
3002
  state.terminalViewportSize = { width: 0, height: 0 };
2969
3003
  state.terminalAutoFollow = true;
2970
3004
  clearTerminalScrollIdleTimer();
2971
- // Double-rAF: wait for browser to complete layout before measuring and fitting
3005
+ // Retry-based fit: wait for browser to complete layout before measuring and fitting
2972
3006
  if (state.fitAddon) {
2973
- requestAnimationFrame(function() {
2974
- requestAnimationFrame(function() {
2975
- if (state.fitAddon && shouldResizeTerminalViewport()) {
2976
- state.fitAddon.fit();
2977
- }
2978
- });
2979
- });
3007
+ ensureTerminalFit();
2980
3008
  }
2981
3009
 
2982
3010
  var viewport = getTerminalViewport();
@@ -3403,7 +3431,7 @@
3403
3431
  updateShellChrome();
3404
3432
 
3405
3433
  var selectedSession = state.sessions.find(function(s) { return s.id === id; });
3406
- state.currentMessages = [];
3434
+ state.currentMessages = data.messages || [];
3407
3435
 
3408
3436
  if (state.terminal) {
3409
3437
  syncTerminalBuffer(id, data.output || "", { mode: "replace" });
@@ -3849,7 +3877,8 @@
3849
3877
  function performUpdate() {
3850
3878
  var msgEl = document.getElementById("update-message");
3851
3879
  var updateBtn = document.getElementById("do-update-button");
3852
- if (updateBtn) updateBtn.disabled = true;
3880
+ if (!updateBtn) return;
3881
+ updateBtn.disabled = true;
3853
3882
  if (msgEl) {
3854
3883
  msgEl.textContent = "正在更新,请稍候...";
3855
3884
  msgEl.style.color = "var(--text-secondary)";
@@ -3869,9 +3898,9 @@
3869
3898
  msgEl.classList.remove("hidden");
3870
3899
  }
3871
3900
  if (data.error) {
3872
- if (updateBtn) updateBtn.disabled = false;
3901
+ updateBtn.disabled = false;
3873
3902
  } else {
3874
- if (updateBtn) updateBtn.classList.add("hidden");
3903
+ updateBtn.classList.add("hidden");
3875
3904
  }
3876
3905
  })
3877
3906
  .catch(function() {
@@ -3880,13 +3909,13 @@
3880
3909
  msgEl.style.color = "var(--error)";
3881
3910
  msgEl.classList.remove("hidden");
3882
3911
  }
3883
- if (updateBtn) updateBtn.disabled = false;
3912
+ updateBtn.disabled = false;
3884
3913
  });
3885
3914
  }
3886
3915
 
3887
3916
  function quickStartSession() {
3888
3917
  var command = getPreferredTool();
3889
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
3918
+ var defaultCwd = getEffectiveCwd();
3890
3919
  var defaultMode = (state.config && state.config.defaultMode) ? state.config.defaultMode : "default";
3891
3920
  state.preferredCommand = command;
3892
3921
  state.chatMode = getSafeModeForTool(command, state.chatMode);
@@ -3923,7 +3952,7 @@
3923
3952
 
3924
3953
  hideError(errorEl);
3925
3954
 
3926
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
3955
+ var defaultCwd = getEffectiveCwd();
3927
3956
  var selectedMode = getSafeModeForTool(command, state.modeValue);
3928
3957
  state.modeValue = selectedMode;
3929
3958
  state.chatMode = selectedMode;
@@ -4001,7 +4030,7 @@
4001
4030
  }
4002
4031
 
4003
4032
  function loadBlankChatCwdDropdown(dropdown) {
4004
- var defaultCwd = state.config && state.config.defaultCwd ? state.config.defaultCwd : "/tmp";
4033
+ var defaultCwd = getConfigCwd();
4005
4034
  dropdown.innerHTML = '<div class="blank-chat-cwd-loading">加载中...</div>';
4006
4035
  fetch("/api/recent-paths", { credentials: "same-origin" })
4007
4036
  .then(function(res) { return res.json(); })
@@ -4359,7 +4388,7 @@
4359
4388
  welcomeInput.placeholder = "正在启动会话...";
4360
4389
  welcomeInput.disabled = true;
4361
4390
  var mode = state.chatMode || "full-access";
4362
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
4391
+ var defaultCwd = getEffectiveCwd();
4363
4392
  var preferredTool = getPreferredTool();
4364
4393
  fetch("/api/commands", {
4365
4394
  method: "POST",
@@ -4421,7 +4450,7 @@
4421
4450
 
4422
4451
  // No selected session, create a new one
4423
4452
  var mode = state.chatMode || "full-access";
4424
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
4453
+ var defaultCwd = getEffectiveCwd();
4425
4454
  var preferredTool = getPreferredTool();
4426
4455
  fetch("/api/commands", {
4427
4456
  method: "POST",
@@ -4488,9 +4517,8 @@
4488
4517
  // Init terminal if not already done
4489
4518
  if (!state.terminal) initTerminal();
4490
4519
  applyCurrentView();
4491
- if (state.currentView === "terminal") {
4492
- state.terminalViewportSize = { width: 0, height: 0 };
4493
- scheduleTerminalResize(true);
4520
+ if (state.terminal && state.fitAddon) {
4521
+ ensureTerminalFit();
4494
4522
  }
4495
4523
  // Don't call renderChat() here — loadOutput() always calls renderChat() after it resolves.
4496
4524
  // Calling renderChat() prematurely would render with stale/empty messages.
@@ -5375,7 +5403,7 @@
5375
5403
  welcomeInput.placeholder = "Claude 正在思考,请稍候...";
5376
5404
  welcomeInput.disabled = true;
5377
5405
  var mode = state.chatMode || "full-access";
5378
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
5406
+ var defaultCwd = getEffectiveCwd();
5379
5407
  var preferredTool = getPreferredTool();
5380
5408
  fetch("/api/commands", {
5381
5409
  method: "POST",
@@ -5411,7 +5439,7 @@
5411
5439
 
5412
5440
  function createSessionFromInput(value, inputBox, welcomeInput) {
5413
5441
  var mode = state.chatMode || "full-access";
5414
- var defaultCwd = state.workingDir || (state.config && state.config.defaultCwd ? state.config.defaultCwd : "");
5442
+ var defaultCwd = getEffectiveCwd();
5415
5443
  var preferredTool = getPreferredTool();
5416
5444
  fetch("/api/commands", {
5417
5445
  method: "POST",
@@ -6458,6 +6486,34 @@
6458
6486
  updateTerminalJumpToBottomButton();
6459
6487
  }
6460
6488
 
6489
+ function ensureTerminalFit() {
6490
+ var maxAttempts = 10;
6491
+ var attempt = 0;
6492
+ function tryFit() {
6493
+ attempt++;
6494
+ state.terminalViewportSize = { width: 0, height: 0 };
6495
+ if (shouldResizeTerminalViewport() && state.fitAddon) {
6496
+ state.fitAddon.fit();
6497
+ maybeScrollTerminalToBottom("resize");
6498
+ if (state.selectedId && state.terminal) {
6499
+ var nextSize = { cols: state.terminal.cols, rows: state.terminal.rows };
6500
+ if (state.lastResize.cols !== nextSize.cols || state.lastResize.rows !== nextSize.rows) {
6501
+ state.lastResize = nextSize;
6502
+ fetch("/api/sessions/" + state.selectedId + "/resize", {
6503
+ method: "POST",
6504
+ headers: { "Content-Type": "application/json" },
6505
+ credentials: "same-origin",
6506
+ body: JSON.stringify(nextSize)
6507
+ }).catch(function() {});
6508
+ }
6509
+ }
6510
+ } else if (attempt < maxAttempts) {
6511
+ requestAnimationFrame(tryFit);
6512
+ }
6513
+ }
6514
+ requestAnimationFrame(tryFit);
6515
+ }
6516
+
6461
6517
  function scheduleTerminalResize(immediate) {
6462
6518
  if (state.resizeTimer) {
6463
6519
  clearTimeout(state.resizeTimer);
@@ -6583,7 +6639,11 @@
6583
6639
  }
6584
6640
  updateSessionSnapshot(snapshot);
6585
6641
  if (msg.sessionId === state.selectedId) {
6642
+ if (msg.data.messages) {
6643
+ state.currentMessages = msg.data.messages;
6644
+ }
6586
6645
  updateTaskDisplay();
6646
+ scheduleChatRender();
6587
6647
  }
6588
6648
 
6589
6649
  }
@@ -6652,6 +6712,8 @@
6652
6712
  if (msg.sessionId === state.selectedId && msg.data) {
6653
6713
  if (chatRenderTimer) { clearTimeout(chatRenderTimer); chatRenderTimer = null; }
6654
6714
  updateTerminalOutput(msg.data.output || "", msg.sessionId, "replace");
6715
+ // Ensure terminal is properly fitted after receiving initial data
6716
+ scheduleTerminalResize(true);
6655
6717
  }
6656
6718
  break;
6657
6719
  case 'usage':
@@ -6710,10 +6772,10 @@
6710
6772
  }
6711
6773
  }
6712
6774
  if (permissionActionsEl) permissionActionsEl.classList.remove("hidden");
6713
- // Also show in task bar
6714
- taskEl.textContent = pendingEscalation ? (pendingEscalation.reason || "等待 Claude 权限授权") : "等待 Claude 权限授权";
6715
- taskEl.classList.remove("hidden");
6716
- taskEl.classList.add("permission-blocked");
6775
+ // Hide top task bar — permission info is already shown in the composer
6776
+ taskEl.textContent = "";
6777
+ taskEl.classList.add("hidden");
6778
+ taskEl.classList.remove("permission-blocked");
6717
6779
  return;
6718
6780
  }
6719
6781
 
@@ -1529,15 +1529,6 @@
1529
1529
  flex-shrink: 0;
1530
1530
  animation: task-pulse 1.2s ease-in-out infinite;
1531
1531
  }
1532
- .current-task.permission-blocked {
1533
- color: #d18b00;
1534
- background: rgba(240, 165, 0, 0.14);
1535
- border-color: rgba(240, 165, 0, 0.3);
1536
- }
1537
- .current-task.permission-blocked::before {
1538
- background: #f0a500;
1539
- animation: none;
1540
- }
1541
1532
  @keyframes task-pulse {
1542
1533
  0%, 100% { opacity: 1; transform: scale(1); }
1543
1534
  50% { opacity: 0.5; transform: scale(0.8); }
@@ -1559,8 +1550,8 @@
1559
1550
  padding: 10px;
1560
1551
  overflow: hidden;
1561
1552
  min-height: 0;
1562
- margin: 0 10px 10px;
1563
- border-radius: var(--radius-lg);
1553
+ margin: 0 6px 6px;
1554
+ border-radius: var(--radius-md);
1564
1555
  border: 1px solid rgba(140, 110, 85, 0.35);
1565
1556
  box-shadow:
1566
1557
  inset 0 1px 0 rgba(255, 255, 255, 0.06),
@@ -4861,7 +4852,7 @@
4861
4852
  width: min(300px, calc(100vw - 20px));
4862
4853
  top: 0;
4863
4854
  }
4864
- .terminal-container { margin: 0 12px 12px; min-height: 0; }
4855
+ .terminal-container { margin: 0 6px 6px; min-height: 0; }
4865
4856
  .btn { min-height: 40px; }
4866
4857
  .btn-sm { min-height: 36px; padding: 0 10px; font-size: 0.75rem; height: 36px; }
4867
4858
  .btn-icon { width: 36px; height: 36px; min-height: 36px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "1.1.4",
3
+ "version": "1.1.7",
4
4
  "description": "A web terminal for local CLI tools like Claude.",
5
5
  "type": "module",
6
6
  "bin": {