aicodeman 1.34.0 → 1.40.0

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 (299) hide show
  1. package/README.md +11 -0
  2. package/README.zh-CN.md +8 -0
  3. package/dist/attachment-registry.d.ts +6 -0
  4. package/dist/attachment-registry.d.ts.map +1 -1
  5. package/dist/attachment-registry.js +9 -3
  6. package/dist/attachment-registry.js.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +2 -2
  9. package/dist/cli.js.map +1 -1
  10. package/dist/config/cli-registry/patterns.d.ts +6 -0
  11. package/dist/config/cli-registry/patterns.d.ts.map +1 -1
  12. package/dist/config/cli-registry/patterns.js +13 -0
  13. package/dist/config/cli-registry/patterns.js.map +1 -1
  14. package/dist/config/cli-registry/schema.d.ts +13 -0
  15. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  16. package/dist/config/cli-registry/schema.js +60 -2
  17. package/dist/config/cli-registry/schema.js.map +1 -1
  18. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  19. package/dist/config/cli-registry/stock.js +175 -7
  20. package/dist/config/cli-registry/stock.js.map +1 -1
  21. package/dist/config/cli-registry/types.d.ts +93 -6
  22. package/dist/config/cli-registry/types.d.ts.map +1 -1
  23. package/dist/config/dependency-registry.d.ts +7 -0
  24. package/dist/config/dependency-registry.d.ts.map +1 -1
  25. package/dist/config/dependency-registry.js +15 -0
  26. package/dist/config/dependency-registry.js.map +1 -1
  27. package/dist/config/path-probe.d.ts +37 -0
  28. package/dist/config/path-probe.d.ts.map +1 -0
  29. package/dist/config/path-probe.js +43 -0
  30. package/dist/config/path-probe.js.map +1 -0
  31. package/dist/deepseek-route-config.d.ts +110 -0
  32. package/dist/deepseek-route-config.d.ts.map +1 -0
  33. package/dist/deepseek-route-config.js +477 -0
  34. package/dist/deepseek-route-config.js.map +1 -0
  35. package/dist/git-workspace-status.d.ts +246 -0
  36. package/dist/git-workspace-status.d.ts.map +1 -0
  37. package/dist/git-workspace-status.js +626 -0
  38. package/dist/git-workspace-status.js.map +1 -0
  39. package/dist/hooks-config.d.ts.map +1 -1
  40. package/dist/hooks-config.js +83 -13
  41. package/dist/hooks-config.js.map +1 -1
  42. package/dist/model-config-resolvers.d.ts +29 -0
  43. package/dist/model-config-resolvers.d.ts.map +1 -0
  44. package/dist/model-config-resolvers.js +34 -0
  45. package/dist/model-config-resolvers.js.map +1 -0
  46. package/dist/session-display-model.d.ts +110 -0
  47. package/dist/session-display-model.d.ts.map +1 -0
  48. package/dist/session-display-model.js +154 -0
  49. package/dist/session-display-model.js.map +1 -0
  50. package/dist/session.d.ts +145 -8
  51. package/dist/session.d.ts.map +1 -1
  52. package/dist/session.js +280 -35
  53. package/dist/session.js.map +1 -1
  54. package/dist/types/api.d.ts +7 -0
  55. package/dist/types/api.d.ts.map +1 -1
  56. package/dist/types/api.js.map +1 -1
  57. package/dist/types/session.d.ts +28 -1
  58. package/dist/types/session.d.ts.map +1 -1
  59. package/dist/types/session.js.map +1 -1
  60. package/dist/types/tools.d.ts +1 -1
  61. package/dist/types/tools.d.ts.map +1 -1
  62. package/dist/utils/bounded-path-probe.d.ts +99 -0
  63. package/dist/utils/bounded-path-probe.d.ts.map +1 -0
  64. package/dist/utils/bounded-path-probe.js +228 -0
  65. package/dist/utils/bounded-path-probe.js.map +1 -0
  66. package/dist/utils/cli-executable-resolver.d.ts +2 -0
  67. package/dist/utils/cli-executable-resolver.d.ts.map +1 -1
  68. package/dist/utils/cli-executable-resolver.js +2 -1
  69. package/dist/utils/cli-executable-resolver.js.map +1 -1
  70. package/dist/utils/deepseek-cli-resolver.d.ts +8 -0
  71. package/dist/utils/deepseek-cli-resolver.d.ts.map +1 -1
  72. package/dist/utils/deepseek-cli-resolver.js +18 -2
  73. package/dist/utils/deepseek-cli-resolver.js.map +1 -1
  74. package/dist/utils/dependency-checker.d.ts +2 -0
  75. package/dist/utils/dependency-checker.d.ts.map +1 -1
  76. package/dist/utils/dependency-checker.js +37 -9
  77. package/dist/utils/dependency-checker.js.map +1 -1
  78. package/dist/utils/index.d.ts +2 -0
  79. package/dist/utils/index.d.ts.map +1 -1
  80. package/dist/utils/index.js +1 -0
  81. package/dist/utils/index.js.map +1 -1
  82. package/dist/web/case-path.d.ts +58 -0
  83. package/dist/web/case-path.d.ts.map +1 -0
  84. package/dist/web/case-path.js +182 -0
  85. package/dist/web/case-path.js.map +1 -0
  86. package/dist/web/launch-defaults.d.ts +22 -0
  87. package/dist/web/launch-defaults.d.ts.map +1 -0
  88. package/dist/web/launch-defaults.js +46 -0
  89. package/dist/web/launch-defaults.js.map +1 -0
  90. package/dist/web/public/admin-ui.js.gz +0 -0
  91. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  92. package/dist/web/public/app.abadc970.js +43 -0
  93. package/dist/web/public/app.abadc970.js.br +0 -0
  94. package/dist/web/public/app.abadc970.js.gz +0 -0
  95. package/dist/web/public/approvals-ui.js.gz +0 -0
  96. package/dist/web/public/{constants.d95fade9.js → constants.c0f8f9de.js} +1009 -127
  97. package/dist/web/public/constants.c0f8f9de.js.br +0 -0
  98. package/dist/web/public/constants.c0f8f9de.js.gz +0 -0
  99. package/dist/web/public/cron-ui.js.gz +0 -0
  100. package/dist/web/public/entrance-animations.js +1 -0
  101. package/dist/web/public/entrance-animations.js.br +0 -0
  102. package/dist/web/public/entrance-animations.js.gz +0 -0
  103. package/dist/web/public/git-status-ui.js +719 -0
  104. package/dist/web/public/git-status-ui.js.br +0 -0
  105. package/dist/web/public/git-status-ui.js.gz +0 -0
  106. package/dist/web/public/home-sessions.js +12 -9
  107. package/dist/web/public/home-sessions.js.br +0 -0
  108. package/dist/web/public/home-sessions.js.gz +0 -0
  109. package/dist/web/public/host-wake-ui.js.gz +0 -0
  110. package/dist/web/public/i18n.a31747a9.js +2 -0
  111. package/dist/web/public/i18n.a31747a9.js.br +0 -0
  112. package/dist/web/public/i18n.a31747a9.js.gz +0 -0
  113. package/dist/web/public/{image-input.a216cf9e.js → image-input.898a538b.js} +18 -8
  114. package/dist/web/public/image-input.898a538b.js.br +0 -0
  115. package/dist/web/public/image-input.898a538b.js.gz +0 -0
  116. package/dist/web/public/index.html +205 -42
  117. package/dist/web/public/index.html.br +0 -0
  118. package/dist/web/public/index.html.gz +0 -0
  119. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  120. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.gz +0 -0
  121. package/dist/web/public/{mobile-handlers.23a85db1.js → mobile-handlers.0ef9c311.js} +20 -0
  122. package/dist/web/public/mobile-handlers.0ef9c311.js.br +0 -0
  123. package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
  124. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  125. package/dist/web/public/mobile-overview.js.gz +0 -0
  126. package/dist/web/public/mobile.111b187d.css +1 -0
  127. package/dist/web/public/mobile.111b187d.css.br +0 -0
  128. package/dist/web/public/mobile.111b187d.css.gz +0 -0
  129. package/dist/web/public/notification-manager.50bb87d8.js.gz +0 -0
  130. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  131. package/dist/web/public/{panels-ui.6a5898d9.js → panels-ui.4735dfc2.js} +4 -4
  132. package/dist/web/public/panels-ui.4735dfc2.js.br +0 -0
  133. package/dist/web/public/{panels-ui.6a5898d9.js.gz → panels-ui.4735dfc2.js.gz} +0 -0
  134. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  135. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  136. package/dist/web/public/readmymind-ui.js.gz +0 -0
  137. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  138. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  139. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  140. package/dist/web/public/session-lineage.js +229 -86
  141. package/dist/web/public/session-lineage.js.br +0 -0
  142. package/dist/web/public/session-lineage.js.gz +0 -0
  143. package/dist/web/public/session-ui.f731602c.js +100 -0
  144. package/dist/web/public/session-ui.f731602c.js.br +0 -0
  145. package/dist/web/public/session-ui.f731602c.js.gz +0 -0
  146. package/dist/web/public/settings-ui.a97ab16f.js +97 -0
  147. package/dist/web/public/settings-ui.a97ab16f.js.br +0 -0
  148. package/dist/web/public/settings-ui.a97ab16f.js.gz +0 -0
  149. package/dist/web/public/spreadsheet-preview-worker.js +290 -0
  150. package/dist/web/public/spreadsheet-preview-worker.js.br +0 -0
  151. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  152. package/dist/web/public/spreadsheet-preview.af82fa2f.js +555 -0
  153. package/dist/web/public/spreadsheet-preview.af82fa2f.js.br +0 -0
  154. package/dist/web/public/spreadsheet-preview.af82fa2f.js.gz +0 -0
  155. package/dist/web/public/spreadsheet-xlsx-core.js +1006 -0
  156. package/dist/web/public/spreadsheet-xlsx-core.js.br +0 -0
  157. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  158. package/dist/web/public/styles.8ee12666.css +1 -0
  159. package/dist/web/public/styles.8ee12666.css.br +0 -0
  160. package/dist/web/public/styles.8ee12666.css.gz +0 -0
  161. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  162. package/dist/web/public/sw.js +2 -2
  163. package/dist/web/public/sw.js.br +0 -0
  164. package/dist/web/public/sw.js.gz +0 -0
  165. package/dist/web/public/tab-layout-browser.065fcba4.js +1 -0
  166. package/dist/web/public/tab-layout-browser.065fcba4.js.br +0 -0
  167. package/dist/web/public/tab-layout-browser.065fcba4.js.gz +0 -0
  168. package/dist/web/public/{tab-rail-resize.dcdc5772.js → tab-rail-resize.a5867793.js} +1 -1
  169. package/dist/web/public/tab-rail-resize.a5867793.js.br +0 -0
  170. package/dist/web/public/tab-rail-resize.a5867793.js.gz +0 -0
  171. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js +1 -0
  172. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.br +0 -0
  173. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  174. package/dist/web/public/terminal-split.js +146 -649
  175. package/dist/web/public/terminal-split.js.br +0 -0
  176. package/dist/web/public/terminal-split.js.gz +0 -0
  177. package/dist/web/public/terminal-tile.js +1611 -0
  178. package/dist/web/public/terminal-tile.js.br +0 -0
  179. package/dist/web/public/terminal-tile.js.gz +0 -0
  180. package/dist/web/public/terminal-ui.5059b30e.js +2 -0
  181. package/dist/web/public/terminal-ui.5059b30e.js.br +0 -0
  182. package/dist/web/public/terminal-ui.5059b30e.js.gz +0 -0
  183. package/dist/web/public/tile-grid.js +2684 -0
  184. package/dist/web/public/tile-grid.js.br +0 -0
  185. package/dist/web/public/tile-grid.js.gz +0 -0
  186. package/dist/web/public/ultracode-panel.js.gz +0 -0
  187. package/dist/web/public/ultracode-windows.js.gz +0 -0
  188. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  189. package/dist/web/public/vendor/exceljs.min.js +44 -0
  190. package/dist/web/public/vendor/exceljs.min.js.br +0 -0
  191. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  192. package/dist/web/public/vendor/fflate.min.js +1 -0
  193. package/dist/web/public/vendor/fflate.min.js.br +0 -0
  194. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  195. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  196. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  197. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  198. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  199. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  200. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  201. package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js.gz +0 -0
  202. package/dist/web/public/vendor/xterm.css.gz +0 -0
  203. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  204. package/dist/web/public/{voice-input.c4b51eb6.js → voice-input.2342c37b.js} +64 -10
  205. package/dist/web/public/voice-input.2342c37b.js.br +0 -0
  206. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  207. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  208. package/dist/web/public/webview-tabs.js +9 -1
  209. package/dist/web/public/webview-tabs.js.br +0 -0
  210. package/dist/web/public/webview-tabs.js.gz +0 -0
  211. package/dist/web/routes/case-routes.d.ts.map +1 -1
  212. package/dist/web/routes/case-routes.js +136 -18
  213. package/dist/web/routes/case-routes.js.map +1 -1
  214. package/dist/web/routes/cli-registry-routes.d.ts.map +1 -1
  215. package/dist/web/routes/cli-registry-routes.js +3 -1
  216. package/dist/web/routes/cli-registry-routes.js.map +1 -1
  217. package/dist/web/routes/doctor-routes.d.ts +23 -0
  218. package/dist/web/routes/doctor-routes.d.ts.map +1 -0
  219. package/dist/web/routes/doctor-routes.js +83 -0
  220. package/dist/web/routes/doctor-routes.js.map +1 -0
  221. package/dist/web/routes/file-routes.d.ts +7 -0
  222. package/dist/web/routes/file-routes.d.ts.map +1 -1
  223. package/dist/web/routes/file-routes.js +34 -4
  224. package/dist/web/routes/file-routes.js.map +1 -1
  225. package/dist/web/routes/git-status-routes.d.ts +16 -0
  226. package/dist/web/routes/git-status-routes.d.ts.map +1 -0
  227. package/dist/web/routes/git-status-routes.js +98 -0
  228. package/dist/web/routes/git-status-routes.js.map +1 -0
  229. package/dist/web/routes/index.d.ts +2 -0
  230. package/dist/web/routes/index.d.ts.map +1 -1
  231. package/dist/web/routes/index.js +2 -0
  232. package/dist/web/routes/index.js.map +1 -1
  233. package/dist/web/routes/session-routes.d.ts +18 -0
  234. package/dist/web/routes/session-routes.d.ts.map +1 -1
  235. package/dist/web/routes/session-routes.js +106 -42
  236. package/dist/web/routes/session-routes.js.map +1 -1
  237. package/dist/web/routes/status-telemetry-routes.d.ts +3 -0
  238. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  239. package/dist/web/routes/status-telemetry-routes.js +12 -0
  240. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  241. package/dist/web/routes/system-routes.d.ts.map +1 -1
  242. package/dist/web/routes/system-routes.js +13 -0
  243. package/dist/web/routes/system-routes.js.map +1 -1
  244. package/dist/web/schemas.d.ts +28 -0
  245. package/dist/web/schemas.d.ts.map +1 -1
  246. package/dist/web/schemas.js +41 -0
  247. package/dist/web/schemas.js.map +1 -1
  248. package/dist/web/server.d.ts +5 -0
  249. package/dist/web/server.d.ts.map +1 -1
  250. package/dist/web/server.js +35 -12
  251. package/dist/web/server.js.map +1 -1
  252. package/dist/web/session-listener-wiring.d.ts +1 -0
  253. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  254. package/dist/web/session-listener-wiring.js +11 -0
  255. package/dist/web/session-listener-wiring.js.map +1 -1
  256. package/package.json +3 -1
  257. package/scripts/postinstall.js +16 -0
  258. package/skills/codeman/reference/verbs.md +3 -0
  259. package/dist/web/public/app.cf0db8ce.js +0 -43
  260. package/dist/web/public/app.cf0db8ce.js.br +0 -0
  261. package/dist/web/public/app.cf0db8ce.js.gz +0 -0
  262. package/dist/web/public/constants.d95fade9.js.br +0 -0
  263. package/dist/web/public/constants.d95fade9.js.gz +0 -0
  264. package/dist/web/public/i18n.398b8331.js +0 -1
  265. package/dist/web/public/i18n.398b8331.js.br +0 -0
  266. package/dist/web/public/i18n.398b8331.js.gz +0 -0
  267. package/dist/web/public/image-input.a216cf9e.js.br +0 -0
  268. package/dist/web/public/image-input.a216cf9e.js.gz +0 -0
  269. package/dist/web/public/mobile-handlers.23a85db1.js.br +0 -0
  270. package/dist/web/public/mobile-handlers.23a85db1.js.gz +0 -0
  271. package/dist/web/public/mobile.1aa4952d.css +0 -1
  272. package/dist/web/public/mobile.1aa4952d.css.br +0 -0
  273. package/dist/web/public/mobile.1aa4952d.css.gz +0 -0
  274. package/dist/web/public/panels-ui.6a5898d9.js.br +0 -0
  275. package/dist/web/public/session-ui.bf66c13b.js +0 -89
  276. package/dist/web/public/session-ui.bf66c13b.js.br +0 -0
  277. package/dist/web/public/session-ui.bf66c13b.js.gz +0 -0
  278. package/dist/web/public/settings-ui.331d3b1d.js +0 -97
  279. package/dist/web/public/settings-ui.331d3b1d.js.br +0 -0
  280. package/dist/web/public/settings-ui.331d3b1d.js.gz +0 -0
  281. package/dist/web/public/styles.8c485d26.css +0 -1
  282. package/dist/web/public/styles.8c485d26.css.br +0 -0
  283. package/dist/web/public/styles.8c485d26.css.gz +0 -0
  284. package/dist/web/public/tab-layout-browser.4e0ed50c.js +0 -1
  285. package/dist/web/public/tab-layout-browser.4e0ed50c.js.br +0 -0
  286. package/dist/web/public/tab-layout-browser.4e0ed50c.js.gz +0 -0
  287. package/dist/web/public/tab-rail-resize.dcdc5772.js.br +0 -0
  288. package/dist/web/public/tab-rail-resize.dcdc5772.js.gz +0 -0
  289. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js +0 -1
  290. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.br +0 -0
  291. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.gz +0 -0
  292. package/dist/web/public/terminal-ui.a4535311.js +0 -2
  293. package/dist/web/public/terminal-ui.a4535311.js.br +0 -0
  294. package/dist/web/public/terminal-ui.a4535311.js.gz +0 -0
  295. package/dist/web/public/upload.html +0 -155
  296. package/dist/web/public/upload.html.br +0 -0
  297. package/dist/web/public/upload.html.gz +0 -0
  298. package/dist/web/public/voice-input.c4b51eb6.js.br +0 -0
  299. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
