@lvce-editor/chat-view 6.9.0 → 6.10.0
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/chatViewWorkerMain.js +64 -267
- package/package.json +1 -1
|
@@ -1269,15 +1269,9 @@ const sendMessagePortToChatNetworkWorker = async port => {
|
|
|
1269
1269
|
const sendMessagePortToChatToolWorker = async port => {
|
|
1270
1270
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatToolWorker', port, 'HandleMessagePort.handleMessagePort');
|
|
1271
1271
|
};
|
|
1272
|
-
const writeFile = async (uri, text) => {
|
|
1273
|
-
await invoke$1('FileSystem.writeFile', uri, text);
|
|
1274
|
-
};
|
|
1275
1272
|
const activateByEvent$1 = (event, assetDir, platform) => {
|
|
1276
1273
|
return invoke$1('ExtensionHostManagement.activateByEvent', event, assetDir, platform);
|
|
1277
1274
|
};
|
|
1278
|
-
const getWorkspacePath = () => {
|
|
1279
|
-
return invoke$1('Workspace.getPath');
|
|
1280
|
-
};
|
|
1281
1275
|
const getPreference = async key => {
|
|
1282
1276
|
return await invoke$1('Preferences.get', key);
|
|
1283
1277
|
};
|
|
@@ -3349,240 +3343,6 @@ const getTools = async () => {
|
|
|
3349
3343
|
return invoke$3('ChatTool.getTools');
|
|
3350
3344
|
};
|
|
3351
3345
|
|
|
3352
|
-
const executeAskQuestionTool = args => {
|
|
3353
|
-
const normalized = args && typeof args === 'object' ? args : {};
|
|
3354
|
-
const question = Reflect.get(normalized, 'question');
|
|
3355
|
-
const answers = Reflect.get(normalized, 'answers');
|
|
3356
|
-
return JSON.stringify({
|
|
3357
|
-
answers: Array.isArray(answers) ? answers.filter(answer => typeof answer === 'string') : [],
|
|
3358
|
-
ok: true,
|
|
3359
|
-
question: typeof question === 'string' ? question : ''
|
|
3360
|
-
});
|
|
3361
|
-
};
|
|
3362
|
-
|
|
3363
|
-
const getToolErrorPayload = error => {
|
|
3364
|
-
const rawStack = error && typeof error === 'object' ? Reflect.get(error, 'stack') : undefined;
|
|
3365
|
-
return {
|
|
3366
|
-
error: String(error),
|
|
3367
|
-
...(typeof rawStack === 'string' && rawStack.trim() ? {
|
|
3368
|
-
errorStack: rawStack,
|
|
3369
|
-
stack: rawStack
|
|
3370
|
-
} : {})
|
|
3371
|
-
};
|
|
3372
|
-
};
|
|
3373
|
-
|
|
3374
|
-
const executeGetWorkspaceUriTool = async (_args, _options) => {
|
|
3375
|
-
try {
|
|
3376
|
-
const workspaceUri = await getWorkspacePath();
|
|
3377
|
-
return JSON.stringify({
|
|
3378
|
-
workspaceUri
|
|
3379
|
-
});
|
|
3380
|
-
} catch (error) {
|
|
3381
|
-
return JSON.stringify(getToolErrorPayload(error));
|
|
3382
|
-
}
|
|
3383
|
-
};
|
|
3384
|
-
|
|
3385
|
-
const isAbsoluteUri$1 = value => {
|
|
3386
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3387
|
-
};
|
|
3388
|
-
const executeListFilesTool = async (args, _options) => {
|
|
3389
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3390
|
-
if (!uri || !isAbsoluteUri$1(uri)) {
|
|
3391
|
-
return JSON.stringify({
|
|
3392
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3393
|
-
});
|
|
3394
|
-
}
|
|
3395
|
-
try {
|
|
3396
|
-
const entries = await invoke$1('FileSystem.readDirWithFileTypes', uri);
|
|
3397
|
-
return JSON.stringify({
|
|
3398
|
-
entries,
|
|
3399
|
-
uri
|
|
3400
|
-
});
|
|
3401
|
-
} catch (error) {
|
|
3402
|
-
return JSON.stringify({
|
|
3403
|
-
...getToolErrorPayload(error),
|
|
3404
|
-
uri
|
|
3405
|
-
});
|
|
3406
|
-
}
|
|
3407
|
-
};
|
|
3408
|
-
|
|
3409
|
-
const isPathTraversalAttempt = path => {
|
|
3410
|
-
if (!path) {
|
|
3411
|
-
return false;
|
|
3412
|
-
}
|
|
3413
|
-
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
3414
|
-
return true;
|
|
3415
|
-
}
|
|
3416
|
-
if (path.startsWith('file://')) {
|
|
3417
|
-
return true;
|
|
3418
|
-
}
|
|
3419
|
-
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
3420
|
-
return true;
|
|
3421
|
-
}
|
|
3422
|
-
const segments = path.split(/[\\/]/);
|
|
3423
|
-
return segments.includes('..');
|
|
3424
|
-
};
|
|
3425
|
-
|
|
3426
|
-
const normalizeRelativePath = path => {
|
|
3427
|
-
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
3428
|
-
if (segments.length === 0) {
|
|
3429
|
-
return '.';
|
|
3430
|
-
}
|
|
3431
|
-
return segments.join('/');
|
|
3432
|
-
};
|
|
3433
|
-
|
|
3434
|
-
const isAbsoluteUri = value => {
|
|
3435
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3436
|
-
};
|
|
3437
|
-
const executeReadFileTool = async (args, _options) => {
|
|
3438
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3439
|
-
if (uri) {
|
|
3440
|
-
if (!isAbsoluteUri(uri)) {
|
|
3441
|
-
return JSON.stringify({
|
|
3442
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3443
|
-
});
|
|
3444
|
-
}
|
|
3445
|
-
try {
|
|
3446
|
-
const content = await readFile(uri);
|
|
3447
|
-
return JSON.stringify({
|
|
3448
|
-
content,
|
|
3449
|
-
uri
|
|
3450
|
-
});
|
|
3451
|
-
} catch (error) {
|
|
3452
|
-
return JSON.stringify({
|
|
3453
|
-
...getToolErrorPayload(error),
|
|
3454
|
-
uri
|
|
3455
|
-
});
|
|
3456
|
-
}
|
|
3457
|
-
}
|
|
3458
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3459
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3460
|
-
return JSON.stringify({
|
|
3461
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3462
|
-
});
|
|
3463
|
-
}
|
|
3464
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3465
|
-
try {
|
|
3466
|
-
const content = await readFile(normalizedPath);
|
|
3467
|
-
return JSON.stringify({
|
|
3468
|
-
content,
|
|
3469
|
-
path: normalizedPath
|
|
3470
|
-
});
|
|
3471
|
-
} catch (error) {
|
|
3472
|
-
return JSON.stringify({
|
|
3473
|
-
...getToolErrorPayload(error),
|
|
3474
|
-
path: normalizedPath
|
|
3475
|
-
});
|
|
3476
|
-
}
|
|
3477
|
-
};
|
|
3478
|
-
|
|
3479
|
-
const maxPayloadLength = 40_000;
|
|
3480
|
-
const executeRenderHtmlTool = async (args, _options) => {
|
|
3481
|
-
const html = typeof args.html === 'string' ? args.html : '';
|
|
3482
|
-
const css = typeof args.css === 'string' ? args.css : '';
|
|
3483
|
-
const title = typeof args.title === 'string' ? args.title : '';
|
|
3484
|
-
if (!html) {
|
|
3485
|
-
return JSON.stringify({
|
|
3486
|
-
error: 'Missing required argument: html'
|
|
3487
|
-
});
|
|
3488
|
-
}
|
|
3489
|
-
if (html.length > maxPayloadLength || css.length > maxPayloadLength) {
|
|
3490
|
-
return JSON.stringify({
|
|
3491
|
-
error: 'Payload too large: keep html/css under 40,000 characters each.'
|
|
3492
|
-
});
|
|
3493
|
-
}
|
|
3494
|
-
return JSON.stringify({
|
|
3495
|
-
css,
|
|
3496
|
-
html,
|
|
3497
|
-
ok: true,
|
|
3498
|
-
title
|
|
3499
|
-
});
|
|
3500
|
-
};
|
|
3501
|
-
|
|
3502
|
-
const toLines = value => {
|
|
3503
|
-
if (!value) {
|
|
3504
|
-
return [];
|
|
3505
|
-
}
|
|
3506
|
-
const split = value.split('\n').map(line => line.endsWith('\r') ? line.slice(0, -1) : line);
|
|
3507
|
-
if (split.length > 0 && split.at(-1) === '') {
|
|
3508
|
-
split.pop();
|
|
3509
|
-
}
|
|
3510
|
-
return split;
|
|
3511
|
-
};
|
|
3512
|
-
const getLineCounts = (before, after) => {
|
|
3513
|
-
const beforeLines = toLines(before);
|
|
3514
|
-
const afterLines = toLines(after);
|
|
3515
|
-
let start = 0;
|
|
3516
|
-
while (start < beforeLines.length && start < afterLines.length && beforeLines[start] === afterLines[start]) {
|
|
3517
|
-
start++;
|
|
3518
|
-
}
|
|
3519
|
-
let beforeEnd = beforeLines.length - 1;
|
|
3520
|
-
let afterEnd = afterLines.length - 1;
|
|
3521
|
-
while (beforeEnd >= start && afterEnd >= start && beforeLines[beforeEnd] === afterLines[afterEnd]) {
|
|
3522
|
-
beforeEnd--;
|
|
3523
|
-
afterEnd--;
|
|
3524
|
-
}
|
|
3525
|
-
return {
|
|
3526
|
-
linesAdded: Math.max(0, afterEnd - start + 1),
|
|
3527
|
-
linesDeleted: Math.max(0, beforeEnd - start + 1)
|
|
3528
|
-
};
|
|
3529
|
-
};
|
|
3530
|
-
const isFileNotFoundError = error => {
|
|
3531
|
-
const message = String(error).toLowerCase();
|
|
3532
|
-
return message.includes('enoent') || message.includes('not found');
|
|
3533
|
-
};
|
|
3534
|
-
const executeWriteFileTool = async (args, _options) => {
|
|
3535
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3536
|
-
const content = typeof args.content === 'string' ? args.content : '';
|
|
3537
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3538
|
-
return JSON.stringify({
|
|
3539
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3540
|
-
});
|
|
3541
|
-
}
|
|
3542
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3543
|
-
try {
|
|
3544
|
-
let previousContent = '';
|
|
3545
|
-
try {
|
|
3546
|
-
previousContent = await readFile(normalizedPath);
|
|
3547
|
-
} catch (error) {
|
|
3548
|
-
if (!isFileNotFoundError(error)) {
|
|
3549
|
-
throw error;
|
|
3550
|
-
}
|
|
3551
|
-
}
|
|
3552
|
-
await writeFile(normalizedPath, content);
|
|
3553
|
-
const {
|
|
3554
|
-
linesAdded,
|
|
3555
|
-
linesDeleted
|
|
3556
|
-
} = getLineCounts(previousContent, content);
|
|
3557
|
-
return JSON.stringify({
|
|
3558
|
-
linesAdded,
|
|
3559
|
-
linesDeleted,
|
|
3560
|
-
ok: true,
|
|
3561
|
-
path: normalizedPath
|
|
3562
|
-
});
|
|
3563
|
-
} catch (error) {
|
|
3564
|
-
return JSON.stringify({
|
|
3565
|
-
...getToolErrorPayload(error),
|
|
3566
|
-
path: normalizedPath
|
|
3567
|
-
});
|
|
3568
|
-
}
|
|
3569
|
-
};
|
|
3570
|
-
|
|
3571
|
-
const parseToolArguments = rawArguments => {
|
|
3572
|
-
if (typeof rawArguments !== 'string') {
|
|
3573
|
-
return {};
|
|
3574
|
-
}
|
|
3575
|
-
try {
|
|
3576
|
-
const parsed = JSON.parse(rawArguments);
|
|
3577
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
3578
|
-
return {};
|
|
3579
|
-
}
|
|
3580
|
-
return parsed;
|
|
3581
|
-
} catch {
|
|
3582
|
-
return {};
|
|
3583
|
-
}
|
|
3584
|
-
};
|
|
3585
|
-
|
|
3586
3346
|
const stringifyToolOutput = output => {
|
|
3587
3347
|
if (typeof output === 'string') {
|
|
3588
3348
|
return output;
|
|
@@ -3590,35 +3350,14 @@ const stringifyToolOutput = output => {
|
|
|
3590
3350
|
return JSON.stringify(output) ?? 'null';
|
|
3591
3351
|
};
|
|
3592
3352
|
const executeChatTool = async (name, rawArguments, options) => {
|
|
3593
|
-
if (options.useChatToolWorker) {
|
|
3594
|
-
|
|
3595
|
-
assetDir: options.assetDir,
|
|
3596
|
-
platform: options.platform
|
|
3597
|
-
});
|
|
3598
|
-
return stringifyToolOutput(workerOutput);
|
|
3599
|
-
}
|
|
3600
|
-
const args = parseToolArguments(rawArguments);
|
|
3601
|
-
if (name === 'read_file') {
|
|
3602
|
-
return executeReadFileTool(args);
|
|
3603
|
-
}
|
|
3604
|
-
if (name === 'write_file') {
|
|
3605
|
-
return executeWriteFileTool(args);
|
|
3606
|
-
}
|
|
3607
|
-
if (name === 'list_files') {
|
|
3608
|
-
return executeListFilesTool(args);
|
|
3609
|
-
}
|
|
3610
|
-
if (name === 'getWorkspaceUri') {
|
|
3611
|
-
return executeGetWorkspaceUriTool();
|
|
3353
|
+
if (!options.useChatToolWorker) {
|
|
3354
|
+
throw new Error('Chat tools must be executed in a web worker environment. Please set useChatToolWorker to true in the options.');
|
|
3612
3355
|
}
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
if (name === 'ask_question') {
|
|
3617
|
-
return executeAskQuestionTool(args);
|
|
3618
|
-
}
|
|
3619
|
-
return JSON.stringify({
|
|
3620
|
-
error: `Unknown tool: ${name}`
|
|
3356
|
+
const workerOutput = await execute(name, rawArguments, {
|
|
3357
|
+
assetDir: options.assetDir,
|
|
3358
|
+
platform: options.platform
|
|
3621
3359
|
});
|
|
3360
|
+
return stringifyToolOutput(workerOutput);
|
|
3622
3361
|
};
|
|
3623
3362
|
|
|
3624
3363
|
const getReadFileTool = () => {
|
|
@@ -7281,6 +7020,31 @@ Assistant: ${assistantText}`;
|
|
|
7281
7020
|
return title && !isDefaultSessionTitle(title) ? title : '';
|
|
7282
7021
|
};
|
|
7283
7022
|
|
|
7023
|
+
const isPathTraversalAttempt = path => {
|
|
7024
|
+
if (!path) {
|
|
7025
|
+
return false;
|
|
7026
|
+
}
|
|
7027
|
+
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
7028
|
+
return true;
|
|
7029
|
+
}
|
|
7030
|
+
if (path.startsWith('file://')) {
|
|
7031
|
+
return true;
|
|
7032
|
+
}
|
|
7033
|
+
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
7034
|
+
return true;
|
|
7035
|
+
}
|
|
7036
|
+
const segments = path.split(/[\\/]/);
|
|
7037
|
+
return segments.includes('..');
|
|
7038
|
+
};
|
|
7039
|
+
|
|
7040
|
+
const normalizeRelativePath = path => {
|
|
7041
|
+
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
7042
|
+
if (segments.length === 0) {
|
|
7043
|
+
return '.';
|
|
7044
|
+
}
|
|
7045
|
+
return segments.join('/');
|
|
7046
|
+
};
|
|
7047
|
+
|
|
7284
7048
|
const mentionRegex = /(^|\s)@([^\s]+)/g;
|
|
7285
7049
|
const maxMentionCount = 5;
|
|
7286
7050
|
const parseMentionedPaths = value => {
|
|
@@ -10673,6 +10437,33 @@ const getToolCallWriteFileVirtualDom = toolCall => {
|
|
|
10673
10437
|
type: Span
|
|
10674
10438
|
}, text(` -${linesDeleted}`), ...(statusLabel ? [text(statusLabel)] : [])];
|
|
10675
10439
|
};
|
|
10440
|
+
const getToolCallEditFileVirtualDom = toolCall => {
|
|
10441
|
+
const target = getReadFileTarget(toolCall.arguments);
|
|
10442
|
+
if (!target) {
|
|
10443
|
+
return [];
|
|
10444
|
+
}
|
|
10445
|
+
const fileName = getFileNameFromUri(target.title);
|
|
10446
|
+
const fileNameClickableProps = target.clickableUri ? {
|
|
10447
|
+
'data-uri': target.clickableUri,
|
|
10448
|
+
onClick: HandleClickReadFile
|
|
10449
|
+
} : {};
|
|
10450
|
+
return [{
|
|
10451
|
+
childCount: 3,
|
|
10452
|
+
className: ChatOrderedListItem,
|
|
10453
|
+
title: target.title,
|
|
10454
|
+
type: Li
|
|
10455
|
+
}, {
|
|
10456
|
+
childCount: 0,
|
|
10457
|
+
className: FileIcon,
|
|
10458
|
+
type: Div
|
|
10459
|
+
}, text('edit_file '), {
|
|
10460
|
+
childCount: 1,
|
|
10461
|
+
className: ChatToolCallReadFileLink,
|
|
10462
|
+
title: target.clickableUri,
|
|
10463
|
+
...fileNameClickableProps,
|
|
10464
|
+
type: Span
|
|
10465
|
+
}, text(fileName)];
|
|
10466
|
+
};
|
|
10676
10467
|
const getToolCallDom = toolCall => {
|
|
10677
10468
|
if (toolCall.name === 'getWorkspaceUri') {
|
|
10678
10469
|
const virtualDom = getToolCallGetWorkspaceUriVirtualDom(toolCall);
|
|
@@ -10692,6 +10483,12 @@ const getToolCallDom = toolCall => {
|
|
|
10692
10483
|
return virtualDom;
|
|
10693
10484
|
}
|
|
10694
10485
|
}
|
|
10486
|
+
if (toolCall.name === 'edit_file') {
|
|
10487
|
+
const virtualDom = getToolCallEditFileVirtualDom(toolCall);
|
|
10488
|
+
if (virtualDom.length > 0) {
|
|
10489
|
+
return virtualDom;
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10695
10492
|
if (toolCall.name === 'render_html') {
|
|
10696
10493
|
const virtualDom = getToolCallRenderHtmlVirtualDom(toolCall);
|
|
10697
10494
|
if (virtualDom.length > 0) {
|