web+coder: segmented per-agent slash menu (agent commands + skills) + cross-agent skill execution
Coder / menu now shows two groups: the active agent's commands first (manifest + live ACP available_commands), BooCoder skills second. SlashCommandPicker gains an opt-in groups prop (flat items path unchanged -> BooChat byte-identical, parity verified); ChatInput takes slashGroups; CoderPane builds the groups. Skills run under the selected agent: coder skill_invoke accepts a provider and, when external, injects the server-side skill body into a dispatched task instead of native inference. Also folds in the initial-chat skill fix (handleLandingSkill: create chat -> assign to pane -> invoke, same transition as a text send) that resolves the landing-page blank screen. BooChat slash menu + skill invocation unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ import { DropOverlay } from '@/components/DropOverlay';
|
||||
import { AgentPicker } from '@/components/AgentPicker';
|
||||
import { AgentCommandsHint } from '@/components/AgentCommandsHint';
|
||||
import { ContextBar } from '@/components/ContextBar';
|
||||
import { SlashCommandPicker } from '@/components/SlashCommandPicker';
|
||||
import { SlashCommandPicker, type SlashCommandGroup } from '@/components/SlashCommandPicker';
|
||||
import { isSlashCommandToken, parseSlashInput, slashQuery } from '@/lib/slash-command';
|
||||
import { api } from '@/api/client';
|
||||
import type { Message } from '@/api/types';
|
||||
@@ -56,6 +56,13 @@ interface Props {
|
||||
// empty). Callers wire this to api.chats.skillInvoke. Omitting the prop
|
||||
// disables slash-command dispatch (input is sent as literal text).
|
||||
onSlashCommand?: (skillName: string, userMessage: string) => void | Promise<void>;
|
||||
// v2.5.9: segmented slash-command DISPLAY source for the picker + hint. When
|
||||
// provided (e.g. CoderPane passing [agent commands, skills]), these labeled
|
||||
// groups are shown instead of the BooChat skills. Invocation routing still
|
||||
// uses the skills lookup — names not in skills (opencode's /help etc.) fall
|
||||
// through and are sent to the agent as literal text. Omitted → BooChat skills
|
||||
// (flat, unchanged — parity).
|
||||
slashGroups?: SlashCommandGroup[];
|
||||
// v1.10.4: send-to-chat reverse path. When chatId is provided, this input
|
||||
// registers in chatInputsRegistry so the terminal floating menu can list
|
||||
// it, and subscribes to sendToChat events scoped to this chatId. Receiving
|
||||
@@ -71,7 +78,7 @@ interface Props {
|
||||
modelContextLimit?: number | null;
|
||||
}
|
||||
|
||||
export function ChatInput({ disabled, projectId, agentId, onAgentChange, sessionId, webSearchEnabled, onSend, onForceSend, onSlashCommand, chatId, chatLabel, messages, modelContextLimit }: Props) {
|
||||
export function ChatInput({ disabled, projectId, agentId, onAgentChange, sessionId, webSearchEnabled, onSend, onForceSend, onSlashCommand, slashGroups, chatId, chatLabel, messages, modelContextLimit }: Props) {
|
||||
const { isMobile } = useViewport();
|
||||
const [value, setValue] = useState('');
|
||||
const [busy, setBusy] = useState(false);
|
||||
@@ -100,6 +107,15 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
for (const s of skills) m.set(s.name, true);
|
||||
return m;
|
||||
}, [skills]);
|
||||
// Flat display source for the hint (and the picker's no-groups fallback):
|
||||
// caller-provided groups flattened, else the BooChat skills.
|
||||
const slashItems = useMemo(
|
||||
() =>
|
||||
slashGroups
|
||||
? slashGroups.flatMap((g) => g.items)
|
||||
: skills.map((s) => ({ name: s.name, description: s.description })),
|
||||
[slashGroups, skills],
|
||||
);
|
||||
const [fileIndex, setFileIndex] = useState<string[] | null>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
@@ -561,8 +577,8 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{skills.length > 0 && (
|
||||
<AgentCommandsHint commands={skills.map((s) => ({ name: s.name, description: s.description }))} />
|
||||
{slashItems.length > 0 && (
|
||||
<AgentCommandsHint commands={slashItems} />
|
||||
)}
|
||||
{/* Batch 9 toolbar — agent picker + quick-toggle menu. v1.11.5.1
|
||||
inlines ContextBar in the same row so the bar lives next to the
|
||||
@@ -661,11 +677,12 @@ export function ChatInput({ disabled, projectId, agentId, onAgentChange, session
|
||||
{slashState && (
|
||||
<SlashCommandPicker
|
||||
query={slashState.query}
|
||||
items={skills}
|
||||
items={slashItems}
|
||||
groups={slashGroups}
|
||||
inputRef={textareaRef}
|
||||
onSelect={handleSlashSelect}
|
||||
onClose={() => setSlashState(null)}
|
||||
emptyLabel="No skills available"
|
||||
emptyLabel={slashGroups ? 'No commands available' : 'No skills available'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user