From feb47e300f523652da4a9a1fd22d32e018041bc3 Mon Sep 17 00:00:00 2001 From: Roomote Date: Wed, 15 Jul 2026 18:47:38 +0000 Subject: [PATCH] refactor: remove customizable Vibes settings Drop the Vibes settings UI, API, and deployment-level overrides. Keep fixed Slack lifecycle reactions and the default Roomote tone file, and remove emoji-based agent summoning. --- .../notifyPullRequestTerminalStatus.test.ts | 2 - .../handlers/slack/events/message-entry.ts | 2 +- .../src/handlers/slack/events/reactions.ts | 108 +- .../slack/helpers/event-normalization.ts | 11 - apps/docs/AGENTS.md | 2 +- apps/docs/docs.json | 1 - apps/docs/vibes.mdx | 91 - .../ideas/let-me-roomote-that-for-you.png | Bin 18838 -> 0 bytes apps/web/public/vibes/ideas/party-parrot.png | Bin 1457 -> 0 bytes .../vibes/ideas/roomote_right_black.png | Bin 4379 -> 0 bytes .../vibes/ideas/roomote_right_green.png | Bin 4298 -> 0 bytes .../public/vibes/ideas/roomote_up_black.png | Bin 5200 -> 0 bytes .../public/vibes/ideas/roomote_up_green.png | Bin 5172 -> 0 bytes apps/web/public/vibes/ideas/ship-it.png | Bin 792 -> 0 bytes apps/web/public/vibes/ideas/sparkles.png | Bin 1172 -> 0 bytes .../settings/vibes/page.client.test.tsx | 14 - .../(authenticated)/settings/vibes/page.tsx | 5 - .../settings/SettingsShell.client.test.tsx | 2 - .../settings/VibesSettings.client.test.tsx | 585 -- .../src/components/settings/VibesSettings.tsx | 688 -- .../settings/pages/VibesSettingsPage.tsx | 12 - .../settings/settings-navigation.ts | 13 - .../src/components/system/primitives/icons.ts | 3 - apps/web/src/lib/settings.ts | 1 - apps/web/src/trpc/commands/vibes/index.ts | 177 - apps/web/src/trpc/routers/_app.ts | 25 - .../callbacks/__tests__/slack-mention.test.ts | 4 +- apps/worker/src/callbacks/slack-mention.ts | 17 +- .../src/commands/__tests__/resume.test.ts | 2 - .../worker/src/commands/__tests__/run.test.ts | 4 - apps/worker/src/commands/resume.ts | 1 - apps/worker/src/commands/run.ts | 1 - .../src/run-task/__tests__/run-task.test.ts | 7 - apps/worker/src/run-task/types.ts | 5 - packages/cloud-agents/package.json | 8 - .../__tests__/fast-agent-prompt.test.ts | 33 +- .../server/fast-agent/fast-agent-prompt.ts | 6 +- .../server/fast-agent/fast-agent-service.ts | 10 +- packages/cloud-agents/src/server/index.ts | 1 - .../src/server/non-task-provider-usage.ts | 1 - .../src/server/style-guidance-validation.ts | 65 - .../workflows/__tests__/systemPrompt.test.ts | 25 +- .../src/style-guidance-constants.ts | 4 - packages/cloud-agents/src/style-guidance.ts | 32 +- packages/cloud-agents/src/system-prompt.ts | 10 +- .../db/drizzle/0012_motionless_mauler.sql | 4 + packages/db/drizzle/meta/0012_snapshot.json | 9108 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/src/lib/automations.ts | 70 - packages/db/src/schema.ts | 12 +- packages/db/src/types.ts | 11 +- .../__tests__/dequeue-resume-task-run.test.ts | 17 - .../__tests__/dequeue-task-run.test.ts | 17 - .../lib/task-runs/dequeue-resume-task-run.ts | 5 - .../server/lib/task-runs/dequeue-task-run.ts | 5 - .../__tests__/show-task-configuration.test.ts | 9 - .../start-auto-routed-slack-task.test.ts | 2 - packages/slack/src/emoji-preferences.ts | 23 +- .../slack/src/start-auto-routed-slack-task.ts | 8 +- packages/slack/src/start-slack-app-mention.ts | 15 +- 60 files changed, 9177 insertions(+), 2114 deletions(-) delete mode 100644 apps/docs/vibes.mdx delete mode 100644 apps/web/public/vibes/ideas/let-me-roomote-that-for-you.png delete mode 100644 apps/web/public/vibes/ideas/party-parrot.png delete mode 100644 apps/web/public/vibes/ideas/roomote_right_black.png delete mode 100644 apps/web/public/vibes/ideas/roomote_right_green.png delete mode 100644 apps/web/public/vibes/ideas/roomote_up_black.png delete mode 100644 apps/web/public/vibes/ideas/roomote_up_green.png delete mode 100644 apps/web/public/vibes/ideas/ship-it.png delete mode 100644 apps/web/public/vibes/ideas/sparkles.png delete mode 100644 apps/web/src/app/(authenticated)/settings/vibes/page.client.test.tsx delete mode 100644 apps/web/src/app/(authenticated)/settings/vibes/page.tsx delete mode 100644 apps/web/src/components/settings/VibesSettings.client.test.tsx delete mode 100644 apps/web/src/components/settings/VibesSettings.tsx delete mode 100644 apps/web/src/components/settings/pages/VibesSettingsPage.tsx delete mode 100644 apps/web/src/trpc/commands/vibes/index.ts delete mode 100644 packages/cloud-agents/src/server/style-guidance-validation.ts delete mode 100644 packages/cloud-agents/src/style-guidance-constants.ts create mode 100644 packages/db/drizzle/0012_motionless_mauler.sql create mode 100644 packages/db/drizzle/meta/0012_snapshot.json diff --git a/apps/api/src/handlers/github/__tests__/notifyPullRequestTerminalStatus.test.ts b/apps/api/src/handlers/github/__tests__/notifyPullRequestTerminalStatus.test.ts index 409ec7a3..10e3562b 100644 --- a/apps/api/src/handlers/github/__tests__/notifyPullRequestTerminalStatus.test.ts +++ b/apps/api/src/handlers/github/__tests__/notifyPullRequestTerminalStatus.test.ts @@ -26,7 +26,6 @@ const { mockResolveSlackReactionNames: vi.fn().mockResolvedValue({ ackEmoji: 'eyes', completionEmoji: 'white_check_mark', - summonEmoji: null, }), mockStickyFooterPost: vi.fn().mockResolvedValue('msg-ts-123'), mockGetCommunicationProviderAdapter: vi.fn(), @@ -147,7 +146,6 @@ describe('notifyPullRequestTerminalStatus', () => { mockResolveSlackReactionNames.mockResolvedValue({ ackEmoji: 'eyes', completionEmoji: 'white_check_mark', - summonEmoji: null, }); mockStickyFooterPost.mockResolvedValue('msg-ts-123'); mockPostMessage.mockResolvedValue({ diff --git a/apps/api/src/handlers/slack/events/message-entry.ts b/apps/api/src/handlers/slack/events/message-entry.ts index f8434034..71c9d31c 100644 --- a/apps/api/src/handlers/slack/events/message-entry.ts +++ b/apps/api/src/handlers/slack/events/message-entry.ts @@ -1587,7 +1587,7 @@ async function isSlackEvalLauncherEnabled(): Promise { ); } -export async function handleSlackEntryEvent(params: { +async function handleSlackEntryEvent(params: { event: SlackEvent; slackInstallation: SlackInstallation; slack: SlackNotifier; diff --git a/apps/api/src/handlers/slack/events/reactions.ts b/apps/api/src/handlers/slack/events/reactions.ts index 9a765ed4..44d3c8b6 100644 --- a/apps/api/src/handlers/slack/events/reactions.ts +++ b/apps/api/src/handlers/slack/events/reactions.ts @@ -39,13 +39,9 @@ import { TASK_SUGGESTION_TYPES, } from '../constants.js'; import type { SlackWebhookContext } from '../context.js'; -import { - isConfiguredSlackReaction, - isThumbsUpReaction, -} from '../helpers/event-normalization.js'; +import { isThumbsUpReaction } from '../helpers/event-normalization.js'; import { postTaskSuggestionStartedMessage } from '../helpers/thread-posting.js'; import { lookupSlackUserMapping } from '../helpers/user-mapping.js'; -import { handleSlackEntryEvent } from './message-entry.js'; import { runTaskSuggestionReactionContention, type TaskSuggestionReactionLaunchResult, @@ -715,12 +711,6 @@ export async function handleReactionAddedEvent(params: { return; } - const isThumbsUp = isThumbsUpReaction(event.reaction); - const isSummonReaction = isConfiguredSlackReaction( - event.reaction, - reactionNames.summonEmoji, - ); - if (event.user === context.slackInstallation.botUserId) { apiLogger.debug( `[SlackWebhook] Ignoring self-reaction from bot user ${event.user} on ${event.item.channel}:${event.item.ts}`, @@ -728,90 +718,36 @@ export async function handleReactionAddedEvent(params: { return; } - if (isThumbsUp) { - apiLogger.debug( - `[SetupSuggestionLifecycle] Processing thumbs-up reaction team=${context.teamId} channel=${event.item.channel} messageTs=${event.item.ts} reaction=${event.reaction} user=${event.user}`, - ); - const setupSuggestionLockKey = `${SLACK_SETUP_SUGGESTION_LOCK_PREFIX}${event.item.channel}:${event.item.ts}`; - const setupSuggestionHandled = await launchTaskSuggestionTaskWithContention( - { - lockKey: setupSuggestionLockKey, - channelId: event.item.channel, - messageTs: event.item.ts, - launch: () => - launchTaskSuggestionTaskFromReaction({ - teamId: context.teamId, - slack: context.slack, - reactionEvent: event, - ackEmoji: reactionNames.ackEmoji, - completionEmoji: reactionNames.completionEmoji, - }), - }, - ); - - if (setupSuggestionHandled) { - apiLogger.debug( - `[SlackWebhook] Setup suggestion reaction handled for ${event.item.channel}:${event.item.ts}`, - ); - return; - } - - apiLogger.debug( - `[SlackWebhook] Reaction no-op for ${event.item.channel}:${event.item.ts}`, - ); - } - - if (!isSummonReaction) { + if (!isThumbsUpReaction(event.reaction)) { return; } - const sourceMessage = await context.slack.getMessage({ - channel: event.item.channel, + apiLogger.debug( + `[SetupSuggestionLifecycle] Processing thumbs-up reaction team=${context.teamId} channel=${event.item.channel} messageTs=${event.item.ts} reaction=${event.reaction} user=${event.user}`, + ); + const setupSuggestionLockKey = `${SLACK_SETUP_SUGGESTION_LOCK_PREFIX}${event.item.channel}:${event.item.ts}`; + const setupSuggestionHandled = await launchTaskSuggestionTaskWithContention({ + lockKey: setupSuggestionLockKey, + channelId: event.item.channel, messageTs: event.item.ts, + launch: () => + launchTaskSuggestionTaskFromReaction({ + teamId: context.teamId, + slack: context.slack, + reactionEvent: event, + ackEmoji: reactionNames.ackEmoji, + completionEmoji: reactionNames.completionEmoji, + }), }); - if (!sourceMessage) { + if (setupSuggestionHandled) { apiLogger.debug( - `[SlackWebhook] Summon reaction source message unavailable for ${event.item.channel}:${event.item.ts}`, + `[SlackWebhook] Setup suggestion reaction handled for ${event.item.channel}:${event.item.ts}`, ); return; } - const isRoomoteAuthoredBotMessage = - sourceMessage.user === context.slackInstallation.botUserId || - sourceMessage.app_id === context.slackInstallation.appId; - - if (isRoomoteAuthoredBotMessage) { - apiLogger.debug( - `[SlackWebhook] Ignoring summon reaction on Roomote-authored bot message ${event.item.channel}:${event.item.ts}`, - ); - return; - } - - if (sourceMessage.text.trim().length === 0 && !sourceMessage.files?.length) { - apiLogger.debug( - `[SlackWebhook] Ignoring summon reaction on empty source message ${event.item.channel}:${event.item.ts}`, - ); - return; - } - - await handleSlackEntryEvent({ - event: { - type: 'message', - channel: event.item.channel, - user: event.user, - text: sourceMessage.text, - ts: sourceMessage.ts, - thread_ts: sourceMessage.thread_ts ?? sourceMessage.ts, - app_id: sourceMessage.app_id, - files: sourceMessage.files, - attachments: sourceMessage.attachments, - }, - slackInstallation: context.slackInstallation as never, - slack: context.slack, - teamId: context.teamId, - ackEmoji: reactionNames.ackEmoji, - completionEmoji: reactionNames.completionEmoji, - skipThreadFollowupHandling: true, - }); + apiLogger.debug( + `[SlackWebhook] Reaction no-op for ${event.item.channel}:${event.item.ts}`, + ); } diff --git a/apps/api/src/handlers/slack/helpers/event-normalization.ts b/apps/api/src/handlers/slack/helpers/event-normalization.ts index 3064984a..6d93394e 100644 --- a/apps/api/src/handlers/slack/helpers/event-normalization.ts +++ b/apps/api/src/handlers/slack/helpers/event-normalization.ts @@ -20,17 +20,6 @@ export function isThumbsUpReaction(reaction: string): boolean { return THUMBS_UP_REACTIONS.has(normalizedReaction); } -export function isConfiguredSlackReaction( - reaction: string, - configuredEmoji: string | null | undefined, -): boolean { - if (!configuredEmoji) { - return false; - } - - return normalizeSlackReactionName(reaction) === configuredEmoji; -} - function coerceSlackWorkflowInputToString(value: unknown): string | undefined { if (typeof value === 'string') { const trimmed = value.trim(); diff --git a/apps/docs/AGENTS.md b/apps/docs/AGENTS.md index c253d7f3..db5bf6dc 100644 --- a/apps/docs/AGENTS.md +++ b/apps/docs/AGENTS.md @@ -11,7 +11,7 @@ Public, user-facing documentation: - setup and self-hosting - product concepts and how Roomote works - admin and configuration workflows (dashboard, environments, skills, - automations, integrations, vibes, personal settings) + automations, integrations, personal settings) - integrations and common user-facing tasks ## What does NOT belong here diff --git a/apps/docs/docs.json b/apps/docs/docs.json index d36d2bec..6e7c3ca3 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -113,7 +113,6 @@ "skills", "automations", "users", - "vibes", "anonymous-analytics", "personal-settings" ] diff --git a/apps/docs/vibes.mdx b/apps/docs/vibes.mdx deleted file mode 100644 index 0671de96..00000000 --- a/apps/docs/vibes.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Vibes -icon: rainbow -description: Tune Roomote Slack reactions, summon emoji, and team-wide tone settings. ---- - -Vibes controls the small signals that make Roomote feel like it belongs in -your team workflow. - -Use this page when you want to change how Roomote reacts in Slack, let -teammates start tasks with an emoji reaction, or adjust the tone Roomote uses -in team-facing messages. - -## What you can configure - -| Setting | What it controls | Example | -| ------------------------- | --------------------------------------------------------------------------- | ------------------------ | -| **Acknowledgement emoji** | The reaction Roomote uses to show it saw a Slack message | `eyes` | -| **Completion emoji** | The reaction Roomote can use when supported work finishes | `white_check_mark` | -| **Summon emoji** | The reaction teammates can add to an existing Slack message to start a task | `shipit` | -| **Style guidance** | Optional guidance for how Roomote should sound in messages | "Direct, concise, calm." | - -Use Slack emoji names, not pasted emoji characters. Roomote accepts names with -or without surrounding colons, so `shipit` and `:shipit:` both describe the -same Slack reaction. - -## Call Roomote with a reaction - -A summon emoji lets a teammate react to an existing Slack message and turn -that message into the starting point for a Roomote task. - -This is useful when: - -- someone reports a bug with enough context in a channel -- a teammate asks a codebase question that Roomote can investigate -- a thread contains a request you want Roomote to pick up without rewriting it - -Pick an emoji the team will not use casually. If the emoji is common, Roomote -may start tasks from reactions that were only meant as normal Slack feedback. -Tell the team what the summon emoji means before turning it on in busy -channels. - -## Choose reaction behavior - -The acknowledgement reaction is the quick "I saw this" signal. The completion -reaction is for supported completion moments where a Slack reaction is the -right confirmation. - -If teammates are missing Roomote's status updates, choose reactions that stand -out in your workspace. If channels feel too busy, keep the defaults or use -quieter custom emoji. - -## Add style guidance - -Use style guidance for tone, not operating policy. - -Good style guidance: - -```text -Keep status updates short and direct. Use plain language. Avoid hype. -``` - -Not-so-good style guidance: - -```text -Always approve PRs. -Never ask follow-up questions. -Use this secret token when tests fail. -``` - -Use [Agent Guidance](/agent-guidance) for team-wide work instructions, -and use [Environments](/environments) for repository-specific setup and -verification rules. - -## Download starter emoji - -The Vibes page includes a few starter Roomote emoji images you can download -and upload to Slack. Use them as a quick starting point if your team wants a -dedicated summon emoji instead of reusing an existing workspace reaction. - -## Common issues - -- **The summon reaction does not start a task.** Check that Slack is - connected, Roomote is in the channel, and the reaction name matches the - saved summon emoji. -- **Roomote reacts with the default emoji.** Save the new emoji name and try - again in a fresh Slack message. -- **The tone feels over-corrected.** Shorten the style guidance. A few clear - sentences work better than a long style guide. -- **A channel gets noisy.** Pick a less common summon emoji or ask the team to - use mentions for requests that need more context. diff --git a/apps/web/public/vibes/ideas/let-me-roomote-that-for-you.png b/apps/web/public/vibes/ideas/let-me-roomote-that-for-you.png deleted file mode 100644 index 4157573d2a7dcdd776393aa60f255c8463c91642..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18838 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 LNkvXXu0mjfa#Pb{ diff --git a/apps/web/public/vibes/ideas/roomote_right_black.png b/apps/web/public/vibes/ideas/roomote_right_black.png deleted file mode 100644 index 598dff330485c53d20979355c1f652d7bf5259a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4379 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 diff --git a/apps/web/public/vibes/ideas/roomote_up_black.png b/apps/web/public/vibes/ideas/roomote_up_black.png deleted file mode 100644 index 5c6f81c71b33473131ffaaa3eb31e1fc8543c840..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5200 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 RB4FSL(p1$}DZ^NW{2v$Vv9kaG diff --git a/apps/web/public/vibes/ideas/roomote_up_green.png b/apps/web/public/vibes/ideas/roomote_up_green.png deleted file mode 100644 index d76575c2490ce2d0cbe5a1f0f75654fa1a1e0b5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5172 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 diff --git a/apps/web/public/vibes/ideas/sparkles.png b/apps/web/public/vibes/ideas/sparkles.png deleted file mode 100644 index f98238f16db2a444e56c7be2545b9af3bebb0b4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1172 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7e6l0AZa85pY67#JE_7#My5g&JNk zFq9fFFuY1&V6d9Oz#v{QXIG#N0|Vos0G|+7paKp~W^Dt0pAf0+a@GC?M(YpT9=+po z^{vd(Qmcut)qEh7JvlJcN#WozV&8<|^ zG2~}sXWD+oAt+i#T8?wy6{kIy9EC*KV$u|2EhH(!Id6lxu91MCFk4}r`v3p`mG3#c1;!#{lDE6dRE~tIW*~>X#M9T6{S^x{ zr#|NoeFYt$^lDER#}JFtdxJuwnH)v-mgyYZp|C@3g+xQAM0f9vwH;k|XWW>3L)QMr z%-AWse``MPdGq(2W%2u&*4!WNb8zr*@p1BU_jgRmo}#2>r6%@M!2PmQ;L5J>>9eL$6n6D#fk#KCf`!$M#2*OMQ0aP0O8Zi#7G-ud}MvZ*!U-=Wl(=$ovCeuAp3s)7leLPb7O$y1!uHh4NxG`;&az&MoaozA3|{fwy8BpL zd-wVLw+XHl51mcVe7btkaE0HYPUm8+jKXIkepj~7iJvfi=J&ebHQs-^cj$|+`*gAN zX0QFS70owK1Z>~(d|laVxw<3Fr!VyTpVy!A{VQ)BYjTabguTuOaXZF@4cQHL@}`(l#)#GBD_ ({ - VibesSettingsPage: () =>
Vibes Settings Page
, -})); - -import Page from './page'; -import { render, screen } from '@testing-library/react'; - -describe('settings vibes page', () => { - it('renders the vibes settings page wrapper', () => { - render(); - - expect(screen.getByText('Vibes Settings Page')).toBeInTheDocument(); - }); -}); diff --git a/apps/web/src/app/(authenticated)/settings/vibes/page.tsx b/apps/web/src/app/(authenticated)/settings/vibes/page.tsx deleted file mode 100644 index db9c1ee2..00000000 --- a/apps/web/src/app/(authenticated)/settings/vibes/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { VibesSettingsPage } from '@/components/settings/pages/VibesSettingsPage'; - -export default function Page() { - return ; -} diff --git a/apps/web/src/components/settings/SettingsShell.client.test.tsx b/apps/web/src/components/settings/SettingsShell.client.test.tsx index faf27e93..94d9f440 100644 --- a/apps/web/src/components/settings/SettingsShell.client.test.tsx +++ b/apps/web/src/components/settings/SettingsShell.client.test.tsx @@ -54,7 +54,6 @@ vi.mock('@/components/system', async () => { Label: ({ children }: { children: ReactNode }) => , PlugIcon: Icon, GraduationCap: Icon, - Rainbow: Icon, ScrollText: Icon, Select: ({ children }: { children: ReactNode }) =>
{children}
, SelectContent: ({ children }: { children: ReactNode }) => ( @@ -101,7 +100,6 @@ describe('SettingsShell', () => { ).toBeInTheDocument(); expect(screen.getByRole('link', { name: /users/i })).toBeInTheDocument(); expect(screen.getByRole('link', { name: /skills/i })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: /vibes/i })).toBeInTheDocument(); expect( screen.getByText( 'Enable deployment integrations. Individual users can optionally link their own accounts when an integration supports it.', diff --git a/apps/web/src/components/settings/VibesSettings.client.test.tsx b/apps/web/src/components/settings/VibesSettings.client.test.tsx deleted file mode 100644 index 48fd5ce3..00000000 --- a/apps/web/src/components/settings/VibesSettings.client.test.tsx +++ /dev/null @@ -1,585 +0,0 @@ -import type { - ButtonHTMLAttributes, - ChangeEvent, - FocusEvent, - HTMLAttributes, - InputHTMLAttributes, - LabelHTMLAttributes, - ReactNode, - SVGProps, - TextareaHTMLAttributes, -} from 'react'; -import { - act, - fireEvent, - render, - screen, - waitFor, -} from '@testing-library/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -const { - inputPropsById, - textareaPropsById, - mockSettingsState, - mockUpdateVibesSettings, - toastErrorMock, - toastSuccessMock, -} = vi.hoisted(() => ({ - inputPropsById: { - current: {} as Record>, - }, - textareaPropsById: { - current: {} as Record>, - }, - mockSettingsState: { - current: { - slackSummonEmoji: null as string | null, - slackAckEmoji: 'eyes', - slackCompletionEmoji: 'white_check_mark', - styleGuidance: null as string | null, - defaults: { - slackAckEmoji: 'eyes', - slackCompletionEmoji: 'white_check_mark', - }, - }, - }, - mockUpdateVibesSettings: vi.fn( - async (input: { - slackSummonEmoji?: string | null; - slackAckEmoji?: string; - slackCompletionEmoji?: string; - styleGuidance?: string | null; - }): Promise< - | { - success: true; - settings: typeof mockSettingsState.current; - } - | { - success: false; - fieldErrors: Partial< - Record< - 'slackAckEmoji' | 'slackCompletionEmoji' | 'styleGuidance', - string - > - >; - } - > => { - const normalize = (value: string | null | undefined) => { - const trimmed = value - ?.trim() - .replace(/^:+|:+$/g, '') - .toLowerCase(); - return trimmed ? trimmed : null; - }; - - if ( - Object.prototype.hasOwnProperty.call(input, 'slackAckEmoji') && - !normalize(input.slackAckEmoji) - ) { - return { - success: false as const, - fieldErrors: { - slackAckEmoji: 'Acknowledgement emoji is required.', - }, - }; - } - - if ( - Object.prototype.hasOwnProperty.call(input, 'slackCompletionEmoji') && - !normalize(input.slackCompletionEmoji) - ) { - return { - success: false as const, - fieldErrors: { - slackCompletionEmoji: 'Completion emoji is required.', - }, - }; - } - - mockSettingsState.current = { - ...mockSettingsState.current, - ...(Object.prototype.hasOwnProperty.call(input, 'slackSummonEmoji') - ? { slackSummonEmoji: normalize(input.slackSummonEmoji) } - : {}), - ...(Object.prototype.hasOwnProperty.call(input, 'slackAckEmoji') - ? { slackAckEmoji: normalize(input.slackAckEmoji) ?? 'eyes' } - : {}), - ...(Object.prototype.hasOwnProperty.call(input, 'slackCompletionEmoji') - ? { - slackCompletionEmoji: - normalize(input.slackCompletionEmoji) ?? 'white_check_mark', - } - : {}), - ...(Object.prototype.hasOwnProperty.call(input, 'styleGuidance') - ? { styleGuidance: input.styleGuidance?.trim() || null } - : {}), - }; - - return { - success: true as const, - settings: mockSettingsState.current, - }; - }, - ), - toastErrorMock: vi.fn(), - toastSuccessMock: vi.fn(), -})); - -vi.mock('sonner', () => ({ - toast: { - error: toastErrorMock, - success: toastSuccessMock, - }, -})); - -vi.mock('@/trpc/client', () => ({ - useTRPC: () => ({ - vibes: { - get: { - queryKey: () => ['vibes'], - queryOptions: () => ({ - queryKey: ['vibes'], - queryFn: async () => mockSettingsState.current, - }), - }, - update: { - mutationOptions: (options = {}) => ({ - mutationFn: mockUpdateVibesSettings, - ...options, - }), - }, - }, - }), -})); - -vi.mock('@/components/settings', () => ({ - Section: ({ - title, - children, - footer, - }: { - title: ReactNode; - children: ReactNode; - footer?: ReactNode; - }) => ( -
-

{title}

-
{children}
- {footer ?
{footer}
: null} -
- ), -})); - -vi.mock('@/components/system', () => ({ - AlertCircle: (props: SVGProps) => , - Button: ({ - children, - ...props - }: { children: ReactNode } & ButtonHTMLAttributes) => ( - - ), - Check: (props: SVGProps) => , - MessageSquareHeart: (props: SVGProps) => , - Input: (props: InputHTMLAttributes) => { - if (props.id) { - inputPropsById.current[props.id] = props; - } - - return ; - }, - Label: ({ - children, - ...props - }: { children: ReactNode } & LabelHTMLAttributes) => ( - - ), - RotateCcw: (props: SVGProps) => , - Skeleton: (props: HTMLAttributes) =>
, - Smile: (props: SVGProps) => , - Spinner: (props: HTMLAttributes) => , - Sun: (props: SVGProps) => , - Textarea: (props: TextareaHTMLAttributes) => { - if (props.id) { - textareaPropsById.current[props.id] = props; - } - - return