@lasso-ai/cli 2.1.7 → 2.1.9
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.js +44 -2
- package/dist/overlay.js +7 -4
- package/dist/runtime/workspace-guard.js +13 -3
- package/package.json +1 -1
package/dist/cli/bridge.js
CHANGED
|
@@ -22,6 +22,37 @@ const backends_1 = require("./backends");
|
|
|
22
22
|
const local_runtime_1 = require("./local-runtime");
|
|
23
23
|
exports.DEFAULT_BRIDGE_PORT = 3056;
|
|
24
24
|
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
25
|
+
function isConversationalPrompt(prompt) {
|
|
26
|
+
const p = prompt.trim().toLowerCase().replace(/[!?.,;:]+$/, "");
|
|
27
|
+
// 1. Direct greetings and conversational niceties
|
|
28
|
+
const greetings = [
|
|
29
|
+
"hi", "hello", "hey", "heya", "howdy", "sup", "yo",
|
|
30
|
+
"good morning", "good afternoon", "good evening",
|
|
31
|
+
"thanks", "thank you", "thx", "ty", "cool", "awesome", "great", "nice",
|
|
32
|
+
"who are you", "what are you", "what can you do", "help", "help me",
|
|
33
|
+
"what is lasso", "how do you work", "how does this work",
|
|
34
|
+
];
|
|
35
|
+
if (greetings.includes(p))
|
|
36
|
+
return true;
|
|
37
|
+
// Short greetings
|
|
38
|
+
if (/^(hi|hello|hey|howdy|yo)\b/i.test(p) && p.split(/\s+/).length <= 4) {
|
|
39
|
+
const buildKeywords = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code)\b/i;
|
|
40
|
+
if (!buildKeywords.test(p))
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
// 2. Action verbs indicating deliberate code changes
|
|
44
|
+
const mutationVerbs = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code|replace|set|switch|swap|rewrite|restyle|rebuild|apply)\b/i;
|
|
45
|
+
// 3. Question / informational prefixes
|
|
46
|
+
const infoPrefixes = /^(what|how|why|when|where|who|which|can you explain|explain|describe|tell me|check out|check|look at|summarize|give me an overview|overview|inspect)\b/i;
|
|
47
|
+
if (infoPrefixes.test(p) && !mutationVerbs.test(p)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// 4. Questions about the project / app / page without mutation verbs
|
|
51
|
+
if (/\b(about|doing|does this|is this|mean|purpose|work|repo|project|codebase|app|application|page|overview|summary)\b/i.test(p) && !mutationVerbs.test(p)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
25
56
|
function cleanConversationReply(value) {
|
|
26
57
|
const text = typeof value === "string" ? value.trim() : "";
|
|
27
58
|
if (!text)
|
|
@@ -463,11 +494,18 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
|
|
|
463
494
|
return { filePath: change.filePath, content };
|
|
464
495
|
}));
|
|
465
496
|
(0, snapshot_1.createSnapshot)(cwd, taskId, instruction, changes.map((change) => change.filePath), undefined, session.id);
|
|
497
|
+
// Extract the assistant's reply from the session conversation so the user
|
|
498
|
+
// sees both the explanation and the review panel — not just "Review changes".
|
|
499
|
+
const sessionConvo = finalSession.conversation || [];
|
|
500
|
+
const assistantReply = [...sessionConvo]
|
|
501
|
+
.reverse()
|
|
502
|
+
.find((m) => m?.role === "assistant" && typeof m.content === "string")
|
|
503
|
+
?.content?.trim();
|
|
466
504
|
socket.send(JSON.stringify({
|
|
467
505
|
type: "agent_status",
|
|
468
506
|
taskId,
|
|
469
507
|
status: "review",
|
|
470
|
-
message: "Review changes",
|
|
508
|
+
message: assistantReply || "Review changes",
|
|
471
509
|
changes,
|
|
472
510
|
}));
|
|
473
511
|
}
|
|
@@ -567,7 +605,7 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
|
|
|
567
605
|
const controller = new AbortController();
|
|
568
606
|
taskControllers.set(taskId, controller);
|
|
569
607
|
const isLocalAgent = ["claude_code", "opencode", "codex_cli", "cursor"].includes(provider || "");
|
|
570
|
-
if (message.type === "ask" && !isLocalAgent) {
|
|
608
|
+
if ((message.type === "ask" || isConversationalPrompt(instruction)) && !isLocalAgent) {
|
|
571
609
|
await handleHostedConversation(taskId, instruction, model, provider, messages, socket, controller.signal);
|
|
572
610
|
return;
|
|
573
611
|
}
|
|
@@ -896,6 +934,10 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
|
|
|
896
934
|
// there are no canned assistant responses in the bridge.
|
|
897
935
|
try {
|
|
898
936
|
const isLocalAgent = ["claude_code", "opencode", "codex_cli", "cursor"].includes(provider || "");
|
|
937
|
+
if (isConversationalPrompt(prompt) && !isLocalAgent) {
|
|
938
|
+
await handleHostedConversation(taskId, prompt, model, provider, message.messages, socket, controller.signal);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
899
941
|
const backendModelId = (0, backends_1.modelIdForBackend)(model || "", provider || "");
|
|
900
942
|
const sessionInput = {
|
|
901
943
|
userPrompt: prompt,
|
package/dist/overlay.js
CHANGED
|
@@ -19632,12 +19632,15 @@
|
|
|
19632
19632
|
];
|
|
19633
19633
|
if (greetings.includes(p)) return true;
|
|
19634
19634
|
if (/^(hi|hello|hey|howdy|yo)\b/i.test(p) && p.split(/\s+/).length <= 4) {
|
|
19635
|
-
const buildKeywords =
|
|
19635
|
+
const buildKeywords = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code)\b/i;
|
|
19636
19636
|
if (!buildKeywords.test(p)) return true;
|
|
19637
19637
|
}
|
|
19638
|
-
const
|
|
19639
|
-
const
|
|
19640
|
-
if (
|
|
19638
|
+
const mutationVerbs = /\b(build|create|add|make|fix|update|modify|change|refactor|implement|delete|remove|style|install|wire|code|replace|set|switch|swap|rewrite|restyle|rebuild|apply)\b/i;
|
|
19639
|
+
const infoPrefixes = /^(what|how|why|when|where|who|which|can you explain|explain|describe|tell me|check out|check|look at|summarize|give me an overview|overview|inspect)\b/i;
|
|
19640
|
+
if (infoPrefixes.test(p) && !mutationVerbs.test(p)) {
|
|
19641
|
+
return true;
|
|
19642
|
+
}
|
|
19643
|
+
if (/\b(about|doing|does this|is this|mean|purpose|work|repo|project|codebase|app|application|page|overview|summary)\b/i.test(p) && !mutationVerbs.test(p)) {
|
|
19641
19644
|
return true;
|
|
19642
19645
|
}
|
|
19643
19646
|
return false;
|
|
@@ -49,6 +49,15 @@ const DEFAULT_IGNORE_DIRS = new Set([
|
|
|
49
49
|
".gradle",
|
|
50
50
|
".terraform",
|
|
51
51
|
]);
|
|
52
|
+
const DEFAULT_IGNORE_FILES = new Set([
|
|
53
|
+
"next-env.d.ts",
|
|
54
|
+
"tsconfig.tsbuildinfo",
|
|
55
|
+
".DS_Store",
|
|
56
|
+
"Thumbs.db",
|
|
57
|
+
]);
|
|
58
|
+
function shouldIgnoreFile(name) {
|
|
59
|
+
return DEFAULT_IGNORE_FILES.has(name) || name.endsWith(".tsbuildinfo");
|
|
60
|
+
}
|
|
52
61
|
function hashBuffer(buf) {
|
|
53
62
|
return node_crypto_1.default.createHash("sha256").update(buf).digest("hex");
|
|
54
63
|
}
|
|
@@ -110,8 +119,9 @@ class WorkspaceGuard {
|
|
|
110
119
|
walk(absPath, relPath, depth + 1);
|
|
111
120
|
continue;
|
|
112
121
|
}
|
|
113
|
-
if (!entry.isFile()) {
|
|
114
|
-
|
|
122
|
+
if (!entry.isFile() || shouldIgnoreFile(entry.name)) {
|
|
123
|
+
if (!entry.isFile())
|
|
124
|
+
guard.skipped.push(relPath);
|
|
115
125
|
continue;
|
|
116
126
|
}
|
|
117
127
|
try {
|
|
@@ -278,7 +288,7 @@ class WorkspaceGuard {
|
|
|
278
288
|
walk(absPath, relPath, depth + 1);
|
|
279
289
|
continue;
|
|
280
290
|
}
|
|
281
|
-
if (!entry.isFile())
|
|
291
|
+
if (!entry.isFile() || shouldIgnoreFile(entry.name))
|
|
282
292
|
continue;
|
|
283
293
|
if (this.ignoreFn && this.ignoreFn(relPath, false))
|
|
284
294
|
continue;
|
package/package.json
CHANGED