claw-design 1.0.1

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/cli/commands/start.d.ts +7 -0
  4. package/dist/cli/commands/start.d.ts.map +1 -0
  5. package/dist/cli/commands/start.js +176 -0
  6. package/dist/cli/commands/start.js.map +1 -0
  7. package/dist/cli/index.d.ts +3 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +20 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/utils/claude.d.ts +21 -0
  12. package/dist/cli/utils/claude.d.ts.map +1 -0
  13. package/dist/cli/utils/claude.js +42 -0
  14. package/dist/cli/utils/claude.js.map +1 -0
  15. package/dist/cli/utils/dev-server.d.ts +14 -0
  16. package/dist/cli/utils/dev-server.d.ts.map +1 -0
  17. package/dist/cli/utils/dev-server.js +57 -0
  18. package/dist/cli/utils/dev-server.js.map +1 -0
  19. package/dist/cli/utils/electron.d.ts +7 -0
  20. package/dist/cli/utils/electron.d.ts.map +1 -0
  21. package/dist/cli/utils/electron.js +36 -0
  22. package/dist/cli/utils/electron.js.map +1 -0
  23. package/dist/cli/utils/output.d.ts +6 -0
  24. package/dist/cli/utils/output.d.ts.map +1 -0
  25. package/dist/cli/utils/output.js +21 -0
  26. package/dist/cli/utils/output.js.map +1 -0
  27. package/dist/cli/utils/port-detect.d.ts +30 -0
  28. package/dist/cli/utils/port-detect.d.ts.map +1 -0
  29. package/dist/cli/utils/port-detect.js +95 -0
  30. package/dist/cli/utils/port-detect.js.map +1 -0
  31. package/dist/cli/utils/preflight.d.ts +20 -0
  32. package/dist/cli/utils/preflight.d.ts.map +1 -0
  33. package/dist/cli/utils/preflight.js +33 -0
  34. package/dist/cli/utils/preflight.js.map +1 -0
  35. package/dist/cli/utils/process.d.ts +23 -0
  36. package/dist/cli/utils/process.d.ts.map +1 -0
  37. package/dist/cli/utils/process.js +57 -0
  38. package/dist/cli/utils/process.js.map +1 -0
  39. package/out/main/index.js +1123 -0
  40. package/out/preload/overlay.cjs +56 -0
  41. package/out/preload/sidebar.cjs +29 -0
  42. package/out/renderer/assets/overlay-Bsx1u_qg.css +449 -0
  43. package/out/renderer/assets/overlay-DZl3I3jq.js +689 -0
  44. package/out/renderer/assets/sidebar-Bt34gvPU.js +563 -0
  45. package/out/renderer/assets/sidebar-BxEPS84k.css +515 -0
  46. package/out/renderer/assets/toast-CLlgwMU_.js +110 -0
  47. package/out/renderer/overlay.html +131 -0
  48. package/out/renderer/sidebar.html +64 -0
  49. package/package.json +67 -0
  50. package/resources/icon.icns +0 -0
  51. package/resources/icon.png +0 -0
  52. package/scripts/postinstall.cjs +56 -0
