@lasso-ai/cli 2.1.3 → 2.1.5

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.
package/dist/overlay.js CHANGED
@@ -9668,6 +9668,21 @@
9668
9668
  position: relative;
9669
9669
  }
9670
9670
 
9671
+ .lasso-model-chevron {
9672
+ flex: 0 0 16px;
9673
+ width: 16px;
9674
+ height: 16px;
9675
+ opacity: 0.72;
9676
+ transition: transform 160ms ease, opacity 160ms ease;
9677
+ }
9678
+
9679
+ .lasso-prompt-model[aria-expanded="true"] .lasso-model-chevron,
9680
+ .lasso-command-model-btn[aria-expanded="true"] .lasso-model-chevron,
9681
+ .lasso-cli-subgroup-header[aria-expanded="true"] .lasso-model-chevron {
9682
+ transform: rotate(180deg);
9683
+ opacity: 1;
9684
+ }
9685
+
9671
9686
  .lasso-prompt-model {
9672
9687
  height: 28px;
9673
9688
  max-width: 190px;
@@ -9786,7 +9801,7 @@
9786
9801
  cursor: pointer;
9787
9802
  }
9788
9803
  .lasso-cli-subgroup-header:hover { background: var(--lo-surface-hover); color: var(--lo-text); }
9789
- .lasso-cli-subgroup-chevron { color: var(--lo-text-3); font-size: 13px; line-height: 10px; }
9804
+ .lasso-cli-subgroup-chevron { color: var(--lo-text-3); }
9790
9805
  .lasso-cli-subgroup-items { padding-left: 6px; }
9791
9806
 
9792
9807
  .lasso-model-item-icon {
@@ -19563,130 +19578,6 @@
19563
19578
  return escapeHtml3(value2);
19564
19579
  }
19565
19580
 
