@lasso-ai/cli 1.0.16 → 1.0.17

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.
Files changed (2) hide show
  1. package/dist/cli/bridge.js +51 -46
  2. package/package.json +1 -1
@@ -114,6 +114,18 @@ function prepareChange(content, change) {
114
114
  const start = content.indexOf(oldString);
115
115
  return { start, end: start + oldString.length, oldString, newString };
116
116
  }
117
+ function proposalMatchesCurrentSource(cwd, changes) {
118
+ try {
119
+ for (const change of changes) {
120
+ const filePath = resolveProposedFile(cwd, change.filePath);
121
+ prepareChange(node_fs_1.default.readFileSync(filePath, "utf8"), change);
122
+ }
123
+ return true;
124
+ }
125
+ catch {
126
+ return false;
127
+ }
128
+ }
117
129
  function readEnvFile(cwd, filename) {
118
130
  try {
119
131
  return node_fs_1.default.readFileSync(node_path_1.default.join(cwd, filename), "utf8").split(/\r?\n/).reduce((values, line) => {
@@ -257,6 +269,43 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
257
269
  if (socket.readyState === socket.OPEN)
258
270
  socket.send(JSON.stringify({ type: "git_state", git }));
259
271
  });
272
+ const runEditReview = (request, config, statusMessage) => {
273
+ activeAgentController?.abort();
274
+ const controller = new AbortController();
275
+ activeAgentController = controller;
276
+ if (statusMessage && socket.readyState === socket.OPEN) {
277
+ socket.send(JSON.stringify({ type: "agent_status", status: "working", message: statusMessage }));
278
+ }
279
+ void (0, agent_1.proposeChanges)(cwd, request, config, controller.signal, (message, detail) => {
280
+ if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
281
+ socket.send(JSON.stringify({ type: "agent_status", status: "working", message, detail }));
282
+ }
283
+ })
284
+ .then((proposal) => {
285
+ if (controller.signal.aborted || socket.readyState !== socket.OPEN)
286
+ return;
287
+ if (!proposalMatchesCurrentSource(cwd, proposal.changes)) {
288
+ if (reviewRefreshAttempts < 1) {
289
+ reviewRefreshAttempts += 1;
290
+ runEditReview(request, config, "The source changed while the proposal was being prepared. Refreshing the review…");
291
+ }
292
+ 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." }));
294
+ }
295
+ return;
296
+ }
297
+ socket.send(JSON.stringify({ type: "agent_status", status: "review", message: proposal.summary, changes: proposal.changes }));
298
+ })
299
+ .catch((error) => {
300
+ 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." }));
302
+ }
303
+ })
304
+ .finally(() => {
305
+ if (activeAgentController === controller)
306
+ activeAgentController = null;
307
+ });
308
+ };
260
309
  socket.on("message", async (raw) => {
261
310
  const msg = JSON.parse(raw.toString());
262
311
  if (msg.type === "edit" || msg.type === "ask") {
@@ -307,34 +356,13 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
307
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." }));
308
357
  return;
309
358
  }
310
- activeAgentController?.abort();
311
- const controller = new AbortController();
312
- activeAgentController = controller;
313
359
  const selectedConfig = localProvider
314
360
  ? { provider: cliProvider, model: msg.model }
315
361
  : { ...agentConfig, provider: (msg.provider || agentConfig.provider), model: msg.model };
316
362
  lastEditRequest = msg;
317
363
  lastEditConfig = selectedConfig;
318
364
  reviewRefreshAttempts = 0;
319
- void (0, agent_1.proposeChanges)(cwd, msg, selectedConfig, controller.signal, (message, detail) => {
320
- if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
321
- socket.send(JSON.stringify({ type: "agent_status", status: "working", message, detail }));
322
- }
323
- })
324
- .then((proposal) => {
325
- if (!controller.signal.aborted)
326
- socket.send(JSON.stringify({ type: "agent_status", status: "review", message: proposal.summary, changes: proposal.changes }));
327
- })
328
- .catch((error) => {
329
- if (controller.signal.aborted)
330
- return;
331
- const message = error instanceof Error ? error.message : "The agent could not prepare a change.";
332
- socket.send(JSON.stringify({ type: "agent_status", status: "error", message }));
333
- })
334
- .finally(() => {
335
- if (activeAgentController === controller)
336
- activeAgentController = null;
337
- });
365
+ runEditReview(msg, selectedConfig);
338
366
  }
339
367
  else if (msg.type === "stop") {
340
368
  activeAgentController?.abort();
@@ -472,30 +500,7 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
472
500
  const message = error instanceof Error ? error.message : "The change could not be applied.";
473
501
  const sourceChanged = message.includes("The source changed after the suggestion was generated");
474
502
  if (sourceChanged && lastEditRequest && lastEditConfig && reviewRefreshAttempts < 1) {
475
- reviewRefreshAttempts += 1;
476
- socket.send(JSON.stringify({ type: "agent_status", status: "working", message: "The source changed. Refreshing the review against the current file…" }));
477
- activeAgentController?.abort();
478
- const controller = new AbortController();
479
- activeAgentController = controller;
480
- void (0, agent_1.proposeChanges)(cwd, lastEditRequest, lastEditConfig, controller.signal, (progress, detail) => {
481
- if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
482
- socket.send(JSON.stringify({ type: "agent_status", status: "working", message: progress, detail }));
483
- }
484
- })
485
- .then((proposal) => {
486
- if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
487
- socket.send(JSON.stringify({ type: "agent_status", status: "review", message: `Review refreshed: ${proposal.summary}`, changes: proposal.changes }));
488
- }
489
- })
490
- .catch((refreshError) => {
491
- if (!controller.signal.aborted && socket.readyState === socket.OPEN) {
492
- socket.send(JSON.stringify({ type: "agent_status", status: "error", message: refreshError instanceof Error ? refreshError.message : "The refreshed review could not be prepared." }));
493
- }
494
- })
495
- .finally(() => {
496
- if (activeAgentController === controller)
497
- activeAgentController = null;
498
- });
503
+ runEditReview(lastEditRequest, lastEditConfig, "The source changed. Refreshing the review against the current file…");
499
504
  }
500
505
  else {
501
506
  socket.send(JSON.stringify({ type: "agent_status", status: "error", message }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lasso-ai/cli",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Select any part of your running app, describe a change, and let AI edit the real source code.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/cli/index.js",