v2.2-paseo-providers: Paseo provider stack + v2.2.1 pane-scoped chat fixes
Ship Paseo-equivalent provider snapshot, AgentComposerBar, ACP dispatch rewrite with streaming/persist, permission prompts, and agent commands. Follow-up: pane-scoped chat resolution, CoderMessageList tool timeline, WS user-delta replace, and inference orphan tool_call stripping. Archive openspec v2-2; update CHANGELOG and CURRENT. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -23,7 +23,8 @@ import { FileMentionPopover } from '@/components/FileMentionPopover';
|
||||
import { DropOverlay } from '@/components/DropOverlay';
|
||||
import { AgentPicker } from '@/components/AgentPicker';
|
||||
import { ContextBar } from '@/components/ContextBar';
|
||||
import { SkillSlashCommand } from '@/components/SkillSlashCommand';
|
||||
import { SlashCommandPicker } from '@/components/SlashCommandPicker';
|
||||
import { isSlashCommandToken, parseSlashInput, slashQuery } from '@/lib/slash-command';
|
||||
import { api } from '@/api/client';
|
||||
import type { Message } from '@/api/types';
|
||||
import { sessionEvents } from '@/hooks/sessionEvents';
|
||||
@@ -87,10 +88,8 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
// Batch 9.6: slash-command dropdown. Opens when `/` is the first char of
|
||||
// the input and stays open while the input is `/<word>` with no whitespace.
|
||||
// Disabled entirely when the caller doesn't pass onSlashCommand.
|
||||
// v1.12 CP7.5: anchorRect was a snapshot taken at open time. SkillSlashCommand
|
||||
// now reads the live textarea rect via inputRef (textareaRef below) so it can
|
||||
// recompute on visualViewport changes (iOS keyboard open/close), so the
|
||||
// anchorRect field is no longer needed in this state.
|
||||
// SlashCommandPicker reads the live textarea rect via inputRef (textareaRef below)
|
||||
// so it can recompute on visualViewport changes (iOS keyboard open/close).
|
||||
const [slashState, setSlashState] = useState<{
|
||||
query: string;
|
||||
} | null>(null);
|
||||
@@ -168,13 +167,11 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
// input parses to a known skill. Falls through to onSend for unknown
|
||||
// slash names (literal text) or when slash dispatch isn't wired.
|
||||
if (onSlashCommand && attachments.length === 0 && text.startsWith('/')) {
|
||||
const match = text.match(/^\/(\S+)\s*([\s\S]*)$/);
|
||||
if (match && skillsLookup.has(match[1]!)) {
|
||||
const skillName = match[1]!;
|
||||
const args = (match[2] ?? '').trim();
|
||||
const parsed = parseSlashInput(text);
|
||||
if (parsed && skillsLookup.has(parsed.cmdName)) {
|
||||
setBusy(true);
|
||||
try {
|
||||
await onSlashCommand(skillName, args);
|
||||
await onSlashCommand(parsed.cmdName, parsed.args);
|
||||
setValue('');
|
||||
setAttachments([]);
|
||||
setSlashState(null);
|
||||
@@ -268,8 +265,8 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
// slash-prefixed token with no whitespace (i.e. user is still typing the
|
||||
// skill name). Hand off to args mode the moment a space appears or the
|
||||
// slash leaves position 0.
|
||||
if (onSlashCommand && /^\/[^\s]*$/.test(newValue)) {
|
||||
const query = newValue.slice(1);
|
||||
if (onSlashCommand && isSlashCommandToken(newValue)) {
|
||||
const query = slashQuery(newValue);
|
||||
if (!slashState) {
|
||||
setSlashState({ query });
|
||||
} else if (slashState.query !== query) {
|
||||
@@ -496,7 +493,7 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
|
||||
function onKeyDown(e: KeyboardEvent<HTMLTextAreaElement>) {
|
||||
if (mentionState?.open) return;
|
||||
// SkillSlashCommand owns Arrow/Enter/Tab/Esc via a document listener; let
|
||||
// SlashCommandPicker owns Arrow/Enter/Tab/Esc via a document listener; let
|
||||
// it consume them so the textarea doesn't also submit on Enter.
|
||||
if (slashState) return;
|
||||
// IME safety: never act on Enter while an IME composition is in flight
|
||||
@@ -658,12 +655,13 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
/>
|
||||
)}
|
||||
{slashState && (
|
||||
<SkillSlashCommand
|
||||
<SlashCommandPicker
|
||||
query={slashState.query}
|
||||
skills={skills}
|
||||
items={skills}
|
||||
inputRef={textareaRef}
|
||||
onSelect={handleSlashSelect}
|
||||
onClose={() => setSlashState(null)}
|
||||
emptyLabel="No skills available"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user