Merge remote-tracking branch 'origin/main' into port-2619

# Conflicts:
#	packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx
This commit is contained in:
Bohdan Triapitsyn
2026-08-29 00:26:49 +03:00
1318 changed files with 118125 additions and 30528 deletions
+69 -1
View File
@@ -1,4 +1,5 @@
import type { SidebarSection } from '@/constants/sidebar';
import type { IconName } from '@/components/icon/icons';
export type SettingsPageSlug =
| 'home'
@@ -24,7 +25,8 @@ export type SettingsPageSlug =
| 'notifications'
| 'voice'
| 'tunnel'
| 'about';
| 'about'
| 'integrations';
type SettingsPageGroup =
| 'general'
@@ -200,6 +202,7 @@ export const SETTINGS_PAGE_METADATA: readonly SettingsPageMeta[] = [
{ slug: 'voice', title: 'Voice', group: 'general', kind: 'single', keywords: ['tts', 'speech', 'voice'], isAvailable: (ctx) => !ctx.isVSCode },
{ slug: 'tunnel', title: 'External Tunnel', group: 'projects', kind: 'single', keywords: ['tunnel', 'external', 'cloudflare', 'qr', 'remote', 'mobile', 'share'], isAvailable: (ctx) => !ctx.isVSCode },
{ slug: 'about', title: 'About', group: 'general', kind: 'single', keywords: ['about', 'version', 'updates', 'release', 'changelog'], isAvailable: (ctx) => ctx.isMobile && !ctx.isVSCode },
{ slug: 'integrations', title: 'Integrations', group: 'general', kind: 'single', keywords: ['integration', 'plugin', 'provider', 'oauth', 'claude', 'cursor', 'command code', 'connect', 'discord', 'telegram', 'messenger'] },
] as const;
const LEGACY_SIDEBAR_SECTION_TO_SETTINGS_SLUG: Record<SidebarSection, SettingsPageSlug> = {
@@ -237,3 +240,68 @@ export function resolveSettingsSlug(value: string | null | undefined): SettingsP
return 'home';
}
// Lives here (not in SettingsView) so light consumers such as the command
// palette can render settings entries without statically importing the whole
// settings surface into the eager startup graph.
export function getSettingsNavIcon(slug: SettingsPageSlug): IconName | null {
switch (slug) {
case 'general':
return 'settings-3';
case 'projects':
return 'folders';
case 'remote-instances':
return 'computer';
case 'appearance':
return 'palette';
case 'chat':
return 'chat-ai-3';
case 'magic-prompts':
return 'ai-generate-2';
case 'snippets':
return 'chat-thread';
case 'notifications':
return 'notification-3';
case 'shortcuts':
return 'command';
case 'sessions':
return 'chat-history';
case 'providers':
return 'cloud';
case 'agents':
return 'ai-agent';
case 'behavior':
return 'brain';
case 'commands':
return 'slash-commands-2';
case 'mcp':
return null;
case 'plugins':
return 'plug-2';
case 'skills.installed':
return 'book-open';
case 'skills.catalog':
return 'book';
case 'git':
return 'git-branch';
case 'integrations':
return 'plug';
case 'usage':
return 'bar-chart-2';
case 'voice':
return 'mic';
case 'tunnel':
return 'home-office';
case 'about':
return 'information';
case 'home':
return null;
default:
return 'robot-2';
}
}
@@ -0,0 +1,41 @@
import { describe, expect, test } from 'bun:test';
import type { I18nKey } from '@/lib/i18n/store';
import { buildSettingsSearchResults } from './search';
const t = (key: I18nKey): string => key;
const runtimeCtx = {
isVSCode: false,
isWeb: true,
isDesktop: false,
isMobile: false,
isDesktopLocalOrigin: false,
isMac: false,
isWindows: false,
isLinux: false,
isWindowsArm64: false,
};
describe('settings search', () => {
test('finds the Claude Code third-party integration', () => {
const results = buildSettingsSearchResults({
query: 'claude',
runtimeCtx,
t,
getPageTitle: (page) => page,
});
expect(results.some((result) => result.id === 'integrations.third-party.opencode-claude')).toBe(true);
});
test('finds third-party integrations by OpenChamber npm package names', () => {
const results = buildSettingsSearchResults({
query: '@openchamber/opencode-cursor',
runtimeCtx,
t,
getPageTitle: (page) => page,
});
expect(results.some((result) => result.id === 'integrations.third-party.opencode-cursor-oauth')).toBe(true);
});
});
+86 -22
View File
@@ -1,4 +1,5 @@
import type { I18nKey } from '@/lib/i18n/store';
import { useUIStore } from '@/stores/useUIStore';
import type { SettingsPageSlug, SettingsRuntimeContext } from './metadata';
import { getSettingsPageMeta } from './metadata';
@@ -49,7 +50,6 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
page: 'appearance',
titleKey: 'settings.openchamber.visual.field.weekStartsOn',
keywords: ['calendar', 'monday', 'sunday'],
isAvailable: (ctx) => !ctx.isVSCode,
},
{
id: 'appearance.light-theme',
@@ -65,14 +65,6 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
keywords: ['theme', 'color', 'dark mode'],
isAvailable: (ctx) => !ctx.isVSCode,
},
{
id: 'appearance.window-transparency',
page: 'appearance',
titleKey: 'settings.openchamber.visual.field.macVibrancy',
descriptionKey: 'settings.openchamber.visual.field.macVibrancyHint',
keywords: ['transparent', 'transparency', 'vibrancy', 'blur', 'macos', 'opaque'],
isAvailable: (ctx) => ctx.isDesktopLocalOrigin,
},
{
id: 'appearance.dock-badge',
page: 'appearance',
@@ -156,19 +148,20 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
descriptionKey: 'settings.openchamber.visual.field.autoSaveEnabledInfo',
keywords: ['editor', 'autosave', 'auto-save', 'files', 'save'],
},
{
id: 'appearance.expanded-editor-toolbar',
page: 'general',
titleKey: 'settings.openchamber.visual.field.expandedEditorToolbar',
keywords: ['editor', 'toolbar', 'tabs', 'docked', 'files'],
isAvailable: (ctx) => !ctx.isVSCode,
},
{
id: 'appearance.file-editor-keymap',
page: 'general',
titleKey: 'settings.openchamber.visual.field.fileEditorKeymap',
keywords: ['editor', 'vim', 'keymap'],
},
{
id: 'appearance.session-tabs',
page: 'general',
titleKey: 'settings.openchamber.visual.field.sessionTabsGroup',
descriptionKey: 'settings.openchamber.visual.field.sessionTabsInfo',
keywords: ['session', 'tabs', 'header', 'working set'],
isAvailable: (ctx) => !ctx.isMobile && !ctx.isVSCode,
},
{
id: 'appearance.terminal-quick-keys',
page: 'general',
@@ -184,6 +177,13 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
descriptionKey: 'settings.openchamber.visual.field.sendAnonymousUsageReportsHint',
keywords: ['telemetry', 'analytics'],
},
{
id: 'general.app-links',
page: 'general',
titleKey: 'settings.openchamber.appLinks.title',
descriptionKey: 'settings.openchamber.appLinks.info',
keywords: ['security', 'app link', 'deep link', 'scheme', 'protocol', 'obsidian', 'notion'],
},
{
id: 'chat.render-mode',
page: 'chat',
@@ -240,6 +240,19 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
titleKey: 'settings.openchamber.visual.section.reasoning',
keywords: ['thinking', 'traces'],
},
{
id: 'chat.streaming',
page: 'chat',
titleKey: 'settings.openchamber.visual.section.streaming',
keywords: ['stream', 'scroll'],
},
{
id: 'chat.streaming-auto-follow',
page: 'chat',
titleKey: 'settings.openchamber.visual.field.streamingAutoFollow',
descriptionKey: 'settings.openchamber.visual.field.streamingAutoFollowInfo',
keywords: ['autoscroll', 'auto-scroll', 'follow', 'stick to bottom', 'streaming'],
},
{
id: 'chat.sticky-user-header',
page: 'chat',
@@ -491,11 +504,29 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
{
id: 'sessions.agent-control-tool',
page: 'general',
titleKey: 'settings.openchamber.opencodeCli.field.agentControlTool',
descriptionKey: 'settings.openchamber.opencodeCli.field.agentControlToolInfo',
titleKey: 'settings.openchamber.tools.field.agentControlTool',
descriptionKey: 'settings.openchamber.tools.field.agentControlToolInfo',
keywords: ['agent', 'tool', 'orchestration', 'openchamber', 'sessions', 'schedule', 'control'],
isAvailable: (ctx) => !ctx.isVSCode,
},
{
id: 'sessions.agent-web-tool',
page: 'general',
titleKey: 'settings.openchamber.tools.field.agentWebTool',
descriptionKey: 'settings.openchamber.tools.field.agentWebToolInfo',
keywords: ['agent', 'tool', 'web', 'browser', 'page', 'preview', 'openchamber'],
isAvailable: (ctx) => !ctx.isVSCode,
},
{
id: 'sessions.agent-memory-tool',
page: 'general',
titleKey: 'settings.openchamber.tools.field.agentMemoryTool',
descriptionKey: 'settings.openchamber.tools.field.agentMemoryToolInfo',
keywords: ['agent', 'tool', 'memory', 'remember', 'recall', 'preferences', 'openchamber'],
// Unreleased: searching for a setting that is not rendered would take the
// user to an empty spot on the page.
isAvailable: (ctx) => !ctx.isVSCode && useUIStore.getState().agentMemoryFeatureAvailable,
},
{
id: 'git.github-account',
page: 'git',
@@ -528,11 +559,11 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
keywords: ['ignored', 'files', 'gitignore'],
},
{
id: 'usage.header-menu',
id: 'usage.work-status-panel',
page: 'usage',
titleKey: 'settings.usage.page.options.showInHeader',
descriptionKey: 'settings.usage.page.options.showInHeaderTooltip',
keywords: ['quota', 'header', 'dropdown'],
titleKey: 'settings.usage.page.options.showInWorkStatus',
descriptionKey: 'settings.usage.page.options.showInWorkStatusTooltip',
keywords: ['quota', 'work', 'status', 'panel'],
},
{
id: 'usage.model-quotas',
@@ -546,6 +577,18 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
titleKey: 'settings.projects.page.field.projectName',
keywords: ['label', 'display name', 'project metadata'],
},
{
id: 'projects.default-model',
page: 'projects',
titleKey: 'settings.projects.page.field.projectModel',
keywords: ['model', 'default', 'new chat', 'project metadata'],
},
{
id: 'projects.default-thinking',
page: 'projects',
titleKey: 'settings.projects.page.field.projectThinking',
keywords: ['thinking', 'variant', 'reasoning', 'effort', 'model', 'project metadata'],
},
{
id: 'projects.accent-color',
page: 'projects',
@@ -940,6 +983,27 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
keywords: ['background', 'push'],
isAvailable: (ctx) => ctx.isWeb && !ctx.isDesktop && !ctx.isVSCode,
},
{
id: 'integrations.third-party',
page: 'integrations',
titleKey: 'settings.integrations.thirdParty.title',
keywords: ['plugin', 'provider', 'oauth', 'install', 'update', 'remove'],
},
{
id: 'integrations.third-party.opencode-claude',
page: 'integrations',
titleKey: 'settings.integrations.thirdParty.opencodeClaude.name',
descriptionKey: 'settings.integrations.thirdParty.opencodeClaude.description',
keywords: ['claude', 'anthropic', 'claude code', 'pro', 'max', 'agent sdk', '@openchamber/opencode-claude'],
},
{
id: 'integrations.third-party.opencode-cursor-oauth',
page: 'integrations',
titleKey: 'settings.integrations.thirdParty.opencodeCursorOauth.name',
descriptionKey: 'settings.integrations.thirdParty.opencodeCursorOauth.description',
keywords: ['cursor', 'oauth', 'subscription', 'openai compatible', '@openchamber/opencode-cursor'],
},
] as const;
interface BuildSettingsSearchResultsOptions {