@@ -0,0 +1,563 @@
1
+ const INITIAL_SIDEBAR_STATE = {
2
+ visual: "hidden",
3
+ tasks: /* @__PURE__ */ new Map(),
4
+ autoExpandTimerId: null,
5
+ selectionModeActive: false
6
+ };
7
+ function computeBadge(tasks) {
8
+ let completed = 0;
9
+ let total = 0;
10
+ for (const task of tasks.values()) {
11
+ total++;
12
+ if (task.status === "done" || task.status === "error") {
13
+ completed++;
14
+ }
15
+ }
16
+ return { completed, total, text: `${completed}/${total}` };
17
+ }
18
+ function sidebarTransition(state2, event) {
19
+ const noEffect = { shouldAutoExpand: false, shouldPulse: null };
20
+ switch (event.type) {
21
+ case "TASK_ADDED": {
22
+ const newTasks = new Map(state2.tasks);
23
+ newTasks.set(event.task.id, event.task);
24
+ if (state2.visual === "hidden") {
25
+ return {
26
+ state: { ...state2, visual: "minimized", tasks: newTasks },
27
+ shouldAutoExpand: true,
28
+ shouldPulse: null
29
+ };
30
+ }
31
+ if (state2.visual === "minimized") {
32
+ return {
33
+ state: { ...state2, tasks: newTasks },
34
+ shouldAutoExpand: true,
35
+ shouldPulse: null
36
+ };
37
+ }
38
+ return {
39
+ state: { ...state2, tasks: newTasks },
40
+ ...noEffect
41
+ };
42
+ }
43
+ case "TASK_UPDATED": {
44
+ const newTasks = new Map(state2.tasks);
45
+ newTasks.set(event.task.id, event.task);
46
+ const isTerminal = event.task.status === "done" || event.task.status === "error";
47
+ const pulse = isTerminal && state2.visual === "minimized" ? event.task.status === "error" ? "error" : "done" : null;
48
+ return {
49
+ state: { ...state2, tasks: newTasks },
50
+ shouldAutoExpand: false,
51
+ shouldPulse: pulse
52
+ };
53
+ }
54
+ case "TASK_DISMISSED": {
55
+ const newTasks = new Map(state2.tasks);
56
+ newTasks.delete(event.id);
57
+ if (newTasks.size === 0) {
58
+ return {
59
+ state: { ...state2, visual: "hidden", tasks: newTasks },
60
+ ...noEffect
61
+ };
62
+ }
63
+ return {
64
+ state: { ...state2, tasks: newTasks },
65
+ ...noEffect
66
+ };
67
+ }
68
+ case "EXPAND": {
69
+ if (state2.visual === "minimized") {
70
+ return {
71
+ state: { ...state2, visual: "expanded" },
72
+ ...noEffect
73
+ };
74
+ }
75
+ return { state: state2, ...noEffect };
76
+ }
77
+ case "COLLAPSE": {
78
+ if (state2.visual === "expanded") {
79
+ return {
80
+ state: { ...state2, visual: "minimized" },
81
+ ...noEffect
82
+ };
83
+ }
84
+ return { state: state2, ...noEffect };
85
+ }
86
+ case "SELECTION_MODE_ACTIVE": {
87
+ if (state2.visual === "expanded") {
88
+ return {
89
+ state: {
90
+ ...state2,
91
+ visual: "minimized",
92
+ selectionModeActive: true
93
+ },
94
+ ...noEffect
95
+ };
96
+ }
97
+ return {
98
+ state: { ...state2, selectionModeActive: true },
99
+ ...noEffect
100
+ };
101
+ }
102
+ case "SELECTION_MODE_INACTIVE": {
103
+ return {
104
+ state: { ...state2, selectionModeActive: false },
105
+ ...noEffect
106
+ };
107
+ }
108
+ case "AUTO_EXPAND_TIMEOUT": {
109
+ if (state2.visual === "expanded") {
110
+ return {
111
+ state: { ...state2, visual: "minimized" },
112
+ ...noEffect
113
+ };
114
+ }
115
+ return { state: state2, ...noEffect };
116
+ }
117
+ default:
118
+ return { state: state2, ...noEffect };
119
+ }
120
+ }
121
+ let state = { ...INITIAL_SIDEBAR_STATE, tasks: /* @__PURE__ */ new Map() };
122
+ const expandedLogs = /* @__PURE__ */ new Set();
123
+ const taskTimers = /* @__PURE__ */ new Map();
124
+ function formatElapsed(ms) {
125
+ const totalSec = Math.floor(ms / 1e3);
126
+ if (totalSec < 60) return `${totalSec}s`;
127
+ const min = Math.floor(totalSec / 60);
128
+ const sec = totalSec % 60;
129
+ return `${min}m ${sec.toString().padStart(2, "0")}s`;
130
+ }
131
+ function startTaskTimer(taskId) {
132
+ if (taskTimers.has(taskId)) return;
133
+ const startTime = Date.now();
134
+ const intervalId = setInterval(() => {
135
+ const el = document.querySelector(`[data-task-id="${taskId}"] .task-timer`);
136
+ if (el) el.textContent = formatElapsed(Date.now() - startTime);
137
+ }, 1e3);
138
+ taskTimers.set(taskId, { startTime, intervalId });
139
+ }
140
+ function stopTaskTimer(taskId) {
141
+ const timer = taskTimers.get(taskId);
142
+ if (!timer) return;
143
+ clearInterval(timer.intervalId);
144
+ const el = document.querySelector(`[data-task-id="${taskId}"] .task-timer`);
145
+ if (el) el.textContent = formatElapsed(Date.now() - timer.startTime);
146
+ taskTimers.delete(taskId);
147
+ }
148
+ function shortModelName(model) {
149
+ if (model.includes("opus")) return "Opus";
150
+ if (model.includes("sonnet")) return "Sonnet";
151
+ if (model.includes("haiku")) return "Haiku";
152
+ return model.replace(/^claude-/, "").replace(/-\d{8}$/, "");
153
+ }
154
+ const STATUS_LABELS = {
155
+ queued: "Queued",
156
+ sending: "Sending",
157
+ editing: "Editing",
158
+ done: "Done",
159
+ error: "Error"
160
+ };
161
+ let minimizedEl;
162
+ let expandedEl;
163
+ let expandBtn;
164
+ let minimizeBtn;
165
+ let taskListEl;
166
+ let badgeEl;
167
+ let badgeTextEl;
168
+ const SVG_NS = "http://www.w3.org/2000/svg";
169
+ function createDismissSvg() {
170
+ const svg = document.createElementNS(SVG_NS, "svg");
171
+ svg.setAttribute("width", "12");
172
+ svg.setAttribute("height", "12");
173
+ svg.setAttribute("viewBox", "0 0 12 12");
174
+ svg.setAttribute("fill", "none");
175
+ const path = document.createElementNS(SVG_NS, "path");
176
+ path.setAttribute("d", "M2 2L10 10M10 2L2 10");
177
+ path.setAttribute("stroke", "currentColor");
178
+ path.setAttribute("stroke-width", "1.5");
179
+ path.setAttribute("stroke-linecap", "round");
180
+ svg.appendChild(path);
181
+ return svg;
182
+ }
183
+ function renderTask(task) {
184
+ const existingRow = taskListEl.querySelector(
185
+ `[data-task-id="${task.id}"]`
186
+ );
187
+ if (existingRow) {
188
+ updateTaskRow(existingRow, task);
189
+ } else {
190
+ const row = createTaskRow(task);
191
+ taskListEl.prepend(row);
192
+ }
193
+ }
194
+ function createTaskRow(task) {
195
+ const row = document.createElement("div");
196
+ row.className = "task-row";
197
+ row.dataset.taskId = task.id;
198
+ row.setAttribute(
199
+ "aria-label",
200
+ `${task.instruction}, status: ${task.status}`
201
+ );
202
+ const instructionEl = document.createElement("div");
203
+ instructionEl.className = task.status === "error" ? "task-instruction error-row" : "task-instruction";
204
+ instructionEl.textContent = task.instruction;
205
+ instructionEl.addEventListener("click", () => toggleLogs(task.id, row));
206
+ row.appendChild(instructionEl);
207
+ const activityEl = document.createElement("div");
208
+ activityEl.className = "task-activity";
209
+ activityEl.textContent = task.activity ?? "";
210
+ activityEl.style.display = task.activity ? "" : "none";
211
+ row.appendChild(activityEl);
212
+ const statusRow = document.createElement("div");
213
+ statusRow.className = "task-status-row";
214
+ const badge = document.createElement("span");
215
+ badge.className = `status-badge ${task.status}`;
216
+ badge.textContent = STATUS_LABELS[task.status];
217
+ statusRow.appendChild(badge);
218
+ const timerEl = document.createElement("span");
219
+ timerEl.className = "task-timer";
220
+ timerEl.textContent = "0s";
221
+ statusRow.appendChild(timerEl);
222
+ if (task.model) {
223
+ const modelEl = document.createElement("span");
224
+ modelEl.className = "task-model";
225
+ modelEl.textContent = shortModelName(task.model);
226
+ statusRow.appendChild(modelEl);
227
+ }
228
+ if (task.status === "sending" || task.status === "editing") {
229
+ startTaskTimer(task.id);
230
+ }
231
+ if (task.status === "sending" || task.status === "editing") {
232
+ const stopBtn = createStopButton(task.id);
233
+ statusRow.appendChild(stopBtn);
234
+ }
235
+ if (task.status === "done") {
236
+ const undoBtn = createUndoButton(task.id);
237
+ statusRow.appendChild(undoBtn);
238
+ const dismissIcon = createDismissIconButton(task.id);
239
+ statusRow.appendChild(dismissIcon);
240
+ }
241
+ row.appendChild(statusRow);
242
+ if (task.status === "error") {
243
+ appendErrorElements(row, task);
244
+ }
245
+ return row;
246
+ }
247
+ function updateTaskRow(row, task) {
248
+ row.setAttribute(
249
+ "aria-label",
250
+ `${task.instruction}, status: ${task.status}`
251
+ );
252
+ const instructionEl = row.querySelector(".task-instruction");
253
+ if (instructionEl) {
254
+ instructionEl.className = task.status === "error" ? "task-instruction error-row" : "task-instruction";
255
+ }
256
+ const activityEl = row.querySelector(".task-activity");
257
+ if (activityEl) {
258
+ activityEl.textContent = task.activity ?? "";
259
+ activityEl.style.display = task.activity ? "" : "none";
260
+ }
261
+ const badge = row.querySelector(".status-badge");
262
+ if (badge) {
263
+ badge.className = `status-badge ${task.status}`;
264
+ badge.textContent = STATUS_LABELS[task.status];
265
+ }
266
+ if (task.status === "sending" || task.status === "editing") {
267
+ startTaskTimer(task.id);
268
+ } else if (task.status === "done" || task.status === "error") {
269
+ stopTaskTimer(task.id);
270
+ }
271
+ row.querySelector(".task-row-stop-btn")?.remove();
272
+ row.querySelector(".task-row-undo-btn")?.remove();
273
+ row.querySelector(".task-row-dismiss-btn")?.remove();
274
+ row.querySelector(".task-error-message")?.remove();
275
+ row.querySelector(".task-button-row")?.remove();
276
+ if (task.status === "sending" || task.status === "editing") {
277
+ const statusRow = row.querySelector(".task-status-row");
278
+ if (statusRow) {
279
+ statusRow.appendChild(createStopButton(task.id));
280
+ }
281
+ }
282
+ if (task.status === "done") {
283
+ const statusRow = row.querySelector(".task-status-row");
284
+ if (statusRow) {
285
+ statusRow.appendChild(createUndoButton(task.id));
286
+ statusRow.appendChild(createDismissIconButton(task.id));
287
+ }
288
+ }
289
+ if (task.status === "error") {
290
+ appendErrorElements(row, task);
291
+ }
292
+ if (expandedLogs.has(task.id)) {
293
+ refreshLogs(task.id, row);
294
+ }
295
+ }
296
+ function createStopButton(taskId) {
297
+ const btn = document.createElement("button");
298
+ btn.className = "task-row-stop-btn";
299
+ btn.textContent = "Stop";
300
+ btn.setAttribute("aria-label", "Stop task");
301
+ btn.addEventListener("click", (e) => {
302
+ e.stopPropagation();
303
+ window.clawSidebar.dismissTask(taskId);
304
+ });
305
+ return btn;
306
+ }
307
+ function createUndoButton(taskId) {
308
+ const btn = document.createElement("button");
309
+ btn.className = "task-row-undo-btn";
310
+ btn.textContent = "Undo";
311
+ btn.setAttribute("aria-label", "Undo task changes");
312
+ btn.addEventListener("click", (e) => {
313
+ e.stopPropagation();
314
+ window.clawSidebar.undoTask(taskId);
315
+ });
316
+ return btn;
317
+ }
318
+ function createDismissIconButton(taskId) {
319
+ const btn = document.createElement("button");
320
+ btn.className = "task-row-dismiss-btn";
321
+ btn.setAttribute("aria-label", "Dismiss task");
322
+ btn.appendChild(createDismissSvg());
323
+ btn.addEventListener("click", (e) => {
324
+ e.stopPropagation();
325
+ handleDismiss(taskId);
326
+ });
327
+ return btn;
328
+ }
329
+ function appendErrorElements(row, task) {
330
+ if (task.error) {
331
+ const errorMsg = document.createElement("div");
332
+ errorMsg.className = "task-error-message";
333
+ errorMsg.textContent = task.error;
334
+ row.appendChild(errorMsg);
335
+ }
336
+ const buttonRow = document.createElement("div");
337
+ buttonRow.className = "task-button-row";
338
+ const retryBtn = document.createElement("button");
339
+ retryBtn.className = "btn-retry";
340
+ retryBtn.textContent = "Retry";
341
+ retryBtn.addEventListener("click", (e) => {
342
+ e.stopPropagation();
343
+ window.clawSidebar.retryTask(task.id);
344
+ });
345
+ buttonRow.appendChild(retryBtn);
346
+ const dismissBtn = document.createElement("button");
347
+ dismissBtn.className = "btn-dismiss";
348
+ dismissBtn.textContent = "Dismiss";
349
+ dismissBtn.addEventListener("click", (e) => {
350
+ e.stopPropagation();
351
+ handleDismiss(task.id);
352
+ });
353
+ buttonRow.appendChild(dismissBtn);
354
+ row.appendChild(buttonRow);
355
+ }
356
+ async function toggleLogs(taskId, row) {
357
+ const existing = row.querySelector(".task-logs");
358
+ if (existing) {
359
+ existing.remove();
360
+ expandedLogs.delete(taskId);
361
+ return;
362
+ }
363
+ expandedLogs.add(taskId);
364
+ await refreshLogs(taskId, row);
365
+ }
366
+ async function refreshLogs(taskId, row) {
367
+ const logs = await window.clawSidebar.getTaskLogs(taskId);
368
+ const existing = row.querySelector(".task-logs");
369
+ if (existing) existing.remove();
370
+ if (logs.length === 0) {
371
+ const logsEl2 = document.createElement("div");
372
+ logsEl2.className = "task-logs";
373
+ logsEl2.textContent = "No logs yet...";
374
+ const activityEl2 = row.querySelector(".task-activity");
375
+ const insertAfter2 = activityEl2 ?? row.querySelector(".task-instruction");
376
+ insertAfter2?.after(logsEl2);
377
+ return;
378
+ }
379
+ const logsEl = document.createElement("div");
380
+ logsEl.className = "task-logs";
381
+ for (const entry of logs) {
382
+ const line = document.createElement("div");
383
+ line.className = `task-log-entry log-${entry.type}`;
384
+ line.textContent = entry.content;
385
+ logsEl.appendChild(line);
386
+ }
387
+ const activityEl = row.querySelector(".task-activity");
388
+ const insertAfter = activityEl ?? row.querySelector(".task-instruction");
389
+ insertAfter?.after(logsEl);
390
+ logsEl.scrollTop = logsEl.scrollHeight;
391
+ }
392
+ function updateBadge() {
393
+ const badge = computeBadge(state.tasks);
394
+ badgeTextEl.textContent = badge.text;
395
+ badgeEl.style.display = badge.total > 0 ? "" : "none";
396
+ }
397
+ function triggerBadgePulse(type) {
398
+ const cls = type === "done" ? "pulse-done" : "pulse-error";
399
+ badgeEl.classList.remove("pulse-done", "pulse-error");
400
+ void badgeEl.offsetWidth;
401
+ badgeEl.classList.add(cls);
402
+ const onEnd = () => {
403
+ badgeEl.classList.remove(cls);
404
+ badgeEl.removeEventListener("animationend", onEnd);
405
+ };
406
+ badgeEl.addEventListener("animationend", onEnd);
407
+ }
408
+ function handleExpand() {
409
+ window.clawSidebar.expand();
410
+ const result = sidebarTransition(state, { type: "EXPAND" });
411
+ state = result.state;
412
+ updateSidebarState(state.visual);
413
+ }
414
+ function handleCollapse() {
415
+ window.clawSidebar.collapse();
416
+ const result = sidebarTransition(state, { type: "COLLAPSE" });
417
+ state = result.state;
418
+ updateSidebarState(state.visual);
419
+ }
420
+ function autoExpandForTask() {
421
+ window.clawSidebar.expand();
422
+ const result = sidebarTransition(state, { type: "EXPAND" });
423
+ state = result.state;
424
+ updateSidebarState(state.visual);
425
+ }
426
+ function handleDismiss(taskId) {
427
+ const row = taskListEl.querySelector(`[data-task-id="${taskId}"]`);
428
+ if (row) row.remove();
429
+ const result = sidebarTransition(state, {
430
+ type: "TASK_DISMISSED",
431
+ id: taskId
432
+ });
433
+ state = result.state;
434
+ updateBadge();
435
+ window.clawSidebar.dismissTask(taskId);
436
+ if (state.visual === "hidden") {
437
+ updateSidebarState("hidden");
438
+ }
439
+ }
440
+ function updateSidebarState(visual) {
441
+ switch (visual) {
442
+ case "hidden":
443
+ minimizedEl.style.display = "none";
444
+ expandedEl.style.display = "none";
445
+ break;
446
+ case "minimized":
447
+ minimizedEl.style.display = "";
448
+ expandedEl.style.display = "none";
449
+ break;
450
+ case "expanded":
451
+ minimizedEl.style.display = "none";
452
+ expandedEl.style.display = "";
453
+ break;
454
+ }
455
+ }
456
+ function setupDrag(handleEl) {
457
+ let isDragging = false;
458
+ let lastScreenX = 0;
459
+ let lastScreenY = 0;
460
+ handleEl.addEventListener("mousedown", (e) => {
461
+ isDragging = true;
462
+ lastScreenX = e.screenX;
463
+ lastScreenY = e.screenY;
464
+ handleEl.style.cursor = "grabbing";
465
+ e.preventDefault();
466
+ });
467
+ document.addEventListener("mousemove", (e) => {
468
+ if (!isDragging) return;
469
+ const dx = e.screenX - lastScreenX;
470
+ const dy = e.screenY - lastScreenY;
471
+ lastScreenX = e.screenX;
472
+ lastScreenY = e.screenY;
473
+ if (dx !== 0 || dy !== 0) {
474
+ window.clawSidebar.dragDelta(dx, dy);
475
+ }
476
+ });
477
+ document.addEventListener("mouseup", () => {
478
+ if (!isDragging) return;
479
+ isDragging = false;
480
+ handleEl.style.cursor = "";
481
+ window.clawSidebar.dragDelta(0, 0).then((pos) => {
482
+ localStorage.setItem("claw-sidebar-pos", JSON.stringify(pos));
483
+ });
484
+ });
485
+ }
486
+ document.addEventListener("DOMContentLoaded", () => {
487
+ minimizedEl = document.getElementById("sidebar-minimized");
488
+ expandedEl = document.getElementById("sidebar-expanded");
489
+ expandBtn = document.getElementById("sidebar-expand-btn");
490
+ minimizeBtn = document.getElementById("sidebar-minimize-btn");
491
+ taskListEl = document.getElementById("sidebar-task-list");
492
+ badgeEl = document.getElementById("sidebar-badge");
493
+ badgeTextEl = document.getElementById("sidebar-badge-text");
494
+ window.clawSidebar.onTaskUpdate((data) => {
495
+ const isNew = !state.tasks.has(data.id);
496
+ if (isNew) {
497
+ const result = sidebarTransition(state, {
498
+ type: "TASK_ADDED",
499
+ task: data
500
+ });
501
+ state = result.state;
502
+ renderTask(data);
503
+ updateBadge();
504
+ if (result.shouldAutoExpand) {
505
+ autoExpandForTask();
506
+ } else {
507
+ updateSidebarState(state.visual);
508
+ }
509
+ } else {
510
+ const result = sidebarTransition(state, {
511
+ type: "TASK_UPDATED",
512
+ task: data
513
+ });
514
+ state = result.state;
515
+ renderTask(data);
516
+ updateBadge();
517
+ if (result.shouldPulse) {
518
+ triggerBadgePulse(result.shouldPulse);
519
+ }
520
+ }
521
+ });
522
+ expandBtn.addEventListener("click", handleExpand);
523
+ minimizeBtn.addEventListener("click", handleCollapse);
524
+ const clearBtn = document.getElementById("sidebar-clear-btn");
525
+ if (clearBtn) {
526
+ clearBtn.addEventListener("click", () => {
527
+ const finishedIds = [];
528
+ for (const [id, task] of state.tasks) {
529
+ if (task.status === "done" || task.status === "error") {
530
+ finishedIds.push(id);
531
+ }
532
+ }
533
+ for (const id of finishedIds) {
534
+ handleDismiss(id);
535
+ }
536
+ });
537
+ }
538
+ expandedEl.addEventListener("mouseenter", () => {
539
+ });
540
+ window.clawSidebar.onStateChange((newState) => {
541
+ const result = sidebarTransition(state, {
542
+ type: newState === "expanded" ? "EXPAND" : newState === "minimized" ? "COLLAPSE" : "TASK_DISMISSED",
543
+ ...newState === "hidden" ? { id: "" } : {}
544
+ });
545
+ state = { ...result.state, visual: newState };
546
+ updateSidebarState(newState);
547
+ updateBadge();
548
+ });
549
+ const dragHandle = document.getElementById("sidebar-drag-handle");
550
+ if (dragHandle) setupDrag(dragHandle);
551
+ const expandedDragHandle = document.getElementById("sidebar-expanded-drag-handle");
552
+ if (expandedDragHandle) setupDrag(expandedDragHandle);
553
+ const savedPos = localStorage.getItem("claw-sidebar-pos");
554
+ if (savedPos) {
555
+ try {
556
+ const { x, y } = JSON.parse(savedPos);
557
+ if (typeof x === "number" && typeof y === "number") {
558
+ window.clawSidebar.setPosition(x, y);
559
+ }
560
+ } catch {
561
+ }
562
+ }
563
+ });