@lasso-ai/cli 2.1.14 → 2.1.16
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/auth.js +1 -7
- package/dist/cli/bridge.d.ts +11 -0
- package/dist/cli/bridge.js +177 -117
- package/dist/cli/host/certificates.js +5 -7
- package/dist/cli/host/daemon.js +16 -5
- package/dist/cli/host/dns.js +4 -1
- package/dist/cli/host/install.js +1 -1
- package/dist/cli/host/next-host-entry.js +1 -3
- package/dist/cli/host/vite-host-entry.js +1 -7
- package/dist/cli/index.js +2 -1
- package/dist/cli/local-runtime.js +3 -8
- package/dist/cli/project.js +8 -12
- package/dist/cli/runtime-client.d.ts +10 -0
- package/dist/cli/runtime-client.js +107 -66
- package/dist/cli/server/vite.js +1 -1
- package/dist/cli/snapshot.js +13 -3
- package/dist/overlay.js +274 -292
- package/dist/runtime/__tests__/adapter-normalization.test.js +7 -1
- package/dist/runtime/action-executor.js +3 -15
- package/dist/runtime/adapters/claude-code-adapter.js +6 -13
- package/dist/runtime/adapters/codex-cli-adapter.js +1 -5
- package/dist/runtime/adapters/local-agent-adapter.js +7 -14
- package/dist/runtime/adapters/opencode-adapter.js +3 -12
- package/dist/runtime/agent-runtime.d.ts +3 -1
- package/dist/runtime/agent-state-machine.js +2 -5
- package/dist/runtime/review.js +3 -7
- package/dist/runtime/verification-engine.d.ts +10 -0
- package/dist/runtime/verification-engine.js +83 -35
- package/dist/runtime/workspace-guard.js +1 -6
- package/package.json +4 -3
package/dist/overlay.js
CHANGED
|
@@ -7815,16 +7815,7 @@
|
|
|
7815
7815
|
});
|
|
7816
7816
|
|
|
7817
7817
|
// src/overlay/state.ts
|
|
7818
|
-
var COLLAB_COLORS = [
|
|
7819
|
-
"#6ea0ff",
|
|
7820
|
-
"#81c995",
|
|
7821
|
-
"#fdd663",
|
|
7822
|
-
"#f28b82",
|
|
7823
|
-
"#c084fc",
|
|
7824
|
-
"#22d3ee",
|
|
7825
|
-
"#fb923c",
|
|
7826
|
-
"#a78bfa"
|
|
7827
|
-
];
|
|
7818
|
+
var COLLAB_COLORS = ["#6ea0ff", "#81c995", "#fdd663", "#f28b82", "#c084fc", "#22d3ee", "#fb923c", "#a78bfa"];
|
|
7828
7819
|
function userNameColor(userId) {
|
|
7829
7820
|
if (!userId) return COLLAB_COLORS[0];
|
|
7830
7821
|
let hash = 0;
|
|
@@ -11531,7 +11522,6 @@
|
|
|
11531
11522
|
align-items: center;
|
|
11532
11523
|
justify-content: space-between;
|
|
11533
11524
|
padding: 6px 8px 8px;
|
|
11534
|
-
border-bottom: 1px solid var(--lo-border-subtle);
|
|
11535
11525
|
font-size: 11px;
|
|
11536
11526
|
font-weight: 600;
|
|
11537
11527
|
color: var(--lo-text-3);
|
|
@@ -11562,6 +11552,48 @@
|
|
|
11562
11552
|
width: 100%;
|
|
11563
11553
|
}
|
|
11564
11554
|
|
|
11555
|
+
.lasso-command-history-load {
|
|
11556
|
+
display: flex;
|
|
11557
|
+
align-items: center;
|
|
11558
|
+
justify-content: space-between;
|
|
11559
|
+
gap: 8px;
|
|
11560
|
+
min-width: 0;
|
|
11561
|
+
flex: 1;
|
|
11562
|
+
padding: 0;
|
|
11563
|
+
border: 0;
|
|
11564
|
+
background: transparent;
|
|
11565
|
+
color: inherit;
|
|
11566
|
+
cursor: pointer;
|
|
11567
|
+
text-align: left;
|
|
11568
|
+
}
|
|
11569
|
+
|
|
11570
|
+
.lasso-command-history-delete {
|
|
11571
|
+
display: inline-flex;
|
|
11572
|
+
align-items: center;
|
|
11573
|
+
justify-content: center;
|
|
11574
|
+
flex: 0 0 auto;
|
|
11575
|
+
width: 24px;
|
|
11576
|
+
height: 24px;
|
|
11577
|
+
padding: 0;
|
|
11578
|
+
border: 0;
|
|
11579
|
+
border-radius: 5px;
|
|
11580
|
+
background: transparent;
|
|
11581
|
+
color: var(--lo-text-3);
|
|
11582
|
+
cursor: pointer;
|
|
11583
|
+
opacity: 0;
|
|
11584
|
+
transition: opacity 120ms ease, color 120ms ease, background 120ms ease;
|
|
11585
|
+
}
|
|
11586
|
+
|
|
11587
|
+
.lasso-command-history-item:hover .lasso-command-history-delete,
|
|
11588
|
+
.lasso-command-history-delete:focus-visible {
|
|
11589
|
+
opacity: 1;
|
|
11590
|
+
}
|
|
11591
|
+
|
|
11592
|
+
.lasso-command-history-delete:hover {
|
|
11593
|
+
color: #fca5a5;
|
|
11594
|
+
background: rgba(239, 68, 68, 0.14);
|
|
11595
|
+
}
|
|
11596
|
+
|
|
11565
11597
|
.lasso-command-history-item:hover {
|
|
11566
11598
|
background: var(--lo-surface-hover);
|
|
11567
11599
|
}
|
|
@@ -13593,16 +13625,7 @@
|
|
|
13593
13625
|
this.commentPins.className = "lasso-comment-pins";
|
|
13594
13626
|
this.dragLayer = document.createElement("div");
|
|
13595
13627
|
this.dragLayer.className = "lasso-drag-layer";
|
|
13596
|
-
this.shadow.append(
|
|
13597
|
-
this.remoteLayer,
|
|
13598
|
-
this.spotlightBox,
|
|
13599
|
-
this.hoverBox,
|
|
13600
|
-
this.selectedBox,
|
|
13601
|
-
this.label,
|
|
13602
|
-
this.activityStrip,
|
|
13603
|
-
this.commentPins,
|
|
13604
|
-
this.dragLayer
|
|
13605
|
-
);
|
|
13628
|
+
this.shadow.append(this.remoteLayer, this.spotlightBox, this.hoverBox, this.selectedBox, this.label, this.activityStrip, this.commentPins, this.dragLayer);
|
|
13606
13629
|
}
|
|
13607
13630
|
isLassoElement(el) {
|
|
13608
13631
|
if (!el) return false;
|
|
@@ -17133,9 +17156,7 @@
|
|
|
17133
17156
|
if (!avatarsEl || !countEl) return;
|
|
17134
17157
|
avatarsEl.innerHTML = "";
|
|
17135
17158
|
const offline = Boolean(state.collabProjectId && !state.collabJoined);
|
|
17136
|
-
const others = [...state.presenceUsers.values()].filter(
|
|
17137
|
-
(user) => user.socketId !== state.collabSocket?.id
|
|
17138
|
-
);
|
|
17159
|
+
const others = [...state.presenceUsers.values()].filter((user) => user.socketId !== state.collabSocket?.id);
|
|
17139
17160
|
for (const user of others.slice(0, 6)) {
|
|
17140
17161
|
const av = document.createElement("button");
|
|
17141
17162
|
av.type = "button";
|
|
@@ -17322,13 +17343,7 @@
|
|
|
17322
17343
|
}
|
|
17323
17344
|
function getSupportedMimeType() {
|
|
17324
17345
|
if (typeof MediaRecorder === "undefined") return "audio/webm";
|
|
17325
|
-
const types = [
|
|
17326
|
-
"audio/webm;codecs=opus",
|
|
17327
|
-
"audio/webm",
|
|
17328
|
-
"audio/mp4",
|
|
17329
|
-
"audio/ogg;codecs=opus",
|
|
17330
|
-
"audio/wav"
|
|
17331
|
-
];
|
|
17346
|
+
const types = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4", "audio/ogg;codecs=opus", "audio/wav"];
|
|
17332
17347
|
for (const t of types) {
|
|
17333
17348
|
if (MediaRecorder.isTypeSupported(t)) return t;
|
|
17334
17349
|
}
|
|
@@ -17350,53 +17365,48 @@
|
|
|
17350
17365
|
const base64 = await blobToBase64(blob);
|
|
17351
17366
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
17352
17367
|
try {
|
|
17353
|
-
const result = await new Promise(
|
|
17354
|
-
(
|
|
17355
|
-
|
|
17356
|
-
|
|
17357
|
-
|
|
17358
|
-
|
|
17359
|
-
|
|
17360
|
-
|
|
17361
|
-
|
|
17362
|
-
|
|
17363
|
-
|
|
17364
|
-
|
|
17365
|
-
|
|
17366
|
-
|
|
17367
|
-
|
|
17368
|
-
reject(new Error(msg.error || "Transcription failed"));
|
|
17369
|
-
}
|
|
17368
|
+
const result = await new Promise((resolve, reject) => {
|
|
17369
|
+
const requestId = `transcribe_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
17370
|
+
const timeout = window.setTimeout(() => {
|
|
17371
|
+
cleanup();
|
|
17372
|
+
reject(new Error("Transcription timed out via local bridge"));
|
|
17373
|
+
}, 25e3);
|
|
17374
|
+
const handler = (event) => {
|
|
17375
|
+
try {
|
|
17376
|
+
const msg = JSON.parse(event.data);
|
|
17377
|
+
if (msg.type === "transcribe_result" && msg.requestId === requestId) {
|
|
17378
|
+
cleanup();
|
|
17379
|
+
if (msg.success) {
|
|
17380
|
+
resolve({ text: msg.text || "", provider: msg.provider || "gradium" });
|
|
17381
|
+
} else {
|
|
17382
|
+
reject(new Error(msg.error || "Transcription failed"));
|
|
17370
17383
|
}
|
|
17371
|
-
} catch {
|
|
17372
17384
|
}
|
|
17373
|
-
}
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
state.bridgeSocket?.
|
|
17379
|
-
|
|
17380
|
-
|
|
17381
|
-
|
|
17382
|
-
|
|
17383
|
-
|
|
17384
|
-
|
|
17385
|
-
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
|
|
17389
|
-
|
|
17385
|
+
} catch {
|
|
17386
|
+
}
|
|
17387
|
+
};
|
|
17388
|
+
const cleanup = () => {
|
|
17389
|
+
window.clearTimeout(timeout);
|
|
17390
|
+
state.bridgeSocket?.removeEventListener("message", handler);
|
|
17391
|
+
};
|
|
17392
|
+
state.bridgeSocket?.addEventListener("message", handler);
|
|
17393
|
+
state.bridgeSocket?.send(
|
|
17394
|
+
JSON.stringify({
|
|
17395
|
+
type: "transcribe",
|
|
17396
|
+
requestId,
|
|
17397
|
+
audio: base64,
|
|
17398
|
+
mimeType,
|
|
17399
|
+
language: "en"
|
|
17400
|
+
})
|
|
17401
|
+
);
|
|
17402
|
+
});
|
|
17390
17403
|
return result;
|
|
17391
17404
|
} catch (bridgeErr) {
|
|
17392
17405
|
console.warn("[transcribe] Bridge transcription failed, falling back to direct server fetch:", bridgeErr);
|
|
17393
17406
|
}
|
|
17394
17407
|
}
|
|
17395
17408
|
const isLassoPage = typeof window !== "undefined" && window.location.hostname.endsWith(".lasso");
|
|
17396
|
-
const candidateUrls = isLassoPage ? ["https://api.lasso.byorello.space/api/v1/transcribe"] : [
|
|
17397
|
-
"https://api.lasso.byorello.space/api/v1/transcribe",
|
|
17398
|
-
"/api/v1/transcribe"
|
|
17399
|
-
];
|
|
17409
|
+
const candidateUrls = isLassoPage ? ["https://api.lasso.byorello.space/api/v1/transcribe"] : ["https://api.lasso.byorello.space/api/v1/transcribe", "/api/v1/transcribe"];
|
|
17400
17410
|
let lastError = new Error("Failed to contact transcription service");
|
|
17401
17411
|
for (const url2 of candidateUrls) {
|
|
17402
17412
|
try {
|
|
@@ -17445,12 +17455,7 @@
|
|
|
17445
17455
|
const legacyGetUserMedia = nav && (nav.getUserMedia || nav.webkitGetUserMedia || nav.mozGetUserMedia || nav.msGetUserMedia);
|
|
17446
17456
|
if (legacyGetUserMedia) {
|
|
17447
17457
|
return new Promise((resolve, reject) => {
|
|
17448
|
-
legacyGetUserMedia.call(
|
|
17449
|
-
nav,
|
|
17450
|
-
{ audio: true },
|
|
17451
|
-
resolve,
|
|
17452
|
-
(err) => reject(new Error(err?.message || "Microphone access was denied."))
|
|
17453
|
-
);
|
|
17458
|
+
legacyGetUserMedia.call(nav, { audio: true }, resolve, (err) => reject(new Error(err?.message || "Microphone access was denied.")));
|
|
17454
17459
|
});
|
|
17455
17460
|
}
|
|
17456
17461
|
if (typeof window !== "undefined") {
|
|
@@ -17494,10 +17499,7 @@
|
|
|
17494
17499
|
activeStream = stream;
|
|
17495
17500
|
currentMimeType = getSupportedMimeType() || "audio/webm";
|
|
17496
17501
|
if (typeof MediaRecorder !== "undefined") {
|
|
17497
|
-
const recorder = new MediaRecorder(
|
|
17498
|
-
stream,
|
|
17499
|
-
currentMimeType ? { mimeType: currentMimeType } : void 0
|
|
17500
|
-
);
|
|
17502
|
+
const recorder = new MediaRecorder(stream, currentMimeType ? { mimeType: currentMimeType } : void 0);
|
|
17501
17503
|
activeRecorder = recorder;
|
|
17502
17504
|
recordedChunks = [];
|
|
17503
17505
|
recorder.ondataavailable = (event) => {
|
|
@@ -18091,9 +18093,7 @@
|
|
|
18091
18093
|
presenceUsers.push({ label: user.name, type: "user", color: user.color || "#6ea0ff" });
|
|
18092
18094
|
}
|
|
18093
18095
|
}
|
|
18094
|
-
const filteredStatic = (!query ? STATIC_TAGS : STATIC_TAGS.filter((t) => t.startsWith(query))).map(
|
|
18095
|
-
(t) => ({ label: t, type: "tag", color: "#94a3b8" })
|
|
18096
|
-
);
|
|
18096
|
+
const filteredStatic = (!query ? STATIC_TAGS : STATIC_TAGS.filter((t) => t.startsWith(query))).map((t) => ({ label: t, type: "tag", color: "#94a3b8" }));
|
|
18097
18097
|
const suggestions = [...presenceUsers, ...filteredStatic].slice(0, 6);
|
|
18098
18098
|
if (suggestions.length === 0) {
|
|
18099
18099
|
tagMenu.hidden = true;
|
|
@@ -19038,7 +19038,8 @@
|
|
|
19038
19038
|
function saveNote(text) {
|
|
19039
19039
|
if (collabEmit("note:save", { body: text }, (response) => {
|
|
19040
19040
|
if (!response.ok) saveNoteLocally(text);
|
|
19041
|
-
}))
|
|
19041
|
+
}))
|
|
19042
|
+
return;
|
|
19042
19043
|
saveNoteLocally(text);
|
|
19043
19044
|
}
|
|
19044
19045
|
function saveNoteLocally(text) {
|
|
@@ -19049,33 +19050,21 @@
|
|
|
19049
19050
|
}
|
|
19050
19051
|
function renderMarkdown(raw) {
|
|
19051
19052
|
let t = raw.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19052
|
-
t = t.replace(
|
|
19053
|
-
/```([\s\S]*?)```/g,
|
|
19054
|
-
(_, code) => `<pre class="lasso-np-pre"><code>${code.trim()}</code></pre>`
|
|
19055
|
-
);
|
|
19053
|
+
t = t.replace(/```([\s\S]*?)```/g, (_, code) => `<pre class="lasso-np-pre"><code>${code.trim()}</code></pre>`);
|
|
19056
19054
|
t = t.replace(/^### (.+)$/gm, '<h3 class="lasso-np-h">$1</h3>');
|
|
19057
19055
|
t = t.replace(/^## (.+)$/gm, '<h2 class="lasso-np-h">$1</h2>');
|
|
19058
19056
|
t = t.replace(/^# (.+)$/gm, '<h1 class="lasso-np-h">$1</h1>');
|
|
19059
19057
|
t = t.replace(/^---$/gm, '<hr class="lasso-np-hr" />');
|
|
19060
19058
|
t = t.replace(/^> (.+)$/gm, '<blockquote class="lasso-np-blockquote">$1</blockquote>');
|
|
19061
|
-
t = t.replace(
|
|
19062
|
-
|
|
19063
|
-
'<div class="lasso-np-check done"><span class="lasso-np-check-box">\u2713</span><del>$1</del></div>'
|
|
19064
|
-
);
|
|
19065
|
-
t = t.replace(
|
|
19066
|
-
/^- \[ \] (.+)$/gm,
|
|
19067
|
-
'<div class="lasso-np-check"><span class="lasso-np-check-box">\u25CB</span>$1</div>'
|
|
19068
|
-
);
|
|
19059
|
+
t = t.replace(/^- \[x\] (.+)$/gm, '<div class="lasso-np-check done"><span class="lasso-np-check-box">\u2713</span><del>$1</del></div>');
|
|
19060
|
+
t = t.replace(/^- \[ \] (.+)$/gm, '<div class="lasso-np-check"><span class="lasso-np-check-box">\u25CB</span>$1</div>');
|
|
19069
19061
|
t = t.replace(/^[-*] (.+)$/gm, '<li class="lasso-np-li">$1</li>');
|
|
19070
19062
|
t = t.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
|
|
19071
19063
|
t = t.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
19072
19064
|
t = t.replace(/\*(.+?)\*/g, "<em>$1</em>");
|
|
19073
19065
|
t = t.replace(/~~(.+?)~~/g, "<del>$1</del>");
|
|
19074
19066
|
t = t.replace(/`(.+?)`/g, '<code class="lasso-np-code">$1</code>');
|
|
19075
|
-
t = t.replace(
|
|
19076
|
-
/\[(.+?)\]\((.+?)\)/g,
|
|
19077
|
-
'<a href="$2" target="_blank" rel="noopener" class="lasso-np-link">$1</a>'
|
|
19078
|
-
);
|
|
19067
|
+
t = t.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener" class="lasso-np-link">$1</a>');
|
|
19079
19068
|
t = t.replace(/\n\n/g, '</p><p class="lasso-np-p">');
|
|
19080
19069
|
t = t.replace(/\n/g, "<br>");
|
|
19081
19070
|
return `<p class="lasso-np-p">${t}</p>`;
|
|
@@ -19600,51 +19589,6 @@
|
|
|
19600
19589
|
var activeStartTime = 0;
|
|
19601
19590
|
var activeConversationId = null;
|
|
19602
19591
|
var conversationList = [];
|
|
19603
|
-
function isConversationalPrompt(prompt) {
|
|
19604
|
-
const p = prompt.trim().toLowerCase().replace(/[!?.,;:]+$/, "");
|
|
19605
|
-
const greetings = [
|
|
19606
|
-
"hi",
|
|
19607
|
-
"hello",
|
|
19608
|
-
"hey",
|
|
19609
|
-
"heya",
|
|
19610
|
-
"howdy",
|
|
19611
|
-
"sup",
|
|
19612
|
-
"yo",
|
|
19613
|
-
"good morning",
|
|
19614
|
-
"good afternoon",
|
|
19615
|
-
"good evening",
|
|
19616
|
-
"thanks",
|
|
19617
|
-
"thank you",
|
|
19618
|
-
"thx",
|
|
19619
|
-
"ty",
|
|
19620
|
-
"cool",
|
|
19621
|
-
"awesome",
|
|
19622
|
-
"great",
|
|
19623
|
-
"nice",
|
|
19624
|
-
"who are you",
|
|
19625
|
-
"what are you",
|
|
19626
|
-
"what can you do",
|
|
19627
|
-
"help",
|
|
19628
|
-
"help me",
|
|
19629
|
-
"what is lasso",
|
|
19630
|
-
"how do you work",
|
|
19631
|
-
"how does this work"
|
|
19632
|
-
];
|
|
19633
|
-
if (greetings.includes(p)) return true;
|
|
19634
|
-
if (/^(hi|hello|hey|howdy|yo)\b/i.test(p) && p.split(/\s+/).length <= 4) {
|
|
19635
|
-
const buildKeywords = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code)\b/i;
|
|
19636
|
-
if (!buildKeywords.test(p)) return true;
|
|
19637
|
-
}
|
|
19638
|
-
const mutationVerbs = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code|replace|set|switch|swap|rewrite|restyle|rebuild|apply)\b/i;
|
|
19639
|
-
const infoPrefixes = /^(what|how|why|when|where|who|which|can you explain|explain|describe|tell me|check out|check|look at|summarize|give me an overview|overview|inspect)\b/i;
|
|
19640
|
-
if (infoPrefixes.test(p) && !mutationVerbs.test(p)) {
|
|
19641
|
-
return true;
|
|
19642
|
-
}
|
|
19643
|
-
if (/\b(about|doing|does this|is this|mean|purpose|work|repo|project|codebase|app|application|page|overview|summary)\b/i.test(p) && !mutationVerbs.test(p)) {
|
|
19644
|
-
return true;
|
|
19645
|
-
}
|
|
19646
|
-
return false;
|
|
19647
|
-
}
|
|
19648
19592
|
function isRetryIntent(prompt) {
|
|
19649
19593
|
const p = prompt.trim().toLowerCase().replace(/[!?.]+$/, "");
|
|
19650
19594
|
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);
|
|
@@ -19765,10 +19709,7 @@
|
|
|
19765
19709
|
const data6 = await apiFetch(`/agent/conversations?projectId=${encodeURIComponent(projectId)}`);
|
|
19766
19710
|
if (data6?.conversations && Array.isArray(data6.conversations)) {
|
|
19767
19711
|
const serverIds = new Set(data6.conversations.map((c) => c.id));
|
|
19768
|
-
const merged = [
|
|
19769
|
-
...data6.conversations,
|
|
19770
|
-
...conversationList.filter((local) => !serverIds.has(local.id))
|
|
19771
|
-
];
|
|
19712
|
+
const merged = [...data6.conversations, ...conversationList.filter((local) => !serverIds.has(local.id))];
|
|
19772
19713
|
conversationList = merged;
|
|
19773
19714
|
}
|
|
19774
19715
|
}
|
|
@@ -19800,17 +19741,44 @@
|
|
|
19800
19741
|
</div>
|
|
19801
19742
|
${conversationList.map(
|
|
19802
19743
|
(conv) => `
|
|
19803
|
-
<
|
|
19804
|
-
<
|
|
19805
|
-
|
|
19806
|
-
<
|
|
19807
|
-
|
|
19808
|
-
|
|
19809
|
-
|
|
19744
|
+
<div class="lasso-command-history-item ${conv.id === activeConversationId ? "active" : ""}" data-conv-id="${escapeHtml4(conv.id)}">
|
|
19745
|
+
<button class="lasso-command-history-load" type="button" title="Open session">
|
|
19746
|
+
<span class="lasso-command-history-title" title="${escapeHtml4(conv.title || "Untitled Session")}">${escapeHtml4(conv.title || "Untitled Session")}</span>
|
|
19747
|
+
<div class="lasso-command-history-meta">
|
|
19748
|
+
<span class="lasso-command-history-scope ${conv.scope || "private"}">${conv.scope || "private"}</span>
|
|
19749
|
+
<span>${formatDateAgo(conv.updatedAt)}</span>
|
|
19750
|
+
</div>
|
|
19751
|
+
</button>
|
|
19752
|
+
<button class="lasso-command-history-delete" type="button" title="Delete session" aria-label="Delete session">
|
|
19753
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v5M14 11v5"/></svg>
|
|
19754
|
+
</button>
|
|
19755
|
+
</div>
|
|
19810
19756
|
`
|
|
19811
19757
|
).join("")}
|
|
19812
19758
|
`;
|
|
19813
19759
|
}
|
|
19760
|
+
async function deleteConversation(convId) {
|
|
19761
|
+
const conversation = conversationList.find((item) => item.id === convId);
|
|
19762
|
+
if (!conversation) return;
|
|
19763
|
+
if (!convId.startsWith("local-session-")) {
|
|
19764
|
+
const deleted = await apiFetch(`/agent/conversations/${encodeURIComponent(convId)}`, { method: "DELETE" });
|
|
19765
|
+
if (!deleted?.success) return;
|
|
19766
|
+
}
|
|
19767
|
+
try {
|
|
19768
|
+
localStorage.removeItem(`lasso:session:${convId}`);
|
|
19769
|
+
const key = getStorageProjectKey();
|
|
19770
|
+
const list2 = JSON.parse(localStorage.getItem(key) || "[]");
|
|
19771
|
+
localStorage.setItem(key, JSON.stringify(list2.filter((item) => item.id !== convId)));
|
|
19772
|
+
} catch {
|
|
19773
|
+
}
|
|
19774
|
+
conversationList = conversationList.filter((item) => item.id !== convId);
|
|
19775
|
+
if (activeConversationId === convId) {
|
|
19776
|
+
activeConversationId = null;
|
|
19777
|
+
commandMessages = [];
|
|
19778
|
+
renderMessages();
|
|
19779
|
+
}
|
|
19780
|
+
renderHistoryPopover();
|
|
19781
|
+
}
|
|
19814
19782
|
async function switchConversation(convId) {
|
|
19815
19783
|
if (activeThinkingInterval) {
|
|
19816
19784
|
clearInterval(activeThinkingInterval);
|
|
@@ -20138,9 +20106,16 @@
|
|
|
20138
20106
|
});
|
|
20139
20107
|
commandHistoryPopover.addEventListener("click", async (event) => {
|
|
20140
20108
|
event.stopPropagation();
|
|
20141
|
-
const
|
|
20109
|
+
const target = event.target;
|
|
20110
|
+
const item = target.closest(".lasso-command-history-item");
|
|
20142
20111
|
if (!item?.dataset.convId) return;
|
|
20143
|
-
|
|
20112
|
+
if (target.closest(".lasso-command-history-delete")) {
|
|
20113
|
+
await deleteConversation(item.dataset.convId);
|
|
20114
|
+
return;
|
|
20115
|
+
}
|
|
20116
|
+
if (target.closest(".lasso-command-history-load")) {
|
|
20117
|
+
await switchConversation(item.dataset.convId);
|
|
20118
|
+
}
|
|
20144
20119
|
});
|
|
20145
20120
|
const setCommandModelMenuOpen = (open) => {
|
|
20146
20121
|
if (!commandModelMenu || !commandModelBtn) return;
|
|
@@ -20294,6 +20269,19 @@
|
|
|
20294
20269
|
}
|
|
20295
20270
|
return;
|
|
20296
20271
|
}
|
|
20272
|
+
const steerBtn = target.closest(".lasso-command-steer-btn");
|
|
20273
|
+
if (steerBtn) {
|
|
20274
|
+
const msgId = steerBtn.closest(".lasso-command-msg")?.dataset.msgId;
|
|
20275
|
+
const msg = commandMessages.find((m) => m.id === msgId);
|
|
20276
|
+
if (msg?.queued && !msg.steering && activeTaskId && state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
20277
|
+
steerBtn.disabled = true;
|
|
20278
|
+
steerBtn.textContent = "Steering\u2026";
|
|
20279
|
+
msg.steering = true;
|
|
20280
|
+
state.bridgeSocket.send(JSON.stringify({ type: "steer", taskId: activeTaskId, queueId: msg.id, prompt: msg.content }));
|
|
20281
|
+
renderMessages();
|
|
20282
|
+
}
|
|
20283
|
+
return;
|
|
20284
|
+
}
|
|
20297
20285
|
const fileCheck = target.closest(".lasso-command-file-check");
|
|
20298
20286
|
if (fileCheck) {
|
|
20299
20287
|
const msgId = fileCheck.closest(".lasso-command-msg")?.dataset.msgId;
|
|
@@ -20505,6 +20493,21 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20505
20493
|
async function handleSubmit() {
|
|
20506
20494
|
if (!commandInput) return;
|
|
20507
20495
|
if (activeTaskId) {
|
|
20496
|
+
const queuedPrompt = commandInput.value.trim();
|
|
20497
|
+
if (queuedPrompt) {
|
|
20498
|
+
commandMessages.push({
|
|
20499
|
+
id: `queued-${Date.now()}`,
|
|
20500
|
+
role: "user",
|
|
20501
|
+
content: queuedPrompt,
|
|
20502
|
+
timestamp: Date.now(),
|
|
20503
|
+
queued: true
|
|
20504
|
+
});
|
|
20505
|
+
commandInput.value = "";
|
|
20506
|
+
autoResizeTextarea(commandInput);
|
|
20507
|
+
renderMessages();
|
|
20508
|
+
scrollToBottom();
|
|
20509
|
+
return;
|
|
20510
|
+
}
|
|
20508
20511
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
20509
20512
|
state.bridgeSocket.send(
|
|
20510
20513
|
JSON.stringify({
|
|
@@ -20561,8 +20564,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20561
20564
|
const taskId2 = `oneshot-${Date.now()}`;
|
|
20562
20565
|
activeTaskId = taskId2;
|
|
20563
20566
|
activeStartTime = Date.now();
|
|
20564
|
-
const
|
|
20565
|
-
const initialStepTitle = isChat ? "Preparing response\u2026" : "Preparing task\u2026";
|
|
20567
|
+
const initialStepTitle = "Preparing task\u2026";
|
|
20566
20568
|
commandMessages.push({
|
|
20567
20569
|
id: taskId2,
|
|
20568
20570
|
role: "assistant",
|
|
@@ -20593,13 +20595,11 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20593
20595
|
if (id) activeConversationId = id;
|
|
20594
20596
|
});
|
|
20595
20597
|
}
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
|
|
20600
|
-
|
|
20601
|
-
});
|
|
20602
|
-
}
|
|
20598
|
+
collabEmit("collab:action", {
|
|
20599
|
+
sessionId: state.collabProjectId,
|
|
20600
|
+
status: "building",
|
|
20601
|
+
summary: prompt.slice(0, 120)
|
|
20602
|
+
});
|
|
20603
20603
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
20604
20604
|
state.bridgeSocket.send(
|
|
20605
20605
|
JSON.stringify({
|
|
@@ -20613,10 +20613,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20613
20613
|
// The current prompt is sent in its dedicated `prompt` field. Keep it
|
|
20614
20614
|
// out of history so the model sees it once, not once as history and
|
|
20615
20615
|
// once as the active request.
|
|
20616
|
-
messages: commandMessages.map((message, index) => ({ message, index })).filter(({ message, index }) => Boolean(message.content) && !message.error && index !== commandMessages.reduce(
|
|
20617
|
-
(last, item, itemIndex) => item.role === "user" && item.content === prompt ? itemIndex : last,
|
|
20618
|
-
-1
|
|
20619
|
-
)).map(({ message }) => message).map((m) => ({ role: m.role, content: m.content }))
|
|
20616
|
+
messages: commandMessages.map((message, index) => ({ message, index })).filter(({ message, index }) => Boolean(message.content) && !message.error && index !== commandMessages.reduce((last, item, itemIndex) => item.role === "user" && item.content === prompt ? itemIndex : last, -1)).map(({ message }) => message).map((m) => ({ role: m.role, content: m.content }))
|
|
20620
20617
|
})
|
|
20621
20618
|
);
|
|
20622
20619
|
} else {
|
|
@@ -20769,6 +20766,18 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20769
20766
|
renderMessages();
|
|
20770
20767
|
}
|
|
20771
20768
|
}
|
|
20769
|
+
function handleCommandBarSteerResult(message) {
|
|
20770
|
+
const queued = commandMessages.find((msg) => msg.id === message.queueId);
|
|
20771
|
+
if (!queued) return;
|
|
20772
|
+
queued.steering = false;
|
|
20773
|
+
if (message.success) {
|
|
20774
|
+
queued.queued = false;
|
|
20775
|
+
queued.steered = true;
|
|
20776
|
+
} else {
|
|
20777
|
+
queued.error = message.error || "The agent could not accept this steering prompt.";
|
|
20778
|
+
}
|
|
20779
|
+
renderMessages();
|
|
20780
|
+
}
|
|
20772
20781
|
function handleCommandBarPrompt(message) {
|
|
20773
20782
|
const taskId2 = message.taskId;
|
|
20774
20783
|
let targetMsg = commandMessages.find((m) => m.id === taskId2);
|
|
@@ -20822,6 +20831,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20822
20831
|
html += `
|
|
20823
20832
|
<div class="lasso-command-msg user" data-msg-id="${msg.id}">
|
|
20824
20833
|
<div class="lasso-command-msg-bubble">${escapeHtml4(msg.content)}</div>
|
|
20834
|
+
${msg.queued ? `<button class="lasso-command-steer-btn" type="button"${msg.steering ? " disabled" : ""} style="margin-top: 6px; padding: 4px 9px; border: 1px solid rgba(96, 165, 250, 0.45); border-radius: 6px; background: rgba(59, 130, 246, 0.14); color: #bfdbfe; cursor: pointer;">${msg.steering ? "Steering\u2026" : "Steer"}</button>` : msg.steered ? `<span class="lasso-command-steered-label" style="display: inline-block; margin-top: 6px; color: #93c5fd; font-size: 12px;">Steered into next turn</span>` : ""}
|
|
20825
20835
|
</div>
|
|
20826
20836
|
`;
|
|
20827
20837
|
} else {
|
|
@@ -20926,13 +20936,15 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20926
20936
|
const activeFile = msg.activeDiffFile || changes[0]?.filePath;
|
|
20927
20937
|
const scopeHtml = msg.todo && msg.todo.length ? `
|
|
20928
20938
|
<div class="lasso-command-scope-list">
|
|
20929
|
-
${msg.todo.map(
|
|
20939
|
+
${msg.todo.map(
|
|
20940
|
+
(item) => `
|
|
20930
20941
|
<div class="lasso-command-scope-item">
|
|
20931
20942
|
<span class="lasso-command-scope-action ${item.action}">${item.action === "create" ? "+" : item.action === "delete" ? "\u2212" : "~"}</span>
|
|
20932
20943
|
<span class="lasso-command-scope-file">${escapeHtml4(item.file)}</span>
|
|
20933
20944
|
<span class="lasso-command-scope-reason">${escapeHtml4(item.reason)}</span>
|
|
20934
20945
|
</div>
|
|
20935
|
-
`
|
|
20946
|
+
`
|
|
20947
|
+
).join("")}
|
|
20936
20948
|
</div>
|
|
20937
20949
|
` : "";
|
|
20938
20950
|
const approvedCount = changes.length - rejected.size;
|
|
@@ -21162,97 +21174,72 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21162
21174
|
if (payload.sessionId !== state.collabProjectId || !payload.itemId) return;
|
|
21163
21175
|
removeClipboardItem(payload.itemId);
|
|
21164
21176
|
});
|
|
21165
|
-
state.collabSocket.on(
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
showActivity(`${name} finished building. Editing resumed.`, "#81c995");
|
|
21181
|
-
return;
|
|
21182
|
-
}
|
|
21177
|
+
state.collabSocket.on("collab:action", (payload) => {
|
|
21178
|
+
if (payload.sessionId !== state.collabProjectId) return;
|
|
21179
|
+
const name = payload.user?.name || "A teammate";
|
|
21180
|
+
const status = payload.status || "";
|
|
21181
|
+
if (status === "building" || status === "build") {
|
|
21182
|
+
if (payload.user?.id && payload.user.id !== state.myUser?.id) {
|
|
21183
|
+
state.buildModeUser = { id: payload.user.id, name };
|
|
21184
|
+
showActivity(`\u23F8\uFE0F ${name} is in Build Mode. Editing is paused.`, "#fbbc04");
|
|
21185
|
+
return;
|
|
21186
|
+
}
|
|
21187
|
+
} else if (status === "idle" || status === "done" || status === "complete") {
|
|
21188
|
+
if (state.buildModeUser && (!payload.user?.id || state.buildModeUser.id === payload.user.id)) {
|
|
21189
|
+
state.buildModeUser = null;
|
|
21190
|
+
showActivity(`${name} finished building. Editing resumed.`, "#81c995");
|
|
21191
|
+
return;
|
|
21183
21192
|
}
|
|
21184
|
-
const text = payload.summary ? `${name} is ${status === "idle" ? "done" : status.replace(/e?$/, "ing")} \u2014 ${payload.summary.slice(0, 90)}` : `${name} ${status === "idle" ? "finished working" : `is ${status}`}`;
|
|
21185
|
-
showActivity(text, userNameColor(payload.user?.id || ""));
|
|
21186
|
-
}
|
|
21187
|
-
);
|
|
21188
|
-
state.collabSocket.on(
|
|
21189
|
-
"collab:spotlight",
|
|
21190
|
-
(payload) => {
|
|
21191
|
-
if (payload.sessionId !== state.collabProjectId || !payload.elementId) return;
|
|
21192
|
-
const el = state.elementRegistry.get(payload.elementId) || null;
|
|
21193
|
-
const by = payload.by || { id: "", name: "Teammate", photo: "" };
|
|
21194
|
-
spotlightFor(by, el, payload.label || "");
|
|
21195
21193
|
}
|
|
21196
|
-
|
|
21197
|
-
|
|
21198
|
-
|
|
21199
|
-
|
|
21200
|
-
|
|
21201
|
-
|
|
21202
|
-
"
|
|
21203
|
-
(payload
|
|
21204
|
-
);
|
|
21205
|
-
state.collabSocket.on(
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
);
|
|
21209
|
-
state.collabSocket.on(
|
|
21210
|
-
"voice:peer_left",
|
|
21211
|
-
(payload) => closePeer(payload.socketId || "")
|
|
21212
|
-
);
|
|
21194
|
+
const text = payload.summary ? `${name} is ${status === "idle" ? "done" : status.replace(/e?$/, "ing")} \u2014 ${payload.summary.slice(0, 90)}` : `${name} ${status === "idle" ? "finished working" : `is ${status}`}`;
|
|
21195
|
+
showActivity(text, userNameColor(payload.user?.id || ""));
|
|
21196
|
+
});
|
|
21197
|
+
state.collabSocket.on("collab:spotlight", (payload) => {
|
|
21198
|
+
if (payload.sessionId !== state.collabProjectId || !payload.elementId) return;
|
|
21199
|
+
const el = state.elementRegistry.get(payload.elementId) || null;
|
|
21200
|
+
const by = payload.by || { id: "", name: "Teammate", photo: "" };
|
|
21201
|
+
spotlightFor(by, el, payload.label || "");
|
|
21202
|
+
});
|
|
21203
|
+
state.collabSocket.on("voice:offer", (payload) => handleOffer(payload));
|
|
21204
|
+
state.collabSocket.on("voice:answer", (payload) => handleAnswer(payload));
|
|
21205
|
+
state.collabSocket.on("voice:candidate", (payload) => handleCandidate(payload));
|
|
21206
|
+
state.collabSocket.on("voice:peer_left", (payload) => closePeer(payload.socketId || ""));
|
|
21213
21207
|
}
|
|
21214
21208
|
function joinCollabSession() {
|
|
21215
21209
|
if (!state.collabSocket?.connected || !state.collabProjectId) return;
|
|
21216
21210
|
const selection = currentSelectionPayload();
|
|
21217
|
-
collabEmit(
|
|
21218
|
-
"
|
|
21219
|
-
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
if (
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21227
|
-
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
if (countEl) countEl.textContent = "";
|
|
21235
|
-
state.myUser = payload.me || null;
|
|
21236
|
-
if (state.myUser?.name) {
|
|
21237
|
-
try {
|
|
21238
|
-
localStorage.setItem("lasso:user:name", state.myUser.name);
|
|
21239
|
-
} catch {
|
|
21240
|
-
}
|
|
21241
|
-
updateEmptyStateUserName();
|
|
21242
|
-
}
|
|
21243
|
-
const snapshot = payload.snapshot || {};
|
|
21244
|
-
applyPresence(snapshot.presence || []);
|
|
21245
|
-
indexLocks(snapshot.locks || []);
|
|
21246
|
-
for (const c of snapshot.comments || []) {
|
|
21247
|
-
upsertComment(c);
|
|
21211
|
+
collabEmit("session:join", { sessionId: state.collabProjectId, selection }, (payload) => {
|
|
21212
|
+
const countEl = getDOM().shadow.querySelector(".lasso-presence-count");
|
|
21213
|
+
if (!payload.ok) {
|
|
21214
|
+
console.warn("[Lasso Collab] Session join failed for", state.collabProjectId, ":", payload.error);
|
|
21215
|
+
state.collabJoined = false;
|
|
21216
|
+
if (countEl) countEl.textContent = state.collabProjectId ? "\xB7 closed" : "";
|
|
21217
|
+
showActivity(payload.error || "Could not join realtime session. Log in to your Lasso workspace and start Lasso to collaborate.", "#fdd663");
|
|
21218
|
+
return;
|
|
21219
|
+
}
|
|
21220
|
+
console.log("[Lasso Collab] Joined realtime session:", state.collabProjectId, "as", payload.me);
|
|
21221
|
+
state.collabJoined = true;
|
|
21222
|
+
if (countEl) countEl.textContent = "";
|
|
21223
|
+
state.myUser = payload.me || null;
|
|
21224
|
+
if (state.myUser?.name) {
|
|
21225
|
+
try {
|
|
21226
|
+
localStorage.setItem("lasso:user:name", state.myUser.name);
|
|
21227
|
+
} catch {
|
|
21248
21228
|
}
|
|
21249
|
-
|
|
21250
|
-
replaceTodos(snapshot.todos || []);
|
|
21251
|
-
renderComments();
|
|
21252
|
-
updateCommentsBadge();
|
|
21253
|
-
startCollabHeartbeat();
|
|
21229
|
+
updateEmptyStateUserName();
|
|
21254
21230
|
}
|
|
21255
|
-
|
|
21231
|
+
const snapshot = payload.snapshot || {};
|
|
21232
|
+
applyPresence(snapshot.presence || []);
|
|
21233
|
+
indexLocks(snapshot.locks || []);
|
|
21234
|
+
for (const c of snapshot.comments || []) {
|
|
21235
|
+
upsertComment(c);
|
|
21236
|
+
}
|
|
21237
|
+
updateLockChip();
|
|
21238
|
+
replaceTodos(snapshot.todos || []);
|
|
21239
|
+
renderComments();
|
|
21240
|
+
updateCommentsBadge();
|
|
21241
|
+
startCollabHeartbeat();
|
|
21242
|
+
});
|
|
21256
21243
|
}
|
|
21257
21244
|
function startCollabHeartbeat() {
|
|
21258
21245
|
if (state.collabHeartbeat) return;
|
|
@@ -21282,16 +21269,20 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21282
21269
|
function initCursorTracking() {
|
|
21283
21270
|
let lastEmit = 0;
|
|
21284
21271
|
const THROTTLE_MS = 50;
|
|
21285
|
-
document.addEventListener(
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21291
|
-
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21272
|
+
document.addEventListener(
|
|
21273
|
+
"mousemove",
|
|
21274
|
+
(e) => {
|
|
21275
|
+
if (!state.collabSocket?.connected || !state.collabJoined || !state.collabProjectId) return;
|
|
21276
|
+
const now = Date.now();
|
|
21277
|
+
if (now - lastEmit < THROTTLE_MS) return;
|
|
21278
|
+
lastEmit = now;
|
|
21279
|
+
collabEmit("presence:update", {
|
|
21280
|
+
sessionId: state.collabProjectId,
|
|
21281
|
+
cursor: { x: e.clientX, y: e.clientY }
|
|
21282
|
+
});
|
|
21283
|
+
},
|
|
21284
|
+
{ passive: true }
|
|
21285
|
+
);
|
|
21295
21286
|
}
|
|
21296
21287
|
function initCollabPagehide() {
|
|
21297
21288
|
window.addEventListener("pagehide", () => {
|
|
@@ -21707,9 +21698,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21707
21698
|
}
|
|
21708
21699
|
}
|
|
21709
21700
|
const sections = [];
|
|
21710
|
-
const sectionEls = document.querySelectorAll(
|
|
21711
|
-
"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']"
|
|
21712
|
-
);
|
|
21701
|
+
const sectionEls = document.querySelectorAll("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']");
|
|
21713
21702
|
for (const el of sectionEls) {
|
|
21714
21703
|
if (el.closest("#lasso-root")) continue;
|
|
21715
21704
|
const tag = el.tagName.toLowerCase();
|
|
@@ -21811,9 +21800,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21811
21800
|
if (!clean || state.runtimeErrors.includes(clean)) return;
|
|
21812
21801
|
state.runtimeErrors = [...state.runtimeErrors.slice(-4), clean];
|
|
21813
21802
|
if (notifyBridge && state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
21814
|
-
state.bridgeSocket.send(
|
|
21815
|
-
JSON.stringify({ type: "runtime_error", selectionId: state.selectionId, details: clean })
|
|
21816
|
-
);
|
|
21803
|
+
state.bridgeSocket.send(JSON.stringify({ type: "runtime_error", selectionId: state.selectionId, details: clean }));
|
|
21817
21804
|
}
|
|
21818
21805
|
}
|
|
21819
21806
|
function formatConsoleArg(arg) {
|
|
@@ -21830,9 +21817,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21830
21817
|
if (errorListenersInstalled) return;
|
|
21831
21818
|
errorListenersInstalled = true;
|
|
21832
21819
|
window.addEventListener("error", (event) => {
|
|
21833
|
-
reportRuntimeError(
|
|
21834
|
-
`${event.message || "Runtime error"}${event.filename ? ` \xB7 ${event.filename}:${event.lineno}` : ""}`
|
|
21835
|
-
);
|
|
21820
|
+
reportRuntimeError(`${event.message || "Runtime error"}${event.filename ? ` \xB7 ${event.filename}:${event.lineno}` : ""}`);
|
|
21836
21821
|
});
|
|
21837
21822
|
window.addEventListener("unhandledrejection", (event) => {
|
|
21838
21823
|
const reason = event.reason instanceof Error ? event.reason.message : String(event.reason || "Unhandled promise rejection");
|
|
@@ -21952,6 +21937,15 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21952
21937
|
window.dispatchEvent(new CustomEvent("lasso-page-folder-created", { detail: { path: message.path || "", error: message.error } }));
|
|
21953
21938
|
return;
|
|
21954
21939
|
}
|
|
21940
|
+
if (message.type === "steer_result" && message.taskId && message.queueId) {
|
|
21941
|
+
handleCommandBarSteerResult({
|
|
21942
|
+
taskId: message.taskId,
|
|
21943
|
+
queueId: message.queueId,
|
|
21944
|
+
success: Boolean(message.success),
|
|
21945
|
+
error: message.error
|
|
21946
|
+
});
|
|
21947
|
+
return;
|
|
21948
|
+
}
|
|
21955
21949
|
if (message.type === "agent_status" && message.status && message.message) {
|
|
21956
21950
|
const taskId2 = message.taskId;
|
|
21957
21951
|
if (isCommandBarTaskId(taskId2)) {
|
|
@@ -22104,9 +22098,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22104
22098
|
}
|
|
22105
22099
|
function findReusableAgentTask(instruction, element) {
|
|
22106
22100
|
const normalized = normalizedInstruction(instruction);
|
|
22107
|
-
return state.agentTasks.find(
|
|
22108
|
-
(task) => normalizedInstruction(task.instruction) === normalized && task.element === (element || void 0)
|
|
22109
|
-
);
|
|
22101
|
+
return state.agentTasks.find((task) => normalizedInstruction(task.instruction) === normalized && task.element === (element || void 0));
|
|
22110
22102
|
}
|
|
22111
22103
|
function getComponentConversation(selectionId) {
|
|
22112
22104
|
const task = state.agentTasks.find((candidate) => candidate.selectionId === selectionId);
|
|
@@ -22825,9 +22817,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22825
22817
|
submitBtn.className = "primary";
|
|
22826
22818
|
submitBtn.addEventListener("click", (e) => {
|
|
22827
22819
|
e.preventDefault();
|
|
22828
|
-
const checked = Array.from(
|
|
22829
|
-
optionsContainer?.querySelectorAll(".lasso-agent-prompt-checkbox:checked") || []
|
|
22830
|
-
).map((cb) => cb.value);
|
|
22820
|
+
const checked = Array.from(optionsContainer?.querySelectorAll(".lasso-agent-prompt-checkbox:checked") || []).map((cb) => cb.value);
|
|
22831
22821
|
respondToAgentPrompt(checked.length ? checked.join(", ") : "None");
|
|
22832
22822
|
});
|
|
22833
22823
|
actions.append(skipBtn, submitBtn);
|
|
@@ -22976,10 +22966,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22976
22966
|
ignoreElements: (node) => node.id === "lasso-root" || Boolean(node.closest?.("#lasso-root"))
|
|
22977
22967
|
};
|
|
22978
22968
|
try {
|
|
22979
|
-
const [fullCanvas, elementCanvas] = await Promise.all([
|
|
22980
|
-
(0, import_html2canvas2.default)(document.body, options),
|
|
22981
|
-
(0, import_html2canvas2.default)(el, options)
|
|
22982
|
-
]);
|
|
22969
|
+
const [fullCanvas, elementCanvas] = await Promise.all([(0, import_html2canvas2.default)(document.body, options), (0, import_html2canvas2.default)(el, options)]);
|
|
22983
22970
|
return {
|
|
22984
22971
|
full: fullCanvas.toDataURL("image/jpeg", 0.72),
|
|
22985
22972
|
element: elementCanvas.toDataURL("image/jpeg", 0.82)
|
|
@@ -23394,10 +23381,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23394
23381
|
requestAgentNotificationPermission();
|
|
23395
23382
|
const bridgeSocket = state.bridgeSocket;
|
|
23396
23383
|
if (!bridgeSocket || bridgeSocket.readyState !== WebSocket.OPEN) {
|
|
23397
|
-
setAgentStatus(
|
|
23398
|
-
"error",
|
|
23399
|
-
"The Lasso agent bridge is not connected. Start Lasso with your dev server and try again."
|
|
23400
|
-
);
|
|
23384
|
+
setAgentStatus("error", "The Lasso agent bridge is not connected. Start Lasso with your dev server and try again.");
|
|
23401
23385
|
return;
|
|
23402
23386
|
}
|
|
23403
23387
|
const ownershipGranted = await acquireOwnership(selectedElement);
|
|
@@ -23441,9 +23425,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23441
23425
|
const changesHistory = state.changesHistory.map((entry) => ({ ...entry, changes: entry.changes.map((change) => ({ ...change })) }));
|
|
23442
23426
|
const rect = selectedElement.getBoundingClientRect();
|
|
23443
23427
|
const computed = getComputedStyle(selectedElement);
|
|
23444
|
-
const attributes = Object.fromEntries(
|
|
23445
|
-
Array.from(selectedElement.attributes).map((attr) => [attr.name, attr.value])
|
|
23446
|
-
);
|
|
23428
|
+
const attributes = Object.fromEntries(Array.from(selectedElement.attributes).map((attr) => [attr.name, attr.value]));
|
|
23447
23429
|
const needsVisualContext = /\b(look|visual|appearance|color|colour|background|image|icon|spacing|layout|position|align|responsive|style|restyle|font|size)\b/i.test(instruction);
|
|
23448
23430
|
const screenshots = needsVisualContext ? await captureElementScreenshot(selectedElement) : await screenshotPromise;
|
|
23449
23431
|
if (bridgeSocket.readyState !== WebSocket.OPEN) {
|