@lasso-ai/cli 1.0.18 → 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/bridge.d.ts +10 -0
- package/dist/cli/bridge.js +58 -43
- package/dist/overlay.js +243 -34
- package/package.json +1 -1
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
|
|
@@ -10882,6 +10884,60 @@
|
|
|
10882
10884
|
display: none;
|
|
10883
10885
|
}
|
|
10884
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
|
+
|
|
10885
10941
|
.lasso-todo-header {
|
|
10886
10942
|
display: flex;
|
|
10887
10943
|
align-items: center;
|
|
@@ -12064,6 +12120,138 @@
|
|
|
12064
12120
|
};
|
|
12065
12121
|
var terminal_default = data4;
|
|
12066
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
|
+
|
|
12067
12255
|
// src/overlay/notifications.ts
|
|
12068
12256
|
var permissionRequest = null;
|
|
12069
12257
|
function requestAgentNotificationPermission() {
|
|
@@ -16841,11 +17029,11 @@
|
|
|
16841
17029
|
}
|
|
16842
17030
|
function updateCommentsBadge() {
|
|
16843
17031
|
const dom = getDOM();
|
|
16844
|
-
const
|
|
16845
|
-
if (!
|
|
17032
|
+
const badge2 = dom.shadow.querySelector(".lasso-comments-badge");
|
|
17033
|
+
if (!badge2) return;
|
|
16846
17034
|
const openCount = threadsInScope().filter((t) => t.root.status === "OPEN").length;
|
|
16847
|
-
|
|
16848
|
-
|
|
17035
|
+
badge2.classList.toggle("visible", openCount > 0);
|
|
17036
|
+
badge2.textContent = String(openCount);
|
|
16849
17037
|
}
|
|
16850
17038
|
function commentPosition(thread) {
|
|
16851
17039
|
const saved = thread.root.meta?.position;
|
|
@@ -17596,7 +17784,7 @@
|
|
|
17596
17784
|
ta.remove();
|
|
17597
17785
|
}
|
|
17598
17786
|
}
|
|
17599
|
-
var
|
|
17787
|
+
var panel2 = null;
|
|
17600
17788
|
var items = [];
|
|
17601
17789
|
var scope = "private";
|
|
17602
17790
|
var PRIVATE_STORAGE_KEY = "lasso:clipboard:private";
|
|
@@ -17655,7 +17843,7 @@
|
|
|
17655
17843
|
<div class="lasso-clipboard-list"></div>
|
|
17656
17844
|
`;
|
|
17657
17845
|
getDOM().shadow.appendChild(el);
|
|
17658
|
-
|
|
17846
|
+
panel2 = el;
|
|
17659
17847
|
el.querySelector(".lasso-clipboard-close").addEventListener("click", () => toggleClipboardPanel(false));
|
|
17660
17848
|
el.querySelectorAll(".lasso-clipboard-tab").forEach((button) => {
|
|
17661
17849
|
button.addEventListener("click", () => {
|
|
@@ -17762,14 +17950,14 @@
|
|
|
17762
17950
|
return TYPE_COLORS[type] ?? TYPE_COLORS.text;
|
|
17763
17951
|
}
|
|
17764
17952
|
function render() {
|
|
17765
|
-
const
|
|
17766
|
-
if (!
|
|
17953
|
+
const list2 = panel2?.querySelector(".lasso-clipboard-list");
|
|
17954
|
+
if (!list2) return;
|
|
17767
17955
|
const visible = items.filter((item) => item.scope === scope);
|
|
17768
17956
|
if (!visible.length) {
|
|
17769
|
-
|
|
17957
|
+
list2.innerHTML = `<div class="lasso-clipboard-empty">${scope === "shared" && !state.collabJoined ? "Join a collaboration session to share items." : "No saved items yet."}</div>`;
|
|
17770
17958
|
return;
|
|
17771
17959
|
}
|
|
17772
|
-
|
|
17960
|
+
list2.innerHTML = visible.map((item) => {
|
|
17773
17961
|
const color = typeColor(item.type);
|
|
17774
17962
|
const icon = typeIcon(item.type);
|
|
17775
17963
|
const preview = escapeHtml3(item.content).slice(0, 220);
|
|
@@ -17793,7 +17981,7 @@
|
|
|
17793
17981
|
</div>
|
|
17794
17982
|
</div>`;
|
|
17795
17983
|
}).join("");
|
|
17796
|
-
|
|
17984
|
+
list2.querySelectorAll(".lasso-clipboard-item").forEach((row) => {
|
|
17797
17985
|
const item = visible.find((candidate) => candidate.uid === row.dataset.id);
|
|
17798
17986
|
if (!item) return;
|
|
17799
17987
|
const copyBtn = row.querySelector(".lasso-clipboard-copy-item");
|
|
@@ -17828,7 +18016,7 @@
|
|
|
17828
18016
|
});
|
|
17829
18017
|
}
|
|
17830
18018
|
function setStatus(message) {
|
|
17831
|
-
const sub =
|
|
18019
|
+
const sub = panel2?.querySelector(".lasso-clipboard-subtitle");
|
|
17832
18020
|
if (!sub) return;
|
|
17833
18021
|
const previous = sub.textContent;
|
|
17834
18022
|
sub.textContent = message;
|
|
@@ -17837,10 +18025,10 @@
|
|
|
17837
18025
|
}, 1800);
|
|
17838
18026
|
}
|
|
17839
18027
|
function toggleClipboardPanel(force) {
|
|
17840
|
-
if (!
|
|
17841
|
-
const next = force === void 0 ? Boolean(
|
|
17842
|
-
|
|
17843
|
-
|
|
18028
|
+
if (!panel2) return;
|
|
18029
|
+
const next = force === void 0 ? Boolean(panel2.hidden) : force;
|
|
18030
|
+
panel2.hidden = !next;
|
|
18031
|
+
panel2.classList.toggle("visible", next);
|
|
17844
18032
|
if (next) requestItems();
|
|
17845
18033
|
}
|
|
17846
18034
|
function escapeHtml3(value2) {
|
|
@@ -18396,7 +18584,7 @@
|
|
|
18396
18584
|
event.preventDefault();
|
|
18397
18585
|
event.stopPropagation();
|
|
18398
18586
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
18399
|
-
state.bridgeSocket.send(JSON.stringify({ type: "stop" }));
|
|
18587
|
+
state.bridgeSocket.send(JSON.stringify({ type: "stop", taskId: state.activeTaskId || void 0 }));
|
|
18400
18588
|
}
|
|
18401
18589
|
appendChat("assistant", "Agent stopped.");
|
|
18402
18590
|
resetAgentState();
|
|
@@ -18457,7 +18645,7 @@
|
|
|
18457
18645
|
rev.querySelector(".lasso-review-undo").addEventListener("click", () => {
|
|
18458
18646
|
if (state.pendingChanges.length && rev.querySelector(".lasso-review-apply").hidden) {
|
|
18459
18647
|
if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
|
|
18460
|
-
state.bridgeSocket.send(JSON.stringify({ type: "undo" }));
|
|
18648
|
+
state.bridgeSocket.send(JSON.stringify({ type: "undo", taskId: state.activeTaskId || void 0 }));
|
|
18461
18649
|
}
|
|
18462
18650
|
return;
|
|
18463
18651
|
}
|
|
@@ -18467,7 +18655,7 @@
|
|
|
18467
18655
|
rev.querySelector(".lasso-review-apply").addEventListener("click", () => {
|
|
18468
18656
|
if (!state.bridgeSocket || state.bridgeSocket.readyState !== WebSocket.OPEN || !state.pendingChanges.length) return;
|
|
18469
18657
|
requestAgentNotificationPermission();
|
|
18470
|
-
state.bridgeSocket.send(JSON.stringify({ type: "apply", changes: state.pendingChanges }));
|
|
18658
|
+
state.bridgeSocket.send(JSON.stringify({ type: "apply", taskId: state.activeTaskId || "", changes: state.pendingChanges }));
|
|
18471
18659
|
appendChat("assistant", "Applying the reviewed change\u2026");
|
|
18472
18660
|
});
|
|
18473
18661
|
return { prompt: el, review: rev };
|
|
@@ -18677,9 +18865,9 @@
|
|
|
18677
18865
|
container.append(document.createTextNode(text.slice(lastIndex)));
|
|
18678
18866
|
}
|
|
18679
18867
|
}
|
|
18680
|
-
function setAgentStatus(status, message,
|
|
18868
|
+
function setAgentStatus(status, message, detail2) {
|
|
18681
18869
|
if (!agentStatusElement || !agentStatusMessage || !sendButton) return;
|
|
18682
|
-
const logMessage =
|
|
18870
|
+
const logMessage = detail2?.trim() || message.trim();
|
|
18683
18871
|
const lastLog = agentLogLines[agentLogLines.length - 1];
|
|
18684
18872
|
if (agentStatusElement.dataset.status === status && agentStatusMessage.textContent === message && (status === "thinking" || status === "working") && (!logMessage || lastLog === logMessage)) return;
|
|
18685
18873
|
appendAgentLog(logMessage);
|
|
@@ -18694,7 +18882,7 @@
|
|
|
18694
18882
|
state.agentRunning = status === "thinking" || status === "working";
|
|
18695
18883
|
sendButton.classList.toggle("loading", state.agentRunning);
|
|
18696
18884
|
if (stopButton) stopButton.hidden = !state.agentRunning;
|
|
18697
|
-
if (promptInput) promptInput.disabled =
|
|
18885
|
+
if (promptInput) promptInput.disabled = false;
|
|
18698
18886
|
const label = sendButton.querySelector("span");
|
|
18699
18887
|
if (label) {
|
|
18700
18888
|
label.textContent = status === "review" ? "Review" : status === "error" ? "Retry" : state.agentRunning ? "" : "Send";
|
|
@@ -18710,7 +18898,7 @@
|
|
|
18710
18898
|
if (!promptInput || !sendButton) return;
|
|
18711
18899
|
const hasInstruction = Boolean(promptInput.value.trim()) || sendButton.dataset.state === "retry" && Boolean(state.lastInstruction?.trim());
|
|
18712
18900
|
const isReviewAction = sendButton.dataset.state === "review";
|
|
18713
|
-
sendButton.disabled =
|
|
18901
|
+
sendButton.disabled = !hasInstruction && !isReviewAction;
|
|
18714
18902
|
}
|
|
18715
18903
|
function resetAgentState() {
|
|
18716
18904
|
state.agentRunning = false;
|
|
@@ -18847,6 +19035,7 @@
|
|
|
18847
19035
|
});
|
|
18848
19036
|
}
|
|
18849
19037
|
appendChat("user", instruction);
|
|
19038
|
+
const task = createAgentTask(instruction);
|
|
18850
19039
|
setAgentStatus("thinking", "Thinking\u2026");
|
|
18851
19040
|
state.lastInstruction = instruction;
|
|
18852
19041
|
promptInput.value = "";
|
|
@@ -18860,6 +19049,7 @@
|
|
|
18860
19049
|
state.bridgeSocket.send(
|
|
18861
19050
|
JSON.stringify({
|
|
18862
19051
|
type: wantsAnswer ? "ask" : "edit",
|
|
19052
|
+
taskId: task.id,
|
|
18863
19053
|
question: wantsAnswer ? instruction : void 0,
|
|
18864
19054
|
instruction,
|
|
18865
19055
|
messages: state.chatHistory,
|
|
@@ -19711,25 +19901,25 @@
|
|
|
19711
19901
|
const parts2 = filePath.split("/");
|
|
19712
19902
|
const name = parts2.pop() || filePath;
|
|
19713
19903
|
const dir = parts2.length ? parts2.join("/") + "/" : "";
|
|
19714
|
-
let
|
|
19904
|
+
let badge2 = "M";
|
|
19715
19905
|
let badgeClass = "mod";
|
|
19716
19906
|
if (code.includes("A")) {
|
|
19717
|
-
|
|
19907
|
+
badge2 = "A";
|
|
19718
19908
|
badgeClass = "add";
|
|
19719
19909
|
} else if (code.includes("D")) {
|
|
19720
|
-
|
|
19910
|
+
badge2 = "D";
|
|
19721
19911
|
badgeClass = "del";
|
|
19722
19912
|
} else if (code.includes("R")) {
|
|
19723
|
-
|
|
19913
|
+
badge2 = "R";
|
|
19724
19914
|
badgeClass = "ren";
|
|
19725
19915
|
} else if (code === "??" || code.includes("?")) {
|
|
19726
|
-
|
|
19916
|
+
badge2 = "U";
|
|
19727
19917
|
badgeClass = "unt";
|
|
19728
19918
|
} else if (code.includes("M")) {
|
|
19729
|
-
|
|
19919
|
+
badge2 = "M";
|
|
19730
19920
|
badgeClass = "mod";
|
|
19731
19921
|
}
|
|
19732
|
-
return { code, badge, badgeClass, path: filePath, dir, name };
|
|
19922
|
+
return { code, badge: badge2, badgeClass, path: filePath, dir, name };
|
|
19733
19923
|
});
|
|
19734
19924
|
}
|
|
19735
19925
|
function escapeHtml4(text) {
|
|
@@ -19940,7 +20130,7 @@
|
|
|
19940
20130
|
const uninitView = gitPanelEl.querySelector(".lasso-git-uninit-view");
|
|
19941
20131
|
const repoView = gitPanelEl.querySelector(".lasso-git-repo-view");
|
|
19942
20132
|
const filesList = gitPanelEl.querySelector(".lasso-git-files-list");
|
|
19943
|
-
const
|
|
20133
|
+
const badge2 = gitPanelEl.querySelector(".lasso-git-changes-badge");
|
|
19944
20134
|
const commitBtn = gitPanelEl.querySelector(".lasso-git-commit-btn");
|
|
19945
20135
|
const commitBtnText = gitPanelEl.querySelector(".lasso-git-commit-btn-text");
|
|
19946
20136
|
const pushBtn = gitPanelEl.querySelector(".lasso-git-push-btn");
|
|
@@ -19963,12 +20153,12 @@
|
|
|
19963
20153
|
uninitView.hidden = next.isRepo;
|
|
19964
20154
|
repoView.hidden = !next.isRepo;
|
|
19965
20155
|
}
|
|
19966
|
-
if (filesList &&
|
|
20156
|
+
if (filesList && badge2 && next.isRepo) {
|
|
19967
20157
|
const rawStatus = next.status || [];
|
|
19968
20158
|
const parsed = parseGitStatus(rawStatus);
|
|
19969
20159
|
const count = parsed.length;
|
|
19970
|
-
|
|
19971
|
-
|
|
20160
|
+
badge2.textContent = count > 0 ? String(count) : "Clean";
|
|
20161
|
+
badge2.className = `lasso-git-changes-badge${count > 0 ? " has-changes" : " clean"}`;
|
|
19972
20162
|
if (count === 0) {
|
|
19973
20163
|
filesList.innerHTML = `
|
|
19974
20164
|
<div class="lasso-git-clean-state">
|
|
@@ -20153,6 +20343,11 @@
|
|
|
20153
20343
|
</svg>
|
|
20154
20344
|
</button>
|
|
20155
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
|
+
|
|
20156
20351
|
<button class="lasso-tool-btn notepad-tool" type="button" aria-label="Notepad" title="Scratchpad & Notes">
|
|
20157
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">
|
|
20158
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"/>
|
|
@@ -20228,6 +20423,7 @@
|
|
|
20228
20423
|
const commentBtn = toolbar.querySelector(".comment-tool");
|
|
20229
20424
|
const gitBtn = toolbar.querySelector(".git-tool");
|
|
20230
20425
|
const todoBtn = toolbar.querySelector(".todo-tool");
|
|
20426
|
+
const agentTasksBtn = toolbar.querySelector(".agent-tasks-tool");
|
|
20231
20427
|
const notepadBtn = toolbar.querySelector(".notepad-tool");
|
|
20232
20428
|
const clipboardBtn = toolbar.querySelector(".clipboard-tool");
|
|
20233
20429
|
const voiceBtn = toolbar.querySelector(".voice-tool");
|
|
@@ -20264,6 +20460,11 @@
|
|
|
20264
20460
|
e.stopPropagation();
|
|
20265
20461
|
toggleTodoPanel();
|
|
20266
20462
|
});
|
|
20463
|
+
agentTasksBtn.addEventListener("click", (e) => {
|
|
20464
|
+
e.preventDefault();
|
|
20465
|
+
e.stopPropagation();
|
|
20466
|
+
toggleTaskPanel();
|
|
20467
|
+
});
|
|
20267
20468
|
notepadBtn.addEventListener("click", (e) => {
|
|
20268
20469
|
e.preventDefault();
|
|
20269
20470
|
e.stopPropagation();
|
|
@@ -20359,6 +20560,9 @@
|
|
|
20359
20560
|
setGeneratedCommitMessage(message.message || "", message.error);
|
|
20360
20561
|
}
|
|
20361
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;
|
|
20362
20566
|
setAgentStatus(message.status, message.message, message.detail);
|
|
20363
20567
|
setDragCardStatus(message.status, message.message);
|
|
20364
20568
|
if (message.status === "review" && message.changes?.length) {
|
|
@@ -20373,11 +20577,15 @@
|
|
|
20373
20577
|
}
|
|
20374
20578
|
}
|
|
20375
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;
|
|
20376
20582
|
void notifyAgent("Agent complete", message.message);
|
|
20377
20583
|
appendChat("assistant", message.message);
|
|
20378
20584
|
resetAgentState();
|
|
20379
20585
|
}
|
|
20380
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;
|
|
20381
20589
|
void notifyAgent(message.type === "applied" ? "Changes applied" : "Change undone", message.message || "Done.");
|
|
20382
20590
|
appendChat("assistant", message.message || "Done.");
|
|
20383
20591
|
releaseHeldLock();
|
|
@@ -20417,6 +20625,7 @@
|
|
|
20417
20625
|
buildTodoPanel();
|
|
20418
20626
|
buildNotepadPanel();
|
|
20419
20627
|
buildClipboardPanel();
|
|
20628
|
+
buildTaskPanel();
|
|
20420
20629
|
buildPrompt();
|
|
20421
20630
|
buildDrag();
|
|
20422
20631
|
initErrorListeners();
|
package/package.json
CHANGED