feat: user-customizable draft welcome starters

Let users curate the draft welcome chips: pin existing commands and skills
as starters, remove them, and drag to reorder — all inline on the draft
screen via a '+' picker dialog and per-chip remove, with no separate
settings UI.

A starter references a command or skill; its scope is inherited from the
item (user-scope -> global, project-scope -> per-project). Global starters
persist to settings.json (useUIStore + client/server sanitizers); project
starters persist to the project config alongside worktree setup commands.
The two scopes form ordered namespaces shown global-first then project,
reorderable only within each group.

The six built-in Session magic-prompt commands are the default global set
and stay available in the picker for re-pinning if removed; they keep their
bespoke icons, while user commands/skills fall back to the Commands/Skills
section icons. Chip labels are normalized (/simplify-code -> 'Simplify
code'). Missing commands/skills are skipped rather than shown broken.

Drag-to-reorder works on desktop and mobile: rectSortingStrategy for the
wrapping multi-row layout, CSS.Translate (no scale) so the lifted chip
doesn't stretch, and MouseSensor + long-press TouchSensor so taps still
submit and swipes still scroll. The '+' picker is a searchable dialog on
every surface.
This commit is contained in:
Bohdan Triapitsyn
2026-05-30 02:04:32 +03:00
parent af615df719
commit 6d4f070d91
18 changed files with 590 additions and 50 deletions
+7
View File
@@ -1459,6 +1459,13 @@ export const dict = {
'chat.draftPresets.plan.label': 'Start feature planning',
'chat.draftPresets.debug.label': 'Debug an issue',
'chat.draftPresets.review.label': 'Review my changes',
'chat.draftStarters.add': 'Add a starter',
'chat.draftStarters.searchPlaceholder': 'Search commands and skills…',
'chat.draftStarters.empty': 'Nothing to add',
'chat.draftStarters.sectionBuiltIn': 'Built-in',
'chat.draftStarters.sectionCommands': 'Commands',
'chat.draftStarters.sectionSkills': 'Skills',
'chat.draftStarters.remove': 'Remove',
'chat.scrollToBottom.aria': 'Scroll to bottom',
'chat.timeline.relative.justNow': 'just now',
'chat.timeline.relative.minutesAgo': '{count}m ago',
+7
View File
@@ -1425,6 +1425,13 @@ export const dict: Record<I18nKey, string> = {
"chat.draftPresets.plan.label": "Start feature planning",
"chat.draftPresets.debug.label": "Debug an issue",
"chat.draftPresets.review.label": "Review my changes",
"chat.draftStarters.add": "Add a starter",
"chat.draftStarters.searchPlaceholder": "Search commands and skills…",
"chat.draftStarters.empty": "Nothing to add",
"chat.draftStarters.sectionBuiltIn": "Built-in",
"chat.draftStarters.sectionCommands": "Commands",
"chat.draftStarters.sectionSkills": "Skills",
"chat.draftStarters.remove": "Remove",
"chat.scrollToBottom.aria": "Ir al final",
"chat.timeline.relative.justNow": "ahora mismo",
"chat.timeline.relative.minutesAgo": "hace {count}m",
+7
View File
@@ -1461,6 +1461,13 @@ export const dict: Record<I18nKey, string> = {
'chat.draftPresets.plan.label': 'Start feature planning',
'chat.draftPresets.debug.label': 'Debug an issue',
'chat.draftPresets.review.label': 'Review my changes',
'chat.draftStarters.add': 'Add a starter',
'chat.draftStarters.searchPlaceholder': 'Search commands and skills…',
'chat.draftStarters.empty': 'Nothing to add',
'chat.draftStarters.sectionBuiltIn': 'Built-in',
'chat.draftStarters.sectionCommands': 'Commands',
'chat.draftStarters.sectionSkills': 'Skills',
'chat.draftStarters.remove': 'Remove',
'chat.scrollToBottom.aria': '맨 아래로 스크롤',
'chat.timeline.relative.justNow': '방금 전',
'chat.timeline.relative.minutesAgo': '{count}분 전',
+7
View File
@@ -451,6 +451,13 @@ export const dict: Record<I18nKey, string> = {
'chat.draftPresets.plan.label': 'Start feature planning',
'chat.draftPresets.debug.label': 'Debug an issue',
'chat.draftPresets.review.label': 'Review my changes',
'chat.draftStarters.add': 'Add a starter',
'chat.draftStarters.searchPlaceholder': 'Search commands and skills…',
'chat.draftStarters.empty': 'Nothing to add',
'chat.draftStarters.sectionBuiltIn': 'Built-in',
'chat.draftStarters.sectionCommands': 'Commands',
'chat.draftStarters.sectionSkills': 'Skills',
'chat.draftStarters.remove': 'Remove',
'chat.scrollToBottom.aria': 'Przewiń na dół',
'chat.timeline.relative.justNow': 'przed chwilą',
'chat.timeline.relative.minutesAgo': '{count}m temu',
@@ -1425,6 +1425,13 @@ export const dict: Record<I18nKey, string> = {
"chat.draftPresets.plan.label": "Start feature planning",
"chat.draftPresets.debug.label": "Debug an issue",
"chat.draftPresets.review.label": "Review my changes",
"chat.draftStarters.add": "Add a starter",
"chat.draftStarters.searchPlaceholder": "Search commands and skills…",
"chat.draftStarters.empty": "Nothing to add",
"chat.draftStarters.sectionBuiltIn": "Built-in",
"chat.draftStarters.sectionCommands": "Commands",
"chat.draftStarters.sectionSkills": "Skills",
"chat.draftStarters.remove": "Remove",
"chat.scrollToBottom.aria": "Ir ao final",
"chat.timeline.relative.justNow": "agora mesmo",
"chat.timeline.relative.minutesAgo": "há {count}m",
+7
View File
@@ -1425,6 +1425,13 @@ export const dict: Record<I18nKey, string> = {
"chat.draftPresets.plan.label": "Розпочати планування фічі",
"chat.draftPresets.debug.label": "Дебаг проблеми",
"chat.draftPresets.review.label": "Переглянути мої зміни",
"chat.draftStarters.add": "Додати стартер",
"chat.draftStarters.searchPlaceholder": "Пошук команд і скілів…",
"chat.draftStarters.empty": "Немає що додати",
"chat.draftStarters.sectionBuiltIn": "Вбудовані",
"chat.draftStarters.sectionCommands": "Команди",
"chat.draftStarters.sectionSkills": "Скіли",
"chat.draftStarters.remove": "Прибрати",
"chat.scrollToBottom.aria": "Прокрутити вниз",
"chat.timeline.relative.justNow": "щойно",
"chat.timeline.relative.minutesAgo": "{count} хв тому",
@@ -1425,6 +1425,13 @@ export const dict: Record<I18nKey, string> = {
'chat.draftPresets.plan.label': 'Start feature planning',
'chat.draftPresets.debug.label': 'Debug an issue',
'chat.draftPresets.review.label': 'Review my changes',
'chat.draftStarters.add': 'Add a starter',
'chat.draftStarters.searchPlaceholder': 'Search commands and skills…',
'chat.draftStarters.empty': 'Nothing to add',
'chat.draftStarters.sectionBuiltIn': 'Built-in',
'chat.draftStarters.sectionCommands': 'Commands',
'chat.draftStarters.sectionSkills': 'Skills',
'chat.draftStarters.remove': 'Remove',
'chat.scrollToBottom.aria': '滚动到底部',
'chat.timeline.relative.justNow': '刚刚',
'chat.timeline.relative.minutesAgo': '{count} 分钟前',
@@ -1422,6 +1422,13 @@ export const dict: Record<I18nKey, string> = {
'chat.draftPresets.plan.label': 'Start feature planning',
'chat.draftPresets.debug.label': 'Debug an issue',
'chat.draftPresets.review.label': 'Review my changes',
'chat.draftStarters.add': 'Add a starter',
'chat.draftStarters.searchPlaceholder': 'Search commands and skills…',
'chat.draftStarters.empty': 'Nothing to add',
'chat.draftStarters.sectionBuiltIn': 'Built-in',
'chat.draftStarters.sectionCommands': 'Commands',
'chat.draftStarters.sectionSkills': 'Skills',
'chat.draftStarters.remove': 'Remove',
'chat.scrollToBottom.aria': '捲動到底部',
'chat.timeline.relative.justNow': '剛剛',
'chat.timeline.relative.minutesAgo': '{count} 分鐘前',