@lasso-ai/cli 2.1.2 → 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/cli/backends.d.ts +2 -0
- package/dist/cli/backends.js +8 -4
- package/dist/cli/bridge.d.ts +4 -0
- package/dist/cli/bridge.js +238 -58
- package/dist/cli/local-runtime.d.ts +5 -0
- package/dist/cli/local-runtime.js +2 -0
- package/dist/cli/oneshot.js +37 -16
- package/dist/cli/project.js +25 -1
- package/dist/cli/runtime-client.d.ts +13 -0
- package/dist/cli/runtime-client.js +1 -1
- package/dist/overlay.js +195 -203
- package/dist/runtime/action-executor.d.ts +2 -1
- package/dist/runtime/action-executor.js +14 -5
- package/dist/runtime/adapters/codex-cli-adapter.d.ts +1 -0
- package/dist/runtime/adapters/codex-cli-adapter.js +32 -4
- package/dist/runtime/adapters/cursor-adapter.js +1 -1
- package/dist/runtime/adapters/local-agent-adapter.js +10 -3
- package/dist/runtime/adapters/opencode-adapter.js +19 -7
- package/dist/runtime/agent-runtime.d.ts +4 -0
- package/dist/runtime/agent-state-machine.d.ts +4 -0
- package/dist/runtime/agent-state-machine.js +10 -2
- package/dist/runtime/backend-interface.d.ts +2 -0
- package/package.json +1 -1
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);
|
|
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-
|
|
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
|
-
|
|
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
|
|
20033
|
+
const willOpen = commandModelMenu?.hidden === true;
|
|
20180
20034
|
if (willOpen) {
|
|
20181
20035
|
populateModelMenu();
|
|
20182
20036
|
}
|
|
20183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
20568
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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><
|
|
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
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
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
|
-
|
|
23217
|
+
releaseHeldLock(elementKey(selectedElement));
|
|
23225
23218
|
return;
|
|
23226
23219
|
}
|
|
23227
23220
|
bridgeSocket.send(
|
|
23228
23221
|
JSON.stringify({
|
|
23229
|
-
type:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
356
|
+
output: { url, check, pageContext },
|
|
348
357
|
observation: {
|
|
349
358
|
type: "browser",
|
|
350
|
-
summary: `
|
|
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;
|