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
+67 -6
View File
@@ -78,6 +78,67 @@ afterEach(async () => {
})
describe('RuntimeSettingsStore', () => {
it('migrates version 17 to empty Runtime customization', async () => {
const { filePath, store } = await createStore()
await store.update(settings())
const previous = JSON.parse(
await readFile(filePath, 'utf8')
) as Record<string, unknown>
previous.version = 17
Reflect.deleteProperty(previous, 'runtimeCustomization')
await writeFile(filePath, JSON.stringify(previous))
const migrated = new RuntimeSettingsStore(
filePath,
cipher
)
await expect(migrated.getRuntimeCustomization()).resolves.toEqual({
opencode: {},
continue: { presets: [] }
})
})
it('persists validated Runtime customization independently', async () => {
const { store } = await createStore()
const presetId = '00000000-0000-4000-8000-000000000071'
const ruleId = '00000000-0000-4000-8000-000000000072'
const promptId = '00000000-0000-4000-8000-000000000073'
const customization = {
opencode: { defaultAgent: 'build' },
continue: {
defaultPresetId: presetId,
presets: [
{
id: presetId,
name: '代码审查',
rules: [
{
id: ruleId,
name: '只报告可复现问题',
content: 'Only report reproducible findings.',
enabled: true
}
],
prompts: [
{
id: promptId,
name: '审查变更',
prompt: 'Review the current changes.'
}
]
}
]
}
}
await expect(
store.updateRuntimeCustomization(customization)
).resolves.toEqual(customization)
await expect(store.getRuntimeCustomization()).resolves.toEqual(
customization
)
})
it('migrates version 16 to disabled default context compression', async () => {
const { filePath, store } = await createStore()
await store.update(settings())
@@ -390,7 +451,7 @@ describe('RuntimeSettingsStore', () => {
const persisted = JSON.parse(
await readFile(filePath, 'utf8')
) as Record<string, unknown>
expect(persisted.version).toBe(17)
expect(persisted.version).toBe(18)
expect(persisted).not.toHaveProperty(
'deepseekHarnessBinaryPath'
)
@@ -669,7 +730,7 @@ describe('RuntimeSettingsStore', () => {
const persisted = JSON.parse(await readFile(filePath, 'utf8')) as {
version: number
}
expect(persisted.version).toBe(17)
expect(persisted.version).toBe(18)
})
it('migrates version 11 and removes the obsolete intranet toggle', async () => {
@@ -689,7 +750,7 @@ describe('RuntimeSettingsStore', () => {
version: number
intranetCompatibilityEnabled?: boolean
}
expect(persisted.version).toBe(17)
expect(persisted.version).toBe(18)
expect(persisted).not.toHaveProperty('intranetCompatibilityEnabled')
})
@@ -1278,7 +1339,7 @@ describe('RuntimeSettingsStore', () => {
version: number
modelProfiles: Array<Record<string, unknown>>
}
expect(persisted.version).toBe(17)
expect(persisted.version).toBe(18)
expect(persisted.modelProfiles).toContainEqual(
expect.objectContaining({
id: imageId,
@@ -1524,7 +1585,7 @@ describe('RuntimeSettingsStore', () => {
unknown
>
expect(saved).toMatchObject({
version: 17,
version: 18,
provider: 'model',
continueBinaryPath: '',
continueMode: 'chat',
@@ -1803,7 +1864,7 @@ describe('RuntimeSettingsStore', () => {
version: number
modelProfiles: Array<Record<string, unknown>>
}
expect(persisted.version).toBe(17)
expect(persisted.version).toBe(18)
expect(persisted.modelProfiles[0]).not.toHaveProperty('credential')
})