19566
- // src/overlay/browser/context.ts
19567
- var import_html2canvas = __toESM(require_html2canvas());
19568
- async function capturePageContext() {
19569
- const url2 = window.location.href;
19570
- const route = window.location.pathname + window.location.search;
19571
- const title = document.title || "Untitled Page";
19572
- const doc = document.documentElement;
19573
- const viewport = {
19574
- width: window.innerWidth,
19575
- height: window.innerHeight,
19576
- scrollX: window.scrollX || window.pageXOffset || 0,
19577
- scrollY: window.scrollY || window.pageYOffset || 0,
19578
- scrollHeight: doc.scrollHeight
19579
- };
19580
- const headings = [];
19581
- const headingEls = document.querySelectorAll("h1, h2, h3, h4");
19582
- for (const el of headingEls) {
19583
- if (el.closest("#lasso-root")) continue;
19584
- const text = (el.textContent || "").trim().replace(/\s+/g, " ");
19585
- if (text) {
19586
- const level = parseInt(el.tagName.replace(/h/i, ""), 10) || 2;
19587
- headings.push({ level, text: text.slice(0, 120) });
19588
- if (headings.length >= 15) break;
19589
- }
19590
- }
19591
- const sections = [];
19592
- const sectionEls = document.querySelectorAll(
19593
- "header, nav, main, section, article, footer, [role='banner'], [role='main'], [role='navigation'], [id*='hero'], [class*='hero'], [id*='feature'], [class*='feature'], [id*='pricing'], [class*='pricing'], [id*='testimonial'], [class*='testimonial']"
19594
- );
19595
- for (const el of sectionEls) {
19596
- if (el.closest("#lasso-root")) continue;
19597
- const tag = el.tagName.toLowerCase();
19598
- const id = el.id ? `#${el.id}` : "";
19599
- const ariaLabel = el.getAttribute("aria-label");
19600
- const name = ariaLabel ? `${tag} (${ariaLabel})` : id ? `${tag}${id}` : tag;
19601
- const textPreview = (el.textContent || "").trim().replace(/\s+/g, " ").slice(0, 160);
19602
- if (textPreview && !sections.some((s) => s.textPreview === textPreview)) {
19603
- sections.push({ name, textPreview });
19604
- if (sections.length >= 12) break;
19605
- }
19606
- }
19607
- const buttons = [];
19608
- const buttonEls = document.querySelectorAll("button, a[role='button'], input[type='button'], input[type='submit'], a.btn, a[class*='button']");
19609
- for (const el of buttonEls) {
19610
- if (el.closest("#lasso-root")) continue;
19611
- const text = (el.textContent || el.value || "").trim().replace(/\s+/g, " ");
19612
- if (text && !buttons.includes(text)) {
19613
- buttons.push(text.slice(0, 50));
19614
- if (buttons.length >= 12) break;
19615
- }
19616
- }
19617
- const links = [];
19618
- const linkEls = document.querySelectorAll("nav a, header a, a.nav-link");
19619
- for (const el of linkEls) {
19620
- if (el.closest("#lasso-root")) continue;
19621
- const text = (el.textContent || "").trim().replace(/\s+/g, " ");
19622
- if (text && !links.includes(text) && !buttons.includes(text)) {
19623
- links.push(text.slice(0, 40));
19624
- if (links.length >= 10) break;
19625
- }
19626
- }
19627
- const inputs = [];
19628
- const inputEls = document.querySelectorAll("input:not([type='hidden']), textarea, select");
19629
- for (const el of inputEls) {
19630
- if (el.closest("#lasso-root")) continue;
19631
- const type = (el.getAttribute("type") || el.tagName.toLowerCase()).slice(0, 20);
19632
- const placeholder = el.getAttribute("placeholder")?.slice(0, 60);
19633
- inputs.push({ type, placeholder });
19634
- if (inputs.length >= 8) break;
19635
- }
19636
- const bodyClone = document.body ? document.body.cloneNode(true) : null;
19637
- if (bodyClone) {
19638
- const lassoRoot = bodyClone.querySelector("#lasso-root");
19639
- if (lassoRoot) lassoRoot.remove();
19640
- }
19641
- const bodyText = (bodyClone?.innerText || document.body?.innerText || "").replace(/\s+/g, " ").slice(0, 1500);
19642
- let selectedElement = void 0;
19643
- if (state.selected && !state.selected.closest("#lasso-root")) {
19644
- const el = state.selected;
19645
- selectedElement = {
19646
- tag: el.tagName.toLowerCase(),
19647
- id: el.id || void 0,
19648
- classes: Array.from(el.classList),
19649
- text: (el.textContent || "").trim().slice(0, 100),
19650
- source: el.getAttribute("data-source") || el.getAttribute("data-lasso-source") || void 0
19651
- };
19652
- }
19653
- let screenshot = void 0;
19654
- try {
19655
- const options = {
19656
- backgroundColor: null,
19657
- useCORS: true,
19658
- logging: false,
19659
- scale: 0.6,
19660
- ignoreElements: (node) => node.id === "lasso-root" || Boolean(node.closest?.("#lasso-root"))
19661
- };
19662
- const canvasPromise = (0, import_html2canvas.default)(document.body, options);
19663
- const timeoutPromise = new Promise((r) => setTimeout(() => r(null), 1200));
19664
- const canvas = await Promise.race([canvasPromise, timeoutPromise]);
19665
- if (canvas && typeof canvas.toDataURL === "function") {
19666
- screenshot = canvas.toDataURL("image/jpeg", 0.65);
19667
- }
19668
- } catch (err) {
19669
- console.warn("[lasso] visual snapshot failed:", err);
19670
- }
19671
- return {
19672
- url: url2,
19673
- route,
19674
- title,
19675
- viewport,
19676
- screenshot,
19677
- runtimeErrors: [...state.runtimeErrors],
19678
- domSummary: {
19679
- headings,
19680
- sections,
19681
- buttons,
19682
- links,
19683
- inputs,
19684
- visibleTextSnippet: bodyText
19685
- },
19686
- selectedElement
19687
- };
19688
- }
19689
-
19690
19581
  // src/overlay/commandbar/commandbar.ts
19691
19582
  var commandBarEl = null;
19692
19583
  var commandInput = null;
@@ -19709,48 +19600,6 @@
19709
19600
  var activeStartTime = 0;
19710
19601
  var activeConversationId = null;
19711
19602
  var conversationList = [];
