feat: expand multi-runtime workflows for 0.10.0

GoodBuddy previously exposed Runtime capabilities, MCP assignments, plugin controls, context compaction, usage reporting, and task-completion behavior through incomplete or inconsistent paths. This release unifies managed OpenCode, Continue, and DeepSeek Harness controls; adds DSH plugin and image workflows; strengthens MCP and Runtime lifecycle bounds; fixes Windows notification activation; validates cross-architecture packages; and presents the approved bilingual four-section release notes.

The DSH plugin marketplace remains a default-off preview whose trusted third-party code runs with current-user permissions. Ask remains read-only, Execute keeps approval controls, and context compaction may use the selected model without deleting GoodBuddy chat history.

Release note: GoodBuddy 0.10.0 重点完善多 Runtime 工作流,统一 OpenCode、Continue 与 DeepSeek Harness 的能力、MCP、插件和上下文管理,并提升长对话、多会话与任务通知的连贯性。
This commit is contained in:
mesalogo
2026-08-17 12:57:12 +08:00
parent f5ee9b2198
commit cbbe30896e
50 changed files with 4077 additions and 605 deletions
+113 -19
View File
@@ -77,6 +77,7 @@ const MAX_NATIVE_MCP_SERVERS =
runtimeNativeInventoryLimits.mcpServers
const MAX_NATIVE_SKILLS = runtimeNativeInventoryLimits.skills
const MAX_NATIVE_RESOURCES = runtimeNativeInventoryLimits.resources
const COMPACTION_USAGE_EVENT_GRACE_MS = 1_000
const EMBEDDED_SERVER_USERNAME = 'goodbuddy'
const OPENCODE_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u
const TEMPORARY_MCP_PREFIXES = [
@@ -2407,27 +2408,120 @@ export class OpenCodeRuntime implements AgentRuntime {
if (context.error || !context.data) {
throw new Error('OpenCode 原生上下文不可用,无法执行 Compact')
}
signal.throwIfAborted()
const compact = await client.v2.session.compact(
{ sessionID: sessionId },
{ signal }
)
if (compact.error) {
throw new Error(
opencodeErrorMessage(
compact.error,
'OpenCode 原生 Compact 失败'
)
)
}
return {
result: {
provider: 'opencode',
strategy: 'native',
compacted: true,
detail: 'OpenCode 已完成原生上下文压缩'
const latestAssistant = [...context.data.data]
.reverse()
.find((message) => message.type === 'assistant')
const configuredModel = this.options.modelProfile
? {
providerID: resolveOpenCodeProvider(
this.options.modelProfile
).id,
modelID: this.options.modelProfile.modelName
}
: latestAssistant?.type === 'assistant'
? {
providerID: latestAssistant.model.providerID,
modelID: latestAssistant.model.id
}
: undefined
if (!configuredModel) {
return {
result: {
provider: 'opencode',
strategy: 'native',
compacted: false,
detail: '当前 OpenCode 会话尚无可用于压缩的模型记录'
}
}
}
signal.throwIfAborted()
const subscriptionController = new AbortController()
const subscription = await client.event.subscribe(
{ directory: this.options.defaultWorkspace },
{
signal: AbortSignal.any([
signal,
subscriptionController.signal
])
}
)
const usageEvents: RuntimeModelUsageEvent[] = []
const reportedMessageIds = new Set<string>()
const usageCapture = (async () => {
for await (const event of subscription.stream) {
if (
event.type === 'message.updated' &&
event.properties.sessionID === sessionId &&
event.properties.info.sessionID === sessionId &&
event.properties.info.role === 'assistant' &&
!reportedMessageIds.has(event.properties.info.id)
) {
const usage = createUsageEvent(
request.requestId,
event.properties.info
)
if (usage) {
reportedMessageIds.add(event.properties.info.id)
usageEvents.push(usage)
}
}
if (
event.type === 'session.idle' &&
event.properties.sessionID === sessionId
) {
return
}
}
})()
try {
const compact = await client.session.summarize(
{
sessionID: sessionId,
directory: this.options.defaultWorkspace,
providerID: configuredModel.providerID,
modelID: configuredModel.modelID,
auto: false
},
{ signal }
)
if (compact.error || compact.data !== true) {
throw new Error(
opencodeErrorMessage(
compact.error,
'OpenCode 原生 Compact 失败'
)
)
}
let graceTimer: ReturnType<typeof setTimeout> | undefined
try {
await Promise.race([
usageCapture,
new Promise<void>((resolveGrace) => {
graceTimer = setTimeout(
resolveGrace,
COMPACTION_USAGE_EVENT_GRACE_MS
)
graceTimer.unref?.()
})
])
} finally {
if (graceTimer) {
clearTimeout(graceTimer)
}
}
return {
result: {
provider: 'opencode',
strategy: 'native',
compacted: true,
detail: 'OpenCode 已完成原生上下文压缩'
},
...(usageEvents.length > 0 ? { usageEvents } : {})
}
} finally {
subscriptionController.abort()
await usageCapture.catch(() => undefined)
}
} finally {
releaseConversation?.()
releaseEmbedded()