dsh-vscode-mode 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +95 -0
  2. package/assets/compare_idle.png +0 -0
  3. package/assets/compare_select.png +0 -0
  4. package/assets/vendor/monaco/vs/abap-D-t0cyap.js +1 -0
  5. package/assets/vendor/monaco/vs/apex-CcIm7xu6.js +1 -0
  6. package/assets/vendor/monaco/vs/assets/css.worker-URu8fCFR.js +97 -0
  7. package/assets/vendor/monaco/vs/assets/editor.worker-lj3bdIIn.js +30 -0
  8. package/assets/vendor/monaco/vs/assets/editorWebWorkerMain-CA_vMoUU.js +30 -0
  9. package/assets/vendor/monaco/vs/assets/html.worker-D1SL3iM8.js +474 -0
  10. package/assets/vendor/monaco/vs/assets/json.worker-CoJx_OPf.js +62 -0
  11. package/assets/vendor/monaco/vs/assets/ts.worker-BWKtMYOk.js +67722 -0
  12. package/assets/vendor/monaco/vs/azcli-BA0tQDCg.js +1 -0
  13. package/assets/vendor/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  14. package/assets/vendor/monaco/vs/bat-C397hTD6.js +1 -0
  15. package/assets/vendor/monaco/vs/bicep-DF5aW17k.js +2 -0
  16. package/assets/vendor/monaco/vs/cameligo-plsz8qhj.js +1 -0
  17. package/assets/vendor/monaco/vs/clojure-Y2auQMzK.js +1 -0
  18. package/assets/vendor/monaco/vs/coffee-Bu45yuWE.js +1 -0
  19. package/assets/vendor/monaco/vs/cpp-CkKPQIni.js +1 -0
  20. package/assets/vendor/monaco/vs/csharp-CX28MZyh.js +1 -0
  21. package/assets/vendor/monaco/vs/csp-D8uWnyxW.js +1 -0
  22. package/assets/vendor/monaco/vs/css-CaeNmE3S.js +3 -0
  23. package/assets/vendor/monaco/vs/css.worker-CyhWkhHo.js +1 -0
  24. package/assets/vendor/monaco/vs/cssMode-CV6Ay48H.js +1 -0
  25. package/assets/vendor/monaco/vs/cypher-DVThT8BS.js +1 -0
  26. package/assets/vendor/monaco/vs/dart-CmGfCvrO.js +1 -0
  27. package/assets/vendor/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  28. package/assets/vendor/monaco/vs/ecl-30fUercY.js +1 -0
  29. package/assets/vendor/monaco/vs/editor/editor.main.css +1 -0
  30. package/assets/vendor/monaco/vs/editor/editor.main.js +1 -0
  31. package/assets/vendor/monaco/vs/editor/editor.worker.js +1 -0
  32. package/assets/vendor/monaco/vs/editor-KLE6jdfb.js +831 -0
  33. package/assets/vendor/monaco/vs/editor.js +1 -0
  34. package/assets/vendor/monaco/vs/editorWorkerHost-fVE1cjcC.js +35 -0
  35. package/assets/vendor/monaco/vs/elixir-xjPaIfzF.js +1 -0
  36. package/assets/vendor/monaco/vs/flow9-DqtmStfK.js +1 -0
  37. package/assets/vendor/monaco/vs/freemarker2-FWreY7v7.js +3 -0
  38. package/assets/vendor/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  39. package/assets/vendor/monaco/vs/go-D_hbi-Jt.js +1 -0
  40. package/assets/vendor/monaco/vs/graphql-CKUU4kLG.js +1 -0
  41. package/assets/vendor/monaco/vs/handlebars-CZi4pHCH.js +1 -0
  42. package/assets/vendor/monaco/vs/hcl-DTaboeZW.js +1 -0
  43. package/assets/vendor/monaco/vs/html-j_7ZTNRU.js +1 -0
  44. package/assets/vendor/monaco/vs/html.worker-CA3iAimZ.js +1 -0
  45. package/assets/vendor/monaco/vs/htmlMode-27by_KM4.js +1 -0
  46. package/assets/vendor/monaco/vs/index-049xrXrp.js +1 -0
  47. package/assets/vendor/monaco/vs/index-CBVt3dzv.js +5 -0
  48. package/assets/vendor/monaco/vs/index.js +1 -0
  49. package/assets/vendor/monaco/vs/ini-CsNwO04R.js +1 -0
  50. package/assets/vendor/monaco/vs/initialize-DL0l1TGY.js +1 -0
  51. package/assets/vendor/monaco/vs/java-CI4ZMsH9.js +1 -0
  52. package/assets/vendor/monaco/vs/javascript-DTJl4Jn1.js +1 -0
  53. package/assets/vendor/monaco/vs/json.worker-BizpAl9O.js +1 -0
  54. package/assets/vendor/monaco/vs/jsonMode-DLUiMUrI.js +1 -0
  55. package/assets/vendor/monaco/vs/julia-BwzEvaQw.js +1 -0
  56. package/assets/vendor/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  57. package/assets/vendor/monaco/vs/language/css/css.worker.js +66 -0
  58. package/assets/vendor/monaco/vs/language/css/monaco.contribution.js +1 -0
  59. package/assets/vendor/monaco/vs/language/html/html.worker.js +443 -0
  60. package/assets/vendor/monaco/vs/language/html/monaco.contribution.js +1 -0
  61. package/assets/vendor/monaco/vs/language/json/json.worker.js +17 -0
  62. package/assets/vendor/monaco/vs/language/json/monaco.contribution.js +1 -0
  63. package/assets/vendor/monaco/vs/language/typescript/monaco.contribution.js +1 -0
  64. package/assets/vendor/monaco/vs/language/typescript/ts.worker.js +67693 -0
  65. package/assets/vendor/monaco/vs/less-C0eDYdqa.js +2 -0
  66. package/assets/vendor/monaco/vs/lexon-iON-Kj97.js +1 -0
  67. package/assets/vendor/monaco/vs/liquid-CLJYelW6.js +1 -0
  68. package/assets/vendor/monaco/vs/loader.js +1368 -0
  69. package/assets/vendor/monaco/vs/lspLanguageFeatures-BIkJOWLw.js +2 -0
  70. package/assets/vendor/monaco/vs/lua-DtygF91M.js +1 -0
  71. package/assets/vendor/monaco/vs/m3-CsR4AuFi.js +1 -0
  72. package/assets/vendor/monaco/vs/main-BEx-Fmlo.js +15 -0
  73. package/assets/vendor/monaco/vs/main-DsK8pnKg.js +3 -0
  74. package/assets/vendor/monaco/vs/markdown-C_rD0bIw.js +1 -0
  75. package/assets/vendor/monaco/vs/mdx-CpzZIPHF.js +1 -0
  76. package/assets/vendor/monaco/vs/mips-CiYP61RB.js +1 -0
  77. package/assets/vendor/monaco/vs/monaco.contribution-9cKT3C7t.js +1 -0
  78. package/assets/vendor/monaco/vs/monaco.contribution-BE88ZNGY.js +1 -0
  79. package/assets/vendor/monaco/vs/monaco.contribution-BPhsneLd.js +1 -0
  80. package/assets/vendor/monaco/vs/monaco.contribution-BgRy6xDf.js +1 -0
  81. package/assets/vendor/monaco/vs/msdax-C38-sJlp.js +1 -0
  82. package/assets/vendor/monaco/vs/mysql-CdtbpvbG.js +1 -0
  83. package/assets/vendor/monaco/vs/nls/lang/zh-cn.d.ts +1 -0
  84. package/assets/vendor/monaco/vs/nls/lang/zh-cn.js +9 -0
  85. package/assets/vendor/monaco/vs/nls.messages-loader.js +1 -0
  86. package/assets/vendor/monaco/vs/objective-c-CntZFaHX.js +1 -0
  87. package/assets/vendor/monaco/vs/pascal-r6kuqfl_.js +1 -0
  88. package/assets/vendor/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  89. package/assets/vendor/monaco/vs/perl-DABw_TcH.js +1 -0
  90. package/assets/vendor/monaco/vs/pgsql-me_jFXeX.js +1 -0
  91. package/assets/vendor/monaco/vs/php-D_kh-9LK.js +1 -0
  92. package/assets/vendor/monaco/vs/pla-VfZjczW0.js +1 -0
  93. package/assets/vendor/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  94. package/assets/vendor/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  95. package/assets/vendor/monaco/vs/powershell-B-7ap1zc.js +1 -0
  96. package/assets/vendor/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  97. package/assets/vendor/monaco/vs/pug-BRpRNeEb.js +1 -0
  98. package/assets/vendor/monaco/vs/python-CqWUUgfu.js +1 -0
  99. package/assets/vendor/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  100. package/assets/vendor/monaco/vs/r-f8dDdrp4.js +1 -0
  101. package/assets/vendor/monaco/vs/razor-hok5y9Km.js +1 -0
  102. package/assets/vendor/monaco/vs/redis-fvZQY4PI.js +1 -0
  103. package/assets/vendor/monaco/vs/redshift-45Et0LQi.js +1 -0
  104. package/assets/vendor/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  105. package/assets/vendor/monaco/vs/ruby-CZO8zYTz.js +1 -0
  106. package/assets/vendor/monaco/vs/rust-Bfetafyc.js +1 -0
  107. package/assets/vendor/monaco/vs/sb-3GYllVck.js +1 -0
  108. package/assets/vendor/monaco/vs/scala-foMgrKo1.js +1 -0
  109. package/assets/vendor/monaco/vs/scheme-CHdMtr7p.js +1 -0
  110. package/assets/vendor/monaco/vs/scss-C1cmLt9V.js +3 -0
  111. package/assets/vendor/monaco/vs/shell-ClXCKCEW.js +1 -0
  112. package/assets/vendor/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  113. package/assets/vendor/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  114. package/assets/vendor/monaco/vs/sparql-AUGFYSyk.js +1 -0
  115. package/assets/vendor/monaco/vs/sql-32GpJSV2.js +1 -0
  116. package/assets/vendor/monaco/vs/st-CuDFIVZ_.js +1 -0
  117. package/assets/vendor/monaco/vs/swift-t-PfMj7W.js +1 -0
  118. package/assets/vendor/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  119. package/assets/vendor/monaco/vs/tcl-D74tq1nH.js +1 -0
  120. package/assets/vendor/monaco/vs/toggleHighContrast-qGX7E9o7.js +61 -0
  121. package/assets/vendor/monaco/vs/ts.worker-2QLmBukE.js +1 -0
  122. package/assets/vendor/monaco/vs/tsMode-B0S_kp2q.js +11 -0
  123. package/assets/vendor/monaco/vs/twig-C6taOxMV.js +1 -0
  124. package/assets/vendor/monaco/vs/typescript-_2t_511t.js +1 -0
  125. package/assets/vendor/monaco/vs/typespec-8OfoLt6R.js +1 -0
  126. package/assets/vendor/monaco/vs/vb-Dyb2648j.js +1 -0
  127. package/assets/vendor/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  128. package/assets/vendor/monaco/vs/workers-BBttULjf.js +1 -0
  129. package/assets/vendor/monaco/vs/xml-cZjNDqDT.js +1 -0
  130. package/assets/vendor/monaco/vs/yaml-A1fOIdH6.js +1 -0
  131. package/cordis.patch.yml +5 -0
  132. package/lib/client.js +1914 -0
  133. package/lib/client.js.map +1 -0
  134. package/lib/index.js +1298 -0
  135. package/lib/index.js.map +1 -0
  136. package/package.json +60 -0
  137. package/src/capture.ts +73 -0
  138. package/src/client/events.ts +36 -0
  139. package/src/client/index.ts +37 -0
  140. package/src/client/monaco/diffRender.ts +162 -0
  141. package/src/client/monaco/loader.ts +71 -0
  142. package/src/client/rpc.ts +28 -0
  143. package/src/client/state/records.ts +90 -0
  144. package/src/client/state/regions.ts +81 -0
  145. package/src/client/styles/css.d.ts +2 -0
  146. package/src/client/styles/editor.css +87 -0
  147. package/src/client/ui/DiffBadge.ts +51 -0
  148. package/src/client/ui/DiffBarEmpty.ts +37 -0
  149. package/src/client/ui/DiffBox.ts +79 -0
  150. package/src/client/ui/DiffLauncher.ts +124 -0
  151. package/src/client/ui/EditorView.ts +577 -0
  152. package/src/client/ui/QuickOpen.ts +91 -0
  153. package/src/client/ui/shared.ts +28 -0
  154. package/src/index.ts +43 -0
  155. package/src/model.ts +197 -0
  156. package/src/registry.ts +35 -0
  157. package/src/revert.ts +107 -0
  158. package/src/routes.ts +138 -0
  159. package/src/rpc.ts +295 -0
  160. package/src/shared/rpc.ts +67 -0
  161. package/src/shared/types.ts +121 -0
  162. package/src/store.ts +244 -0
  163. package/src/workspace.ts +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/shared/rpc.ts","../src/routes.ts","../src/model.ts","../src/store.ts","../src/registry.ts","../src/capture.ts","../src/workspace.ts","../src/revert.ts","../src/rpc.ts","../src/index.ts"],"sourcesContent":["/**\n * dsh-vscode-mode RPC contract — method names, per-method request/ok payloads,\n * and the typed handler map shared by the host dispatcher and the client\n * fetch wrapper. 载荷形状与历史实现一字不差,仅把隐式约定类型化。\n *\n * Purity rule: no node/react imports (same as types.ts).\n * 作者 ddj 2026-08-20\n */\nimport type {\n ArchiveBatch,\n ArchiveEntry,\n RecordView,\n StaleHunk,\n} from './types.js'\n\n/** webServer 精确路由。 */\nexport const RPC_PATH = '/edrv/rpc'\n\n/** 决策作用域:call=整条记录,hunk=单个差异块。 */\nexport type RpcScope = 'call' | 'hunk'\n\n/** 每个方法的请求参数(sessionId 为公共可选字段)。 */\nexport interface RpcRequestMap {\n 'edrv.list': { sessionId?: string; callIds?: string[] }\n 'edrv.accept': { sessionId?: string; callId: string; scope?: RpcScope; hunkIndex?: number }\n 'edrv.reject': { sessionId?: string; callId: string; scope?: RpcScope; hunkIndex?: number }\n 'edrv.read': { sessionId?: string; path: string }\n 'edrv.original': { sessionId?: string; path: string }\n 'edrv.save': { sessionId?: string; path: string; content: string }\n 'edrv.archiveList': { sessionId?: string }\n 'edrv.archiveRead': { sessionId?: string; path?: string }\n 'edrv.rollback': { sessionId?: string; path: string; batch?: number }\n 'edrv.debug': { sessionId?: string; text: string }\n 'edrv.searchFiles': { sessionId?: string; query: string }\n}\n\nexport type RpcMethod = keyof RpcRequestMap\n\n/** 每个方法成功(ok:true)时的附加载荷。 */\nexport interface RpcOkMap {\n 'edrv.list': { records: RecordView[] }\n 'edrv.accept': { record: RecordView }\n 'edrv.reject': { record: RecordView }\n 'edrv.read': { content: string; size: number }\n 'edrv.original': { content: string; size: number; stale: StaleHunk[]; fallback: boolean }\n 'edrv.save': object\n 'edrv.archiveList': { entries: ArchiveEntry[] }\n 'edrv.archiveRead': { batches: ArchiveBatch[] }\n 'edrv.rollback': { path: string; batch: number | null }\n 'edrv.debug': object\n 'edrv.searchFiles': { files: string[]; truncated: boolean }\n}\n\n/** 统一响应:{ok:true, ...payload} 或 {ok:false, error}。 */\nexport type RpcResult<M extends RpcMethod> =\n | ({ ok: true } & RpcOkMap[M])\n | { ok: false; error: string }\n\n/** 每个方法的 handler 签名(host 分发表与 client 类型检查共用)。 */\nexport type RpcHandler<M extends RpcMethod> = (\n args: RpcRequestMap[M],\n) => Promise<RpcResult<M>>\n\n/** host RPC 分发表:method → handler。 */\nexport type RpcHandlerMap = {\n [M in RpcMethod]: RpcHandler<M>\n}\n","/**\n * dsh-vscode-mode host — webServer 路由注册(/edrv/rpc、/edrv/assets/*、/edrv/vendor/*)。\n * 迁移自原 src/index.ts 的路由部分,路径/行为一字不改。\n * 作者 ddj 2026-08-20\n */\nimport { readFile } from 'node:fs/promises'\nimport { dirname, extname, join, normalize, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { RPC_PATH } from './shared/rpc.js'\nimport type { RpcMethod, RpcRequestMap } from './shared/rpc.js'\nimport type { Ctx } from './store.js'\n\nconst IMG_ROUTES = [\n { url: '/edrv/assets/compare-idle.png', file: 'compare_idle.png' },\n { url: '/edrv/assets/compare-select.png', file: 'compare_select.png' },\n]\n\n/** Monaco AMD 构建静态资源(随包发布,离线可用;前缀路由 /edrv/vendor/*)。 */\nconst VENDOR_PREFIX = '/edrv/vendor'\nconst VENDOR_MIME: Record<string, string> = {\n '.js': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json',\n '.map': 'application/json',\n '.ts': 'text/plain; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.html': 'text/html; charset=utf-8',\n '.md': 'text/markdown',\n}\n\n/** 图标目录:默认插件包内 assets/(随包发布);config.imageDir 可覆盖(用于自定义换图)。 */\nfunction imageDirOf(config: unknown): string {\n const cfg = config as { imageDir?: unknown } | undefined\n if (cfg && typeof cfg.imageDir === 'string' && cfg.imageDir) return cfg.imageDir.replace(/\\\\/g, '/')\n return join(dirname(fileURLToPath(import.meta.url)), '..', 'assets')\n}\n\n/** Monaco AMD 静态目录(随包发布)。 */\nconst vendorDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'assets', 'vendor')\n\n/**\n * 注册全部 webServer 路由。\n * @author ddj 2026年08月20号\n * @param ctx DSH 上下文\n * @param config 插件配置(可选 imageDir 等)\n * @param handleRpc RPC 分发入口(method,args → RpcResult)\n */\nexport function registerRoutes(\n ctx: Ctx,\n config: unknown,\n handleRpc: <M extends RpcMethod>(method: M, args: RpcRequestMap[M]) => Promise<unknown>,\n): void {\n const imgDir = imageDirOf(config)\n const web = ctx.get('webServer')\n if (!web) return\n\n ctx.effect(() => web.register({\n kind: 'exact',\n path: RPC_PATH,\n handler: async (req: unknown, res: { statusCode?: number; setHeader: (k: string, v: string) => void; end: (b?: string) => void }) => {\n try {\n const chunks: Uint8Array[] = []\n for await (const chunk of req as AsyncIterable<Uint8Array>) chunks.push(chunk)\n let input: { method?: string; args?: unknown } = {}\n try {\n input = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}')\n } catch (error) {\n input = {}\n }\n const method = (typeof input.method === 'string' ? input.method : '') as RpcMethod\n const result = await handleRpc(method, (input.args ?? {}) as never)\n res.statusCode = 200\n res.setHeader('content-type', 'application/json')\n res.end(JSON.stringify(result))\n } catch (error) {\n res.statusCode = 500\n res.end(JSON.stringify({ ok: false, error: String(error) }))\n }\n },\n }), 'edrv: /edrv/rpc route')\n\n for (const r of IMG_ROUTES) {\n ctx.effect(() => web.register({\n kind: 'exact',\n path: r.url,\n handler: async (req: unknown, res: { statusCode?: number; setHeader: (k: string, v: string) => void; end: (b?: string | Uint8Array) => void }) => {\n try {\n const body = await readFile(imgDir + '/' + r.file)\n res.statusCode = 200\n res.setHeader('content-type', 'image/png')\n res.setHeader('cache-control', 'no-cache')\n res.end(body)\n } catch (error) {\n res.statusCode = 404\n res.end()\n }\n },\n }), 'edrv: static ' + r.file)\n }\n\n // Monaco Editor AMD 构建:/edrv/vendor/* → assets/vendor/*(路径穿越防护 + 按扩展名 MIME)\n ctx.effect(() => web.register({\n kind: 'prefix',\n path: VENDOR_PREFIX,\n handler: async (req: { method?: string; url?: string }, res: { statusCode?: number; setHeader: (k: string, v: string) => void; end: (b?: string | Uint8Array) => void }) => {\n try {\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n res.statusCode = 405\n res.end()\n return\n }\n const pathname = new URL(req.url ?? '/', 'http://x').pathname\n const rel = decodeURIComponent(pathname.slice(VENDOR_PREFIX.length)).replace(/^\\/+/, '')\n if (!rel) { res.statusCode = 404; res.end(); return }\n const target = resolve(normalize(join(vendorDir, rel)))\n if (target !== vendorDir && !target.startsWith(vendorDir + sep)) {\n res.statusCode = 403\n res.end()\n return\n }\n const body = await readFile(target)\n res.statusCode = 200\n res.setHeader('content-type', VENDOR_MIME[extname(target)] ?? 'application/octet-stream')\n res.setHeader('cache-control', 'public, max-age=3600')\n res.end(body)\n } catch (error) {\n res.statusCode = 404\n res.end()\n }\n },\n }), 'edrv: /edrv/vendor prefix')\n}\n","/**\n * dsh-vscode-mode host — 纯域逻辑(无 ctx/fs/IO 依赖,可直接单测)。\n * 迁移自原 src/index.ts 的纯函数部分,语义一字不改。\n * 作者 ddj 2026-08-20\n */\nimport type { Decision, DiffRecord, Hunk, RecordSummary } from './shared/types.js'\n\n/** 工作区记录桶上限(超过后按 at 最旧剔除)。 */\nexport const MAX_RECORDS = 200\n\n/**\n * 归一化一条持久化记录(容忍旧版/损坏字段)。\n * @author ddj 2026年08月20号\n * @param raw 反序列化的原始记录\n * @returns 合法记录或 null\n */\nexport function normalizeRecord(raw: unknown): DiffRecord | null {\n if (!raw || typeof raw !== 'object') return null\n const r = raw as Record<string, unknown>\n if (typeof r.callId !== 'string' || typeof r.path !== 'string') return null\n const hunks: Hunk[] = Array.isArray(r.hunks)\n ? (r.hunks as unknown[]).filter((h) => h && typeof (h as { newText?: unknown }).newText === 'string') as Hunk[]\n : []\n const toolName: DiffRecord['toolName'] = r.toolName === 'write' ? 'write' : 'edit'\n return {\n callId: r.callId,\n toolName,\n path: r.path,\n before: typeof r.before === 'string' ? r.before : null,\n create: r.create === true,\n callHunk: r.callHunk && typeof (r.callHunk as { oldText?: unknown }).oldText === 'string'\n ? { oldText: (r.callHunk as { oldText: string }).oldText, newText: (r.callHunk as { newText: string }).newText }\n : null,\n hunks: hunks.map((h) => ({ oldText: typeof h.oldText === 'string' ? h.oldText : null, newText: h.newText })),\n decisions: r.decisions && typeof r.decisions === 'object'\n ? r.decisions as DiffRecord['decisions']\n : { call: 'pending', perHunk: hunks.map(() => 'pending' as Decision) },\n note: typeof r.note === 'string' ? r.note : null,\n superseded: r.superseded === true,\n archived: r.archived === true,\n batch: Number.isInteger(r.batch) ? (r.batch as number) : 0,\n at: typeof r.at === 'string' ? r.at : new Date().toISOString(),\n }\n}\n\n/**\n * 写决策到记录(scope=call 整体 / hunk 单个块)。\n * @author ddj 2026年08月20号\n * @param record 记录\n * @param scope 作用域\n * @param idx hunk 下标(仅 scope=hunk 时生效)\n * @param value 决策值\n * @returns 更新后的记录(原对象就地修改)\n */\nexport function markDecision(record: DiffRecord, scope: string, idx: number | undefined, value: Decision): DiffRecord {\n const dec = record.decisions\n if (scope === 'hunk' && Array.isArray(dec.perHunk) && Number.isInteger(idx)) {\n const i = idx as number\n if (i >= 0 && i < dec.perHunk.length) dec.perHunk[i] = value\n } else {\n dec.call = value\n if (Array.isArray(dec.perHunk)) dec.perHunk = dec.perHunk.map(() => value)\n }\n record.at = new Date().toISOString()\n return record\n}\n\n/** 记录是否已无任何待决策差异(superseded 或全部已决策)。 */\nexport function recordResolved(record: DiffRecord): boolean {\n if (record.superseded === true) return true\n const perHunk = Array.isArray(record.decisions.perHunk) ? record.decisions.perHunk : []\n if (perHunk.length) return perHunk.every((v) => v === 'accepted' || v === 'rejected')\n return record.decisions.call === 'accepted' || record.decisions.call === 'rejected'\n}\n\n/**\n * 记录决策摘要(采纳/拒绝/待处理计数,superseded 标记)。\n * @author ddj 2026年08月20号\n * @param record 记录\n * @returns 摘要\n */\nexport function recSummary(record: DiffRecord): RecordSummary {\n const perHunk = Array.isArray(record.decisions.perHunk) ? record.decisions.perHunk : []\n const n = Math.max(1, Array.isArray(record.hunks) ? record.hunks.length : 1)\n let accepted = 0\n let rejected = 0\n let pending = 0\n if (perHunk.length) {\n for (const v of perHunk) {\n if (v === 'accepted') accepted++\n else if (v === 'rejected') rejected++\n else pending++\n }\n } else if (record.decisions.call === 'accepted') accepted = n\n else if (record.decisions.call === 'rejected') rejected = n\n else pending = n\n return { accepted, rejected, pending, superseded: record.superseded === true }\n}\n\n/**\n * 重建\"本批次修改前\"内容:把仍待处理(pending)的差异块按 新→旧 顺序从当前内容反解\n * (newText → oldText)。已采纳/已拒绝的块跳过。反解失败的块标记为 stale。\n * @author ddj 2026年08月20号\n * @param records 该文件的活动记录\n * @param content 当前磁盘内容\n * @returns 重建内容与 stale 定位\n */\nexport function reconstructOriginal(records: DiffRecord[], content: string): { content: string; stale: Array<{ callId: string; idx: number }> } {\n const pending: Array<{ rec: DiffRecord; idx: number }> = []\n for (const rec of records) {\n const perHunk = Array.isArray(rec.decisions.perHunk) ? rec.decisions.perHunk : []\n for (let i = 0; i < rec.hunks.length; i++) {\n const st = perHunk.length ? perHunk[i] : rec.decisions.call\n if (st === 'pending') pending.push({ rec, idx: i })\n }\n }\n pending.sort((a, b) => (a.rec.at < b.rec.at ? 1 : a.rec.at > b.rec.at ? -1 : 0))\n let out = content\n const stale: Array<{ callId: string; idx: number }> = []\n for (const p of pending) {\n const h = p.rec.hunks[p.idx]\n const precise = p.rec.toolName === 'edit' && p.rec.hunks.length <= 1 && p.rec.callHunk ? p.rec.callHunk : h\n const newText = precise.newText ?? ''\n const at = out.indexOf(newText)\n if (at < 0) { stale.push({ callId: p.rec.callId, idx: p.idx }); continue }\n const oldText = precise.oldText === null ? '' : precise.oldText\n out = out.slice(0, at) + oldText + out.slice(at + newText.length)\n }\n return { content: out, stale }\n}\n\n/** 文件当前最大批次号(无记录为 0)。 */\nexport function fileMaxBatch(records: Map<string, DiffRecord>, path: string): number {\n let m = 0\n for (const r of records.values()) {\n if (r.path === path && Number.isInteger(r.batch) && r.batch > m) m = r.batch\n }\n return m\n}\n\n/** 记录桶裁剪:超出 MAX_RECORDS 时剔除最旧的。 */\nexport function prune(map: Map<string, DiffRecord>, max = MAX_RECORDS): void {\n if (map.size <= max) return\n const sorted = [...map.values()].sort((a, b) => (a.at < b.at ? -1 : 1))\n for (let i = 0; i < sorted.length - max; i++) map.delete(sorted[i].callId)\n}\n\n/** 按批次分组记录。 */\nexport function groupByBatch(recs: DiffRecord[]): Map<number | null, DiffRecord[]> {\n const map = new Map<number | null, DiffRecord[]>()\n for (const r of recs) {\n const k = Number.isInteger(r.batch) ? r.batch : null\n if (!map.has(k)) map.set(k, [])\n map.get(k)!.push(r)\n }\n return map\n}\n\n/**\n * 归档条目构造(一条批次一条)。\n * @author ddj 2026年08月20号\n * @param recs 同批次记录(非空)\n * @param cwd 工作区\n * @param reason 归档原因\n */\nexport function archiveEntryFor(recs: DiffRecord[], cwd: string, reason: string): {\n at: string\n cwd: string\n path: string\n batch: number | null\n reason: string\n records: Array<Record<string, unknown>>\n} {\n const first = recs[0]\n return {\n at: new Date().toISOString(),\n cwd,\n path: first.path,\n batch: Number.isInteger(first.batch) ? first.batch : null,\n reason,\n records: recs.map((r) => ({\n callId: r.callId,\n toolName: r.toolName,\n path: r.path,\n create: r.create === true,\n callHunk: r.callHunk,\n hunks: r.hunks,\n decisions: r.decisions,\n note: r.note ?? null,\n before: typeof r.before === 'string' ? r.before : null,\n superseded: r.superseded === true,\n batch: Number.isInteger(r.batch) ? r.batch : null,\n at: r.at,\n summary: recSummary(r),\n })),\n }\n}\n","/**\n * dsh-vscode-mode host — 存储层(sidecar 读写合并 + 归档持久化 + stale 检测)。\n * 迁移自原 src/index.ts 的 fs/ctx IO 部分,语义一字不改。\n * 作者 ddj 2026-08-20\n */\nimport type { ArchiveBatch, ArchiveData, DiffRecord, SidecarData } from './shared/types.js'\nimport { archiveEntryFor, groupByBatch, normalizeRecord } from './model.js'\n\nexport const SIDECAR = '.dsh-edit-review.json'\nexport const SIDECAR_ARCHIVE = '.dsh-edit-review-archive.json'\nexport const READ_CAP = 8 * 1024 * 1024\n\n/** DSH 上下文与会话类型较宽松:本地无 dsh 类型声明,显式 any + 文档约束。 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Ctx = any\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Session = any\n\n/** 会话沙箱策略(policyOf):可能不存在,调用方需容忍 undefined。 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function policyOf(ctx: Ctx, session: Session | undefined): any {\n const svc = ctx.get('sandboxPolicy')\n if (!svc) return undefined\n return session ? svc.resolve({ session }) : svc.resolve()\n}\n\n/** 按会话 cwd 解析目标路径。 */\nexport async function resolveTarget(ctx: Ctx, session: Session | undefined, path: string): Promise<string> {\n const fs = ctx.get('fs')\n const cwd = session?.header?.cwd\n return fs.resolve(path, cwd ? { cwd } : {})\n}\n\n/** 读取工作区主 sidecar 文本(缺失/失败 → null)。 */\nasync function readSidecarText(ctx: Ctx, cwd: string | null): Promise<string | null> {\n const fs = ctx.get('fs')\n if (!fs || !cwd) return null\n try {\n return await fs.readText(await fs.resolve(SIDECAR, { cwd }))\n } catch (error) {\n return null\n }\n}\n\n/**\n * 解析主 sidecar:v2 直接返回;v1 迁移为 v2 结构(按会话 cwd 分桶)。\n * @author ddj 2026年08月20号\n * @param text sidecar 文本\n * @returns v2 数据或 null\n */\nexport function parseSidecar(text: string | null): SidecarData | null {\n if (!text) return null\n try {\n const data = JSON.parse(text)\n if (data && typeof data === 'object' && data.version === 2 && data.workspaces && typeof data.workspaces === 'object') {\n return data as SidecarData\n }\n if (data && data.version === 1 && data.sessions && typeof data.sessions === 'object') {\n const workspaces: SidecarData['workspaces'] = {}\n for (const bucket of Object.values(data.sessions)) {\n const b = bucket as { cwd?: unknown; records?: unknown; at?: unknown }\n if (typeof b.cwd === 'string' && b.records) {\n workspaces[b.cwd] = { at: typeof b.at === 'number' ? b.at : Date.now(), records: b.records as Record<string, DiffRecord> }\n }\n }\n return { version: 2, updatedAt: typeof data.updatedAt === 'string' ? data.updatedAt : new Date().toISOString(), workspaces }\n }\n return null\n } catch (error) {\n return null\n }\n}\n\n/** 加载某工作区的记录桶(内存 Map;缺失 → 空)。 */\nexport async function loadBucket(ctx: Ctx, cwd: string): Promise<Map<string, DiffRecord>> {\n const text = await readSidecarText(ctx, cwd)\n const data = parseSidecar(text)\n const map = new Map<string, DiffRecord>()\n if (data && data.workspaces[cwd] && typeof data.workspaces[cwd].records === 'object') {\n for (const rec of Object.values(data.workspaces[cwd].records)) {\n const n = normalizeRecord(rec)\n if (n) map.set(n.callId, n)\n }\n }\n return map\n}\n\n/** 保存某工作区的记录桶(写前合并,不覆盖其他工作区)。 */\nexport async function saveBucket(ctx: Ctx, cwd: string, recsMap: Map<string, DiffRecord>, session?: Session): Promise<void> {\n const fs = ctx.get('fs')\n if (!fs || !cwd) return\n try {\n const target = await fs.resolve(SIDECAR, { cwd })\n const existing = parseSidecar(await readSidecarText(ctx, cwd)) ?? { version: 2, updatedAt: '', workspaces: {} } as SidecarData\n existing.workspaces[cwd] = { at: Date.now(), records: Object.fromEntries(recsMap) }\n existing.updatedAt = new Date().toISOString()\n await fs.writeText(target, JSON.stringify(existing), void 0, void 0, policyOf(ctx, session))\n } catch (error) {\n console.error('edrv saveBucket failed', error)\n }\n}\n\n/**\n * 读取记录目标文件内容(按 path 缓存一次;缺失/过大/失败 → null/'' 占位)。\n * @author ddj 2026年08月20号\n * @param cache path → 内容(null=缺失/读取失败,''=过大跳过)\n */\nexport async function readForCache(ctx: Ctx, session: Session, cache: Map<string, string | null>, path: string): Promise<string | null> {\n if (cache.has(path)) return cache.get(path) ?? null\n const fs = ctx.get('fs')\n if (!fs) { cache.set(path, null); return null }\n try {\n const target = await resolveTarget(ctx, session, path)\n const info = await fs.stat(target)\n if (!info || info.type !== 'file') { cache.set(path, null); return null }\n if ((info.size ?? 0) > READ_CAP) { cache.set(path, ''); return '' }\n const content = await fs.readText(target)\n cache.set(path, content)\n return content\n } catch (error) {\n cache.set(path, null)\n return null\n }\n}\n\n/**\n * 判断记录是否已无任何可操作差异(stale):待决策 hunk 的新文本在磁盘均找不到,\n * 或新建文件已不存在,或全为空差异。满足则应由 host 自动归档。\n * @author ddj 2026年08月20号\n */\nexport async function recordIsStale(ctx: Ctx, session: Session, cache: Map<string, string | null>, rec: DiffRecord): Promise<boolean> {\n if (rec.superseded === true) return true\n if (!Array.isArray(rec.hunks) || !rec.hunks.length) return true\n const perHunk = Array.isArray(rec.decisions.perHunk) ? rec.decisions.perHunk : []\n let hasLocatablePending = false\n for (let i = 0; i < rec.hunks.length; i++) {\n const st = perHunk.length ? perHunk[i] : rec.decisions.call\n if (st === 'accepted' || st === 'rejected') continue\n if (rec.create === true) {\n const content = await readForCache(ctx, session, cache, rec.path)\n if (content !== null) { hasLocatablePending = true; break }\n continue\n }\n const precise = rec.toolName === 'edit' && rec.callHunk ? rec.callHunk : rec.hunks[i]\n const oldText = precise?.oldText ?? null\n const newText = precise?.newText ?? null\n if (oldText !== null && oldText === newText) continue\n if (newText === null || newText === undefined) continue\n const content = await readForCache(ctx, session, cache, rec.path)\n if (content !== null && content.indexOf(newText) >= 0) { hasLocatablePending = true; break }\n }\n return !hasLocatablePending\n}\n\n/**\n * edrv.list 全量轮询时自动清理 stale 记录:标记 superseded 并归档,\n * 防止\"幽灵差异\"长期留在审查列表且无法操作。\n * @author ddj 2026年08月20号\n * @returns 自动归档条数\n */\nexport async function autoArchiveStale(ctx: Ctx, session: Session, cwd: string, bucket: Map<string, DiffRecord>): Promise<number> {\n const fs = ctx.get('fs')\n if (!fs) return 0\n const cache = new Map<string, string | null>()\n const stale: DiffRecord[] = []\n for (const rec of bucket.values()) {\n if (rec.archived || rec.superseded === true) continue\n if (await recordIsStale(ctx, session, cache, rec)) stale.push(rec)\n }\n if (!stale.length) return 0\n for (const r of stale) { r.superseded = true; r.at = new Date().toISOString() }\n await archiveRecords(ctx, session, cwd, bucket, stale, '差异无法定位(已被后续修改覆盖),自动归档')\n return stale.length\n}\n\n/** 读取归档 sidecar 文本(缺失/失败 → null)。 */\nexport async function readArchiveText(ctx: Ctx, cwd: string | null): Promise<string | null> {\n const fs = ctx.get('fs')\n if (!fs || !cwd) return null\n try {\n return await fs.readText(await fs.resolve(SIDECAR_ARCHIVE, { cwd }))\n } catch (error) {\n return null\n }\n}\n\n/** 解析归档 sidecar(损坏 → 空数组)。 */\nexport function parseArchive(text: string | null): ArchiveBatch[] {\n if (!text) return []\n try {\n const data = JSON.parse(text)\n if (data && typeof data === 'object' && Array.isArray(data.batches)) return data.batches as ArchiveBatch[]\n } catch (error) { /* 忽略损坏 */ }\n return []\n}\n\n/** 追加归档条目(按 cwd+path+batch 合并,同 callId 去重)。 */\nexport async function appendArchiveEntries(ctx: Ctx, cwd: string, entries: Array<ReturnType<typeof archiveEntryFor>>, session?: Session): Promise<void> {\n const fs = ctx.get('fs')\n if (!fs || !cwd) return\n try {\n const target = await fs.resolve(SIDECAR_ARCHIVE, { cwd })\n const existing = parseArchive(await readArchiveText(ctx, cwd))\n for (const e of entries) {\n const idx = existing.findIndex((x) => x.cwd === e.cwd && x.path === e.path && x.batch === e.batch)\n if (idx >= 0) {\n const exist = existing[idx]\n const seen = new Set((exist.records || []).map((r) => r.callId))\n for (const rec of e.records) {\n if (!seen.has(String(rec.callId))) {\n exist.records.push(rec as unknown as ArchiveBatch['records'][number])\n seen.add(String(rec.callId))\n }\n }\n exist.lastAt = e.at\n exist.reason = e.reason\n } else {\n existing.push(e as unknown as ArchiveBatch)\n }\n }\n const data: ArchiveData = { version: 1, updatedAt: new Date().toISOString(), batches: existing }\n await fs.writeText(target, JSON.stringify(data), void 0, void 0, policyOf(ctx, session))\n } catch (error) {\n console.error('edrv appendArchiveEntries failed', error)\n }\n}\n\n/** 归档记录:标记 archived、按批次写入归档、落盘工作区桶。 */\nexport async function archiveRecords(\n ctx: Ctx,\n session: Session,\n cwd: string,\n bucket: Map<string, DiffRecord>,\n recs: DiffRecord[],\n reason: string,\n): Promise<void> {\n if (!recs.length) return\n const fresh = recs.filter((r) => !r.archived)\n for (const r of recs) r.archived = true\n const entries: Array<ReturnType<typeof archiveEntryFor>> = []\n for (const list of groupByBatch(recs).values()) entries.push(archiveEntryFor(list, cwd, reason))\n await appendArchiveEntries(ctx, cwd, entries, session)\n if (fresh.length) await saveBucket(ctx, cwd, bucket, session)\n}\n","/**\n * dsh-vscode-mode host — 工作区记录桶注册表与会话助手。\n * 迁移自原 src/index.ts 的 registry/sessionOf/cwdOf/bucketOf,语义不改。\n * 作者 ddj 2026-08-20\n */\nimport type { DiffRecord } from './shared/types.js'\nimport type { Ctx, Session } from './store.js'\nimport { loadBucket } from './store.js'\n\n/** cwd → 记录桶(内存缓存;随会话销毁清理)。 */\nexport type Registry = Map<string, Map<string, DiffRecord>>\n\n/** 按 sessionId 取会话;缺省时仅当唯一活跃会话才返回。 */\nexport function sessionOf(ctx: Ctx, sessionId?: string): Session | undefined {\n const sessions = ctx.get('sessions')\n if (!sessions) return undefined\n if (sessionId) return sessions.get(sessionId)\n const live = sessions.list().filter((s: Session) => s.id)\n return live.length === 1 ? live[0] : undefined\n}\n\n/** 会话工作区 cwd。 */\nexport function cwdOf(session: Session | undefined): string | null {\n return session?.header?.cwd ?? null\n}\n\n/** 取(或加载)某工作区记录桶。 */\nexport function bucketOf(registry: Registry, ctx: Ctx, cwd: string): Promise<Map<string, DiffRecord>> {\n const existing = registry.get(cwd)\n if (existing) return Promise.resolve(existing)\n return loadBucket(ctx, cwd).then((map) => {\n registry.set(cwd, map)\n return map\n })\n}\n","/**\n * dsh-vscode-mode host — 捕获层:监听 tools/result,把 edit/write 差异落成审查记录。\n * 迁移自原 src/index.ts 的 tools/result 处理,语义不改。\n * 作者 ddj 2026-08-20\n */\nimport type { DiffRecord } from './shared/types.js'\nimport type { Ctx, Session } from './store.js'\nimport { archiveRecords, loadBucket, saveBucket } from './store.js'\nimport { fileMaxBatch, prune, recordResolved } from './model.js'\nimport type { Registry } from './registry.js'\nimport { cwdOf } from './registry.js'\n\n/**\n * 捕获一次工具执行结果(tools/result):edit/write 成功时构造记录、\n * 递增文件批次、融合归档被后续修改取代的旧差异、落盘。\n * @author ddj 2026年08月20号\n * @param ctx DSH 上下文\n * @param registry 工作区记录桶注册表\n * @param exec 工具执行描述(name/arguments/callId/agent.session)\n * @param result 执行结果(value/meta/isError)\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function captureToolResult(ctx: Ctx, registry: Registry, exec: any, result: any): Promise<void> {\n const session: Session | undefined = exec?.agent?.session\n if (!session || (exec?.name !== 'edit' && exec?.name !== 'write')) return\n if (result?.isError || !result?.value) return\n try {\n const cwd = cwdOf(session)\n if (!cwd) return\n const value = result.value\n const args = exec.arguments || {}\n const path = typeof value.path === 'string' ? value.path : args.file_path\n if (!path) return\n const metaDiffs: DiffRecord['hunks'] = Array.isArray(result.meta?.diffs) ? result.meta.diffs : []\n const before = typeof value.before === 'string' ? value.before : null\n const create = exec.name === 'write' && value.before === null\n const callHunk = exec.name === 'edit' && typeof args.old_string === 'string' ? { oldText: args.old_string, newText: args.new_string } : null\n const synthHunk = create ? { oldText: null as string | null, newText: typeof args.content === 'string' ? args.content : (typeof value.after === 'string' ? value.after : '') } : null\n const hunks = metaDiffs.length ? metaDiffs : (synthHunk ? [synthHunk] : (callHunk ? [callHunk] : []))\n if (!hunks.length) return\n const record: DiffRecord = {\n callId: exec.callId,\n toolName: exec.name,\n path,\n before,\n create,\n callHunk,\n hunks,\n decisions: { call: 'pending', perHunk: hunks.map(() => 'pending') },\n note: create ? '新建文件:全部拒绝将删除该文件' : before === null ? '未捕获修改前内容(大文件)' : null,\n superseded: false,\n archived: false,\n batch: 0,\n at: new Date().toISOString(),\n }\n let bucket = registry.get(cwd)\n if (!bucket) { bucket = await loadBucket(ctx, cwd); registry.set(cwd, bucket) }\n record.batch = fileMaxBatch(bucket, path) + 1\n bucket.set(exec.callId, record)\n // 融合:文件被再次修改(batch 递增)时,早于最新批次的未归档差异一律归档(内容已含其效果/被取代)\n const prior: DiffRecord[] = []\n for (const r of bucket.values()) {\n if (r.path === path && r.callId !== exec.callId && !r.archived && (r.batch ?? 0) < record.batch) prior.push(r)\n }\n if (prior.length) {\n await archiveRecords(ctx, session, cwd, bucket, prior, prior.every(recordResolved) ? '已处理且被后续修改取代' : '被后续修改融合(内容已含其效果)')\n }\n prune(bucket)\n await saveBucket(ctx, cwd, bucket, session)\n } catch (error) {\n console.error('edrv capture failed', error)\n }\n}\n","/**\n * dsh-vscode-mode host — 工作区文件清单扫描与缓存(快速打开/搜索用)。\n * 迁移自原 src/index.ts 的 listWorkspaceFiles,语义不改。\n * 作者 ddj 2026-08-20\n */\nimport type { Ctx, Session } from './store.js'\nimport { policyOf } from './store.js'\n\n/** 文件清单缓存 TTL 与扫描上限(避免大工作区反复全量扫描)。 */\nconst FILE_INDEX_TTL = 60_000\nconst SCAN_CAP = 6000\n/** cwd → { at, files }(随会话销毁清理)。 */\nconst fileIndex = new Map<string, { at: number; files: string[] }>()\n\n/**\n * 扫描工作区文件清单(快速打开/搜索用):subprocess(Windows powershell / POSIX find),\n * 排除常见重目录,容量上限 SCAN_CAP;结果缓存(TTL FILE_INDEX_TTL)。失败返回 null。\n * @author ddj 2026年08月20号\n * @param ctx DSH 上下文\n * @param session 会话(取工作区根)\n * @param cwd 工作区目录\n * @returns 绝对路径清单;不可用(无 subprocess/fs)或扫描失败返回 null\n */\nexport async function listWorkspaceFiles(ctx: Ctx, session: Session, cwd: string): Promise<string[] | null> {\n const cached = fileIndex.get(cwd)\n if (cached && Date.now() - cached.at < FILE_INDEX_TTL) return cached.files\n const sub = ctx.get('subprocess')\n const fs = ctx.get('fs')\n if (!sub || !fs) return null\n const policy = policyOf(ctx, session)\n let root: string\n try {\n const rootTarget = await fs.resolve(policy?.workspaceRoot ?? '.', {})\n root = fs.processPath(rootTarget)\n } catch (error) {\n root = cwd\n }\n const lines: string[] = []\n const run = async (argv: string[]): Promise<void> => {\n const handle = sub.spawn({\n argv,\n stdio: { stdout: { maxBytes: 8 << 20 }, stderr: { maxBytes: 1 << 16 }, stdin: 'ignore' },\n graceMs: 20000,\n })\n const outcome = await handle.done\n const code = outcome?.exitCode ?? outcome?.code\n if (code !== 0) throw new Error('scan exit ' + code)\n const text = handle.collected?.stdout?.readFrom(0).text ?? ''\n for (const ln of text.split(/\\r?\\n/)) {\n const s = ln.trim()\n if (s) lines.push(s)\n }\n }\n try {\n if (process.platform === 'win32') {\n const cmd = 'Get-ChildItem -LiteralPath \"' + String(root).replace(/\"/g, '\"\"') + '\" -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.FullName -notmatch \\'(node_modules|\\\\.git|\\\\.tmp|\\\\.cache|dist|build|vendor|coverage|__pycache__)\\' } | Select-Object -First ' + SCAN_CAP + ' | ForEach-Object { $_.FullName }'\n await run(['powershell', '-NoProfile', '-NonInteractive', '-Command', cmd])\n } else {\n const cmd = 'find ' + JSON.stringify(root) + ' -type f -not -path \\'*/node_modules/*\\' -not -path \\'*/.git/*\\' -not -path \\'*/.tmp/*\\' -not -path \\'*/.cache/*\\' -not -path \\'*/dist/*\\' -not -path \\'*/build/*\\' -not -path \\'*/vendor/*\\' -not -path \\'*/coverage/*\\' 2>/dev/null | head -n ' + SCAN_CAP\n await run(['/bin/sh', '-c', cmd])\n }\n } catch (error) {\n console.error('edrv scan failed', error)\n return null\n }\n const files = lines.slice(0, SCAN_CAP)\n if (files.length) fileIndex.set(cwd, { at: Date.now(), files })\n return files\n}\n\n/** 会话销毁时清理文件索引缓存。 */\nexport function dropFileIndex(cwd: string): void {\n fileIndex.delete(cwd)\n}\n","/**\n * dsh-vscode-mode host — 回滚/删除(fs + subprocess 操作)。\n * 迁移自原 src/index.ts 的 revertCall/revertHunk/deleteCreated/restoreFile,语义不改。\n * 作者 ddj 2026-08-20\n */\nimport type { DiffRecord } from './shared/types.js'\nimport type { Ctx, Session } from './store.js'\nimport { policyOf, resolveTarget } from './store.js'\n\nexport type Result = { ok: true } | { ok: false; error: string }\n\n/**\n * 删除新建文件(拒绝创建时):subprocess 删除,路径先经 fs.contains 校验工作区边界。\n * @author ddj 2026年08月20号\n * @returns 成功或失败原因\n */\nexport async function deleteCreated(ctx: Ctx, session: Session, record: DiffRecord): Promise<Result> {\n const sub = ctx.get('subprocess')\n const fs = ctx.get('fs')\n if (!sub || !fs) return { ok: false, error: '回滚不可用:缺少 subprocess/fs' }\n const policy = policyOf(ctx, session)\n const rootTarget = await fs.resolve(policy?.workspaceRoot ?? '.', {})\n const target = await resolveTarget(ctx, session, record.path)\n if (!fs.contains(rootTarget, target)) return { ok: false, error: '拒绝删除:目标不在会话工作区内' }\n const p = fs.processPath(target)\n // subprocess 契约:spawn({ argv, stdio, graceMs }),done → { exitCode },输出走 handle.collected\n const attempt = async (argv: string[]): Promise<void> => {\n const handle = sub.spawn({\n argv,\n stdio: { stdout: { maxBytes: 1 << 16 }, stderr: { maxBytes: 1 << 16 }, stdin: 'ignore' },\n graceMs: 10000,\n })\n const outcome = await handle.done\n const code = outcome?.exitCode ?? outcome?.code\n if (code !== 0) {\n const err = handle.collected?.stderr?.readFrom(0).text ?? ''\n throw new Error('exit ' + code + ' ' + err)\n }\n }\n try {\n await attempt(['powershell', '-NoProfile', '-NonInteractive', '-Command', 'Remove-Item -LiteralPath \"' + p + '\" -Force'])\n return { ok: true }\n } catch (error) {\n try {\n await attempt(['/bin/rm', '-f', '--', p])\n return { ok: true }\n } catch (error2) {\n return { ok: false, error: '删除失败(文件仍存在):' + String(error) + ' / ' + String(error2) }\n }\n }\n}\n\n/** 整调用回滚:write/编辑用 before 整文件恢复;新建文件转 deleteCreated。 */\nexport async function revertCall(ctx: Ctx, session: Session, record: DiffRecord): Promise<Result> {\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '回滚不可用:缺少 fs' }\n if (record.before === null) {\n if (!record.create) return { ok: false, error: '无法回滚:缺少修改前内容(大文件或旧记录)' }\n return deleteCreated(ctx, session, record)\n }\n try {\n const target = await resolveTarget(ctx, session, record.path)\n await fs.writeText(target, record.before, void 0, void 0, policyOf(ctx, session))\n return { ok: true }\n } catch (error) {\n return { ok: false, error: '回滚失败:' + String(error) }\n }\n}\n\n/** 单 hunk 回滚:用 callHunk(edit 单 hunk 精确串)经 fs.editText 反替换。 */\nexport async function revertHunk(ctx: Ctx, session: Session, record: DiffRecord, idx: number): Promise<Result> {\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '回滚不可用:缺少 fs' }\n const hunk = record.hunks[idx]\n const precise = record.toolName === 'edit' && record.hunks.length <= 1 && record.callHunk ? record.callHunk : hunk\n if (!precise) return { ok: false, error: '找不到该差异块' }\n try {\n const target = await resolveTarget(ctx, session, record.path)\n await fs.editText(target, { oldString: precise.newText, newString: precise.oldText === null ? '' : precise.oldText }, void 0, void 0, policyOf(ctx, session))\n return { ok: true }\n } catch (error) {\n return { ok: false, error: '回滚失败:该区域可能已被后续修改影响(' + String(error) + ')' }\n }\n}\n\n/**\n * 恢复文件到记录对应状态(批次回滚用):返回错误文案或 null(成功)。\n * @author ddj 2026年08月20号\n */\nexport async function restoreFile(ctx: Ctx, session: Session, rec: DiffRecord): Promise<string | null> {\n const fs = ctx.get('fs')\n if (!fs) return '缺少 fs'\n if (rec.before === null || rec.before === undefined) {\n if (rec.create === true) {\n const out = await deleteCreated(ctx, session, rec)\n return out.ok ? null : out.error\n }\n return '缺少修改前内容(大文件或旧记录),无法回滚'\n }\n try {\n const target = await resolveTarget(ctx, session, rec.path)\n await fs.writeText(target, rec.before, void 0, void 0, policyOf(ctx, session))\n return null\n } catch (error) {\n return '回滚失败:' + String(error)\n }\n}\n","/**\n * dsh-vscode-mode host — RPC 分发:类型化方法表替代巨型 switch。\n * 迁移自原 src/index.ts 的 handleRpc,方法名/载荷/错误文案一字不改。\n * 新功能 = shared/rpc.ts 加方法 + 这里加一个 handler,不改其他模块。\n * 作者 ddj 2026-08-20\n */\nimport type { RpcHandlerMap, RpcMethod, RpcRequestMap, RpcResult } from './shared/rpc.js'\nimport type { DiffRecord, RecordView } from './shared/types.js'\nimport type { Ctx, Session } from './store.js'\nimport {\n READ_CAP,\n appendArchiveEntries,\n archiveRecords,\n autoArchiveStale,\n parseArchive,\n policyOf,\n readArchiveText,\n resolveTarget,\n saveBucket,\n} from './store.js'\nimport { archiveEntryFor, markDecision, recordResolved, reconstructOriginal } from './model.js'\nimport type { Registry } from './registry.js'\nimport { bucketOf, cwdOf, sessionOf } from './registry.js'\nimport { listWorkspaceFiles } from './workspace.js'\nimport { restoreFile, revertCall, revertHunk } from './revert.js'\n\n/** cwd → Promise 链:串行化 debug 日志追加(fs read+write 非原子,避免并发丢行)。 */\nconst debugWriteQueues = new Map<string, Promise<void>>()\n\n/** 记录 → 客户端视图(不含 before 全文,仅长度)。 */\nfunction recView(record: DiffRecord): RecordView {\n return {\n callId: record.callId,\n toolName: record.toolName,\n path: record.path,\n beforeLen: typeof record.before === 'string' ? record.before.length : 0,\n create: record.create === true,\n callHunk: record.callHunk,\n hunks: record.hunks,\n decisions: record.decisions,\n note: record.note ?? null,\n superseded: record.superseded === true,\n at: record.at,\n }\n}\n\n/** 会话/工作区公共前置:返回 {session,cwd} 或错误文案。 */\nasync function requireSession(ctx: Ctx, sessionId: string | undefined): Promise<\n { session: Session; cwd: string } | { err: string }\n> {\n const session = sessionOf(ctx, sessionId)\n if (!session) return { err: '会话不存在' }\n const cwd = cwdOf(session)\n if (!cwd) return { err: '会话无工作区' }\n return { session, cwd }\n}\n\n/** 各方法 handler 表(类型由 shared/rpc 的 RpcHandlerMap 约束)。 */\nexport function buildHandlers(ctx: Ctx, registry: Registry): RpcHandlerMap {\n return {\n 'edrv.list': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n const want = Array.isArray(args.callIds) ? new Set(args.callIds) : null\n if (!want) await autoArchiveStale(ctx, sc.session, sc.cwd, bucket) // 全量轮询时自动清理 stale 幽灵差异\n const out: RecordView[] = []\n for (const rec of bucket.values()) {\n // 面板全量查询过滤已归档;聊天条按 callId 查询保留(状态徽章仍需正确显示)\n if (!want && rec.archived) continue\n if (want && !want.has(rec.callId)) continue\n out.push(recView(rec))\n }\n out.sort((a, b) => (a.at < b.at ? -1 : 1))\n return { ok: true, records: out }\n },\n 'edrv.accept': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n const record = bucket.get(args.callId)\n if (!record) return { ok: false, error: '记录不存在' }\n markDecision(record, args.scope ?? 'call', args.hunkIndex, 'accepted')\n if (recordResolved(record)) await archiveRecords(ctx, sc.session, sc.cwd, bucket, [record], '已处理')\n else await saveBucket(ctx, sc.cwd, bucket, sc.session)\n return { ok: true, record: recView(record) }\n },\n 'edrv.reject': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n const record = bucket.get(args.callId)\n if (!record) return { ok: false, error: '记录不存在' }\n const scope = args.scope ?? 'call'\n const outcome = scope === 'hunk' ? await revertHunk(ctx, sc.session, record, args.hunkIndex ?? -1) : await revertCall(ctx, sc.session, record)\n if (!outcome.ok) return { ok: false, error: outcome.error }\n markDecision(record, scope, args.hunkIndex, 'rejected')\n record.at = new Date().toISOString()\n if (recordResolved(record)) await archiveRecords(ctx, sc.session, sc.cwd, bucket, [record], '已处理(回滚)')\n else await saveBucket(ctx, sc.cwd, bucket, sc.session)\n return { ok: true, record: recView(record) }\n },\n 'edrv.read': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '缺少 fs' }\n try {\n const target = await resolveTarget(ctx, sc.session, args.path)\n const info = await fs.stat(target)\n if (!info || info.type !== 'file') return { ok: false, error: '文件不存在' }\n if ((info.size ?? 0) > READ_CAP) return { ok: false, error: '文件过大(>8MB),不支持整文件预览' }\n const content = await fs.readText(target)\n return { ok: true, content, size: content.length }\n } catch (error) {\n return { ok: false, error: '读取失败:' + String(error) }\n }\n },\n 'edrv.original': async (args) => {\n // 重建\"本批次修改前\"内容:DiffEditor 原始侧。仅反解 pending 块;\n // 全部反解失败时回退到最早记录的整体 before(若存在)。\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '缺少 fs' }\n try {\n const target = await resolveTarget(ctx, sc.session, args.path)\n const info = await fs.stat(target)\n if (!info || info.type !== 'file') return { ok: false, error: '文件不存在' }\n if ((info.size ?? 0) > READ_CAP) return { ok: false, error: '文件过大(>8MB),不支持差异重建' }\n const content = await fs.readText(target)\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n const records = [...bucket.values()].filter((r) => r.path === args.path && !r.archived).sort((a, b) => (a.at < b.at ? -1 : 1))\n if (!records.length) return { ok: true, content, size: content.length, stale: [], fallback: false }\n const rebuilt = reconstructOriginal(records, content)\n if (rebuilt.stale.length && records[0].before !== null) {\n return { ok: true, content: records[0].before, size: records[0].before.length, stale: rebuilt.stale, fallback: true }\n }\n return { ok: true, content: rebuilt.content, size: rebuilt.content.length, stale: rebuilt.stale, fallback: false }\n } catch (error) {\n return { ok: false, error: '重建失败:' + String(error) }\n }\n },\n 'edrv.save': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '缺少 fs' }\n try {\n const target = await resolveTarget(ctx, sc.session, args.path)\n await fs.writeText(target, args.content, void 0, void 0, policyOf(ctx, sc.session))\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n let changed = false\n for (const rec of bucket.values()) {\n if (rec.path === args.path && rec.superseded !== true) { rec.superseded = true; rec.at = new Date().toISOString(); changed = true }\n }\n if (changed) {\n const done: DiffRecord[] = []\n for (const rec of bucket.values()) if (rec.path === args.path && rec.superseded) done.push(rec)\n if (done.length) await archiveRecords(ctx, sc.session, sc.cwd, bucket, done, '被手动编辑覆盖')\n else await saveBucket(ctx, sc.cwd, bucket, sc.session)\n }\n return { ok: true }\n } catch (error) {\n return { ok: false, error: '保存失败:' + String(error) }\n }\n },\n 'edrv.archiveList': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const batches = parseArchive(await readArchiveText(ctx, sc.cwd)).filter((b) => b.cwd === sc.cwd)\n const entries = batches.map((b) => {\n const recs = Array.isArray(b.records) ? b.records : []\n const sum = recs.reduce((s, r) => {\n const sm = r.summary || { accepted: 0, rejected: 0, pending: 0, superseded: false }\n s.accepted += sm.accepted || 0\n s.rejected += sm.rejected || 0\n s.pending += sm.pending || 0\n if (sm.superseded) s.superseded++\n return s\n }, { accepted: 0, rejected: 0, pending: 0, superseded: 0 })\n return { at: b.at, lastAt: b.lastAt || b.at, path: b.path, batch: b.batch ?? null, reason: b.reason ?? null, nRecords: recs.length, summary: sum }\n })\n entries.sort((a, b) => (Number(b.batch ?? -1) - Number(a.batch ?? -1)) || (a.at < b.at ? 1 : -1))\n return { ok: true, entries }\n },\n 'edrv.archiveRead': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const batchPath = args.path\n const batches = parseArchive(await readArchiveText(ctx, sc.cwd)).filter((b) => b.cwd === sc.cwd && (!batchPath || b.path === batchPath))\n return { ok: true, batches }\n },\n 'edrv.rollback': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const fs = ctx.get('fs')\n if (!fs) return { ok: false, error: '缺少 fs' }\n const batch = args.batch\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n let affected: DiffRecord[] = []\n let beforeRec: DiffRecord | null = null\n if (batch !== undefined) {\n const all = parseArchive(await readArchiveText(ctx, sc.cwd)).filter((b) => b.cwd === sc.cwd && b.path === args.path)\n const recs: DiffRecord[] = []\n for (const b of all) if (b.batch === batch) for (const r of (b.records || [])) recs.push(r as unknown as DiffRecord)\n if (!recs.length) return { ok: false, error: '归档中找不到该批次' }\n recs.sort((a, b2) => (a.at < b2.at ? -1 : 1))\n beforeRec = recs[0]\n affected = recs\n } else {\n for (const r of bucket.values()) if (r.path === args.path && !r.archived) affected.push(r)\n if (!affected.length) return { ok: false, error: '该文件没有可回滚的差异' }\n affected.sort((a, b2) => (a.at < b2.at ? -1 : 1))\n beforeRec = affected[0]\n }\n const rerr = await restoreFile(ctx, sc.session, beforeRec)\n if (rerr) return { ok: false, error: rerr }\n if (batch === undefined) {\n await archiveRecords(ctx, sc.session, sc.cwd, bucket, affected, '已回滚')\n } else {\n const all = parseArchive(await readArchiveText(ctx, sc.cwd)).filter((b) => b.cwd === sc.cwd && b.path === args.path && b.batch === batch)\n const sumRecs = all.reduce((s, b) => s + ((b.records || []).length), 0)\n const logRec = Object.assign({}, affected[0], { note: (affected[0].note ? affected[0].note + ';' : '') + '回滚至本批次前(批次 ' + batch + ')' })\n await appendArchiveEntries(ctx, sc.cwd, [archiveEntryFor([logRec], sc.cwd, '已回滚(批次 ' + batch + ',' + sumRecs + ' 条)')], sc.session)\n // 批次回滚恢复的是旧内容,文件当前活跃差异已失效,一并归档\n const activeRecs: DiffRecord[] = []\n for (const r of bucket.values()) if (r.path === args.path && !r.archived) activeRecs.push(r)\n if (activeRecs.length) await archiveRecords(ctx, sc.session, sc.cwd, bucket, activeRecs, '已回滚(批次回滚覆盖)')\n }\n return { ok: true, path: args.path, batch: batch ?? null }\n },\n 'edrv.debug': async (args) => {\n // 诊断日志:client 上报 → 写入工作区旁车 .dsh-edit-review-debug.log(console 不一定落盘,文件可靠)\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const fs = ctx.get('fs')\n const text = String(args.text ?? '')\n const prev = debugWriteQueues.get(sc.cwd) || Promise.resolve()\n const task = prev.then(async () => {\n try {\n const target = await fs.resolve('.dsh-edit-review-debug.log', { cwd: sc.cwd })\n const old = await fs.readText(target).catch(() => '')\n const line = new Date().toISOString() + ' ' + text + '\\n'\n await fs.writeText(target, (old || '') + line, void 0, void 0, policyOf(ctx, sc.session))\n } catch (e) { /* 写日志失败忽略 */ }\n })\n debugWriteQueues.set(sc.cwd, task)\n await task\n console.error('[edrv-debug] ' + text)\n return { ok: true }\n },\n 'edrv.searchFiles': async (args) => {\n const sc = await requireSession(ctx, args.sessionId)\n if ('err' in sc) return { ok: false, error: sc.err }\n const query = String(args.query ?? '').trim().toLowerCase()\n const files: string[] = []\n if (query.length >= 2) {\n const bucket = await bucketOf(registry, ctx, sc.cwd)\n const pool = new Set<string>()\n // 活跃差异路径恒并入(保证差异文件一定可搜到,即使工作区扫描不可用)\n for (const rec of bucket.values()) if (rec.path) pool.add(rec.path)\n const listed = await listWorkspaceFiles(ctx, sc.session, sc.cwd)\n if (listed) for (const f of listed) pool.add(f)\n const score = (p: string): number => {\n const pl = p.toLowerCase()\n const base = pl.split(/[\\\\/]/).pop() || ''\n if (base.includes(query)) return 0\n if (pl.includes(query)) return 1\n return -1\n }\n const hit = [...pool].filter((p) => score(p) >= 0)\n hit.sort((a, b) => (score(a) - score(b)) || (a < b ? -1 : 1))\n files.push(...hit.slice(0, 50))\n }\n return { ok: true, files, truncated: files.length >= 50 }\n },\n }\n}\n\n/**\n * 统一入口:按方法分发到 handler 表。\n * @author ddj 2026年08月20号\n */\nexport async function handleRpc<M extends RpcMethod>(\n ctx: Ctx,\n registry: Registry,\n method: M,\n args: RpcRequestMap[M],\n): Promise<RpcResult<M>> {\n const handlers = buildHandlers(ctx, registry)\n const handler = handlers[method]\n if (!handler) return { ok: false, error: '未知方法: ' + String(method) } as RpcResult<M>\n return handler(args)\n}\n","/**\n * @dsh-external 生态 → dsh-vscode-mode:DSH 上的类 VSCode 编码体验(Host 半入口)。\n * 职责:装配 capture(tools/result 捕获 edit/write 差异)、RPC 分发(11 个 edrv.* 方法)、\n * webServer 路由(/edrv/rpc、/edrv/assets/*、/edrv/vendor/*)、工作区旁车持久化。\n * 结构:shared/(双面契约) + model/store/capture/workspace/revert/registry/rpc/routes(host 模块)。\n * 作者 ddj 2026-08-20\n */\nimport { registerRoutes } from './routes.js'\nimport { captureToolResult } from './capture.js'\nimport { handleRpc } from './rpc.js'\nimport { dropFileIndex } from './workspace.js'\nimport { cwdOf } from './registry.js'\nimport type { Registry } from './registry.js'\nimport type { Ctx } from './store.js'\n\nexport const name = \"dsh-vscode-mode\"\nexport const inject = ['sessions', 'fs', 'webServer']\n\n/**\n * 装配插件:挂事件监听、注册路由。\n * @author ddj 2026年08月20号\n * @param ctx DSH 上下文(sessions/fs/webServer 由 inject 提供;sandboxPolicy/subprocess 惰性获取)\n * @param config 插件配置(可选 imageDir 覆盖图标目录)\n */\nexport function apply(ctx: Ctx, config?: unknown): void {\n const registry: Registry = new Map()\n\n ctx.on('tools/result', (exec: unknown, result: unknown) => {\n void captureToolResult(ctx, registry, exec, result)\n })\n\n ctx.on('session/disposed', (session: unknown) => {\n const cwd = cwdOf(session as never)\n if (cwd) {\n registry.delete(cwd)\n dropFileIndex(cwd)\n }\n })\n\n registerRoutes(ctx, config, (method, args) => handleRpc(ctx, registry, method, args))\n\n ctx.logger?.info?.('[' + name + '] 编辑差异审查已装配(/edrv/rpc 路由就绪)')\n}\n"],"mappings":";;;;;AAgBA,MAAa,WAAW;;;;;;;;ACJxB,MAAM,aAAa,CACjB;CAAE,KAAK;CAAiC,MAAM;AAAmB,GACjE;CAAE,KAAK;CAAmC,MAAM;AAAqB,CACvE;;AAGA,MAAM,gBAAgB;AACtB,MAAM,cAAsC;CAC1C,OAAO;CACP,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,QAAQ;CACR,SAAS;CACT,OAAO;AACT;;AAGA,SAAS,WAAW,QAAyB;CAC3C,MAAM,MAAM;CACZ,IAAI,OAAO,OAAO,IAAI,aAAa,YAAY,IAAI,UAAU,OAAO,IAAI,SAAS,QAAQ,OAAO,GAAG;CACnG,OAAO,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,MAAM,QAAQ;AACrE;;AAGA,MAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,MAAM,UAAU,QAAQ;;;;;;;;AASxF,SAAgB,eACd,KACA,QACA,WACM;CACN,MAAM,SAAS,WAAW,MAAM;CAChC,MAAM,MAAM,IAAI,IAAI,WAAW;CAC/B,IAAI,CAAC,KAAK;CAEV,IAAI,aAAa,IAAI,SAAS;EAC5B,MAAM;EACN,MAAM;EACN,SAAS,OAAO,KAAc,QAAuG;GACnI,IAAI;IACF,MAAM,SAAuB,CAAC;IAC9B,WAAW,MAAM,SAAS,KAAkC,OAAO,KAAK,KAAK;IAC7E,IAAI,QAA6C,CAAC;IAClD,IAAI;KACF,QAAQ,KAAK,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM,KAAK,IAAI;IACnE,SAAS,OAAO;KACd,QAAQ,CAAC;IACX;IAEA,MAAM,SAAS,MAAM,UADL,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,IAC1B,MAAM,QAAQ,CAAC,CAAW;IAClE,IAAI,aAAa;IACjB,IAAI,UAAU,gBAAgB,kBAAkB;IAChD,IAAI,IAAI,KAAK,UAAU,MAAM,CAAC;GAChC,SAAS,OAAO;IACd,IAAI,aAAa;IACjB,IAAI,IAAI,KAAK,UAAU;KAAE,IAAI;KAAO,OAAO,OAAO,KAAK;IAAE,CAAC,CAAC;GAC7D;EACF;CACF,CAAC,GAAG,uBAAuB;CAE3B,KAAK,MAAM,KAAK,YACd,IAAI,aAAa,IAAI,SAAS;EAC5B,MAAM;EACN,MAAM,EAAE;EACR,SAAS,OAAO,KAAc,QAAoH;GAChJ,IAAI;IACF,MAAM,OAAO,MAAM,SAAS,SAAS,MAAM,EAAE,IAAI;IACjD,IAAI,aAAa;IACjB,IAAI,UAAU,gBAAgB,WAAW;IACzC,IAAI,UAAU,iBAAiB,UAAU;IACzC,IAAI,IAAI,IAAI;GACd,SAAS,OAAO;IACd,IAAI,aAAa;IACjB,IAAI,IAAI;GACV;EACF;CACF,CAAC,GAAG,kBAAkB,EAAE,IAAI;CAI9B,IAAI,aAAa,IAAI,SAAS;EAC5B,MAAM;EACN,MAAM;EACN,SAAS,OAAO,KAAwC,QAAoH;GAC1K,IAAI;IACF,IAAI,IAAI,WAAW,SAAS,IAAI,WAAW,QAAQ;KACjD,IAAI,aAAa;KACjB,IAAI,IAAI;KACR;IACF;IACA,MAAM,WAAW,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC;IACrD,MAAM,MAAM,mBAAmB,SAAS,MAAM,EAAoB,CAAC,CAAC,CAAC,QAAQ,QAAQ,EAAE;IACvF,IAAI,CAAC,KAAK;KAAE,IAAI,aAAa;KAAK,IAAI,IAAI;KAAG;IAAO;IACpD,MAAM,SAAS,QAAQ,UAAU,KAAK,WAAW,GAAG,CAAC,CAAC;IACtD,IAAI,WAAW,aAAa,CAAC,OAAO,WAAW,YAAY,GAAG,GAAG;KAC/D,IAAI,aAAa;KACjB,IAAI,IAAI;KACR;IACF;IACA,MAAM,OAAO,MAAM,SAAS,MAAM;IAClC,IAAI,aAAa;IACjB,IAAI,UAAU,gBAAgB,YAAY,QAAQ,MAAM,MAAM,0BAA0B;IACxF,IAAI,UAAU,iBAAiB,sBAAsB;IACrD,IAAI,IAAI,IAAI;GACd,SAAS,OAAO;IACd,IAAI,aAAa;IACjB,IAAI,IAAI;GACV;EACF;CACF,CAAC,GAAG,2BAA2B;AACjC;;;;;;;ACzHA,SAAgB,gBAAgB,KAAiC;CAC/D,IAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,OAAO;CAC5C,MAAM,IAAI;CACV,IAAI,OAAO,EAAE,WAAW,YAAY,OAAO,EAAE,SAAS,UAAU,OAAO;CACvE,MAAM,QAAgB,MAAM,QAAQ,EAAE,KAAK,IACtC,EAAE,MAAoB,QAAQ,MAAM,KAAK,OAAQ,EAA4B,YAAY,QAAQ,IAClG,CAAC;CACL,MAAM,WAAmC,EAAE,aAAa,UAAU,UAAU;CAC5E,OAAO;EACL,QAAQ,EAAE;EACV;EACA,MAAM,EAAE;EACR,QAAQ,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;EAClD,QAAQ,EAAE,WAAW;EACrB,UAAU,EAAE,YAAY,OAAQ,EAAE,SAAmC,YAAY,WAC7E;GAAE,SAAU,EAAE,SAAiC;GAAS,SAAU,EAAE,SAAiC;EAAQ,IAC7G;EACJ,OAAO,MAAM,KAAK,OAAO;GAAE,SAAS,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU;GAAM,SAAS,EAAE;EAAQ,EAAE;EAC3G,WAAW,EAAE,aAAa,OAAO,EAAE,cAAc,WAC7C,EAAE,YACF;GAAE,MAAM;GAAW,SAAS,MAAM,UAAU,SAAqB;EAAE;EACvE,MAAM,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO;EAC5C,YAAY,EAAE,eAAe;EAC7B,UAAU,EAAE,aAAa;EACzB,OAAO,OAAO,UAAU,EAAE,KAAK,IAAK,EAAE,QAAmB;EACzD,IAAI,OAAO,EAAE,OAAO,WAAW,EAAE,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;CAC/D;AACF;;;;;;;;;;AAWA,SAAgB,aAAa,QAAoB,OAAe,KAAyB,OAA6B;CACpH,MAAM,MAAM,OAAO;CACnB,IAAI,UAAU,UAAU,MAAM,QAAQ,IAAI,OAAO,KAAK,OAAO,UAAU,GAAG,GAAG;EAC3E,MAAM,IAAI;EACV,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,QAAQ,IAAI,QAAQ,KAAK;CACzD,OAAO;EACL,IAAI,OAAO;EACX,IAAI,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,UAAU,IAAI,QAAQ,UAAU,KAAK;CAC3E;CACA,OAAO,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;CACnC,OAAO;AACT;;AAGA,SAAgB,eAAe,QAA6B;CAC1D,IAAI,OAAO,eAAe,MAAM,OAAO;CACvC,MAAM,UAAU,MAAM,QAAQ,OAAO,UAAU,OAAO,IAAI,OAAO,UAAU,UAAU,CAAC;CACtF,IAAI,QAAQ,QAAQ,OAAO,QAAQ,OAAO,MAAM,MAAM,cAAc,MAAM,UAAU;CACpF,OAAO,OAAO,UAAU,SAAS,cAAc,OAAO,UAAU,SAAS;AAC3E;;;;;;;AAQA,SAAgB,WAAW,QAAmC;CAC5D,MAAM,UAAU,MAAM,QAAQ,OAAO,UAAU,OAAO,IAAI,OAAO,UAAU,UAAU,CAAC;CACtF,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC;CAC3E,IAAI,WAAW;CACf,IAAI,WAAW;CACf,IAAI,UAAU;CACd,IAAI,QAAQ,QACV,KAAK,MAAM,KAAK,SACd,IAAI,MAAM,YAAY;MACjB,IAAI,MAAM,YAAY;MACtB;MAEF,IAAI,OAAO,UAAU,SAAS,YAAY,WAAW;MACvD,IAAI,OAAO,UAAU,SAAS,YAAY,WAAW;MACrD,UAAU;CACf,OAAO;EAAE;EAAU;EAAU;EAAS,YAAY,OAAO,eAAe;CAAK;AAC/E;;;;;;;;;AAUA,SAAgB,oBAAoB,SAAuB,SAAqF;CAC9I,MAAM,UAAmD,CAAC;CAC1D,KAAK,MAAM,OAAO,SAAS;EACzB,MAAM,UAAU,MAAM,QAAQ,IAAI,UAAU,OAAO,IAAI,IAAI,UAAU,UAAU,CAAC;EAChF,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,QAAQ,KAEpC,KADW,QAAQ,SAAS,QAAQ,KAAK,IAAI,UAAU,UAC5C,WAAW,QAAQ,KAAK;GAAE;GAAK,KAAK;EAAE,CAAC;CAEtD;CACA,QAAQ,MAAM,GAAG,MAAO,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,KAAK,CAAE;CAC/E,IAAI,MAAM;CACV,MAAM,QAAgD,CAAC;CACvD,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,IAAI,EAAE,IAAI,MAAM,EAAE;EACxB,MAAM,UAAU,EAAE,IAAI,aAAa,UAAU,EAAE,IAAI,MAAM,UAAU,KAAK,EAAE,IAAI,WAAW,EAAE,IAAI,WAAW;EAC1G,MAAM,UAAU,QAAQ,WAAW;EACnC,MAAM,KAAK,IAAI,QAAQ,OAAO;EAC9B,IAAI,KAAK,GAAG;GAAE,MAAM,KAAK;IAAE,QAAQ,EAAE,IAAI;IAAQ,KAAK,EAAE;GAAI,CAAC;GAAG;EAAS;EACzE,MAAM,UAAU,QAAQ,YAAY,OAAO,KAAK,QAAQ;EACxD,MAAM,IAAI,MAAM,GAAG,EAAE,IAAI,UAAU,IAAI,MAAM,KAAK,QAAQ,MAAM;CAClE;CACA,OAAO;EAAE,SAAS;EAAK;CAAM;AAC/B;;AAGA,SAAgB,aAAa,SAAkC,MAAsB;CACnF,IAAI,IAAI;CACR,KAAK,MAAM,KAAK,QAAQ,OAAO,GAC7B,IAAI,EAAE,SAAS,QAAQ,OAAO,UAAU,EAAE,KAAK,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE;CAEzE,OAAO;AACT;;AAGA,SAAgB,MAAM,KAA8B,MAAA,KAAyB;CAC3E,IAAI,IAAI,QAAQ,KAAK;CACrB,MAAM,SAAS,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE;CACtE,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,SAAS,KAAK,KAAK,IAAI,OAAO,OAAO,EAAE,CAAC,MAAM;AAC3E;;AAGA,SAAgB,aAAa,MAAsD;CACjF,MAAM,sBAAM,IAAI,IAAiC;CACjD,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,IAAI,OAAO,UAAU,EAAE,KAAK,IAAI,EAAE,QAAQ;EAChD,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,CAAC;EAC9B,IAAI,IAAI,CAAC,CAAC,CAAE,KAAK,CAAC;CACpB;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,gBAAgB,MAAoB,KAAa,QAO/D;CACA,MAAM,QAAQ,KAAK;CACnB,OAAO;EACL,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;EAC3B;EACA,MAAM,MAAM;EACZ,OAAO,OAAO,UAAU,MAAM,KAAK,IAAI,MAAM,QAAQ;EACrD;EACA,SAAS,KAAK,KAAK,OAAO;GACxB,QAAQ,EAAE;GACV,UAAU,EAAE;GACZ,MAAM,EAAE;GACR,QAAQ,EAAE,WAAW;GACrB,UAAU,EAAE;GACZ,OAAO,EAAE;GACT,WAAW,EAAE;GACb,MAAM,EAAE,QAAQ;GAChB,QAAQ,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;GAClD,YAAY,EAAE,eAAe;GAC7B,OAAO,OAAO,UAAU,EAAE,KAAK,IAAI,EAAE,QAAQ;GAC7C,IAAI,EAAE;GACN,SAAS,WAAW,CAAC;EACvB,EAAE;CACJ;AACF;;;AC5LA,MAAa,UAAU;AACvB,MAAa,kBAAkB;;AAW/B,SAAgB,SAAS,KAAU,SAAmC;CACpE,MAAM,MAAM,IAAI,IAAI,eAAe;CACnC,IAAI,CAAC,KAAK,OAAO,KAAA;CACjB,OAAO,UAAU,IAAI,QAAQ,EAAE,QAAQ,CAAC,IAAI,IAAI,QAAQ;AAC1D;;AAGA,eAAsB,cAAc,KAAU,SAA8B,MAA+B;CACzG,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,MAAM,MAAM,SAAS,QAAQ;CAC7B,OAAO,GAAG,QAAQ,MAAM,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC;AAC5C;;AAGA,eAAe,gBAAgB,KAAU,KAA4C;CACnF,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,MAAM,CAAC,KAAK,OAAO;CACxB,IAAI;EACF,OAAO,MAAM,GAAG,SAAS,MAAM,GAAG,QAAQ,SAAS,EAAE,IAAI,CAAC,CAAC;CAC7D,SAAS,OAAO;EACd,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,aAAa,MAAyC;CACpE,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI;EACF,MAAM,OAAO,KAAK,MAAM,IAAI;EAC5B,IAAI,QAAQ,OAAO,SAAS,YAAY,KAAK,YAAY,KAAK,KAAK,cAAc,OAAO,KAAK,eAAe,UAC1G,OAAO;EAET,IAAI,QAAQ,KAAK,YAAY,KAAK,KAAK,YAAY,OAAO,KAAK,aAAa,UAAU;GACpF,MAAM,aAAwC,CAAC;GAC/C,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,QAAQ,GAAG;IACjD,MAAM,IAAI;IACV,IAAI,OAAO,EAAE,QAAQ,YAAY,EAAE,SACjC,WAAW,EAAE,OAAO;KAAE,IAAI,OAAO,EAAE,OAAO,WAAW,EAAE,KAAK,KAAK,IAAI;KAAG,SAAS,EAAE;IAAsC;GAE7H;GACA,OAAO;IAAE,SAAS;IAAG,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAAG;GAAW;EAC7H;EACA,OAAO;CACT,SAAS,OAAO;EACd,OAAO;CACT;AACF;;AAGA,eAAsB,WAAW,KAAU,KAA+C;CAExF,MAAM,OAAO,aAAa,MADP,gBAAgB,KAAK,GAAG,CACb;CAC9B,MAAM,sBAAM,IAAI,IAAwB;CACxC,IAAI,QAAQ,KAAK,WAAW,QAAQ,OAAO,KAAK,WAAW,IAAI,CAAC,YAAY,UAC1E,KAAK,MAAM,OAAO,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,GAAG;EAC7D,MAAM,IAAI,gBAAgB,GAAG;EAC7B,IAAI,GAAG,IAAI,IAAI,EAAE,QAAQ,CAAC;CAC5B;CAEF,OAAO;AACT;;AAGA,eAAsB,WAAW,KAAU,KAAa,SAAkC,SAAkC;CAC1H,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,MAAM,CAAC,KAAK;CACjB,IAAI;EACF,MAAM,SAAS,MAAM,GAAG,QAAQ,SAAS,EAAE,IAAI,CAAC;EAChD,MAAM,WAAW,aAAa,MAAM,gBAAgB,KAAK,GAAG,CAAC,KAAK;GAAE,SAAS;GAAG,WAAW;GAAI,YAAY,CAAC;EAAE;EAC9G,SAAS,WAAW,OAAO;GAAE,IAAI,KAAK,IAAI;GAAG,SAAS,OAAO,YAAY,OAAO;EAAE;EAClF,SAAS,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EAC5C,MAAM,GAAG,UAAU,QAAQ,KAAK,UAAU,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC;CAC7F,SAAS,OAAO;EACd,QAAQ,MAAM,0BAA0B,KAAK;CAC/C;AACF;;;;;;AAOA,eAAsB,aAAa,KAAU,SAAkB,OAAmC,MAAsC;CACtI,IAAI,MAAM,IAAI,IAAI,GAAG,OAAO,MAAM,IAAI,IAAI,KAAK;CAC/C,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,IAAI;EAAE,MAAM,IAAI,MAAM,IAAI;EAAG,OAAO;CAAK;CAC9C,IAAI;EACF,MAAM,SAAS,MAAM,cAAc,KAAK,SAAS,IAAI;EACrD,MAAM,OAAO,MAAM,GAAG,KAAK,MAAM;EACjC,IAAI,CAAC,QAAQ,KAAK,SAAS,QAAQ;GAAE,MAAM,IAAI,MAAM,IAAI;GAAG,OAAO;EAAK;EACxE,KAAK,KAAK,QAAQ,KAAA,SAAe;GAAE,MAAM,IAAI,MAAM,EAAE;GAAG,OAAO;EAAG;EAClE,MAAM,UAAU,MAAM,GAAG,SAAS,MAAM;EACxC,MAAM,IAAI,MAAM,OAAO;EACvB,OAAO;CACT,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,IAAI;EACpB,OAAO;CACT;AACF;;;;;;AAOA,eAAsB,cAAc,KAAU,SAAkB,OAAmC,KAAmC;CACpI,IAAI,IAAI,eAAe,MAAM,OAAO;CACpC,IAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,QAAQ,OAAO;CAC3D,MAAM,UAAU,MAAM,QAAQ,IAAI,UAAU,OAAO,IAAI,IAAI,UAAU,UAAU,CAAC;CAChF,IAAI,sBAAsB;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,QAAQ,KAAK;EACzC,MAAM,KAAK,QAAQ,SAAS,QAAQ,KAAK,IAAI,UAAU;EACvD,IAAI,OAAO,cAAc,OAAO,YAAY;EAC5C,IAAI,IAAI,WAAW,MAAM;GAEvB,IAAI,MADkB,aAAa,KAAK,SAAS,OAAO,IAAI,IAAI,MAChD,MAAM;IAAE,sBAAsB;IAAM;GAAM;GAC1D;EACF;EACA,MAAM,UAAU,IAAI,aAAa,UAAU,IAAI,WAAW,IAAI,WAAW,IAAI,MAAM;EACnF,MAAM,UAAU,SAAS,WAAW;EACpC,MAAM,UAAU,SAAS,WAAW;EACpC,IAAI,YAAY,QAAQ,YAAY,SAAS;EAC7C,IAAI,YAAY,QAAQ,YAAY,KAAA,GAAW;EAC/C,MAAM,UAAU,MAAM,aAAa,KAAK,SAAS,OAAO,IAAI,IAAI;EAChE,IAAI,YAAY,QAAQ,QAAQ,QAAQ,OAAO,KAAK,GAAG;GAAE,sBAAsB;GAAM;EAAM;CAC7F;CACA,OAAO,CAAC;AACV;;;;;;;AAQA,eAAsB,iBAAiB,KAAU,SAAkB,KAAa,QAAkD;CAEhI,IAAI,CADO,IAAI,IAAI,IACb,GAAG,OAAO;CAChB,MAAM,wBAAQ,IAAI,IAA2B;CAC7C,MAAM,QAAsB,CAAC;CAC7B,KAAK,MAAM,OAAO,OAAO,OAAO,GAAG;EACjC,IAAI,IAAI,YAAY,IAAI,eAAe,MAAM;EAC7C,IAAI,MAAM,cAAc,KAAK,SAAS,OAAO,GAAG,GAAG,MAAM,KAAK,GAAG;CACnE;CACA,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,KAAK,MAAM,KAAK,OAAO;EAAE,EAAE,aAAa;EAAM,EAAE,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;CAAE;CAC9E,MAAM,eAAe,KAAK,SAAS,KAAK,QAAQ,OAAO,uBAAuB;CAC9E,OAAO,MAAM;AACf;;AAGA,eAAsB,gBAAgB,KAAU,KAA4C;CAC1F,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,MAAM,CAAC,KAAK,OAAO;CACxB,IAAI;EACF,OAAO,MAAM,GAAG,SAAS,MAAM,GAAG,QAAQ,iBAAiB,EAAE,IAAI,CAAC,CAAC;CACrE,SAAS,OAAO;EACd,OAAO;CACT;AACF;;AAGA,SAAgB,aAAa,MAAqC;CAChE,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,IAAI;EACF,MAAM,OAAO,KAAK,MAAM,IAAI;EAC5B,IAAI,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,KAAK,OAAO,GAAG,OAAO,KAAK;CACnF,SAAS,OAAO,CAAa;CAC7B,OAAO,CAAC;AACV;;AAGA,eAAsB,qBAAqB,KAAU,KAAa,SAAoD,SAAkC;CACtJ,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,MAAM,CAAC,KAAK;CACjB,IAAI;EACF,MAAM,SAAS,MAAM,GAAG,QAAQ,iBAAiB,EAAE,IAAI,CAAC;EACxD,MAAM,WAAW,aAAa,MAAM,gBAAgB,KAAK,GAAG,CAAC;EAC7D,KAAK,MAAM,KAAK,SAAS;GACvB,MAAM,MAAM,SAAS,WAAW,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK;GACjG,IAAI,OAAO,GAAG;IACZ,MAAM,QAAQ,SAAS;IACvB,MAAM,OAAO,IAAI,KAAK,MAAM,WAAW,CAAC,EAAA,CAAG,KAAK,MAAM,EAAE,MAAM,CAAC;IAC/D,KAAK,MAAM,OAAO,EAAE,SAClB,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,MAAM,CAAC,GAAG;KACjC,MAAM,QAAQ,KAAK,GAAiD;KACpE,KAAK,IAAI,OAAO,IAAI,MAAM,CAAC;IAC7B;IAEF,MAAM,SAAS,EAAE;IACjB,MAAM,SAAS,EAAE;GACnB,OACE,SAAS,KAAK,CAA4B;EAE9C;EACA,MAAM,OAAoB;GAAE,SAAS;GAAG,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GAAG,SAAS;EAAS;EAC/F,MAAM,GAAG,UAAU,QAAQ,KAAK,UAAU,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC;CACzF,SAAS,OAAO;EACd,QAAQ,MAAM,oCAAoC,KAAK;CACzD;AACF;;AAGA,eAAsB,eACpB,KACA,SACA,KACA,QACA,MACA,QACe;CACf,IAAI,CAAC,KAAK,QAAQ;CAClB,MAAM,QAAQ,KAAK,QAAQ,MAAM,CAAC,EAAE,QAAQ;CAC5C,KAAK,MAAM,KAAK,MAAM,EAAE,WAAW;CACnC,MAAM,UAAqD,CAAC;CAC5D,KAAK,MAAM,QAAQ,aAAa,IAAI,CAAC,CAAC,OAAO,GAAG,QAAQ,KAAK,gBAAgB,MAAM,KAAK,MAAM,CAAC;CAC/F,MAAM,qBAAqB,KAAK,KAAK,SAAS,OAAO;CACrD,IAAI,MAAM,QAAQ,MAAM,WAAW,KAAK,KAAK,QAAQ,OAAO;AAC9D;;;;ACtOA,SAAgB,UAAU,KAAU,WAAyC;CAC3E,MAAM,WAAW,IAAI,IAAI,UAAU;CACnC,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,IAAI,WAAW,OAAO,SAAS,IAAI,SAAS;CAC5C,MAAM,OAAO,SAAS,KAAK,CAAC,CAAC,QAAQ,MAAe,EAAE,EAAE;CACxD,OAAO,KAAK,WAAW,IAAI,KAAK,KAAK,KAAA;AACvC;;AAGA,SAAgB,MAAM,SAA6C;CACjE,OAAO,SAAS,QAAQ,OAAO;AACjC;;AAGA,SAAgB,SAAS,UAAoB,KAAU,KAA+C;CACpG,MAAM,WAAW,SAAS,IAAI,GAAG;CACjC,IAAI,UAAU,OAAO,QAAQ,QAAQ,QAAQ;CAC7C,OAAO,WAAW,KAAK,GAAG,CAAC,CAAC,MAAM,QAAQ;EACxC,SAAS,IAAI,KAAK,GAAG;EACrB,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;ACZA,eAAsB,kBAAkB,KAAU,UAAoB,MAAW,QAA4B;CAC3G,MAAM,UAA+B,MAAM,OAAO;CAClD,IAAI,CAAC,WAAY,MAAM,SAAS,UAAU,MAAM,SAAS,SAAU;CACnE,IAAI,QAAQ,WAAW,CAAC,QAAQ,OAAO;CACvC,IAAI;EACF,MAAM,MAAM,MAAM,OAAO;EACzB,IAAI,CAAC,KAAK;EACV,MAAM,QAAQ,OAAO;EACrB,MAAM,OAAO,KAAK,aAAa,CAAC;EAChC,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAK;EAChE,IAAI,CAAC,MAAM;EACX,MAAM,YAAiC,MAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,OAAO,KAAK,QAAQ,CAAC;EAChG,MAAM,SAAS,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;EACjE,MAAM,SAAS,KAAK,SAAS,WAAW,MAAM,WAAW;EACzD,MAAM,WAAW,KAAK,SAAS,UAAU,OAAO,KAAK,eAAe,WAAW;GAAE,SAAS,KAAK;GAAY,SAAS,KAAK;EAAW,IAAI;EACxI,MAAM,YAAY,SAAS;GAAE,SAAS;GAAuB,SAAS,OAAO,KAAK,YAAY,WAAW,KAAK,UAAW,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;EAAI,IAAI;EACjL,MAAM,QAAQ,UAAU,SAAS,YAAa,YAAY,CAAC,SAAS,IAAK,WAAW,CAAC,QAAQ,IAAI,CAAC;EAClG,IAAI,CAAC,MAAM,QAAQ;EACnB,MAAM,SAAqB;GACzB,QAAQ,KAAK;GACb,UAAU,KAAK;GACf;GACA;GACA;GACA;GACA;GACA,WAAW;IAAE,MAAM;IAAW,SAAS,MAAM,UAAU,SAAS;GAAE;GAClE,MAAM,SAAS,oBAAoB,WAAW,OAAO,kBAAkB;GACvE,YAAY;GACZ,UAAU;GACV,OAAO;GACP,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;EAC7B;EACA,IAAI,SAAS,SAAS,IAAI,GAAG;EAC7B,IAAI,CAAC,QAAQ;GAAE,SAAS,MAAM,WAAW,KAAK,GAAG;GAAG,SAAS,IAAI,KAAK,MAAM;EAAE;EAC9E,OAAO,QAAQ,aAAa,QAAQ,IAAI,IAAI;EAC5C,OAAO,IAAI,KAAK,QAAQ,MAAM;EAE9B,MAAM,QAAsB,CAAC;EAC7B,KAAK,MAAM,KAAK,OAAO,OAAO,GAC5B,IAAI,EAAE,SAAS,QAAQ,EAAE,WAAW,KAAK,UAAU,CAAC,EAAE,aAAa,EAAE,SAAS,KAAK,OAAO,OAAO,MAAM,KAAK,CAAC;EAE/G,IAAI,MAAM,QACR,MAAM,eAAe,KAAK,SAAS,KAAK,QAAQ,OAAO,MAAM,MAAM,cAAc,IAAI,gBAAgB,kBAAkB;EAEzH,MAAM,MAAM;EACZ,MAAM,WAAW,KAAK,KAAK,QAAQ,OAAO;CAC5C,SAAS,OAAO;EACd,QAAQ,MAAM,uBAAuB,KAAK;CAC5C;AACF;;;;AC/DA,MAAM,iBAAiB;AACvB,MAAM,WAAW;;AAEjB,MAAM,4BAAY,IAAI,IAA6C;;;;;;;;;;AAWnE,eAAsB,mBAAmB,KAAU,SAAkB,KAAuC;CAC1G,MAAM,SAAS,UAAU,IAAI,GAAG;CAChC,IAAI,UAAU,KAAK,IAAI,IAAI,OAAO,KAAK,gBAAgB,OAAO,OAAO;CACrE,MAAM,MAAM,IAAI,IAAI,YAAY;CAChC,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO;CACxB,MAAM,SAAS,SAAS,KAAK,OAAO;CACpC,IAAI;CACJ,IAAI;EACF,MAAM,aAAa,MAAM,GAAG,QAAQ,QAAQ,iBAAiB,KAAK,CAAC,CAAC;EACpE,OAAO,GAAG,YAAY,UAAU;CAClC,SAAS,OAAO;EACd,OAAO;CACT;CACA,MAAM,QAAkB,CAAC;CACzB,MAAM,MAAM,OAAO,SAAkC;EACnD,MAAM,SAAS,IAAI,MAAM;GACvB;GACA,OAAO;IAAE,QAAQ,EAAE,UAAU,KAAK,GAAG;IAAG,QAAQ,EAAE,UAAU,MAAQ;IAAG,OAAO;GAAS;GACvF,SAAS;EACX,CAAC;EACD,MAAM,UAAU,MAAM,OAAO;EAC7B,MAAM,OAAO,SAAS,YAAY,SAAS;EAC3C,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,eAAe,IAAI;EACnD,MAAM,OAAO,OAAO,WAAW,QAAQ,SAAS,CAAC,CAAC,CAAC,QAAQ;EAC3D,KAAK,MAAM,MAAM,KAAK,MAAM,OAAO,GAAG;GACpC,MAAM,IAAI,GAAG,KAAK;GAClB,IAAI,GAAG,MAAM,KAAK,CAAC;EACrB;CACF;CACA,IAAI;EACF,IAAI,QAAQ,aAAa,SAEvB,MAAM,IAAI;GAAC;GAAc;GAAc;GAAmB;GAD9C,kCAAiC,OAAO,IAAI,CAAC,CAAC,QAAQ,MAAM,MAAI,IAAI;EACP,CAAC;OAG1E,MAAM,IAAI;GAAC;GAAW;GADV,UAAU,KAAK,UAAU,IAAI,IAAI;EACd,CAAC;CAEpC,SAAS,OAAO;EACd,QAAQ,MAAM,oBAAoB,KAAK;EACvC,OAAO;CACT;CACA,MAAM,QAAQ,MAAM,MAAM,GAAG,QAAQ;CACrC,IAAI,MAAM,QAAQ,UAAU,IAAI,KAAK;EAAE,IAAI,KAAK,IAAI;EAAG;CAAM,CAAC;CAC9D,OAAO;AACT;;AAGA,SAAgB,cAAc,KAAmB;CAC/C,UAAU,OAAO,GAAG;AACtB;;;;;;;;ACzDA,eAAsB,cAAc,KAAU,SAAkB,QAAqC;CACnG,MAAM,MAAM,IAAI,IAAI,YAAY;CAChC,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO;EAAE,IAAI;EAAO,OAAO;CAAyB;CACrE,MAAM,SAAS,SAAS,KAAK,OAAO;CACpC,MAAM,aAAa,MAAM,GAAG,QAAQ,QAAQ,iBAAiB,KAAK,CAAC,CAAC;CACpE,MAAM,SAAS,MAAM,cAAc,KAAK,SAAS,OAAO,IAAI;CAC5D,IAAI,CAAC,GAAG,SAAS,YAAY,MAAM,GAAG,OAAO;EAAE,IAAI;EAAO,OAAO;CAAkB;CACnF,MAAM,IAAI,GAAG,YAAY,MAAM;CAE/B,MAAM,UAAU,OAAO,SAAkC;EACvD,MAAM,SAAS,IAAI,MAAM;GACvB;GACA,OAAO;IAAE,QAAQ,EAAE,UAAU,MAAQ;IAAG,QAAQ,EAAE,UAAU,MAAQ;IAAG,OAAO;GAAS;GACvF,SAAS;EACX,CAAC;EACD,MAAM,UAAU,MAAM,OAAO;EAC7B,MAAM,OAAO,SAAS,YAAY,SAAS;EAC3C,IAAI,SAAS,GAAG;GACd,MAAM,MAAM,OAAO,WAAW,QAAQ,SAAS,CAAC,CAAC,CAAC,QAAQ;GAC1D,MAAM,IAAI,MAAM,UAAU,OAAO,MAAM,GAAG;EAC5C;CACF;CACA,IAAI;EACF,MAAM,QAAQ;GAAC;GAAc;GAAc;GAAmB;GAAY,gCAA+B,IAAI;EAAU,CAAC;EACxH,OAAO,EAAE,IAAI,KAAK;CACpB,SAAS,OAAO;EACd,IAAI;GACF,MAAM,QAAQ;IAAC;IAAW;IAAM;IAAM;GAAC,CAAC;GACxC,OAAO,EAAE,IAAI,KAAK;EACpB,SAAS,QAAQ;GACf,OAAO;IAAE,IAAI;IAAO,OAAO,iBAAiB,OAAO,KAAK,IAAI,QAAQ,OAAO,MAAM;GAAE;EACrF;CACF;AACF;;AAGA,eAAsB,WAAW,KAAU,SAAkB,QAAqC;CAChG,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,IAAI,OAAO;EAAE,IAAI;EAAO,OAAO;CAAc;CAClD,IAAI,OAAO,WAAW,MAAM;EAC1B,IAAI,CAAC,OAAO,QAAQ,OAAO;GAAE,IAAI;GAAO,OAAO;EAAwB;EACvE,OAAO,cAAc,KAAK,SAAS,MAAM;CAC3C;CACA,IAAI;EACF,MAAM,SAAS,MAAM,cAAc,KAAK,SAAS,OAAO,IAAI;EAC5D,MAAM,GAAG,UAAU,QAAQ,OAAO,QAAQ,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC;EAChF,OAAO,EAAE,IAAI,KAAK;CACpB,SAAS,OAAO;EACd,OAAO;GAAE,IAAI;GAAO,OAAO,UAAU,OAAO,KAAK;EAAE;CACrD;AACF;;AAGA,eAAsB,WAAW,KAAU,SAAkB,QAAoB,KAA8B;CAC7G,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,IAAI,OAAO;EAAE,IAAI;EAAO,OAAO;CAAc;CAClD,MAAM,OAAO,OAAO,MAAM;CAC1B,MAAM,UAAU,OAAO,aAAa,UAAU,OAAO,MAAM,UAAU,KAAK,OAAO,WAAW,OAAO,WAAW;CAC9G,IAAI,CAAC,SAAS,OAAO;EAAE,IAAI;EAAO,OAAO;CAAU;CACnD,IAAI;EACF,MAAM,SAAS,MAAM,cAAc,KAAK,SAAS,OAAO,IAAI;EAC5D,MAAM,GAAG,SAAS,QAAQ;GAAE,WAAW,QAAQ;GAAS,WAAW,QAAQ,YAAY,OAAO,KAAK,QAAQ;EAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC;EAC5J,OAAO,EAAE,IAAI,KAAK;CACpB,SAAS,OAAO;EACd,OAAO;GAAE,IAAI;GAAO,OAAO,wBAAwB,OAAO,KAAK,IAAI;EAAI;CACzE;AACF;;;;;AAMA,eAAsB,YAAY,KAAU,SAAkB,KAAyC;CACrG,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,IAAI,CAAC,IAAI,OAAO;CAChB,IAAI,IAAI,WAAW,QAAQ,IAAI,WAAW,KAAA,GAAW;EACnD,IAAI,IAAI,WAAW,MAAM;GACvB,MAAM,MAAM,MAAM,cAAc,KAAK,SAAS,GAAG;GACjD,OAAO,IAAI,KAAK,OAAO,IAAI;EAC7B;EACA,OAAO;CACT;CACA,IAAI;EACF,MAAM,SAAS,MAAM,cAAc,KAAK,SAAS,IAAI,IAAI;EACzD,MAAM,GAAG,UAAU,QAAQ,IAAI,QAAQ,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC;EAC7E,OAAO;CACT,SAAS,OAAO;EACd,OAAO,UAAU,OAAO,KAAK;CAC/B;AACF;;;;AC/EA,MAAM,mCAAmB,IAAI,IAA2B;;AAGxD,SAAS,QAAQ,QAAgC;CAC/C,OAAO;EACL,QAAQ,OAAO;EACf,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,WAAW,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,SAAS;EACtE,QAAQ,OAAO,WAAW;EAC1B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd,WAAW,OAAO;EAClB,MAAM,OAAO,QAAQ;EACrB,YAAY,OAAO,eAAe;EAClC,IAAI,OAAO;CACb;AACF;;AAGA,eAAe,eAAe,KAAU,WAEtC;CACA,MAAM,UAAU,UAAU,KAAK,SAAS;CACxC,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,QAAQ;CACpC,MAAM,MAAM,MAAM,OAAO;CACzB,IAAI,CAAC,KAAK,OAAO,EAAE,KAAK,SAAS;CACjC,OAAO;EAAE;EAAS;CAAI;AACxB;;AAGA,SAAgB,cAAc,KAAU,UAAmC;CACzE,OAAO;EACL,aAAa,OAAO,SAAS;GAC3B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;GACnD,MAAM,OAAO,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAI,IAAI,KAAK,OAAO,IAAI;GACnE,IAAI,CAAC,MAAM,MAAM,iBAAiB,KAAK,GAAG,SAAS,GAAG,KAAK,MAAM;GACjE,MAAM,MAAoB,CAAC;GAC3B,KAAK,MAAM,OAAO,OAAO,OAAO,GAAG;IAEjC,IAAI,CAAC,QAAQ,IAAI,UAAU;IAC3B,IAAI,QAAQ,CAAC,KAAK,IAAI,IAAI,MAAM,GAAG;IACnC,IAAI,KAAK,QAAQ,GAAG,CAAC;GACvB;GACA,IAAI,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE;GACzC,OAAO;IAAE,IAAI;IAAM,SAAS;GAAI;EAClC;EACA,eAAe,OAAO,SAAS;GAC7B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;GACnD,MAAM,SAAS,OAAO,IAAI,KAAK,MAAM;GACrC,IAAI,CAAC,QAAQ,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAChD,aAAa,QAAQ,KAAK,SAAS,QAAQ,KAAK,WAAW,UAAU;GACrE,IAAI,eAAe,MAAM,GAAG,MAAM,eAAe,KAAK,GAAG,SAAS,GAAG,KAAK,QAAQ,CAAC,MAAM,GAAG,KAAK;QAC5F,MAAM,WAAW,KAAK,GAAG,KAAK,QAAQ,GAAG,OAAO;GACrD,OAAO;IAAE,IAAI;IAAM,QAAQ,QAAQ,MAAM;GAAE;EAC7C;EACA,eAAe,OAAO,SAAS;GAC7B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;GACnD,MAAM,SAAS,OAAO,IAAI,KAAK,MAAM;GACrC,IAAI,CAAC,QAAQ,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAChD,MAAM,QAAQ,KAAK,SAAS;GAC5B,MAAM,UAAU,UAAU,SAAS,MAAM,WAAW,KAAK,GAAG,SAAS,QAAQ,KAAK,aAAa,EAAE,IAAI,MAAM,WAAW,KAAK,GAAG,SAAS,MAAM;GAC7I,IAAI,CAAC,QAAQ,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,QAAQ;GAAM;GAC1D,aAAa,QAAQ,OAAO,KAAK,WAAW,UAAU;GACtD,OAAO,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;GACnC,IAAI,eAAe,MAAM,GAAG,MAAM,eAAe,KAAK,GAAG,SAAS,GAAG,KAAK,QAAQ,CAAC,MAAM,GAAG,SAAS;QAChG,MAAM,WAAW,KAAK,GAAG,KAAK,QAAQ,GAAG,OAAO;GACrD,OAAO;IAAE,IAAI;IAAM,QAAQ,QAAQ,MAAM;GAAE;EAC7C;EACA,aAAa,OAAO,SAAS;GAC3B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,KAAK,IAAI,IAAI,IAAI;GACvB,IAAI,CAAC,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC5C,IAAI;IACF,MAAM,SAAS,MAAM,cAAc,KAAK,GAAG,SAAS,KAAK,IAAI;IAC7D,MAAM,OAAO,MAAM,GAAG,KAAK,MAAM;IACjC,IAAI,CAAC,QAAQ,KAAK,SAAS,QAAQ,OAAO;KAAE,IAAI;KAAO,OAAO;IAAQ;IACtE,KAAK,KAAK,QAAQ,KAAA,SAAe,OAAO;KAAE,IAAI;KAAO,OAAO;IAAsB;IAClF,MAAM,UAAU,MAAM,GAAG,SAAS,MAAM;IACxC,OAAO;KAAE,IAAI;KAAM;KAAS,MAAM,QAAQ;IAAO;GACnD,SAAS,OAAO;IACd,OAAO;KAAE,IAAI;KAAO,OAAO,UAAU,OAAO,KAAK;IAAE;GACrD;EACF;EACA,iBAAiB,OAAO,SAAS;GAG/B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,KAAK,IAAI,IAAI,IAAI;GACvB,IAAI,CAAC,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC5C,IAAI;IACF,MAAM,SAAS,MAAM,cAAc,KAAK,GAAG,SAAS,KAAK,IAAI;IAC7D,MAAM,OAAO,MAAM,GAAG,KAAK,MAAM;IACjC,IAAI,CAAC,QAAQ,KAAK,SAAS,QAAQ,OAAO;KAAE,IAAI;KAAO,OAAO;IAAQ;IACtE,KAAK,KAAK,QAAQ,KAAA,SAAe,OAAO;KAAE,IAAI;KAAO,OAAO;IAAqB;IACjF,MAAM,UAAU,MAAM,GAAG,SAAS,MAAM;IAExC,MAAM,UAAU,CAAC,IAAG,MADC,SAAS,UAAU,KAAK,GAAG,GAAG,EAAA,CACxB,OAAO,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,KAAK,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE;IAC7H,IAAI,CAAC,QAAQ,QAAQ,OAAO;KAAE,IAAI;KAAM;KAAS,MAAM,QAAQ;KAAQ,OAAO,CAAC;KAAG,UAAU;IAAM;IAClG,MAAM,UAAU,oBAAoB,SAAS,OAAO;IACpD,IAAI,QAAQ,MAAM,UAAU,QAAQ,EAAE,CAAC,WAAW,MAChD,OAAO;KAAE,IAAI;KAAM,SAAS,QAAQ,EAAE,CAAC;KAAQ,MAAM,QAAQ,EAAE,CAAC,OAAO;KAAQ,OAAO,QAAQ;KAAO,UAAU;IAAK;IAEtH,OAAO;KAAE,IAAI;KAAM,SAAS,QAAQ;KAAS,MAAM,QAAQ,QAAQ;KAAQ,OAAO,QAAQ;KAAO,UAAU;IAAM;GACnH,SAAS,OAAO;IACd,OAAO;KAAE,IAAI;KAAO,OAAO,UAAU,OAAO,KAAK;IAAE;GACrD;EACF;EACA,aAAa,OAAO,SAAS;GAC3B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,KAAK,IAAI,IAAI,IAAI;GACvB,IAAI,CAAC,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC5C,IAAI;IACF,MAAM,SAAS,MAAM,cAAc,KAAK,GAAG,SAAS,KAAK,IAAI;IAC7D,MAAM,GAAG,UAAU,QAAQ,KAAK,SAAS,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,GAAG,OAAO,CAAC;IAClF,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;IACnD,IAAI,UAAU;IACd,KAAK,MAAM,OAAO,OAAO,OAAO,GAC9B,IAAI,IAAI,SAAS,KAAK,QAAQ,IAAI,eAAe,MAAM;KAAE,IAAI,aAAa;KAAM,IAAI,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;KAAG,UAAU;IAAK;IAEpI,IAAI,SAAS;KACX,MAAM,OAAqB,CAAC;KAC5B,KAAK,MAAM,OAAO,OAAO,OAAO,GAAG,IAAI,IAAI,SAAS,KAAK,QAAQ,IAAI,YAAY,KAAK,KAAK,GAAG;KAC9F,IAAI,KAAK,QAAQ,MAAM,eAAe,KAAK,GAAG,SAAS,GAAG,KAAK,QAAQ,MAAM,SAAS;UACjF,MAAM,WAAW,KAAK,GAAG,KAAK,QAAQ,GAAG,OAAO;IACvD;IACA,OAAO,EAAE,IAAI,KAAK;GACpB,SAAS,OAAO;IACd,OAAO;KAAE,IAAI;KAAO,OAAO,UAAU,OAAO,KAAK;IAAE;GACrD;EACF;EACA,oBAAoB,OAAO,SAAS;GAClC,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GAEnD,MAAM,UADU,aAAa,MAAM,gBAAgB,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,QAAQ,GAAG,GACtE,CAAC,CAAC,KAAK,MAAM;IACjC,MAAM,OAAO,MAAM,QAAQ,EAAE,OAAO,IAAI,EAAE,UAAU,CAAC;IACrD,MAAM,MAAM,KAAK,QAAQ,GAAG,MAAM;KAChC,MAAM,KAAK,EAAE,WAAW;MAAE,UAAU;MAAG,UAAU;MAAG,SAAS;MAAG,YAAY;KAAM;KAClF,EAAE,YAAY,GAAG,YAAY;KAC7B,EAAE,YAAY,GAAG,YAAY;KAC7B,EAAE,WAAW,GAAG,WAAW;KAC3B,IAAI,GAAG,YAAY,EAAE;KACrB,OAAO;IACT,GAAG;KAAE,UAAU;KAAG,UAAU;KAAG,SAAS;KAAG,YAAY;IAAE,CAAC;IAC1D,OAAO;KAAE,IAAI,EAAE;KAAI,QAAQ,EAAE,UAAU,EAAE;KAAI,MAAM,EAAE;KAAM,OAAO,EAAE,SAAS;KAAM,QAAQ,EAAE,UAAU;KAAM,UAAU,KAAK;KAAQ,SAAS;IAAI;GACnJ,CAAC;GACD,QAAQ,MAAM,GAAG,MAAO,OAAO,EAAE,SAAS,EAAE,IAAI,OAAO,EAAE,SAAS,EAAE,MAAO,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG;GAChG,OAAO;IAAE,IAAI;IAAM;GAAQ;EAC7B;EACA,oBAAoB,OAAO,SAAS;GAClC,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,YAAY,KAAK;GAEvB,OAAO;IAAE,IAAI;IAAM,SADH,aAAa,MAAM,gBAAgB,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC,aAAa,EAAE,SAAS,UACpG;GAAE;EAC7B;EACA,iBAAiB,OAAO,SAAS;GAC/B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GAEnD,IAAI,CADO,IAAI,IAAI,IACb,GAAG,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC5C,MAAM,QAAQ,KAAK;GACnB,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;GACnD,IAAI,WAAyB,CAAC;GAC9B,IAAI,YAA+B;GACnC,IAAI,UAAU,KAAA,GAAW;IACvB,MAAM,MAAM,aAAa,MAAM,gBAAgB,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,QAAQ,GAAG,OAAO,EAAE,SAAS,KAAK,IAAI;IACnH,MAAM,OAAqB,CAAC;IAC5B,KAAK,MAAM,KAAK,KAAK,IAAI,EAAE,UAAU,OAAO,KAAK,MAAM,KAAM,EAAE,WAAW,CAAC,GAAI,KAAK,KAAK,CAA0B;IACnH,IAAI,CAAC,KAAK,QAAQ,OAAO;KAAE,IAAI;KAAO,OAAO;IAAY;IACzD,KAAK,MAAM,GAAG,OAAQ,EAAE,KAAK,GAAG,KAAK,KAAK,CAAE;IAC5C,YAAY,KAAK;IACjB,WAAW;GACb,OAAO;IACL,KAAK,MAAM,KAAK,OAAO,OAAO,GAAG,IAAI,EAAE,SAAS,KAAK,QAAQ,CAAC,EAAE,UAAU,SAAS,KAAK,CAAC;IACzF,IAAI,CAAC,SAAS,QAAQ,OAAO;KAAE,IAAI;KAAO,OAAO;IAAc;IAC/D,SAAS,MAAM,GAAG,OAAQ,EAAE,KAAK,GAAG,KAAK,KAAK,CAAE;IAChD,YAAY,SAAS;GACvB;GACA,MAAM,OAAO,MAAM,YAAY,KAAK,GAAG,SAAS,SAAS;GACzD,IAAI,MAAM,OAAO;IAAE,IAAI;IAAO,OAAO;GAAK;GAC1C,IAAI,UAAU,KAAA,GACZ,MAAM,eAAe,KAAK,GAAG,SAAS,GAAG,KAAK,QAAQ,UAAU,KAAK;QAChE;IAEL,MAAM,UADM,aAAa,MAAM,gBAAgB,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,QAAQ,GAAG,OAAO,EAAE,SAAS,KAAK,QAAQ,EAAE,UAAU,KACjH,CAAC,CAAC,QAAQ,GAAG,MAAM,KAAM,EAAE,WAAW,CAAC,EAAA,CAAG,QAAS,CAAC;IACtE,MAAM,SAAS,OAAO,OAAO,CAAC,GAAG,SAAS,IAAI,EAAE,OAAO,SAAS,EAAE,CAAC,OAAO,SAAS,EAAE,CAAC,OAAO,MAAM,MAAM,gBAAgB,QAAQ,IAAI,CAAC;IACtI,MAAM,qBAAqB,KAAK,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,GAAG,KAAK,YAAY,QAAQ,MAAM,UAAU,KAAK,CAAC,GAAG,GAAG,OAAO;IAElI,MAAM,aAA2B,CAAC;IAClC,KAAK,MAAM,KAAK,OAAO,OAAO,GAAG,IAAI,EAAE,SAAS,KAAK,QAAQ,CAAC,EAAE,UAAU,WAAW,KAAK,CAAC;IAC3F,IAAI,WAAW,QAAQ,MAAM,eAAe,KAAK,GAAG,SAAS,GAAG,KAAK,QAAQ,YAAY,aAAa;GACxG;GACA,OAAO;IAAE,IAAI;IAAM,MAAM,KAAK;IAAM,OAAO,SAAS;GAAK;EAC3D;EACA,cAAc,OAAO,SAAS;GAE5B,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,KAAK,IAAI,IAAI,IAAI;GACvB,MAAM,OAAO,OAAO,KAAK,QAAQ,EAAE;GAEnC,MAAM,QADO,iBAAiB,IAAI,GAAG,GAAG,KAAK,QAAQ,QAAQ,EAAA,CAC3C,KAAK,YAAY;IACjC,IAAI;KACF,MAAM,SAAS,MAAM,GAAG,QAAQ,8BAA8B,EAAE,KAAK,GAAG,IAAI,CAAC;KAC7E,MAAM,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,CAAC,YAAY,EAAE;KACpD,MAAM,wBAAO,IAAI,KAAK,EAAA,CAAE,YAAY,IAAI,MAAM,OAAO;KACrD,MAAM,GAAG,UAAU,SAAS,OAAO,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG,SAAS,KAAK,GAAG,OAAO,CAAC;IAC1F,SAAS,GAAG,CAAgB;GAC9B,CAAC;GACD,iBAAiB,IAAI,GAAG,KAAK,IAAI;GACjC,MAAM;GACN,QAAQ,MAAM,kBAAkB,IAAI;GACpC,OAAO,EAAE,IAAI,KAAK;EACpB;EACA,oBAAoB,OAAO,SAAS;GAClC,MAAM,KAAK,MAAM,eAAe,KAAK,KAAK,SAAS;GACnD,IAAI,SAAS,IAAI,OAAO;IAAE,IAAI;IAAO,OAAO,GAAG;GAAI;GACnD,MAAM,QAAQ,OAAO,KAAK,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY;GAC1D,MAAM,QAAkB,CAAC;GACzB,IAAI,MAAM,UAAU,GAAG;IACrB,MAAM,SAAS,MAAM,SAAS,UAAU,KAAK,GAAG,GAAG;IACnD,MAAM,uBAAO,IAAI,IAAY;IAE7B,KAAK,MAAM,OAAO,OAAO,OAAO,GAAG,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI;IAClE,MAAM,SAAS,MAAM,mBAAmB,KAAK,GAAG,SAAS,GAAG,GAAG;IAC/D,IAAI,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK,IAAI,CAAC;IAC9C,MAAM,SAAS,MAAsB;KACnC,MAAM,KAAK,EAAE,YAAY;KAEzB,KADa,GAAG,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,GAAA,CAC/B,SAAS,KAAK,GAAG,OAAO;KACjC,IAAI,GAAG,SAAS,KAAK,GAAG,OAAO;KAC/B,OAAO;IACT;IACA,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,KAAK,CAAC;IACjD,IAAI,MAAM,GAAG,MAAO,MAAM,CAAC,IAAI,MAAM,CAAC,MAAO,IAAI,IAAI,KAAK,EAAE;IAC5D,MAAM,KAAK,GAAG,IAAI,MAAM,GAAG,EAAE,CAAC;GAChC;GACA,OAAO;IAAE,IAAI;IAAM;IAAO,WAAW,MAAM,UAAU;GAAG;EAC1D;CACF;AACF;;;;;AAMA,eAAsB,UACpB,KACA,UACA,QACA,MACuB;CAEvB,MAAM,UADW,cAAc,KAAK,QACb,CAAC,CAAC;CACzB,IAAI,CAAC,SAAS,OAAO;EAAE,IAAI;EAAO,OAAO,WAAW,OAAO,MAAM;CAAE;CACnE,OAAO,QAAQ,IAAI;AACrB;;;;;;;;;;ACvRA,MAAa,OAAO;AACpB,MAAa,SAAS;CAAC;CAAY;CAAM;AAAW;;;;;;;AAQpD,SAAgB,MAAM,KAAU,QAAwB;CACtD,MAAM,2BAAqB,IAAI,IAAI;CAEnC,IAAI,GAAG,iBAAiB,MAAe,WAAoB;EACzD,kBAAuB,KAAK,UAAU,MAAM,MAAM;CACpD,CAAC;CAED,IAAI,GAAG,qBAAqB,YAAqB;EAC/C,MAAM,MAAM,MAAM,OAAgB;EAClC,IAAI,KAAK;GACP,SAAS,OAAO,GAAG;GACnB,cAAc,GAAG;EACnB;CACF,CAAC;CAED,eAAe,KAAK,SAAS,QAAQ,SAAS,UAAU,KAAK,UAAU,QAAQ,IAAI,CAAC;CAEpF,IAAI,QAAQ,OAAO,6CAA0C;AAC/D"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "dsh-vscode-mode",
