@@ -2108,17 +2128,6 @@ export function SettingsPanel({
- )}
{agentRuntimeType === 'deepseek-harness' && (
@@ -2216,23 +2225,25 @@ export function SettingsPanel({
- )}
- {agentRuntimeType === 'deepseek-harness' && (
-
- )}
- {agentRuntimeType === 'deepseek-harness' && (
-
)}
>
)}
+
+
+
+ {activeTab === 'runtime' &&
+ agentRuntimeType === 'deepseek-harness' && (
+
+ )}
{activeTab === 'model' && (
<>
diff --git a/src/renderer/src/WorkspacePrimitives.test.tsx b/src/renderer/src/WorkspacePrimitives.test.tsx
index 4f108ea..8ea26e1 100644
--- a/src/renderer/src/WorkspacePrimitives.test.tsx
+++ b/src/renderer/src/WorkspacePrimitives.test.tsx
@@ -174,6 +174,45 @@ describe('WorkspacePrimitives', () => {
)
})
+ it('keeps full-page settings navigation readable and content fluid', () => {
+ expect(stylesheet).toMatch(
+ /\.settings-page \.settings-panel__body\s*\{[^}]*grid-template-columns:\s*190px minmax\(0,\s*1fr\);/u
+ )
+ expect(stylesheet).toMatch(
+ /\.settings-page \.settings-panel__content\s*\{[^}]*width:\s*min\(100%,\s*var\(--content-standard\)\);/u
+ )
+ expect(stylesheet).toMatch(
+ /\.settings-page \.settings-tabs button strong\s*\{[^}]*font-size:\s*var\(--font-body\);/u
+ )
+ expect(stylesheet).toMatch(
+ /\.settings-page \.settings-tabs button small\s*\{[^}]*font-size:\s*var\(--font-caption\);/u
+ )
+ })
+
+ it('keeps Runtime customization hierarchy and dangerous actions clear', () => {
+ expect(stylesheet).toMatch(
+ /\.runtime-customization-section__header strong\s*\{[^}]*font-size:\s*var\(--font-section-title\);/u
+ )
+ expect(stylesheet).toMatch(
+ /\.runtime-customization-editor\s*\{[^}]*padding:\s*0;[^}]*border:\s*0;[^}]*background:\s*transparent;/u
+ )
+ expect(stylesheet).toMatch(
+ /\.runtime-native-inventory__status\s*\{[^}]*display:\s*flex;[^}]*min-height:\s*42px;/u
+ )
+ expect(stylesheet).not.toContain(
+ '.runtime-native-inventory__header'
+ )
+ expect(stylesheet).toMatch(
+ /\.runtime-customization-section__dirty\s*\{[^}]*display:\s*flex;[^}]*justify-content:\s*space-between;/u
+ )
+ expect(stylesheet).toMatch(
+ /\.danger-ghost\s*\{[^}]*color:\s*var\(--danger\);[^}]*font-size:\s*var\(--font-caption\);/u
+ )
+ expect(stylesheet).toMatch(
+ /\.danger-ghost:disabled\s*\{[^}]*color:\s*var\(--text-muted\);[^}]*cursor:\s*not-allowed;/u
+ )
+ })
+
it('keeps knowledge settings cards separated as page sections', () => {
expect(stylesheet).toMatch(
/\.knowledge-settings\s*\{[^}]*display:\s*grid;[^}]*width:\s*min\(920px,\s*100%\);[^}]*gap:\s*var\(--space-6\);/u
diff --git a/src/renderer/src/i18n/locales/en-US/settings.ts b/src/renderer/src/i18n/locales/en-US/settings.ts
index fb15377..ae91918 100644
--- a/src/renderer/src/i18n/locales/en-US/settings.ts
+++ b/src/renderer/src/i18n/locales/en-US/settings.ts
@@ -196,48 +196,41 @@ export const settings = {
permissions:
'Choose Ask or Execute in a conversation. Ask can use only read-only capabilities allowed by the current Runtime. Execute can use enabled tools, and records tool calls in Activity.',
customization: {
- title: 'Native Runtime customization',
+ title: 'Capabilities and defaults',
description:
- 'Manage capabilities supplied by this Runtime. The inventory excludes Skills assigned by GoodBuddy and temporary GoodBuddy MCP servers.',
- refresh: 'Refresh native Runtime capabilities',
+ 'Configure this Runtime’s defaults and inspect its built-in capabilities. The inventory excludes Skills assigned by GoodBuddy and temporary MCP servers.',
+ refresh: 'Refresh capability inventory',
retry: 'Retry',
- loading: 'Loading native Runtime capabilities…',
- save: 'Save Runtime customization',
- saving: 'Saving…',
- saved: 'Runtime customization saved',
+ loading: 'Loading capability inventory…',
+ unsaved:
+ 'There are unsaved Runtime customization changes. Use “Save settings” at the top right to save everything together.',
+ discard: 'Discard customization changes',
+ unsavedClose:
+ 'Save or discard the Runtime customization changes before closing Settings.',
enabled: 'Enabled',
disabled: 'Disabled',
errors: {
- load: 'Could not load native Runtime capabilities',
+ load: 'Could not load capability inventory',
save: 'Could not save Runtime customization'
},
inventory: {
- tabsAriaLabel: 'Native Runtime capabilities',
- nativeOnly:
- 'Only Runtime-native configuration and plugin capabilities are shown. GoodBuddy assignments are excluded.',
- status: {
- available: 'Native Runtime capabilities available',
- partial: 'Native Runtime capabilities partially available',
- unavailable: 'Native Runtime capabilities unavailable',
- 'connection-only': 'Runtime connection only',
- unsupported: 'Native inventory is not supported'
- },
- agents: 'Native Agents',
- tools: 'Native Tools',
- skills: 'Native Skills',
- mcp: 'Native MCP',
+ tabsAriaLabel: 'Capability inventory',
+ agents: 'Agents',
+ tools: 'Tools',
+ skills: 'Skills',
+ mcp: 'MCP',
commands: 'Commands',
- rules: 'Native Rules',
- prompts: 'Prompt templates',
- resources: 'MCP Resources',
- lsp: 'LSP status',
- formatters: 'Formatter status',
+ rules: 'Rules',
+ prompts: 'Prompts',
+ resources: 'Resources',
+ lsp: 'LSP',
+ formatters: 'Formatters',
empty: 'None detected',
emptyDescription:
- 'The current Runtime did not report any native capabilities in this category.',
+ 'The current Runtime did not report any capabilities in this category.',
unsupported: 'Not supported by this Runtime',
toolsUnsupported:
- 'This Runtime does not support static discovery of native Tools',
+ 'This Runtime does not support static discovery of Tools',
toolModes: 'Ask: {{ask}} · Execute: {{execute}}',
toolKind: {
read: 'Read',
@@ -286,12 +279,13 @@ export const settings = {
title: 'Context and compaction'
},
opencode: {
- defaultAgent: 'Default Runtime Agent',
+ defaultAgent: 'Default Agent',
runtimeDefault: 'Let OpenCode choose',
agentDescription:
'Applies only to GoodBuddy-managed local OpenCode. A conversation can still select a different Agent.'
},
continue: {
+ editorTitle: 'Continue configuration presets',
editPreset: 'Edit configuration preset',
noPresets: 'No presets',
addPreset: 'Add preset',
@@ -321,8 +315,9 @@ export const settings = {
promptContent: '{{name}} content',
removePrompt: 'Delete Prompt {{name}}',
mergedRules: 'View {{count}} merged Rules',
+ emptyPresetTitle: 'No Continue presets yet',
emptyPreset:
- 'Add a preset to manage Continue Rules and Prompt templates.'
+ 'Use “Add preset” above to create Rules and Prompt templates.'
}
},
advanced: 'Advanced settings',
diff --git a/src/renderer/src/i18n/locales/zh-CN/settings.ts b/src/renderer/src/i18n/locales/zh-CN/settings.ts
index 836eb44..6cc0114 100644
--- a/src/renderer/src/i18n/locales/zh-CN/settings.ts
+++ b/src/renderer/src/i18n/locales/zh-CN/settings.ts
@@ -175,46 +175,39 @@ export const settings = {
permissions:
'对话时可选择 Ask 或 Execute。Ask 仅可调用当前 Runtime 允许的只读能力;Execute 可调用已启用工具,调用过程会记录到活动。',
customization: {
- title: 'Runtime 原生定制',
+ title: '能力与默认配置',
description:
- '管理当前 Runtime 自己提供的能力;清单不包含 GoodBuddy 分配的 Skills 或临时 MCP。',
- refresh: '刷新 Runtime 原生能力',
+ '设置当前 Runtime 的默认项并查看自带能力;清单不包含 GoodBuddy 分配的 Skills 或临时 MCP。',
+ refresh: '刷新能力清单',
retry: '重试',
- loading: '正在读取 Runtime 原生能力…',
- save: '保存 Runtime 定制',
- saving: '正在保存…',
- saved: '已保存 Runtime 定制设置',
+ loading: '正在读取能力清单…',
+ unsaved:
+ '有未保存的 Runtime 定制更改,点击页面右上角“保存设置”统一保存。',
+ discard: '撤销定制更改',
+ unsavedClose:
+ '请先保存或撤销 Runtime 定制更改,再关闭设置中心。',
enabled: '已启用',
disabled: '已停用',
errors: {
- load: '读取 Runtime 原生能力失败',
+ load: '读取能力清单失败',
save: '保存 Runtime 定制失败'
},
inventory: {
- tabsAriaLabel: 'Runtime 原生能力',
- nativeOnly:
- '这里只显示 Runtime 原生配置与插件能力,不显示 GoodBuddy 分配内容。',
- status: {
- available: 'Runtime 原生能力可用',
- partial: 'Runtime 原生能力部分可用',
- unavailable: 'Runtime 原生能力不可用',
- 'connection-only': '仅确认 Runtime 连接',
- unsupported: 'Runtime 不支持原生能力清单'
- },
- agents: '原生 Agents',
- tools: '原生 Tools',
- skills: '原生 Skills',
- mcp: '原生 MCP',
+ tabsAriaLabel: '能力清单',
+ agents: 'Agents',
+ tools: 'Tools',
+ skills: 'Skills',
+ mcp: 'MCP',
commands: 'Commands',
- rules: '原生 Rules',
- prompts: 'Prompt 模板',
- resources: 'MCP Resources',
- lsp: 'LSP 状态',
- formatters: 'Formatter 状态',
+ rules: 'Rules',
+ prompts: 'Prompts',
+ resources: 'Resources',
+ lsp: 'LSP',
+ formatters: 'Formatters',
empty: '未发现',
- emptyDescription: '当前 Runtime 未报告此类别中的可用原生能力。',
+ emptyDescription: '当前 Runtime 未报告此类别中的可用能力。',
unsupported: '当前 Runtime 不支持',
- toolsUnsupported: '当前 Runtime 不支持静态发现原生 Tools',
+ toolsUnsupported: '当前 Runtime 不支持静态发现 Tools',
toolModes: 'Ask:{{ask}} · Execute:{{execute}}',
toolKind: {
read: '读取',
@@ -263,12 +256,13 @@ export const settings = {
title: '上下文与压缩'
},
opencode: {
- defaultAgent: '默认 Runtime Agent',
+ defaultAgent: '默认 Agent',
runtimeDefault: '由 OpenCode 选择',
agentDescription:
'只影响 GoodBuddy 管理的本机 OpenCode;聊天中仍可为当前对话单独选择。'
},
continue: {
+ editorTitle: 'Continue 配置预设',
editPreset: '编辑配置预设',
noPresets: '尚无预设',
addPreset: '添加预设',
@@ -295,7 +289,8 @@ export const settings = {
promptContent: '{{name}} 内容',
removePrompt: '删除 Prompt {{name}}',
mergedRules: '查看最终合并的 {{count}} 条 Rule',
- emptyPreset: '添加一个预设后即可管理 Rules 与 Prompt 模板。'
+ emptyPresetTitle: '还没有 Continue 预设',
+ emptyPreset: '使用上方“添加预设”创建 Rules 与 Prompt 模板。'
}
},
advanced: '高级设置',
diff --git a/src/renderer/src/styles.css b/src/renderer/src/styles.css
index 4c1556f..bfedf6a 100644
--- a/src/renderer/src/styles.css
+++ b/src/renderer/src/styles.css
@@ -4949,7 +4949,7 @@ button > svg {
padding: 24px 32px 32px;
overflow: hidden;
align-items: stretch;
- grid-template-columns: 190px minmax(0, 760px);
+ grid-template-columns: 190px minmax(0, 1fr);
justify-content: start;
gap: 28px;
}
@@ -4986,6 +4986,7 @@ button > svg {
}
.settings-page .settings-panel__content {
+ width: min(100%, var(--content-standard));
min-height: 0;
padding-right: var(--space-1);
overflow-y: auto;
@@ -5048,9 +5049,16 @@ button > svg {
text-align: left;
}
+.settings-page .settings-tabs button strong {
+ font-size: var(--font-body);
+ line-height: 1.35;
+}
+
.settings-page .settings-tabs button small {
display: block;
margin-top: 3px;
+ font-size: var(--font-caption);
+ line-height: 1.35;
}
.settings-page .settings-tabs button[aria-selected='true'] {
@@ -5306,14 +5314,25 @@ button > svg {
.runtime-customization-section__header > div {
min-width: 0;
-}
-
-.runtime-customization-section__header > div {
+ display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--space-1);
}
+.runtime-customization-section__header strong {
+ color: var(--text-primary);
+ font-size: var(--font-section-title);
+ font-weight: 650;
+ line-height: 1.4;
+}
+
+.runtime-customization-section__header small {
+ color: var(--text-muted);
+ font-size: var(--font-caption);
+ line-height: 1.5;
+}
+
.runtime-customization-section__error {
display: flex;
align-items: center;
@@ -5332,18 +5351,22 @@ button > svg {
.runtime-customization-editor {
min-width: 0;
margin: 0;
- padding: var(--space-4);
- border: 1px solid var(--border-default);
- border-radius: var(--radius-card);
- background: var(--surface-subtle);
+ padding: 0;
+ border: 0;
+ background: transparent;
}
.runtime-native-inventory__status {
- display: grid;
+ display: flex;
+ align-items: center;
+ min-height: 42px;
padding: var(--space-3);
border: 1px solid var(--border-default);
border-radius: var(--radius-control);
- gap: var(--space-1);
+ color: var(--text-secondary);
+ font-size: var(--font-body);
+ line-height: 1.5;
+ overflow-wrap: anywhere;
}
.runtime-native-inventory__status--available {
@@ -5363,13 +5386,16 @@ button > svg {
background: var(--warning-subtle);
}
-.runtime-native-inventory__status small {
+.runtime-customization-section__dirty {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-top: var(--space-3);
+ border-top: 1px solid var(--border-subtle);
color: var(--text-secondary);
- overflow-wrap: anywhere;
-}
-
-.runtime-customization-section__actions {
- justify-content: flex-end;
+ flex-wrap: wrap;
+ font-size: var(--font-caption);
+ gap: var(--space-3);
}
.runtime-native-inventory > .page-tabs {
@@ -7419,6 +7445,39 @@ details.settings-section > :not(summary) + :not(summary) {
color: var(--text-secondary);
}
+.danger-ghost {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-height: var(--control-height);
+ padding: 0 var(--space-3);
+ border: 1px solid transparent;
+ border-radius: var(--radius-control);
+ background: transparent;
+ color: var(--danger);
+ cursor: pointer;
+ font-size: var(--font-caption);
+ font-weight: 650;
+ gap: var(--space-2);
+}
+
+.danger-ghost:hover {
+ border-color: var(--danger-border);
+ background: var(--danger-subtle);
+}
+
+.danger-ghost:disabled {
+ border-color: transparent;
+ background: transparent;
+ color: var(--text-muted);
+ cursor: not-allowed;
+ opacity: 0.65;
+}
+
+.danger-ghost.icon-button {
+ padding: 0;
+}
+
.conversation-row {
position: relative;
display: flex;
diff --git a/src/shared/assistant-contracts.ts b/src/shared/assistant-contracts.ts
index 985d7ab..650edca 100644
--- a/src/shared/assistant-contracts.ts
+++ b/src/shared/assistant-contracts.ts
@@ -251,22 +251,31 @@ export const conversationContextMetricsSchema = z
.object({
runtimeSelectionKey: z.string().trim().min(1).max(1_000),
contextTokens: z.number().int().nonnegative().max(50_000_000),
+ source: z.enum(['provider', 'estimated']),
+ basis: z.enum(['model-call', 'conversation']).optional(),
+ // Accepted only to migrate snapshots saved before display settings
+ // were derived from the current Runtime configuration.
effectiveTriggerTokens: z
.number()
.int()
.nonnegative()
- .max(10_000_000),
+ .max(10_000_000)
+ .optional(),
contextWindowTokens: z
.number()
.int()
.nonnegative()
.max(10_000_000)
.optional(),
- compressionEnabled: z.boolean(),
- source: z.enum(['provider', 'estimated']),
- basis: z.enum(['model-call', 'conversation']).optional()
+ compressionEnabled: z.boolean().optional(),
})
.strict()
+ .transform((metrics) => ({
+ runtimeSelectionKey: metrics.runtimeSelectionKey,
+ contextTokens: metrics.contextTokens,
+ source: metrics.source,
+ basis: metrics.basis
+ }))
export type ConversationContextMetrics = z.infer<
typeof conversationContextMetricsSchema