跳转至

P1.UA8R1-subgraph-redesign-tab-and-ports · tab bar + 默认端口 + 端口可配 UI

Worker:ClaudeA · 前端 / 预计:1.5d / 优先级:P1 / 状态:dispatched 隔离:🧵 文件隔离(同 worktree 同 branch · 与 fork 2 文件正交可串行/单 commit)


🔍 触发与解锁链

触发 状态 影响
用户实测 ADR-08 议题④ 5 hotfix 后仍不可用 ✅ 2026-05-31 14:21 双击 modal 不符期望 / 默认端口缺失 / 端口无法配
用户拍板 5 决议方向 + accept ADR-08-R1 ✅ 14:35 / 14:44 R1.1=B(tab) · R1.2=B(默认 1in/1out) · R1.4=B(全可配)
parent zombie P1.U-subgraph-canvas + hotfix ✅ af945e2 + 40781e8 推导算法 + 单击高亮 + cyclic 检查保留不动

→ 本 fork 改 modal→tab + 加默认端口 + 加端口可配 UI(R1.1+R1.2+R1.4 三决议)· fork 2 (持久化+Ctrl+S) 文件正交可并行


任务定义(基于 ADR-AIOS-08-R1 §5)

实施 ADR-08-R1 三决议(R1.1+R1.2+R1.4)· 修复用户实测议题④ 4 大不可用问题中的"双击 modal" + "默认端口缺失" + "端口无法配" 3 项(持久化 + Ctrl+S 由 fork 2 实施):

  • R1.1 tab 模式:LinkEditor 顶部 tab bar(Main / Subgraph A / Subgraph B / +)· 双击 SubgraphNodeInstance → 创建/激活对应 tab + 切换至该 tab · tab 可关闭(× · 仅关视图不删 def)· mobile 折叠为 hamburger
  • R1.2 默认虚拟端口:Toolbar 入口 1 创建 SubgraphDefinition 时默认含 inputPorts: [{ id: 'in_0', label: 'Input 1', type: 'audio', internalMapping: null }] + outputPorts: [{ id: 'out_0', label: 'Output 1', type: 'audio', internalMapping: null }](入口 2 多选封装保留 40781e8 推导算法不动)
  • R1.4 端口全可配:Inspector 段加 SubgraphPortsSection · add/remove/rename/reorder · type 下拉 audio / control(预留 K2-protocol-v2)

严守保留(零回归 · 不动)· 推导算法(40781e8)· 单击高亮 · cyclic 检查 · types/subgraph.ts 现有字段 · LEGACY_LINK_FILE_MAP 7d 宽限。


完整 prompt(直接复制粘贴 worker 终端)

