@lasso-ai/cli 1.0.17 → 1.0.19
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/agent.js +35 -2
- package/dist/cli/bridge.d.ts +10 -0
- package/dist/cli/bridge.js +58 -43
- package/dist/overlay.js +248 -34
- package/package.json +1 -1
package/dist/cli/agent.js
CHANGED
|
@@ -193,6 +193,39 @@ function extractLocalAgentText(raw, provider) {
|
|
|
193
193
|
}
|
|
194
194
|
return texts.at(-1) || raw;
|
|
195
195
|
}
|
|
196
|
+
function extractLocalAgentProposal(raw, provider) {
|
|
197
|
+
const outputs = [];
|
|
198
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
199
|
+
try {
|
|
200
|
+
const event = JSON.parse(line);
|
|
201
|
+
const item = event.item;
|
|
202
|
+
const part = event.part;
|
|
203
|
+
const values = provider === "claude-code"
|
|
204
|
+
? [event.result, ...(event.message?.content || []).map((entry) => entry.text)]
|
|
205
|
+
: provider === "opencode"
|
|
206
|
+
? [part?.type === "text" ? part.text : undefined, event.text, event.output_text]
|
|
207
|
+
: [event.text, event.output_text, item?.text, item?.output_text, item?.message];
|
|
208
|
+
for (const value of values)
|
|
209
|
+
if (typeof value === "string" && value.trim())
|
|
210
|
+
outputs.push(value);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
if (line.trim())
|
|
214
|
+
outputs.push(line);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Tool events are interleaved with the final answer. Try text events in
|
|
218
|
+
// reverse order, then the complete stream as a final fallback.
|
|
219
|
+
for (const output of [...outputs.reverse(), raw]) {
|
|
220
|
+
try {
|
|
221
|
+
return jsonFrom(output);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Keep looking; this output may only be a progress or tool event.
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
throw new Error("The agent returned no valid reviewable changes. Progress output may have been mixed with the final JSON.");
|
|
228
|
+
}
|
|
196
229
|
function snippet(value, max = 80) {
|
|
197
230
|
const s = String(value ?? "").trim().replace(/\s+/g, " ");
|
|
198
231
|
return s.length > max ? `${s.slice(0, max)}…` : s;
|
|
@@ -309,7 +342,7 @@ function localCommand(provider, model, prompt) {
|
|
|
309
342
|
return { command: "claude", args: ["-p", prompt || "", "--output-format", "stream-json", "--verbose", "--permission-mode", "plan", "--max-turns", "3", ...(selectedModel ? ["--model", selectedModel] : [])] };
|
|
310
343
|
}
|
|
311
344
|
if (provider === "opencode") {
|
|
312
|
-
return { command: "opencode", args: ["run", "--format", "json", ...(selectedModel ? ["--model", selectedModel] : []), prompt || ""] };
|
|
345
|
+
return { command: "opencode", args: ["run", "--format", "json", "--agent", "plan", ...(selectedModel ? ["--model", selectedModel] : []), prompt || ""] };
|
|
313
346
|
}
|
|
314
347
|
return { command: "codex", args: ["exec", "--json", "--sandbox", "read-only", "--skip-git-repo-check", ...(selectedModel ? ["--model", selectedModel] : []), prompt || ""] };
|
|
315
348
|
}
|
|
@@ -355,7 +388,7 @@ async function proposeWithLocalAgent(cwd, instruction, context, config, signal,
|
|
|
355
388
|
}
|
|
356
389
|
if (exitCode !== 0)
|
|
357
390
|
throw new Error(localAgentError(command, stderr, exitCode));
|
|
358
|
-
return
|
|
391
|
+
return extractLocalAgentProposal(stdout, config.provider);
|
|
359
392
|
}
|
|
360
393
|
async function proposeChanges(cwd, input, config, signal, onProgress) {
|
|
361
394
|
const context = await contextFor(cwd, input.element);
|
package/dist/cli/bridge.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type BridgeMessage = {
|
|
|
14
14
|
from: "overlay" | "cli";
|
|
15
15
|
} | {
|
|
16
16
|
type: "edit";
|
|
17
|
+
taskId: string;
|
|
17
18
|
instruction: string;
|
|
18
19
|
model: string;
|
|
19
20
|
provider?: "anthropic" | "openai" | "google" | "ollama" | "cli";
|
|
@@ -48,6 +49,7 @@ export type BridgeMessage = {
|
|
|
48
49
|
};
|
|
49
50
|
} | {
|
|
50
51
|
type: "ask";
|
|
52
|
+
taskId: string;
|
|
51
53
|
question: string;
|
|
52
54
|
model: string;
|
|
53
55
|
provider?: "anthropic" | "openai" | "google" | "ollama" | "cli";
|
|
@@ -81,11 +83,14 @@ export type BridgeMessage = {
|
|
|
81
83
|
details: string;
|
|
82
84
|
} | {
|
|
83
85
|
type: "apply";
|
|
86
|
+
taskId: string;
|
|
84
87
|
changes: SourceChange[];
|
|
85
88
|
} | {
|
|
86
89
|
type: "undo";
|
|
90
|
+
taskId?: string;
|
|
87
91
|
} | {
|
|
88
92
|
type: "stop";
|
|
93
|
+
taskId?: string;
|
|
89
94
|
} | {
|
|
90
95
|
type: "git_status";
|
|
91
96
|
} | {
|
|
@@ -101,6 +106,7 @@ export type BridgeMessage = {
|
|
|
101
106
|
type: "git_push";
|
|
102
107
|
} | {
|
|
103
108
|
type: "agent_status";
|
|
109
|
+
taskId?: string;
|
|
104
110
|
status: "thinking" | "working" | "review" | "error" | "stopped";
|
|
105
111
|
message: string;
|
|
106
112
|
} | {
|
|
@@ -134,18 +140,22 @@ export type ServerBridgeMessage = {
|
|
|
134
140
|
error?: string;
|
|
135
141
|
} | {
|
|
136
142
|
type: "agent_status";
|
|
143
|
+
taskId?: string;
|
|
137
144
|
status: "thinking" | "working" | "review" | "error" | "stopped";
|
|
138
145
|
message: string;
|
|
139
146
|
detail?: string;
|
|
140
147
|
changes?: SourceChange[];
|
|
141
148
|
} | {
|
|
142
149
|
type: "assistant_message";
|
|
150
|
+
taskId?: string;
|
|
143
151
|
message: string;
|
|
144
152
|
} | {
|
|
145
153
|
type: "applied";
|
|
154
|
+
taskId?: string;
|
|
146
155
|
message: string;
|
|
147
156
|
} | {
|
|
148
157
|
type: "undone";
|
|
158
|
+
taskId?: string;
|
|
149
159
|
message: string;
|
|
150
160
|
} | {
|
|
151
161
|
type: "transcribe_result";
|
package/dist/cli/bridge.js
CHANGED
|
@@ -147,10 +147,10 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
147
147
|
const bridgeServer = node_http_1.default.createServer(); // dedicated, empty HTTP server
|
|
148
148
|
const wss = new ws_1.WebSocketServer({ server: bridgeServer });
|
|
149
149
|
let overlaySocket = null;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
const taskSnapshots = new Map();
|
|
151
|
+
const editRequests = new Map();
|
|
152
|
+
const editConfigs = new Map();
|
|
153
|
+
const reviewRefreshAttempts = new Map();
|
|
154
154
|
const envRoots = [cwd, node_path_1.default.join(cwd, "web"), node_path_1.default.join(cwd, "server")];
|
|
155
155
|
const fileEnv = envRoots.reduce((values, root) => ({
|
|
156
156
|
...values,
|
|
@@ -179,11 +179,15 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
179
179
|
};
|
|
180
180
|
})();
|
|
181
181
|
let activeAgentController = null;
|
|
182
|
+
const taskControllers = new Map();
|
|
182
183
|
let localAgents = new Set();
|
|
183
184
|
bridgeServer.on("request", (req, res) => {
|
|
184
185
|
if (req.method !== "POST" || req.url?.split("?", 1)[0] !== "/__lasso/bridge/restart")
|
|
185
186
|
return;
|
|
186
187
|
activeAgentController?.abort();
|
|
188
|
+
for (const controller of taskControllers.values())
|
|
189
|
+
controller.abort();
|
|
190
|
+
taskControllers.clear();
|
|
187
191
|
activeAgentController = null;
|
|
188
192
|
for (const socket of wss.clients)
|
|
189
193
|
socket.close(1000, "Bridge restarted by the CLI");
|
|
@@ -270,40 +274,41 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
270
274
|
socket.send(JSON.stringify({ type: "git_state", git }));
|
|
271
275
|
});
|
|
272
276
|
const runEditReview = (request, config, statusMessage) => {
|
|
273
|
-
|
|
277
|
+
taskControllers.get(request.taskId)?.abort();
|
|
274
278
|
const controller = new AbortController();
|
|
275
|
-
|
|
279
|
+
taskControllers.set(request.taskId, controller);
|
|
276
280
|
if (statusMessage && socket.readyState === socket.OPEN) {
|
|
277
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "working", message: statusMessage }));
|
|
281
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: request.taskId, status: "working", message: statusMessage }));
|
|
278
282
|
}
|
|
279
283
|
void (0, agent_1.proposeChanges)(cwd, request, config, controller.signal, (message, detail) => {
|
|
280
284
|
if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
|
|
281
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "working", message, detail }));
|
|
285
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: request.taskId, status: "working", message, detail }));
|
|
282
286
|
}
|
|
283
287
|
})
|
|
284
288
|
.then((proposal) => {
|
|
285
289
|
if (controller.signal.aborted || socket.readyState !== socket.OPEN)
|
|
286
290
|
return;
|
|
287
291
|
if (!proposalMatchesCurrentSource(cwd, proposal.changes)) {
|
|
288
|
-
|
|
289
|
-
|
|
292
|
+
const refreshAttempts = reviewRefreshAttempts.get(request.taskId) || 0;
|
|
293
|
+
if (refreshAttempts < 1) {
|
|
294
|
+
reviewRefreshAttempts.set(request.taskId, refreshAttempts + 1);
|
|
290
295
|
runEditReview(request, config, "The source changed while the proposal was being prepared. Refreshing the review…");
|
|
291
296
|
}
|
|
292
297
|
else {
|
|
293
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: "The source is still changing. Stop the dev-server edit or try the request again." }));
|
|
298
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: request.taskId, status: "error", message: "The source is still changing. Stop the dev-server edit or try the request again." }));
|
|
294
299
|
}
|
|
295
300
|
return;
|
|
296
301
|
}
|
|
297
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "review", message: proposal.summary, changes: proposal.changes }));
|
|
302
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: request.taskId, status: "review", message: proposal.summary, changes: proposal.changes }));
|
|
298
303
|
})
|
|
299
304
|
.catch((error) => {
|
|
300
305
|
if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
|
|
301
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: error instanceof Error ? error.message : "The agent could not prepare a change." }));
|
|
306
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: request.taskId, status: "error", message: error instanceof Error ? error.message : "The agent could not prepare a change." }));
|
|
302
307
|
}
|
|
303
308
|
})
|
|
304
309
|
.finally(() => {
|
|
305
|
-
if (
|
|
306
|
-
|
|
310
|
+
if (taskControllers.get(request.taskId) === controller)
|
|
311
|
+
taskControllers.delete(request.taskId);
|
|
307
312
|
});
|
|
308
313
|
};
|
|
309
314
|
socket.on("message", async (raw) => {
|
|
@@ -318,56 +323,59 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
318
323
|
const localProvider = msg.provider === "cli";
|
|
319
324
|
const cliProvider = msg.model.startsWith("claude-code:") ? "claude-code" : msg.model.startsWith("opencode:") ? "opencode" : "codex";
|
|
320
325
|
if (!lassoKeyConfigured && !localProvider) {
|
|
321
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: "Set your Lasso API key before asking the hosted agent a question." }));
|
|
326
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "error", message: "Set your Lasso API key before asking the hosted agent a question." }));
|
|
322
327
|
return;
|
|
323
328
|
}
|
|
324
329
|
if (!agentConfig && !localProvider) {
|
|
325
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: "No hosted agent is configured. Select Claude Code/Codex or add a provider key." }));
|
|
330
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "error", message: "No hosted agent is configured. Select Claude Code/Codex or add a provider key." }));
|
|
326
331
|
return;
|
|
327
332
|
}
|
|
328
|
-
|
|
333
|
+
taskControllers.get(msg.taskId)?.abort();
|
|
329
334
|
const controller = new AbortController();
|
|
330
|
-
|
|
335
|
+
taskControllers.set(msg.taskId, controller);
|
|
331
336
|
const selectedConfig = localProvider
|
|
332
337
|
? { provider: cliProvider, model: msg.model }
|
|
333
338
|
: { ...agentConfig, provider: (msg.provider || agentConfig.provider), model: msg.model };
|
|
334
339
|
void (0, agent_1.answerQuestion)(cwd, { question: msg.question, context: msg.context, element: msg.element, messages: msg.messages }, selectedConfig, controller.signal, (message, detail) => {
|
|
335
340
|
if (!controller.signal.aborted && socket.readyState === socket.OPEN)
|
|
336
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "working", message, detail }));
|
|
341
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "working", message, detail }));
|
|
337
342
|
}).then((answer) => {
|
|
338
343
|
if (!controller.signal.aborted)
|
|
339
|
-
socket.send(JSON.stringify({ type: "assistant_message", message: answer }));
|
|
344
|
+
socket.send(JSON.stringify({ type: "assistant_message", taskId: msg.taskId, message: answer }));
|
|
340
345
|
}).catch((error) => {
|
|
341
346
|
if (!controller.signal.aborted)
|
|
342
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: error instanceof Error ? error.message : "The agent could not answer." }));
|
|
347
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "error", message: error instanceof Error ? error.message : "The agent could not answer." }));
|
|
343
348
|
}).finally(() => {
|
|
344
|
-
if (
|
|
345
|
-
|
|
349
|
+
if (taskControllers.get(msg.taskId) === controller)
|
|
350
|
+
taskControllers.delete(msg.taskId);
|
|
346
351
|
});
|
|
347
352
|
}
|
|
348
353
|
else if (msg.type === "edit") {
|
|
349
354
|
const localProvider = msg.provider === "cli";
|
|
350
355
|
const cliProvider = msg.model.startsWith("claude-code:") ? "claude-code" : msg.model.startsWith("opencode:") ? "opencode" : "codex";
|
|
351
356
|
if (!lassoKeyConfigured && !localProvider) {
|
|
352
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: "Set VITE_LASSO_API_KEY or NEXT_LASSO_API_KEY in your app environment before sending an edit." }));
|
|
357
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "error", message: "Set VITE_LASSO_API_KEY or NEXT_LASSO_API_KEY in your app environment before sending an edit." }));
|
|
353
358
|
return;
|
|
354
359
|
}
|
|
355
360
|
if (!agentConfig && !localProvider) {
|
|
356
|
-
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: "Add a supported agent key: GOOGLE_GENERATIVE_AI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY." }));
|
|
361
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "error", message: "Add a supported agent key: GOOGLE_GENERATIVE_AI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY." }));
|
|
357
362
|
return;
|
|
358
363
|
}
|
|
359
364
|
const selectedConfig = localProvider
|
|
360
365
|
? { provider: cliProvider, model: msg.model }
|
|
361
366
|
: { ...agentConfig, provider: (msg.provider || agentConfig.provider), model: msg.model };
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
reviewRefreshAttempts
|
|
367
|
+
editRequests.set(msg.taskId, msg);
|
|
368
|
+
editConfigs.set(msg.taskId, selectedConfig);
|
|
369
|
+
reviewRefreshAttempts.set(msg.taskId, 0);
|
|
365
370
|
runEditReview(msg, selectedConfig);
|
|
366
371
|
}
|
|
367
372
|
else if (msg.type === "stop") {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
if (msg.taskId)
|
|
374
|
+
taskControllers.get(msg.taskId)?.abort();
|
|
375
|
+
else
|
|
376
|
+
for (const controller of taskControllers.values())
|
|
377
|
+
controller.abort();
|
|
378
|
+
socket.send(JSON.stringify({ type: "agent_status", taskId: msg.taskId, status: "stopped", message: "Agent stopped." }));
|
|
371
379
|
}
|
|
372
380
|
else if (msg.type === "runtime_error") {
|
|
373
381
|
socket.send(JSON.stringify({ type: "agent_status", status: "error", message: `Runtime error detected${msg.selectionId ? ` for selection ${msg.selectionId}` : ""}: ${msg.details}` }));
|
|
@@ -468,7 +476,7 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
468
476
|
}
|
|
469
477
|
else if (msg.type === "apply") {
|
|
470
478
|
try {
|
|
471
|
-
|
|
479
|
+
const snapshots = [];
|
|
472
480
|
const planned = new Map();
|
|
473
481
|
for (const change of msg.changes) {
|
|
474
482
|
const filePath = resolveProposedFile(cwd, change.filePath);
|
|
@@ -483,24 +491,31 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
483
491
|
}
|
|
484
492
|
// Validate every change before writing any file, then apply each
|
|
485
493
|
// file's replacements from the end toward the beginning.
|
|
494
|
+
taskSnapshots.set(msg.taskId, snapshots);
|
|
486
495
|
for (const [filePath, changes] of planned) {
|
|
487
496
|
const content = changes[0].content;
|
|
488
|
-
|
|
497
|
+
snapshots.push({ filePath, content });
|
|
489
498
|
const nextContent = [...changes]
|
|
490
499
|
.sort((a, b) => b.start - a.start)
|
|
491
500
|
.reduce((value, change) => value.slice(0, change.start) + change.newString + value.slice(change.end), content);
|
|
492
501
|
node_fs_1.default.writeFileSync(filePath, nextContent);
|
|
493
502
|
}
|
|
494
|
-
socket.send(JSON.stringify({ type: "applied", message: `${msg.changes.length} file${msg.changes.length === 1 ? "" : "s"} updated. Your dev server will reload.` }));
|
|
503
|
+
socket.send(JSON.stringify({ type: "applied", taskId: msg.taskId, message: `${msg.changes.length} file${msg.changes.length === 1 ? "" : "s"} updated. Your dev server will reload.` }));
|
|
495
504
|
}
|
|
496
505
|
catch (error) {
|
|
497
|
-
|
|
506
|
+
// Validation happens before writes, but restore this task's snapshot
|
|
507
|
+
// if a filesystem error occurs during the write phase.
|
|
508
|
+
for (const snapshot of taskSnapshots.get(msg.taskId) || [])
|
|
498
509
|
node_fs_1.default.writeFileSync(snapshot.filePath, snapshot.content);
|
|
499
|
-
|
|
510
|
+
taskSnapshots.delete(msg.taskId);
|
|
500
511
|
const message = error instanceof Error ? error.message : "The change could not be applied.";
|
|
501
512
|
const sourceChanged = message.includes("The source changed after the suggestion was generated");
|
|
502
|
-
|
|
503
|
-
|
|
513
|
+
const editRequest = editRequests.get(msg.taskId);
|
|
514
|
+
const editConfig = editConfigs.get(msg.taskId);
|
|
515
|
+
const refreshAttempts = reviewRefreshAttempts.get(msg.taskId) || 0;
|
|
516
|
+
if (sourceChanged && editRequest && editConfig && refreshAttempts < 1) {
|
|
517
|
+
reviewRefreshAttempts.set(msg.taskId, refreshAttempts + 1);
|
|
518
|
+
runEditReview(editRequest, editConfig, "The source changed. Refreshing the review against the current file…");
|
|
504
519
|
}
|
|
505
520
|
else {
|
|
506
521
|
socket.send(JSON.stringify({ type: "agent_status", status: "error", message }));
|
|
@@ -508,11 +523,11 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
|
|
|
508
523
|
}
|
|
509
524
|
}
|
|
510
525
|
else if (msg.type === "undo") {
|
|
511
|
-
|
|
526
|
+
const snapshots = taskSnapshots.get(msg.taskId || "") || [];
|
|
527
|
+
for (const snapshot of snapshots)
|
|
512
528
|
node_fs_1.default.writeFileSync(snapshot.filePath, snapshot.content);
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
socket.send(JSON.stringify({ type: "undone", message: count ? "The accepted change was reverted." : "There is no accepted change to undo." }));
|
|
529
|
+
taskSnapshots.delete(msg.taskId || "");
|
|
530
|
+
socket.send(JSON.stringify({ type: "undone", taskId: msg.taskId, message: snapshots.length ? "The accepted change was reverted." : "There is no accepted change to undo." }));
|
|
516
531
|
}
|
|
517
532
|
});
|
|
518
533
|
socket.on("close", () => {
|
package/dist/overlay.js
CHANGED
|
@@ -7878,6 +7878,8 @@
|
|
|
7878
7878
|
chatHistory = [];
|
|
7879
7879
|
changesHistory = [];
|
|
7880
7880
|
pendingChanges = [];
|
|
7881
|
+
agentTasks = [];
|
|
7882
|
+
activeTaskId = null;
|
|
7881
7883
|
runtimeErrors = [];
|
|
7882
7884
|
screenshotPromise = Promise.resolve({});
|
|
7883
7885
|
// Agent State
|
|
@@ -10180,8 +10182,13 @@
|
|
|
10180
10182
|
display: none;
|
|
10181
10183
|
}
|
|
10182
10184
|
|
|
10185
|
+
.lasso-prompt-send.loading span {
|
|
10186
|
+
display: none;
|
|
10187
|
+
}
|
|
10188
|
+
|
|
10183
10189
|
.lasso-prompt-send.loading::before {
|
|
10184
10190
|
content: "";
|
|
10191
|
+
display: block;
|
|
10185
10192
|
width: 12px;
|
|
10186
10193
|
height: 12px;
|
|
10187
10194
|
border: 2px solid rgba(0, 0, 0, 0.3);
|
|
@@ -10877,6 +10884,60 @@
|
|
|
10877
10884
|
display: none;
|
|
10878
10885
|
}
|
|
10879
10886
|
|
|
10887
|
+
.lasso-task-panel {
|
|
10888
|
+
position: fixed;
|
|
10889
|
+
right: 12px;
|
|
10890
|
+
bottom: 82px;
|
|
10891
|
+
width: 390px;
|
|
10892
|
+
max-width: calc(100vw - 24px);
|
|
10893
|
+
max-height: min(560px, calc(100vh - 104px));
|
|
10894
|
+
padding: 14px;
|
|
10895
|
+
display: flex;
|
|
10896
|
+
flex-direction: column;
|
|
10897
|
+
gap: 10px;
|
|
10898
|
+
color: var(--lo-text);
|
|
10899
|
+
background: var(--lo-surface);
|
|
10900
|
+
border: 1px solid var(--lo-border);
|
|
10901
|
+
border-radius: var(--lo-radius-xl);
|
|
10902
|
+
box-shadow: 0 18px 50px rgba(0,0,0,.35);
|
|
10903
|
+
z-index: 30;
|
|
10904
|
+
opacity: 0;
|
|
10905
|
+
transform: translateY(8px) scale(.98);
|
|
10906
|
+
transition: opacity 150ms ease, transform 150ms ease;
|
|
10907
|
+
pointer-events: auto;
|
|
10908
|
+
}
|
|
10909
|
+
|
|
10910
|
+
.lasso-task-panel.visible { opacity: 1; transform: translateY(0) scale(1); }
|
|
10911
|
+
.lasso-task-panel[hidden] { display: none; }
|
|
10912
|
+
.lasso-task-header, .lasso-task-title-row, .lasso-task-detail-heading { display: flex; align-items: center; }
|
|
10913
|
+
.lasso-task-header { justify-content: space-between; }
|
|
10914
|
+
.lasso-task-title-row { gap: 7px; font-size: 13px; font-weight: 600; }
|
|
10915
|
+
.lasso-task-badge { min-width: 18px; padding: 2px 5px; border-radius: 999px; background: var(--lo-indigo); color: #fff; font-size: 10px; text-align: center; }
|
|
10916
|
+
.lasso-task-close, .lasso-task-back { border: 0; background: transparent; color: var(--lo-text-3); cursor: pointer; }
|
|
10917
|
+
.lasso-task-close { font-size: 20px; line-height: 20px; }
|
|
10918
|
+
.lasso-task-body { min-height: 90px; max-height: 470px; overflow: auto; }
|
|
10919
|
+
.lasso-task-list { display: flex; flex-direction: column; gap: 3px; }
|
|
10920
|
+
.lasso-task-row { width: 100%; display: flex; align-items: center; gap: 9px; padding: 9px; border: 0; border-radius: var(--lo-radius-md); background: transparent; color: var(--lo-text); text-align: left; cursor: pointer; }
|
|
10921
|
+
.lasso-task-row:hover, .lasso-task-row.active { background: var(--lo-surface-hover); }
|
|
10922
|
+
.lasso-task-status { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%; background: var(--lo-text-3); }
|
|
10923
|
+
.lasso-task-status.thinking, .lasso-task-status.working { background: var(--lo-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--lo-primary) 18%, transparent); }
|
|
10924
|
+
.lasso-task-status.review { background: #fbbf24; }
|
|
10925
|
+
.lasso-task-status.complete { background: #34d399; }
|
|
10926
|
+
.lasso-task-status.error { background: #f87171; }
|
|
10927
|
+
.lasso-task-row-copy { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
|
|
10928
|
+
.lasso-task-row-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 500; }
|
|
10929
|
+
.lasso-task-row-copy small, .lasso-task-message { color: var(--lo-text-3); font-size: 11px; }
|
|
10930
|
+
.lasso-task-empty { padding: 25px 10px; color: var(--lo-text-3); font-size: 12px; text-align: center; }
|
|
10931
|
+
.lasso-task-detail { padding: 4px 2px; }
|
|
10932
|
+
.lasso-task-detail-heading { justify-content: space-between; margin-bottom: 12px; }
|
|
10933
|
+
.lasso-task-detail-status { color: var(--lo-primary); font-size: 11px; font-weight: 600; }
|
|
10934
|
+
.lasso-task-prompt { margin: 0 0 10px; font-size: 13px; line-height: 1.45; }
|
|
10935
|
+
.lasso-task-message { margin: 0 0 12px; line-height: 1.45; }
|
|
10936
|
+
.lasso-task-changes { margin-bottom: 10px; color: var(--lo-text-2); font-size: 11px; }
|
|
10937
|
+
.lasso-task-apply { padding: 7px 11px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-primary); color: #111214; font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; }
|
|
10938
|
+
|
|
10939
|
+
.lasso-agent-tasks-badge { position: absolute; top: 5px; right: 5px; width: 6px; height: 6px; border-radius: 50%; background: var(--lo-primary); }
|
|
10940
|
+
|
|
10880
10941
|
.lasso-todo-header {
|
|
10881
10942
|
display: flex;
|
|
10882
10943
|
align-items: center;
|
|
@@ -12059,6 +12120,138 @@
|
|
|
12059
12120
|
};
|
|
12060
12121
|
var terminal_default = data4;
|
|
12061
12122
|
|
|
12123
|
+
// src/overlay/tasks/tasks.ts
|
|
12124
|
+
var panel = null;
|
|
12125
|
+
var list = null;
|
|
12126
|
+
var detail = null;
|
|
12127
|
+
var badge = null;
|
|
12128
|
+
var statusLabel = {
|
|
12129
|
+
queued: "Queued",
|
|
12130
|
+
thinking: "Thinking",
|
|
12131
|
+
working: "Working",
|
|
12132
|
+
review: "Review",
|
|
12133
|
+
complete: "Complete",
|
|
12134
|
+
error: "Error",
|
|
12135
|
+
stopped: "Stopped"
|
|
12136
|
+
};
|
|
12137
|
+
function taskId() {
|
|
12138
|
+
return `task-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
12139
|
+
}
|
|
12140
|
+
function createAgentTask(instruction) {
|
|
12141
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12142
|
+
const task = { id: taskId(), instruction, status: "queued", message: "Queued", createdAt: now, updatedAt: now };
|
|
12143
|
+
state.agentTasks.unshift(task);
|
|
12144
|
+
state.activeTaskId = task.id;
|
|
12145
|
+
renderTasks();
|
|
12146
|
+
return task;
|
|
12147
|
+
}
|
|
12148
|
+
function getAgentTask(id) {
|
|
12149
|
+
return id ? state.agentTasks.find((task) => task.id === id) : void 0;
|
|
12150
|
+
}
|
|
12151
|
+
function updateAgentTask(id, patch) {
|
|
12152
|
+
if (!id) return;
|
|
12153
|
+
const task = getAgentTask(id);
|
|
12154
|
+
if (!task) return;
|
|
12155
|
+
Object.assign(task, patch, { updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
12156
|
+
renderTasks();
|
|
12157
|
+
}
|
|
12158
|
+
function selectAgentTask(id) {
|
|
12159
|
+
if (!getAgentTask(id)) return;
|
|
12160
|
+
state.activeTaskId = id;
|
|
12161
|
+
renderTasks();
|
|
12162
|
+
}
|
|
12163
|
+
function toggleTaskPanel(force) {
|
|
12164
|
+
if (!panel) return;
|
|
12165
|
+
panel.hidden = force === void 0 ? !panel.hidden : !force;
|
|
12166
|
+
panel.classList.toggle("visible", !panel.hidden);
|
|
12167
|
+
if (!panel.hidden) renderTasks();
|
|
12168
|
+
}
|
|
12169
|
+
function buildTaskPanel() {
|
|
12170
|
+
const dom = getDOM();
|
|
12171
|
+
panel = document.createElement("div");
|
|
12172
|
+
panel.className = "lasso-task-panel";
|
|
12173
|
+
panel.hidden = true;
|
|
12174
|
+
panel.innerHTML = `
|
|
12175
|
+
<div class="lasso-task-header">
|
|
12176
|
+
<div class="lasso-task-title-row">
|
|
12177
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="3"/><path d="M7 8h10M7 12h6M7 16h8"/></svg>
|
|
12178
|
+
<span>Agent tasks</span><span class="lasso-task-badge" hidden>0</span>
|
|
12179
|
+
</div>
|
|
12180
|
+
<button class="lasso-task-close" type="button" aria-label="Close tasks">\xD7</button>
|
|
12181
|
+
</div>
|
|
12182
|
+
<div class="lasso-task-body">
|
|
12183
|
+
<div class="lasso-task-list"></div>
|
|
12184
|
+
<div class="lasso-task-detail" hidden></div>
|
|
12185
|
+
</div>
|
|
12186
|
+
`;
|
|
12187
|
+
dom.shadow.appendChild(panel);
|
|
12188
|
+
list = panel.querySelector(".lasso-task-list");
|
|
12189
|
+
detail = panel.querySelector(".lasso-task-detail");
|
|
12190
|
+
badge = panel.querySelector(".lasso-task-badge");
|
|
12191
|
+
panel.querySelector(".lasso-task-close").addEventListener("click", () => toggleTaskPanel(false));
|
|
12192
|
+
renderTasks();
|
|
12193
|
+
return panel;
|
|
12194
|
+
}
|
|
12195
|
+
function renderTasks() {
|
|
12196
|
+
if (!list || !detail || !badge) return;
|
|
12197
|
+
const running = state.agentTasks.filter((task) => task.status === "thinking" || task.status === "working").length;
|
|
12198
|
+
badge.hidden = state.agentTasks.length === 0;
|
|
12199
|
+
badge.textContent = String(running || state.agentTasks.length);
|
|
12200
|
+
list.replaceChildren();
|
|
12201
|
+
if (!state.agentTasks.length) {
|
|
12202
|
+
list.innerHTML = `<div class="lasso-task-empty">Prompt an element to start a task.</div>`;
|
|
12203
|
+
} else {
|
|
12204
|
+
for (const task of state.agentTasks) {
|
|
12205
|
+
const button = document.createElement("button");
|
|
12206
|
+
button.type = "button";
|
|
12207
|
+
button.className = `lasso-task-row${task.id === state.activeTaskId ? " active" : ""}`;
|
|
12208
|
+
button.innerHTML = `<span class="lasso-task-status ${task.status}"></span><span class="lasso-task-row-copy"><strong></strong><small>${statusLabel[task.status]}</small></span>`;
|
|
12209
|
+
button.querySelector("strong").textContent = task.instruction;
|
|
12210
|
+
button.addEventListener("click", () => selectAgentTask(task.id));
|
|
12211
|
+
list.appendChild(button);
|
|
12212
|
+
}
|
|
12213
|
+
}
|
|
12214
|
+
const selected = getAgentTask(state.activeTaskId);
|
|
12215
|
+
if (!selected) {
|
|
12216
|
+
detail.hidden = true;
|
|
12217
|
+
return;
|
|
12218
|
+
}
|
|
12219
|
+
detail.hidden = false;
|
|
12220
|
+
detail.replaceChildren();
|
|
12221
|
+
const heading = document.createElement("div");
|
|
12222
|
+
heading.className = "lasso-task-detail-heading";
|
|
12223
|
+
heading.innerHTML = `<span class="lasso-task-detail-status ${selected.status}">${statusLabel[selected.status]}</span><button type="button" class="lasso-task-back">All tasks</button>`;
|
|
12224
|
+
heading.querySelector("button").addEventListener("click", () => {
|
|
12225
|
+
state.activeTaskId = null;
|
|
12226
|
+
renderTasks();
|
|
12227
|
+
});
|
|
12228
|
+
const prompt = document.createElement("p");
|
|
12229
|
+
prompt.className = "lasso-task-prompt";
|
|
12230
|
+
prompt.textContent = selected.instruction;
|
|
12231
|
+
const activity = document.createElement("p");
|
|
12232
|
+
activity.className = "lasso-task-message";
|
|
12233
|
+
activity.textContent = selected.response || selected.message;
|
|
12234
|
+
detail.append(heading, prompt, activity);
|
|
12235
|
+
if (selected.changes?.length) {
|
|
12236
|
+
const changes = document.createElement("div");
|
|
12237
|
+
changes.className = "lasso-task-changes";
|
|
12238
|
+
changes.textContent = `${selected.changes.length} proposed file change${selected.changes.length === 1 ? "" : "s"}`;
|
|
12239
|
+
detail.appendChild(changes);
|
|
12240
|
+
if (selected.status === "review") {
|
|
12241
|
+
const apply = document.createElement("button");
|
|
12242
|
+
apply.type = "button";
|
|
12243
|
+
apply.className = "lasso-task-apply";
|
|
12244
|
+
apply.textContent = "Apply changes";
|
|
12245
|
+
apply.addEventListener("click", () => {
|
|
12246
|
+
if (state.bridgeSocket?.readyState !== WebSocket.OPEN) return;
|
|
12247
|
+
state.bridgeSocket.send(JSON.stringify({ type: "apply", taskId: selected.id, changes: selected.changes }));
|
|
12248
|
+
updateAgentTask(selected.id, { message: "Applying changes\u2026" });
|
|
12249
|
+
});
|
|
12250
|
+
detail.appendChild(apply);
|
|
12251
|
+
}
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
|
|
12062
12255
|
// src/overlay/notifications.ts
|
|
12063
12256
|
var permissionRequest = null;
|
|
12064
12257
|
function requestAgentNotificationPermission() {
|
|
@@ -16836,11 +17029,11 @@
|
|
|
16836
17029
|
}
|
|
16837
17030
|
function updateCommentsBadge() {
|
|
16838
17031
|
const dom = getDOM();
|
|
16839
|
-
const
|
|
16840
|
-
if (!
|
|
17032
|
+
const badge2 = dom.shadow.querySelector(".lasso-comments-badge");
|
|
17033
|
+
if (!badge2) return;
|
|
16841
17034
|
const openCount = threadsInScope().filter((t) => t.root.status === "OPEN").length;
|
|
16842
|
-
|
|
16843
|
-
|
|
17035
|
+
badge2.classList.toggle("visible", openCount > 0);
|
|
17036
|
+
badge2.textContent = String(openCount);
|
|
16844
17037
|
}
|
|
16845
17038
|
function commentPosition(thread) {
|
|
16846
17039
|
const saved = thread.root.meta?.position;
|
|
@@ -17591,7 +17784,7 @@
|
|
|
17591
17784
|
ta.remove();
|
|
17592
17785
|
}
|
|
17593
17786
|
}
|
|
17594
|
-
var
|
|
17787
|
+
var panel2 = null;
|
|
17595
17788
|
var items = [];
|
|
17596
17789
|
var scope = "private";
|
|
17597
17790
|
var PRIVATE_STORAGE_KEY = "lasso:clipboard:private";
|
|
@@ -17650,7 +17843,7 @@
|
|
|
17650
17843
|
<div class="lasso-clipboard-list"></div>
|
|
17651
17844
|
`;
|
|
17652
17845
|
getDOM().shadow.appendChild(el);
|
|
17653
|
-
|
|
17846
|
+
panel2 = el;
|
|
17654
17847
|
el.querySelector(".lasso-clipboard-close").addEventListener("click", () => toggleClipboardPanel(false));
|
|
17655
17848
|
el.querySelectorAll(".lasso-clipboard-tab").forEach((button) => {
|
|
17656
17849
|
button.addEventListener("click", () => {
|
|
@@ -17757,14 +17950,14 @@
|
|
|
17757
17950
|
return TYPE_COLORS[type] ?? TYPE_COLORS.text;
|
|
17758
17951
|
}
|
|
17759
17952
|
function render() {
|
|
17760
|
-
const
|
|
17761
|
-
if (!
|
|
17953
|
+
const list2 = panel2?.querySelector(".lasso-clipboard-list");
|
|
17954
|
+
if (!list2) return;
|
|
17762
17955
|
const visible = items.filter((item) => item.scope === scope);
|
|
17763
17956
|
if (!visible.length) {
|
|
17764
|
-
|
|
17957
|
+
list2.innerHTML = `<div class="lasso-clipboard-empty">${scope === "shared" && !state.collabJoined ? "Join a collaboration session to share items." : "No saved items yet."}</div>`;
|
|
17765
17958
|
return;
|
|
17766
17959
|
}
|
|
17767
|
-
|
|
17960
|
+
list2.innerHTML = visible.map((item) => {
|
|
17768
17961
|
const color = typeColor(item.type);
|
|
17769
17962
|
const icon = typeIcon(item.type);
|
|
17770
17963
|
const preview = escapeHtml3(item.content).slice(0, 220);
|
|
@@ -17788,7 +17981,7 @@
|
|
|
17788
17981
|
</div>
|
|
17789
17982
|
</div>`;
|
|
17790
17983
|
}).join("");
|
|
17791
|
-
|
|
17984
|
+
list2.querySelectorAll(".lasso-clipboard-item").forEach((row) => {
|
|
17792
17985
|
const item = visible.find((candidate) => candidate.uid === row.dataset.id);
|
|
17793
17986
|
if (!item) return;
|
|
17794
17987
|
const copyBtn = row.querySelector(".lasso-clipboard-copy-item");
|
|
@@ -17823,7 +18016,7 @@
|
|
|
17823
18016
|
});
|
|
17824
18017
|
}
|
|
17825
18018
|
function setStatus(message) {
|
|
17826
|
-
const sub =
|
|
18019
|
+
const sub = panel2?.querySelector(".lasso-clipboard-subtitle");
|
|
17827
18020
|
if (!sub) return;
|
|
17828
18021
|
const previous = sub.textContent;
|
|
17829
18022
|
sub.textContent = message;
|
|
@@ -17832,10 +18025,10 @@
|
|
|
17832
18025
|
}, 1800);
|
|
17833
18026
|
}
|
|
17834
18027
|
function toggleClipboardPanel(force) {
|
|
17835
|
-
if (!
|
|
17836
|
-
const next = force === void 0 ? Boolean(
|
|
17837
|
-
|
|
17838
|
-
|
|
18028
|
+
if (!panel2) return;
|
|
18029
|
+
const next = force === void 0 ? Boolean(panel2.hidden) : force;
|
|
18030
|
+
panel2.hidden = !next;
|
|
18031
|
+
panel2.classList.toggle("visible", next);
|
|
17839
18032
|
if (next) requestItems();
|
|
17840
18033
|
}
|
|
17841
18034
|
function escapeHtml3(value2) {
|
|
@@ -18391,7 +18584,7 @@
|
|
|
18391
18584
|
event.preventDefault();
|
|
18392
18585
|
event.stopPropagation();
|
|
18393
18586
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
18394
|
-
state.bridgeSocket.send(JSON.stringify({ type: "stop" }));
|
|
18587
|
+
state.bridgeSocket.send(JSON.stringify({ type: "stop", taskId: state.activeTaskId || void 0 }));
|
|
18395
18588
|
}
|
|
18396
18589
|
appendChat("assistant", "Agent stopped.");
|
|
18397
18590
|
resetAgentState();
|
|
@@ -18452,7 +18645,7 @@
|
|
|
18452
18645
|
rev.querySelector(".lasso-review-undo").addEventListener("click", () => {
|
|
18453
18646
|
if (state.pendingChanges.length && rev.querySelector(".lasso-review-apply").hidden) {
|
|
18454
18647
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
18455
|
-
state.bridgeSocket.send(JSON.stringify({ type: "undo" }));
|
|
18648
|
+
state.bridgeSocket.send(JSON.stringify({ type: "undo", taskId: state.activeTaskId || void 0 }));
|
|
18456
18649
|
}
|
|
18457
18650
|
return;
|
|
18458
18651
|
}
|
|
@@ -18462,7 +18655,7 @@
|
|
|
18462
18655
|
rev.querySelector(".lasso-review-apply").addEventListener("click", () => {
|
|
18463
18656
|
if (!state.bridgeSocket || state.bridgeSocket.readyState !== WebSocket.OPEN || !state.pendingChanges.length) return;
|
|
18464
18657
|
requestAgentNotificationPermission();
|
|
18465
|
-
state.bridgeSocket.send(JSON.stringify({ type: "apply", changes: state.pendingChanges }));
|
|
18658
|
+
state.bridgeSocket.send(JSON.stringify({ type: "apply", taskId: state.activeTaskId || "", changes: state.pendingChanges }));
|
|
18466
18659
|
appendChat("assistant", "Applying the reviewed change\u2026");
|
|
18467
18660
|
});
|
|
18468
18661
|
return { prompt: el, review: rev };
|
|
@@ -18672,9 +18865,9 @@
|
|
|
18672
18865
|
container.append(document.createTextNode(text.slice(lastIndex)));
|
|
18673
18866
|
}
|
|
18674
18867
|
}
|
|
18675
|
-
function setAgentStatus(status, message,
|
|
18868
|
+
function setAgentStatus(status, message, detail2) {
|
|
18676
18869
|
if (!agentStatusElement || !agentStatusMessage || !sendButton) return;
|
|
18677
|
-
const logMessage =
|
|
18870
|
+
const logMessage = detail2?.trim() || message.trim();
|
|
18678
18871
|
const lastLog = agentLogLines[agentLogLines.length - 1];
|
|
18679
18872
|
if (agentStatusElement.dataset.status === status && agentStatusMessage.textContent === message && (status === "thinking" || status === "working") && (!logMessage || lastLog === logMessage)) return;
|
|
18680
18873
|
appendAgentLog(logMessage);
|
|
@@ -18689,7 +18882,7 @@
|
|
|
18689
18882
|
state.agentRunning = status === "thinking" || status === "working";
|
|
18690
18883
|
sendButton.classList.toggle("loading", state.agentRunning);
|
|
18691
18884
|
if (stopButton) stopButton.hidden = !state.agentRunning;
|
|
18692
|
-
if (promptInput) promptInput.disabled =
|
|
18885
|
+
if (promptInput) promptInput.disabled = false;
|
|
18693
18886
|
const label = sendButton.querySelector("span");
|
|
18694
18887
|
if (label) {
|
|
18695
18888
|
label.textContent = status === "review" ? "Review" : status === "error" ? "Retry" : state.agentRunning ? "" : "Send";
|
|
@@ -18705,7 +18898,7 @@
|
|
|
18705
18898
|
if (!promptInput || !sendButton) return;
|
|
18706
18899
|
const hasInstruction = Boolean(promptInput.value.trim()) || sendButton.dataset.state === "retry" && Boolean(state.lastInstruction?.trim());
|
|
18707
18900
|
const isReviewAction = sendButton.dataset.state === "review";
|
|
18708
|
-
sendButton.disabled =
|
|
18901
|
+
sendButton.disabled = !hasInstruction && !isReviewAction;
|
|
18709
18902
|
}
|
|
18710
18903
|
function resetAgentState() {
|
|
18711
18904
|
state.agentRunning = false;
|
|
@@ -18842,6 +19035,7 @@
|
|
|
18842
19035
|
});
|
|
18843
19036
|
}
|
|
18844
19037
|
appendChat("user", instruction);
|
|
19038
|
+
const task = createAgentTask(instruction);
|
|
18845
19039
|
setAgentStatus("thinking", "Thinking\u2026");
|
|
18846
19040
|
state.lastInstruction = instruction;
|
|
18847
19041
|
promptInput.value = "";
|
|
@@ -18855,6 +19049,7 @@
|
|
|
18855
19049
|
state.bridgeSocket.send(
|
|
18856
19050
|
JSON.stringify({
|
|
18857
19051
|
type: wantsAnswer ? "ask" : "edit",
|
|
19052
|
+
taskId: task.id,
|
|
18858
19053
|
question: wantsAnswer ? instruction : void 0,
|
|
18859
19054
|
instruction,
|
|
18860
19055
|
messages: state.chatHistory,
|
|
@@ -19706,25 +19901,25 @@
|
|
|
19706
19901
|
const parts2 = filePath.split("/");
|
|
19707
19902
|
const name = parts2.pop() || filePath;
|
|
19708
19903
|
const dir = parts2.length ? parts2.join("/") + "/" : "";
|
|
19709
|
-
let
|
|
19904
|
+
let badge2 = "M";
|
|
19710
19905
|
let badgeClass = "mod";
|
|
19711
19906
|
if (code.includes("A")) {
|
|
19712
|
-
|
|
19907
|
+
badge2 = "A";
|
|
19713
19908
|
badgeClass = "add";
|
|
19714
19909
|
} else if (code.includes("D")) {
|
|
19715
|
-
|
|
19910
|
+
badge2 = "D";
|
|
19716
19911
|
badgeClass = "del";
|
|
19717
19912
|
} else if (code.includes("R")) {
|
|
19718
|
-
|
|
19913
|
+
badge2 = "R";
|
|
19719
19914
|
badgeClass = "ren";
|
|
19720
19915
|
} else if (code === "??" || code.includes("?")) {
|
|
19721
|
-
|
|
19916
|
+
badge2 = "U";
|
|
19722
19917
|
badgeClass = "unt";
|
|
19723
19918
|
} else if (code.includes("M")) {
|
|
19724
|
-
|
|
19919
|
+
badge2 = "M";
|
|
19725
19920
|
badgeClass = "mod";
|
|
19726
19921
|
}
|
|
19727
|
-
return { code, badge, badgeClass, path: filePath, dir, name };
|
|
19922
|
+
return { code, badge: badge2, badgeClass, path: filePath, dir, name };
|
|
19728
19923
|
});
|
|
19729
19924
|
}
|
|
19730
19925
|
function escapeHtml4(text) {
|
|
@@ -19935,7 +20130,7 @@
|
|
|
19935
20130
|
const uninitView = gitPanelEl.querySelector(".lasso-git-uninit-view");
|
|
19936
20131
|
const repoView = gitPanelEl.querySelector(".lasso-git-repo-view");
|
|
19937
20132
|
const filesList = gitPanelEl.querySelector(".lasso-git-files-list");
|
|
19938
|
-
const
|
|
20133
|
+
const badge2 = gitPanelEl.querySelector(".lasso-git-changes-badge");
|
|
19939
20134
|
const commitBtn = gitPanelEl.querySelector(".lasso-git-commit-btn");
|
|
19940
20135
|
const commitBtnText = gitPanelEl.querySelector(".lasso-git-commit-btn-text");
|
|
19941
20136
|
const pushBtn = gitPanelEl.querySelector(".lasso-git-push-btn");
|
|
@@ -19958,12 +20153,12 @@
|
|
|
19958
20153
|
uninitView.hidden = next.isRepo;
|
|
19959
20154
|
repoView.hidden = !next.isRepo;
|
|
19960
20155
|
}
|
|
19961
|
-
if (filesList &&
|
|
20156
|
+
if (filesList && badge2 && next.isRepo) {
|
|
19962
20157
|
const rawStatus = next.status || [];
|
|
19963
20158
|
const parsed = parseGitStatus(rawStatus);
|
|
19964
20159
|
const count = parsed.length;
|
|
19965
|
-
|
|
19966
|
-
|
|
20160
|
+
badge2.textContent = count > 0 ? String(count) : "Clean";
|
|
20161
|
+
badge2.className = `lasso-git-changes-badge${count > 0 ? " has-changes" : " clean"}`;
|
|
19967
20162
|
if (count === 0) {
|
|
19968
20163
|
filesList.innerHTML = `
|
|
19969
20164
|
<div class="lasso-git-clean-state">
|
|
@@ -20148,6 +20343,11 @@
|
|
|
20148
20343
|
</svg>
|
|
20149
20344
|
</button>
|
|
20150
20345
|
|
|
20346
|
+
<button class="lasso-tool-btn agent-tasks-tool" type="button" aria-label="Agent tasks" title="Agent tasks">
|
|
20347
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="3"/><path d="M7 8h10M7 12h6M7 16h8"/></svg>
|
|
20348
|
+
<i class="lasso-agent-tasks-badge" hidden></i>
|
|
20349
|
+
</button>
|
|
20350
|
+
|
|
20151
20351
|
<button class="lasso-tool-btn notepad-tool" type="button" aria-label="Notepad" title="Scratchpad & Notes">
|
|
20152
20352
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
20153
20353
|
<path d="M16 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8l-5-5z"/>
|
|
@@ -20223,6 +20423,7 @@
|
|
|
20223
20423
|
const commentBtn = toolbar.querySelector(".comment-tool");
|
|
20224
20424
|
const gitBtn = toolbar.querySelector(".git-tool");
|
|
20225
20425
|
const todoBtn = toolbar.querySelector(".todo-tool");
|
|
20426
|
+
const agentTasksBtn = toolbar.querySelector(".agent-tasks-tool");
|
|
20226
20427
|
const notepadBtn = toolbar.querySelector(".notepad-tool");
|
|
20227
20428
|
const clipboardBtn = toolbar.querySelector(".clipboard-tool");
|
|
20228
20429
|
const voiceBtn = toolbar.querySelector(".voice-tool");
|
|
@@ -20259,6 +20460,11 @@
|
|
|
20259
20460
|
e.stopPropagation();
|
|
20260
20461
|
toggleTodoPanel();
|
|
20261
20462
|
});
|
|
20463
|
+
agentTasksBtn.addEventListener("click", (e) => {
|
|
20464
|
+
e.preventDefault();
|
|
20465
|
+
e.stopPropagation();
|
|
20466
|
+
toggleTaskPanel();
|
|
20467
|
+
});
|
|
20262
20468
|
notepadBtn.addEventListener("click", (e) => {
|
|
20263
20469
|
e.preventDefault();
|
|
20264
20470
|
e.stopPropagation();
|
|
@@ -20354,6 +20560,9 @@
|
|
|
20354
20560
|
setGeneratedCommitMessage(message.message || "", message.error);
|
|
20355
20561
|
}
|
|
20356
20562
|
if (message.type === "agent_status" && message.status && message.message) {
|
|
20563
|
+
const taskStatus = message.status === "error" ? "error" : message.status === "stopped" ? "stopped" : message.status;
|
|
20564
|
+
updateAgentTask(message.taskId, { status: taskStatus, message: message.message, detail: message.detail, changes: message.changes });
|
|
20565
|
+
if (message.taskId && message.taskId !== state.activeTaskId) return;
|
|
20357
20566
|
setAgentStatus(message.status, message.message, message.detail);
|
|
20358
20567
|
setDragCardStatus(message.status, message.message);
|
|
20359
20568
|
if (message.status === "review" && message.changes?.length) {
|
|
@@ -20368,11 +20577,15 @@
|
|
|
20368
20577
|
}
|
|
20369
20578
|
}
|
|
20370
20579
|
if (message.type === "assistant_message" && message.message) {
|
|
20580
|
+
updateAgentTask(message.taskId, { status: "complete", message: "Complete", response: message.message });
|
|
20581
|
+
if (message.taskId && message.taskId !== state.activeTaskId) return;
|
|
20371
20582
|
void notifyAgent("Agent complete", message.message);
|
|
20372
20583
|
appendChat("assistant", message.message);
|
|
20373
20584
|
resetAgentState();
|
|
20374
20585
|
}
|
|
20375
20586
|
if (message.type === "applied" || message.type === "undone") {
|
|
20587
|
+
updateAgentTask(message.taskId, { status: "complete", message: message.message || "Done." });
|
|
20588
|
+
if (message.taskId && message.taskId !== state.activeTaskId) return;
|
|
20376
20589
|
void notifyAgent(message.type === "applied" ? "Changes applied" : "Change undone", message.message || "Done.");
|
|
20377
20590
|
appendChat("assistant", message.message || "Done.");
|
|
20378
20591
|
releaseHeldLock();
|
|
@@ -20412,6 +20625,7 @@
|
|
|
20412
20625
|
buildTodoPanel();
|
|
20413
20626
|
buildNotepadPanel();
|
|
20414
20627
|
buildClipboardPanel();
|
|
20628
|
+
buildTaskPanel();
|
|
20415
20629
|
buildPrompt();
|
|
20416
20630
|
buildDrag();
|
|
20417
20631
|
initErrorListeners();
|
package/package.json
CHANGED