@@ -0,0 +1,290 @@
1
+ /**
2
+ * @fileoverview Same-origin XLSX parsing worker for the file-preview overlay.
3
+ *
4
+ * Runs off the main thread and is the ONLY place the spreadsheet vendor bundles
5
+ * load: fflate + the pure core at worker start, ExcelJS only after the ZIP has
6
+ * passed `admitXlsx()` (entry/inflate/ratio/cell/style caps). ExcelJS is then
7
+ * given a STORE-only archive rebuilt from the entries admission inflated, never
8
+ * the fetched bytes, so it can only parse what admission counted. The page never
9
+ * loads either vendor file. Cell values are sent back as plain strings; the
10
+ * renderer writes them with `textContent`. Formulas are never evaluated (the
11
+ * cached result is shown, else the formula text), and nothing here fetches:
12
+ * external links, images and drawings are reported as unsupported features.
13
+ *
14
+ * Script URLs are RELATIVE so they resolve against this worker's own URL, which
15
+ * keeps a reverse-proxy `--base-url` mount working.
16
+ */
17
+
18
+ 'use strict';
19
+
20
+ const spreadsheetAssetVersion = new URL(self.location.href).searchParams.get('v') || 'dev';
21
+ const spreadsheetAssetQuery = `?v=${encodeURIComponent(spreadsheetAssetVersion)}`;
22
+ importScripts(`vendor/fflate.min.js${spreadsheetAssetQuery}`, `spreadsheet-xlsx-core.js${spreadsheetAssetQuery}`);
23
+
24
+ const core = self.CodemanSpreadsheetXlsxCore;
25
+ let workbook = null;
26
+ let sheetsById = new Map();
27
+ // Per sheet: its populated rows in order, each with its populated cells in
28
+ // column order, built once at load from the keys that exist (`populatedRowIndex`).
29
+ let populatedRowsById = new Map();
30
+ // Merges read once at load: `sheet.model` rebuilds every row and cell model,
31
+ // which is far too much to pay on every tile.
32
+ let mergesById = new Map();
33
+ let normalizedStyles = [];
34
+ let styleIds = new Map();
35
+ let themePalette = core.DEFAULT_THEME_PALETTE;
36
+
37
+ function postError(error) {
38
+ self.postMessage({
39
+ type: 'error',
40
+ code: error?.code || 'parse-failed',
41
+ message: error?.message || 'Spreadsheet preview failed',
42
+ });
43
+ }
44
+
45
+ // Maximum cells in one tile reply; the renderer draws at most this many too.
46
+ const MAX_TILE_CELLS = 2500;
47
+
48
+ // ExcelJS keeps the workbook's raw theme XML on `_themes.theme1`; the admitted
49
+ // entry is the fallback and the default Office palette is the last resort.
50
+ function readThemeXml(loadedWorkbook, admittedEntries) {
51
+ const stashed = loadedWorkbook?._themes?.theme1;
52
+ if (typeof stashed === 'string' && stashed.length > 0) return stashed;
53
+ const theme = admittedEntries?.['xl/theme/theme1.xml'];
54
+ return theme ? new TextDecoder().decode(theme) : '';
55
+ }
56
+
57
+ function normalizeStyle(cell) {
58
+ // Colours are resolved and contrast-checked as a PAIR. Emitting a
59
+ // font colour without its background lets workbook text land on the skin's
60
+ // `var(--bg-primary)` and disappear.
61
+ const colors = core.resolveCellColors(cell.fill?.fgColor, cell.font?.color, themePalette);
62
+ const style = {
63
+ font: {
64
+ bold: Boolean(cell.font?.bold),
65
+ italic: Boolean(cell.font?.italic),
66
+ color: colors.foreground,
67
+ },
68
+ fill: colors.background,
69
+ alignment: ['left', 'center', 'right'].includes(cell.alignment?.horizontal) ? cell.alignment.horizontal : undefined,
70
+ wrapText: Boolean(cell.alignment?.wrapText),
71
+ };
72
+ const key = JSON.stringify(style);
73
+ if (styleIds.has(key)) return styleIds.get(key);
74
+ if (normalizedStyles.length >= core.LIMITS.maxStyles) {
75
+ throw new core.XlsxPreviewError('style-limit', 'Workbook exceeds the normalized styles limit');
76
+ }
77
+ const id = normalizedStyles.length;
78
+ normalizedStyles.push(style);
79
+ styleIds.set(key, id);
80
+ return id;
81
+ }
82
+
83
+ // Ascending numeric own keys of a sparse array. ExcelJS keeps rows at
84
+ // `_rows[r - 1]` and a row's cells at `_cells[col - 1]`, and one far index puts
85
+ // the array in dictionary mode, where its own `eachRow`, `eachCell` and
86
+ // `hasValues` (forEach/some) visit every index up to the largest: a single XFD
87
+ // cell per row costs 16,384 steps a row. Walking the keys that exist does not.
88
+ function presentIndices(sparse) {
89
+ const indices = [];
90
+ for (const key of Object.keys(sparse || [])) {
91
+ const index = Number(key);
92
+ if (Number.isInteger(index) && index >= 0) indices.push(index);
93
+ }
94
+ return indices.sort((a, b) => a - b);
95
+ }
96
+
97
+ // The rows and cells `sheet.eachRow({ includeEmpty: false })` and
98
+ // `row.eachCell({ includeEmpty: false })` would visit, in the same order: a
99
+ // cell counts when it exists and its type is not `ValueType.Null`, and a row
100
+ // counts when it holds at least one such cell (ExcelJS's `row.hasValues`).
101
+ function populatedRowIndex(sheet) {
102
+ const nullType = self.ExcelJS.ValueType.Null;
103
+ const rows = [];
104
+ for (const rowIndex of presentIndices(sheet._rows)) {
105
+ const row = sheet._rows[rowIndex];
106
+ if (!row) continue;
107
+ const cells = [];
108
+ for (const cellIndex of presentIndices(row._cells)) {
109
+ const cell = row._cells[cellIndex];
110
+ if (cell && cell.type !== nullType) cells.push(cell);
111
+ }
112
+ if (cells.length > 0) rows.push({ number: row.number, row, cells });
113
+ }
114
+ return rows;
115
+ }
116
+
117
+ function worksheetMetadata(sheet) {
118
+ const cellRefs = [];
119
+ const rowOverrides = [];
120
+ const populatedRows = populatedRowIndex(sheet);
121
+ for (const { number, row, cells } of populatedRows) {
122
+ for (const cell of cells) {
123
+ cellRefs.push(cell.address);
124
+ normalizeStyle(cell);
125
+ }
126
+ if (row.hidden) rowOverrides.push([number, 0]);
127
+ else if (row.height) rowOverrides.push([number, Math.min(546, Math.max(0, row.height * (4 / 3)))]);
128
+ }
129
+ // `sheet.model` rebuilds every row and cell model, so merges come straight
130
+ // from ExcelJS's own merge map, in the order the model getter would list them.
131
+ const merges = Object.values(sheet._merges || {}).map((merge) => merge.range);
132
+ const extent = core.deriveExtent(cellRefs, merges);
133
+ const columnOverrides = [];
134
+ for (let col = 1; col <= extent.cols; col += 1) {
135
+ const column = sheet.getColumn(col);
136
+ if (column.hidden) columnOverrides.push([col, 0]);
137
+ else if (column.width) columnOverrides.push([col, Math.min(1785, Math.max(0, column.width * 7))]);
138
+ }
139
+ return {
140
+ populatedRows,
141
+ merges,
142
+ metadata: {
143
+ id: String(sheet.id),
144
+ name: sheet.name,
145
+ rows: extent.rows,
146
+ cols: extent.cols,
147
+ defaultRowHeight: Math.min(546, Math.max(1, (sheet.properties?.defaultRowHeight || 15) * (4 / 3))),
148
+ defaultColumnWidth: Math.min(1785, Math.max(1, (sheet.properties?.defaultColWidth || 9.14) * 7)),
149
+ rowOverrides,
150
+ columnOverrides,
151
+ merges,
152
+ },
153
+ };
154
+ }
155
+
156
+ function cellDisplay(cell, date1904, warnings) {
157
+ const formatted = core.formatCellValue(cell.value, cell.numFmt || 'General', date1904);
158
+ if (formatted.warning) warnings.add(formatted.warning);
159
+ return formatted.text;
160
+ }
161
+
162
+ async function loadWorkbook(bytes) {
163
+ const admission = core.admitXlsx(new Uint8Array(bytes), self.fflate);
164
+ const admitted = core.buildAdmittedArchive(admission, self.fflate);
165
+ if (!self.ExcelJS) importScripts(`vendor/exceljs.min.js${spreadsheetAssetQuery}`);
166
+ const nextWorkbook = new self.ExcelJS.Workbook();
167
+ // ExcelJS's DefinedNames model setter expands every range into one object per
168
+ // cell (a whole-sheet name exhausts the heap), and admission reads only the
169
+ // `<sheet>` ids in xl/workbook.xml, never defined names. The preview never shows defined names, so they are not
170
+ // stored at all; print areas and titles are split off before this setter runs.
171
+ // defineProperty throws if a future ExcelJS renames `_definedNames`, rather
172
+ // than silently expanding again.
173
+ Object.defineProperty(nextWorkbook._definedNames, 'model', { configurable: true, get: () => [], set: () => {} });
174
+ // ExcelJS expands every address of a `<dataValidation sqref>` into its own
175
+ // object (a whole-column dropdown is a million), and the preview never shows
176
+ // validations, so they are not parsed at all. `maxRows` is a per-sheet
177
+ // backstop behind admission's row count, which also caps the workbook total.
178
+ await nextWorkbook.xlsx.load(admitted, {
179
+ ignoreNodes: ['dataValidations'],
180
+ maxRows: core.LIMITS.maxRowsPerSheet,
181
+ });
182
+ const nextSheets = new Map();
183
+ const nextRows = new Map();
184
+ const nextMerges = new Map();
185
+ normalizedStyles = [];
186
+ styleIds = new Map();
187
+ themePalette = core.parseThemePalette(readThemeXml(nextWorkbook, admission.entries));
188
+ const sheets = [];
189
+ for (const sheet of nextWorkbook.worksheets) {
190
+ if (sheet.state === 'hidden' || sheet.state === 'veryHidden') continue;
191
+ const sheetResult = worksheetMetadata(sheet);
192
+ const metadata = sheetResult.metadata;
193
+ nextSheets.set(metadata.id, sheet);
194
+ nextRows.set(metadata.id, sheetResult.populatedRows);
195
+ nextMerges.set(metadata.id, sheetResult.merges);
196
+ sheets.push(metadata);
197
+ }
198
+ workbook = nextWorkbook;
199
+ sheetsById = nextSheets;
200
+ populatedRowsById = nextRows;
201
+ mergesById = nextMerges;
202
+ self.postMessage({
203
+ type: 'metadata',
204
+ sheets,
205
+ styles: normalizedStyles,
206
+ date1904: Boolean(workbook.properties?.date1904),
207
+ empty: sheets.length === 0,
208
+ warnings: admission.features,
209
+ });
210
+ }
211
+
212
+ function sendTile(message) {
213
+ if (!workbook) throw new Error('Workbook is not loaded');
214
+ const sheet = sheetsById.get(String(message.sheetId));
215
+ if (!sheet) throw new Error('Worksheet is unavailable');
216
+ const range = message.range;
217
+ const warnings = new Set();
218
+ const cells = [];
219
+ const seenCells = new Set();
220
+ let truncated = false;
221
+ // Hidden rows and columns are 0 px, so a viewport can span thousands of them
222
+ // (a filtered sheet); they are never drawn, so never sent.
223
+ const hiddenColumns = new Map();
224
+ const columnHidden = (col) => {
225
+ if (!hiddenColumns.has(col)) hiddenColumns.set(col, Boolean(sheet.getColumn(col).hidden));
226
+ return hiddenColumns.get(col);
227
+ };
228
+ const addCell = (cell) => {
229
+ const key = `${cell.row}:${cell.col}`;
230
+ if (seenCells.has(key) || (cell.isMerged && cell.master !== cell)) return;
231
+ if (sheet.getRow(cell.row).hidden || columnHidden(cell.col)) return;
232
+ if (cells.length >= MAX_TILE_CELLS) {
233
+ truncated = true;
234
+ return;
235
+ }
236
+ seenCells.add(key);
237
+ cells.push({
238
+ row: cell.row,
239
+ col: cell.col,
240
+ text: cellDisplay(cell, Boolean(workbook.properties?.date1904), warnings),
241
+ styleId: normalizeStyle(cell),
242
+ });
243
+ };
244
+ const populatedRows = populatedRowsById.get(String(message.sheetId)) || [];
245
+ for (const populated of populatedRows) {
246
+ if (truncated) break;
247
+ if (populated.number < range.r1) continue;
248
+ if (populated.number > range.r2) break;
249
+ if (populated.row.hidden) continue;
250
+ for (const cell of populated.cells) {
251
+ if (cell.col < range.c1) continue;
252
+ if (cell.col > range.c2) break;
253
+ addCell(cell);
254
+ }
255
+ }
256
+ const merges = core.intersectingMerges(mergesById.get(String(message.sheetId)) || [], range);
257
+ for (const merge of merges) {
258
+ const anchor = core.parseRange(merge);
259
+ if (anchor) addCell(sheet.getCell(anchor.r1, anchor.c1));
260
+ }
261
+ if (truncated) warnings.add(`View truncated to the first ${MAX_TILE_CELLS} cells`);
262
+ self.postMessage({
263
+ type: 'tile',
264
+ requestId: message.requestId,
265
+ sheetId: String(message.sheetId),
266
+ cells,
267
+ merges,
268
+ // One counted entry for many unsupported number formats keeps the notice bar short.
269
+ warnings: core.foldWarnings(Array.from(warnings)),
270
+ });
271
+ }
272
+
273
+ self.onmessage = async (event) => {
274
+ try {
275
+ const message = event.data || {};
276
+ if (message.type === 'load') await loadWorkbook(message.bytes);
277
+ else if (message.type === 'tile') sendTile(message);
278
+ else if (message.type === 'dispose') {
279
+ workbook = null;
280
+ sheetsById = new Map();
281
+ populatedRowsById = new Map();
282
+ mergesById = new Map();
283
+ themePalette = core.DEFAULT_THEME_PALETTE;
284
+ }
285
+ } catch (error) {
286
+ postError(error);
287
+ }
288
+ };
289
+
290
+ self.postMessage({ type: 'ready' });