fix(stage-pages,stage-ui): plugin host update
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
"DOM.Iterable",
|
||||
"DOM.AsyncIterable"
|
||||
],
|
||||
"useDefineForClassFields": true,
|
||||
"paths": {
|
||||
"@proj-airi/stage-ui/*": [
|
||||
"../../packages/stage-ui/src/*"
|
||||
|
||||
@@ -106,6 +106,18 @@ async function loadEnabled() {
|
||||
}
|
||||
}
|
||||
|
||||
async function setAutoReload(plugin: PluginManifestSummary, enabled: boolean) {
|
||||
try {
|
||||
await store.setAutoReload({
|
||||
name: plugin.name,
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : `Failed to update auto-reload state for ${plugin.name}.`)
|
||||
}
|
||||
}
|
||||
|
||||
async function setEnabled(plugin: PluginManifestSummary, enabled: boolean) {
|
||||
try {
|
||||
await store.setEnabled({
|
||||
@@ -173,7 +185,7 @@ onMounted(async () => {
|
||||
:description="store.error"
|
||||
/>
|
||||
|
||||
<div :class="['grid', 'gap-2', 'sm:grid-cols-2', 'xl:grid-cols-4']">
|
||||
<div :class="['grid', 'gap-2', 'sm:grid-cols-2', 'xl:grid-cols-6']">
|
||||
<div :class="['rounded-xl', 'bg-neutral-100', 'p-3', 'dark:bg-neutral-900/70']">
|
||||
<div :class="['text-xs', 'uppercase', 'opacity-70']">
|
||||
Discovered
|
||||
@@ -206,6 +218,14 @@ onMounted(async () => {
|
||||
{{ readyCapabilitiesCount }} / {{ store.capabilities.length }}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['rounded-xl', 'bg-neutral-100', 'p-3', 'dark:bg-neutral-900/70']">
|
||||
<div :class="['text-xs', 'uppercase', 'opacity-70']">
|
||||
Kits
|
||||
</div>
|
||||
<div :class="['text-2xl', 'font-semibold']">
|
||||
{{ store.kits.length }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="['flex', 'flex-wrap', 'items-center', 'gap-2']">
|
||||
@@ -272,6 +292,9 @@ onMounted(async () => {
|
||||
<span :class="['rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', ...chipClasses(plugin.enabled ? 'emerald' : 'neutral')]">
|
||||
{{ plugin.enabled ? 'enabled' : 'disabled' }}
|
||||
</span>
|
||||
<span :class="['rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', ...chipClasses(plugin.autoReload ? 'amber' : 'neutral')]">
|
||||
{{ plugin.autoReload ? 'auto reload on' : 'auto reload off' }}
|
||||
</span>
|
||||
<span :class="['rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', ...chipClasses(plugin.loaded ? 'emerald' : 'neutral')]">
|
||||
{{ plugin.loaded ? 'loaded' : 'not loaded' }}
|
||||
</span>
|
||||
@@ -280,6 +303,14 @@ onMounted(async () => {
|
||||
</span>
|
||||
</div>
|
||||
<div :class="['flex', 'flex-wrap', 'items-center', 'gap-2']">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:label="plugin.autoReload ? 'Auto Reload Off' : 'Auto Reload On'"
|
||||
:icon="plugin.autoReload ? 'i-solar:refresh-circle-bold' : 'i-solar:refresh-bold-duotone'"
|
||||
:loading="store.loading"
|
||||
@click="setAutoReload(plugin, !plugin.autoReload)"
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
@@ -372,6 +403,37 @@ onMounted(async () => {
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
title="Kits"
|
||||
icon="i-solar:box-bold-duotone"
|
||||
inner-class="gap-2"
|
||||
>
|
||||
<div
|
||||
v-if="store.kits.length === 0"
|
||||
:class="['text-sm', 'opacity-70']"
|
||||
>
|
||||
No kits registered.
|
||||
</div>
|
||||
<div v-else :class="['grid', 'gap-2']">
|
||||
<div
|
||||
v-for="kit in store.kits"
|
||||
:key="kit.kitId"
|
||||
:class="['rounded-lg', 'border', 'border-neutral-300', 'bg-white/60', 'p-3', 'dark:border-neutral-800', 'dark:bg-neutral-950/60']"
|
||||
>
|
||||
<div :class="['flex', 'flex-wrap', 'items-center', 'justify-between', 'gap-2']">
|
||||
<span :class="['font-mono', 'text-xs', 'sm:text-sm']">{{ kit.kitId }}</span>
|
||||
<span :class="['rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', ...chipClasses('neutral')]">
|
||||
v{{ kit.version }}
|
||||
</span>
|
||||
</div>
|
||||
<div :class="['mt-2', 'text-xs', 'opacity-70']">
|
||||
runtimes: {{ kit.runtimes.join(', ') || '-' }}
|
||||
</div>
|
||||
<pre :class="['mt-2', 'overflow-auto', 'rounded-lg', 'bg-neutral-100', 'p-2', 'text-xs', 'dark:bg-neutral-900/70']">{{ JSON.stringify(kit.capabilities, null, 2) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
title="Capabilities"
|
||||
icon="i-solar:widget-2-bold-duotone"
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface PluginManifestSummary {
|
||||
entrypoints: Record<string, string | undefined>
|
||||
path: string
|
||||
enabled: boolean
|
||||
autoReload: boolean
|
||||
loaded: boolean
|
||||
isNew: boolean
|
||||
}
|
||||
@@ -32,9 +33,36 @@ export interface PluginHostSessionSummary {
|
||||
moduleId: string
|
||||
}
|
||||
|
||||
export interface PluginHostKitCapabilitySummary {
|
||||
key: string
|
||||
actions: string[]
|
||||
}
|
||||
|
||||
export interface PluginHostKitSummary {
|
||||
kitId: string
|
||||
version: string
|
||||
capabilities: PluginHostKitCapabilitySummary[]
|
||||
runtimes: Array<'electron' | 'node' | 'web'>
|
||||
}
|
||||
|
||||
export interface PluginHostModuleSummary {
|
||||
moduleId: string
|
||||
ownerSessionId: string
|
||||
ownerPluginId: string
|
||||
kitId: string
|
||||
kitModuleType: string
|
||||
state: 'announced' | 'active' | 'degraded' | 'withdrawn'
|
||||
runtime: 'electron' | 'node' | 'web'
|
||||
revision: number
|
||||
updatedAt: number
|
||||
config: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface PluginHostDebugSnapshot {
|
||||
registry: PluginRegistrySnapshot
|
||||
sessions: PluginHostSessionSummary[]
|
||||
kits: PluginHostKitSummary[]
|
||||
modules: PluginHostModuleSummary[]
|
||||
capabilities: PluginCapabilityState[]
|
||||
refreshedAt: number
|
||||
}
|
||||
@@ -42,6 +70,7 @@ export interface PluginHostDebugSnapshot {
|
||||
interface PluginHostDebugBridge {
|
||||
list: () => Promise<PluginRegistrySnapshot>
|
||||
setEnabled: (payload: { name: string, enabled: boolean, path?: string }) => Promise<PluginRegistrySnapshot>
|
||||
setAutoReload: (payload: { name: string, enabled: boolean }) => Promise<PluginRegistrySnapshot>
|
||||
loadEnabled: () => Promise<PluginRegistrySnapshot>
|
||||
load: (payload: { name: string }) => Promise<PluginRegistrySnapshot>
|
||||
unload: (payload: { name: string }) => Promise<PluginRegistrySnapshot>
|
||||
@@ -60,6 +89,7 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb
|
||||
const bridge = ref<PluginHostDebugBridge>()
|
||||
const registry = ref<PluginRegistrySnapshot>()
|
||||
const sessions = ref<PluginHostSessionSummary[]>([])
|
||||
const kits = ref<PluginHostKitSummary[]>([])
|
||||
const capabilities = ref<PluginCapabilityState[]>([])
|
||||
const refreshedAt = ref<number>()
|
||||
const error = ref<string>()
|
||||
@@ -87,6 +117,7 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb
|
||||
function assignInspection(snapshot: PluginHostDebugSnapshot) {
|
||||
assignRegistry(snapshot.registry)
|
||||
sessions.value = snapshot.sessions
|
||||
kits.value = snapshot.kits
|
||||
capabilities.value = snapshot.capabilities
|
||||
refreshedAt.value = snapshot.refreshedAt
|
||||
}
|
||||
@@ -146,6 +177,13 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb
|
||||
return nextRegistry
|
||||
}
|
||||
|
||||
async function setAutoReload(payload: { name: string, enabled: boolean }) {
|
||||
const nextRegistry = await withBridge(activeBridge => activeBridge.setAutoReload(payload))
|
||||
assignRegistry(nextRegistry)
|
||||
await refreshInspection()
|
||||
return nextRegistry
|
||||
}
|
||||
|
||||
async function loadEnabled() {
|
||||
const nextRegistry = await withBridge(activeBridge => activeBridge.loadEnabled())
|
||||
assignRegistry(nextRegistry)
|
||||
@@ -170,6 +208,7 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb
|
||||
return {
|
||||
registry,
|
||||
sessions,
|
||||
kits,
|
||||
capabilities,
|
||||
refreshedAt,
|
||||
loading,
|
||||
@@ -185,6 +224,7 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb
|
||||
refreshInspection,
|
||||
refreshAll,
|
||||
setEnabled,
|
||||
setAutoReload,
|
||||
loadEnabled,
|
||||
load,
|
||||
unload,
|
||||
|
||||
@@ -55,11 +55,16 @@ export const useContextBridgeStore = defineStore('mods:api:context-bridge', () =
|
||||
|
||||
const { post: broadcastContext, data: incomingContext } = useBroadcastChannel<ContextMessage, ContextMessage>({ name: CONTEXT_CHANNEL_NAME })
|
||||
const { post: broadcastStreamEvent, data: incomingStreamEvent } = useBroadcastChannel<ChatStreamEvent, ChatStreamEvent>({ name: CHAT_STREAM_CHANNEL_NAME })
|
||||
const sparkNotifyHostRole = ref<'main' | 'client'>('client')
|
||||
|
||||
const disposeHookFns = ref<Array<() => void>>([])
|
||||
let remoteStreamGuard: { sessionId: string, generation: number } | null = null
|
||||
let initialized = false
|
||||
|
||||
function setSparkNotifyHostRole(role: 'main' | 'client') {
|
||||
sparkNotifyHostRole.value = role
|
||||
}
|
||||
|
||||
async function initialize() {
|
||||
await mutex.acquire()
|
||||
|
||||
@@ -525,5 +530,6 @@ export const useContextBridgeStore = defineStore('mods:api:context-bridge', () =
|
||||
return {
|
||||
initialize,
|
||||
dispose,
|
||||
setSparkNotifyHostRole,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user