跳转至
DRAFT

Phase 0 · 基线对齐 + 协议改造设计

目标:建立"v4.3 demo 协议契约"→"frontend_vue3 Pinia + EventBus 实现"的完整对照表,作为后续 Phase 1-17 的统一接口规约。

工作量:1 工作日 · 依赖:无 · 后置 phase:1-17(全部依赖本 phase 的协议契约)


1. 目标(一句话)

把 v4.3 demo 中的 12 类 postMessage 协议完整、无遗漏、语义保留地映射到 frontend_vue3 的 Pinia store action + EventBus event,并产出 TS 类型定义文件,让后续每个 phase 都能精确引用。


2. 前置条件

  • ✅ frontend_vue3 项目结构已就绪(subagent 调研确认)
  • ✅ Shell 容器组件树已搭建(XiStudioShell + 9 子组件)
  • ✅ codex.css 已接入
  • ✅ Pinia + persistedstate 已配置
  • ✅ v4.3 demo 协议清单已锁定(详见 v1.2-ide-architecture.md §13

3. 任务清单

3.1 子任务 T0.1 · 当前 frontend_vue3 完整基线快照(0.25d)

扫描并记录:

  • src/components/shell/ 全部 .vue 文件列表 + 每个文件的核心 props/emits/slots 摘要
  • src/stages/{xilink,xitune,xiforge,xitest}/ 入口文件结构(已实现 vs 占位)
  • src/stores/ 现有 store 列表 + state 字段 + action 列表
  • src/composables/ 现有 composable 列表 + 用途
  • src/types/ 现有 TS 类型定义(特别是 communication.ts 完整 10 类 CommandType)
  • src/api/ 或 WebSocket 客户端实现位置
  • e2e/ 现有 4 个 spec 的 describe 块清单 + 测试覆盖范围
  • package.json 依赖列表(确认 mitt / pinia-plugin-persistedstate / vitest / playwright 都在)

产出docs/08-implementation/30-frontend-vue3/00-baseline-snapshot.json(结构化数据 · 后续 phase 引用)

3.2 子任务 T0.2 · 协议改造对照表定稿(0.25d)

基于 00-master-plan.md §3.1 的草表,逐条审查 + 锁定

v4.3 原 postMessage 类型 方向 改造方案 实现位置 优先级
stage-ready useStageReady() composable + 路由 onMounted src/composables/useStageReady.ts P1
toolbar-inject useTopbarStore.setToolbar(buttons) src/stores/topbar.ts P1
toolbar-click EventBus toolbar:click src/utils/eventBus.ts P1
mode-switcher-inject useTopbarStore.setModes(chips, activeKey) 同上 P1
mode-switch-click EventBus mode-switch:click 同上 P1
engine-control useEngineStore.toggle/start/stop/restart src/stores/engine.ts P1
engine-state-changed useEngineStore.state reactive 同上 P1
dock-inject useDockStore.setLeft/setRight src/stores/dock.ts P2
inspector-inject useInspectorStore.setHtml(html, module) src/stores/inspector.ts P2
module-properties-inject useBottomStore.setModuleHtml(html, module) src/stores/bottom.ts P2
select-node EventBus node:selected + useInspectorStore 联动 EventBus + store P2
tuning-dialog EventBus dialog:open + useDialogStore.open() src/stores/dialog.ts P2
show-toast useToastStore.show(message, type?) src/stores/toast.ts P1
stage-status useStatusBarStore.setStageHtml(html) src/stores/statusbar.ts P2
stage-hint useBottomStore.setHint(html) 同 bottom P2
doc-tabs-inject useTopbarStore.setDocTabs(tabs, activeKey) 同 topbar P3
doc-tab-click/close/new EventBus doc-tab:{click/close/new} EventBus P3
subtab 已被 doc-tab-click 取代 · 不实现

符号说明:↑ = stage → shell · ↓ = shell → stage · → = shell 内部广播

3.3 子任务 T0.3 · TS 类型定义草案(0.25d)

新建 src/types/protocol.ts,包含全部协议数据契约:

// =====================================================================
// XiStudio v4.3 协议改造 · TS 类型定义
// 基于 v1.2-ide-architecture.md §13 锁定
// =====================================================================

export type StageKey = 'xilink' | 'xitune' | 'xiforge' | 'xitest'

// ---- Shell → Stage 类型(注入到 Pinia store) ----

export interface ToolbarButton {
  id: string
  icon?: string
  label?: string
  tip?: string
  toggle?: boolean       // v4.3 新增 · true 表示开关按钮(如引擎 ▶/■)
  active?: boolean       // 当前是否激活(仅普通按钮用 · toggle 按钮由 store 状态决定)
  disabled?: boolean
}

export interface ModeChip {
  key: string
  icon?: string
  label: string
  tip?: string
  disabled?: boolean     // license add-on 未授权时灰显
}

export interface DocTab {
  key: string
  icon?: string
  label: string
  dirty?: boolean
}

export interface DockPane {
  key: string
  icon: string
  tip: string
  html?: string          // legacy demo 形态 · Vue 路线下应改为 component 组件名 + props
  component?: string     // Vue 路线推荐 · component name registered globally
  props?: Record<string, unknown>
}

// ---- 引擎状态 ----

export type EngineState = 'stopped' | 'running' | 'restarting' | 'error'

export interface EngineStateInfo {
  state: EngineState
  sampleRate?: number
  bufferSize?: number
  latencyMs?: number
}

// ---- EventBus 事件载荷 ----

export interface ToolbarClickPayload {
  stage: StageKey
  id: string
}

export interface ModeSwitchClickPayload {
  stage: StageKey
  key: string
}

export interface DocTabPayload {
  stage: StageKey
  key?: string           // close / click 时必填 · new 时可选
}

export interface NodeSelectedPayload {
  stage: StageKey
  node: string
  label: string
}

export interface DialogOpenPayload {
  stage: StageKey
  module: string
  label: string
  preset?: string        // 可选 · 关联当前激活 preset
}

// ---- Toast / 通知 ----

export type ToastType = 'info' | 'success' | 'warning' | 'error'

export interface ToastMessage {
  id: string
  type: ToastType
  message: string
  duration?: number      // ms · 默认 3000
}

新建 src/utils/eventBus.ts

import mitt, { type Emitter } from 'mitt'
import type {
  ToolbarClickPayload,
  ModeSwitchClickPayload,
  DocTabPayload,
  NodeSelectedPayload,
  DialogOpenPayload,
} from '@/types/protocol'

export type AppEvents = {
  'toolbar:click':       ToolbarClickPayload
  'mode-switch:click':   ModeSwitchClickPayload
  'doc-tab:click':       DocTabPayload
  'doc-tab:close':       DocTabPayload
  'doc-tab:new':         DocTabPayload
  'node:selected':       NodeSelectedPayload
  'dialog:open':         DialogOpenPayload
  'engine:control':      { stage: StageKey; action: 'start' | 'stop' | 'toggle' | 'restart' }
}

export const eventBus: Emitter<AppEvents> = mitt<AppEvents>()

3.4 子任务 T0.4 · Pinia store 骨架草案(0.25d)

新建 7 个核心 store 的骨架文件(仅 state + action 签名 · 实现留给后续 phase):

src/stores/topbar.ts

import { defineStore } from 'pinia'
import type { ToolbarButton, ModeChip, DocTab, StageKey } from '@/types/protocol'

export const useTopbarStore = defineStore('topbar', {
  state: () => ({
    // mode-switcher
    modes: [] as ModeChip[],
    activeMode: '' as string,
    // stageToolbar
    toolbar: [] as ToolbarButton[],
    // doc-tabs (sub-tabs-bar)
    docTabs: [] as DocTab[],
    activeDocTab: '' as string,
  }),
  actions: {
    setModes(chips: ModeChip[], activeKey?: string) {
      this.modes = chips
      this.activeMode = activeKey || chips[0]?.key || ''
    },
    setToolbar(buttons: ToolbarButton[]) {
      this.toolbar = buttons
    },
    setDocTabs(tabs: DocTab[], activeKey?: string) {
      this.docTabs = tabs
      this.activeDocTab = activeKey || tabs[0]?.key || ''
    },
    clear() {
      this.modes = []
      this.activeMode = ''
      this.toolbar = []
      this.docTabs = []
      this.activeDocTab = ''
    },
  },
})

src/stores/engine.ts

import { defineStore } from 'pinia'
import type { EngineState } from '@/types/protocol'

export const useEngineStore = defineStore('engine', {
  state: () => ({
    state: 'stopped' as EngineState,
    sampleRate: 48000,
    bufferSize: 256,
    latencyMs: 0,
  }),
  getters: {
    running: (s) => s.state === 'running',
  },
  actions: {
    toggle() {
      this.state = this.running ? 'stopped' : 'running'
    },
    start() { this.state = 'running' },
    stop()  { this.state = 'stopped' },
    restart() {
      this.state = 'restarting'
      setTimeout(() => { this.state = 'running' }, 500)
    },
  },
  // 不持久化 · 引擎运行状态是会话级
})

其余 5 个 store 骨架(dock / inspector / bottom / dialog / toast / statusbar)

详细签名见 00-master-plan.md §3.3

业务级 store(project / profile / preset / test)留待 Phase 8/9/14/15 实现。


4. 接口契约

4.1 与现有 src/types/communication.ts(WebSocket 10 类命令)的关系

两套协议并存且互不冲突

  • communication.ts = 前端 ↔ ASP.NET Core 8 后端的 WebSocket 命令(set_param / write_link / start_audio_engine 等)
  • protocol.ts(新建) = 前端内部 Shell ↔ Stage 的同进程通信契约(取代 v4.3 demo 的 postMessage)

调用流向示例(▶ 按钮):

[用户点击 ▶ 按钮(StageBar 组件)]
[Vue @click → useEngineStore.toggle()]
[engine store · state = 'running']
    ↓ watch
[useWebSocket.send({type: 'start_audio_engine', link, durationSec})]  ← 走 communication.ts 协议
[ASP.NET Core 8 后端启动 AudioEngine]
[后端 broadcast set_param 等 → WebSocket 接收 → Pinia store 更新]
[Sink RMS Dock ECharts 重渲]

4.2 license 守卫预留位

虽然 license 系统不在 Phase 0 范围内,但 store 设计要预留:

  • useTopbarStore.modes 中的 ModeChip.disabled 字段 → 后续 license add-on 联动
  • useTopbarStore.toolbar 中的 ToolbarButton.disabled 字段 → 同上
  • 4 Stage Pill 的渲染逻辑:useLicenseStore.canEnter(stage) (Phase 17 前接入)

5. 验收标准

维度 标准
完整性 18 类 protocol 项全部有改造方案落地(2 类合并:subtab 被 doc-tab-click 取代)
TS 严格 src/types/protocol.ts 编译无 any · 所有 store action 签名带类型
基线快照存档 00-baseline-snapshot.json 写入仓库,记录 Phase 0 时刻所有关键文件清单与字段
文档可执行 后续 phase 文档可直接引用本 phase 的改造对照表,无需重新解释协议含义
代码骨架就位 src/types/protocol.ts + src/utils/eventBus.ts + 7 个 store 骨架文件已 commit(feat(p0): protocol scaffolding

6. 验收脚本

6.1 手动验证

# 1. 类型检查通过
cd 04_development/frontend_vue3
npx tsc --noEmit

# 2. 单元测试启动 OK
npx vitest run --config vitest.config.ts test/unit/

# 3. Dev server 启动无报错
npm run dev
# 浏览器打开 http://localhost:3000 · 确认 Shell 容器渲染 + 4 Pill 可见

6.2 自动 e2e(暂不新增 spec · 沿用 4 个现有 spec 跑通即可)

npx playwright test
# 期望:integration-profile / source-sink / unittest-mixer / unittest-sst 全绿

7. 风险与回滚点

风险 缓解
现有 useLayoutStore 字段与新 store 重名 T0.1 扫描时确认无 namespace 冲突;如有冲突,在新 store 名前加 useTopbar* 等具体前缀
mitt 包未安装 T0.4 时 npm install mitt
后续 phase 发现协议遗漏 任何 phase 发现新需求时,回到本文档新增条目 + 升 v1.1

回滚:本 phase 的改动全部限定在 src/types/ + src/utils/ + src/stores/,不修改任何 .vue 组件 · 全部回滚只需 git revert 单个 commit。


8. 关联文档


Phase 0 · 基线对齐 v1.0 · 2026-05-19 · 1 工作日 · 产出 4 类骨架文件 + 1 份基线快照 + 1 份对照表锁定