3
+ "version": "0.1.1",
4
+ "description": "DSH 上的类 VSCode 编码体验:Monaco 中央编辑器(文件页签/QuickOpen/状态栏)+ Agent 编辑差异审查(整文件差异/采纳/拒绝/归档/回滚),状态持久化到工作区旁车",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": "^22.19.0 || >=24.0.0"
8
+ },
9
+ "packageManager": "pnpm@11.3.0",
10
+ "main": "./lib/index.js",
11
+ "files": [
12
+ "lib",
13
+ "assets",
14
+ "src",
15
+ "cordis.patch.yml"
16
+ ],
17
+ "license": "BSD-3-Clause",
18
+ "peerDependencies": {
19
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.0.1-rc <2",
20
+ "@deepseek-ai/dsh-llm": ">=0.0.1-rc <2",
21
+ "@deepseek-ai/dsh-tools": ">=0.0.1-rc <2",
22
+ "cordis": ">=4.0.0-rc <5",
23
+ "react": "^18.2.0",
24
+ "schemastery": "^3.18.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^24.13.3",
28
+ "@types/react": "^18.3.1",
29
+ "react": "^18.3.1",
30
+ "tsdown": "^0.22.14",
31
+ "typescript": "^5.9.0",
32
+ "vitest": "^3.2.4"
33
+ },
34
+ "scripts": {
35
+ "build": "tsdown",
36
+ "build:client": "tsdown",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit",
38
+ "test": "vitest run",
39
+ "prebuild": "node -e \"fs.rmSync('lib',{recursive:true,force:true})\"",
40
+ "prepare": "npm run prebuild && npm run build",
41
+ "pack": "npm run prebuild && npm run build && npm pack"
42
+ },
43
+ "exports": {
44
+ ".": "./lib/index.js",
45
+ "./client": "./lib/client.js",
46
+ "./package.json": "./package.json"
47
+ },
48
+ "dsh": {
49
+ "bundle": {
50
+ "patch": "./cordis.patch.yml"
51
+ },
52
+ "client": {
53
+ "inject": [
54
+ "@deepseek-ai/dsh-client-runtime",
55
+ "@deepseek-ai/dsh-client-ui-slots"
56
+ ],
57
+ "platform": "web"
58
+ }
59
+ }
60
+ }
package/src/capture.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * dsh-vscode-mode host — 捕获层:监听 tools/result,把 edit/write 差异落成审查记录。
3
+ * 迁移自原 src/index.ts 的 tools/result 处理,语义不改。
4
+ * 作者 ddj 2026-08-20
5
+ */
6
+ import type { DiffRecord } from './shared/types.js'
7
+ import type { Ctx, Session } from './store.js'
8
+ import { archiveRecords, loadBucket, saveBucket } from './store.js'
9
+ import { fileMaxBatch, prune, recordResolved } from './model.js'
10
+ import type { Registry } from './registry.js'
11
+ import { cwdOf } from './registry.js'
12
+
13
+ /**
14
+ * 捕获一次工具执行结果(tools/result):edit/write 成功时构造记录、
15
+ * 递增文件批次、融合归档被后续修改取代的旧差异、落盘。
16
+ * @author ddj 2026年08月20号
17
+ * @param ctx DSH 上下文
18
+ * @param registry 工作区记录桶注册表
19
+ * @param exec 工具执行描述(name/arguments/callId/agent.session)
20
+ * @param result 执行结果(value/meta/isError)
21
+ */
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ export async function captureToolResult(ctx: Ctx, registry: Registry, exec: any, result: any): Promise<void> {
24
+ const session: Session | undefined = exec?.agent?.session
25
+ if (!session || (exec?.name !== 'edit' && exec?.name !== 'write')) return
26
+ if (result?.isError || !result?.value) return
27
+ try {
28
+ const cwd = cwdOf(session)
29
+ if (!cwd) return
30
+ const value = result.value
31
+ const args = exec.arguments || {}
32
+ const path = typeof value.path === 'string' ? value.path : args.file_path
33
+ if (!path) return
34
+ const metaDiffs: DiffRecord['hunks'] = Array.isArray(result.meta?.diffs) ? result.meta.diffs : []
35
+ const before = typeof value.before === 'string' ? value.before : null
36
+ const create = exec.name === 'write' && value.before === null
37
+ const callHunk = exec.name === 'edit' && typeof args.old_string === 'string' ? { oldText: args.old_string, newText: args.new_string } : null
38
+ const synthHunk = create ? { oldText: null as string | null, newText: typeof args.content === 'string' ? args.content : (typeof value.after === 'string' ? value.after : '') } : null
39
+ const hunks = metaDiffs.length ? metaDiffs : (synthHunk ? [synthHunk] : (callHunk ? [callHunk] : []))
40
+ if (!hunks.length) return
41
+ const record: DiffRecord = {
42
+ callId: exec.callId,
43
+ toolName: exec.name,
44
+ path,
45
+ before,
46
+ create,
47
+ callHunk,
48
+ hunks,
49
+ decisions: { call: 'pending', perHunk: hunks.map(() => 'pending') },
50
+ note: create ? '新建文件:全部拒绝将删除该文件' : before === null ? '未捕获修改前内容(大文件)' : null,
51
+ superseded: false,
52
+ archived: false,
53
+ batch: 0,
54
+ at: new Date().toISOString(),
55
+ }
56
+ let bucket = registry.get(cwd)
57
+ if (!bucket) { bucket = await loadBucket(ctx, cwd); registry.set(cwd, bucket) }
58
+ record.batch = fileMaxBatch(bucket, path) + 1
59
+ bucket.set(exec.callId, record)
60
+ // 融合:文件被再次修改(batch 递增)时,早于最新批次的未归档差异一律归档(内容已含其效果/被取代)
61
+ const prior: DiffRecord[] = []
62
+ for (const r of bucket.values()) {
63
+ if (r.path === path && r.callId !== exec.callId && !r.archived && (r.batch ?? 0) < record.batch) prior.push(r)
64
+ }
65
+ if (prior.length) {
66
+ await archiveRecords(ctx, session, cwd, bucket, prior, prior.every(recordResolved) ? '已处理且被后续修改取代' : '被后续修改融合(内容已含其效果)')
67
+ }
68
+ prune(bucket)
69
+ await saveBucket(ctx, cwd, bucket, session)
70
+ } catch (error) {
71
+ console.error('edrv capture failed', error)
72
+ }
73
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * dsh-vscode-mode client — 跨组件/跨 slot 的窗口事件助手。
3
+ * 迁移自原 src/client/index.ts 的 openEditorView 与事件派发,语义不改。
4
+ * 作者 ddj 2026-08-20
5
+ */
6
+
7
+ /**
8
+ * 打开中央「文件编辑」页签:点击 shell 会话头部的视图页签(DOM 级,无需 store actions)。
9
+ * @author ddj 2026年08月20号
10
+ * @param path 要打开的路径(可空)
11
+ */
12
+ export function openEditorView(path: string | null): void {
13
+ const tabs = Array.from(document.querySelectorAll('div[role="tablist"] button[role="tab"]'))
14
+ for (const b of tabs) {
15
+ if (b.textContent && b.textContent.includes('文件编辑')) { (b as HTMLButtonElement).click(); break }
16
+ }
17
+ const p = path ?? null
18
+ setTimeout(() => {
19
+ window.dispatchEvent(new CustomEvent('edrv:open-editor', { detail: { path: p } }))
20
+ }, 80)
21
+ }
22
+
23
+ /** 差异状态变化:触发角标/DiffBox 重拉。 */
24
+ export function emitRefresh(): void {
25
+ window.dispatchEvent(new CustomEvent('edrv:refresh'))
26
+ }
27
+
28
+ /** 打开指定路径到编辑区页签。 */
29
+ export function emitOpenEditor(path: string): void {
30
+ window.dispatchEvent(new CustomEvent('edrv:open-editor', { detail: { path } }))
31
+ }
32
+
33
+ /** 拉起 DiffLauncher。 */
34
+ export function emitShowLauncher(): void {
35
+ window.dispatchEvent(new CustomEvent('edrv:show-launcher'))
36
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * dsh-vscode-mode client — 浏览器半入口:slot 注册 + 装配。
3
+ * 挂点:conversation.view「文件编辑」页签(中央 Monaco 编辑器)+ header 差异角标。
4
+ * 与 Host 通信:同源 fetch('/edrv/rpc')(shared/rpc 契约)。
5
+ * 作者 ddj 2026-08-20
6
+ */
7
+ import React from 'react'
8
+ import './styles/editor.css'
9
+ import { EditorView } from './ui/EditorView.js'
10
+ import { DiffBadge } from './ui/DiffBadge.js'
11
+
12
+ export const inject = ['slots', 'timer']
13
+
14
+ /**
15
+ * 装配客户端:注册中央编辑区视图与 header 差异角标。
16
+ * @author ddj 2026年08月20号
17
+ * @param ctx 客户端根上下文(slots + timer 服务)
18
+ */
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ export function apply(ctx: any): void {
21
+ const schedule = (fn: () => void, ms: number) => ctx.timeout(fn, ms)
22
+
23
+ // 中央「文件编辑」页签:类 VSCode 编辑器(顶部=文件页签+搜索框,差异 UI=文件底部圆角悬浮框)
24
+ ctx.slots.register({
25
+ name: 'conversation.view',
26
+ id: 'edrv-editor',
27
+ order: 5,
28
+ label: '文件编辑',
29
+ inject: (sessionId: string) => ({ sessionId }),
30
+ }, (props: unknown) => React.createElement(EditorView, Object.assign({}, props, { schedule })))
31
+
32
+ // header 差异角标:仅当前工作区存在差异时渲染
33
+ ctx.slots.register(
34
+ { name: 'conversation.session.header.utilities', id: 'edrv-diff-badge', order: 90, label: '差异' },
35
+ (props: unknown) => React.createElement(DiffBadge, Object.assign({}, props)),
36
+ )
37
+ }
@@ -0,0 +1,162 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * dsh-vscode-mode client — 行内差异自绘(新增行绿底 + glyph margin '+';删除块 view zone 红底)。
4
+ * 迁移自原 src/client/index.ts 的 diff-render effect,语义不改。
5
+ * 作者 ddj 2026-08-20
6
+ */
7
+
8
+ /**
9
+ * 差异渲染器(每 EditorView 挂载一个,内部持有 zone/decoration 状态)。
10
+ * @param log 诊断日志函数((sessionId, text) => void)
11
+ */
12
+ export function createDiffRenderer(log) {
13
+ let viewZoneIds = []
14
+ let decorations = []
15
+
16
+ /**
17
+ * 渲染当前 pending 差异:绿底 decoration + 删除块 view zones + '-' 号 overlay(滚动同步)。
18
+ * @param monaco window.monaco
19
+ * @param editor Monaco 编辑器实例
20
+ * @param pendingRegions 待处理差异区域
21
+ * @param sessionId 会话 id
22
+ */
23
+ const render = (monaco, editor, pendingRegions, sessionId) => {
24
+ const renderT0 = Date.now()
25
+ const callIdAttr = (callId, idx) => String(callId) + ':' + String(idx)
26
+ log(sessionId, '[diff-render] begin regs=' + pendingRegions.length + ' ' + pendingRegions.map((r) => callIdAttr(r.callId, r.idx) + '@' + (r.start ?? '?') + '-' + (r.end ?? '?') + '(-' + (r.oldLines ? r.oldLines.length : 0) + '/+' + (r.newLines ? r.newLines.length : 0) + ')').join('|'))
27
+
28
+ const decos = []
29
+ for (const r of pendingRegions) {
30
+ if (r.start === undefined || r.end === undefined) continue
31
+ if (!r.create && r.newLines && r.newLines.length) {
32
+ decos.push({
33
+ range: new monaco.Range(r.start, 1, Math.max(r.start, r.end - 1), 1),
34
+ options: { isWholeLine: true, className: 'edrv-mn-add-line', linesDecorationsClassName: 'edrv-mn-gutter-add' },
35
+ })
36
+ }
37
+ }
38
+ decorations = editor.deltaDecorations(decorations, decos)
39
+
40
+ // 删除块 view zones(红底 + 正文;- 号由独立 overlay 层渲染,定位在 decoration 列与 + 同列,
41
+ // 不受 view zone 容器定位/裁剪影响;滚动用 translateY 同步)
42
+ let createdZones = []
43
+ editor.changeViewZones((accessor) => {
44
+ for (const id of viewZoneIds) { try { accessor.removeZone(id) } catch (e) { /* 已移除 */ } }
45
+ viewZoneIds = []
46
+ const zones = []
47
+ for (const r of pendingRegions) {
48
+ if (r.create) continue
49
+ const oldLines = r.oldLines && r.oldLines.length ? r.oldLines : null
50
+ if (!oldLines) continue
51
+ const after = Math.max(0, (r.start ?? 1) - 1)
52
+ const domNode = document.createElement('div')
53
+ domNode.className = 'edrv-del-zone'
54
+ domNode.dataset.edrvHunk = callIdAttr(r.callId, r.idx)
55
+ for (const t of oldLines) {
56
+ const row = document.createElement('div')
57
+ row.className = 'edrv-del-row'
58
+ const text = document.createElement('span')
59
+ text.className = 'edrv-del-text'
60
+ text.textContent = t
61
+ row.appendChild(text)
62
+ domNode.appendChild(row)
63
+ }
64
+ const id = accessor.addZone({
65
+ afterLineNumber: after,
66
+ heightInLines: oldLines.length,
67
+ domNode,
68
+ suppressMouseDown: false,
69
+ })
70
+ viewZoneIds.push(id)
71
+ zones.push({ domNode, after, n: oldLines.length })
72
+ }
73
+ createdZones = zones
74
+ })
75
+
76
+ if (createdZones.length) {
77
+ const root = editor.getDomNode()
78
+ if (root) {
79
+ let overlay = root.querySelector('.edrv-minus-overlay')
80
+ if (!overlay) {
81
+ overlay = document.createElement('div')
82
+ overlay.className = 'edrv-minus-overlay'
83
+ root.appendChild(overlay)
84
+ }
85
+ overlay.innerHTML = ''
86
+ const lineH = editor.getOption(monaco.editor.EditorOption.lineHeight) || 20
87
+ let li = null
88
+ try { li = editor.getLayoutInfo() } catch (e) { /* ignore */ }
89
+ const left = li ? li.decorationsLeft : 0
90
+ const width = li && li.decorationsWidth > 0 ? li.decorationsWidth : 16
91
+ const lineCount = editor.getModel().getLineCount()
92
+ let itemIdx = 0
93
+ let zi = 0
94
+ for (const z of createdZones) {
95
+ // 用 Monaco 坐标 API 计算 view zone 顶部,避免离屏 zone DOM 未布局导致 getBoundingClientRect 为 0
96
+ const anchor = Math.min(z.after + 1, lineCount)
97
+ let zoneBottom = editor.getTopForLineNumber(anchor)
98
+ if (z.after >= lineCount) zoneBottom += lineH
99
+ const zoneTop = zoneBottom - z.n * lineH
100
+ for (let i = 0; i < z.n; i++) {
101
+ const item = document.createElement('div')
102
+ item.className = 'edrv-minus-item'
103
+ item.textContent = '-'
104
+ item.style.width = width + 'px'
105
+ item.style.height = lineH + 'px'
106
+ item.dataset.zone = String(zi)
107
+ item.dataset.row = String(i)
108
+ item.style.top = (zoneTop + i * lineH) + 'px'
109
+ item.style.left = left + 'px'
110
+ overlay.appendChild(item)
111
+ itemIdx++
112
+ }
113
+ zi++
114
+ }
115
+ log(sessionId, '[diff-render] placed zones=' + createdZones.length + ' items=' + itemIdx + ' left=' + left + ' w=' + width + ' t+' + (Date.now() - renderT0) + 'ms')
116
+ // 滚动同步:overlay 随内容滚动(内容坐标 - scrollTop)
117
+ const syncScroll = () => {
118
+ const s2 = editor.getScrollTop() || 0
119
+ if (overlay) overlay.style.transform = 'translateY(' + (-s2) + 'px)'
120
+ }
121
+ syncScroll()
122
+ overlay.__edrvSync = syncScroll
123
+ if (!overlay.__edrvBound) {
124
+ overlay.__edrvBound = true
125
+ editor.onDidScrollChange(syncScroll)
126
+ }
127
+ // 已可见的 zone 用真实 DOM 坐标做一次微调(离屏 zone 仍保留坐标 API 位置)
128
+ setTimeout(() => {
129
+ try {
130
+ const edRect = root.getBoundingClientRect()
131
+ const st = editor.getScrollTop() || 0
132
+ const items = overlay.querySelectorAll('.edrv-minus-item')
133
+ for (const item of items) {
134
+ const zIndex = Number(item.dataset.zone)
135
+ const rIndex = Number(item.dataset.row)
136
+ const z = createdZones[zIndex]
137
+ if (!z || !z.domNode.isConnected) continue
138
+ const rowEl = z.domNode.querySelectorAll('.edrv-del-row')[rIndex]
139
+ if (!rowEl) continue
140
+ const rowRect = rowEl.getBoundingClientRect()
141
+ if (rowRect.height > 0) {
142
+ item.style.top = (rowRect.top - edRect.top + st) + 'px'
143
+ }
144
+ }
145
+ } catch (e) { log(sessionId, '[diff-render] correct fail ' + String(e)) }
146
+ }, 50)
147
+ }
148
+ } else {
149
+ const root = editor.getDomNode()
150
+ const overlay = root && root.querySelector('.edrv-minus-overlay')
151
+ if (overlay) overlay.innerHTML = ''
152
+ }
153
+ }
154
+
155
+ /** 卸载清理(EditorView unmount 时调用)。 */
156
+ const dispose = () => {
157
+ viewZoneIds = []
158
+ decorations = []
159
+ }
160
+
161
+ return { render, dispose }
162
+ }