diff --git a/packages/app/e2e/support/helpers/agent-profiles.ts b/packages/app/e2e/support/helpers/agent-profiles.ts index 59deb8863..d9bd9c404 100644 --- a/packages/app/e2e/support/helpers/agent-profiles.ts +++ b/packages/app/e2e/support/helpers/agent-profiles.ts @@ -275,7 +275,7 @@ async function fillAgentProfileForm(page: Page, draft: AgentProfileDraft): Promi await chooseSelectFieldOption(page, { field: "mode", option: draft.mode }); } if (draft.notes !== undefined) { - await modal.getByRole("textbox", { name: "Notes for agents", exact: true }).fill(draft.notes); + await modal.getByRole("textbox", { name: "When to use", exact: true }).fill(draft.notes); } } @@ -329,11 +329,18 @@ export async function expectAgentProfileForm( const modal = editModal(page); await expect(modal).toBeVisible({ timeout: 30_000 }); await expect(modal.getByRole("textbox", { name: "Name", exact: true })).toHaveValue(name); + const notesHint = modal.getByTestId("agent-profile-notes-field-hint"); + await expect(notesHint).toHaveText( + "Helps agents choose this profile when starting another agent.", + ); + expect(await notesHint.evaluate((element) => getComputedStyle(element).webkitLineClamp)).not.toBe( + "1", + ); for (const [field, value] of Object.entries(expected)) { if (field === "notes") { - await expect( - modal.getByRole("textbox", { name: "Notes for agents", exact: true }), - ).toHaveValue(value); + await expect(modal.getByRole("textbox", { name: "When to use", exact: true })).toHaveValue( + value, + ); continue; } await expect( diff --git a/packages/app/src/agent-profiles/internal/agent-profile-glyph.tsx b/packages/app/src/agent-profiles/internal/agent-profile-glyph.tsx index e9795614e..35ff3c099 100644 --- a/packages/app/src/agent-profiles/internal/agent-profile-glyph.tsx +++ b/packages/app/src/agent-profiles/internal/agent-profile-glyph.tsx @@ -1,7 +1,6 @@ import { withUnistyles } from "react-native-unistyles"; import { BookOpen, - Bot, Boxes, Brain, Bug, @@ -27,6 +26,7 @@ import { Server, Shield, Sparkles, + Star, Terminal, TestTube, Wrench, @@ -42,7 +42,7 @@ import { } from "./profile-appearance"; /** Drawn when a profile names no icon, and as the "default" cell in the picker grid. */ -const ThemedDefaultIcon = withUnistyles(Bot); +const ThemedDefaultIcon = withUnistyles(Star); /** * `withUnistyles` has to wrap each icon once at module scope, so the registry diff --git a/packages/app/src/components/ui/control-geometry.test.ts b/packages/app/src/components/ui/control-geometry.test.ts index d62455aef..5f4a653e5 100644 --- a/packages/app/src/components/ui/control-geometry.test.ts +++ b/packages/app/src/components/ui/control-geometry.test.ts @@ -86,23 +86,28 @@ describe("control geometry", () => { expect(geometry.formTextInputMd.lineHeight).toBe(20); }); - it("derives field padding from line height without changing the control height", () => { + it("derives field padding from content and border without changing the control height", () => { const geometry = createControlGeometry(theme); + const borderWidth = theme.borderWidth[1]; expect(geometry.fieldControlSm.minHeight).toBe(32); - expect(geometry.fieldControlSm.paddingVertical).toBe(6); - expect(geometry.fieldTextSm.lineHeight + geometry.fieldControlSm.paddingVertical * 2).toBe( - geometry.fieldControlSm.minHeight, - ); + expect(geometry.fieldControlSm.paddingVertical).toBe(5); + expect( + geometry.fieldTextSm.lineHeight + + geometry.fieldControlSm.paddingVertical * 2 + + borderWidth * 2, + ).toBe(geometry.fieldControlSm.minHeight); expect(geometry.fieldControlMd.minHeight).toBe(44); - expect(geometry.fieldControlMd.paddingVertical).toBe(12); - expect(geometry.fieldTextMd.lineHeight + geometry.fieldControlMd.paddingVertical * 2).toBe( - geometry.fieldControlMd.minHeight, - ); + expect(geometry.fieldControlMd.paddingVertical).toBe(11); + expect( + geometry.fieldTextMd.lineHeight + + geometry.fieldControlMd.paddingVertical * 2 + + borderWidth * 2, + ).toBe(geometry.fieldControlMd.minHeight); - expect(geometry.formTextInputSm.paddingVertical).toBe(6); - expect(geometry.formTextInputMd.paddingVertical).toBe(12); + expect(geometry.formTextInputSm.paddingVertical).toBe(5); + expect(geometry.formTextInputMd.paddingVertical).toBe(11); }); it("keeps segmented controls ghost with button-radius segments in a button-sized track", () => { diff --git a/packages/app/src/components/ui/control-geometry.ts b/packages/app/src/components/ui/control-geometry.ts index 526f52862..0538fa40f 100644 --- a/packages/app/src/components/ui/control-geometry.ts +++ b/packages/app/src/components/ui/control-geometry.ts @@ -78,8 +78,12 @@ function fieldLineHeight(fontSize: number): number { return Math.round(fontSize * FIELD_TEXT_LINE_HEIGHT_RATIO); } -function fieldVerticalPadding(controlHeight: number, lineHeight: number): number { - return (controlHeight - lineHeight) / 2; +function fieldVerticalPadding( + controlHeight: number, + lineHeight: number, + borderWidth: number, +): number { + return (controlHeight - lineHeight - borderWidth * 2) / 2; } export function getControlInteractionPhase( @@ -111,18 +115,27 @@ export function resolveControlInteractionStyles( } export function createControlGeometry(theme: Theme) { + const controlBorderWidth = theme.borderWidth[1]; const fieldTextSmLineHeight = fieldLineHeight(theme.fontSize.base); const fieldTextMdLineHeight = fieldLineHeight(theme.fontSize.base); const fieldControlSm = { minHeight: CONTROL_HEIGHTS.compact, paddingHorizontal: theme.spacing[3], - paddingVertical: fieldVerticalPadding(CONTROL_HEIGHTS.compact, fieldTextSmLineHeight), + paddingVertical: fieldVerticalPadding( + CONTROL_HEIGHTS.compact, + fieldTextSmLineHeight, + controlBorderWidth, + ), borderRadius: theme.borderRadius.md, }; const fieldControlMd = { minHeight: CONTROL_HEIGHTS.field, paddingHorizontal: theme.spacing[4], - paddingVertical: fieldVerticalPadding(CONTROL_HEIGHTS.field, fieldTextMdLineHeight), + paddingVertical: fieldVerticalPadding( + CONTROL_HEIGHTS.field, + fieldTextMdLineHeight, + controlBorderWidth, + ), borderRadius: theme.borderRadius.lg, }; const fieldTextSm = { @@ -182,7 +195,7 @@ export function createControlGeometry(theme: Theme) { fieldTextSm, fieldTextMd, controlRest: { - borderWidth: theme.borderWidth[1], + borderWidth: controlBorderWidth, borderColor: "transparent", outlineWidth: 0, outlineColor: "transparent", diff --git a/packages/app/src/components/ui/form-field.tsx b/packages/app/src/components/ui/form-field.tsx index 4df8136d0..d7c5356f0 100644 --- a/packages/app/src/components/ui/form-field.tsx +++ b/packages/app/src/components/ui/form-field.tsx @@ -45,7 +45,7 @@ export function Field({ label, children, hint, error, testID }: FieldProps) { } if (hint) { return ( - + {hint} ); diff --git a/packages/app/src/i18n/resources/ar.ts b/packages/app/src/i18n/resources/ar.ts index 1e0cf7f75..114629e26 100644 --- a/packages/app/src/i18n/resources/ar.ts +++ b/packages/app/src/i18n/resources/ar.ts @@ -2343,9 +2343,9 @@ export const ar: TranslationResources = { featuresLabel: "السمات", featureCount: "{{count}} سمة", featureCountOne: "{{count}} سمة", - notesLabel: "ملاحظات للوكلاء", + notesLabel: "متى يُستخدم", notesPlaceholder: "استخدمه لعمل الواجهة — المكونات والتخطيط ورموز التصميم.", - notesHint: 'تُعاد بواسطة أداة MCP "list_profiles". اكتبها كتعليمة لوكيل آخر.', + notesHint: "يساعد الوكلاء على اختيار ملف التعريف هذا عند بدء وكيل آخر.", save: "حفظ", saving: "جارٍ الحفظ...", remove: "إزالة", diff --git a/packages/app/src/i18n/resources/en.ts b/packages/app/src/i18n/resources/en.ts index 72c190c88..3beebc278 100644 --- a/packages/app/src/i18n/resources/en.ts +++ b/packages/app/src/i18n/resources/en.ts @@ -2410,10 +2410,9 @@ export const en = { featuresLabel: "Features", featureCount: "{{count}} features", featureCountOne: "{{count}} feature", - notesLabel: "Notes for agents", + notesLabel: "When to use", notesPlaceholder: "Use for UI work — components, layout and design tokens.", - notesHint: - "Returned by the list_profiles MCP tool. Write it as an instruction to another agent.", + notesHint: "Helps agents choose this profile when starting another agent.", save: "Save", saving: "Saving...", remove: "Remove", diff --git a/packages/app/src/i18n/resources/es.ts b/packages/app/src/i18n/resources/es.ts index 4eadca32d..9be4b5bbd 100644 --- a/packages/app/src/i18n/resources/es.ts +++ b/packages/app/src/i18n/resources/es.ts @@ -2397,10 +2397,9 @@ export const es: TranslationResources = { featuresLabel: "Características", featureCount: "{{count}} características", featureCountOne: "{{count}} característica", - notesLabel: "Notas para los agentes", + notesLabel: "Cuándo usarlo", notesPlaceholder: "Úselo para trabajo de UI: componentes, diseño y tokens de diseño.", - notesHint: - 'Devuelto por la herramienta MCP "list_profiles". Escríbalo como una instrucción para otro agente.', + notesHint: "Ayuda a los agentes a elegir este perfil al iniciar otro agente.", save: "Guardar", saving: "Guardando...", remove: "Eliminar", diff --git a/packages/app/src/i18n/resources/fr.ts b/packages/app/src/i18n/resources/fr.ts index ef312200a..b5c54a0d5 100644 --- a/packages/app/src/i18n/resources/fr.ts +++ b/packages/app/src/i18n/resources/fr.ts @@ -2404,11 +2404,10 @@ export const fr: TranslationResources = { featuresLabel: "Caractéristiques", featureCount: "{{count}} caractéristiques", featureCountOne: "{{count}} caractéristique", - notesLabel: "Notes pour les agents", + notesLabel: "Quand l’utiliser", notesPlaceholder: "À utiliser pour le travail sur l'UI — composants, mise en page et tokens de design.", - notesHint: - "Renvoyé par l'outil MCP « list_profiles ». Rédigez-le comme une instruction destinée à un autre agent.", + notesHint: "Aide les agents à choisir ce profil lorsqu’ils démarrent un autre agent.", save: "Enregistrer", saving: "Enregistrement...", remove: "Supprimer", diff --git a/packages/app/src/i18n/resources/ja.ts b/packages/app/src/i18n/resources/ja.ts index 57cf19418..0feb4869a 100644 --- a/packages/app/src/i18n/resources/ja.ts +++ b/packages/app/src/i18n/resources/ja.ts @@ -2366,10 +2366,9 @@ export const ja: TranslationResources = { featuresLabel: "機能", featureCount: "{{count}}個の機能", featureCountOne: "{{count}}個の機能", - notesLabel: "エージェントへのメモ", + notesLabel: "使用する場面", notesPlaceholder: "UI作業に使用 — コンポーネント、レイアウト、デザイントークンなど。", - notesHint: - "list_profiles MCPツールによって返されます。他のエージェントへの指示として記述してください。", + notesHint: "別のエージェントを起動するとき、このプロファイルを選ぶために使用されます。", save: "保存", saving: "保存中...", remove: "削除", diff --git a/packages/app/src/i18n/resources/ko.ts b/packages/app/src/i18n/resources/ko.ts index 537d724dc..e70a966ad 100644 --- a/packages/app/src/i18n/resources/ko.ts +++ b/packages/app/src/i18n/resources/ko.ts @@ -2355,10 +2355,9 @@ export const ko: TranslationResources = { featuresLabel: "기능", featureCount: "기능 {{count}}개", featureCountOne: "기능 {{count}}개", - notesLabel: "에이전트를 위한 메모", + notesLabel: "사용 시점", notesPlaceholder: "UI 작업에 사용 — 컴포넌트, 레이아웃, 디자인 토큰.", - notesHint: - "list_profiles MCP 도구가 반환합니다. 다른 에이전트에게 전달할 지침으로 작성하세요.", + notesHint: "에이전트가 다른 에이전트를 시작할 때 이 프로필을 선택하는 데 사용됩니다.", save: "저장", saving: "저장하는 중...", remove: "제거", diff --git a/packages/app/src/i18n/resources/pt-BR.ts b/packages/app/src/i18n/resources/pt-BR.ts index a65d05391..409875100 100644 --- a/packages/app/src/i18n/resources/pt-BR.ts +++ b/packages/app/src/i18n/resources/pt-BR.ts @@ -2382,10 +2382,9 @@ export const ptBR: TranslationResources = { featuresLabel: "Recursos", featureCount: "{{count}} recursos", featureCountOne: "{{count}} recurso", - notesLabel: "Notas para os agentes", + notesLabel: "Quando usar", notesPlaceholder: "Use para trabalho de UI — componentes, layout e tokens de design.", - notesHint: - 'Retornado pela ferramenta MCP "list_profiles". Escreva como uma instrução para outro agente.', + notesHint: "Ajuda os agentes a escolher este perfil ao iniciar outro agente.", save: "Salvar", saving: "Salvando...", remove: "Remover", diff --git a/packages/app/src/i18n/resources/ru.ts b/packages/app/src/i18n/resources/ru.ts index 6a4e719e7..25b94e024 100644 --- a/packages/app/src/i18n/resources/ru.ts +++ b/packages/app/src/i18n/resources/ru.ts @@ -2387,10 +2387,9 @@ export const ru: TranslationResources = { featuresLabel: "Функции", featureCount: "Функции: {{count}}", featureCountOne: "{{count}} функция", - notesLabel: "Заметки для агентов", + notesLabel: "Когда использовать", notesPlaceholder: "Используйте для работы над UI — компоненты, макет и токены дизайна.", - notesHint: - "MCP-инструмент «list_profiles» возвращает эти заметки. Сформулируйте их как инструкцию для другого агента.", + notesHint: "Помогает агентам выбрать этот профиль при запуске другого агента.", save: "Сохранить", saving: "Сохранение...", remove: "Удалить", diff --git a/packages/app/src/i18n/resources/zh-CN.ts b/packages/app/src/i18n/resources/zh-CN.ts index 3fb546b88..6fcc2e1d0 100644 --- a/packages/app/src/i18n/resources/zh-CN.ts +++ b/packages/app/src/i18n/resources/zh-CN.ts @@ -2317,9 +2317,9 @@ export const zhCN: TranslationResources = { featuresLabel: "Features", featureCount: "{{count}} 个 Feature", featureCountOne: "{{count}} 个 Feature", - notesLabel: "给 Agent 的说明", + notesLabel: "适用场景", notesPlaceholder: "用于 UI 工作 — 组件、布局和设计 token。", - notesHint: "由 list_profiles MCP 工具返回。请将其写成给另一个 Agent 的指令。", + notesHint: "帮助 Agent 在启动另一个 Agent 时选择此配置。", save: "保存", saving: "保存中...", remove: "移除",