- {command.argumentHint}
+
+ {filteredCommandGroups.system.map((command, index) => {
+ const Icon = getSystemSlashCommandIcon(command.name)
+ return (
+
{ slashItemRefs.current[index] = el }}
+ onClick={() => selectSlashCommand(command.name)}
+ onMouseEnter={() => setSlashSelectedIndex(index)}
+ className={`flex w-full cursor-default items-center gap-3 rounded-[var(--radius-md)] px-3 py-2 text-left transition-colors ${
+ index === slashSelectedIndex
+ ? 'bg-[var(--color-surface-hover)]'
+ : 'hover:bg-[var(--color-surface-hover)]'
+ }`}
+ >
+
+
+
+ {command.name}
- ) : null}
-
-
- {command.description}
-
-
- ))}
+ {command.argumentHint ? (
+
+ {command.argumentHint}
+
+ ) : null}
+
+
+ {command.description}
+
+
+ )
+ })}
+
+ {filteredCommandGroups.skills.length > 0 ? (
+
0
+ ? 'mt-1 border-t border-[var(--color-border-separator)] pt-1'
+ : ''}
+ >
+
+ {t('sidebar.skills')}
+
+ {filteredCommandGroups.skills.map((command, skillIndex) => {
+ const index = filteredCommandGroups.system.length + skillIndex
+ return (
+
{ slashItemRefs.current[index] = el }}
+ onClick={() => selectSlashCommand(command.name)}
+ onMouseEnter={() => setSlashSelectedIndex(index)}
+ className={`flex w-full cursor-default items-center gap-3 rounded-[var(--radius-md)] px-3 py-2 text-left transition-colors ${
+ index === slashSelectedIndex
+ ? 'bg-[var(--color-surface-hover)]'
+ : 'hover:bg-[var(--color-surface-hover)]'
+ }`}
+ >
+
+
+ {command.name}
+
+
+ {command.description}
+
+
+ {t('chat.slashSkillPersonal')}
+
+
+ )
+ })}
+
+ ) : null}
{!isMobileComposer ? (
diff --git a/desktop/src/components/chat/composerUtils.test.ts b/desktop/src/components/chat/composerUtils.test.ts
index f713caeb..837d6f60 100644
--- a/desktop/src/components/chat/composerUtils.test.ts
+++ b/desktop/src/components/chat/composerUtils.test.ts
@@ -5,6 +5,7 @@ import {
filterSlashCommands,
findSlashToken,
getLocalizedFallbackCommands,
+ groupSlashCommands,
insertSlashTrigger,
mergeSlashCommands,
replaceSlashCommand,
@@ -161,6 +162,33 @@ describe('composerUtils', () => {
])
})
+ it('groups built-in app commands before personal skills without changing their relative order', () => {
+ const groups = groupSlashCommands([
+ { name: 'amazon-review-scraper', description: 'Collect Amazon reviews' },
+ { name: 'status', description: 'Show session status' },
+ { name: 'agent debugger', description: 'Run the debugger agent' },
+ { name: 'audit', description: 'Audit product UX' },
+ { name: 'model', description: 'Switch model' },
+ ])
+
+ expect(groups.system.map((command) => command.name)).toEqual([
+ 'status',
+ 'agent debugger',
+ 'model',
+ ])
+ expect(groups.skills.map((command) => command.name)).toEqual([
+ 'amazon-review-scraper',
+ 'audit',
+ ])
+ expect(groups.ordered.map((command) => command.name)).toEqual([
+ 'status',
+ 'agent debugger',
+ 'model',
+ 'amazon-review-scraper',
+ 'audit',
+ ])
+ })
+
it('resolves hidden settings aliases without displaying duplicate fallback rows', () => {
expect(resolveSlashUiAction('plugins')).toEqual({ type: 'settings', tab: 'plugins' })
expect(resolveSlashUiAction('memory')).toEqual({ type: 'settings', tab: 'memory' })
diff --git a/desktop/src/components/chat/composerUtils.ts b/desktop/src/components/chat/composerUtils.ts
index 3663d38b..c240b1cc 100644
--- a/desktop/src/components/chat/composerUtils.ts
+++ b/desktop/src/components/chat/composerUtils.ts
@@ -119,6 +119,38 @@ export type SlashCommandOption = {
argumentHint?: string
}
+export type SlashCommandGroups = {
+ system: SlashCommandOption[]
+ skills: SlashCommandOption[]
+ ordered: SlashCommandOption[]
+}
+
+function isSystemSlashCommand(command: SlashCommandOption): boolean {
+ const rootCommand = command.name.trim().split(/\s+/, 1)[0]
+ return Boolean(rootCommand && BUILT_IN_COMMAND_NAMES.has(rootCommand))
+}
+
+export function groupSlashCommands(
+ commands: ReadonlyArray,
+): SlashCommandGroups {
+ const system: SlashCommandOption[] = []
+ const skills: SlashCommandOption[] = []
+
+ for (const command of commands) {
+ if (isSystemSlashCommand(command)) {
+ system.push(command)
+ } else {
+ skills.push(command)
+ }
+ }
+
+ return {
+ system,
+ skills,
+ ordered: [...system, ...skills],
+ }
+}
+
export type AgentSlashCommandSource = {
agentType: string
description?: string
diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts
index ca5f5102..84b84933 100644
--- a/desktop/src/i18n/locales/en.ts
+++ b/desktop/src/i18n/locales/en.ts
@@ -1580,6 +1580,7 @@ Row 9, all 8 cells: continuing from straight down, turning left through lower-le
'chat.conversationNavigator.label': 'Conversation navigation',
'chat.conversationNavigator.attachments': '{count} attachments',
'chat.slashCommands': 'Slash commands',
+ 'chat.slashSkillPersonal': 'Personal',
'chat.pendingMessageGuide': 'Guide',
'chat.pendingMessageGuideNow': 'Guide now',
'chat.pendingMessageEdit': 'Edit queued message',
diff --git a/desktop/src/i18n/locales/jp.ts b/desktop/src/i18n/locales/jp.ts
index 7f1776ea..025282d3 100644
--- a/desktop/src/i18n/locales/jp.ts
+++ b/desktop/src/i18n/locales/jp.ts
@@ -1582,6 +1582,7 @@ export const jp: Record = {
'chat.conversationNavigator.label': '会話ナビゲーション',
'chat.conversationNavigator.attachments': '添付ファイル {count} 件',
'chat.slashCommands': 'スラッシュコマンド',
+ 'chat.slashSkillPersonal': '個人',
'chat.pendingMessageGuide': '誘導',
'chat.pendingMessageGuideNow': '今すぐ誘導',
'chat.pendingMessageEdit': 'キュー中のメッセージを編集',
diff --git a/desktop/src/i18n/locales/kr.ts b/desktop/src/i18n/locales/kr.ts
index 36951047..fcfe4770 100644
--- a/desktop/src/i18n/locales/kr.ts
+++ b/desktop/src/i18n/locales/kr.ts
@@ -1582,6 +1582,7 @@ export const kr: Record = {
'chat.conversationNavigator.label': '대화 탐색',
'chat.conversationNavigator.attachments': '첨부 파일 {count}개',
'chat.slashCommands': '슬래시 명령',
+ 'chat.slashSkillPersonal': '개인',
'chat.pendingMessageGuide': '가이드',
'chat.pendingMessageGuideNow': '지금 가이드',
'chat.pendingMessageEdit': '대기 메시지 편집',
diff --git a/desktop/src/i18n/locales/zh-TW.ts b/desktop/src/i18n/locales/zh-TW.ts
index d262e0d2..60e650b5 100644
--- a/desktop/src/i18n/locales/zh-TW.ts
+++ b/desktop/src/i18n/locales/zh-TW.ts
@@ -1581,6 +1581,7 @@ export const zh: Record = {
'chat.conversationNavigator.label': '對話導覽',
'chat.conversationNavigator.attachments': '{count} 個附件',
'chat.slashCommands': '斜槓命令',
+ 'chat.slashSkillPersonal': '個人',
'chat.pendingMessageGuide': '引導',
'chat.pendingMessageGuideNow': '立即引導',
'chat.pendingMessageEdit': '編輯排隊訊息',
diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts
index 41e5416c..43c23d10 100644
--- a/desktop/src/i18n/locales/zh.ts
+++ b/desktop/src/i18n/locales/zh.ts
@@ -1581,6 +1581,7 @@ export const zh: Record = {
'chat.conversationNavigator.label': '对话导航',
'chat.conversationNavigator.attachments': '{count} 个附件',
'chat.slashCommands': '斜杠命令',
+ 'chat.slashSkillPersonal': '个人',
'chat.pendingMessageGuide': '引导',
'chat.pendingMessageGuideNow': '立即引导',
'chat.pendingMessageEdit': '编辑排队消息',