Skip to content

Commit a29de30

Browse files
fix: slash commands populated from SDK init (slash_commands array), merged with IPC list
1 parent 8dc676c commit a29de30

3 files changed

Lines changed: 41 additions & 7 deletions

File tree

crates/session/src/claude.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,20 @@ impl ClaudeSession {
270270
vec![AgentEvent::SessionReady { claude_session_id: sid, model: confirmed_model }]
271271
}
272272
"slash_commands" => {
273-
// Slash commands from the SDK init — we just log them,
274-
// the frontend loads them separately via list_slash_commands
275-
vec![]
273+
// Forward slash commands from SDK init to frontend
274+
if let Some(cmds) = obj.get("commands").and_then(|c| c.as_array()) {
275+
let cmd_list: Vec<String> = cmds.iter()
276+
.filter_map(|c| c.as_str().map(String::from))
277+
.collect();
278+
let description = cmd_list.join(",");
279+
// Abuse SessionError to send the command list to the frontend
280+
// The frontend will detect the "slash_commands:" prefix
281+
vec![AgentEvent::SessionError {
282+
message: format!("slash_commands:{description}"),
283+
}]
284+
} else {
285+
vec![]
286+
}
276287
}
277288
"turn_started" => {
278289
vec![AgentEvent::TurnStarted { turn_id: "sidecar".to_string() }]

crates/tauri-app/frontend/src/components/composer/Composer.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,32 @@ export function Composer() {
7676
const [slashFilter, setSlashFilter] = createSignal("");
7777
const [slashIndex, setSlashIndex] = createSignal(0);
7878

79-
// Load slash commands (and reload when provider changes)
79+
// Load slash commands from IPC + merge SDK init commands from store
8080
createEffect(() => {
8181
const p = store.selectedProvider;
8282
ipc.listSlashCommands(p).then(setSlashCommands).catch(() => setSlashCommands([]));
8383
});
8484

85+
const allSlashCommands = () => {
86+
const ipcCmds = slashCommands();
87+
const sdkCmds = store.availableSlashCommands || [];
88+
// Merge SDK commands that aren't already in the IPC list
89+
const existing = new Set(ipcCmds.map((c) => c.name));
90+
const merged = [...ipcCmds];
91+
for (const cmd of sdkCmds) {
92+
const name = cmd.startsWith("/") ? cmd : `/${cmd}`;
93+
if (!existing.has(name)) {
94+
merged.push({ name, description: `Skill: ${cmd}`, source: "sdk" });
95+
}
96+
}
97+
return merged;
98+
};
99+
85100
const filteredSlash = () => {
86101
const q = slashFilter().toLowerCase();
87-
if (!q) return slashCommands().slice(0, 12);
88-
return slashCommands().filter((c) => c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q)).slice(0, 12);
102+
const cmds = allSlashCommands();
103+
if (!q) return cmds.slice(0, 15);
104+
return cmds.filter((c) => c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q)).slice(0, 15);
89105
};
90106

91107
function handleSlashSelect(cmd: SlashCommand) {

crates/tauri-app/frontend/src/stores/app-store.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export interface AppStore {
6060
projectPrMap: Record<string, Record<string, number>>;
6161
activeModel: string | null;
6262
unreadTabs: Record<string, boolean>;
63+
availableSlashCommands: string[];
6364
recentlyClosedTabs: string[];
6465
keyboardHelpOpen: boolean;
6566
}
@@ -103,6 +104,7 @@ function createAppStore() {
103104
projectPrMap: {},
104105
activeModel: null,
105106
unreadTabs: {},
107+
availableSlashCommands: [],
106108
recentlyClosedTabs: [],
107109
keyboardHelpOpen: false,
108110
});
@@ -721,12 +723,17 @@ function createAppStore() {
721723
}
722724
break;
723725
case "session_error": {
726+
// Check if this is a slash_commands update (smuggled via session_error)
727+
if (payload.message?.startsWith("slash_commands:")) {
728+
const cmdList = payload.message.slice("slash_commands:".length).split(",").filter(Boolean);
729+
setStore("availableSlashCommands", cmdList);
730+
break;
731+
}
724732
setStore("sessionStatuses", thread_id, "error");
725733
setStore("threadMessages", thread_id, (msgs) => [
726734
...(msgs || []),
727735
{ id: crypto.randomUUID(), thread_id, role: "system" as const, content: `Error: ${payload.message}` },
728736
]);
729-
// Always notify on errors
730737
const errTitle = getThreadTitle(thread_id);
731738
sendNotification(`${errTitle} - Error`, payload.message || "Session error");
732739
break;

0 commit comments

Comments
 (0)