19712
- function isConversationalPrompt(prompt) {
19713
- const p = prompt.trim().toLowerCase().replace(/[!?.,;:]+$/, "");
19714
- const greetings = [
19715
- "hi",
19716
- "hello",
19717
- "hey",
19718
- "heya",
19719
- "howdy",
19720
- "sup",
19721
- "yo",
19722
- "good morning",
19723
- "good afternoon",
19724
- "good evening",
19725
- "thanks",
19726
- "thank you",
19727
- "thx",
19728
- "ty",
19729
- "cool",
19730
- "awesome",
19731
- "great",
19732
- "nice",
19733
- "who are you",
19734
- "what are you",
19735
- "what can you do",
19736
- "help",
19737
- "help me",
19738
- "what is lasso",
19739
- "how do you work",
19740
- "how does this work"
19741
- ];
19742
- if (greetings.includes(p)) return true;
19743
- if (/^(hi|hello|hey|howdy|yo)\b/i.test(p) && p.split(/\s+/).length <= 4) {
19744
- const buildKeywords = /(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code)/i;
19745
- if (!buildKeywords.test(p)) return true;
19746
- }
19747
- const questionOnly = /^(what is|what's|how do i|why does|can you explain|tell me about)\b/i.test(p);
19748
- const actionVerbs = /(build|create|add|make|fix|update|modify|change|refactor|implement|write code|code this|delete|remove|generate)/i;
19749
- if (questionOnly && !actionVerbs.test(p)) {
19750
- return true;
19751
- }
19752
- return false;
19753
- }
19754
19603
  function isRetryIntent(prompt) {
19755
19604
  const p = prompt.trim().toLowerCase().replace(/[!?.]+$/, "");
19756
19605
  return /^(try\s+again|retry|re-?try|do\s+it\s+again|run\s+again|attempt\s+again|go\s+again|one\s+more\s+time|again)$/.test(p);
@@ -20076,10 +19925,10 @@
20076
19925
  ></textarea>
20077
19926
  <div class="lasso-command-input-toolbar">
20078
19927
  <div class="lasso-command-model-select">
20079
- <button class="lasso-command-model-btn" type="button" aria-label="Select model">
19928
+ <button class="lasso-command-model-btn" type="button" aria-label="Select model" aria-expanded="false" aria-haspopup="listbox">
20080
19929
  <span class="lasso-command-model-icon"></span>
20081
19930
  <span class="lasso-command-model-label"></span>
20082
- <svg class="lasso-command-model-chevron" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
19931
+ <svg class="lasso-model-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
20083
19932
  <path d="M6 9l6 6 6-6"/>
20084
19933
  </svg>
20085
19934
  </button>
@@ -20152,7 +20001,7 @@
20152
20001
  if (!commandHistoryPopover) return;
20153
20002
  const isHidden = commandHistoryPopover.hidden;
20154
20003
  if (isHidden) {
20155
- if (commandModelMenu) commandModelMenu.hidden = true;
20004
+ setCommandModelMenuOpen(false);
20156
20005
  commandHistoryPopover.hidden = false;
20157
20006
  commandHistoryBtn?.classList.add("active");
20158
20007
  await loadConversationList();
@@ -20168,6 +20017,11 @@
20168
20017
  if (!item?.dataset.convId) return;
20169
20018
  await switchConversation(item.dataset.convId);
20170
20019
  });
20020
+ const setCommandModelMenuOpen = (open) => {
20021
+ if (!commandModelMenu || !commandModelBtn) return;
20022
+ commandModelMenu.hidden = !open;
20023
+ commandModelBtn.setAttribute("aria-expanded", String(open));
20024
+ };
20171
20025
  commandModelBtn.addEventListener("click", (event) => {
20172
20026
  event.preventDefault();
20173
20027
  event.stopPropagation();
@@ -20176,11 +20030,11 @@
20176
20030
  commandHistoryBtn?.classList.remove("active");
20177
20031
  }
20178
20032
  if (commandModelMenu) {
20179
- const willOpen = commandModelMenu.hidden;
20033
+ const willOpen = commandModelMenu?.hidden === true;
20180
20034
  if (willOpen) {
20181
20035
  populateModelMenu();
20182
20036
  }
20183
- commandModelMenu.hidden = !willOpen;
20037
+ setCommandModelMenuOpen(willOpen);
20184
20038
  }
20185
20039
  });
