Files
ycode/docs/workbench-file-editor-assessment-2026-10-16.md
T

148 lines
20 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.
# Workbench 文本预览与编辑源码评估(2026-10-16)
结论:普通文件树打开的 text/code 预览,原版就是 **只读 MonacoEditor**,不是一个需要保存按钮的通用文件编辑器。当前 YCode 的只读方向与该入口一致,但 `<pre>` 远未等价于原 Monaco 渲染、查找、折叠、选择和主题。现有 REA 已保存完整 Monaco 包装组件与核心引擎源码,能够按源码恢复;目前缺的是完整引擎依赖闭包的本地接线与运行时验收,不能概括为“拿不到源码”。原 Monaco npm 精确版本仍未证实,不应根据 CDN 字符串安装猜测版本。
评估阶段只读现有 YCode、既有 REA Evidence;追加检查只通过已有 REA `export-selected-artifact-text` 对固定 ASAR 的明确 metadata 路径导出,未操作原版页面、未安装依赖。后续经 root 授权的只读代码预览实现与真实验收记录见文末。offset 均为对应原始 JS 字符串的 **零起点 UTF-16、半开区间**,不是重排后代码行号,也不是 UTF-8 文件字节偏移。
## 原版入口与实际行为
| 入口 | 源码实际实现 | 编辑/保存边界 |
| --- | --- | --- |
| 文件树普通 text/code | `FileViewer → FileViewerContent → MonacoEditor`,lazy `codeEditor-D3P9alks.js` | `readOnly:true`,没有此分支的 `onChange`/磁盘保存。不要添加原版不存在的 save UI。 |
| 文件树 Markdown rendered 模式 | `FileViewerMarkdownPreview → MarkdownEditorCore` | 这里同样 `readOnly:true`;提供相对图片解析、文件链接、zoom。原条件是 rendered 且文件名以 `.md` 结尾。 |
| media artifact 的 CodePreview | 同一个 MonacoEditor | `readOnly:true`,**fontSize14、minimap:true**;不能与普通文件的 13px/minimap:false 混用。 |
| custom artifact `contentType:'code'` | `ArtifactContentRenderer → MonacoEditor` | 传 `readOnly:!artifact.enableEdit`。该调用片段没有传 `onChange` 或 save,故不能据 enableEdit 宣称已支持磁盘持久化。 |
| media Markdown 编辑 | `markdown-editor-C1Uvzy8a.js` 的 `MarkdownEditor`,默认 readOnly:false,使用 `MarkdownEditorCore` | 完整文档编辑、dirty/save/source 注册、外部文件变化订阅;支持 in-process 与 isolated iframe guest 两条路径。独立于普通 text 预览。 |
| 较早 custom Markdown 分支 | `src-Cng7axVa.js` 的 `MarkdownViewer/MarkdownEditor` | 能看到 LexicalComposer 与 SavePlugin;这不能用来替代当前 media Markdown SDK 实现。 |
| code diff / file-change | `PierreDiffEditor` | 与 MonacoEditor 同一打包文件导出,但底层是 Pierre diff;不是普通文本编辑器。YCode 已有 recovered-pierre 引擎。 |
| HTML 编辑 | 独立 `onEditHtml/isHtmlEditing/onExitEditHtml` 与 browser/document preview 路由 | 不属于普通 text/code 分支;本次未证明完整 HTML 编辑宿主/save 协议,不借此扩展通用文件编辑需求。 |
普通预览核心调用确切为:
```tsx
<MonacoEditor value={content || ''} language={getLanguageFromFileName(filename)}
readOnly={true} minimap={false} lineNumbers="on" wordWrap="on"
fontSize={13} height="100%" />
```
位置:`media-preview-DMz4TW4q.js` offset 201964(props 的 readOnly 位于 201991);`FileViewerContent` 起点 194277;lazy Monaco import 位于 186752。CodePreview 的 14px/minimap:true 在 205633 附近。custom artifact code/diff 路由分别在 `src-Cng7axVa.js` 411051、411458;diff lazy 导出 `PierreDiffEditor` 在 394785。
普通入口是 renderer 内的 Monaco DOM 编辑控件:完整 `editor.api2/editor.main` 与 React loader 调用链可见,**没有证据将其称为 CodeMirror 或外部原生 VS Code 编辑宿主**。此结论只限上述入口,不推断全应用从未使用其他编辑器。
## 已拿到的包装组件与依赖
`codeEditor-D3P9alks.js` 原末尾直接导出 `re as MonacoEditor, No as PierreDiffEditor`。Monaco 组件赋值 `re` 在 **[14737,21221)**,6484 字符,原体 SHA-256:`6d7aeb7714f2f52fd86c37957a12c5774be029b31e96f39a50b7e8e6ec11b9a8`。自定义搜索组件 `ee` 在 **[11624,13951)**,2327 字符,SHA:`e8030c9dd9bb94e12f4a3e4816362ec53e52b4380b348c38b42627ff37dbfac4`。这两段均已保存在静态 shipped-artifact Evidence 中;runtime 的 339 项集合没加载该 lazy 文件,不等于源码缺失。
包装层已确证的行为:
- 字体 `'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace`;普通入口 13px,包装默认 lineHeight20/tabSize4;字体最终值 `max(8, fontSize + --cb-font-size-offset)`,监听 `cb-font-size-change`。
- `automaticLayout:true`、`scrollBeyondLastLine:false`、纵横 scrollbar10px/useShadows:false、folding:true、glyphMargin:false、contextmenu:true、links:true、colorDecorators:true、括号及缩进 guides。
- 只读时 `renderLineHighlight:'none'`、`matchBrackets:'never'`、`selectionHighlight:false`、`occurrencesHighlight:'off'`。
- 自定义 Ctrl/Cmd+F 搜索;大小写、整词、regex、匹配计数、prev/next、Escape,Monaco decoration 标记与 `revealLineInCenter`。这不是对话区的 CSS Highlight 搜索。
- SharedThemeManager 从源主题/CSS 构造 `custom-dark/custom-light`,订阅主题变化;模型/编辑器/decoration 有卸载释放逻辑。`onChange` 只是包装层回调能力,不是保存文件实现。
源码依赖链为 `MonacoEditor → monaco-init → React Monaco loader / editor.main → editor.api2 + monaco.contribution + workers + 动态语言模块`。不能直接 import 整个 `codeEditor` 原入口:它混有 Pierre 引擎、应用 UI imports 与模块初始化;应像既有 Pierre recovery 一样抽取所需 closure,并将 React/i18n/UI primitives 与宿主入口显式绑定。
现有 Pierre recovery 已明确拒绝 `./src-0FGg1seX.js`、`./monaco-init-CE4MbM4x.js` 进入其闭包。因此 `recovered-pierre/engine.mjs` 不能当成已经恢复了 Monaco 的证明;可复用的是它的 AST closure/hash/资源复制工作方式。
`monaco-init` 优先导入本地 `editor.main-POO0Vbhx.js`。其 `configureMonacoEnvironment` 在 window 尚无 MonacoEnvironment 时设置 **no-op worker**(offset16148/16626),注释日志明确为 CSP compatibility。`workers-BAt3Re_d.js` 也有标准 getWorker/getWorkerUrl/createWorker 路径。不得无证据新增“原版已运行完整 TS language server”的结论。
`editor.main` 静态依赖的核心模块已在 runtime Evidence;但它声明的 **92 个动态 import 在该 runtime 集合中均未捕获**,包括 `cssMode-Z-o80aSY.js`、`htmlMode-BDZbYlMj.js`、`jsonMode-DdQpkp6D.js`、各 Monarch 语言模块。这是采集覆盖缺口,不是包中不存在。后续可用固定 ASAR 的 REA selected export 补齐闭包,不需原版 live UI。Pierre/Shiki 的语言模块文件即使已保存,也不能自动顶替 Monaco 对应模块。
Markdown SDK 另有真实 `smart-doc-convert` module worker:`markdown-editor-core` offset84806 引用 `worker-impl-DwAbHlUk.js`,当前 runtime 集合无此 worker。core 还依赖 `dist-CnSZIDKe.js` 的 block/contenteditable SDK 等模块。其 guest bridge有 requestSave/requestContent/requestDirty/saveResult;这条编辑链比只读 Monaco 预览大得多,不是“抽出一个 contenteditable div”即可还原。
## 精确版本能否确认
WorkBuddy 版本确认为 **@genie/workbuddy-desktop 5.8.2**,固定 ASAR SHA 为 `035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918`。
**Monaco npm 精确版本未确证。** 已查到的三个不同标记必须区分:
| 标记 | 原模块/offset | 能证明什么 |
| --- | --- | --- |
| `monaco-editor@0.55.1/min/vs` | monaco-init 6631 | 内嵌 loader 的默认 CDN 路径;不是本地 ESM 构建版本证明。 |
| `monaco-editor@0.45.0/min/vs` | monaco-init 17250、17850附近 | 本地导入失败时自定义 fallback 路径;与上项不同,更不能据此定本地版本。 |
| `Code - OSS Dev`、`version:'1.104.0-dev'` | editor.api2 399559 | 内嵌 VS Code 产品 metadata;不是 Monaco 包的 semver。 |
已保存 root `package.json` 没有 Monaco/React-Monaco 的直接版本。补充通过 public REA root-pin selected export 检查以下五个明确路径,均返回“Selected path is absent from the ASAR inventory”:`node_modules/monaco-editor/package.json`、`node_modules/@monaco-editor/react/package.json`、`node_modules/@monaco-editor/loader/package.json`、`node_modules/@genie/workbuddy-desktop-sdk/package.json`、`node_modules/@genie/workbuddy-core/package.json`。执行记录在 [.tmp/rea-editor-package-metadata-report.json](C:/Users/Administrator/code/YCode/.tmp/rea-editor-package-metadata-report.json)。这是这些路径的缺失,不能外推为整个打包应用绝无 lockfile/元数据。
两种实现路线的判断:
| 路线 | 当前可实施性 | 限制 |
| --- | --- | --- |
| 原版 wrapper/CSS + 原版 ESM chunks | **推荐**。构建内容由原 SHA 固定,避免猜包版本;需 REA 导出动态语言闭包及 YCode 本地 loader 适配。 | 资源体积/模块环、动态路径、CSP、主题和卸载必须验证。单纯复制文件不等于运行通过。 |
| 原版 wrapper/CSS + npm 安装同版本 Monaco | **暂不能称为“同版本”**。需先有可信 package/lock/notice/source-map 等版本证据。 | 0.55.1 或0.45.0目前都只是 CDN 路径;即使版本证实,也还要验证原 bundle 是否有补丁。 |
不需要为只读预览先解决 npm semver:原 ESM chunks 已给出了更精确的实现身份。不要为了“更新到最新版”更换引擎。
## 评估时 YCode 的差异基线
当前代码位置:[WorkbenchResourceBody.tsx](C:/Users/Administrator/code/YCode/src/renderer/src/workbuddy/workbench/WorkbenchResourceBody.tsx)、[workbench-adapters.css](C:/Users/Administrator/code/YCode/src/renderer/src/workbuddy/workbench/workbench-adapters.css:41)、[resources.ts](C:/Users/Administrator/code/YCode/src/main/resources.ts:73)。
| 项目 | 原普通文件预览 | YCode 当前 |
| --- | --- | --- |
| 排版/文本引擎 | Monaco 的真实字形测量、virtualized editor、gutter、selection/scroll/fold | `<pre>` 内逐行 div+span;13px/**22px**,固定48px行号 gutter,自定义padding;无法视为相同布局。 |
| 语言/颜色 | 按文件扩展名映射语言、Monarch tokenization、源主题配色 | 普通文本分支无语法 token、语言识别或编辑器主题。 |
| 查找 | 独立 editor CtrlF/大小写/整词/regex/计数/导航/decoration | 普通 `<pre>` 无该实现。 |
| 浏览交互 | fold、context menu、链接、字符/词/行选择、键盘移动、括号/缩进 guides | 仅浏览器文本选择与滚动;range 高亮是宿主新增样式,不是已恢复 Monaco decorations。 |
| 内容范围 | FileViewer 向 Monaco 传当前完整 content | resources.read 默认约400行,range窗口,最多2000行;截断文本不能当作完整 Monaco model。 |
| 读取上限 | 源 size-limit 按类别:txt50MiB、md30MiB、html50MiB,未知类别默认1GiB;检查集合含code,判断为size>=limit | 所有文本统一2MiB;二进制NUL拒绝;UTF-8读取。这些策略尚不等价。 |
| Markdown/HTML | 原 viewMode与专用SDK/browser路线 | 当前按扩展名直接送 ArtifactHostPreview,不等于源文件树的 source/rendered 模式及编辑路由。 |
| 磁盘保存 | 普通code预览不需要;Markdown编辑的 onSaveFile→local writeFile 或sandbox写入是另一条能力 | 当前 resources API只有read/readText/download等,没有通用编辑写回契约;Artifact cache update也不是写盘。 |
现有 `ArtifactPierreDiff` 已接 recovered-pierre,可继续独立验收。它不是只读文件 `<pre>` 的替代品,也不提供普通文件保存。YCode `ArtifactCode` 的 RecoveredCodeBlock 同样不是 MonacoEditor。
## 最小真实接入边界与后续证据
第一步只替换 **普通 text/code 只读预览**:保留真实 session/workspace 资源读取与 owner 隔离,恢复 `getLanguageFromFileName`、MonacoEditor/SearchWidget/CSS 与必要主题构造器;使用完整 `resources.readText` 内容建立 model,按源 props 接入 font13/line20/minimapfalse/wrapon/readOnlytrue。不要为该入口新增 save,不改成 code diff,不把400行窗口静默当全文。
加载与 worker 由独立 YCode host adapter 承担:本地 ESM 地址、CSS、动态 grammar import、CSP、主题事件和 model/worker卸载必须指向 YCode 自有资源。保留源 no-op worker 的事实;要启用真正语言 worker 则需新的功能证据和单独验收,不能把“worker包存在”当作原版已启用。源码恢复应保留body/hash及明确的React/翻译/主题接口适配记录,避免执行原应用全局初始化。
可以先单独恢复的低依赖纯源码:
| 源体 | offset | 依赖边界 |
| --- | --- | --- |
| `getLanguageFromFileName` | media-preview [191107,192191) | 扩展名 literal map,纯函数;SHA `666dfd63d32a89ed66020d0a4fb6d1a41c25be41692c3538e6b167c157fa1465`。 |
| `isUnsupportedBinaryPreview` | media-preview [186118,186398) | 纯判定+已知5项内容类型常量;SHA `e9f2e71fbfc9d3d5cb650d47cddf72f08ffc84e9b082b18b758120aedd6e0b49`。 |
| `getMonacoLanguage` | codeEditor [13985,14121) | 纯函数+语言alias map;SHA `3cd971a3042c0c9e504356e9e5b987161675e781c08000b28903fb9d10cf612a`。 |
| `resolvePreviewSizeCategory/Limit`、`resolveOversized`、`formatBytesHuman` | preview-size-limit 模块 | 纯策略与常量;可原体恢复,需保留>=边界和类别差异。 |
| SearchWidget、loading/binary/oversized视觉片段 | 上述组件与media CSS | React+源icons/buttons/i18n可隔离恢复;SearchWidget真正导航仍需Monaco实例。不是完整低依赖编辑器。 |
第二步才单独评估 Markdown 编辑:补 `worker-impl` 和block SDK/guest依赖,通过YCode主进程实现真实全文写回、dirty/revision冲突、文件变化订阅、保存错误、关闭前未保存处理;接 source `onSaveFile` 协议后再谈与原编辑能力等价。原 local链在 `detail-panel-wrapper` offset56030 使用 `writeFile(sessionId,path,text,{allowedDirs:[path]})`,云侧 offset58522 为 `writeSandboxFile`,offset135434将选出的能力传作onSaveFile。不得把cache callback或export下载冒充写回。
还需取得或验收的证据:
1. 通过REA静态 selected export补齐Monaco dynamic grammar/mode依赖图、可能字体/worker资源;保持ASAR root pin。若必须安装npm版,再找精确版本及补丁来源证据。无需占原版页面完成静态闭包导出。
2. 原版实际普通代码文件的light/dark、长行wrap、行号gutter、CtrlF三种选项、折叠、复制/选择、空文件、多tab切换的REA runtime layout/截图/动作记录。目前静态props已证实,但这些状态尚未在本次验证。
3. YCode真实production App验收完整读取、中文/Latin字形、长文本/范围定位、搜索/复制/主题、快速切tab后的model释放;sourceGPU环境做定点像素比较。编译通过不等于1:1。
4. Markdown编辑另采dirty/save/外部修改/关闭确认/guest协议,不能使用普通只读代码截图替代。
## 可复核 Evidence 与文件哈希
| 保存证据 | 内容/身份 |
| --- | --- |
| `.tmp/rea-selected-editor-evidence.json`,`ev_eff23685a08fc8c5ed6ad542c21b24337ed3d7a7c9a483628762ae17828b5d36` | `codeEditor-D3P9alks.js` SHA `5e9a16dca97c102afc3c73cd7dd32ba63daf5e7ddff12707ee1ea63e7a427b19`;`codeEditor-Bxmo_AI3.css` SHA `1c8f2210c731a25f9051088df0db78b9de5b087c802b3a9e36828c1b6b54c353`。 |
| `.tmp/rea-selected-package-plugin-evidence.json`,`ev_2caae424199a38371af743ef9111db835504c2dae54c1f02e1f9e5511032cc6b` | package.json SHA `a295ae602e936abda5ae45f7a5c21fc481014989d2cf369182d3ce5d9dd400c2`;确认产品5.8.2。 |
| `.tmp/rea-runtime-scripts.json`,`ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb` | 本文运行时JS来源,共339项;是有界已加载集合。 |
| media-preview-DMz4TW4q.js | SHA `e8c19693ac7d8d06b45b531de405cc23c071fa19ebd5543b483a43dbdfce8111`。 |
| monaco-init-CE4MbM4x.js | SHA `3cfc0aab23c1d7e100ae094bd058c0b794b3ef933eb5873011ad45368350f13a`。 |
| editor.api2-dPwET-7w.js / editor.main-POO0Vbhx.js | SHA分别 `8aa5a0e62e8f97673ade05dd05098782bb4f457c3ef6d2f6e67cf3ac0404bea7` / `a7321a42627d1814bc74385b647e21248cb23a1cd3a5daeaeb1ef7670dd08f37`。 |
| workers-BAt3Re_d.js | SHA `c502bc2291877793f68723fc7519ef587c1388f3ca4aed8603fed3372edc6dda`。 |
| src-Cng7axVa.js / detail-panel-wrapper-DkXYIOHM.js | SHA分别 `5ce8649e3bfac10aec1e63afee726ab45abaafc5aa7cc372892e20f3eba18c8b` / `35099e6a9294923f3cb413629ff47a65e5d545a7ff9226eff97675ae2dd5f906`。 |
| markdown-editor-C1Uvzy8a.js / markdown-editor-core-CH4mirps.js | SHA分别 `03c659e7a50e011db1f03b50dd80af5b99c435e6ddaf9321dee1d5fdbe579861` / `63a120cb404c65d621e4ac1489f4c6d6178d7789cd9f9e1ac2d39b4d52553477`。 |
| preview-size-limit-BPMUeizf.js | SHA `a35b8b9877f689a4e0ac3d346efc58e7e4e71bb70a1123766ebc596416123c0a`。 |
| `.tmp/rea-css-recovered/manifest.json`,`ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94` | editor-gwlzV742.css SHA `90a835b8c3b45dbf7d2f2c699876b393f0564a657e7639cc916daa506e1685b3`;media-preview-Dvr0Ekj9.css SHA `36758fadd61577145a3b46dd12bcd966c662ea0cfaa4e62dc3e31ba4bf7f5fb8`;markdown-editor-core-DOOI2-AG.css SHA `351d38dab5173c10da28b2d2962bdd21e20c44ce13dc8c65ae84667d8c919f85`。 |
评估阶段验证:已重新计算上述10份runtime JS的SHA-256,全部匹配;selected codeEditor JS/CSS与root package导出文本的SHA/size匹配;Babel AST核对wrapper/SearchWidget/纯函数原体offset与hash;运行现有 public REA export明确记录metadata路径缺失。
## 后续授权实现与真实 App 验收
已通过 [recover-source-code-preview.mjs](C:/Users/Administrator/code/YCode/scripts/rea/recover-source-code-preview.mjs) 补齐 **101 个固定 shipped assets**,包含完整当前入口依赖闭包、Monaco模式/语言模块、4个语言worker入口、codicon.ttf。8份新增 root-pin REA Evidence 保存在 `.tmp/rea-monaco-chunks-000.json` 至 `007.json`;逐文件Evidence/hash、依赖graph与原体hash在 [source-code-assets/manifest.json](C:/Users/Administrator/code/YCode/src/renderer/src/workbuddy/workbench/source-code-assets/manifest.json)。没有安装猜测版本的Monaco包。
[SourceCodePreview.tsx](C:/Users/Administrator/code/YCode/src/renderer/src/workbuddy/workbench/SourceCodePreview.tsx) 已替换 WorkbenchResourceBody 最后普通text的pre分支,其他文件类型路由保留。恢复了原6484字符Monaco包装体、2327字符SearchWidget与原类名/CSS/语言映射/close SVG;YCode React单例、原生input/button绑定是显式宿主适配。原引擎保留源no-op worker设置,资源均来自YCode本地。
必要构建适配有明确记录:原打包器`__vite__mapDeps`预加载表改为YCode的空预加载adapter,由当前Vite负责实际import与CSS地址,防止保留旧URL及Vite保留名重声明;本地导入失败的两条CDN fallback改为本地错误,失败显示原缓存文本。其余未适配资产保持逐字节SHA相同。不能据这些适配声称搜索栏全部宿主控件已经逐像素相同。
全文通过真实`resources.readText`读取;按现有上限仍是2MiB。range使用一个Monaco decoration并reveal,450→20→无range保持同一500行model URI;root的store仅对已有成功text资源更新range,避免上层loading卸载editor。现有打开model不会自动响应外部文件变化;range重开保留缓存;关闭面板卸载后重开会重新读全文。文件watch、显式刷新语义、超2MiB策略、Markdown/HTML编辑写回仍待独立接入,普通只读文件没有新增save。
已验证:`npm run build`(含node/web typecheck)、`node scripts/source-code-recovery-regression.mjs`(101资产、完整闭包、9个原体hash、无原app/React全局依赖)、`node scripts/verify-source-code-preview.cjs`(真实隔离production App/文件树/IPC)。最终报告:[source-code-preview-Su4EM3/report.json](C:/Users/Administrator/code/YCode/.tmp/source-code-preview-Su4EM3/report.json)。覆盖500行全文、源只读13px/20px/wrap/scrollbar/tabSize、真实彩色Monarch token、500个搜索命中、450→20→无range同model、深色、两会话同名文件隔离、真实临时文件删除后的错误及原文fallback。HTTP请求与renderer error均为空。原版live未操作;没有进行原版普通代码窗口的完整像素/动效验收。