Skills:基于"锚点文件"双向追踪链路并横向扩展
第一步:从用户给的文件/目录出发,确定"锚点"所在层级
用户给的可能是任意层的任意文件。先判断它在哪一层:
code
src/renderer/ → Renderer 层(Vue/Pinia/UI) src/preload/ → Preload 层(类型桥接) src/main/ → Main 层(服务/Bridge) src/utility/ → Utility 层(独立进程,实际执行) src/Public/ → Shared 层(跨进程共享类型/常量)
判断依据:看路径前缀即可。
第二步:从锚点文件"双向追踪"
向下追(→ 被谁依赖 / 谁 import 了我):
code
grep 锚点文件的导出符号 → 找到所有消费者
例如锚点是 retrieval-plan.node.ts,导出了 runRetrievalPlanning:
- •grep
runRetrievalPlanning→ 发现graph.ts调用它 - •grep
buildKnowledgeQaGraph→ 发现models/index.ts注册它 - •继续追 →
agent-manager.ts→langchain-client-bridge-service.ts→ ...
向上追(→ 我依赖谁 / 我 import 了什么):
code
直接读锚点文件的 import 语句
例如同一个 retrieval-plan.node.ts:
- •
import type { ... } from '@shared/langchain-client.types'→ 找到类型根定义 - •
import { ChatOpenAI } from '@langchain/openai'→ 外部依赖,不用管 - •
import { HumanMessage, SystemMessage } from '@langchain/core/messages'→ 外部依赖
双向结果汇总成一条完整链路:
code
[类型根定义] ← 锚点文件 import
↕
[锚点文件] (用户给的起点)
↕
[调用者] ← grep 锚点导出符号
↕
[更上层调用者] ← 继续 grep
↕
... 直到链路两端都到达边界(UI 端 / 类型端)
第三步:定位"类型根定义"——这一步必须显式做
关键原则:横向扩展的起点永远是类型根定义所在的文件。
追踪方法:
- •读锚点文件的 import,找所有
import type { Xxx }语句 - •对每个类型,追溯到最终定义处(不是 re-export 处)
- •确认该定义文件所在层级
LuminaStudio 中类型根定义的层级规律:
| alias 前缀 | 实际路径 | 角色 |
|---|---|---|
@shared/* | src/Public/ShareTypes/* | 跨进程类型的唯一根定义 |
@preload/types | src/preload/types/ | Renderer ↔ Main IPC 契约的根定义 |
模块内部 ./types | 各模块自己的 types.ts | 模块内部私有类型 |
| 扩展时的判断: |
- •要加的字段是跨进程传递的(renderer → utility)→ 改
@shared层 - •要加的字段只在 renderer 内部用 → 改 renderer 本地 types
- •要加的字段只在 utility 内部用 → 改 utility 本地 types
第四步:识别链路上每层的组织模式
对链路经过的每个目录,判断:
模式 A:index 文件聚合同级模块
code
nodes/
├── planning/
│ └── retrieval-plan.node.ts
├── summary/
│ └── summary-decision.node.ts
└── knowledge/
└── knowledge-retrieval.node.ts
- •特征:子目录/子文件并列,index.ts 只做 re-export 或注册
- •扩展方式:新建同级目录/文件 + 在 index 里加注册
模式 B:单文件集中定义
code
langchain-client.types.ts ← 所有类型平铺在一个文件 ai-chat-service.ts ← 所有 handler 方法在一个 class
- •特征:同一职责的内容全在一个文件内
- •扩展方式:在文件内追加字段/方法/分支
判断方法(读目录结构 + 看 index.ts):
- •目录下有 index.ts 且内容是
export { xxx } from './子模块'→ 模式 A - •目录下只有一个大文件或无 index → 模式 B
- •有些层混合使用(如 store 目录下用 A,但单个 store 内部是 B)
第五步:确认每层是"透传"还是"处理"
沿链路从一端到另一端,逐层标记:
- •处理层:读取/解析/使用了这个字段的具体值 → ✅ 需要改逻辑
- •透传层:只是把整个 config 对象原样传递 → ❌ 不需要改逻辑(类型自动跟随根定义)
典型链路标记示例(给 KnowledgeQaModelConfig 加字段):
code
Shared Types → 处理(根定义,加字段) Renderer Store → 处理(维护 state + action) Renderer UI → 处理(展示/编辑 UI) Preload Types → 透传(自动引用 Shared Types) Main Service → 看情况(如果只是把 config 往下传就是透传) Main Bridge → 透传(postMessage 整个 config) Utility Manager → 透传(config 传给 buildGraph) Utility Graph → 处理(解构字段传给 node) Utility Node → 处理(使用字段值)
横向扩展的最小改动 = 只改"处理层" + 根定义。
第六步:输出扩展方案
按以下结构组织:
markdown
## 1. 类型根定义变更 - 文件:(哪个文件,什么组织模式) - 变更:(追加什么字段到哪个 interface) ## 2. 链路各层变更(仅处理层) 按数据流方向逐层列出: - 层名 / 文件 / 组织模式 / 具体变更 ## 3. 透传层(确认无需改动) 列出哪些层只需类型跟随,不改逻辑 ## 4. 注意事项 - 缓存/热生效问题(如 agent 按 conversation 缓存,config 变了需要重建) - 序列化问题(如 Pinia ref 需要 JSON.parse(JSON.stringify) 去响应式包装)
操作 Checklist(给 LLM 执行时用)
- •读锚点文件 → 判断所在层
- •读 import 语句 → 向上追到类型根定义
- •grep 导出符号 → 向下追到所有消费者
- •汇总完整链路 → 按层排列所有涉及文件
- •每层判断组织模式 → A(index聚合)还是 B(单文件)
- •每层标记透传/处理 → 确认最小改动范围
- •从类型根定义开始写方案 → 逐层向两端展开