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:
@@ -3,6 +3,50 @@ import {
|
||||
type BrowserWindow,
|
||||
type NotificationConstructorOptions
|
||||
} from 'electron'
|
||||
import { showWindow } from './window'
|
||||
|
||||
const MAX_RETAINED_NOTIFICATIONS = 64
|
||||
const NOTIFICATION_RETENTION_MS = 15 * 60_000
|
||||
const activeNotifications = new Map<Notification, () => void>()
|
||||
const pendingWindowActivations = new WeakSet<BrowserWindow>()
|
||||
|
||||
function activateWindow(window: BrowserWindow): void {
|
||||
try {
|
||||
if (window.isDestroyed()) {
|
||||
return
|
||||
}
|
||||
const webContents = window.webContents
|
||||
if (
|
||||
webContents &&
|
||||
(!webContents.getURL() ||
|
||||
webContents.isLoadingMainFrame())
|
||||
) {
|
||||
if (!pendingWindowActivations.has(window)) {
|
||||
pendingWindowActivations.add(window)
|
||||
webContents.once('did-finish-load', () => {
|
||||
pendingWindowActivations.delete(window)
|
||||
activateWindow(window)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
showWindow(window)
|
||||
} catch {
|
||||
// The window can be destroyed between checks while a native callback runs.
|
||||
}
|
||||
}
|
||||
|
||||
export function registerDesktopNotificationActivation(
|
||||
window: BrowserWindow,
|
||||
platform: NodeJS.Platform = process.platform
|
||||
): void {
|
||||
if (platform !== 'win32') {
|
||||
return
|
||||
}
|
||||
Notification.handleActivation(() => {
|
||||
activateWindow(window)
|
||||
})
|
||||
}
|
||||
|
||||
export function showDesktopNotificationWhenUnfocused(
|
||||
window: BrowserWindow,
|
||||
@@ -15,6 +59,53 @@ export function showDesktopNotificationWhenUnfocused(
|
||||
) {
|
||||
return false
|
||||
}
|
||||
new Notification(options).show()
|
||||
|
||||
const notification = new Notification(options)
|
||||
let retentionTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
const release = (): void => {
|
||||
if (retentionTimer) {
|
||||
clearTimeout(retentionTimer)
|
||||
retentionTimer = undefined
|
||||
}
|
||||
activeNotifications.delete(notification)
|
||||
notification.removeListener('click', handleClick)
|
||||
notification.removeListener('close', release)
|
||||
notification.removeListener('failed', release)
|
||||
}
|
||||
const dismiss = (): void => {
|
||||
try {
|
||||
notification.close()
|
||||
} catch {
|
||||
// The native notification may already have been dismissed.
|
||||
} finally {
|
||||
release()
|
||||
}
|
||||
}
|
||||
const handleClick = (): void => {
|
||||
try {
|
||||
activateWindow(window)
|
||||
} finally {
|
||||
release()
|
||||
}
|
||||
}
|
||||
|
||||
if (activeNotifications.size >= MAX_RETAINED_NOTIFICATIONS) {
|
||||
activeNotifications.values().next().value?.()
|
||||
}
|
||||
activeNotifications.set(notification, dismiss)
|
||||
retentionTimer = setTimeout(dismiss, NOTIFICATION_RETENTION_MS)
|
||||
retentionTimer.unref?.()
|
||||
|
||||
notification.once('click', handleClick)
|
||||
notification.once('close', release)
|
||||
notification.once('failed', release)
|
||||
|
||||
try {
|
||||
notification.show()
|
||||
} catch (error) {
|
||||
release()
|
||||
throw error
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user