feat(plugins): 悬浮状态胶囊(B3 落地,复刻 ZCode 药丸⇄面板二态)

This commit is contained in:
Rick Ye
2026-09-11 15:49:50 +08:00
parent 1326f9b672
commit ad16ed7239
8 changed files with 315 additions and 200 deletions
+22 -3
View File
@@ -132,6 +132,8 @@ class PluginHost {
/** 状态胶囊/工具栏按钮:pluginId → (itemId → data) */
private statusItems = new Map<string, Map<string, StatusItem>>()
private toolbarButtons = new Map<string, Map<string, ToolbarButtonDef>>()
/** 状态条目最近写入时间(悬浮胶囊"最新消息"判定),key = pluginId\0itemId */
private statusUpdatedAt = new Map<string, number>()
/** 跨插件服务注册表(pluginId → serviceName → impl);每次 runtime 重建时清空重建 */
private services = new Map<string, Map<string, unknown>>()
/** 已声明的存储 schema(api.storage.declareSchema;管理页 Tooltip 与 Agent 内省数据源) */
@@ -339,6 +341,7 @@ class PluginHost {
log.info('reload begin')
this.statusItems.clear()
this.toolbarButtons.clear()
this.statusUpdatedAt.clear()
this.services.clear()
this.storageSchemas.clear()
await this.scan()
@@ -534,7 +537,14 @@ class PluginHost {
uiState(): PluginsUiState {
const status: PluginStatusEntry[] = []
for (const [pluginId, items] of this.statusItems) {
for (const [itemId, item] of items) status.push({ pluginId, itemId, item })
for (const [itemId, item] of items) {
status.push({
pluginId,
itemId,
item,
updatedAt: this.statusUpdatedAt.get(`${pluginId}\0${itemId}`) ?? Date.now()
})
}
}
const toolbar: PluginToolbarEntry[] = []
for (const [pluginId, buttons] of this.toolbarButtons) {
@@ -552,8 +562,14 @@ class PluginHost {
items = new Map()
this.statusItems.set(pluginId, items)
}
if (item) items.set(itemId, item)
else items.delete(itemId)
const stampKey = `${pluginId}\0${itemId}`
if (item) {
items.set(itemId, item)
this.statusUpdatedAt.set(stampKey, Date.now())
} else {
items.delete(itemId)
this.statusUpdatedAt.delete(stampKey)
}
if (items.size === 0) this.statusItems.delete(pluginId)
this.send('plugins:uiState', this.uiState())
}
@@ -581,6 +597,9 @@ class PluginHost {
private clearPluginUi(pluginId: string): void {
this.statusItems.delete(pluginId)
this.toolbarButtons.delete(pluginId)
for (const key of [...this.statusUpdatedAt.keys()]) {
if (key.startsWith(`${pluginId}\0`)) this.statusUpdatedAt.delete(key)
}
this.settingsSchemas.delete(pluginId)
this.dropSettingsCallbacks(pluginId)
this.services.delete(pluginId)