@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 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(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
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 tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
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]+)/.exec(source)?.[1]?.trim() ?? "";
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 /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
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.source, ["command", "cmd"]);
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.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
215
- const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
216
- const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
217
- const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
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(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
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 tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
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]+)/.exec(source)?.[1]?.trim() ?? "";
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 /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
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.source, ["command", "cmd"]);
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.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
201
- const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
202
- const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
203
- const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
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(`\\b(?:${names})\\s*:\\s*(\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
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
- const source = typeof value === 'string' ? value : '';
137
- const tools = source
138
- ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8)
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]+)/.exec(source)?.[1]?.trim() ?? '';
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 /\b(test|typecheck|lint|build)\b/i.test(command) ? 'test' : 'command';
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.source, ['command', 'cmd']);
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.source, ['file_path', 'target_file', 'target_directory', 'path']) || patchPath(envelope.source);
241
- const query = firstString(args, ['query', 'pattern']) || sourceString(envelope.source, ['query', 'pattern', 'q']);
242
- const url = firstString(args, ['url']) || sourceString(envelope.source, ['url', 'ref_id']);
243
- const subject = firstString(args, ['subject', 'description', 'summary', 'task', 'prompt']) || sourceString(envelope.source, ['subject', 'description', 'summary', 'task', 'prompt']);
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(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
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 tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
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]+)/.exec(source)?.[1]?.trim() ?? "";
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 /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
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.source, ["command", "cmd"]);
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.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
218
- const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
219
- const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
220
- const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
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(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
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 tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
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]+)/.exec(source)?.[1]?.trim() ?? "";
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 /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
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.source, ["command", "cmd"]);
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.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
215
- const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
216
- const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
217
- const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter-ai-dev/supercode-ui",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "description": "Composable default UI kit for Supercode-powered coding-agent experiences",
6
6
  "exports": {