Files
makelore/.project-docs/20-architecture/module-map.md
brother7 fba68e86d9
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled
merge: fix opencode model switching runtime refresh
2026-08-21 01:48:01 +08:00

85 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Module Map
## Source Layout
| Path | Responsibility | Owner Notes |
|---|---|---|
| `src/components/works/ProjectPublishAction.tsx` | 可发布项目的一键提交、云构建轮询与用户可理解状态 | 只通过 Renderer API 提交非敏感元数据;绑定告警不终止轮询 |
| `src/lib/works-square.ts` | Renderer 侧 Works Square Host API 契约与安全错误映射 | 不接触 Token、ZIP、本地绝对路径或自动部署状态 |
| `electron/api/routes/works.ts` | Works Host API、Renderer capability 门禁、上游安全投影 | 发布凭据、打包、上传与本地绑定均在 Main 内完成 |
| `electron/services/project-release-builder.ts` | Main-owned 安全快照、本地 npm/Vite 构建、source+built 双归档与 v1 contract | 固定 npm 11.6.2;项目 Vite 由 lockfile 决定;Vite config/plugins 以桌面用户权限执行 |
| `electron/services/publish-runtime.ts` | 安装包内 npm 闭包定位与 Electron Node 执行 | 不回退全局 npm/PATH;缺失或版本不符 fail closed |
| `electron/services/static-release-server.ts` | 用内存 built snapshot 建立一次性 loopback origin | 预检和最终上传归档必须来自相同文件字节;总是清理临时服务 |
| `electron/agent-browser/module.ts` | built artifact 的桌面/移动临时 WebContents/CDP 预检 | UX fail-fast;不生成可信 receipt、不得升级为平台证明 |
| `electron/agent-browser/electron-adapter.ts` | Electron WebContents/CDP 设备指标、事件与临时 partition 适配 | probe 不挂载 UI,并在结束后销毁视图、清理隔离存储 |
| `electron/services/project-packager.ts` | 受控项目扫描、静态 ZIP 生成和敏感/历史控制文件排除 | 只允许可发布 `ProjectType`,不提供 Compose 或手工 ZIP 路径 |
| `electron/services/works-submission-binding.ts` | submission binding v2 持久化与旧 schema 迁移 | 旧中间态终止为 `legacy_retired`;文件名暂作安装兼容 |
| `electron/api/works-play-url.ts` | 公共播放 URL 的共享安全校验 | 公共 `play_url` 必须同源 HTTPS 且精确匹配 App 路径 |
| `src/pages/Chat/OpencodeChatPanel.tsx` | AI 编程 Agent 选择、首次 session 创建、per-Session 模型选择、prompt 提交与消息/压缩混合时间线 | 页面模型选择器与 `/models` / `/model` 共用 OpenCode Session 切换动作;伙伴模型只作为新 Session 默认值,选中 Session 只投影自己的 run error |
| `src/lib/opencode-session-state.ts` | OpenCode 会话消息与上下文压缩时间线的规范化、hydration 和事件归并 | 压缩 UI identity 不变;native Part/event identity 用于回放去重,completed 状态不可降级 |
| `src/stores/opencode.ts` | OpenCode runtime、session、消息缓存、per-Session 模型/提交/启动确认与压缩生命周期 | Session 列表 hydration 恢复当前模型;每个 Session 独立持有 model/run/error/queue,10 秒 run-token watchdog 只终止对应 Session 且不自动重放;`session.compacted` 只完成压缩项,真实 idle 才释放 run 队列 |
| `electron/opencode/client.ts` | Makelore 内部 OpenCode DTO 与固定 runtime HTTP wire contract | 内部 `{ providerID, modelID }` 在 Session 模型切换边界映射为 OpenCode 1.18.9 `ModelRef` 的 `{ providerID, id }`;runtime 升级时复核 schema |
| `electron/opencode/provider-config.ts` | Main-owned OpenCode provider/env 配置构建 | 托管本地 AI proxy 在 owned fresh runtime 启动时使用当前进程 Host API token;持久化旧 token 不得覆盖本次 runtime 已注入值 |
| `electron/api/routes/opencode.ts` | Main-owned OpenCode Session 模型切换、execution acceptance、provider/runtime freshness 与项目 Agent 门禁 | Session 模型切换调用 OpenCode native endpoint,不写 provider/伙伴配置;fresh runtime 已生效 proxy token 的持久化不标记 stale,attached/unknown 与不确定写入仍 fail closed;message/command/summarize 共用 bounded manager FIFO,普通执行路径不自动 restart/reload/dispose |
| `electron/opencode/project-agent-runtime.ts` | 项目 Agent 逐 id desired/applied 内容状态、runtime generation provenance、live registry acceptance 与配置 mutation 串行化 | owned fresh generation 中首次出现的唯一 id 可在 live `/agent` 暴露后应用;同 id 编辑、删除后重建及 attached/unknown generation 仍 fail closed,用户修改的 retired Agent 文件不得被删除 |
| `electron/opencode/runtime-config-readiness.ts` | manager + generation scoped provider/runtime stale latch | timeout/partial persistence 保持 sticky uncertain 状态;只有成功显式 apply 后的合格 fresh generation 可解除,迟到 lease 不能改写 readiness |
| `electron/api/routes/ai-proxy.ts` | Main-owned 模型代理、凭据边界与上游响应投影 | 仅对明确上游分组饱和做终止态兼容投影,通用限速保持 `429` |
| `shared/opencode-error-details.ts` | OpenCode 上游饱和错误的窄化共享分类 | 不以通用 `rate_limit_exceeded` 单独判定饱和 |
| `electron/main/updater.ts` | 目标 feed 解析、electron-updater 生命周期与原始诊断 | 缺少稳定 manifest 保持错误;事件/Promise 重复失败按检查实例去重 |
| `src/components/settings/UpdateSettings.tsx` | 更新状态、重试与用户可读错误展示 | 只显示一条简洁中文提示;技术诊断统一回退到本地化通用文案 |
| `shared/image-workspace.ts` | AI 绘画 Workspace、Conversation、Task、Asset 与事件共享契约 | Conversation 状态与 Workspace 任务归属必须分离 |
| `electron/api/routes/image-workspace.ts` | AI 绘画 Host API 与本地事件流投影 | Renderer 只通过该路由访问 Main-owned workspace adapter |
| `electron/image-workspace/works-square-workspace.ts` | Works Square 多 Conversation 云端适配器与双向 Gateway 命令/事件映射 | 使用服务端持久 Session;WebSocket 传输故障才以同一幂等 ID 回退 REST;未知 Gateway 错误文本不得穿透安全投影;本地清理不 DELETE 远端 Session |
| `electron/image-workspace/local-workspace.ts` | 未打包开发模式的本地 Workspace 适配器和 v2→v3 迁移 | 仅开发使用,不得成为打包回退 |
| `src/stores/image-workspace.ts` | 当前 Workspace/Conversation、项目任务及流式更新状态 | Quote/task 按 Workspace 无 UI 错误副作用地对账;Conversation 写入按 Workspace-load + Conversation-selection generation/revision 防护 |
| `src/pages/ImageCanvas/index.tsx` | Conversation 对话、Quote 确认、统一任务列表、新会话入口与单图来源选择器 | 图片 Brief 选择/上传图生图参考图;视频 Brief 绑定首帧;均提交一个 Workspace Asset ID |
| `src/components/layout/ImageWorkspaceSidebar.tsx` | Workspace 与近期 Conversation 切换/创建 | 切换会话不清空项目级任务 |
| `shared/image-prompt-museum.ts` | Prompt Museum 列表、分类、详情、署名与分页共享 DTO | 客户端不包含内容数据集,只定义服务端字段契约 |
| `electron/api/routes/image-prompt-museum.ts` | Main-owned Museum 列表/详情代理与 Works 登录态 | 仅 GET 固定路径和白名单查询;Renderer 不获得 Bearer Token |
| `src/pages/ImagePromptMuseum/index.tsx` / `src/lib/image-prompt-museum.ts` / `src/stores/image-prompt-museum.ts` | Museum 搜索/筛选/详情与一次性 Prompt 回填 | 原 Prompt 只带回 Canvas 输入框,不自动发送;页面不接受投稿或互动 |
| `shared/learning.ts` / `src/lib/learning.ts` | Learning 项目列表、详情、媒体和下载结果的共享 DTO/Renderer facade | 项目 API 访问走固定 Host API;Renderer 不持有 Token、任意归档 URL 或本地路径,README 仅接受无凭据 HTTPS 图片 URL |
| `electron/api/routes/learning.ts` / `electron/services/learning-project-download.ts` | Main-owned Learning 项目代理、封面/历史媒体读取和原生 ZIP 保存 | 固定 Works 路径、严格 DTO 与媒体 MIME/大小边界、最多五跳同源重定向、SHA-256/ZIP 签名校验和原子重命名;归档不做大小校验 |
| `src/pages/Learning/` / `src/components/layout/LearningSidebar.tsx` | 分页项目卡片、README 详情和下载入口 | 保留登录与 `module_access.learning`;README 禁用原始 HTML,仅图片节点直连无凭据 HTTPS URL,旧生成/播放器入口不存在 |
| `src/pages/AiHardware/index.tsx` | Robot 管理、现有六位 Binding,以及已实现的 default-on 引导式热点配网状态机 | 只编排非敏感步骤;不接收 Wi-Fi 密码,不把 `bound` 展示为在线证明 |
| `src/lib/ai-hardware.ts` | Renderer 侧 Robot Host API 类型、安全错误映射和稳定 Binding/hotspot facade | 读取 Main-owned capability,调用固定 portal-open,并只传递短效 hotspot candidate ID;不添加任意 URL、SSID 或 Renderer IPC |
| `electron/api/routes/ai-hardware.ts` | Main-owned Robot 云端代理,以及本地 capability/portal/hotspot actions | 默认开启、精确环境值 `0` 回滚;所有本地操作必须在 Works token/上游访问前返回,且只投影稳定安全错误 |
| `electron/robot-hotspot/index.ts` | Robot hotspot 深模块:候选过滤/去重/TTL、操作互斥、超时和精确 SSID 核验 | 只接受 Adapter 输出与不透明 candidate ID;Renderer 不能选择任意 SSID |
| `electron/robot-hotspot/windows.ts` | Windows 原生 WLAN 扫描、临时开放网络连接和当前 SSID 查询 | 懒加载 `wlanapi.dll`;不使用 `netsh`、不保存 profile、不主动断开 |
| `electron/robot-hotspot/macos.ts` | macOS CoreLocation 授权与 worker-owned CoreWLAN 扫描/关联/核验 | Objective-C 对象不跨线程;取消/超时终止 worker,旧终止屏障阻止迟到权限/native continuation |
| `electron/robot-hotspot/adapter.ts` | 平台 Adapter 的最小内部契约与稳定错误分类 | 平台细节不进入 Host/Renderer 公共 DTO |
## Dependency Direction
- Renderer UI → Renderer API contract → Main Host routes → Main services → Works Square;Renderer 不反向读取 Main 凭据、文件系统或归档。
- AI 编程 Renderer per-Session model/run state → Host API → Main Session switch 或 manager-scoped execution acceptance → per-project Agent acceptance → OpenCode runtime;OpenCode provider 请求再经 Main AI proxy 访问模型上游。Renderer 不直接持有上游凭据或本地 runtime URL,Main 临界区只覆盖配置/请求 acceptance,不覆盖模型回复时长。
- Project configuration 决定产品分流;Main release builder 生成 source/built/contract,服务端独立重算和校验决定发布安全,本地 `ProjectType` 不是授权结论。
- Built artifact preflight 检查最终上传的同字节快照,但客户端可被绕过且不产生可信 receipt;服务端仍是合同、摘要和不可变 Release 安全权威。
- Robot Renderer → typed AI hardware API → Main Host route → Robot Hotspot Module → Windows/macOS Adapter。云端 Binding 仍由 Main 代理;热点选择/连接移入页面,但家庭 Wi-Fi 凭据输入仍只留在固件 Portal,系统 Wi-Fi 保留为兜底。
- Prompt Museum Renderer → typed Host API facade → Main fixed list/detail route → Works Square。Museum 只把用户明确选择的 Prompt 原文暂存到进程内 Store 并导航回当前 Canvas;不会直接触发 Agent 命令或生成任务。
- Learning Renderer → typed Host API → Main fixed project routes → Works Square list/detail/media/archive。Main 代理受控图片并持有原生保存与归档校验;Renderer 只获得安全 DTO、图片数据和保存结果。
## Risky Or Sensitive Areas
- `electron/api/routes/works.ts` 同时承担发布 capability、上游安全投影和错误脱敏,变更时必须验证未在拒绝前读取凭据或项目文件。
- `project-release-builder.ts` 执行受信本地项目的 Vite config/plugins,拥有桌面用户权限;必须保持路径、环境、时间、输出、进程树和临时目录限制,不得包装为 sandbox。
- `electron/agent-browser/module.ts` 的预检必须继续拒绝外域访问、隔离临时 partition 并清理所有 view/listener;不能因本地通过而跳过服务端逐字节校验。生产 opaque-origin 行为不由该 loopback 检查覆盖。
- `works-cloud-deploy.json` 是兼容文件名;不得因名称重新引入自动部署协调语义。
- `runtime_url` 是一个客户端版本的迁移回退;删除前必须确认服务端和存量数据稳定提供 `play_url`。
- `ai-proxy.ts` 的上游饱和状态投影依赖当前固定 OpenCode 的重试语义和窄化错误文案;升级 runtime 或调整上游错误格式时必须复核,不能把所有 `429` 统一终止。
- OpenCode 压缩时间线依赖 native compaction Part、Session run token 与 runtime generation 的关联;hydration 必须保持 completed 单调,不能用 `session.compacted` 提前结束 run 或释放 queued prompt。
- OpenCode execution acceptance 同时涉及 provider persistence、runtime lifecycle、Agent config mutation 和 runtime HTTP。锁顺序必须保持 manager → project,所有等待与 HTTP 都使用同一 hard deadline/AbortSignal;timeout 后 lease 必须撤销,queued cancellation 不能让后续 mutation 绕过前驱。
- OpenCode Agent hot reload 没有 authoritative whole-instance quiescence oracle。owned fresh generation 可接受 live registry 新发现的唯一 id,但不得以 live 同 id 代替内容 freshness;同 id 编辑或删除后重建若要即时生效,必须先获得 upstream directory-scoped invalidation 或权威 quiescence seam,不能从 `/session/status` 推断 dispose/reload 安全。
- `electron/main/updater.ts` 的稳定源错误归一化必须保持窄化:只识别 Works Square 对应 manifest 的 404,不得吞掉其他 feed/网络/签名错误;Renderer 的脱敏边界不能取代 Main 原始日志。
- 多 Conversation 事件处理必须区分对话快照与 Workspace 任务更新;不得用任务时间戳推进 Conversation 流水位,也不得让旧会话的迟到流覆盖当前会话。
- Quote 编辑、重报价、确认和项目删除都跨 Renderer/Main/Works Square。异步结果必须核对当前 Workspace + Conversation;删除当前项目时必须先使旧选择和事件流失效,再加载剩余 Workspace。
- Prompt Museum 图片和来源 URL 来自服务端数据。服务端必须完成内容授权/署名审核;若未来需要凭据化素材,应新增 Main-owned 媒体代理,不能把对象存储凭据放进 Renderer URL。
- Learning 的远端 JSON、Markdown、媒体、错误和 ZIP 下载跨信任边界;必须保持严格 DTO、固定项目/封面/历史媒体路径、可信 raster MIME、媒体/README 大小、同源重定向、SHA-256、ZIP 签名、一次 401 refresh 和固定安全错误。ZIP 下载明确不校验 `Content-Length`、`archiveBytes`、实际流字节数或客户端大小上限。README 仅允许图片节点直连经服务端校验的无凭据 HTTPS URL,不能扩展为任意 Works 下载或文件系统代理。
- Gateway 命令的 REST fallback 只处理 WebSocket 发送、断连和 ACK 超时,必须复用 `client_command_id`;业务错误回退会造成重复提交。Quote 任务恢复只更新 Workspace 所有的任务,不能覆盖当前 Conversation。
- `closeEventSessions` 只负责本地流和缓存生命周期;远端 Conversation Session 是服务端持久资源。
- 单图来源选择器当前仍由精确中文 quick reply 触发,并以 Brief medium 判断图生图或视频首帧用途;扩展更多输入用途前应先把消息协议升级为结构化 action/purpose,避免展示文案与行为继续耦合。
- Guided Hotspot Binding 已由产品决策默认开启,并通过 native dependency 执行未经认证的热点扫描/连接。未完成指定固件镜像核对、六位码发行契约、签名 macOS x64/arm64 worker/ASAR/Koffi 验证、Windows 真机和完整 Electron/Robot smoke 前不得宣称完整兼容;现场异常使用精确环境值 `0` 回滚。
## Last Updated
2026-08-21