20186
20040
  commandModelMenu.addEventListener("click", (event) => {
@@ -20202,7 +20056,7 @@
20202
20056
  commandModelLabel.textContent = found.label;
20203
20057
  }
20204
20058
  populateModelMenu();
20205
- if (commandModelMenu) commandModelMenu.hidden = true;
20059
+ setCommandModelMenuOpen(false);
20206
20060
  });
20207
20061
  document.addEventListener("click", (event) => {
20208
20062
  const path = event.composedPath ? event.composedPath() : [];
@@ -20210,7 +20064,7 @@
20210
20064
  if (commandModelMenu && !commandModelMenu.hidden) {
20211
20065
  if (!path.includes(commandModelBtn) && !path.includes(commandModelMenu)) {
20212
20066
  if (!commandModelBtn?.contains(target) && !commandModelMenu?.contains(target)) {
20213
- commandModelMenu.hidden = true;
20067
+ setCommandModelMenuOpen(false);
20214
20068
  }
20215
20069
  }
20216
20070
  }
@@ -20223,6 +20077,11 @@
20223
20077
  }
20224
20078
  }
20225
20079
  });
20080
+ document.addEventListener("keydown", (event) => {
20081
+ if (event.key !== "Escape" || commandModelMenu?.hidden !== false) return;
20082
+ setCommandModelMenuOpen(false);
20083
+ commandModelBtn?.focus();
20084
+ });
20226
20085
  commandClose.addEventListener("click", (event) => {
20227
20086
  event.preventDefault();
20228
20087
  event.stopPropagation();
@@ -20391,6 +20250,10 @@
20391
20250
  function closeCommandBar() {
20392
20251
  if (!commandBarEl) return;
20393
20252
  commandBarEl.hidden = true;
20253
+ if (commandModelMenu) {
20254
+ commandModelMenu.hidden = true;
20255
+ commandModelBtn?.setAttribute("aria-expanded", "false");
20256
+ }
20394
20257
  isOneShotMode = false;
20395
20258
  getDOM().shadow.querySelector(".command-tool")?.classList.remove("active");
20396
20259
  }
@@ -20510,14 +20373,14 @@
20510
20373
  const taskId2 = `oneshot-${Date.now()}`;
20511
20374
  activeTaskId = taskId2;
20512
20375
  activeStartTime = Date.now();
20513
- const isChat = isConversationalPrompt(prompt);
20376
+ const initialStepTitle = "Thinking\u2026";
20514
20377
  commandMessages.push({
20515
20378
  id: taskId2,
20516
20379
  role: "assistant",
20517
20380
  content: "",
20518
20381
  timestamp: Date.now(),
20519
20382
  thinking: {
20520
- steps: [{ title: isChat ? "Thinking..." : "Planning your request...", status: "running" }],
20383
+ steps: [{ title: initialStepTitle, status: "running" }],
20521
20384
  durationSeconds: 0,
20522
20385
  completed: false,
20523
20386
  expanded: true
@@ -20548,12 +20411,6 @@
20548
20411
  summary: prompt.slice(0, 120)
20549
20412
  });
20550
20413
  }
20551
- let pageContext = void 0;
20552
- try {
20553
- pageContext = await capturePageContext();
20554
- } catch (err) {
20555
- console.warn("[lasso] capturePageContext failed:", err);
20556
- }
20557
20414
  if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
20558
20415
  state.bridgeSocket.send(
20559
20416
  JSON.stringify({
@@ -20564,8 +20421,13 @@
20564
20421
  scope: "project",
20565
20422
  model: state.selectedModel.id,
20566
20423
  provider: state.selectedModel.provider,
20567
- messages: commandMessages.filter((m) => m.content && !m.error).map((m) => ({ role: m.role, content: m.content })),
20568
- pageContext
20424
+ // The current prompt is sent in its dedicated `prompt` field. Keep it
20425
+ // out of history so the model sees it once, not once as history and
20426
+ // once as the active request.
20427
+ messages: commandMessages.map((message, index) => ({ message, index })).filter(({ message, index }) => Boolean(message.content) && !message.error && index !== commandMessages.reduce(
20428
+ (last, item, itemIndex) => item.role === "user" && item.content === prompt ? itemIndex : last,
20429
+ -1
20430
+ )).map(({ message }) => message).map((m) => ({ role: m.role, content: m.content }))
20569
20431
  })
20570
20432
  );
20571
20433
  } else {
@@ -21583,6 +21445,130 @@
21583
21445
  }
21584
21446
  }