[U-thread]   P1.UA8R1-subgraph-redesign-tab-and-ports
[部门]       前端 (frontend_vue3) · 推荐 skill: vuejs-typescript-best-practices
[Worker CWD] d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies]   P1.K-xilink-canvas(写 tab bar + 内嵌画布) + P1.K-xilink-toolbar(读) + P1.K-inspector(写 端口段) + P1.K-types(写 扩字段)
[隔离]       🧵 文件隔离 · 与 fork 2 (linkStore + keymap) 文件正交可串行 / 单 commit · 不动 stages/xitest/* / stages/xitune/*
[优先级]     P1 · 1.5d · ADR-08-R1 fork 1 · 议题④ 修订主体
[ADR]        d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/ADR/ADR-AIOS-08-R1-subgraph-redesign.md(必读 §5 三决议 R1.1+R1.2+R1.4)
[业务行为契约引用] ADR-08-R1 §5 + ADR-08 验收清单 §议题④ C4-1~C4-17 + 用户原话(默认 1in/1out + tab 切换 + 端口可配)

[参考文档](绝对路径)
  - ADR 主文档:d:/.../docs/08-implementation/40-aios/ADR/ADR-AIOS-08-R1-subgraph-redesign.md
  - 父 ADR:d:/.../docs/08-implementation/40-aios/ADR/ADR-AIOS-08-xilink-stage-ux.md(§2.5 议题④)
  - 子进程 PCB:d:/.../docs/08-implementation/40-aios/processes/P_arch/ADR-AIOS-08-R1/PROCESS.md(本 fork 占位记账)
  - 验收清单:d:/.../docs/08-implementation/40-aios/ADR/ADR-AIOS-08-acceptance-checklist.md(议题④ C4-1~C4-17)
  - parent zombie 标本:d:/.../docs/08-implementation/40-aios/prompts/done/P1.UH-subgraph-ports-and-dblclick-fix--40781e8.md(端口推导 + 双击 hotfix · 不动)
  - 子图骨架:d:/.../docs/08-implementation/40-aios/prompts/done/P1.U-subgraph-canvas--af945e2.md(看 SubgraphCanvas 现状)
  - schema 标本:d:/.../docs/08-implementation/40-aios/prompts/done/P1.U-subgraph-schema-extend--e93ef27.md(SubgraphPort 字段)
  - Inspector 框架:d:/.../docs/08-implementation/40-aios/prompts/done/P0.U-right-inspector-framework--77b7a50.md(挂段方式)
  - 现状必读:
    · frontend_vue3/src/stages/xilink/LinkEditor.vue(全文 · 找 tab/modal 容器位置)
    · frontend_vue3/src/stages/xilink/SubgraphCanvas.vue(全文 · 当前 modal 实装)
    · frontend_vue3/src/stages/xilink/composables/useSubgraph.ts(全文 · 复用 createSubgraphFromSelection · 加 createEmptySubgraph + tab state)
    · frontend_vue3/src/types/subgraph.ts(看 SubgraphPort 现有字段)
    · frontend_vue3/src/components/inspector/RightInspector.vue(看 6 段挂载方式)
    · 现有 inspector/*Section.vue(选 1-2 个看 props/emit 模式)

【背景】
ADR-08 议题④ parent zombie af945e2 + hotfix 40781e8 完成了子图骨架 + 推导 + 双击/单击 hotfix · 但用户 14:21 实测仍不可用:
- 原话:"双击 modal 不是预期 + 默认端口必须有 1in/1out + 端口必须可配 + 持久化失败"
- 14:35 拍板 5 决议(R1.1=tab/R1.2=默认 1in/1out/R1.3=补 toJSON/R1.4=全可配/R1.5=Ctrl+S)
- 本 fork 实施 R1.1+R1.2+R1.4 · fork 2 实施 R1.3+R1.5(并行 / 同 ClaudeA 串行)

【执行步骤】

Step 1 · 真值核查(必跑 · 0.15d)
- git status / git pull origin xistudio --no-rebase
- cat frontend_vue3/src/stages/xilink/LinkEditor.vue(找 tab 容器候选位置 / SubgraphCanvas modal 注入点)
- cat frontend_vue3/src/stages/xilink/SubgraphCanvas.vue(看 modal Teleport · 改造点)
- cat frontend_vue3/src/stages/xilink/composables/useSubgraph.ts(看 createSubgraphFromSelection · 找加 createEmptySubgraph + openTabs/activeTab 切入位置)
- cat frontend_vue3/src/types/subgraph.ts(确认 SubgraphPort 现字段:id/label/type/internalMapping · 加 description?/order?)
- cat frontend_vue3/src/components/inspector/RightInspector.vue(看 6 段挂载 · 选哪段加 SubgraphPortsSection)
- 输出真值核查到 commit body:
  · LinkEditor 顶部布局现状(可加 tab bar 位置)
  · SubgraphCanvas modal 改 tab 内嵌画布的最小改动
  · Inspector 6 段当前 + SubgraphPortsSection 挂第几段
  · types/subgraph.ts 扩字段无破坏现有(LEGACY 兼容)

Step 2 · 扩 types/subgraph.ts(0.05d)
- 编辑 frontend_vue3/src/types/subgraph.ts
- SubgraphPort 接口加 2 可选字段:
  · description?: string(端口说明 · Ximind 大模型可读)
  · order?: number(用户 reorder 用 · 默认按数组下标)
- 不动现有字段 · 旧 SubgraphPort(无 description/order)继续合法

Step 3 · R1.2 默认虚拟端口(0.2d)
- 编辑 frontend_vue3/src/stages/xilink/composables/useSubgraph.ts
- 新增导出函数 createEmptySubgraph(name?: string): SubgraphDefinition:
  · 返默认含 inputPorts: [{ id: 'in_0', label: 'Input 1', type: 'audio', internalMapping: null, order: 0 }]
  · 返默认含 outputPorts: [{ id: 'out_0', label: 'Output 1', type: 'audio', internalMapping: null, order: 0 }]
  · nodes: [] · edges: [] · cyclic 检查跳过(空子图无环)
- 找 Toolbar 入口 1 "新建子图" 按钮处理函数 · 改调用 createEmptySubgraph
- 入口 2(多选封装 createSubgraphFromSelection)保留不动 · 推导算法 zero 改

Step 4 · R1.1 tab 模式画布容器改造(0.4d)
- 编辑 frontend_vue3/src/stages/xilink/LinkEditor.vue
- 顶部加 tab bar 组件(LinkEditorTabs.vue · 可新建 · ≤ 80 行 SFC)· tab 项:
  · `Main`(始终在 · 不可关)
  · `Subgraph X`(每打开一个 SubgraphDefinition 加 1 tab · × 可关 · 关闭仅移出 openTabs · 不删 SubgraphDefinition)
  · `+` 按钮(等价"新建子图" · 调 createEmptySubgraph)
- 编辑 useSubgraph.ts:加状态 openTabs: Ref<string[]>(SubgraphDefinition.id 数组) + activeTab: Ref<'main' | string>
- 改造 SubgraphCanvas.vue:从 Teleport modal 改为 inline 画布(根据 activeTab 切换显示 main 画布 / 某子图画布)
  · 主画布(Main)和子图画布共用 LinkEditor 主区域
  · v-show 切换(不 unmount 保留状态 · 用户期望 tab 切回保留视图)
- 双击 SubgraphNodeInstance handler(40781e8 已有 openSubgraphEditor):
  · 若 def.id 不在 openTabs → push 进 openTabs
  · 设 activeTab = def.id
  · 切换画布显示
- 关闭 tab(× 按钮)→ 从 openTabs 移除 · 若是 activeTab 切回 'main'
- 响应式:viewport < 768px tab bar 折叠成 hamburger menu(下拉显示当前 tab + 其他 tab 列表 · 复用现有响应式工具)
- 面包屑保留(子图 tab 内顶部):`Main / Subgraph X` 风格 · 现有 SubgraphBreadcrumb 复用

Step 5 · R1.4 端口全可配 Inspector 段(0.4d)
- 新建 frontend_vue3/src/components/inspector/SubgraphPortsSection.vue(≤ 150 行 SFC)
- props:`subgraphDef: SubgraphDefinition`(由 inspector router 注入 · 现有机制)
- emits:`update:def`(整 SubgraphDefinition 回传 store)
- 模板含 4 区:
  · 基本信息(name 输入 + description 输入 · readonly:nodes 数量 / edges 数量预览)
  · inputPorts 列表(<tr> 行:label 输入 + type 下拉(audio/control) + internalMapping readonly + ▲▼ 重排 + 🗑 删除)
  · `+ Add Input Port` 按钮 → push `{ id: 'in_<N>', label: 'Input <N+1>', type: 'audio', internalMapping: null, order: <N> }`
  · outputPorts 列表(同 inputPorts 结构) + `+ Add Output Port`
- 改 SubgraphPort 时立即 emit `update:def`(整 def 深拷贝回传 · fork 2 isDirty watch 会捕)
- 编辑 RightInspector.vue:在现有 6 段中插入 SubgraphPortsSection(选中 SubgraphNodeInstance 或 SubgraphDefinition 时显示 · 普通 module 时隐藏 · 用现有 inspectorRouter 路由)

Step 6 · vitest 单测(0.2d)
- 新增 frontend_vue3/tests/composables/useSubgraph-default-ports.test.ts(≥ 4 case):
  · case 1:createEmptySubgraph() 返回含 1 inputPort + 1 outputPort
  · case 2:默认端口 internalMapping === null
  · case 3:默认端口 type === 'audio' · order === 0
  · case 4:createSubgraphFromSelection(40781e8 推导路径)不受 createEmptySubgraph 影响(回归)
- 新增 frontend_vue3/tests/components/SubgraphPortsSection.test.ts(≥ 5 case):
  · case 1:渲染 1in/1out · 显示 2 行
  · case 2:Add Input Port 按钮 click · emit update:def 含 2 inputPorts
  · case 3:删除 1 outputPort · emit update:def 含 0 outputPorts
  · case 4:rename label · emit update:def 含新 label
  · case 5:type 切换 audio→control · emit update:def 字段更新

Step 7 · build + test + 手动 e2e(0.2d)
- cd frontend_vue3
- npm run typecheck(零错误)
- npm run test:unit(基线 +9 case 全绿)
- 手动 e2e(浏览器):
  · npm run dev
  · 进 P1-xilink stage
  · 点 Toolbar "新建子图" → 父画布出现 SubgraphNodeInstance(✅ 显示 1 input + 1 output 默认端口)
  · 双击 SubgraphNodeInstance → 顶部 tab bar 出现 `Main | Subgraph A` · activeTab=Subgraph A · 画布切换显示子图画布
  · 点 Main tab → 切回主画布 · 子图 tab 视图保留
  · 关 Subgraph A tab(×)→ tab 移除 · activeTab=Main · 重新双击 SubgraphNodeInstance 重开
  · 选中 SubgraphNodeInstance → Inspector 显示 SubgraphPortsSection
  · Add Input Port → 子图节点新增 1 input(右侧端口数 +1)
  · Rename Input 1 → Audio L · 节点端口 label 更新
  · Type 切 audio→control · type 标识变化
  · 删除 Output 1 → 节点输出端口 -1(节点变"纯输入")
  · ⚠️ 持久化(fork 2 实装):本 fork 不保证刷新后保留 · 用户验收时与 fork 2 合并测

Step 8 · commit + push(0.05d)
- git add frontend_vue3/src/stages/xilink/LinkEditor.vue \
          frontend_vue3/src/stages/xilink/SubgraphCanvas.vue \
          frontend_vue3/src/stages/xilink/LinkEditorTabs.vue(新建) \
          frontend_vue3/src/stages/xilink/composables/useSubgraph.ts \
          frontend_vue3/src/components/inspector/SubgraphPortsSection.vue(新建) \
          frontend_vue3/src/components/inspector/RightInspector.vue \
          frontend_vue3/src/types/subgraph.ts \
          frontend_vue3/tests/composables/useSubgraph-default-ports.test.ts \
          frontend_vue3/tests/components/SubgraphPortsSection.test.ts
- git commit subject + trailer 见下
- git push origin xistudio

【验收】

形式合规:
- [ ] npm run typecheck 零错误
- [ ] npm run test:unit 全绿(基线 +9 case)
- [ ] 仅修动 7-9 文件(2 新建 SFC + 1 types 扩 + 5 改 + 2 tests)
- [ ] 不破坏 推导算法(40781e8) · 单击高亮 · cyclic 检查
- [ ] 不动 stages/xitest/* / stages/xitune/* / stores/linkStore.ts(fork 2 范畴)

业务行为契约(端到端真值 · 必跑):
- [ ] Toolbar 新建子图 → 默认 1 input + 1 output 端口可见(R1.2)
- [ ] 双击 SubgraphNodeInstance → 顶部 tab bar 加 tab + 切换画布(R1.1)
- [ ] tab × 关闭 → 视图移除 · SubgraphDefinition 仍在 store(再次双击重开)
- [ ] mobile 视口 tab bar 折叠 hamburger(R1.1 响应式)
- [ ] Inspector SubgraphPortsSection · Add/Remove/Rename/Reorder 全可用(R1.4)
- [ ] type 下拉支持 audio + control(K2-protocol-v2 预留)
- [ ] 节点端口数随 Inspector 操作实时更新

【commit】
subject:`feat(P1.UA8R1-subgraph-redesign-tab-and-ports): tab bar + default 1in/1out + Inspector ports config · ADR-08-R1 §5 R1.1+R1.2+R1.4`

trailer(必须精确):
[step=8/8] [pid=P1] [uid=UA8R1-subgraph-redesign-tab-and-ports] [occupies=P1.K-xilink-canvas+P1.K-inspector+P1.K-types]
[files=frontend_vue3/src/stages/xilink/LinkEditor.vue, SubgraphCanvas.vue, LinkEditorTabs.vue, composables/useSubgraph.ts, components/inspector/SubgraphPortsSection.vue, RightInspector.vue, types/subgraph.ts, tests/composables/useSubgraph-default-ports.test.ts, tests/components/SubgraphPortsSection.test.ts]
[isolation] file(同 worktree 同 branch · 与 fork 2 文件正交)
[adr] ADR-AIOS-08-R1 §5 R1.1+R1.2+R1.4
[truth-check] LinkEditor 顶部布局=<X> · SubgraphCanvas modal 改造点=<Y> · Inspector 段插入位置=<Z>
[acceptance] 双击切 tab + 默认 1in/1out + 端口 Inspector 可配 · 待 fork 2 zombie 后用户合测 C4-1~C4-17

【禁止】
1. ❌ 不动 stores/linkStore.ts toJSON/fromJSON(fork 2 范畴 · 即便顺手见也不改)
2. ❌ 不动 useSubgraph.ts createSubgraphFromSelection 推导算法(40781e8 已落 · 仅加 createEmptySubgraph)
3. ❌ 不动 cyclic 检查 · 单击高亮 · 双击调 openSubgraphEditor 现有逻辑
4. ❌ 不动 types/subgraph.ts 现字段(仅扩 description?/order? 可选 · LEGACY 兼容)
5. ❌ 不动 stages/xitest/* / stages/xitune/* · 不动 ADR-08 议题①②③⑤ 已 zombie 区域
6. ❌ 不引入新画布库 / 新依赖(用现有 vue-flow / Pinia / SFC)
7. ❌ 不实装 autosave(R1.5 决议明确不做 · fork 2 仅 Ctrl+S)
8. ❌ 不省略 truth-check 报告 + 三元组 trailer

解锁链(本任务 zombie 后)

  • ✅ 配合 fork 2(P1.UA8R1-subgraph-persist-and-dirty)zombie → ADR-08 议题④ 全 17 项验收(C4-1~C4-17)解锁
  • ✅ K2-protocol-v2 §control-signal-bus 接入预留(SubgraphPort.type='control')
  • ✅ Ximind 大模型可读端口配置(SubgraphPort.description / label)

风险评估

风险 缓解
⚠️ tab bar 加在 LinkEditor 顶部可能与现 toolbar 布局冲突 Step 1 真值核查先看 LinkEditor 现 layout · tab bar 加在 toolbar 下方独立行 / 复用现有空间
⚠️ SubgraphCanvas 从 Teleport modal 改 inline 可能影响 z-index / 现有动画 v-show 切换保状态 · 删 modal 包装 · 改用 LinkEditor 主区 v-if/v-show 切换
⚠️ Inspector 段插入位置不当导致其他段错乱 用 inspectorRouter 现有路由(P0.U-right-inspector-framework 77b7a50 框架) · 仅 SubgraphNodeInstance/Definition 选中时显示
⚠️ 与 fork 2(linkStore + keymap)同 ClaudeA worker 串行可能漏触发 isDirty fork 1 改 SubgraphPort 时通过 store action(emit update:def → store mutation)· fork 2 watch store 自然捕到

历史

时间 事件 hash
2026-05-31 20:51 dispatched · 用户拍板 start P1.UA8R1-subgraph-redesign-tab-and-ports · ADR-08-R1 fork 1 三决议(R1.1 tab + R1.2 默认端口 + R1.4 Inspector 可配)· 1.5d ClaudeA · 与 fork 2 文件正交可串行 / 单 commit