@lasso-ai/cli 2.1.3 → 2.1.6
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/runtime-client.d.ts +13 -0
- package/dist/cli/runtime-client.js +1 -1
- package/dist/overlay.js +205 -167
- 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;
|
|
@@ -20076,10 +19967,10 @@
|
|
|
20076
19967
|
></textarea>
|
|
20077
19968
|
<div class="lasso-command-input-toolbar">
|
|
20078
19969
|
<div class="lasso-command-model-select">
|
|
20079
|
-
<button class="lasso-command-model-btn" type="button" aria-label="Select model">
|
|
19970
|
+
<button class="lasso-command-model-btn" type="button" aria-label="Select model" aria-expanded="false" aria-haspopup="listbox">
|
|
20080
19971
|
<span class="lasso-command-model-icon"></span>
|
|
20081
19972
|
<span class="lasso-command-model-label"></span>
|
|
20082
|
-
<svg class="lasso-
|
|
19973
|
+
<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
19974
|
<path d="M6 9l6 6 6-6"/>
|
|
20084
19975
|
</svg>
|
|
20085
19976
|
</button>
|
|
@@ -20152,7 +20043,7 @@
|
|
|
20152
20043
|
if (!commandHistoryPopover) return;
|
|
20153
20044
|
const isHidden = commandHistoryPopover.hidden;
|
|
20154
20045
|
if (isHidden) {
|
|
20155
|
-
|
|
20046
|
+
setCommandModelMenuOpen(false);
|
|
20156
20047
|
commandHistoryPopover.hidden = false;
|
|
20157
20048
|
commandHistoryBtn?.classList.add("active");
|
|
20158
20049
|
await loadConversationList();
|
|
@@ -20168,6 +20059,11 @@
|
|
|
20168
20059
|
if (!item?.dataset.convId) return;
|
|
20169
20060
|
await switchConversation(item.dataset.convId);
|
|
20170
20061
|
});
|
|
20062
|
+
const setCommandModelMenuOpen = (open) => {
|
|
20063
|
+
if (!commandModelMenu || !commandModelBtn) return;
|
|
20064
|
+
commandModelMenu.hidden = !open;
|
|
20065
|
+
commandModelBtn.setAttribute("aria-expanded", String(open));
|
|
20066
|
+
};
|
|
20171
20067
|
commandModelBtn.addEventListener("click", (event) => {
|
|
20172
20068
|
event.preventDefault();
|
|
20173
20069
|
event.stopPropagation();
|
|
@@ -20176,11 +20072,11 @@
|
|
|
20176
20072
|
commandHistoryBtn?.classList.remove("active");
|
|
20177
20073
|
}
|
|
20178
20074
|
if (commandModelMenu) {
|
|
20179
|
-
const willOpen = commandModelMenu
|
|
20075
|
+
const willOpen = commandModelMenu?.hidden === true;
|
|
20180
20076
|
if (willOpen) {
|
|
20181
20077
|
populateModelMenu();
|
|
20182
20078
|
}
|
|
20183
|
-
|
|
20079
|
+
setCommandModelMenuOpen(willOpen);
|
|
20184
20080
|
}
|
|
20185
20081
|
});
|
|
20186
20082
|
commandModelMenu.addEventListener("click", (event) => {
|
|
@@ -20202,7 +20098,7 @@
|
|
|
20202
20098
|
commandModelLabel.textContent = found.label;
|
|
20203
20099
|
}
|
|
20204
20100
|
populateModelMenu();
|
|
20205
|
-
|
|
20101
|
+
setCommandModelMenuOpen(false);
|
|
20206
20102
|
});
|
|
20207
20103
|
document.addEventListener("click", (event) => {
|
|
20208
20104
|
const path = event.composedPath ? event.composedPath() : [];
|
|
@@ -20210,7 +20106,7 @@
|
|
|
20210
20106
|
if (commandModelMenu && !commandModelMenu.hidden) {
|
|
20211
20107
|
if (!path.includes(commandModelBtn) && !path.includes(commandModelMenu)) {
|
|
20212
20108
|
if (!commandModelBtn?.contains(target) && !commandModelMenu?.contains(target)) {
|
|
20213
|
-
|
|
20109
|
+
setCommandModelMenuOpen(false);
|
|
20214
20110
|
}
|
|
20215
20111
|
}
|
|
20216
20112
|
}
|
|
@@ -20223,6 +20119,11 @@
|
|
|
20223
20119
|
}
|
|
20224
20120
|
}
|
|
20225
20121
|
});
|
|
20122
|
+
document.addEventListener("keydown", (event) => {
|
|
20123
|
+
if (event.key !== "Escape" || commandModelMenu?.hidden !== false) return;
|
|
20124
|
+
setCommandModelMenuOpen(false);
|
|
20125
|
+
commandModelBtn?.focus();
|
|
20126
|
+
});
|
|
20226
20127
|
commandClose.addEventListener("click", (event) => {
|
|
20227
20128
|
event.preventDefault();
|
|
20228
20129
|
event.stopPropagation();
|
|
@@ -20391,6 +20292,10 @@
|
|
|
20391
20292
|
function closeCommandBar() {
|
|
20392
20293
|
if (!commandBarEl) return;
|
|
20393
20294
|
commandBarEl.hidden = true;
|
|
20295
|
+
if (commandModelMenu) {
|
|
20296
|
+
commandModelMenu.hidden = true;
|
|
20297
|
+
commandModelBtn?.setAttribute("aria-expanded", "false");
|
|
20298
|
+
}
|
|
20394
20299
|
isOneShotMode = false;
|
|
20395
20300
|
getDOM().shadow.querySelector(".command-tool")?.classList.remove("active");
|
|
20396
20301
|
}
|
|
@@ -20511,13 +20416,14 @@
|
|
|
20511
20416
|
activeTaskId = taskId2;
|
|
20512
20417
|
activeStartTime = Date.now();
|
|
20513
20418
|
const isChat = isConversationalPrompt(prompt);
|
|
20419
|
+
const initialStepTitle = isChat ? "Preparing response\u2026" : "Preparing task\u2026";
|
|
20514
20420
|
commandMessages.push({
|
|
20515
20421
|
id: taskId2,
|
|
20516
20422
|
role: "assistant",
|
|
20517
20423
|
content: "",
|
|
20518
20424
|
timestamp: Date.now(),
|
|
20519
20425
|
thinking: {
|
|
20520
|
-
steps: [{ title:
|
|
20426
|
+
steps: [{ title: initialStepTitle, status: "running" }],
|
|
20521
20427
|
durationSeconds: 0,
|
|
20522
20428
|
completed: false,
|
|
20523
20429
|
expanded: true
|
|
@@ -20548,12 +20454,6 @@
|
|
|
20548
20454
|
summary: prompt.slice(0, 120)
|
|
20549
20455
|
});
|
|
20550
20456
|
}
|
|
20551
|
-
let pageContext = void 0;
|
|
20552
|
-
try {
|
|
20553
|
-
pageContext = await capturePageContext();
|
|
20554
|
-
} catch (err) {
|
|
20555
|
-
console.warn("[lasso] capturePageContext failed:", err);
|
|
20556
|
-
}
|
|
20557
20457
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
20558
20458
|
state.bridgeSocket.send(
|
|
20559
20459
|
JSON.stringify({
|
|
@@ -20564,8 +20464,13 @@
|
|
|
20564
20464
|
scope: "project",
|
|
20565
20465
|
model: state.selectedModel.id,
|
|
20566
20466
|
provider: state.selectedModel.provider,
|
|
20567
|
-
|
|
20568
|
-
|
|
20467
|
+
// The current prompt is sent in its dedicated `prompt` field. Keep it
|
|
20468
|
+
// out of history so the model sees it once, not once as history and
|
|
20469
|
+
// once as the active request.
|
|
20470
|
+
messages: commandMessages.map((message, index) => ({ message, index })).filter(({ message, index }) => Boolean(message.content) && !message.error && index !== commandMessages.reduce(
|
|
20471
|
+
(last, item, itemIndex) => item.role === "user" && item.content === prompt ? itemIndex : last,
|
|
20472
|
+
-1
|
|
20473
|
+
)).map(({ message }) => message).map((m) => ({ role: m.role, content: m.content }))
|
|
20569
20474
|
})
|
|
20570
20475
|
);
|
|
20571
20476
|
} else {
|
|
@@ -20611,14 +20516,17 @@
|
|
|
20611
20516
|
expanded: true
|
|
20612
20517
|
};
|
|
20613
20518
|
}
|
|
20614
|
-
|
|
20615
|
-
|
|
20519
|
+
const stepTitle = (message.message || "").trim();
|
|
20520
|
+
if (stepTitle && stepTitle !== "Thinking\u2026" && stepTitle !== "Thinking") {
|
|
20521
|
+
for (const step of targetMsg.thinking.steps) {
|
|
20522
|
+
if (step.status === "running") step.status = "completed";
|
|
20523
|
+
}
|
|
20524
|
+
targetMsg.thinking.steps.push({
|
|
20525
|
+
title: stepTitle,
|
|
20526
|
+
detail: message.detail,
|
|
20527
|
+
status: "running"
|
|
20528
|
+
});
|
|
20616
20529
|
}
|
|
20617
|
-
targetMsg.thinking.steps.push({
|
|
20618
|
-
title: message.message,
|
|
20619
|
-
detail: message.detail,
|
|
20620
|
-
status: "running"
|
|
20621
|
-
});
|
|
20622
20530
|
renderMessages();
|
|
20623
20531
|
scrollToBottom();
|
|
20624
20532
|
} else if (message.status === "review" || message.status === "complete") {
|
|
@@ -21583,6 +21491,130 @@
|
|
|
21583
21491
|
}
|
|
21584
21492
|
}
|
|
21585
21493
|
|
|
21494
|
+
// src/overlay/browser/context.ts
|
|
21495
|
+
var import_html2canvas = __toESM(require_html2canvas());
|
|
21496
|
+
async function capturePageContext() {
|
|
21497
|
+
const url2 = window.location.href;
|
|
21498
|
+
const route = window.location.pathname + window.location.search;
|
|
21499
|
+
const title = document.title || "Untitled Page";
|
|
21500
|
+
const doc = document.documentElement;
|
|
21501
|
+
const viewport = {
|
|
21502
|
+
width: window.innerWidth,
|
|
21503
|
+
height: window.innerHeight,
|
|
21504
|
+
scrollX: window.scrollX || window.pageXOffset || 0,
|
|
21505
|
+
scrollY: window.scrollY || window.pageYOffset || 0,
|
|
21506
|
+
scrollHeight: doc.scrollHeight
|
|
21507
|
+
};
|
|
21508
|
+
const headings = [];
|
|
21509
|
+
const headingEls = document.querySelectorAll("h1, h2, h3, h4");
|
|
21510
|
+
for (const el of headingEls) {
|
|
21511
|
+
if (el.closest("#lasso-root")) continue;
|
|
21512
|
+
const text = (el.textContent || "").trim().replace(/\s+/g, " ");
|
|
21513
|
+
if (text) {
|
|
21514
|
+
const level = parseInt(el.tagName.replace(/h/i, ""), 10) || 2;
|
|
21515
|
+
headings.push({ level, text: text.slice(0, 120) });
|
|
21516
|
+
if (headings.length >= 15) break;
|
|
21517
|
+
}
|
|
21518
|
+
}
|
|
21519
|
+
const sections = [];
|
|
21520
|
+
const sectionEls = document.querySelectorAll(
|
|
21521
|
+
"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']"
|
|
21522
|
+
);
|
|
21523
|
+
for (const el of sectionEls) {
|
|
21524
|
+
if (el.closest("#lasso-root")) continue;
|
|
21525
|
+
const tag = el.tagName.toLowerCase();
|
|
21526
|
+
const id = el.id ? `#${el.id}` : "";
|
|
21527
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
21528
|
+
const name = ariaLabel ? `${tag} (${ariaLabel})` : id ? `${tag}${id}` : tag;
|
|
21529
|
+
const textPreview = (el.textContent || "").trim().replace(/\s+/g, " ").slice(0, 160);
|
|
21530
|
+
if (textPreview && !sections.some((s) => s.textPreview === textPreview)) {
|
|
21531
|
+
sections.push({ name, textPreview });
|
|
21532
|
+
if (sections.length >= 12) break;
|
|
21533
|
+
}
|
|
21534
|
+
}
|
|
21535
|
+
const buttons = [];
|
|
21536
|
+
const buttonEls = document.querySelectorAll("button, a[role='button'], input[type='button'], input[type='submit'], a.btn, a[class*='button']");
|
|
21537
|
+
for (const el of buttonEls) {
|
|
21538
|
+
if (el.closest("#lasso-root")) continue;
|
|
21539
|
+
const text = (el.textContent || el.value || "").trim().replace(/\s+/g, " ");
|
|
21540
|
+
if (text && !buttons.includes(text)) {
|
|
21541
|
+
buttons.push(text.slice(0, 50));
|
|
21542
|
+
if (buttons.length >= 12) break;
|
|
21543
|
+
}
|
|
21544
|
+
}
|
|
21545
|
+
const links = [];
|
|
21546
|
+
const linkEls = document.querySelectorAll("nav a, header a, a.nav-link");
|
|
21547
|
+
for (const el of linkEls) {
|
|
21548
|
+
if (el.closest("#lasso-root")) continue;
|
|
21549
|
+
const text = (el.textContent || "").trim().replace(/\s+/g, " ");
|
|
21550
|
+
if (text && !links.includes(text) && !buttons.includes(text)) {
|
|
21551
|
+
links.push(text.slice(0, 40));
|
|
21552
|
+
if (links.length >= 10) break;
|
|
21553
|
+
}
|
|
21554
|
+
}
|
|
21555
|
+
const inputs = [];
|
|
21556
|
+
const inputEls = document.querySelectorAll("input:not([type='hidden']), textarea, select");
|
|
21557
|
+
for (const el of inputEls) {
|
|
21558
|
+
if (el.closest("#lasso-root")) continue;
|
|
21559
|
+
const type = (el.getAttribute("type") || el.tagName.toLowerCase()).slice(0, 20);
|
|
21560
|
+
const placeholder = el.getAttribute("placeholder")?.slice(0, 60);
|
|
21561
|
+
inputs.push({ type, placeholder });
|
|
21562
|
+
if (inputs.length >= 8) break;
|
|
21563
|
+
}
|
|
21564
|
+
const bodyClone = document.body ? document.body.cloneNode(true) : null;
|
|
21565
|
+
if (bodyClone) {
|
|
21566
|
+
const lassoRoot = bodyClone.querySelector("#lasso-root");
|
|
21567
|
+
if (lassoRoot) lassoRoot.remove();
|
|
21568
|
+
}
|
|
21569
|
+
const bodyText = (bodyClone?.innerText || document.body?.innerText || "").replace(/\s+/g, " ").slice(0, 1500);
|
|
21570
|
+
let selectedElement = void 0;
|
|
21571
|
+
if (state.selected && !state.selected.closest("#lasso-root")) {
|
|
21572
|
+
const el = state.selected;
|
|
21573
|
+
selectedElement = {
|
|
21574
|
+
tag: el.tagName.toLowerCase(),
|
|
21575
|
+
id: el.id || void 0,
|
|
21576
|
+
classes: Array.from(el.classList),
|
|
21577
|
+
text: (el.textContent || "").trim().slice(0, 100),
|
|
21578
|
+
source: el.getAttribute("data-source") || el.getAttribute("data-lasso-source") || void 0
|
|
21579
|
+
};
|
|
21580
|
+
}
|
|
21581
|
+
let screenshot = void 0;
|
|
21582
|
+
try {
|
|
21583
|
+
const options = {
|
|
21584
|
+
backgroundColor: null,
|
|
21585
|
+
useCORS: true,
|
|
21586
|
+
logging: false,
|
|
21587
|
+
scale: 0.6,
|
|
21588
|
+
ignoreElements: (node) => node.id === "lasso-root" || Boolean(node.closest?.("#lasso-root"))
|
|
21589
|
+
};
|
|
21590
|
+
const canvasPromise = (0, import_html2canvas.default)(document.body, options);
|
|
21591
|
+
const timeoutPromise = new Promise((r) => setTimeout(() => r(null), 1200));
|
|
21592
|
+
const canvas = await Promise.race([canvasPromise, timeoutPromise]);
|
|
21593
|
+
if (canvas && typeof canvas.toDataURL === "function") {
|
|
21594
|
+
screenshot = canvas.toDataURL("image/jpeg", 0.65);
|
|
21595
|
+
}
|
|
21596
|
+
} catch (err) {
|
|
21597
|
+
console.warn("[lasso] visual snapshot failed:", err);
|
|
21598
|
+
}
|
|
21599
|
+
return {
|
|
21600
|
+
url: url2,
|
|
21601
|
+
route,
|
|
21602
|
+
title,
|
|
21603
|
+
viewport,
|
|
21604
|
+
screenshot,
|
|
21605
|
+
runtimeErrors: [...state.runtimeErrors],
|
|
21606
|
+
domSummary: {
|
|
21607
|
+
headings,
|
|
21608
|
+
sections,
|
|
21609
|
+
buttons,
|
|
21610
|
+
links,
|
|
21611
|
+
inputs,
|
|
21612
|
+
visibleTextSnippet: bodyText
|
|
21613
|
+
},
|
|
21614
|
+
selectedElement
|
|
21615
|
+
};
|
|
21616
|
+
}
|
|
21617
|
+
|
|
21586
21618
|
// src/overlay/bridge/bridge.ts
|
|
21587
21619
|
function reportRuntimeError(details, notifyBridge = true) {
|
|
21588
21620
|
const clean = details.slice(0, 1200);
|
|
@@ -21647,6 +21679,10 @@
|
|
|
21647
21679
|
state.bridgeSocket.addEventListener("message", (event) => {
|
|
21648
21680
|
try {
|
|
21649
21681
|
const message = JSON.parse(event.data);
|
|
21682
|
+
if (message.type === "page_context_request" && message.requestId) {
|
|
21683
|
+
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." }));
|
|
21684
|
+
return;
|
|
21685
|
+
}
|
|
21650
21686
|
if (message.type === "config") {
|
|
21651
21687
|
state.apiKeyConfigured = Boolean(message.apiKeyConfigured);
|
|
21652
21688
|
if (message.collab) {
|
|
@@ -22211,9 +22247,9 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22211
22247
|
</button>
|
|
22212
22248
|
|
|
22213
22249
|
<div class="lasso-prompt-model-wrap">
|
|
22214
|
-
<button class="lasso-prompt-model" type="button" aria-label="Choose model">
|
|
22250
|
+
<button class="lasso-prompt-model" type="button" aria-label="Choose model" aria-expanded="false" aria-haspopup="listbox">
|
|
22215
22251
|
<span class="lasso-prompt-model-name"></span>
|
|
22216
|
-
<svg width="
|
|
22252
|
+
<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
22253
|
<path d="M6 9l6 6 6-6"/>
|
|
22218
22254
|
</svg>
|
|
22219
22255
|
</button>
|
|
@@ -22381,10 +22417,15 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22381
22417
|
};
|
|
22382
22418
|
promptTop.addEventListener("pointerup", stopPromptDrag);
|
|
22383
22419
|
promptTop.addEventListener("pointercancel", stopPromptDrag);
|
|
22420
|
+
const setModelMenuOpen = (open) => {
|
|
22421
|
+
if (!modelMenu || !modelBtn) return;
|
|
22422
|
+
modelMenu.hidden = !open;
|
|
22423
|
+
modelBtn.setAttribute("aria-expanded", String(open));
|
|
22424
|
+
};
|
|
22384
22425
|
modelBtn.addEventListener("click", (event) => {
|
|
22385
22426
|
event.preventDefault();
|
|
22386
22427
|
event.stopPropagation();
|
|
22387
|
-
|
|
22428
|
+
setModelMenuOpen(modelMenu?.hidden === true);
|
|
22388
22429
|
});
|
|
22389
22430
|
modelMenu.addEventListener("click", (event) => {
|
|
22390
22431
|
event.stopPropagation();
|
|
@@ -22401,7 +22442,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22401
22442
|
state.selectedModel = found;
|
|
22402
22443
|
rememberModel(found);
|
|
22403
22444
|
syncModelMenu2();
|
|
22404
|
-
|
|
22445
|
+
setModelMenuOpen(false);
|
|
22405
22446
|
});
|
|
22406
22447
|
document.addEventListener("click", (event) => {
|
|
22407
22448
|
if (!modelMenu || modelMenu.hidden) return;
|
|
@@ -22409,7 +22450,12 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22409
22450
|
if (path.includes(modelBtn) || path.includes(modelMenu)) return;
|
|
22410
22451
|
const target = event.target;
|
|
22411
22452
|
if (modelBtn?.contains(target) || modelMenu?.contains(target)) return;
|
|
22412
|
-
|
|
22453
|
+
setModelMenuOpen(false);
|
|
22454
|
+
});
|
|
22455
|
+
document.addEventListener("keydown", (event) => {
|
|
22456
|
+
if (event.key !== "Escape" || modelMenu?.hidden !== false) return;
|
|
22457
|
+
setModelMenuOpen(false);
|
|
22458
|
+
modelBtn?.focus();
|
|
22413
22459
|
});
|
|
22414
22460
|
refreshModelMenu();
|
|
22415
22461
|
promptInput.addEventListener("input", syncSendButtonState);
|
|
@@ -22677,7 +22723,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22677
22723
|
subHeader.type = "button";
|
|
22678
22724
|
subHeader.className = "lasso-cli-subgroup-header";
|
|
22679
22725
|
subHeader.setAttribute("aria-expanded", String(openCliGroups.has(cliKey)));
|
|
22680
|
-
subHeader.innerHTML = `<span>${providerLabels[cliKey] || cliKey}</span><
|
|
22726
|
+
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
22727
|
const subItems = document.createElement("div");
|
|
22682
22728
|
subItems.className = "lasso-cli-subgroup-items";
|
|
22683
22729
|
subItems.hidden = !openCliGroups.has(cliKey);
|
|
@@ -23156,11 +23202,6 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23156
23202
|
promptInput.style.height = "auto";
|
|
23157
23203
|
syncSendButtonState();
|
|
23158
23204
|
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
23205
|
const bridgeSocket = state.bridgeSocket;
|
|
23165
23206
|
if (!bridgeSocket || bridgeSocket.readyState !== WebSocket.OPEN) {
|
|
23166
23207
|
setAgentStatus(
|
|
@@ -23169,11 +23210,9 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23169
23210
|
);
|
|
23170
23211
|
return;
|
|
23171
23212
|
}
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
}
|
|
23176
|
-
if (!wantsAnswer && state.collabSocket?.connected && state.collabJoined) {
|
|
23213
|
+
const ownershipGranted = await acquireOwnership(selectedElement);
|
|
23214
|
+
if (!ownershipGranted) return;
|
|
23215
|
+
if (state.collabSocket?.connected && state.collabJoined) {
|
|
23177
23216
|
collabEmit("collab:action", {
|
|
23178
23217
|
sessionId: state.collabProjectId,
|
|
23179
23218
|
status: "preparing",
|
|
@@ -23221,14 +23260,13 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23221
23260
|
const message = "The Lasso agent bridge disconnected before the task could start.";
|
|
23222
23261
|
updateAgentTask(task.id, { status: "error", message });
|
|
23223
23262
|
appendChat("error", message, task.id);
|
|
23224
|
-
|
|
23263
|
+
releaseHeldLock(elementKey(selectedElement));
|
|
23225
23264
|
return;
|
|
23226
23265
|
}
|
|
23227
23266
|
bridgeSocket.send(
|
|
23228
23267
|
JSON.stringify({
|
|
23229
|
-
type:
|
|
23268
|
+
type: "edit",
|
|
23230
23269
|
taskId: task.id,
|
|
23231
|
-
question: wantsAnswer ? instruction : void 0,
|
|
23232
23270
|
instruction,
|
|
23233
23271
|
messages,
|
|
23234
23272
|
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;
|