@volter-ai-dev/supercode-ui 0.1.15 → 0.1.16
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/components.mjs +138 -11
- package/conversation.mjs +138 -11
- package/core.mjs +88 -13
- package/embed.mjs +138 -11
- package/messenger.mjs +138 -11
- package/package.json +1 -1
package/components.mjs
CHANGED
|
@@ -113,18 +113,116 @@ function decodedLiteral(value) {
|
|
|
113
113
|
function sourceString(source, keys) {
|
|
114
114
|
if (!source) return "";
|
|
115
115
|
const names = keys.join("|");
|
|
116
|
-
const match = new RegExp(
|
|
116
|
+
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
117
117
|
return decodedLiteral(match?.[1]);
|
|
118
118
|
}
|
|
119
|
+
function callArgumentSource(source, open) {
|
|
120
|
+
let depth = 1;
|
|
121
|
+
let quote = "";
|
|
122
|
+
let escaped = false;
|
|
123
|
+
let lineComment = false;
|
|
124
|
+
let blockComment = false;
|
|
125
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
126
|
+
const char = source[index];
|
|
127
|
+
const next = source[index + 1];
|
|
128
|
+
if (lineComment) {
|
|
129
|
+
if (char === "\n") lineComment = false;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (blockComment) {
|
|
133
|
+
if (char === "*" && next === "/") {
|
|
134
|
+
blockComment = false;
|
|
135
|
+
index += 1;
|
|
136
|
+
}
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (quote) {
|
|
140
|
+
if (escaped) escaped = false;
|
|
141
|
+
else if (char === "\\") escaped = true;
|
|
142
|
+
else if (char === quote) quote = "";
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (char === "/" && next === "/") {
|
|
146
|
+
lineComment = true;
|
|
147
|
+
index += 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (char === "/" && next === "*") {
|
|
151
|
+
blockComment = true;
|
|
152
|
+
index += 1;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
156
|
+
quote = char;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (char === "(") depth += 1;
|
|
160
|
+
else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
161
|
+
}
|
|
162
|
+
return source.slice(open + 1);
|
|
163
|
+
}
|
|
164
|
+
function toolCalls(source) {
|
|
165
|
+
const calls = [];
|
|
166
|
+
let quote = "";
|
|
167
|
+
let escaped = false;
|
|
168
|
+
let lineComment = false;
|
|
169
|
+
let blockComment = false;
|
|
170
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
171
|
+
const char = source[index];
|
|
172
|
+
const next = source[index + 1];
|
|
173
|
+
if (lineComment) {
|
|
174
|
+
if (char === "\n") lineComment = false;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (blockComment) {
|
|
178
|
+
if (char === "*" && next === "/") {
|
|
179
|
+
blockComment = false;
|
|
180
|
+
index += 1;
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (quote) {
|
|
185
|
+
if (escaped) escaped = false;
|
|
186
|
+
else if (char === "\\") escaped = true;
|
|
187
|
+
else if (char === quote) quote = "";
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (char === "/" && next === "/") {
|
|
191
|
+
lineComment = true;
|
|
192
|
+
index += 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (char === "/" && next === "*") {
|
|
196
|
+
blockComment = true;
|
|
197
|
+
index += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
201
|
+
quote = char;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
|
|
205
|
+
const nameStart = index + 6;
|
|
206
|
+
let nameEnd = nameStart;
|
|
207
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
|
|
208
|
+
let open = nameEnd;
|
|
209
|
+
while (/\s/.test(source[open] ?? "")) open += 1;
|
|
210
|
+
if (nameEnd === nameStart || source[open] !== "(") continue;
|
|
211
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
212
|
+
index = open;
|
|
213
|
+
}
|
|
214
|
+
return calls;
|
|
215
|
+
}
|
|
119
216
|
function toolEnvelope(entry) {
|
|
120
217
|
const value = argumentValue(entry.arguments);
|
|
121
|
-
const source = typeof value === "string" ? value : "";
|
|
122
|
-
const
|
|
218
|
+
const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
|
|
219
|
+
const calls = source ? toolCalls(source) : [];
|
|
220
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
123
221
|
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
124
|
-
return { args: record(value), source, tools, name };
|
|
222
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
|
|
125
223
|
}
|
|
126
224
|
function patchPath(source) {
|
|
127
|
-
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]
|
|
225
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
|
|
128
226
|
}
|
|
129
227
|
function explicitNumber(sources, keys) {
|
|
130
228
|
for (const source of sources) {
|
|
@@ -174,6 +272,35 @@ function editPreview(args, resultText, source) {
|
|
|
174
272
|
if (patch) return patch;
|
|
175
273
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
176
274
|
}
|
|
275
|
+
function verificationCommand(command) {
|
|
276
|
+
let shell = "";
|
|
277
|
+
let quote = "";
|
|
278
|
+
let escaped = false;
|
|
279
|
+
for (const char of command) {
|
|
280
|
+
if (escaped) {
|
|
281
|
+
escaped = false;
|
|
282
|
+
shell += quote ? " " : char;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (char === "\\") {
|
|
286
|
+
escaped = true;
|
|
287
|
+
shell += quote ? " " : char;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (quote) {
|
|
291
|
+
if (char === quote) quote = "";
|
|
292
|
+
shell += " ";
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
296
|
+
quote = char;
|
|
297
|
+
shell += " ";
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
shell += char;
|
|
301
|
+
}
|
|
302
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
303
|
+
}
|
|
177
304
|
function classifyTool(name, command) {
|
|
178
305
|
const normalized = name.toLocaleLowerCase();
|
|
179
306
|
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
@@ -184,7 +311,7 @@ function classifyTool(name, command) {
|
|
|
184
311
|
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
185
312
|
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
186
313
|
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
187
|
-
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return
|
|
314
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
188
315
|
return "other";
|
|
189
316
|
}
|
|
190
317
|
function toolAction(status, category, name, tools) {
|
|
@@ -209,12 +336,12 @@ function toolAction(status, category, name, tools) {
|
|
|
209
336
|
function createToolPresentation(entry) {
|
|
210
337
|
const envelope = toolEnvelope(entry);
|
|
211
338
|
const args = envelope.args;
|
|
212
|
-
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.
|
|
339
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
213
340
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
214
|
-
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.
|
|
215
|
-
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.
|
|
216
|
-
const url = firstString(args, ["url"]) || sourceString(envelope.
|
|
217
|
-
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.
|
|
341
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
342
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
343
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
344
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "prompt"]);
|
|
218
345
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
219
346
|
const items = planItems(args);
|
|
220
347
|
const taskId = firstString(args, ["taskId", "task_id"]);
|
package/conversation.mjs
CHANGED
|
@@ -99,18 +99,116 @@ function decodedLiteral(value) {
|
|
|
99
99
|
function sourceString(source, keys) {
|
|
100
100
|
if (!source) return "";
|
|
101
101
|
const names = keys.join("|");
|
|
102
|
-
const match = new RegExp(
|
|
102
|
+
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
103
103
|
return decodedLiteral(match?.[1]);
|
|
104
104
|
}
|
|
105
|
+
function callArgumentSource(source, open) {
|
|
106
|
+
let depth = 1;
|
|
107
|
+
let quote = "";
|
|
108
|
+
let escaped = false;
|
|
109
|
+
let lineComment = false;
|
|
110
|
+
let blockComment = false;
|
|
111
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
112
|
+
const char = source[index];
|
|
113
|
+
const next = source[index + 1];
|
|
114
|
+
if (lineComment) {
|
|
115
|
+
if (char === "\n") lineComment = false;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (blockComment) {
|
|
119
|
+
if (char === "*" && next === "/") {
|
|
120
|
+
blockComment = false;
|
|
121
|
+
index += 1;
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (quote) {
|
|
126
|
+
if (escaped) escaped = false;
|
|
127
|
+
else if (char === "\\") escaped = true;
|
|
128
|
+
else if (char === quote) quote = "";
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (char === "/" && next === "/") {
|
|
132
|
+
lineComment = true;
|
|
133
|
+
index += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (char === "/" && next === "*") {
|
|
137
|
+
blockComment = true;
|
|
138
|
+
index += 1;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
142
|
+
quote = char;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (char === "(") depth += 1;
|
|
146
|
+
else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
147
|
+
}
|
|
148
|
+
return source.slice(open + 1);
|
|
149
|
+
}
|
|
150
|
+
function toolCalls(source) {
|
|
151
|
+
const calls = [];
|
|
152
|
+
let quote = "";
|
|
153
|
+
let escaped = false;
|
|
154
|
+
let lineComment = false;
|
|
155
|
+
let blockComment = false;
|
|
156
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
157
|
+
const char = source[index];
|
|
158
|
+
const next = source[index + 1];
|
|
159
|
+
if (lineComment) {
|
|
160
|
+
if (char === "\n") lineComment = false;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (blockComment) {
|
|
164
|
+
if (char === "*" && next === "/") {
|
|
165
|
+
blockComment = false;
|
|
166
|
+
index += 1;
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (quote) {
|
|
171
|
+
if (escaped) escaped = false;
|
|
172
|
+
else if (char === "\\") escaped = true;
|
|
173
|
+
else if (char === quote) quote = "";
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (char === "/" && next === "/") {
|
|
177
|
+
lineComment = true;
|
|
178
|
+
index += 1;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (char === "/" && next === "*") {
|
|
182
|
+
blockComment = true;
|
|
183
|
+
index += 1;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
187
|
+
quote = char;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
|
|
191
|
+
const nameStart = index + 6;
|
|
192
|
+
let nameEnd = nameStart;
|
|
193
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
|
|
194
|
+
let open = nameEnd;
|
|
195
|
+
while (/\s/.test(source[open] ?? "")) open += 1;
|
|
196
|
+
if (nameEnd === nameStart || source[open] !== "(") continue;
|
|
197
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
198
|
+
index = open;
|
|
199
|
+
}
|
|
200
|
+
return calls;
|
|
201
|
+
}
|
|
105
202
|
function toolEnvelope(entry) {
|
|
106
203
|
const value = argumentValue(entry.arguments);
|
|
107
|
-
const source = typeof value === "string" ? value : "";
|
|
108
|
-
const
|
|
204
|
+
const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
|
|
205
|
+
const calls = source ? toolCalls(source) : [];
|
|
206
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
109
207
|
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
110
|
-
return { args: record(value), source, tools, name };
|
|
208
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
|
|
111
209
|
}
|
|
112
210
|
function patchPath(source) {
|
|
113
|
-
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]
|
|
211
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
|
|
114
212
|
}
|
|
115
213
|
function explicitNumber(sources, keys) {
|
|
116
214
|
for (const source of sources) {
|
|
@@ -160,6 +258,35 @@ function editPreview(args, resultText, source) {
|
|
|
160
258
|
if (patch) return patch;
|
|
161
259
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
162
260
|
}
|
|
261
|
+
function verificationCommand(command) {
|
|
262
|
+
let shell = "";
|
|
263
|
+
let quote = "";
|
|
264
|
+
let escaped = false;
|
|
265
|
+
for (const char of command) {
|
|
266
|
+
if (escaped) {
|
|
267
|
+
escaped = false;
|
|
268
|
+
shell += quote ? " " : char;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (char === "\\") {
|
|
272
|
+
escaped = true;
|
|
273
|
+
shell += quote ? " " : char;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (quote) {
|
|
277
|
+
if (char === quote) quote = "";
|
|
278
|
+
shell += " ";
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
282
|
+
quote = char;
|
|
283
|
+
shell += " ";
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
shell += char;
|
|
287
|
+
}
|
|
288
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
289
|
+
}
|
|
163
290
|
function classifyTool(name, command) {
|
|
164
291
|
const normalized = name.toLocaleLowerCase();
|
|
165
292
|
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
@@ -170,7 +297,7 @@ function classifyTool(name, command) {
|
|
|
170
297
|
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
171
298
|
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
172
299
|
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
173
|
-
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return
|
|
300
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
174
301
|
return "other";
|
|
175
302
|
}
|
|
176
303
|
function toolAction(status, category, name, tools) {
|
|
@@ -195,12 +322,12 @@ function toolAction(status, category, name, tools) {
|
|
|
195
322
|
function createToolPresentation(entry) {
|
|
196
323
|
const envelope = toolEnvelope(entry);
|
|
197
324
|
const args = envelope.args;
|
|
198
|
-
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.
|
|
325
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
199
326
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
200
|
-
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.
|
|
201
|
-
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.
|
|
202
|
-
const url = firstString(args, ["url"]) || sourceString(envelope.
|
|
203
|
-
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.
|
|
327
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
328
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
329
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
330
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "prompt"]);
|
|
204
331
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
205
332
|
const items = planItems(args);
|
|
206
333
|
const taskId = firstString(args, ["taskId", "task_id"]);
|
package/core.mjs
CHANGED
|
@@ -127,22 +127,83 @@ function decodedLiteral(value) {
|
|
|
127
127
|
function sourceString(source, keys) {
|
|
128
128
|
if (!source) return '';
|
|
129
129
|
const names = keys.join('|');
|
|
130
|
-
const match = new RegExp(
|
|
130
|
+
const match = new RegExp(`(?:^|[,{\\s])[\"']?(?:${names})[\"']?\\s*:\\s*(\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
131
131
|
return decodedLiteral(match?.[1]);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
function callArgumentSource(source, open) {
|
|
135
|
+
let depth = 1;
|
|
136
|
+
let quote = '';
|
|
137
|
+
let escaped = false;
|
|
138
|
+
let lineComment = false;
|
|
139
|
+
let blockComment = false;
|
|
140
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
141
|
+
const char = source[index];
|
|
142
|
+
const next = source[index + 1];
|
|
143
|
+
if (lineComment) { if (char === '\n') lineComment = false; continue; }
|
|
144
|
+
if (blockComment) { if (char === '*' && next === '/') { blockComment = false; index += 1; } continue; }
|
|
145
|
+
if (quote) {
|
|
146
|
+
if (escaped) escaped = false;
|
|
147
|
+
else if (char === '\\') escaped = true;
|
|
148
|
+
else if (char === quote) quote = '';
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (char === '/' && next === '/') { lineComment = true; index += 1; continue; }
|
|
152
|
+
if (char === '/' && next === '*') { blockComment = true; index += 1; continue; }
|
|
153
|
+
if (char === '"' || char === "'" || char === '`') { quote = char; continue; }
|
|
154
|
+
if (char === '(') depth += 1;
|
|
155
|
+
else if (char === ')' && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
156
|
+
}
|
|
157
|
+
return source.slice(open + 1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function toolCalls(source) {
|
|
161
|
+
const calls = [];
|
|
162
|
+
let quote = '';
|
|
163
|
+
let escaped = false;
|
|
164
|
+
let lineComment = false;
|
|
165
|
+
let blockComment = false;
|
|
166
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
167
|
+
const char = source[index];
|
|
168
|
+
const next = source[index + 1];
|
|
169
|
+
if (lineComment) { if (char === '\n') lineComment = false; continue; }
|
|
170
|
+
if (blockComment) { if (char === '*' && next === '/') { blockComment = false; index += 1; } continue; }
|
|
171
|
+
if (quote) {
|
|
172
|
+
if (escaped) escaped = false;
|
|
173
|
+
else if (char === '\\') escaped = true;
|
|
174
|
+
else if (char === quote) quote = '';
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (char === '/' && next === '/') { lineComment = true; index += 1; continue; }
|
|
178
|
+
if (char === '/' && next === '*') { blockComment = true; index += 1; continue; }
|
|
179
|
+
if (char === '"' || char === "'" || char === '`') { quote = char; continue; }
|
|
180
|
+
if (!source.startsWith('tools.', index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? '')) continue;
|
|
181
|
+
const nameStart = index + 6;
|
|
182
|
+
let nameEnd = nameStart;
|
|
183
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? '')) nameEnd += 1;
|
|
184
|
+
let open = nameEnd;
|
|
185
|
+
while (/\s/.test(source[open] ?? '')) open += 1;
|
|
186
|
+
if (nameEnd === nameStart || source[open] !== '(') continue;
|
|
187
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
188
|
+
index = open;
|
|
189
|
+
}
|
|
190
|
+
return calls;
|
|
191
|
+
}
|
|
192
|
+
|
|
134
193
|
function toolEnvelope(entry) {
|
|
135
194
|
const value = argumentValue(entry.arguments);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
195
|
+
// Codex custom tools retain their safe JavaScript wrapper directly, while function-call
|
|
196
|
+
// envelopes usually retain JSON. Parse the latter, but treat unparsed text only as source for
|
|
197
|
+
// bounded literal extraction—never evaluate it and never surface the wrapper as primary UI.
|
|
198
|
+
const source = typeof value === 'string' ? value : value === null ? entry.arguments ?? '' : '';
|
|
199
|
+
const calls = source ? toolCalls(source) : [];
|
|
200
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
140
201
|
const name = tools.length === 1 ? tools[0] : entry.label ?? 'tool';
|
|
141
|
-
return { args: record(value), source, tools, name };
|
|
202
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? '', tools, name };
|
|
142
203
|
}
|
|
143
204
|
|
|
144
205
|
function patchPath(source) {
|
|
145
|
-
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]
|
|
206
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? '';
|
|
146
207
|
}
|
|
147
208
|
|
|
148
209
|
function explicitNumber(sources, keys) {
|
|
@@ -198,6 +259,20 @@ function editPreview(args, resultText, source) {
|
|
|
198
259
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? '') ? resultText : '';
|
|
199
260
|
}
|
|
200
261
|
|
|
262
|
+
function verificationCommand(command) {
|
|
263
|
+
let shell = '';
|
|
264
|
+
let quote = '';
|
|
265
|
+
let escaped = false;
|
|
266
|
+
for (const char of command) {
|
|
267
|
+
if (escaped) { escaped = false; shell += quote ? ' ' : char; continue; }
|
|
268
|
+
if (char === '\\') { escaped = true; shell += quote ? ' ' : char; continue; }
|
|
269
|
+
if (quote) { if (char === quote) quote = ''; shell += ' '; continue; }
|
|
270
|
+
if (char === '"' || char === "'" || char === '`') { quote = char; shell += ' '; continue; }
|
|
271
|
+
shell += char;
|
|
272
|
+
}
|
|
273
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
274
|
+
}
|
|
275
|
+
|
|
201
276
|
function classifyTool(name, command) {
|
|
202
277
|
const normalized = name.toLocaleLowerCase();
|
|
203
278
|
if (/write_stdin|^wait$/.test(normalized)) return 'command';
|
|
@@ -208,7 +283,7 @@ function classifyTool(name, command) {
|
|
|
208
283
|
if (/browser|web|fetch|url/.test(normalized)) return 'web';
|
|
209
284
|
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return 'agent';
|
|
210
285
|
if (/test|typecheck|lint|build/.test(normalized)) return 'test';
|
|
211
|
-
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return
|
|
286
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? 'test' : 'command';
|
|
212
287
|
return 'other';
|
|
213
288
|
}
|
|
214
289
|
|
|
@@ -235,12 +310,12 @@ function toolAction(status, category, name, tools) {
|
|
|
235
310
|
export function createToolPresentation(entry) {
|
|
236
311
|
const envelope = toolEnvelope(entry);
|
|
237
312
|
const args = envelope.args;
|
|
238
|
-
const command = firstString(args, ['command', 'cmd']) || sourceString(envelope.
|
|
313
|
+
const command = firstString(args, ['command', 'cmd']) || sourceString(envelope.callSource, ['command', 'cmd']);
|
|
239
314
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || '');
|
|
240
|
-
const path = firstString(args, ['file_path', 'target_file', 'target_directory', 'path']) || sourceString(envelope.
|
|
241
|
-
const query = firstString(args, ['query', 'pattern']) || sourceString(envelope.
|
|
242
|
-
const url = firstString(args, ['url']) || sourceString(envelope.
|
|
243
|
-
const subject = firstString(args, ['subject', 'description', 'summary', 'task', 'prompt']) || sourceString(envelope.
|
|
315
|
+
const path = firstString(args, ['file_path', 'target_file', 'target_directory', 'path']) || sourceString(envelope.callSource, ['file_path', 'target_file', 'target_directory', 'path']) || patchPath(envelope.source);
|
|
316
|
+
const query = firstString(args, ['query', 'pattern']) || sourceString(envelope.callSource, ['query', 'pattern', 'q']);
|
|
317
|
+
const url = firstString(args, ['url']) || sourceString(envelope.callSource, ['url', 'ref_id']);
|
|
318
|
+
const subject = firstString(args, ['subject', 'description', 'summary', 'task', 'prompt']) || sourceString(envelope.callSource, ['subject', 'description', 'summary', 'task', 'prompt']);
|
|
244
319
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? 'background task' : /write_stdin|^wait$/i.test(envelope.name) ? 'background command' : '';
|
|
245
320
|
const items = planItems(args);
|
|
246
321
|
const taskId = firstString(args, ['taskId', 'task_id']);
|
package/embed.mjs
CHANGED
|
@@ -116,18 +116,116 @@ function decodedLiteral(value) {
|
|
|
116
116
|
function sourceString(source, keys) {
|
|
117
117
|
if (!source) return "";
|
|
118
118
|
const names = keys.join("|");
|
|
119
|
-
const match = new RegExp(
|
|
119
|
+
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
120
120
|
return decodedLiteral(match?.[1]);
|
|
121
121
|
}
|
|
122
|
+
function callArgumentSource(source, open) {
|
|
123
|
+
let depth = 1;
|
|
124
|
+
let quote = "";
|
|
125
|
+
let escaped = false;
|
|
126
|
+
let lineComment = false;
|
|
127
|
+
let blockComment = false;
|
|
128
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
129
|
+
const char = source[index];
|
|
130
|
+
const next = source[index + 1];
|
|
131
|
+
if (lineComment) {
|
|
132
|
+
if (char === "\n") lineComment = false;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (blockComment) {
|
|
136
|
+
if (char === "*" && next === "/") {
|
|
137
|
+
blockComment = false;
|
|
138
|
+
index += 1;
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (quote) {
|
|
143
|
+
if (escaped) escaped = false;
|
|
144
|
+
else if (char === "\\") escaped = true;
|
|
145
|
+
else if (char === quote) quote = "";
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (char === "/" && next === "/") {
|
|
149
|
+
lineComment = true;
|
|
150
|
+
index += 1;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (char === "/" && next === "*") {
|
|
154
|
+
blockComment = true;
|
|
155
|
+
index += 1;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
159
|
+
quote = char;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (char === "(") depth += 1;
|
|
163
|
+
else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
164
|
+
}
|
|
165
|
+
return source.slice(open + 1);
|
|
166
|
+
}
|
|
167
|
+
function toolCalls(source) {
|
|
168
|
+
const calls = [];
|
|
169
|
+
let quote = "";
|
|
170
|
+
let escaped = false;
|
|
171
|
+
let lineComment = false;
|
|
172
|
+
let blockComment = false;
|
|
173
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
174
|
+
const char = source[index];
|
|
175
|
+
const next = source[index + 1];
|
|
176
|
+
if (lineComment) {
|
|
177
|
+
if (char === "\n") lineComment = false;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (blockComment) {
|
|
181
|
+
if (char === "*" && next === "/") {
|
|
182
|
+
blockComment = false;
|
|
183
|
+
index += 1;
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (quote) {
|
|
188
|
+
if (escaped) escaped = false;
|
|
189
|
+
else if (char === "\\") escaped = true;
|
|
190
|
+
else if (char === quote) quote = "";
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (char === "/" && next === "/") {
|
|
194
|
+
lineComment = true;
|
|
195
|
+
index += 1;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (char === "/" && next === "*") {
|
|
199
|
+
blockComment = true;
|
|
200
|
+
index += 1;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
204
|
+
quote = char;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
|
|
208
|
+
const nameStart = index + 6;
|
|
209
|
+
let nameEnd = nameStart;
|
|
210
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
|
|
211
|
+
let open = nameEnd;
|
|
212
|
+
while (/\s/.test(source[open] ?? "")) open += 1;
|
|
213
|
+
if (nameEnd === nameStart || source[open] !== "(") continue;
|
|
214
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
215
|
+
index = open;
|
|
216
|
+
}
|
|
217
|
+
return calls;
|
|
218
|
+
}
|
|
122
219
|
function toolEnvelope(entry) {
|
|
123
220
|
const value = argumentValue(entry.arguments);
|
|
124
|
-
const source = typeof value === "string" ? value : "";
|
|
125
|
-
const
|
|
221
|
+
const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
|
|
222
|
+
const calls = source ? toolCalls(source) : [];
|
|
223
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
126
224
|
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
127
|
-
return { args: record(value), source, tools, name };
|
|
225
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
|
|
128
226
|
}
|
|
129
227
|
function patchPath(source) {
|
|
130
|
-
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]
|
|
228
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
|
|
131
229
|
}
|
|
132
230
|
function explicitNumber(sources, keys) {
|
|
133
231
|
for (const source of sources) {
|
|
@@ -177,6 +275,35 @@ function editPreview(args, resultText, source) {
|
|
|
177
275
|
if (patch) return patch;
|
|
178
276
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
179
277
|
}
|
|
278
|
+
function verificationCommand(command) {
|
|
279
|
+
let shell = "";
|
|
280
|
+
let quote = "";
|
|
281
|
+
let escaped = false;
|
|
282
|
+
for (const char of command) {
|
|
283
|
+
if (escaped) {
|
|
284
|
+
escaped = false;
|
|
285
|
+
shell += quote ? " " : char;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (char === "\\") {
|
|
289
|
+
escaped = true;
|
|
290
|
+
shell += quote ? " " : char;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (quote) {
|
|
294
|
+
if (char === quote) quote = "";
|
|
295
|
+
shell += " ";
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
299
|
+
quote = char;
|
|
300
|
+
shell += " ";
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
shell += char;
|
|
304
|
+
}
|
|
305
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
306
|
+
}
|
|
180
307
|
function classifyTool(name, command) {
|
|
181
308
|
const normalized = name.toLocaleLowerCase();
|
|
182
309
|
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
@@ -187,7 +314,7 @@ function classifyTool(name, command) {
|
|
|
187
314
|
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
188
315
|
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
189
316
|
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
190
|
-
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return
|
|
317
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
191
318
|
return "other";
|
|
192
319
|
}
|
|
193
320
|
function toolAction(status, category, name, tools) {
|
|
@@ -212,12 +339,12 @@ function toolAction(status, category, name, tools) {
|
|
|
212
339
|
function createToolPresentation(entry) {
|
|
213
340
|
const envelope = toolEnvelope(entry);
|
|
214
341
|
const args = envelope.args;
|
|
215
|
-
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.
|
|
342
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
216
343
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
217
|
-
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.
|
|
218
|
-
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.
|
|
219
|
-
const url = firstString(args, ["url"]) || sourceString(envelope.
|
|
220
|
-
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.
|
|
344
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
345
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
346
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
347
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "prompt"]);
|
|
221
348
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
222
349
|
const items = planItems(args);
|
|
223
350
|
const taskId = firstString(args, ["taskId", "task_id"]);
|
package/messenger.mjs
CHANGED
|
@@ -113,18 +113,116 @@ function decodedLiteral(value) {
|
|
|
113
113
|
function sourceString(source, keys) {
|
|
114
114
|
if (!source) return "";
|
|
115
115
|
const names = keys.join("|");
|
|
116
|
-
const match = new RegExp(
|
|
116
|
+
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
117
117
|
return decodedLiteral(match?.[1]);
|
|
118
118
|
}
|
|
119
|
+
function callArgumentSource(source, open) {
|
|
120
|
+
let depth = 1;
|
|
121
|
+
let quote = "";
|
|
122
|
+
let escaped = false;
|
|
123
|
+
let lineComment = false;
|
|
124
|
+
let blockComment = false;
|
|
125
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
126
|
+
const char = source[index];
|
|
127
|
+
const next = source[index + 1];
|
|
128
|
+
if (lineComment) {
|
|
129
|
+
if (char === "\n") lineComment = false;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (blockComment) {
|
|
133
|
+
if (char === "*" && next === "/") {
|
|
134
|
+
blockComment = false;
|
|
135
|
+
index += 1;
|
|
136
|
+
}
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (quote) {
|
|
140
|
+
if (escaped) escaped = false;
|
|
141
|
+
else if (char === "\\") escaped = true;
|
|
142
|
+
else if (char === quote) quote = "";
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (char === "/" && next === "/") {
|
|
146
|
+
lineComment = true;
|
|
147
|
+
index += 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (char === "/" && next === "*") {
|
|
151
|
+
blockComment = true;
|
|
152
|
+
index += 1;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
156
|
+
quote = char;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (char === "(") depth += 1;
|
|
160
|
+
else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
161
|
+
}
|
|
162
|
+
return source.slice(open + 1);
|
|
163
|
+
}
|
|
164
|
+
function toolCalls(source) {
|
|
165
|
+
const calls = [];
|
|
166
|
+
let quote = "";
|
|
167
|
+
let escaped = false;
|
|
168
|
+
let lineComment = false;
|
|
169
|
+
let blockComment = false;
|
|
170
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
171
|
+
const char = source[index];
|
|
172
|
+
const next = source[index + 1];
|
|
173
|
+
if (lineComment) {
|
|
174
|
+
if (char === "\n") lineComment = false;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (blockComment) {
|
|
178
|
+
if (char === "*" && next === "/") {
|
|
179
|
+
blockComment = false;
|
|
180
|
+
index += 1;
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (quote) {
|
|
185
|
+
if (escaped) escaped = false;
|
|
186
|
+
else if (char === "\\") escaped = true;
|
|
187
|
+
else if (char === quote) quote = "";
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (char === "/" && next === "/") {
|
|
191
|
+
lineComment = true;
|
|
192
|
+
index += 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (char === "/" && next === "*") {
|
|
196
|
+
blockComment = true;
|
|
197
|
+
index += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
201
|
+
quote = char;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
|
|
205
|
+
const nameStart = index + 6;
|
|
206
|
+
let nameEnd = nameStart;
|
|
207
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
|
|
208
|
+
let open = nameEnd;
|
|
209
|
+
while (/\s/.test(source[open] ?? "")) open += 1;
|
|
210
|
+
if (nameEnd === nameStart || source[open] !== "(") continue;
|
|
211
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
212
|
+
index = open;
|
|
213
|
+
}
|
|
214
|
+
return calls;
|
|
215
|
+
}
|
|
119
216
|
function toolEnvelope(entry) {
|
|
120
217
|
const value = argumentValue(entry.arguments);
|
|
121
|
-
const source = typeof value === "string" ? value : "";
|
|
122
|
-
const
|
|
218
|
+
const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
|
|
219
|
+
const calls = source ? toolCalls(source) : [];
|
|
220
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
123
221
|
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
124
|
-
return { args: record(value), source, tools, name };
|
|
222
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
|
|
125
223
|
}
|
|
126
224
|
function patchPath(source) {
|
|
127
|
-
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]
|
|
225
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
|
|
128
226
|
}
|
|
129
227
|
function explicitNumber(sources, keys) {
|
|
130
228
|
for (const source of sources) {
|
|
@@ -174,6 +272,35 @@ function editPreview(args, resultText, source) {
|
|
|
174
272
|
if (patch) return patch;
|
|
175
273
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
176
274
|
}
|
|
275
|
+
function verificationCommand(command) {
|
|
276
|
+
let shell = "";
|
|
277
|
+
let quote = "";
|
|
278
|
+
let escaped = false;
|
|
279
|
+
for (const char of command) {
|
|
280
|
+
if (escaped) {
|
|
281
|
+
escaped = false;
|
|
282
|
+
shell += quote ? " " : char;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (char === "\\") {
|
|
286
|
+
escaped = true;
|
|
287
|
+
shell += quote ? " " : char;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (quote) {
|
|
291
|
+
if (char === quote) quote = "";
|
|
292
|
+
shell += " ";
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
296
|
+
quote = char;
|
|
297
|
+
shell += " ";
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
shell += char;
|
|
301
|
+
}
|
|
302
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
303
|
+
}
|
|
177
304
|
function classifyTool(name, command) {
|
|
178
305
|
const normalized = name.toLocaleLowerCase();
|
|
179
306
|
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
@@ -184,7 +311,7 @@ function classifyTool(name, command) {
|
|
|
184
311
|
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
185
312
|
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
186
313
|
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
187
|
-
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return
|
|
314
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
188
315
|
return "other";
|
|
189
316
|
}
|
|
190
317
|
function toolAction(status, category, name, tools) {
|
|
@@ -209,12 +336,12 @@ function toolAction(status, category, name, tools) {
|
|
|
209
336
|
function createToolPresentation(entry) {
|
|
210
337
|
const envelope = toolEnvelope(entry);
|
|
211
338
|
const args = envelope.args;
|
|
212
|
-
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.
|
|
339
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
213
340
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
214
|
-
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.
|
|
215
|
-
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.
|
|
216
|
-
const url = firstString(args, ["url"]) || sourceString(envelope.
|
|
217
|
-
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.
|
|
341
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
342
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
343
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
344
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "prompt"]);
|
|
218
345
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
219
346
|
const items = planItems(args);
|
|
220
347
|
const taskId = firstString(args, ["taskId", "task_id"]);
|