Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/channels/base/src/AcpBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface AcpBridgeOptions {
export interface AvailableCommand {
name: string;
description: string;
input?: { hint: string } | null;
}

export interface ToolCallEvent {
Expand Down
31 changes: 31 additions & 0 deletions packages/cli/src/acp-integration/session/Session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ describe('Session', () => {
{
name: 'init',
description: 'Initialize project context',
kind: 'built-in',
argumentHint: '[path]',
},
]);
Expand All @@ -247,11 +248,41 @@ describe('Session', () => {
});
});

it('sets input for built-in commands with subCommands', async () => {
getAvailableCommandsSpy.mockResolvedValueOnce([
{
name: 'export',
description: 'Export conversation history',
kind: 'built-in',
subCommands: [
{ name: 'md', description: 'Export as markdown', kind: 'built-in' },
],
},
]);

await session.sendAvailableCommandsUpdate();

expect(mockClient.sessionUpdate).toHaveBeenCalledWith({
sessionId: 'test-session-id',
update: {
sessionUpdate: 'available_commands_update',
availableCommands: [
{
name: 'export',
description: 'Export conversation history',
input: { hint: '' },
},
],
},
});
});

it('attaches available skills to available_commands_update metadata', async () => {
getAvailableCommandsSpy.mockResolvedValueOnce([
{
name: 'init',
description: 'Initialize project context',
kind: 'built-in',
},
]);
mockConfig.getSkillManager = vi.fn().mockReturnValue({
Expand Down
27 changes: 21 additions & 6 deletions packages/cli/src/acp-integration/session/Session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {
type NonInteractiveSlashCommandResult,
} from '../../nonInteractiveCliCommands.js';
import { isSlashCommand } from '../../ui/utils/commandUtils.js';
import { CommandKind } from '../../ui/commands/types.js';
import { parseAcpModelOption } from '../../utils/acpModelUtils.js';
import { classifyApiError } from '../../ui/hooks/useGeminiStream.js';

Expand Down Expand Up @@ -976,14 +977,28 @@ export class Session implements SessionContext {
'acp',
);

// Convert SlashCommand[] to AvailableCommand[] format for ACP protocol
const availableCommands: AvailableCommand[] = slashCommands.map(
(cmd) => ({
// Convert SlashCommand[] to AvailableCommand[] format for ACP protocol.
// Commands that accept arguments get input: { hint } so the client can
// let users type arguments before submitting. Commands with no argument
// support get input: null so the client auto-submits them on selection.
//
// A command is considered to accept arguments when any of:
// - it is not a BUILT_IN command (skills, file commands, etc.)
// - it has a completion function
// - it declares an argumentHint
// - it has subCommands
const availableCommands: AvailableCommand[] = slashCommands.map((cmd) => {
const acceptsInput =
cmd.kind !== CommandKind.BUILT_IN ||
cmd.completion != null ||
cmd.argumentHint != null ||
(cmd.subCommands != null && cmd.subCommands.length > 0);
return {
name: cmd.name,
description: cmd.description,
input: cmd.argumentHint ? { hint: cmd.argumentHint } : null,
}),
);
input: acceptsInput ? { hint: cmd.argumentHint ?? '' } : null,
};
});

let availableSkills: string[] | undefined;
try {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/ui/commands/bugCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const bugCommand: SlashCommand = {
return t('submit a bug report');
},
kind: CommandKind.BUILT_IN,
argumentHint: '<description>',
supportedModes: ['interactive', 'non_interactive', 'acp'] as const,
action: async (context: CommandContext, args?: string): Promise<void> => {
const bugDescription = (args || '').trim();
Expand Down
99 changes: 96 additions & 3 deletions packages/vscode-ide-companion/src/webview/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ const secondarySkillItem: CompletionItem = {
value: 'skills code-review',
};

const commitCommandItem: CompletionItem = {
id: 'commit',
label: '/commit',
type: 'command',
value: 'commit',
};

const clearCommandItem: CompletionItem = {
id: 'clear',
label: '/clear',
type: 'command',
value: 'clear',
};

vi.mock('./hooks/useVSCode.js', () => ({
useVSCode: () => ({
postMessage: mockPostMessage,
Expand Down Expand Up @@ -101,7 +115,11 @@ vi.mock('./hooks/useWebViewMessages.js', async () => {
}: {
setIsAuthenticated: (value: boolean) => void;
setAvailableCommands: (
value: Array<{ name: string; description?: string }>,
value: Array<{
name: string;
description: string;
input?: { hint: string } | null;
}>,
) => void;
setAvailableSkills: (value: string[]) => void;
}) => {
Expand All @@ -114,7 +132,21 @@ vi.mock('./hooks/useWebViewMessages.js', async () => {
initializedRef.current = true;
setIsAuthenticated(true);
setAvailableCommands([
{ name: 'skills', description: 'List available skills' },
{
name: 'skills',
description: 'List available skills',
input: null,
},
{
name: 'commit',
description: 'Commit current changes',
input: { hint: '' },
},
{
name: 'clear',
description: 'Clear the chat',
input: null,
},
]);
setAvailableSkills(['code-review']);
}, [setAvailableCommands, setAvailableSkills, setIsAuthenticated]);
Expand Down Expand Up @@ -143,7 +175,12 @@ vi.mock('./hooks/useCompletionTrigger.js', () => ({
isOpen: true,
triggerChar: '/',
query: 'skills ',
items: [slashSkillsItem, secondarySkillItem],
items: [
slashSkillsItem,
secondarySkillItem,
commitCommandItem,
clearCommandItem,
],
closeCompletion: mockCloseCompletion,
openCompletion: mockOpenCompletion,
refreshCompletion: vi.fn(),
Expand Down Expand Up @@ -184,6 +221,7 @@ vi.mock('@qwen-code/webui', () => ({
EmptyState: () => null,
ChatHeader: () => null,
SessionSelector: () => null,
stripZeroWidthSpaces: (text: string) => text.replace(/\u200B/g, ''),
}));

vi.mock('./components/layout/InputForm.js', () => ({
Expand Down Expand Up @@ -217,6 +255,15 @@ vi.mock('./components/layout/InputForm.js', () => ({
<button onClick={() => onCompletionFill?.(secondarySkillItem)}>
select-skill-tab
</button>
<button onClick={() => onCompletionSelect(commitCommandItem)}>
select-commit-enter
</button>
<button onClick={() => onCompletionSelect(clearCommandItem)}>
select-clear-enter
</button>
<button onClick={() => onCompletionFill?.(clearCommandItem)}>
select-clear-tab
</button>
</div>
),
}));
Expand Down Expand Up @@ -410,4 +457,50 @@ describe('App /skills secondary picker', () => {
'/skills code-review ',
);
});

it('fills slash commands that declare input when pressing Enter', async () => {
const rendered = renderApp();
root = rendered.root;
container = rendered.container;

await act(async () => {});
setInputSelection(rendered.container, '/');

clickButton(rendered.container, 'select-commit-enter');

expect(mockPostMessage).not.toHaveBeenCalled();
expect(getRenderedInputText(rendered.container)).toBe('/commit ');
expect(mockCloseCompletion).toHaveBeenCalled();
});

it('auto-submits slash commands without input when pressing Enter', async () => {
const rendered = renderApp();
root = rendered.root;
container = rendered.container;

await act(async () => {});
setInputSelection(rendered.container, '/');

clickButton(rendered.container, 'select-clear-enter');

expect(mockPostMessage).toHaveBeenCalledWith({
type: 'sendMessage',
data: { text: '/clear' },
});
expect(mockCloseCompletion).toHaveBeenCalled();
});

it('fills slash commands without input when pressing Tab', async () => {
const rendered = renderApp();
root = rendered.root;
container = rendered.container;

await act(async () => {});
setInputSelection(rendered.container, '/');

clickButton(rendered.container, 'select-clear-tab');

expect(mockPostMessage).not.toHaveBeenCalled();
expect(getRenderedInputText(rendered.container)).toBe('/clear ');
});
});
80 changes: 44 additions & 36 deletions packages/vscode-ide-companion/src/webview/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
useMessageSubmit,
} from './hooks/useMessageSubmit.js';
import type { PermissionOption, PermissionToolCall } from '@qwen-code/webui';
import { stripZeroWidthSpaces } from '@qwen-code/webui';
import type { TextMessage } from './hooks/message/useMessageHandling.js';
import type { ToolCallData } from './components/messages/toolcalls/ToolCall.js';
import { ToolCall } from './components/messages/toolcalls/ToolCall.js';
Expand Down Expand Up @@ -176,7 +177,7 @@
}
// No wrapper div — message components render directly as children
// of the scroll container, preserving the original CSS layout.
if (child == null) return null;

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected '===' and instead saw '=='

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 180 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected '===' and instead saw '=='
mapping.push(index);
return <React.Fragment key={`msg-${index}`}>{child}</React.Fragment>;
});
Expand Down Expand Up @@ -212,7 +213,7 @@
while (directChild && directChild.parentElement !== container) {
directChild = directChild.parentElement;
}
if (!directChild) return -1;

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 216 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

// Find DOM child position among container's children
const children = container.children;
Expand Down Expand Up @@ -796,52 +797,49 @@
}
};

if (itemId === 'auth') {
clearTriggerText();
vscode.postMessage({ type: 'auth', data: {} });
closeCompletion();
return;
}

if (itemId === 'account') {
clearTriggerText();
vscode.postMessage({ type: 'getAccountInfo', data: {} });
closeCompletion();
return;
}
// Client-side commands that trigger extension actions directly
// instead of being sent to the agent as messages.
const clientActions: Record<string, () => void> = {
auth: () => vscode.postMessage({ type: 'auth', data: {} }),
account: () =>
vscode.postMessage({ type: 'getAccountInfo', data: {} }),
model: () => setShowModelSelector(true),
};

if (itemId === 'model') {
const clientAction = clientActions[itemId];
if (clientAction) {
clearTriggerText();
setShowModelSelector(true);
clientAction();
closeCompletion();
return;
}

// Handle server-provided slash commands by sending them as messages.
// Skip when fillOnly (Tab) — let the generic insertion path fill the
// command text so the user can keep typing arguments.
// Special case: /skills always uses fill behavior (Enter = Tab) to
// allow the secondary skill picker to appear.
// For server-provided slash commands, decide based on the `input`
// field: commands without input (input == null) auto-submit
// immediately; commands that accept input fall through to the generic
// insertion path so users can type arguments before submitting.
// Special case: /skills always uses fill behavior to allow the
// secondary skill picker to appear.
const serverCmd = availableCommands.find((c) => c.name === itemId);
const isSkillsCmd = shouldOpenSkillsSecondaryPicker(
item,
availableSkills,
);
if (
serverCmd &&
!fillOnly &&
!isSkillsCmd &&
!isExpandableSlashCommand(serverCmd.name)
) {
// Clear the trigger text since we're sending the command
clearTriggerText();
// Send the slash command as a user message
vscode.postMessage({
type: 'sendMessage',
data: { text: `/${serverCmd.name}` },
});
closeCompletion();
return;
if (!serverCmd.input && !fillOnly) {
clearTriggerText();
vscode.postMessage({
type: 'sendMessage',
data: { text: `/${serverCmd.name}` },
});
closeCompletion();
return;
}
// Command accepts input — fall through to fill the input box.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] Falling through here uses the generic insertion path, which reads inputElement.textContent directly. If the empty editor contains the U+200B height placeholder, filling a slash command can preserve that hidden character and produce text like \u200B/commit . shouldSendMessage strips the placeholder only for the emptiness check, but the actual sendMessage payload still uses the raw text, so downstream slash-command handling may not recognize the command.

Please normalize the text used for completion insertion, for example by stripping U+200B before computing textBeforeCursor/newText, and ensure the value passed to setInputText is placeholder-free. Be careful to adjust cursor offsets after normalization.

— gpt-5.5 via Qwen Code /review

}

// Handle secondary skill selection — send `/skills <name>` with
Expand Down Expand Up @@ -875,12 +873,16 @@
return;
}

// Current text and cursor
const text = inputElement.textContent || '';
// Current text and cursor — strip U+200B height placeholder so it
// does not contaminate the inserted completion text.
const rawText = inputElement.textContent || '';
const text = stripZeroWidthSpaces(rawText);
const range = selection.getRangeAt(0);

// Compute total text offset for contentEditable
let cursorPos = text.length;
// Compute total text offset for contentEditable. The DOM offsets
// are based on rawText (which may contain U+200B), so we compute the
// raw cursor position first and then adjust for stripped characters.
let rawCursorPos = rawText.length;
if (range.startContainer === inputElement) {
const childIndex = range.startOffset;
let offset = 0;
Expand All @@ -891,7 +893,7 @@
) {
offset += inputElement.childNodes[i].textContent?.length || 0;
}
cursorPos = offset || text.length;
rawCursorPos = offset || rawText.length;
} else if (range.startContainer.nodeType === Node.TEXT_NODE) {
const walker = document.createTreeWalker(
inputElement,
Expand All @@ -910,8 +912,14 @@
offset += node.textContent?.length || 0;
node = walker.nextNode();
}
cursorPos = found ? offset : text.length;
rawCursorPos = found ? offset : rawText.length;
}
// Adjust cursor to match the stripped text by subtracting
// zero-width characters that appeared before the cursor.
const zeroWidthBeforeCursor = (
rawText.substring(0, rawCursorPos).match(/\u200B/g) || []
).length;
const cursorPos = Math.max(0, rawCursorPos - zeroWidthBeforeCursor);

// Replace from trigger to cursor with selected value
const textBeforeCursor = text.substring(0, cursorPos);
Expand Down Expand Up @@ -1203,7 +1211,7 @@
useEffect(() => {
const handler = (event: MessageEvent) => {
const message = event.data;
if (message?.type !== 'copyCommand') return;

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1214 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

const { action } = message.data as { action: string };

Expand Down Expand Up @@ -1234,7 +1242,7 @@
msg.kind === 'image' && msg.imagePath
? `![image](${msg.imagePath})`
: (msg.content || '').trim();
if (!content) continue;

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1245 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition
if (msg.role === 'user') {
parts.push(`**User:** ${content}`);
} else if (msg.role === 'thinking') {
Expand All @@ -1247,7 +1255,7 @@
item.type === 'in-progress-tool-call'
) {
const tc = item.data as ToolCallData;
if (!shouldShowToolCall(tc.kind)) continue;

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Lint

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition

Check warning on line 1258 in packages/vscode-ide-companion/src/webview/App.tsx

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

Expected { after 'if' condition
const text = formatToolCallForCopy(tc, true);
if (text) {
parts.push(`**[Tool: ${tc.kind}]**\n\n${text}`);
Expand Down
Loading
Loading