feat: ship skill and MCP workflows with signed updater for v0.0.7

This commit is contained in:
xiaohan.yuan committed 2026-10-21 00:04:17 +08:00
1 parent 1b52df0603
commit a01085c656
136 files changed
+18646 -217

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
export interface UpdateLifecyclePorts {
quiesce(): Promise<void>
restore(): void
shutdown(): Promise<void>
exit(): void
log(error: unknown): void
prepareTimeoutMs?: number
quitTimeoutMs?: number
}
export function createUpdateLifecycle(ports: UpdateLifecyclePorts): {
beforeInstall(): Promise<boolean>
installFailed(): void
quitForUpdate(): Promise<void>
} {
let preparation: Promise<void> | null = null
let committed = false
const restore = (): void => { if (!committed) ports.restore() }
const installFailed = (): void => {
// Stopping work is not cancellable. Do not resume underneath an old stop.
if (preparation) void preparation.then(restore, restore)
else restore()
}
return {
async beforeInstall() {
if (committed) throw new Error('安装器已启动,请退出应用完成更新')
if (preparation) throw new Error('上次更新准备仍在结束中,请稍后重试')
let timer: ReturnType<typeof setTimeout> | undefined
const pending = ports.quiesce()
preparation = pending
void pending.finally(() => { if (preparation === pending) preparation = null }).catch(() => undefined)
try {
await Promise.race([
pending,
new Promise<never>((_, reject) => {
timer = setTimeout(() => reject(new Error('任务清理尚未结束,暂不能开始新任务;请稍后重试或重启应用')), ports.prepareTimeoutMs ?? 30_000)
})
])
return true
} finally { clearTimeout(timer) }
},
installFailed,
async quitForUpdate() {
committed = true
let timer: ReturnType<typeof setTimeout> | undefined
try {
await Promise.race([
ports.shutdown(),
new Promise<void>(resolve => { timer = setTimeout(resolve, ports.quitTimeoutMs ?? 15_000) })
])
} catch (error) {
ports.log(error)
} finally {
clearTimeout(timer)
ports.exit()
}
}
}
}