@lasso-ai/cli 2.1.14 → 2.1.15
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.js +137 -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 +2 -0
- package/dist/cli/runtime-client.js +73 -65
- package/dist/cli/server/vite.js +1 -1
- package/dist/cli/snapshot.js +13 -3
- package/dist/overlay.js +139 -282
- 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-state-machine.js +2 -5
- package/dist/runtime/review.js +3 -7
- 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;
|
|
@@ -13593,16 +13584,7 @@
|
|
|
13593
13584
|
this.commentPins.className = "lasso-comment-pins";
|
|
13594
13585
|
this.dragLayer = document.createElement("div");
|
|
13595
13586
|
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
|
-
);
|
|
13587
|
+
this.shadow.append(this.remoteLayer, this.spotlightBox, this.hoverBox, this.selectedBox, this.label, this.activityStrip, this.commentPins, this.dragLayer);
|
|
13606
13588
|
}
|
|
13607
13589
|
isLassoElement(el) {
|
|
13608
13590
|
if (!el) return false;
|
|
@@ -17133,9 +17115,7 @@
|
|
|
17133
17115
|
if (!avatarsEl || !countEl) return;
|
|
17134
17116
|
avatarsEl.innerHTML = "";
|
|
17135
17117
|
const offline = Boolean(state.collabProjectId && !state.collabJoined);
|
|
17136
|
-
const others = [...state.presenceUsers.values()].filter(
|
|
17137
|
-
(user) => user.socketId !== state.collabSocket?.id
|
|
17138
|
-
);
|
|
17118
|
+
const others = [...state.presenceUsers.values()].filter((user) => user.socketId !== state.collabSocket?.id);
|
|
17139
17119
|
for (const user of others.slice(0, 6)) {
|
|
17140
17120
|
const av = document.createElement("button");
|
|
17141
17121
|
av.type = "button";
|
|
@@ -17322,13 +17302,7 @@
|
|
|
17322
17302
|
}
|
|
17323
17303
|
function getSupportedMimeType() {
|
|
17324
17304
|
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
|
-
];
|
|
17305
|
+
const types = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4", "audio/ogg;codecs=opus", "audio/wav"];
|
|
17332
17306
|
for (const t of types) {
|
|
17333
17307
|
if (MediaRecorder.isTypeSupported(t)) return t;
|
|
17334
17308
|
}
|
|
@@ -17350,53 +17324,48 @@
|
|
|
17350
17324
|
const base64 = await blobToBase64(blob);
|
|
17351
17325
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
17352
17326
|
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
|
-
}
|
|
17327
|
+
const result = await new Promise((resolve, reject) => {
|
|
17328
|
+
const requestId = `transcribe_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
17329
|
+
const timeout = window.setTimeout(() => {
|
|
17330
|
+
cleanup();
|
|
17331
|
+
reject(new Error("Transcription timed out via local bridge"));
|
|
17332
|
+
}, 25e3);
|
|
17333
|
+
const handler = (event) => {
|
|
17334
|
+
try {
|
|
17335
|
+
const msg = JSON.parse(event.data);
|
|
17336
|
+
if (msg.type === "transcribe_result" && msg.requestId === requestId) {
|
|
17337
|
+
cleanup();
|
|
17338
|
+
if (msg.success) {
|
|
17339
|
+
resolve({ text: msg.text || "", provider: msg.provider || "gradium" });
|
|
17340
|
+
} else {
|
|
17341
|
+
reject(new Error(msg.error || "Transcription failed"));
|
|
17370
17342
|
}
|
|
17371
|
-
} catch {
|
|
17372
17343
|
}
|
|
17373
|
-
}
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
state.bridgeSocket?.
|
|
17379
|
-
|
|
17380
|
-
|
|
17381
|
-
|
|
17382
|
-
|
|
17383
|
-
|
|
17384
|
-
|
|
17385
|
-
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
|
|
17389
|
-
|
|
17344
|
+
} catch {
|
|
17345
|
+
}
|
|
17346
|
+
};
|
|
17347
|
+
const cleanup = () => {
|
|
17348
|
+
window.clearTimeout(timeout);
|
|
17349
|
+
state.bridgeSocket?.removeEventListener("message", handler);
|
|
17350
|
+
};
|
|
17351
|
+
state.bridgeSocket?.addEventListener("message", handler);
|
|
17352
|
+
state.bridgeSocket?.send(
|
|
17353
|
+
JSON.stringify({
|
|
17354
|
+
type: "transcribe",
|
|
17355
|
+
requestId,
|
|
17356
|
+
audio: base64,
|
|
17357
|
+
mimeType,
|
|
17358
|
+
language: "en"
|
|
17359
|
+
})
|
|
17360
|
+
);
|
|
17361
|
+
});
|
|
17390
17362
|
return result;
|
|
17391
17363
|
} catch (bridgeErr) {
|
|
17392
17364
|
console.warn("[transcribe] Bridge transcription failed, falling back to direct server fetch:", bridgeErr);
|
|
17393
17365
|
}
|
|
17394
17366
|
}
|
|
17395
17367
|
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
|
-
];
|
|
17368
|
+
const candidateUrls = isLassoPage ? ["https://api.lasso.byorello.space/api/v1/transcribe"] : ["https://api.lasso.byorello.space/api/v1/transcribe", "/api/v1/transcribe"];
|
|
17400
17369
|
let lastError = new Error("Failed to contact transcription service");
|
|
17401
17370
|
for (const url2 of candidateUrls) {
|
|
17402
17371
|
try {
|
|
@@ -17445,12 +17414,7 @@
|
|
|
17445
17414
|
const legacyGetUserMedia = nav && (nav.getUserMedia || nav.webkitGetUserMedia || nav.mozGetUserMedia || nav.msGetUserMedia);
|
|
17446
17415
|
if (legacyGetUserMedia) {
|
|
17447
17416
|
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
|
-
);
|
|
17417
|
+
legacyGetUserMedia.call(nav, { audio: true }, resolve, (err) => reject(new Error(err?.message || "Microphone access was denied.")));
|
|
17454
17418
|
});
|
|
17455
17419
|
}
|
|
17456
17420
|
if (typeof window !== "undefined") {
|
|
@@ -17494,10 +17458,7 @@
|
|
|
17494
17458
|
activeStream = stream;
|
|
17495
17459
|
currentMimeType = getSupportedMimeType() || "audio/webm";
|
|
17496
17460
|
if (typeof MediaRecorder !== "undefined") {
|
|
17497
|
-
const recorder = new MediaRecorder(
|
|
17498
|
-
stream,
|
|
17499
|
-
currentMimeType ? { mimeType: currentMimeType } : void 0
|
|
17500
|
-
);
|
|
17461
|
+
const recorder = new MediaRecorder(stream, currentMimeType ? { mimeType: currentMimeType } : void 0);
|
|
17501
17462
|
activeRecorder = recorder;
|
|
17502
17463
|
recordedChunks = [];
|
|
17503
17464
|
recorder.ondataavailable = (event) => {
|
|
@@ -18091,9 +18052,7 @@
|
|
|
18091
18052
|
presenceUsers.push({ label: user.name, type: "user", color: user.color || "#6ea0ff" });
|
|
18092
18053
|
}
|
|
18093
18054
|
}
|
|
18094
|
-
const filteredStatic = (!query ? STATIC_TAGS : STATIC_TAGS.filter((t) => t.startsWith(query))).map(
|
|
18095
|
-
(t) => ({ label: t, type: "tag", color: "#94a3b8" })
|
|
18096
|
-
);
|
|
18055
|
+
const filteredStatic = (!query ? STATIC_TAGS : STATIC_TAGS.filter((t) => t.startsWith(query))).map((t) => ({ label: t, type: "tag", color: "#94a3b8" }));
|
|
18097
18056
|
const suggestions = [...presenceUsers, ...filteredStatic].slice(0, 6);
|
|
18098
18057
|
if (suggestions.length === 0) {
|
|
18099
18058
|
tagMenu.hidden = true;
|
|
@@ -19038,7 +18997,8 @@
|
|
|
19038
18997
|
function saveNote(text) {
|
|
19039
18998
|
if (collabEmit("note:save", { body: text }, (response) => {
|
|
19040
18999
|
if (!response.ok) saveNoteLocally(text);
|
|
19041
|
-
}))
|
|
19000
|
+
}))
|
|
19001
|
+
return;
|
|
19042
19002
|
saveNoteLocally(text);
|
|
19043
19003
|
}
|
|
19044
19004
|
function saveNoteLocally(text) {
|
|
@@ -19049,33 +19009,21 @@
|
|
|
19049
19009
|
}
|
|
19050
19010
|
function renderMarkdown(raw) {
|
|
19051
19011
|
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
|
-
);
|
|
19012
|
+
t = t.replace(/```([\s\S]*?)```/g, (_, code) => `<pre class="lasso-np-pre"><code>${code.trim()}</code></pre>`);
|
|
19056
19013
|
t = t.replace(/^### (.+)$/gm, '<h3 class="lasso-np-h">$1</h3>');
|
|
19057
19014
|
t = t.replace(/^## (.+)$/gm, '<h2 class="lasso-np-h">$1</h2>');
|
|
19058
19015
|
t = t.replace(/^# (.+)$/gm, '<h1 class="lasso-np-h">$1</h1>');
|
|
19059
19016
|
t = t.replace(/^---$/gm, '<hr class="lasso-np-hr" />');
|
|
19060
19017
|
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
|
-
);
|
|
19018
|
+
t = t.replace(/^- \[x\] (.+)$/gm, '<div class="lasso-np-check done"><span class="lasso-np-check-box">\u2713</span><del>$1</del></div>');
|
|
19019
|
+
t = t.replace(/^- \[ \] (.+)$/gm, '<div class="lasso-np-check"><span class="lasso-np-check-box">\u25CB</span>$1</div>');
|
|
19069
19020
|
t = t.replace(/^[-*] (.+)$/gm, '<li class="lasso-np-li">$1</li>');
|
|
19070
19021
|
t = t.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
|
|
19071
19022
|
t = t.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
19072
19023
|
t = t.replace(/\*(.+?)\*/g, "<em>$1</em>");
|
|
19073
19024
|
t = t.replace(/~~(.+?)~~/g, "<del>$1</del>");
|
|
19074
19025
|
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
|
-
);
|
|
19026
|
+
t = t.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener" class="lasso-np-link">$1</a>');
|
|
19079
19027
|
t = t.replace(/\n\n/g, '</p><p class="lasso-np-p">');
|
|
19080
19028
|
t = t.replace(/\n/g, "<br>");
|
|
19081
19029
|
return `<p class="lasso-np-p">${t}</p>`;
|
|
@@ -19600,51 +19548,6 @@
|
|
|
19600
19548
|
var activeStartTime = 0;
|
|
19601
19549
|
var activeConversationId = null;
|
|
19602
19550
|
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
19551
|
function isRetryIntent(prompt) {
|
|
19649
19552
|
const p = prompt.trim().toLowerCase().replace(/[!?.]+$/, "");
|
|
19650
19553
|
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 +19668,7 @@
|
|
|
19765
19668
|
const data6 = await apiFetch(`/agent/conversations?projectId=${encodeURIComponent(projectId)}`);
|
|
19766
19669
|
if (data6?.conversations && Array.isArray(data6.conversations)) {
|
|
19767
19670
|
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
|
-
];
|
|
19671
|
+
const merged = [...data6.conversations, ...conversationList.filter((local) => !serverIds.has(local.id))];
|
|
19772
19672
|
conversationList = merged;
|
|
19773
19673
|
}
|
|
19774
19674
|
}
|
|
@@ -20561,8 +20461,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20561
20461
|
const taskId2 = `oneshot-${Date.now()}`;
|
|
20562
20462
|
activeTaskId = taskId2;
|
|
20563
20463
|
activeStartTime = Date.now();
|
|
20564
|
-
const
|
|
20565
|
-
const initialStepTitle = isChat ? "Preparing response\u2026" : "Preparing task\u2026";
|
|
20464
|
+
const initialStepTitle = "Preparing task\u2026";
|
|
20566
20465
|
commandMessages.push({
|
|
20567
20466
|
id: taskId2,
|
|
20568
20467
|
role: "assistant",
|
|
@@ -20593,13 +20492,11 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20593
20492
|
if (id) activeConversationId = id;
|
|
20594
20493
|
});
|
|
20595
20494
|
}
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
|
|
20600
|
-
|
|
20601
|
-
});
|
|
20602
|
-
}
|
|
20495
|
+
collabEmit("collab:action", {
|
|
20496
|
+
sessionId: state.collabProjectId,
|
|
20497
|
+
status: "building",
|
|
20498
|
+
summary: prompt.slice(0, 120)
|
|
20499
|
+
});
|
|
20603
20500
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
20604
20501
|
state.bridgeSocket.send(
|
|
20605
20502
|
JSON.stringify({
|
|
@@ -20613,10 +20510,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20613
20510
|
// The current prompt is sent in its dedicated `prompt` field. Keep it
|
|
20614
20511
|
// out of history so the model sees it once, not once as history and
|
|
20615
20512
|
// 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 }))
|
|
20513
|
+
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
20514
|
})
|
|
20621
20515
|
);
|
|
20622
20516
|
} else {
|
|
@@ -20926,13 +20820,15 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
20926
20820
|
const activeFile = msg.activeDiffFile || changes[0]?.filePath;
|
|
20927
20821
|
const scopeHtml = msg.todo && msg.todo.length ? `
|
|
20928
20822
|
<div class="lasso-command-scope-list">
|
|
20929
|
-
${msg.todo.map(
|
|
20823
|
+
${msg.todo.map(
|
|
20824
|
+
(item) => `
|
|
20930
20825
|
<div class="lasso-command-scope-item">
|
|
20931
20826
|
<span class="lasso-command-scope-action ${item.action}">${item.action === "create" ? "+" : item.action === "delete" ? "\u2212" : "~"}</span>
|
|
20932
20827
|
<span class="lasso-command-scope-file">${escapeHtml4(item.file)}</span>
|
|
20933
20828
|
<span class="lasso-command-scope-reason">${escapeHtml4(item.reason)}</span>
|
|
20934
20829
|
</div>
|
|
20935
|
-
`
|
|
20830
|
+
`
|
|
20831
|
+
).join("")}
|
|
20936
20832
|
</div>
|
|
20937
20833
|
` : "";
|
|
20938
20834
|
const approvedCount = changes.length - rejected.size;
|
|
@@ -21162,97 +21058,72 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21162
21058
|
if (payload.sessionId !== state.collabProjectId || !payload.itemId) return;
|
|
21163
21059
|
removeClipboardItem(payload.itemId);
|
|
21164
21060
|
});
|
|
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
|
-
}
|
|
21061
|
+
state.collabSocket.on("collab:action", (payload) => {
|
|
21062
|
+
if (payload.sessionId !== state.collabProjectId) return;
|
|
21063
|
+
const name = payload.user?.name || "A teammate";
|
|
21064
|
+
const status = payload.status || "";
|
|
21065
|
+
if (status === "building" || status === "build") {
|
|
21066
|
+
if (payload.user?.id && payload.user.id !== state.myUser?.id) {
|
|
21067
|
+
state.buildModeUser = { id: payload.user.id, name };
|
|
21068
|
+
showActivity(`\u23F8\uFE0F ${name} is in Build Mode. Editing is paused.`, "#fbbc04");
|
|
21069
|
+
return;
|
|
21070
|
+
}
|
|
21071
|
+
} else if (status === "idle" || status === "done" || status === "complete") {
|
|
21072
|
+
if (state.buildModeUser && (!payload.user?.id || state.buildModeUser.id === payload.user.id)) {
|
|
21073
|
+
state.buildModeUser = null;
|
|
21074
|
+
showActivity(`${name} finished building. Editing resumed.`, "#81c995");
|
|
21075
|
+
return;
|
|
21183
21076
|
}
|
|
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
21077
|
}
|
|
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
|
-
);
|
|
21078
|
+
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}`}`;
|
|
21079
|
+
showActivity(text, userNameColor(payload.user?.id || ""));
|
|
21080
|
+
});
|
|
21081
|
+
state.collabSocket.on("collab:spotlight", (payload) => {
|
|
21082
|
+
if (payload.sessionId !== state.collabProjectId || !payload.elementId) return;
|
|
21083
|
+
const el = state.elementRegistry.get(payload.elementId) || null;
|
|
21084
|
+
const by = payload.by || { id: "", name: "Teammate", photo: "" };
|
|
21085
|
+
spotlightFor(by, el, payload.label || "");
|
|
21086
|
+
});
|
|
21087
|
+
state.collabSocket.on("voice:offer", (payload) => handleOffer(payload));
|
|
21088
|
+
state.collabSocket.on("voice:answer", (payload) => handleAnswer(payload));
|
|
21089
|
+
state.collabSocket.on("voice:candidate", (payload) => handleCandidate(payload));
|
|
21090
|
+
state.collabSocket.on("voice:peer_left", (payload) => closePeer(payload.socketId || ""));
|
|
21213
21091
|
}
|
|
21214
21092
|
function joinCollabSession() {
|
|
21215
21093
|
if (!state.collabSocket?.connected || !state.collabProjectId) return;
|
|
21216
21094
|
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);
|
|
21095
|
+
collabEmit("session:join", { sessionId: state.collabProjectId, selection }, (payload) => {
|
|
21096
|
+
const countEl = getDOM().shadow.querySelector(".lasso-presence-count");
|
|
21097
|
+
if (!payload.ok) {
|
|
21098
|
+
console.warn("[Lasso Collab] Session join failed for", state.collabProjectId, ":", payload.error);
|
|
21099
|
+
state.collabJoined = false;
|
|
21100
|
+
if (countEl) countEl.textContent = state.collabProjectId ? "\xB7 closed" : "";
|
|
21101
|
+
showActivity(payload.error || "Could not join realtime session. Log in to your Lasso workspace and start Lasso to collaborate.", "#fdd663");
|
|
21102
|
+
return;
|
|
21103
|
+
}
|
|
21104
|
+
console.log("[Lasso Collab] Joined realtime session:", state.collabProjectId, "as", payload.me);
|
|
21105
|
+
state.collabJoined = true;
|
|
21106
|
+
if (countEl) countEl.textContent = "";
|
|
21107
|
+
state.myUser = payload.me || null;
|
|
21108
|
+
if (state.myUser?.name) {
|
|
21109
|
+
try {
|
|
21110
|
+
localStorage.setItem("lasso:user:name", state.myUser.name);
|
|
21111
|
+
} catch {
|
|
21248
21112
|
}
|
|
21249
|
-
|
|
21250
|
-
replaceTodos(snapshot.todos || []);
|
|
21251
|
-
renderComments();
|
|
21252
|
-
updateCommentsBadge();
|
|
21253
|
-
startCollabHeartbeat();
|
|
21113
|
+
updateEmptyStateUserName();
|
|
21254
21114
|
}
|
|
21255
|
-
|
|
21115
|
+
const snapshot = payload.snapshot || {};
|
|
21116
|
+
applyPresence(snapshot.presence || []);
|
|
21117
|
+
indexLocks(snapshot.locks || []);
|
|
21118
|
+
for (const c of snapshot.comments || []) {
|
|
21119
|
+
upsertComment(c);
|
|
21120
|
+
}
|
|
21121
|
+
updateLockChip();
|
|
21122
|
+
replaceTodos(snapshot.todos || []);
|
|
21123
|
+
renderComments();
|
|
21124
|
+
updateCommentsBadge();
|
|
21125
|
+
startCollabHeartbeat();
|
|
21126
|
+
});
|
|
21256
21127
|
}
|
|
21257
21128
|
function startCollabHeartbeat() {
|
|
21258
21129
|
if (state.collabHeartbeat) return;
|
|
@@ -21282,16 +21153,20 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21282
21153
|
function initCursorTracking() {
|
|
21283
21154
|
let lastEmit = 0;
|
|
21284
21155
|
const THROTTLE_MS = 50;
|
|
21285
|
-
document.addEventListener(
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21291
|
-
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21156
|
+
document.addEventListener(
|
|
21157
|
+
"mousemove",
|
|
21158
|
+
(e) => {
|
|
21159
|
+
if (!state.collabSocket?.connected || !state.collabJoined || !state.collabProjectId) return;
|
|
21160
|
+
const now = Date.now();
|
|
21161
|
+
if (now - lastEmit < THROTTLE_MS) return;
|
|
21162
|
+
lastEmit = now;
|
|
21163
|
+
collabEmit("presence:update", {
|
|
21164
|
+
sessionId: state.collabProjectId,
|
|
21165
|
+
cursor: { x: e.clientX, y: e.clientY }
|
|
21166
|
+
});
|
|
21167
|
+
},
|
|
21168
|
+
{ passive: true }
|
|
21169
|
+
);
|
|
21295
21170
|
}
|
|
21296
21171
|
function initCollabPagehide() {
|
|
21297
21172
|
window.addEventListener("pagehide", () => {
|
|
@@ -21707,9 +21582,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21707
21582
|
}
|
|
21708
21583
|
}
|
|
21709
21584
|
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
|
-
);
|
|
21585
|
+
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
21586
|
for (const el of sectionEls) {
|
|
21714
21587
|
if (el.closest("#lasso-root")) continue;
|
|
21715
21588
|
const tag = el.tagName.toLowerCase();
|
|
@@ -21811,9 +21684,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21811
21684
|
if (!clean || state.runtimeErrors.includes(clean)) return;
|
|
21812
21685
|
state.runtimeErrors = [...state.runtimeErrors.slice(-4), clean];
|
|
21813
21686
|
if (notifyBridge && state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
21814
|
-
state.bridgeSocket.send(
|
|
21815
|
-
JSON.stringify({ type: "runtime_error", selectionId: state.selectionId, details: clean })
|
|
21816
|
-
);
|
|
21687
|
+
state.bridgeSocket.send(JSON.stringify({ type: "runtime_error", selectionId: state.selectionId, details: clean }));
|
|
21817
21688
|
}
|
|
21818
21689
|
}
|
|
21819
21690
|
function formatConsoleArg(arg) {
|
|
@@ -21830,9 +21701,7 @@ Please proceed directly with the implementation and code changes from this point
|
|
|
21830
21701
|
if (errorListenersInstalled) return;
|
|
21831
21702
|
errorListenersInstalled = true;
|
|
21832
21703
|
window.addEventListener("error", (event) => {
|
|
21833
|
-
reportRuntimeError(
|
|
21834
|
-
`${event.message || "Runtime error"}${event.filename ? ` \xB7 ${event.filename}:${event.lineno}` : ""}`
|
|
21835
|
-
);
|
|
21704
|
+
reportRuntimeError(`${event.message || "Runtime error"}${event.filename ? ` \xB7 ${event.filename}:${event.lineno}` : ""}`);
|
|
21836
21705
|
});
|
|
21837
21706
|
window.addEventListener("unhandledrejection", (event) => {
|
|
21838
21707
|
const reason = event.reason instanceof Error ? event.reason.message : String(event.reason || "Unhandled promise rejection");
|
|
@@ -22104,9 +21973,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22104
21973
|
}
|
|
22105
21974
|
function findReusableAgentTask(instruction, element) {
|
|
22106
21975
|
const normalized = normalizedInstruction(instruction);
|
|
22107
|
-
return state.agentTasks.find(
|
|
22108
|
-
(task) => normalizedInstruction(task.instruction) === normalized && task.element === (element || void 0)
|
|
22109
|
-
);
|
|
21976
|
+
return state.agentTasks.find((task) => normalizedInstruction(task.instruction) === normalized && task.element === (element || void 0));
|
|
22110
21977
|
}
|
|
22111
21978
|
function getComponentConversation(selectionId) {
|
|
22112
21979
|
const task = state.agentTasks.find((candidate) => candidate.selectionId === selectionId);
|
|
@@ -22825,9 +22692,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22825
22692
|
submitBtn.className = "primary";
|
|
22826
22693
|
submitBtn.addEventListener("click", (e) => {
|
|
22827
22694
|
e.preventDefault();
|
|
22828
|
-
const checked = Array.from(
|
|
22829
|
-
optionsContainer?.querySelectorAll(".lasso-agent-prompt-checkbox:checked") || []
|
|
22830
|
-
).map((cb) => cb.value);
|
|
22695
|
+
const checked = Array.from(optionsContainer?.querySelectorAll(".lasso-agent-prompt-checkbox:checked") || []).map((cb) => cb.value);
|
|
22831
22696
|
respondToAgentPrompt(checked.length ? checked.join(", ") : "None");
|
|
22832
22697
|
});
|
|
22833
22698
|
actions.append(skipBtn, submitBtn);
|
|
@@ -22976,10 +22841,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
22976
22841
|
ignoreElements: (node) => node.id === "lasso-root" || Boolean(node.closest?.("#lasso-root"))
|
|
22977
22842
|
};
|
|
22978
22843
|
try {
|
|
22979
|
-
const [fullCanvas, elementCanvas] = await Promise.all([
|
|
22980
|
-
(0, import_html2canvas2.default)(document.body, options),
|
|
22981
|
-
(0, import_html2canvas2.default)(el, options)
|
|
22982
|
-
]);
|
|
22844
|
+
const [fullCanvas, elementCanvas] = await Promise.all([(0, import_html2canvas2.default)(document.body, options), (0, import_html2canvas2.default)(el, options)]);
|
|
22983
22845
|
return {
|
|
22984
22846
|
full: fullCanvas.toDataURL("image/jpeg", 0.72),
|
|
22985
22847
|
element: elementCanvas.toDataURL("image/jpeg", 0.82)
|
|
@@ -23394,10 +23256,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23394
23256
|
requestAgentNotificationPermission();
|
|
23395
23257
|
const bridgeSocket = state.bridgeSocket;
|
|
23396
23258
|
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
|
-
);
|
|
23259
|
+
setAgentStatus("error", "The Lasso agent bridge is not connected. Start Lasso with your dev server and try again.");
|
|
23401
23260
|
return;
|
|
23402
23261
|
}
|
|
23403
23262
|
const ownershipGranted = await acquireOwnership(selectedElement);
|
|
@@ -23441,9 +23300,7 @@ The agent is automatically attempting to fix the build errors...`;
|
|
|
23441
23300
|
const changesHistory = state.changesHistory.map((entry) => ({ ...entry, changes: entry.changes.map((change) => ({ ...change })) }));
|
|
23442
23301
|
const rect = selectedElement.getBoundingClientRect();
|
|
23443
23302
|
const computed = getComputedStyle(selectedElement);
|
|
23444
|
-
const attributes = Object.fromEntries(
|
|
23445
|
-
Array.from(selectedElement.attributes).map((attr) => [attr.name, attr.value])
|
|
23446
|
-
);
|
|
23303
|
+
const attributes = Object.fromEntries(Array.from(selectedElement.attributes).map((attr) => [attr.name, attr.value]));
|
|
23447
23304
|
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
23305
|
const screenshots = needsVisualContext ? await captureElementScreenshot(selectedElement) : await screenshotPromise;
|
|
23449
23306
|
if (bridgeSocket.readyState !== WebSocket.OPEN) {
|
|
@@ -186,7 +186,13 @@ function loadFixtureLines(name) {
|
|
|
186
186
|
adapter.parse(JSON.stringify({ type: "item.completed", item: { item_type: "command_execution", command: "ls", exit_code: 0, status: "completed" } }), ctx, sink);
|
|
187
187
|
adapter.parse(JSON.stringify({
|
|
188
188
|
type: "item.completed",
|
|
189
|
-
item: {
|
|
189
|
+
item: {
|
|
190
|
+
item_type: "file_change",
|
|
191
|
+
changes: [
|
|
192
|
+
{ path: "/proj/src/old.ts", kind: "delete" },
|
|
193
|
+
{ path: "/proj/src/new.ts", kind: "add" },
|
|
194
|
+
],
|
|
195
|
+
},
|
|
190
196
|
}), ctx, sink);
|
|
191
197
|
adapter.parse(JSON.stringify({ type: "turn.completed" }), ctx, sink);
|
|
192
198
|
strict_1.default.equal(state.sessionId, "thr-1");
|