v1.1 Viewer 双模式 + Workbench 通用设置 & Skills 全局管理 - #1
Conversation
现象: Viewer 单一形态无法同时服务开发项目与运行工作流两类心智模型; 改法: 按第一性原理定稿双模式信息架构, 开发=空间导航(全量树+高亮), 运行=产物消费(类型/目录facets+卡片流), 并明确目录多/卡片多的边界处理 Co-Authored-By: Codex <noreply@openai.com>
现象: 设置页只有Kimi配置可视化且改了不生效; 根因: 缺配置生效契约, workbench自身配置层缺失; 改法: 四层架构(产品/共享资源/投影/引擎原生), Skill用混合投影, MCP用标准定义+生成, Memory标待议, 配置存exe路径并附卡诺+第一性原理迭代规划M0-M3 Co-Authored-By: Codex <noreply@openai.com>
现象: workbench 自身配置缺失, 现有设置页只读写 Kimi 的 config.toml; 改法: 新增 WorkbenchConfigService, 配置存 exe 所在路径 config/ 子目录, exe 目录不可写时回落 userData, 支持 forceFallback 隔离 demo/sandbox; 附可写探测/原子写/损坏配置回退 Co-Authored-By: Codex <noreply@openai.com>
现象: 设置 tab 仅在 Kimi 引擎激活时可见, CloudCLI/Codex 下被隐藏且 switchTab 拒绝进入; 改法: 移除 switchTab 的 kimi-only 判断与 shell 的 hidden 逻辑, 设置入口对所有引擎开放 Co-Authored-By: Codex <noreply@openai.com>
现象: 仅默认权限模式变化会触发引擎重启, 其余字段改了不生效; 根因: 缺配置变更到运行时行为的传导契约; 改法: 新增 SETTING_SCOPES 与 hasEngineConfigChanged, 任何引擎配置变化保存后自动重启 Kimi Web 并应用到新会话 Co-Authored-By: Codex <noreply@openai.com>
现象: workbench 配置层已就绪但无 UI 读写, 配置与运行时脱节; 改法: 设置页新增 Workbench 通用面板(默认引擎/记住上次引擎), get-state/save 透传 workbench 配置, 启动按 resolveStartupEngine 决定初始引擎, 切换引擎时按 rememberEngine 持久化 lastEngine, 并清理 switchEngine 里切 CloudCLI 强制退出设置页的遗留逻辑 Co-Authored-By: Codex <noreply@openai.com>
现象: CloudCLI 上游发布 v1.37.1, 项目锁定 1.37.0; 改法: 依赖声明与 lock 升级到 1.37.1, 连带 @openai/codex-sdk 0.144→0.146; native 依赖(better-sqlite3/bcrypt/claude-agent-sdk)不变, 无 ABI 风险; npm install 同步修正 lock 遗留的 1.0.0-beta.2 版本漂移 Co-Authored-By: Codex <noreply@openai.com>
现象: 文件树仅返回人类可读产物, 开发项目时源码/图片/二进制不可见; 改法: /api/tree 支持 mode=dev 返回全量树并按 doc/code/image/binary 标记, /api/file 允许读取源码文本, 新增 /api/raw-file 图片流式接口; 运行模式默认行为不变 Co-Authored-By: Codex <noreply@openai.com>
现象: 前端无模式切换, 开发项目时源码/图片/二进制无法查看; 改法: 顶栏新增自动/开发/运行三档切换并 localStorage 持久化, 开发模式按 kind 渲染源码高亮(highlight.js)/图片预览/二进制降级, 文件树图标随 kind 区分; 引入 highlight.js 依赖与 esbuild 打包脚本 Co-Authored-By: Codex <noreply@openai.com>
P1 现象/根因: dev 模式打开图片或二进制后, 5s 周期的新鲜度检查调 /api/file-meta, 但该接口只接受文档扩展名, 恒返回 403, 界面被误标文件已删除或无法读取. 改法: file-meta 只返回 mtime/size 元数据且不含内容, 仅受 safeResolve 边界约束, 移除按扩展名拦截. P2 收窄: CODE_EXTENSIONS 移除 .env(点文件本不进树, 避免直接 API 暴露密钥); 清理 scanTree 中 classifyFileKind 永不返回 null 导致的死分支. Co-Authored-By: Codex <noreply@openai.com>
现象: 运行模式文件树无类型/目录总览, 无法按产物类型或落盘目录快速定位; 改法: 文件树顶部新增类型 facets(md/html/mmd/json)与目录 facets(顶层目录), 按数量降序, 点击过滤树; 顺带修复 loadTree 误删 currentRoot 赋值与重复 renderTree, viewerMode 读取经 normalizeViewerMode 校验非法值回退 auto Co-Authored-By: Codex <noreply@openai.com>
现象: 目录 facets 只匹配顶层目录名, output/reports 二级产物目录无法过滤, 且目录/卡片多时无上限; 改法: 目录 facets 收集所有直接含产物的目录(含嵌套)按相对路径匹配 dirname, 目录上限 12 个按产物数降序, 产物卡片流上限 100 条并提示总数, chip 限宽省略 Co-Authored-By: Codex <noreply@openai.com>
现象: viewer 默认模式只存在前端 localStorage, 无法从 workbench 设置页配置; 改法: workbench 配置新增 viewerMode 字段, 设置页 Workbench 面板加 Viewer 默认模式下拉, viewer 启动时 localStorage 未手动设置则读取 workbench 默认值, 手动覆盖优先级更高 Co-Authored-By: Codex <noreply@openai.com>
现象: 开发模式源码预览只有单一浅色, 看起来未高亮; 根因: highlight.js 只生成 hljs-* 标签, 未配套 token 级 CSS 配色; 改法: 补充 github-dark 风格 token 配色(keyword/string/number/title/comment 等), 与深色背景匹配 Co-Authored-By: Codex <noreply@openai.com>
现象: 切换目录后仅顶层目录展开, 二级目录折叠需手动点开; 改法: 默认展开深度由仅第一层改为前两层, 深目录仍折叠避免大目录 DOM 爆炸; 更新树状态单测匹配新默认 Co-Authored-By: Codex <noreply@openai.com>
现象: 本轮产物点击打开预览, 已删除的临时产物提示非法文件路径; 根因: safeResolve 对文件不存在与路径越权都返回 null, /api/file 一律回 403; 改法: 新增 pathInScope 区分文件不存在(404, 含符号链接逃逸检测)与路径越权(403), 保持安全边界 Co-Authored-By: Codex <noreply@openai.com>
现象: tmp-* 临时目录产物和 .draft/.tmp/备份等过程文件混入本轮产物与时间机器; 改法: 统一过滤规则(目录 tmp/temp-* 前缀, 文件 .draft.md/.tmp/~ 后缀), 作用于扫描树/watcher/快照/时间机器记录与回填, 只保留正式落盘文件 Co-Authored-By: Codex <noreply@openai.com>
能力资产库SSOT + 三引擎投影(指针/软链/复制) + 安全红线(只管理自建项/移除先备份) + AI摘要入口预留; 原型按第一性原理重构: 默认全开, 展开细调, 同步机制入诊断折叠 Co-Authored-By: Codex <noreply@openai.com>
新增skills-service: SSOT能力库, 默认三引擎全开, Kimi指针/Claude/Codex自动投影(symlink失败回退copy), 冲突不覆盖用户手放项, 移除先备份可恢复; main/preload新增add/remove/sync三IPC; 设置页Skills面板按v2原型落地(详情展开/引擎启停/高级诊断/AI摘要入口占位); 10个单测覆盖添加/投影/回退/冲突/备份/移除 Co-Authored-By: Codex <noreply@openai.com>
fs.watch递归在Windows上频发漏事件/文件名null, 导致scheduleArtifact不触发, 前端产物列表与时间机器长时间不更新; 加每3s轮询兜底(扫描mtime变化, 发现差异时触发scheduleArtifact), 保持fs.watch作快速通道, close()时清理定时器 Co-Authored-By: Codex <noreply@openai.com>
现象/根因:引擎开关只存在渲染状态,Kimi 能力库指针未落配置,移除备份无恢复入口,投影归属判断可能覆盖外部路径;改法:持久化 apps 矩阵并维护 extra_skill_dirs,补齐恢复 IPC/UI,使用投影标记与链接归属校验,拒绝路径穿越与外部文件覆盖;T1: 修复主进程缺失 skills-service 导入;T2: 普通文件、外部目录、外部 symlink 均报告 conflict;T3: copy 投影可重复同步/安全移除; Co-Authored-By: Codex <noreply@openai.com>
现象/根因:Windows fs.watch 失效时 polling 只扫描当前文件,未比较旧快照键集合,删除文件不会进入本轮产物与时间机器;改法:完整扫描时对旧快照做差集并调度 deleted 事件,扫描预算耗尽或目录读取失败时跳过差集避免误报;补充强制关闭 fs.watch 的删除回归测试; Co-Authored-By: Codex <noreply@openai.com>
| await fs.mkdir(ssotDir, { recursive: true }) | ||
| const tmpDir = path.join(ssotDir, `.${name}.tmp-${process.pid}-${Date.now()}`) | ||
| try { | ||
| await fs.cp(resolvedSource, tmpDir, { recursive: true }) |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
addSkillToLibrary copies untrusted skill directories with fs.cp(..., { recursive: true }) without rejecting symlink roots/entries. A crafted skill directory can preserve symlinks into tmpDir, and later projection writes (copyReplace) can follow those symlinks and write .kcc-workbench-projection.json outside the intended managed skill path.
Impact: an imported malicious skill can trigger unintended filesystem writes outside the Workbench-managed directory boundary.
Reviewed by Cursor Security Reviewer for commit a743151. Configure here.
| if (!sanitizeName(skillName)) throw new Error(`无效的 Skill 名称:${skillName}`) | ||
| const root = path.resolve(backupDir) | ||
| const source = path.resolve(backupPath) | ||
| if (source !== root && !source.startsWith(`${root}${path.sep}`)) { |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
restoreSkill validates backupPath using a lexical path.resolve + startsWith check. This does not protect against symlinked entries under backupDir that resolve outside the backup root before copy, so containment can be bypassed.
Impact: restore can ingest content from outside the intended backup boundary, weakening filesystem trust guarantees for managed skills.
Reviewed by Cursor Security Reviewer for commit a743151. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a743151. Configure here.
| } | ||
| } | ||
| return results | ||
| } |
There was a problem hiding this comment.
Disabled skills leave engine projections
High Severity
syncSkillToEngines only projects engines whose app flag is truthy and never removes an existing symlink or owned copy when that engine is turned off. The M1 design requires cleaning Workbench-owned projections for disabled managed skills, so Claude/Codex keep loading skills the UI shows as off until a full remove (and even then only if that engine is still marked enabled).
Reviewed by Cursor Bugbot for commit a743151. Configure here.
| const source = path.join(path.resolve(libraryPath), skillName) | ||
| const removal = {} | ||
| for (const engine of ENGINES) { | ||
| if (!apps?.[engine]) continue |
There was a problem hiding this comment.
Remove skips disabled engine dirs
High Severity
removeSkill only clears projections for engines still marked enabled in apps. After a user disables Claude/Codex (which does not tear down projections) and then removes the skill, those engine directories are skipped while the SSOT entry is deleted, leaving orphaned Workbench links or copies that engines still load.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a743151. Configure here.
| results[name] = await syncSkillToEngines({ | ||
| libraryPath, | ||
| skillName: name, | ||
| apps: effectiveApps, |
There was a problem hiding this comment.
Sync merges nested apps shape wrong
Medium Severity
settings:skills-sync builds effectiveApps by spreading each managed entry, but those entries are { apps: {…} }, not a flat kimi/claude/codex map. Without a full flat payload.apps override, syncSkillToEngines sees no top-level engine flags and silently skips every engine.
Reviewed by Cursor Bugbot for commit a743151. Configure here.
| if (input.dataset.app !== 'kimi') input.checked = false | ||
| else input.checked = true | ||
| setStatus('至少保留一个引擎启用', true) | ||
| return |
There was a problem hiding this comment.
Last-engine guard desyncs UI state
Medium Severity
When the last enabled engine is a non-Kimi engine and the user turns it off, the guard sets kimi true in memory but leaves that engine false and forces the checkbox to stay unchecked without re-rendering or syncing. UI and skill.apps diverge from the “at least one engine” rule the prototype enforced by reverting the toggle.
Reviewed by Cursor Bugbot for commit a743151. Configure here.


概述
面向 v1.1:Viewer 引入开发/运行双模式,并落地 Workbench 通用设置(引擎无关入口 + 生效契约),随后完成 M1 Skills 全局管理(能力资产库 + 三引擎投影)。
主要内容
测试
npm test 全绿:103 passed(含 M1 skills 服务 10 个单测)。
待验收
Note
High Risk
Writes and deletes under user engine skill directories (symlinks/copies/backups) and mutates Kimi config with broader service restarts. Large settings/IPC surface plus filesystem projection makes mistakes high-impact.
Overview
Ships v1.1 product surface: Viewer dev/run/auto views, a portable Workbench config layer, and a global Skills library that projects one SSOT into Kimi / Claude / Codex.
Viewer adds a top-bar mode switch. Dev mode requests a full tree (
?mode=dev) with source highlighting (highlight.js), image preview, and binary fallback. Run mode adds type/dir facets and caps artifact cards. Default engine/mode persist viaworkbench-config.json(execonfig/with userData fallback); settings is no longer Kimi-only, and Kimi restarts on any engine config change, not just permission mode.Skills replaces extra-dir textareas with a managed library: add/copy, per-engine enable matrix, symlink-then-copy projection into
~/.claude/skillsand~/.agents/skills, Kimiextra_skill_dirspointer, backup-before-remove + restore. User-owned dirs are not overwritten. Also bumps app version to1.0.0and CloudCLI/Codex packages.Reviewed by Cursor Bugbot for commit a743151. Bugbot is set up for automated code reviews on this repo. Configure here.