21585
21447
 
21448
+ // src/overlay/browser/context.ts
21449
+ var import_html2canvas = __toESM(require_html2canvas());
21450
+ async function capturePageContext() {
21451
+ const url2 = window.location.href;
21452
+ const route = window.location.pathname + window.location.search;
21453
+ const title = document.title || "Untitled Page";
21454
+ const doc = document.documentElement;
21455
+ const viewport = {
21456
+ width: window.innerWidth,
21457
+ height: window.innerHeight,
21458
+ scrollX: window.scrollX || window.pageXOffset || 0,
21459
+ scrollY: window.scrollY || window.pageYOffset || 0,
21460
+ scrollHeight: doc.scrollHeight
21461
+ };
21462
+ const headings = [];
21463
+ const headingEls = document.querySelectorAll("h1, h2, h3, h4");
21464
+ for (const el of headingEls) {
21465
+ if (el.closest("#lasso-root")) continue;
21466
+ const text = (el.textContent || "").trim().replace(/\s+/g, " ");
21467
+ if (text) {
21468
+ const level = parseInt(el.tagName.replace(/h/i, ""), 10) || 2;
21469
+ headings.push({ level, text: text.slice(0, 120) });
21470
+ if (headings.length >= 15) break;
21471
+ }
21472
+ }
21473
+ const sections = [];
21474
+ const sectionEls = document.querySelectorAll(
21475
+ "header, nav, main, section, article, footer, [role='banner'], [role='main'], [role='navigation'], [id*='hero'], [class*='hero'], [id*='feature'], [class*='feature'], [id*='pricing'], [class*='pricing'], [id*='testimonial'], [class*='testimonial']"
21476
+ );
21477
+ for (const el of sectionEls) {
21478
+ if (el.closest("#lasso-root")) continue;
21479
+ const tag = el.tagName.toLowerCase();
21480
+ const id = el.id ? `#${el.id}` : "";
21481
+ const ariaLabel = el.getAttribute("aria-label");
21482
+ const name = ariaLabel ? `${tag} (${ariaLabel})` : id ? `${tag}${id}` : tag;
21483
+ const textPreview = (el.textContent || "").trim().replace(/\s+/g, " ").slice(0, 160);
21484
+ if (textPreview && !sections.some((s) => s.textPreview === textPreview)) {
21485
+ sections.push({ name, textPreview });
21486
+ if (sections.length >= 12) break;
21487
+ }
21488
+ }
21489
+ const buttons = [];
21490
+ const buttonEls = document.querySelectorAll("button, a[role='button'], input[type='button'], input[type='submit'], a.btn, a[class*='button']");
21491
+ for (const el of buttonEls) {
21492
+ if (el.closest("#lasso-root")) continue;
21493
+ const text = (el.textContent || el.value || "").trim().replace(/\s+/g, " ");
21494
+ if (text && !buttons.includes(text)) {
21495
+ buttons.push(text.slice(0, 50));
21496
+ if (buttons.length >= 12) break;
21497
+ }
21498
+ }
21499
+ const links = [];
21500
+ const linkEls = document.querySelectorAll("nav a, header a, a.nav-link");
21501
+ for (const el of linkEls) {
21502
+ if (el.closest("#lasso-root")) continue;
21503
+ const text = (el.textContent || "").trim().replace(/\s+/g, " ");
21504
+ if (text && !links.includes(text) && !buttons.includes(text)) {
21505
+ links.push(text.slice(0, 40));
21506
+ if (links.length >= 10) break;
21507
+ }
21508
+ }
21509
+ const inputs = [];
21510
+ const inputEls = document.querySelectorAll("input:not([type='hidden']), textarea, select");
21511
+ for (const el of inputEls) {
21512
+ if (el.closest("#lasso-root")) continue;
21513
+ const type = (el.getAttribute("type") || el.tagName.toLowerCase()).slice(0, 20);
21514
+ const placeholder = el.getAttribute("placeholder")?.slice(0, 60);
21515
+ inputs.push({ type, placeholder });
21516
+ if (inputs.length >= 8) break;
21517
+ }
21518
+ const bodyClone = document.body ? document.body.cloneNode(true) : null;
21519
+ if (bodyClone) {
21520
+ const lassoRoot = bodyClone.querySelector("#lasso-root");
21521
+ if (lassoRoot) lassoRoot.remove();
21522
+ }
21523
+ const bodyText = (bodyClone?.innerText || document.body?.innerText || "").replace(/\s+/g, " ").slice(0, 1500);
21524
+ let selectedElement = void 0;
21525
+ if (state.selected && !state.selected.closest("#lasso-root")) {
21526
+ const el = state.selected;
21527
+ selectedElement = {
21528
+ tag: el.tagName.toLowerCase(),
21529
+ id: el.id || void 0,
21530
+ classes: Array.from(el.classList),
21531
+ text: (el.textContent || "").trim().slice(0, 100),
21532
+ source: el.getAttribute("data-source") || el.getAttribute("data-lasso-source") || void 0
21533
+ };
21534
+ }
21535
+ let screenshot = void 0;
21536
+ try {
21537
+ const options = {
21538
+ backgroundColor: null,
21539
+ useCORS: true,
21540
+ logging: false,
21541
+ scale: 0.6,
21542
+ ignoreElements: (node) => node.id === "lasso-root" || Boolean(node.closest?.("#lasso-root"))
21543
+ };
21544
+ const canvasPromise = (0, import_html2canvas.default)(document.body, options);
21545
+ const timeoutPromise = new Promise((r) => setTimeout(() => r(null), 1200));
21546
+ const canvas = await Promise.race([canvasPromise, timeoutPromise]);
21547
+ if (canvas && typeof canvas.toDataURL === "function") {
21548
+ screenshot = canvas.toDataURL("image/jpeg", 0.65);
21549
+ }
21550
+ } catch (err) {
21551
+ console.warn("[lasso] visual snapshot failed:", err);
21552
+ }
21553
+ return {
21554
+ url: url2,
21555
+ route,
21556
+ title,
21557
+ viewport,
21558
+ screenshot,
21559
+ runtimeErrors: [...state.runtimeErrors],
21560
+ domSummary: {
21561
+ headings,
21562
+ sections,
21563
+ buttons,
21564
+ links,
21565
+ inputs,
21566
+ visibleTextSnippet: bodyText
21567
+ },
21568
+ selectedElement
21569
+ };
21570
+ }
21571
+
21586
21572
  // src/overlay/bridge/bridge.ts
