From 9615bb32562ef41f2a05b9412cd34b8995acdef7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 28 Aug 2026 18:05:58 +0000 Subject: [PATCH 1/2] Add workbench plan, gap checklist, and IM design Document the terminal-manager north star, mosaic/workspace/ACP/provider plan, owner decisions, and the independent IM agent bridge. Co-authored-by: Gao Yu --- docs/desktop-gap-checklist.md | 34 ++++++++++ docs/im-bridge.md | 56 ++++++++++++++++ docs/workbench-plan.md | 118 ++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 docs/desktop-gap-checklist.md create mode 100644 docs/im-bridge.md create mode 100644 docs/workbench-plan.md diff --git a/docs/desktop-gap-checklist.md b/docs/desktop-gap-checklist.md new file mode 100644 index 0000000..6c2a3e1 --- /dev/null +++ b/docs/desktop-gap-checklist.md @@ -0,0 +1,34 @@ +# JuCode Desktop 差距清单(Gap Checklist) + +> 基准:`main@6f83aa4`。配套阅读:`docs/workbench-plan.md`。 +> 已勾选([x])= 方向已确认、直接排期实施;未勾选([ ])= 存在分歧或多方案,需要 owner 拍板后才能动工。 + +## 已确认(直接实施) + +| 状态 | 事项 | 说明 | 相关代码 | +| --- | --- | --- | --- | +| [x] | 马赛克平铺树 + 多面板同时可见 | 手写二叉 TileTree,叶子为标签栈;替代"右 Dock 单激活面板"模型 | `src/lib/RightDock.svelte`、新 `src/lib/workbench/tiles.ts` | +| [x] | 双击最大化/还原 | 树外记 `maximizedLeafId`,不改布局树 | 新 `src/lib/workbench/` | +| [x] | 拖拽分屏落点预览 | 叶子边缘 1/4 命中区 + 半透明预览层 | 新 `src/lib/workbench/` | +| [x] | Workspace 实体 + 从 Project 迁移 | Workspace ⊃ Project;首启把现有 `SavedProject[]` 包进默认工作区,序列化加 `version` | `src/lib/session.svelte.ts`(`SavedProject`、`serialize/restore`) | +| [x] | 原生 TUI 标签 | `pty_open` 增加 cmd/args,直接跑 jucode/codex/claude 交互式 CLI;v1 为独立会话 | `src-tauri/src/lib.rs`(`pty_open`)、`src/lib/TerminalPanel.svelte` | +| [x] | ACP 作为新增后端(先上 feature flag) | 新 `BackendId` 类别;保留 codex/claude 原生 adapter(hunks/resume/set_model 不回退) | `src/lib/backends/index.ts`、新 `backends/acp.ts` | +| [x] | 模型选择器四分组 | Codex 官方 / Claude 官方 / JuCode 内置 / 自定义(BYOK),标注官方 vs 内置 | `src/lib/Composer.svelte`、`src/lib/settings/CustomProviderForm.svelte` | +| [x] | serve/CLI 功能对齐残留 | 补齐 `/pin`、`command_list` 等 CLI 已有而桌面缺失/不完整的命令 | `src/lib/backends/{jucode,codex,claude}.ts` | + +## 待拍板(需 owner 决策) + +| 状态 | 事项 | 选项与倾向 | 相关代码 | +| --- | --- | --- | --- | +| [ ] | CodeMirror 编辑器:保留 vs 隐藏 | A=冻结为 diff/代码审阅面(本文倾向);B=移出主 UI。任一选项均不加 LSP | `src/lib/editor/EditorPane.svelte` 等 | +| [ ] | 内嵌浏览器 + DOM 拾取器:保留 vs 隐藏 | A=冻结为只读预览、移除 DOM 拾取器(倾向);B=整体移除。拾取器+截图回传已近似 browser-use,与北极星冲突 | `src-tauri/src/browser.rs`、`src-tauri/src/browser_init.js`、`src/lib/BrowserPanel.svelte`、`src/lib/browser.svelte.ts` | +| [ ] | GitHub PR 创建:保留 vs 隐藏 | 倾向保留(属"交付"而非 IDE 功能),但需与北极星裁剪口径一致 | `src/lib/gitops.ts`(`gh pr view/create` 封装)、`src/lib/GitPanel.svelte` | +| [ ] | MiMo ASR 语音输入:保留 vs 隐藏 | MiMo 是 ASR 不是 LLM;与"管理 agent"主线无关但成本低 | `src/lib/audio.ts`、`src/lib/protocol.ts` | +| [ ] | 布局引擎:手写 vs dockview | 本文强烈倾向手写二叉树(轻量、可测、贴合 Svelte 5);dockview 是重依赖 | 新 `src/lib/workbench/tiles.ts` | +| [ ] | GUI/TUI 同会话交接(handoff) | v1 不做;v2 可做"显式关一侧、resume 另一侧"(codex `thread/resume`、claude 会话文件)。永不双活 | `src/lib/backends/{codex,claude}.ts` | +| [ ] | IM 在应用退出后保持在线 | 需要独立守护进程(daemon)或系统服务;否则 IM 仅在桌面运行时可用 | 新模块,见 `docs/im-bridge.md` | +| [ ] | IM 渠道:仅走 OpenClaw 网关 vs 应用内原生 Rust 渠道实现 | 倾向 OpenClaw-only 起步;原生实现 = 5 套 SDK 维护成本 | 见 `docs/im-bridge.md` | +| [ ] | 技能来源:桌面直连 GitHub vs jucode-backend 聚合 | 直连(anthropics/skills raw)简单但无审计;后端聚合可做许可/兼容性过滤 | `src/lib/Marketplace.svelte`、`src/lib/protocol.ts`(`fetchMarketplace`) | +| [ ] | Provider 目录数据源 | models.dev 快照 vs OpenRouter 目录 vs 仅 JuCode `/v1/models` | `src/lib/settings/`、`src/lib/pricing.ts` | +| [ ] | 密钥存储:沿用 JSON vs OS 钥匙串 | 现状明文写 `~/.jucode/{config.json,auth.json}`;钥匙串更安全但跨平台成本高 | `src/lib/protocol.ts`(`writeConfig`) | +| [ ] | Workspace 持久化位置 | 现状会话/布局大量依赖 `localStorage`(如 `jucode-dock-tabs`);建议迁 app-data 文件(可备份、可被 IM 桥读取) | `src/lib/RightDock.svelte`、`src/lib/session.svelte.ts` | diff --git a/docs/im-bridge.md b/docs/im-bridge.md new file mode 100644 index 0000000..9b53553 --- /dev/null +++ b/docs/im-bridge.md @@ -0,0 +1,56 @@ +# IM 桥设计(IM Bridge) + +> 配套阅读:`docs/workbench-plan.md` §3.7。定位:IM 是 JuCode Desktop 唯一的第三方集成方向。 + +## 1. 形态:独立 IM agent + +IM 桥是一个 **独立 agent**,不是聊天会话里的一个功能: + +- 它不复用 `src/lib/session.svelte.ts` 里的任何会话;它通过桌面端暴露的 MCP server 与工作台交互。 +- 职责只有三类:**查询**(workspace / 项目 / 标签页 / 会话的结构化状态)、**通知**(会话进度与完成事件推送到 IM 渠道)、**指派**(把 IM 侧收到的 prompt 提交给指定会话,经确认队列)。 +- 它不直接持有任何引擎 adapter,也不读写用户文件系统。 + +``` +IM 渠道 ── OpenClaw 网关 ── IM agent ── MCP(localhost+token) ── JuCode Desktop + (微信/TG/Discord/飞书) (workspace/会话) +``` + +## 2. 桌面端 MCP 工具清单 + +桌面端内置一个仅监听 `127.0.0.1` 的 MCP server(streamable HTTP),供 IM agent 调用: + +| 工具 | 类型 | 说明 | +| --- | --- | --- | +| `list_workspaces` | 查询 | 返回 workspace → project → 标签页树(id、名称、路径、后端、布局摘要) | +| `get_session_status` | 查询 | 指定会话的状态:引擎、模型、运行/空闲/等待批准、当前 plan 步骤、最近一条消息摘要 | +| `get_session_transcript_tail` | 查询 | 会话最近 N 条消息的脱敏文本(不含文件内容附件) | +| `list_pending_approvals` | 查询 | 各会话待批准的工具调用摘要 | +| `assign_prompt` | 指派 | 向指定会话提交 prompt;**默认进入确认队列**,返回 queue id | +| `get_assignment_status` | 查询 | 查询指派的状态(排队 / 已放行 / 已拒绝 / 已完成) | +| `subscribe_events` | 通知 | 订阅进度事件流:turn 开始/结束、plan 更新、会话完成、错误、待批准出现 | + +**刻意不提供**:文件读写、shell 执行、批准/拒绝工具调用、修改配置——IM 侧永远拿不到直接改动本机的能力。 + +## 3. 安全模型 + +1. **仅 localhost**:MCP server 绑定 `127.0.0.1`,不监听外网;与外部渠道的连接由 IM agent 经 OpenClaw 网关向外发起(出站连接),桌面端不开公网入站端口。 +2. **Token 鉴权**:桌面端启动时生成随机 token,IM agent 必须携带;token 不落 IM 渠道,只存在于本机配置。 +3. **确认队列(confirm-before-assign,默认开启)**:`assign_prompt` 不直接注入会话,而是进入桌面 UI 的确认队列,用户看到"来自 <渠道>/<发送者> 的 prompt → 目标会话"后手动放行。可按渠道+会话粒度选择"信任后自动放行",默认不信任。 +4. **无文件系统工具**:见上表;即使 IM agent 被劫持,攻击面也止于"读会话摘要 + 排队一条待确认的 prompt"。 +5. **发送者白名单**:渠道侧只响应绑定过的账号/群。 + +## 4. 渠道接入 + +统一经 **OpenClaw / Cloudbot 网关** 接入,不在应用内手写 5 套渠道 SDK(待拍板项见 `docs/desktop-gap-checklist.md`): + +| 渠道 | 接入方式 | 说明 | +| --- | --- | --- | +| Telegram | 官方 Bot API | 经 OpenClaw 渠道插件 | +| Discord | 官方 Bot API(Gateway) | 经 OpenClaw 渠道插件 | +| 飞书 | 官方开放平台机器人 API | 经 OpenClaw 渠道插件 | +| 微信 | **腾讯 openclaw-weixin / iLink 插件** | 走腾讯提供的插件通道,而非第三方协议 hook / 逆向方案。注意:不要将其宣传为"合法官方机器人 API"之类的合规背书;本文档不做任何法律层面的声明,接入前请自行确认适用条款 | + +## 5. 边界与后续 + +- **应用退出后 IM 是否在线**:当前设计下 MCP server 随桌面应用生命周期存在,应用退出即离线;若要求 always-on,需要独立 daemon(待拍板,见 checklist)。 +- v1 通知走轮询/事件订阅二选一实现即可,不引入消息队列等重依赖(遵循 AGENTS.md 轻量原则)。 diff --git a/docs/workbench-plan.md b/docs/workbench-plan.md new file mode 100644 index 0000000..0506a74 --- /dev/null +++ b/docs/workbench-plan.md @@ -0,0 +1,118 @@ +# JuCode Desktop 工作台架构规划(Workbench Plan) + +> 基准代码:`main@6f83aa4`。定位声明:JuCode Desktop 是一个 **终端 / TUI 编码代理管理器**,不是完整的 AI IDE。本文给出从当前代码到北极星目标的架构方案。 + +## 1. 现状(已核实事实) + +以下每条均在 `6f83aa4` 上核实过,附代码出处: + +- **技术栈**:Tauri 2 + Svelte 5(runes)。前端入口 `src/routes/+page.svelte`,Rust 侧 `src-tauri/src/lib.rs`。 +- **多引擎后端**:jucode / codex / claude 三个后端通过统一的 `EngineAdapter` 接口接入(`src/lib/backends/index.ts` 的 `createAdapter(id: BackendId)`,实现在 `src/lib/backends/{jucode,codex,claude}.ts`)。事件被归一化为 `NormalizedEvent` 流。 +- **布局**:侧边栏(`src/lib/Sidebar.svelte`)+ 聊天主区 + 可选 CodeMirror 编辑器(`src/lib/editor/EditorPane.svelte`)+ 右侧 Dock。右侧 Dock 共 **9 种面板类型**(`src/lib/RightDock.svelte` 的 `ALL_PANELS`:plan / goal / changes / turns / files / git / term / browser / diag),同一时刻只有一个激活标签;标签持久化在 `localStorage`(key `jucode-dock-tabs`)。 +- **项目 ⊃ 会话,但没有 Workspace**:`src/lib/session.svelte.ts` 的 `SavedProject` 持久化 `{id, name, path, tabs[], worktree?, lastBackend?}`,即一个 Project 已经容纳多个会话标签,但不存在跨项目的 Workspace 实体。 +- **内嵌浏览器是原生子窗口**:`src-tauri/src/browser.rs` 用 `WebviewWindowBuilder` 创建原生子 `WebviewWindow`(非 DOM iframe),全局单例(`BROWSER_LABEL`),由前端 `src/lib/BrowserPanel.svelte` 定位覆盖到面板区域。带 DOM 元素拾取器(`src/lib/browser.svelte.ts`、`src-tauri/src/browser_init.js`)。 +- **PTY 已存在但只跑用户 shell**:Rust 侧基于 `portable-pty`(`src-tauri/src/lib.rs` 中 `pty_open/pty_write/pty_resize/pty_close`),前端 `src/lib/TerminalPanel.svelte` 用 `@xterm/xterm` 渲染。当前 `pty_open` 启动的是用户默认 shell,**不是** agent 交互式 TUI。 +- **没有任何 ACP**(Agent Client Protocol)代码。 +- **模型选择器已存在**:`src/lib/Composer.svelte` 的 `modelRows/modelActive` 弹层,由各 adapter 的 `model_status` / `set_model` 驱动;支持自定义 OpenAI 兼容 provider(`src/lib/settings/CustomProviderForm.svelte`,字段 `id/base_url/api_key/models`)。**MiMo 是 ASR(语音输入),不是 LLM**(`src/lib/audio.ts`、`src/lib/protocol.ts`)。 +- **MCP / 技能 UI 仅对 jucode 后端生效**:`src/lib/settings/McpSection.svelte`、`src/lib/Marketplace.svelte`(经 `/skills install` 命令下发),codex / claude 后端不接入这套 UI。 +- **没有任何 IM 集成**。 +- **已有的"偏 IDE"能力清单**:CodeMirror 编辑器(含 diff gutter / AI 高亮)、内嵌浏览器 + DOM 拾取器、屏幕捕获(`src-tauri/src/capture.rs`)、并行任务 worktree(`src/lib/gitops.ts` 的 `parseWorktreeList` 等)、Git 面板、GitHub PR 桥(`src/lib/gitops.ts` 封装 `gh pr view/create`,UI 在 `src/lib/GitPanel.svelte`)。 + +## 2. 北极星目标(用户输入) + +1. 管理所有编码 agent:既提供 GUI 包装,也能直接跑 **原生 agent TUI**。 +2. **马赛克(mosaic)标签布局**:多个标签同时可见、类 Windows Snap 的吸附分屏、双击最大化/还原、拖拽时显示分屏预览。 +3. **Workspace 包含多个标签页**(跨项目)。 +4. ACP 包装质量对标 VS Code agents UI / T3code。 +5. MCP + 技能插件管理;官方 JuCode 技能 + Anthropic 技能([anthropics/skills](https://github.com/anthropics/skills);注意其中 docx/pdf/pptx/xlsx 四个文档技能是 **source-available 而非 OSS 许可**,且 Claude Code 无法使用这些预置文档技能)。 +6. 模型切换四分组:Codex 官方 / Claude 官方 / JuCode 已配置全部模型;区分"官方 provider"与"内置 provider"。 +7. 更多 LLM provider 通过 **复用** 接入,而不是写 10+ 个 adapter。 +8. **不是完整 IDE**:不做 memory、不做 computer-use、不做 browser-use。 +9. 唯一的第三方集成是 **IM**:微信(经腾讯 openclaw-weixin / iLink 插件接入——**不要**将其表述为"合法官方机器人 API")、OpenClaw/Cloudbot、Telegram、Discord、飞书。 +10. IM 是一个 **独立 agent**:可查询 workspace / 标签页结构化信息、推送进度与完成通知、把 prompt 指派到指定会话。 + +## 3. 架构建议 + +### 3.1 实体模型:Workspace ⊃ Project + +在 `SavedProject` 之上加一层 Workspace,而不是重写会话层: + +``` +Workspace ─┬─ Project A ─┬─ Session(GUI, jucode) + │ └─ Session(TUI, codex) ← PTY 标签 + ├─ Project B ── Session(GUI, claude) + └─ layout: TileTree ← 布局归 Workspace +``` + +- `SessionStore`(`src/lib/session.svelte.ts`)当前直接持有 `projects: Project[]`;新增 `WorkspaceStore` 持有 `workspaces: Workspace[]`,每个 Workspace 引用一组 project id + 一棵布局树。 +- **迁移**:首次启动时把现有全部 `SavedProject[]` 包进一个名为"默认工作区"的 Workspace,序列化格式加 `version` 字段。现有 `serialize()/restore()`(`session.svelte.ts:459/482`)保持兼容读取。 + +### 3.2 布局:手写二叉平铺树(不引入 dockview) + +- 数据结构:`TileNode = Leaf(tabStackId) | Split(dir, ratio, [TileNode, TileNode])`。纯函数操作(split / remove / resize / normalize),放 `src/lib/workbench/tiles.ts`,配单测(拆分、移除后归并、比例归一化)。 +- 每个叶子是一个 **标签栈**(多个 tab,一个激活),tab 内容类型:GUI 会话 / TUI 会话 / 冻结的预览面板(见 3.6)。 +- 交互:拖拽 tab 到叶子边缘 1/4 区域显示半透明 **分屏预览**(一个绝对定位 div,无需引擎支持);**双击 tab 栏最大化/还原**(在树外记一个 `maximizedLeafId`,还原即清空,不改树)。 +- 不用 dockview 的理由:它是 Vue/React/vanilla 面板框架,体积与抽象都超出需要,且与 Svelte 5 runes 响应式模型不贴合;本项目设计规则明确"性能与轻量优先、不引入重依赖"(AGENTS.md)。二叉树 + 少量 DOM 是可控且可测的。 +- 现有 `RightDock.svelte` 的 9 面板可以先原样作为一种 tab 类型挂进叶子,逐步拆散。 + +### 3.3 原生 TUI 标签 = PTY 里跑交互式 CLI + +- 复用现有 PTY 通道:给 `pty_open`(`src-tauri/src/lib.rs:2197`)加可选 `cmd/args` 参数,直接拉起 `jucode` / `codex` / `claude` 交互式 CLI,而不是用户 shell;前端复用 `TerminalPanel.svelte` 的 xterm 渲染。 +- **v1:独立会话**。TUI 标签就是一个独立的 agent 会话,与 GUI 会话互不共享状态。这是零协议成本的正确起点。 +- **v2(可选):显式交接(handoff)**。GUI 会话可"转为 TUI":GUI 侧关闭 adapter,拿会话/thread id,在 PTY 里以 resume 方式拉起 CLI(codex 有 `thread/resume`,claude 有 `--session-id` + 会话文件,见 `src/lib/backends/{codex,claude}.ts`)。反向同理。 +- **永远不做"双活"**:同一引擎会话绝不同时被 GUI adapter 和 TUI 进程持有——两个客户端抢一个 stdio/会话文件没有可靠语义。 + +### 3.4 ACP:作为新增 BackendKind,不替换原生 adapter + +- 在 `src/lib/backends/index.ts` 的 `BackendId` 上新增 `acp` 类别(一个 ACP adapter × N 个可执行配置),先藏在 feature flag 后面。 +- **保留** codex / claude 原生 adapter:它们已实现 diff hunks、`resume`、`set_model`、command_list 等能力(见 `src/lib/backends/codex.test.ts`、`claude.test.ts` 中对 `caps.resume`、`set_model`、`command_list` 的断言),ACP v1 协议面覆盖不了这些,切 ACP 会是功能回退。 +- ACP 的价值是**长尾**:任何实现了 ACP 的第三方 agent 一次接入,UI 质量对标 VS Code agents UI / T3code——即 plan、tool call、diff、权限请求都走已有的 `NormalizedEvent` 归一化渲染,而不是另做一套界面。 + +### 3.5 模型与 Provider + +- 模型选择器改为四分组:**Codex 官方 / Claude 官方 / JuCode 内置 / 自定义**。数据源分别是 codex adapter 的 `model_status`、claude adapter 的 `list_models`、jucode 后端配置、`CustomProviderForm` 的 BYOK 条目。UI 上明确标注"官方 provider"与"内置 provider"。 +- 扩展更多 provider 走 **目录 + BYOK 复用**,不写 10+ adapter: + - 内置一份 [models.dev](https://models.dev) 目录快照(构建期生成的 JSON),提供 provider → base_url / 模型清单的预填;用户只填 API key,落到现有自定义 OpenAI 兼容 provider 通道。 + - OpenRouter 作为 featured 条目置顶(一个 key 覆盖长尾模型)。 + - **不在桌面端内嵌 LiteLLM**:那是一个 Python 代理服务,与"轻量桌面应用"冲突;聚合应发生在 jucode 后端或用户自己的网关。 + +### 3.6 收敛"IDE 化"能力(两种专家观点,需要拍板) + +北极星明确"不是完整 IDE、不做 browser-use",但代码里已有编辑器、内嵌浏览器 + DOM 拾取器、GitHub PR 桥。两种处理观点: + +- **观点 A(冻结为预览面)**:保留 CodeMirror 编辑器和内嵌浏览器,但**冻结**——编辑器定位为"代码/diff 审阅面"(保留 diff gutter、AI 高亮),浏览器定位为"只读预览面";不再投入 LSP、补全、调试等 IDE 方向的功能。理由:审阅 agent 产出的 diff、预览 agent 起的 dev server,是"管理 agent"闭环的一部分,不是 IDE 功能。 +- **观点 B(移除/隐藏)**:编辑器、内嵌浏览器、GitHub PR 桥都移出主 UI(藏到设置开关或直接删)。理由:DOM 拾取器 + 截图回传(`browser_init.js` + `capture.rs`)事实上已经是半个 browser-use,与北极星直接冲突;留着就会被继续投喂功能。 +- **本文建议**:取 A 的编辑器(冻结为审阅面)+ 介于 A/B 之间的浏览器(冻结为纯预览;**若用户确认严格执行北极星,则移除 DOM 拾取器**)。GitHub PR 桥保留(它服务于"agent 完成任务后交付",不是 IDE 功能)。**明确不加 LSP**。最终需 owner 在 `docs/desktop-gap-checklist.md` 中逐项拍板。 + +### 3.7 IM:独立 agent + MCP 桥(详见 `docs/im-bridge.md`) + +- IM agent 是独立进程/会话,不复用聊天会话。桌面端暴露一个 **仅监听 localhost、token 鉴权的 MCP server**,提供查询 workspace/标签结构、读取会话进度、指派 prompt 等工具。 +- 渠道接入统一走 **OpenClaw 网关**(Telegram / Discord / 飞书官方 Bot API;微信经腾讯 openclaw-weixin / iLink 插件),**不要**上来就在应用内手写 5 套渠道 SDK。 +- 默认 **confirm-before-assign**:IM 侧发来的 prompt 先进桌面确认队列,用户放行后才注入会话。 + +### 3.8 技能与 MCP 管理 + +- 现有 Marketplace(`src/lib/Marketplace.svelte`)与 MCP 设置(`McpSection.svelte`)是 jucode-only。规划为统一插件管理页: + - **技能源**:官方 JuCode 技能 + [anthropics/skills](https://github.com/anthropics/skills)。展示时标注许可:anthropics/skills 中 docx / pdf / pptx / xlsx 为 source-available(非 OSS),且 **Claude Code 无法使用这些预置文档技能**,UI 需按后端做可用性过滤。 + - **MCP**:配置按后端能力分发(jucode 走现有 `/mcp` 命令通道;claude / codex 写各自配置文件)。 + - 技能获取路径(桌面直连 GitHub vs 经 jucode-backend 聚合)是待拍板项。 + +## 4. 分期 + +| 阶段 | 内容 | 涉及模块 | +| --- | --- | --- | +| M1 | 平铺树 + 多可见面板 + 双击最大化 + 分屏预览;Workspace 实体与迁移 | `src/lib/workbench/`(新)、`session.svelte.ts`、`+page.svelte` | +| M2 | 原生 TUI 标签(PTY 跑 jucode/codex/claude CLI,独立会话) | `src-tauri/src/lib.rs`(pty_open 扩展)、`TerminalPanel.svelte` | +| M3 | 模型选择器四分组;provider 目录 + BYOK 复用;serve/CLI 功能对齐残留(`/pin`、`command_list`) | `Composer.svelte`、`settings/`、`backends/` | +| M4 | ACP backend(flag 后);技能/MCP 统一管理页 | `backends/acp.ts`(新)、`Marketplace.svelte`、`McpSection.svelte` | +| M5 | IM 桥(MCP server + OpenClaw 网关 + 确认队列) | 新 crate/模块,见 `docs/im-bridge.md` | +| 贯穿 | IDE 能力收敛(按 checklist 拍板结果执行) | `editor/`、`BrowserPanel`、`GitPanel` | + +## 5. 不做的事 + +- 不做完整 IDE:无 LSP、无补全、无调试器。 +- 不做 memory、computer-use、browser-use。 +- 不在桌面端内嵌 LiteLLM 等聚合代理。 +- 不为 IM 手写 5 套渠道 SDK。 +- 不引入 dockview 等重型面板框架。 +- 不做 GUI/TUI 同会话双活。 From 1132557d3fe2ed28ea282d22323b4e33170050cb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 28 Aug 2026 18:19:45 +0000 Subject: [PATCH 2/2] Lock desktop owner decisions in plan docs Co-authored-by: Gao Yu --- docs/desktop-gap-checklist.md | 27 ++++++++++----------- docs/im-bridge.md | 6 +++-- docs/workbench-plan.md | 45 +++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/docs/desktop-gap-checklist.md b/docs/desktop-gap-checklist.md index 6c2a3e1..8bdb9d0 100644 --- a/docs/desktop-gap-checklist.md +++ b/docs/desktop-gap-checklist.md @@ -12,23 +12,22 @@ | [x] | 拖拽分屏落点预览 | 叶子边缘 1/4 命中区 + 半透明预览层 | 新 `src/lib/workbench/` | | [x] | Workspace 实体 + 从 Project 迁移 | Workspace ⊃ Project;首启把现有 `SavedProject[]` 包进默认工作区,序列化加 `version` | `src/lib/session.svelte.ts`(`SavedProject`、`serialize/restore`) | | [x] | 原生 TUI 标签 | `pty_open` 增加 cmd/args,直接跑 jucode/codex/claude 交互式 CLI;v1 为独立会话 | `src-tauri/src/lib.rs`(`pty_open`)、`src/lib/TerminalPanel.svelte` | -| [x] | ACP 作为新增后端(先上 feature flag) | 新 `BackendId` 类别;保留 codex/claude 原生 adapter(hunks/resume/set_model 不回退) | `src/lib/backends/index.ts`、新 `backends/acp.ts` | +| [x] | ACP 作为新增后端(先上 feature flag) | 新 `BackendId` 类别;保留 jucode/codex/claude 原生 adapter(hunks/resume/set_model 不回退) | `src/lib/backends/index.ts`、新 `backends/acp.ts` | | [x] | 模型选择器四分组 | Codex 官方 / Claude 官方 / JuCode 内置 / 自定义(BYOK),标注官方 vs 内置 | `src/lib/Composer.svelte`、`src/lib/settings/CustomProviderForm.svelte` | | [x] | serve/CLI 功能对齐残留 | 补齐 `/pin`、`command_list` 等 CLI 已有而桌面缺失/不完整的命令 | `src/lib/backends/{jucode,codex,claude}.ts` | +| [x] | CodeMirror 仅作 AUDIT/diff 审阅面 | 不扩展为编辑器、不加 LSP;默认隐藏,只能由用户交互打开 | `src/lib/editor/EditorPane.svelte` 等 | +| [x] | 内嵌浏览器保留元素拾取器 | 浏览器仅用于预览与用户主动 pick;不做 agent 浏览器自动化,不把 picker 定义为 browser-use | `src-tauri/src/browser.rs`、`src-tauri/src/browser_init.js`、`src/lib/BrowserPanel.svelte`、`src/lib/browser.svelte.ts` | +| [x] | GitHub PR 作为插件 | 保留 PR 交付能力,但从 core 边界移到插件,不作为桌面核心功能 | `src/lib/gitops.ts`、`src/lib/GitPanel.svelte` | +| [x] | 扩展 ASR 接入 | 保留 MiMo ASR,并扩展到更多 ASR 协议/provider;不将 ASR 归类为 LLM provider | `src/lib/audio.ts`、`src/lib/protocol.ts` | +| [x] | IM 独立 agent | OpenClaw 网关优先;默认 confirm-before-assign;v1 随桌面生命周期运行,不做 always-on daemon,后续有需要再评估 | 见 `docs/im-bridge.md` | +| [x] | 技能来源 | 同时支持官方 JuCode 技能与 [anthropics/skills](https://github.com/anthropics/skills),并展示许可与后端兼容性 | `src/lib/Marketplace.svelte`、`src/lib/protocol.ts` | +| [x] | Provider 目录 | 内置 models.dev 快照 + 复用现有 BYOK 通道 + OpenRouter featured;不内嵌 LiteLLM | `src/lib/settings/`、`src/lib/pricing.ts` | +| [x] | 密钥存储 | 密钥继续存 JSON,以简单加密保护;不接 OS keychain | `src/lib/protocol.ts`(`writeConfig`) | +| [x] | Workspace 持久化 | 迁移到 app-data 文件并带版本;不使用 `localStorage` 作为 Workspace/布局持久层 | `src/lib/RightDock.svelte`、`src/lib/session.svelte.ts` | +| [x] | 产品能力边界 | 不做 memory、computer-use、内置 browser-use;元素拾取器仅是用户控制的 preview + pick | `src/lib/BrowserPanel.svelte`、`src-tauri/src/browser_init.js` | -## 待拍板(需 owner 决策) +## 后续项(不影响已锁定方向) -| 状态 | 事项 | 选项与倾向 | 相关代码 | +| 状态 | 事项 | 规划 | 相关代码 | | --- | --- | --- | --- | -| [ ] | CodeMirror 编辑器:保留 vs 隐藏 | A=冻结为 diff/代码审阅面(本文倾向);B=移出主 UI。任一选项均不加 LSP | `src/lib/editor/EditorPane.svelte` 等 | -| [ ] | 内嵌浏览器 + DOM 拾取器:保留 vs 隐藏 | A=冻结为只读预览、移除 DOM 拾取器(倾向);B=整体移除。拾取器+截图回传已近似 browser-use,与北极星冲突 | `src-tauri/src/browser.rs`、`src-tauri/src/browser_init.js`、`src/lib/BrowserPanel.svelte`、`src/lib/browser.svelte.ts` | -| [ ] | GitHub PR 创建:保留 vs 隐藏 | 倾向保留(属"交付"而非 IDE 功能),但需与北极星裁剪口径一致 | `src/lib/gitops.ts`(`gh pr view/create` 封装)、`src/lib/GitPanel.svelte` | -| [ ] | MiMo ASR 语音输入:保留 vs 隐藏 | MiMo 是 ASR 不是 LLM;与"管理 agent"主线无关但成本低 | `src/lib/audio.ts`、`src/lib/protocol.ts` | -| [ ] | 布局引擎:手写 vs dockview | 本文强烈倾向手写二叉树(轻量、可测、贴合 Svelte 5);dockview 是重依赖 | 新 `src/lib/workbench/tiles.ts` | | [ ] | GUI/TUI 同会话交接(handoff) | v1 不做;v2 可做"显式关一侧、resume 另一侧"(codex `thread/resume`、claude 会话文件)。永不双活 | `src/lib/backends/{codex,claude}.ts` | -| [ ] | IM 在应用退出后保持在线 | 需要独立守护进程(daemon)或系统服务;否则 IM 仅在桌面运行时可用 | 新模块,见 `docs/im-bridge.md` | -| [ ] | IM 渠道:仅走 OpenClaw 网关 vs 应用内原生 Rust 渠道实现 | 倾向 OpenClaw-only 起步;原生实现 = 5 套 SDK 维护成本 | 见 `docs/im-bridge.md` | -| [ ] | 技能来源:桌面直连 GitHub vs jucode-backend 聚合 | 直连(anthropics/skills raw)简单但无审计;后端聚合可做许可/兼容性过滤 | `src/lib/Marketplace.svelte`、`src/lib/protocol.ts`(`fetchMarketplace`) | -| [ ] | Provider 目录数据源 | models.dev 快照 vs OpenRouter 目录 vs 仅 JuCode `/v1/models` | `src/lib/settings/`、`src/lib/pricing.ts` | -| [ ] | 密钥存储:沿用 JSON vs OS 钥匙串 | 现状明文写 `~/.jucode/{config.json,auth.json}`;钥匙串更安全但跨平台成本高 | `src/lib/protocol.ts`(`writeConfig`) | -| [ ] | Workspace 持久化位置 | 现状会话/布局大量依赖 `localStorage`(如 `jucode-dock-tabs`);建议迁 app-data 文件(可备份、可被 IM 桥读取) | `src/lib/RightDock.svelte`、`src/lib/session.svelte.ts` | diff --git a/docs/im-bridge.md b/docs/im-bridge.md index 9b53553..8e5fb5f 100644 --- a/docs/im-bridge.md +++ b/docs/im-bridge.md @@ -1,6 +1,8 @@ # IM 桥设计(IM Bridge) > 配套阅读:`docs/workbench-plan.md` §3.7。定位:IM 是 JuCode Desktop 唯一的第三方集成方向。 +> +> **Owner 决策(2026-08-28,已锁定)**:IM 使用独立 agent;v1 优先接 OpenClaw 网关并默认 confirm-before-assign;不做 always-on daemon,后续有明确需要再评估。 ## 1. 形态:独立 IM agent @@ -41,7 +43,7 @@ IM 渠道 ── OpenClaw 网关 ── IM agent ── MCP(localhost+token) ─ ## 4. 渠道接入 -统一经 **OpenClaw / Cloudbot 网关** 接入,不在应用内手写 5 套渠道 SDK(待拍板项见 `docs/desktop-gap-checklist.md`): +v1 统一经 **OpenClaw / Cloudbot 网关** 接入,不在应用内手写 5 套渠道 SDK: | 渠道 | 接入方式 | 说明 | | --- | --- | --- | @@ -52,5 +54,5 @@ IM 渠道 ── OpenClaw 网关 ── IM agent ── MCP(localhost+token) ─ ## 5. 边界与后续 -- **应用退出后 IM 是否在线**:当前设计下 MCP server 随桌面应用生命周期存在,应用退出即离线;若要求 always-on,需要独立 daemon(待拍板,见 checklist)。 +- **应用退出后 IM 离线**:v1 的 MCP server 与 IM agent 均随桌面应用生命周期运行,不安装 always-on daemon 或系统服务。仅在后续出现明确需求并重新决策后,才评估独立 daemon。 - v1 通知走轮询/事件订阅二选一实现即可,不引入消息队列等重依赖(遵循 AGENTS.md 轻量原则)。 diff --git a/docs/workbench-plan.md b/docs/workbench-plan.md index 0506a74..026a9ad 100644 --- a/docs/workbench-plan.md +++ b/docs/workbench-plan.md @@ -2,6 +2,22 @@ > 基准代码:`main@6f83aa4`。定位声明:JuCode Desktop 是一个 **终端 / TUI 编码代理管理器**,不是完整的 AI IDE。本文给出从当前代码到北极星目标的架构方案。 +## Owner decisions(2026-08-28,已锁定) + +- 布局使用手写二叉 TileTree,**不引入 dockview**。 +- Workspace 与布局持久化到 **app-data 文件**,不使用 `localStorage` 作为持久层。 +- 密钥继续保存在 JSON 中并做简单加密,**不接 OS keychain**。 +- CodeMirror 不扩展为编辑器:只用于 **AUDIT/diff**,默认隐藏,仅在用户交互后打开。 +- 内嵌浏览器保留元素拾取器;它只做用户控制的 **preview + pick**,不是 browser-use 自动化。 +- GitHub PR 能力作为 **插件** 实现,不进入 core。 +- 保留 MiMo ASR,并扩展更多 ASR 协议/provider。 +- ACP 是新增 backend;保留原生 jucode / codex / claude backend。 +- 模型选择器使用四分组。 +- IM 是独立 agent:OpenClaw 网关优先、confirm-before-assign;v1 不做 always-on daemon,后续有明确需要再评估。 +- 技能源为官方 JuCode 技能 + [anthropics/skills](https://github.com/anthropics/skills)。 +- Provider 目录使用 models.dev 快照 + BYOK + OpenRouter featured;不引入 LiteLLM。 +- 不做 memory、computer-use、内置 browser-use。 + ## 1. 现状(已核实事实) 以下每条均在 `6f83aa4` 上核实过,附代码出处: @@ -46,6 +62,7 @@ Workspace ─┬─ Project A ─┬─ Session(GUI, jucode) - `SessionStore`(`src/lib/session.svelte.ts`)当前直接持有 `projects: Project[]`;新增 `WorkspaceStore` 持有 `workspaces: Workspace[]`,每个 Workspace 引用一组 project id + 一棵布局树。 - **迁移**:首次启动时把现有全部 `SavedProject[]` 包进一个名为"默认工作区"的 Workspace,序列化格式加 `version` 字段。现有 `serialize()/restore()`(`session.svelte.ts:459/482`)保持兼容读取。 +- **持久化**:Workspace、TileTree 与标签状态统一写入 app-data 下的版本化文件;`localStorage` 只可保留非关键、可丢弃的 UI 偏好,不作为 Workspace/布局事实来源。 ### 3.2 布局:手写二叉平铺树(不引入 dockview) @@ -75,27 +92,35 @@ Workspace ─┬─ Project A ─┬─ Session(GUI, jucode) - 内置一份 [models.dev](https://models.dev) 目录快照(构建期生成的 JSON),提供 provider → base_url / 模型清单的预填;用户只填 API key,落到现有自定义 OpenAI 兼容 provider 通道。 - OpenRouter 作为 featured 条目置顶(一个 key 覆盖长尾模型)。 - **不在桌面端内嵌 LiteLLM**:那是一个 Python 代理服务,与"轻量桌面应用"冲突;聚合应发生在 jucode 后端或用户自己的网关。 +- MiMo 保留为 ASR provider,并把语音输入层抽象到更多 ASR 协议/provider;ASR 配置与 LLM provider 目录分开。 -### 3.6 收敛"IDE 化"能力(两种专家观点,需要拍板) +### 3.6 收敛"IDE 化"能力(已锁定) -北极星明确"不是完整 IDE、不做 browser-use",但代码里已有编辑器、内嵌浏览器 + DOM 拾取器、GitHub PR 桥。两种处理观点: +北极星明确"不是完整 IDE、不做 browser-use",已有能力按以下边界收敛: -- **观点 A(冻结为预览面)**:保留 CodeMirror 编辑器和内嵌浏览器,但**冻结**——编辑器定位为"代码/diff 审阅面"(保留 diff gutter、AI 高亮),浏览器定位为"只读预览面";不再投入 LSP、补全、调试等 IDE 方向的功能。理由:审阅 agent 产出的 diff、预览 agent 起的 dev server,是"管理 agent"闭环的一部分,不是 IDE 功能。 -- **观点 B(移除/隐藏)**:编辑器、内嵌浏览器、GitHub PR 桥都移出主 UI(藏到设置开关或直接删)。理由:DOM 拾取器 + 截图回传(`browser_init.js` + `capture.rs`)事实上已经是半个 browser-use,与北极星直接冲突;留着就会被继续投喂功能。 -- **本文建议**:取 A 的编辑器(冻结为审阅面)+ 介于 A/B 之间的浏览器(冻结为纯预览;**若用户确认严格执行北极星,则移除 DOM 拾取器**)。GitHub PR 桥保留(它服务于"agent 完成任务后交付",不是 IDE 功能)。**明确不加 LSP**。最终需 owner 在 `docs/desktop-gap-checklist.md` 中逐项拍板。 +- **CodeMirror**:仅保留为 AUDIT/diff 审阅面,可承载 diff gutter 与 AI 高亮;不扩展编辑能力,不加 LSP、补全或调试。入口默认隐藏,只有用户明确交互时才打开。 +- **内嵌浏览器**:保留预览与 DOM 元素拾取器,但 picker 必须由用户主动触发;不提供 agent 自主导航、点击、填表等自动化,因此不属于内置 browser-use。 +- **GitHub PR**:保留"任务完成后交付"能力,但以插件提供,core 不直接拥有 GitHub PR 创建逻辑。 +- **产品禁区**:不加入 memory、computer-use 或内置 browser-use。 ### 3.7 IM:独立 agent + MCP 桥(详见 `docs/im-bridge.md`) - IM agent 是独立进程/会话,不复用聊天会话。桌面端暴露一个 **仅监听 localhost、token 鉴权的 MCP server**,提供查询 workspace/标签结构、读取会话进度、指派 prompt 等工具。 - 渠道接入统一走 **OpenClaw 网关**(Telegram / Discord / 飞书官方 Bot API;微信经腾讯 openclaw-weixin / iLink 插件),**不要**上来就在应用内手写 5 套渠道 SDK。 - 默认 **confirm-before-assign**:IM 侧发来的 prompt 先进桌面确认队列,用户放行后才注入会话。 +- v1 随桌面应用生命周期运行,应用退出即离线;不提供 always-on daemon。独立 daemon 仅作为后续有明确需求时的可选演进。 ### 3.8 技能与 MCP 管理 - 现有 Marketplace(`src/lib/Marketplace.svelte`)与 MCP 设置(`McpSection.svelte`)是 jucode-only。规划为统一插件管理页: - **技能源**:官方 JuCode 技能 + [anthropics/skills](https://github.com/anthropics/skills)。展示时标注许可:anthropics/skills 中 docx / pdf / pptx / xlsx 为 source-available(非 OSS),且 **Claude Code 无法使用这些预置文档技能**,UI 需按后端做可用性过滤。 - **MCP**:配置按后端能力分发(jucode 走现有 `/mcp` 命令通道;claude / codex 写各自配置文件)。 - - 技能获取路径(桌面直连 GitHub vs 经 jucode-backend 聚合)是待拍板项。 + - 技能的下载传输路径可按审计与缓存要求实现,但不得改变上述两个已锁定技能源。 + +### 3.9 本地数据与密钥 + +- Workspace、布局和标签元数据写 app-data 中的版本化文件,支持迁移与备份;不落 `localStorage`。 +- Provider 密钥继续使用 JSON 配置格式,对敏感字段做简单加密;不依赖 OS keychain。加密失败必须显式报错,不能回退为明文写入。 ## 4. 分期 @@ -103,15 +128,15 @@ Workspace ─┬─ Project A ─┬─ Session(GUI, jucode) | --- | --- | --- | | M1 | 平铺树 + 多可见面板 + 双击最大化 + 分屏预览;Workspace 实体与迁移 | `src/lib/workbench/`(新)、`session.svelte.ts`、`+page.svelte` | | M2 | 原生 TUI 标签(PTY 跑 jucode/codex/claude CLI,独立会话) | `src-tauri/src/lib.rs`(pty_open 扩展)、`TerminalPanel.svelte` | -| M3 | 模型选择器四分组;provider 目录 + BYOK 复用;serve/CLI 功能对齐残留(`/pin`、`command_list`) | `Composer.svelte`、`settings/`、`backends/` | -| M4 | ACP backend(flag 后);技能/MCP 统一管理页 | `backends/acp.ts`(新)、`Marketplace.svelte`、`McpSection.svelte` | +| M3 | 模型选择器四分组;models.dev 快照 + BYOK + OpenRouter featured;扩展 ASR provider;serve/CLI 功能对齐残留(`/pin`、`command_list`) | `Composer.svelte`、`settings/`、`audio.ts`、`protocol.ts`、`backends/` | +| M4 | ACP backend(flag 后,保留原生 backend);技能/MCP 统一管理页;GitHub PR 插件化 | `backends/acp.ts`(新)、`Marketplace.svelte`、`McpSection.svelte`、插件接口 | | M5 | IM 桥(MCP server + OpenClaw 网关 + 确认队列) | 新 crate/模块,见 `docs/im-bridge.md` | -| 贯穿 | IDE 能力收敛(按 checklist 拍板结果执行) | `editor/`、`BrowserPanel`、`GitPanel` | +| 贯穿 | IDE 能力按 owner 决策收敛;Workspace/app-data 与 JSON 密钥迁移 | `editor/`、`BrowserPanel`、`session.svelte.ts`、配置存储 | ## 5. 不做的事 - 不做完整 IDE:无 LSP、无补全、无调试器。 -- 不做 memory、computer-use、browser-use。 +- 不做 memory、computer-use、内置 browser-use;用户主动操作的浏览器 preview + pick 不属于自动化。 - 不在桌面端内嵌 LiteLLM 等聚合代理。 - 不为 IM 手写 5 套渠道 SDK。 - 不引入 dockview 等重型面板框架。