@lasso-ai/cli 1.0.25 → 1.0.27

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 (2) hide show
  1. package/dist/overlay.js +68 -17
  2. package/package.json +1 -1
package/dist/overlay.js CHANGED
@@ -10916,6 +10916,9 @@
10916
10916
  .lasso-task-badge { min-width: 18px; padding: 2px 5px; border-radius: 999px; background: var(--lo-indigo); color: #fff; font-size: 10px; text-align: center; }
10917
10917
  .lasso-task-close, .lasso-task-back { border: 0; background: transparent; color: var(--lo-text-3); cursor: pointer; }
10918
10918
  .lasso-task-close { font-size: 20px; line-height: 20px; }
10919
+ .lasso-task-tabs { display: flex; gap: 4px; margin: 10px 0 8px; padding: 3px; border-radius: var(--lo-radius-md); background: var(--lo-surface-2); }
10920
+ .lasso-task-tab { flex: 1; padding: 6px 8px; border: 0; border-radius: 7px; background: transparent; color: var(--lo-text-3); font: inherit; font-size: 11px; cursor: pointer; }
10921
+ .lasso-task-tab.active { background: var(--lo-surface); color: var(--lo-text); box-shadow: 0 1px 3px rgba(0,0,0,.16); }
10919
10922
  .lasso-task-body { min-height: 90px; max-height: 470px; overflow: auto; }
10920
10923
  .lasso-task-list { display: flex; flex-direction: column; gap: 3px; }
10921
10924
  .lasso-task-row { width: 100%; display: flex; align-items: center; gap: 9px; padding: 9px; border: 0; border-radius: var(--lo-radius-md); background: transparent; color: var(--lo-text); text-align: left; cursor: pointer; }
@@ -10928,6 +10931,7 @@
10928
10931
  .lasso-task-row-copy { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
10929
10932
  .lasso-task-row-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 500; }
10930
10933
  .lasso-task-row-copy small, .lasso-task-message { color: var(--lo-text-3); font-size: 11px; }
10934
+ .lasso-task-review-label { margin-left: auto; padding: 4px 7px; border-radius: var(--lo-radius-full); background: color-mix(in srgb, #fbbf24 16%, transparent); color: #fbbf24; font-size: 10px; font-weight: 600; cursor: pointer; }
10931
10935
  .lasso-task-empty { padding: 25px 10px; color: var(--lo-text-3); font-size: 12px; text-align: center; }
10932
10936
  .lasso-task-detail { padding: 4px 2px; }
10933
10937
  .lasso-task-detail-heading { justify-content: space-between; margin-bottom: 12px; }
@@ -12128,6 +12132,7 @@
12128
12132
  var detail = null;
12129
12133
  var badge = null;
12130
12134
  var selectionListeners = /* @__PURE__ */ new Set();
12135
+ var reviewListeners = /* @__PURE__ */ new Set();
12131
12136
  var statusLabel = {
12132
12137
  queued: "Queued",
12133
12138
  thinking: "Thinking",
@@ -12150,9 +12155,16 @@
12150
12155
  selectionListeners.add(listener);
12151
12156
  return () => selectionListeners.delete(listener);
12152
12157
  }
12158
+ function onAgentTaskReviewRequested(listener) {
12159
+ reviewListeners.add(listener);
12160
+ return () => reviewListeners.delete(listener);
12161
+ }
12153
12162
  function notifyTaskSelection(task) {
12154
12163
  for (const listener of selectionListeners) listener(task);
12155
12164
  }
12165
+ function notifyTaskReviewRequested(task) {
12166
+ for (const listener of reviewListeners) listener(task);
12167
+ }
12156
12168
  function createAgentTask(instruction, messages = state.chatHistory, changesHistory = state.changesHistory, element = state.selected, selectionId = state.selectionId) {
12157
12169
  const now = (/* @__PURE__ */ new Date()).toISOString();
12158
12170
  const task = {
@@ -12222,6 +12234,12 @@
12222
12234
  notifyTaskSelection(task || null);
12223
12235
  renderTasks();
12224
12236
  }
12237
+ function requestAgentTaskReview(id) {
12238
+ const task = getAgentTask(id);
12239
+ if (!task || task.status !== "review") return;
12240
+ selectAgentTask(task.id);
12241
+ notifyTaskReviewRequested(task);
12242
+ }
12225
12243
  function toggleTaskPanel(force) {
12226
12244
  if (!panel) return;
12227
12245
  panel.hidden = force === void 0 ? !panel.hidden : !force;
@@ -12241,6 +12259,10 @@
12241
12259
  </div>
12242
12260
  <button class="lasso-task-close" type="button" aria-label="Close tasks">\xD7</button>
12243
12261
  </div>
12262
+ <div class="lasso-task-tabs" role="tablist" aria-label="Task status">
12263
+ <button class="lasso-task-tab active" type="button" role="tab" data-task-tab="active" aria-selected="true">In progress</button>
12264
+ <button class="lasso-task-tab" type="button" role="tab" data-task-tab="complete" aria-selected="false">Completed</button>
12265
+ </div>
12244
12266
  <div class="lasso-task-body">
12245
12267
  <div class="lasso-task-list"></div>
12246
12268
  <div class="lasso-task-detail" hidden></div>
@@ -12251,27 +12273,47 @@
12251
12273
  detail = panel.querySelector(".lasso-task-detail");
12252
12274
  badge = panel.querySelector(".lasso-task-badge");
12253
12275
  panel.querySelector(".lasso-task-close").addEventListener("click", () => toggleTaskPanel(false));
12276
+ panel.querySelectorAll(".lasso-task-tab").forEach((tab) => {
12277
+ tab.addEventListener("click", () => {
12278
+ panel?.querySelectorAll(".lasso-task-tab").forEach((item) => {
12279
+ const active = item === tab;
12280
+ item.classList.toggle("active", active);
12281
+ item.setAttribute("aria-selected", String(active));
12282
+ });
12283
+ renderTasks();
12284
+ });
12285
+ });
12254
12286
  renderTasks();
12255
12287
  return panel;
12256
12288
  }
12257
12289
  function renderTasks() {
12258
- if (!list || !detail || !badge) return;
12290
+ const panelEl = panel;
12291
+ if (!panelEl || !list || !detail || !badge) return;
12259
12292
  const activeCount = state.agentTasks.filter((task) => task.status !== "complete" && task.status !== "error" && task.status !== "stopped").length;
12260
12293
  badge.hidden = state.agentTasks.length === 0;
12261
12294
  badge.textContent = String(activeCount || state.agentTasks.length);
12262
12295
  const navBadge = getDOM().shadow.querySelector(".lasso-agent-tasks-badge");
12263
12296
  if (navBadge) navBadge.hidden = activeCount === 0;
12264
12297
  list.replaceChildren();
12265
- if (!state.agentTasks.length) {
12298
+ const activeTab = panelEl.querySelector(".lasso-task-tab.active")?.dataset.taskTab || "active";
12299
+ const visibleTasks = state.agentTasks.filter((task) => activeTab === "complete" ? task.status === "complete" : task.status !== "complete");
12300
+ if (!visibleTasks.length) {
12266
12301
  list.innerHTML = `<div class="lasso-task-empty">Prompt an element to start a task.</div>`;
12267
12302
  } else {
12268
- for (const task of state.agentTasks) {
12303
+ for (const task of visibleTasks) {
12269
12304
  const button = document.createElement("button");
12270
12305
  button.type = "button";
12271
12306
  button.className = `lasso-task-row${task.id === state.activeTaskId ? " active" : ""}`;
12272
- button.innerHTML = `<span class="lasso-task-status ${task.status}"></span><span class="lasso-task-row-copy"><strong></strong><small>${statusLabel[task.status]}</small></span>`;
12307
+ button.innerHTML = `<span class="lasso-task-status ${task.status}"></span><span class="lasso-task-row-copy"><strong></strong><small>${statusLabel[task.status]}</small></span>${task.status === "review" ? '<span class="lasso-task-review-label">Review</span>' : ""}`;
12273
12308
  button.querySelector("strong").textContent = task.instruction;
12274
12309
  button.addEventListener("click", () => selectAgentTask(task.id));
12310
+ if (task.status === "review") {
12311
+ const review = button.querySelector(".lasso-task-review-label");
12312
+ review.addEventListener("click", (event) => {
12313
+ event.stopPropagation();
12314
+ requestAgentTaskReview(task.id);
12315
+ });
12316
+ }
12275
12317
  list.appendChild(button);
12276
12318
  }
12277
12319
  }
@@ -12310,16 +12352,12 @@
12310
12352
  changes.textContent = `${pendingChanges.length} proposed file change${pendingChanges.length === 1 ? "" : "s"}`;
12311
12353
  detail.appendChild(changes);
12312
12354
  if (selected.status === "review") {
12313
- const apply = document.createElement("button");
12314
- apply.type = "button";
12315
- apply.className = "lasso-task-apply";
12316
- apply.textContent = "Apply changes";
12317
- apply.addEventListener("click", () => {
12318
- if (state.bridgeSocket?.readyState !== WebSocket.OPEN) return;
12319
- state.bridgeSocket.send(JSON.stringify({ type: "apply", taskId: selected.id, changes: pendingChanges }));
12320
- updateAgentTask(selected.id, { status: "working", message: "Applying changes\u2026", activity: [...selected.activity, "Applying changes\u2026"] });
12321
- });
12322
- detail.appendChild(apply);
12355
+ const review = document.createElement("button");
12356
+ review.type = "button";
12357
+ review.className = "lasso-task-apply";
12358
+ review.textContent = "Review changes";
12359
+ review.addEventListener("click", () => requestAgentTaskReview(selected.id));
12360
+ detail.appendChild(review);
12323
12361
  }
12324
12362
  }
12325
12363
  }
@@ -18591,7 +18629,7 @@
18591
18629
  <div class="lasso-review-files"></div>
18592
18630
  <div class="lasso-review-actions">
18593
18631
  <button class="lasso-review-undo" type="button">Keep editing</button>
18594
- <button class="lasso-review-apply primary" type="button">Apply changes</button>
18632
+ <button class="lasso-review-apply primary" type="button">Accept &amp; apply</button>
18595
18633
  </div>
18596
18634
  `;
18597
18635
  dom.shadow.appendChild(rev);
@@ -18600,6 +18638,11 @@
18600
18638
  if (task) restoreTaskPrompt(task);
18601
18639
  else resetPromptSession();
18602
18640
  });
18641
+ onAgentTaskReviewRequested((task) => {
18642
+ state.promptTaskId = task.id;
18643
+ state.pendingChanges = [...task.pendingChanges.length ? task.pendingChanges : task.changes || []];
18644
+ showReview(state.pendingChanges, task.message);
18645
+ });
18603
18646
  const promptTop = el.querySelector(".lasso-prompt-top");
18604
18647
  let dragState = null;
18605
18648
  promptTop.addEventListener("pointerdown", (event) => {
@@ -18745,6 +18788,11 @@
18745
18788
  if (!taskId2 || !state.bridgeSocket || state.bridgeSocket.readyState !== WebSocket.OPEN || !state.pendingChanges.length) return;
18746
18789
  requestAgentNotificationPermission();
18747
18790
  state.bridgeSocket.send(JSON.stringify({ type: "apply", taskId: taskId2, changes: state.pendingChanges }));
18791
+ updateAgentTask(taskId2, {
18792
+ status: "working",
18793
+ message: "Applying accepted changes\u2026",
18794
+ activity: [...getAgentTask(taskId2)?.activity || [], "Applying accepted changes\u2026"]
18795
+ });
18748
18796
  appendChat("assistant", "Applying the reviewed change\u2026", taskId2);
18749
18797
  });
18750
18798
  return { prompt: el, review: rev };
@@ -19063,7 +19111,7 @@
19063
19111
  state.promptTaskId = task.id;
19064
19112
  state.chatHistory = [...task.messages];
19065
19113
  state.changesHistory = task.changesHistory.map((entry) => ({ ...entry, changes: entry.changes.map((change) => ({ ...change })) }));
19066
- state.pendingChanges = [...task.pendingChanges];
19114
+ state.pendingChanges = [...task.pendingChanges.length ? task.pendingChanges : task.changes || []];
19067
19115
  state.lastInstruction = task.lastInstruction;
19068
19116
  state.selectionId = task.selectionId;
19069
19117
  state.screenshotPromise = Promise.resolve({});
@@ -19092,7 +19140,6 @@
19092
19140
  }
19093
19141
  if (promptEl) promptEl.classList.add("visible");
19094
19142
  setSelectMode(false);
19095
- if (task.status === "review" && state.pendingChanges.length) showReview(state.pendingChanges, task.message);
19096
19143
  setAgentStatus(task.status, task.message, task.detail, task.id, false);
19097
19144
  requestAnimationFrame(() => promptInput?.focus());
19098
19145
  }
@@ -19173,6 +19220,10 @@
19173
19220
  async function handleSend(event) {
19174
19221
  event.preventDefault();
19175
19222
  event.stopPropagation();
19223
+ if (sendButton?.dataset.state === "review") {
19224
+ if (state.pendingChanges.length) showReview(state.pendingChanges, "Review the proposed source changes.");
19225
+ return;
19226
+ }
19176
19227
  const selectedElement = state.selected;
19177
19228
  if (!selectedElement || !promptInput || !sendButton) return;
19178
19229
  const instruction = promptInput.value.trim() || (sendButton.dataset.state === "retry" ? state.lastInstruction : "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lasso-ai/cli",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Select any part of your running app, describe a change, and let AI edit the real source code.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/cli/index.js",