diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml index 2cdf3e8bfb..529d3b58ce 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md -2026-08-08-native-windows-pull-request-ci.md: 8b657e3bffa7279560f3f87e5c35e7f462f2cac1 -2026-08-08-native-windows-pull-request-ci.zh.md: 6f23dd1df1ef31a8952425bdc6ed00a720d162dd +2026-08-08-native-windows-pull-request-ci.md: 4fa293c7701264cfaa557c64b9ac897d8e0e5c0f +2026-08-08-native-windows-pull-request-ci.zh.md: 575a4acda1d0ba6b2e97cccffaf107e113608ad8 diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md index 8b657e3bff..4fa293c770 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md @@ -36,6 +36,8 @@ Two product boundaries required foundation repairs. Include's debounced config p The subsequent exact hosted run isolated seven other fixture contracts. The PowerShell background-output case now waits for process completion before draining and comparing the final delta, while the pi-ai idle-watchdog case retains a bounded one-second close deadline that accommodates the delayed Windows socket notification. The asynchronous workspace projection seeds its in-memory filesystem at the host-resolved root. The Include retry acceptance asserts the injected failure and eventual persistence rather than an incidental total rename count, which may include another valid serialized write. LSP's bare-command fixture supplies a `.cmd` executable through `PATHEXT` on Windows, and URI rendering expectations distinguish the execution world's path convention from the test host's separators. None of these changes skips a supported path or weakens the asserted outcome. +That run also made syntax highlighting sensitive to runner contention rather than source text. Shiki's JavaScript engine deferred TextMate regexes longer than 3,000 characters until their first match, while Shiki counted that compilation against its 500 ms per-line tokenization budget. A busy Windows coverage worker could therefore stop the first TypeScript line after the `const` match and return the remainder under the same keyword style. The client now uses Shiki's default regex translation with lazy compilation disabled: scanner construction compiles each pattern eagerly, while the existing 500 ms budget still bounds scanning of user content. The token-boundary and Markdown DOM fixtures continue to require the complete highlighted result rather than accepting the partial stream. + POSIX mode bits, chmod-based unreadability, and chmod-based writer-lock refusal do not exist as equivalent Windows facilities. Those acceptance cases remain enforced on POSIX and are skipped on Windows; content, atomic replacement, symlink safety, rollback and recovery through platform-independent filesystem conflicts, and native Windows long-path behavior remain covered. No supported product source is excluded from Windows coverage to accommodate these differences. Wine-only infrastructure is absent from the supported workflow: there is no apt-cache producer, compatibility script, hoisted snapshot install, Windows Node download, or local `check:windows-wine` command. The [archived Wine experiment](../../archived/process/2026-07-27-wine-windows-gates-experiment.md) remains historical evidence for its measured latency and fidelity trade-offs, not a current execution path. diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md index 6f23dd1df1..575a4acda1 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md @@ -36,6 +36,8 @@ Status: implemented 随后的分支头精确托管运行又隔离出另外 7 项 fixture 契约。PowerShell 后台输出场景现在会等待进程完成,再排空并比较最后一段增量;pi-ai 空闲 watchdog 场景则保留 1 秒的有界关闭期限,以容纳 Windows 延迟送达的 socket 通知。异步工作区投影会在宿主解析后的根目录上填充内存文件系统。Include 重试验收现在断言注入的故障与最终持久化结果,而不再断言可能包含另一项合法串行写入的偶然 rename 总次数。LSP 的裸命令 fixture 会在 Windows 上通过 `PATHEXT` 提供 `.cmd` 可执行文件,URI 渲染预期也会区分执行环境的路径约定与测试宿主的分隔符。上述修改既没有跳过受支持路径,也没有削弱结果断言。 +该次运行还暴露出语法高亮会受运行器资源争用影响,而不只取决于源文本。Shiki 的 JavaScript 引擎会把超过 3,000 个字符的 TextMate 正则推迟到首次匹配时再编译,Shiki 同时把这段编译时间计入每行 500 毫秒的 tokenization(词元化)预算。繁忙的 Windows 覆盖率工作线程因此可能在首次 TypeScript 行匹配到 `const` 后提前停止,并让剩余内容沿用同一关键字样式。客户端现在仍使用 Shiki 的默认正则转换,但关闭延迟编译:scanner(扫描器)创建时会立即编译各项模式,而既有的 500 毫秒预算仍会约束对用户内容的扫描。词元边界与 Markdown DOM fixture 会继续要求完整高亮结果,不接受这类部分结果流。 + POSIX 模式位、基于 chmod 的不可读状态和基于 chmod 的 writer lock 拒绝在 Windows 上没有等价机制。这些验收场景继续在 POSIX 上强制执行,并在 Windows 上跳过;内容、原子替换、符号链接安全、通过平台无关文件系统冲突验证的回滚与恢复,以及原生 Windows 长路径行为仍保有覆盖。没有任何受支持的产品源码为适应这些差异而从 Windows 覆盖率中排除。 受支持的工作流不含 Wine 专属基础设施:不存在 apt 缓存生产者、兼容性脚本、对仓库快照执行的 hoisted 安装、Windows Node 下载或本地 `check:windows-wine` 命令。[已归档的 Wine 实验](../../archived/process/2026-07-27-wine-windows-gates-experiment.md)仍作为其实测延迟与保真度取舍的历史证据,而非当前执行路径。 diff --git a/packages/client/ui-primitives/src/markdown/highlight.ts b/packages/client/ui-primitives/src/markdown/highlight.ts index d0727c833a..b9271c101b 100644 --- a/packages/client/ui-primitives/src/markdown/highlight.ts +++ b/packages/client/ui-primitives/src/markdown/highlight.ts @@ -19,7 +19,7 @@ */ import { createHighlighterCoreSync, createCssVariablesTheme } from 'shiki/core' -import { createJavaScriptRegexEngine } from 'shiki/engine/javascript' +import { createJavaScriptRegexEngine, defaultJavaScriptRegexConstructor } from 'shiki/engine/javascript' import langTs from '@shikijs/langs/typescript' import langBash from '@shikijs/langs/shellscript' import langJson from '@shikijs/langs/json' @@ -140,6 +140,20 @@ const cssVariablesTheme = createCssVariablesTheme({ fontStyle: true, }) +/** + * The client regex engine compiles each TextMate pattern when its scanner is + * created. Shiki otherwise defers patterns longer than 3,000 characters until + * their first match; that compilation counts against Shiki's 500 ms per-line + * budget and can return a partial token stream under host contention. Eager + * compilation leaves the same budget in place for scanning user content. + */ +const regexEngine = createJavaScriptRegexEngine({ + forgiving: true, + regexConstructor: pattern => defaultJavaScriptRegexConstructor(pattern, { + lazyCompileLength: Number.POSITIVE_INFINITY, + }), +}) + let singleton: HighlighterCore | undefined /** The synchronous highlighter (one instance per document); pre-warmed below, lazy as the fallback. */ @@ -147,7 +161,7 @@ function highlighter(): HighlighterCore { singleton ??= createHighlighterCoreSync({ themes: [cssVariablesTheme], langs: LANGS, - engine: createJavaScriptRegexEngine({ forgiving: true }), + engine: regexEngine, }) return singleton }