21587
21573
  function reportRuntimeError(details, notifyBridge = true) {
21588
21574
  const clean = details.slice(0, 1200);
@@ -21647,6 +21633,10 @@
21647
21633
  state.bridgeSocket.addEventListener("message", (event) => {
21648
21634
  try {
21649
21635
  const message = JSON.parse(event.data);
21636
+ if (message.type === "page_context_request" && message.requestId) {
21637
+ void capturePageContext().then((pageContext) => send({ type: "page_context_response", requestId: message.requestId, pageContext })).catch((error) => send({ type: "page_context_response", requestId: message.requestId, error: error instanceof Error ? error.message : "Unable to capture page context." }));
21638
+ return;
21639
+ }
21650
21640
  if (message.type === "config") {
21651
21641
  state.apiKeyConfigured = Boolean(message.apiKeyConfigured);
21652
21642
  if (message.collab) {
@@ -22211,9 +22201,9 @@ The agent is automatically attempting to fix the build errors...`;
22211
22201
  </button>
22212
22202
 
22213
22203
  <div class="lasso-prompt-model-wrap">
22214
- <button class="lasso-prompt-model" type="button" aria-label="Choose model">
22204
+ <button class="lasso-prompt-model" type="button" aria-label="Choose model" aria-expanded="false" aria-haspopup="listbox">
22215
22205
  <span class="lasso-prompt-model-name"></span>
22216
- <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
22206
+ <svg class="lasso-model-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
22217
22207
  <path d="M6 9l6 6 6-6"/>
22218
22208
  </svg>
22219
22209
  </button>
@@ -22381,10 +22371,15 @@ The agent is automatically attempting to fix the build errors...`;
22381
22371
  };
22382
22372
  promptTop.addEventListener("pointerup", stopPromptDrag);
22383
22373
  promptTop.addEventListener("pointercancel", stopPromptDrag);
22374
+ const setModelMenuOpen = (open) => {
22375
+ if (!modelMenu || !modelBtn) return;
22376
+ modelMenu.hidden = !open;
22377
+ modelBtn.setAttribute("aria-expanded", String(open));
22378
+ };
22384
22379
  modelBtn.addEventListener("click", (event) => {
22385
22380
  event.preventDefault();
22386
22381
  event.stopPropagation();
22387
- if (modelMenu) modelMenu.hidden = !modelMenu.hidden;
22382
+ setModelMenuOpen(modelMenu?.hidden === true);
22388
22383
  });
22389
22384
  modelMenu.addEventListener("click", (event) => {
22390
22385
  event.stopPropagation();
@@ -22401,7 +22396,7 @@ The agent is automatically attempting to fix the build errors...`;
22401
22396
  state.selectedModel = found;
22402
22397
  rememberModel(found);
22403
22398
  syncModelMenu2();
22404
- if (modelMenu) modelMenu.hidden = true;
22399
+ setModelMenuOpen(false);
22405
22400
  });
22406
22401
  document.addEventListener("click", (event) => {
22407
22402
  if (!modelMenu || modelMenu.hidden) return;
@@ -22409,7 +22404,12 @@ The agent is automatically attempting to fix the build errors...`;
22409
22404
  if (path.includes(modelBtn) || path.includes(modelMenu)) return;
22410
22405
  const target = event.target;
22411
22406
  if (modelBtn?.contains(target) || modelMenu?.contains(target)) return;
22412
- modelMenu.hidden = true;
22407
+ setModelMenuOpen(false);
22408
+ });
22409
+ document.addEventListener("keydown", (event) => {
22410
+ if (event.key !== "Escape" || modelMenu?.hidden !== false) return;
22411
+ setModelMenuOpen(false);
22412
+ modelBtn?.focus();
22413
22413
  });
22414
22414
  refreshModelMenu();
22415
22415
  promptInput.addEventListener("input", syncSendButtonState);
@@ -22677,7 +22677,7 @@ The agent is automatically attempting to fix the build errors...`;
22677
22677
  subHeader.type = "button";
22678
22678
  subHeader.className = "lasso-cli-subgroup-header";
22679
22679
  subHeader.setAttribute("aria-expanded", String(openCliGroups.has(cliKey)));
22680
- subHeader.innerHTML = `<span>${providerLabels[cliKey] || cliKey}</span><span class="lasso-cli-subgroup-chevron">${openCliGroups.has(cliKey) ? "\u2303" : "\u2304"}</span>`;
22680
+ subHeader.innerHTML = `<span>${providerLabels[cliKey] || cliKey}</span><svg class="lasso-model-chevron lasso-cli-subgroup-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>`;
22681
22681
  const subItems = document.createElement("div");
22682
22682
  subItems.className = "lasso-cli-subgroup-items";
22683
22683
  subItems.hidden = !openCliGroups.has(cliKey);
@@ -23156,11 +23156,6 @@ The agent is automatically attempting to fix the build errors...`;
23156
23156
  promptInput.style.height = "auto";
23157
23157
  syncSendButtonState();
23158
23158
  requestAgentNotificationPermission();
23159
- const isQuestionPrefix = /^(what|why|how|when|where|who|which|explain|describe|tell me about)\b/i.test(instruction);
23160
- const isImperativeEdit = /\b(can|could|would|please)\s+(you\s+)?(change|edit|update|add|fix|make|replace|remove|install|redesign|switch|swap|set)\b/i.test(instruction);
23161
- const isConversationalQuestion = (isQuestionPrefix || /\?$/.test(instruction)) && !isImperativeEdit;
23162
- const isGreeting = /^(hi|hello|hey|thanks|thank you)\b/i.test(instruction) && instruction.split(/\s+/).length <= 4;
23163
- const wantsAnswer = isConversationalQuestion || isGreeting;
23164
23159
  const bridgeSocket = state.bridgeSocket;
23165
23160
  if (!bridgeSocket || bridgeSocket.readyState !== WebSocket.OPEN) {
23166
23161
  setAgentStatus(
@@ -23169,11 +23164,9 @@ The agent is automatically attempting to fix the build errors...`;
23169
23164
  );
23170
23165
  return;
23171
23166
  }
23172
- if (!wantsAnswer) {
23173
- const ownershipGranted = await acquireOwnership(selectedElement);
23174
- if (!ownershipGranted) return;
23175
- }
23176
- if (!wantsAnswer && state.collabSocket?.connected && state.collabJoined) {
23167
+ const ownershipGranted = await acquireOwnership(selectedElement);
23168
+ if (!ownershipGranted) return;
23169
+ if (state.collabSocket?.connected && state.collabJoined) {
23177
23170
  collabEmit("collab:action", {
23178
23171
  sessionId: state.collabProjectId,
23179
23172
  status: "preparing",
@@ -23221,14 +23214,13 @@ The agent is automatically attempting to fix the build errors...`;
23221
23214
  const message = "The Lasso agent bridge disconnected before the task could start.";
23222
23215
  updateAgentTask(task.id, { status: "error", message });
23223
23216
  appendChat("error", message, task.id);
23224
- if (!wantsAnswer) releaseHeldLock(elementKey(selectedElement));
23217
+ releaseHeldLock(elementKey(selectedElement));
23225
23218
  return;
23226
23219
  }
23227
23220
  bridgeSocket.send(
23228
23221
  JSON.stringify({
23229
- type: wantsAnswer ? "ask" : "edit",
23222
+ type: "edit",
23230
23223
  taskId: task.id,
23231
- question: wantsAnswer ? instruction : void 0,
23232
23224
  instruction,
23233
23225
  messages,
23234
23226
  changesHistory,
@@ -19,7 +19,8 @@ export interface ActionExecutionResult {
19
19
  }
20
20
  export declare class ActionExecutor {
21
21
  private projectPath;
22
- constructor(projectPath: string);
22
+ private browserContextProvider?;
23
+ constructor(projectPath: string, browserContextProvider?: (action: any) => Promise<any>);
23
24
  /**
24
25
  * Execute a single action
25
26
  */
@@ -11,8 +11,10 @@ const node_util_1 = require("node:util");
11
11
  const exec = (0, node_util_1.promisify)(node_child_process_1.exec);
12
12
  class ActionExecutor {
13
13
  projectPath;
14
- constructor(projectPath) {
14
+ browserContextProvider;
15
+ constructor(projectPath, browserContextProvider) {
15
16
  this.projectPath = projectPath;
17
+ this.browserContextProvider = browserContextProvider;
16
18
  }
17
19
  /**
18
20
  * Execute a single action
@@ -340,15 +342,22 @@ class ActionExecutor {
340
342
  const { id, data } = action;
341
343
  const url = data.url;
342
344
  const check = data.check;
343
- // TODO: Implement actual browser checking via Puppeteer or similar
345
+ if (!this.browserContextProvider) {
346
+ return {
347
+ success: false,
348
+ actionId: id,
349
+ error: "Live browser context is unavailable because no overlay is connected.",
350
+ };
351
+ }
352
+ const pageContext = await this.browserContextProvider(action);
344
353
  return {
345
354
  success: true,
346
355
  actionId: id,
347
- output: { url, check, result: "pending" },
356
+ output: { url, check, pageContext },
348
357
  observation: {
349
358
  type: "browser",
350
- summary: `Browser check pending: ${url}`,
351
- data: { url, check },
359
+ summary: `Captured live browser context${url ? ` for ${url}` : ""}`,
360
+ data: { url, check, pageContext },
352
361
  },
353
362
  };
354
363
  }
@@ -36,6 +36,7 @@ export declare class CodexCLIAdapter extends LocalAgentAdapter {
36
36
  protected handleLine(line: string, context: TaskContext, sink: EventSink): boolean;
37
37
  private handleItemCompleted;
38
38
  private recordFailure;
39
+ private describeError;
39
40
  protected inspectFailureText(text: string): {
40
41
  message: string;
41
42
  authFailure?: boolean;