feat: add native runtime customization

OpenCode and Continue customization was previously planned but unavailable, and Runtime-native capabilities were not represented consistently across providers. GoodBuddy now provides secure Main-owned customization settings, truthful native inventories, OpenCode Agents and Commands, Continue Rules and Prompts, DSH Web Search/Fetch, MCP Prompt and Resource metadata, and manual compaction where supported.

Native capabilities are presented in eleven accessible tabs with Tools separated from Commands, LSP, and Formatters. Tool source and Ask/Execute availability are explicit, external OpenCode remains connection-only, Continue reports unsupported static tool discovery instead of advertising unreachable Skills, and disposable inventory probes avoid retaining background runtimes.

Ask remains read-only at the Runtime boundary, Execute keeps the existing authorization controls, and credentials remain confined to Main.

Release note: 新增 OpenCode、Continue 与 DeepSeek Harness 的 Runtime 原生定制与真实能力清单;工具来源、Ask/Execute 可用性、上下文压缩和 MCP 元数据现在可清晰查看,同时继续保持 Main 进程凭据保护与现有权限边界。
This commit is contained in:
mesalogo
2026-08-16 17:08:46 +08:00
parent ff61b5f81d
commit b56b0f8826
55 changed files with 9059 additions and 433 deletions
+91 -2
View File
@@ -1342,8 +1342,10 @@ export function McpSettingsSection({
</div>
<span className="mcp-server-card__summary">
{result
? t('mcp.builtin.toolCount', {
count: result.toolCount
? t('mcp.custom.contentCounts', {
tools: result.toolCount,
prompts: result.promptCount ?? 0,
resources: result.resourceCount ?? 0
})
: t('mcp.custom.toolsUndetected')}
<ChevronDown
@@ -1466,6 +1468,93 @@ export function McpSettingsSection({
</p>
)}
</section>
<section
aria-label={t('mcp.custom.promptsAriaLabel', {
name: server.name
})}
className="mcp-server-tools"
>
<div className="mcp-server-tools__heading">
<strong>{t('mcp.custom.prompts')}</strong>
<small>
{result.promptsSupported
? t('mcp.custom.promptCount', {
count: result.promptCount ?? 0
})
: t('mcp.custom.notSupported')}
</small>
</div>
{result.prompts?.length ? (
<ul>
{result.prompts.map((prompt) => (
<li key={prompt.name}>
<div>
<code>{prompt.name}</code>
</div>
{prompt.description && (
<p>{prompt.description}</p>
)}
{prompt.arguments.length > 0 && (
<small>
{t('mcp.custom.promptArguments', {
names: prompt.arguments
.map((argument) =>
argument.required
? `${argument.name}*`
: argument.name
)
.join(', ')
})}
</small>
)}
</li>
))}
</ul>
) : result.promptsSupported ? (
<p className="settings-empty">
{t('mcp.custom.noPrompts')}
</p>
) : null}
</section>
<section
aria-label={t('mcp.custom.resourcesAriaLabel', {
name: server.name
})}
className="mcp-server-tools"
>
<div className="mcp-server-tools__heading">
<strong>{t('mcp.custom.resources')}</strong>
<small>
{result.resourcesSupported
? t('mcp.custom.resourceCount', {
count: result.resourceCount ?? 0
})
: t('mcp.custom.notSupported')}
</small>
</div>
{result.resources?.length ? (
<ul>
{result.resources.map((resource) => (
<li key={`${resource.uri}\0${resource.name}`}>
<div>
<strong>{resource.name}</strong>
{resource.mimeType && (
<small>{resource.mimeType}</small>
)}
</div>
<code>{resource.uri}</code>
{resource.description && (
<p>{resource.description}</p>
)}
</li>
))}
</ul>
) : result.resourcesSupported ? (
<p className="settings-empty">
{t('mcp.custom.noResources')}
</p>
) : null}
</section>
</>
) : (
<p className="settings-empty">