@arnilo/prism-tools 0.0.0-stage → 0.13.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 (331) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -2
  4. package/browser/README.md +98 -0
  5. package/browser/skills/browser-automation/SKILL.md +14 -0
  6. package/browser/src/actions/cdp.ts +131 -0
  7. package/browser/src/actions/dialog.ts +25 -0
  8. package/browser/src/actions/download_release.ts +22 -0
  9. package/browser/src/actions/index.ts +37 -0
  10. package/browser/src/actions/locator.ts +70 -0
  11. package/browser/src/actions/navigate.ts +23 -0
  12. package/browser/src/actions/screenshot.ts +27 -0
  13. package/browser/src/actions/scroll.ts +24 -0
  14. package/browser/src/actions/select_page.ts +21 -0
  15. package/browser/src/actions/types.ts +114 -0
  16. package/browser/src/actions/upload.ts +44 -0
  17. package/browser/src/actions/wait.ts +45 -0
  18. package/browser/src/browser.ts +197 -0
  19. package/browser/src/cdp.ts +178 -0
  20. package/browser/src/checkpoint.ts +189 -0
  21. package/browser/src/config.ts +72 -0
  22. package/browser/src/downloads.ts +253 -0
  23. package/browser/src/errors.ts +31 -0
  24. package/browser/src/evaluate.ts +101 -0
  25. package/browser/src/index.ts +129 -0
  26. package/browser/src/limits.ts +271 -0
  27. package/browser/src/manager.ts +730 -0
  28. package/browser/src/network.ts +263 -0
  29. package/browser/src/observe.ts +178 -0
  30. package/browser/src/policy.ts +133 -0
  31. package/browser/src/screenshot.ts +107 -0
  32. package/browser/src/shared-sandbox.ts +53 -0
  33. package/browser/src/snapshot.ts +99 -0
  34. package/browser/src/targets.ts +165 -0
  35. package/browser/src/tools.ts +480 -0
  36. package/browser/src/types.ts +316 -0
  37. package/browser/src/uploads.ts +174 -0
  38. package/coding/README.md +337 -0
  39. package/coding/src/agent/acp-operations.ts +146 -0
  40. package/coding/src/agent/artifacts.ts +38 -0
  41. package/coding/src/agent/ask-user-decision.ts +623 -0
  42. package/coding/src/agent/atomic-write.ts +23 -0
  43. package/coding/src/agent/bounded-file.ts +21 -0
  44. package/coding/src/agent/checks.ts +301 -0
  45. package/coding/src/agent/coding-checkpoint.ts +828 -0
  46. package/coding/src/agent/delete.ts +237 -0
  47. package/coding/src/agent/diagnostics-tool.ts +163 -0
  48. package/coding/src/agent/diagnostics.ts +262 -0
  49. package/coding/src/agent/edit-diff.ts +382 -0
  50. package/coding/src/agent/edit.ts +322 -0
  51. package/coding/src/agent/effects.ts +102 -0
  52. package/coding/src/agent/env.ts +28 -0
  53. package/coding/src/agent/execution-policy.ts +89 -0
  54. package/coding/src/agent/file-mutation-queue.ts +72 -0
  55. package/coding/src/agent/forge/github.ts +603 -0
  56. package/coding/src/agent/forge/index.ts +16 -0
  57. package/coding/src/agent/forge/types.ts +185 -0
  58. package/coding/src/agent/git-aware-repository.ts +305 -0
  59. package/coding/src/agent/git-exec.ts +326 -0
  60. package/coding/src/agent/git-status.ts +177 -0
  61. package/coding/src/agent/git-tools.ts +360 -0
  62. package/coding/src/agent/git.ts +1074 -0
  63. package/coding/src/agent/glob-match.ts +146 -0
  64. package/coding/src/agent/glob.ts +182 -0
  65. package/coding/src/agent/goal-verify.ts +385 -0
  66. package/coding/src/agent/grep-worker.ts +74 -0
  67. package/coding/src/agent/grep.ts +459 -0
  68. package/coding/src/agent/identity.ts +48 -0
  69. package/coding/src/agent/index.ts +676 -0
  70. package/coding/src/agent/language/client.ts +429 -0
  71. package/coding/src/agent/language/framing.ts +190 -0
  72. package/coding/src/agent/language/index.ts +23 -0
  73. package/coding/src/agent/language/intelligence.ts +682 -0
  74. package/coding/src/agent/language/types.ts +187 -0
  75. package/coding/src/agent/lifecycle-events.ts +121 -0
  76. package/coding/src/agent/lifecycle.ts +166 -0
  77. package/coding/src/agent/limits.ts +214 -0
  78. package/coding/src/agent/move.ts +178 -0
  79. package/coding/src/agent/mutation-path.ts +52 -0
  80. package/coding/src/agent/output-accumulator.ts +304 -0
  81. package/coding/src/agent/path-utils.ts +120 -0
  82. package/coding/src/agent/process/index.ts +58 -0
  83. package/coding/src/agent/process/recovery.ts +508 -0
  84. package/coding/src/agent/process/sessions-host.ts +222 -0
  85. package/coding/src/agent/process/sessions-monitor.ts +141 -0
  86. package/coding/src/agent/process/sessions-recovery.ts +241 -0
  87. package/coding/src/agent/process/sessions-spawn.ts +613 -0
  88. package/coding/src/agent/process/sessions-teardown.ts +281 -0
  89. package/coding/src/agent/process/sessions.ts +30 -0
  90. package/coding/src/agent/process/types.ts +358 -0
  91. package/coding/src/agent/read-path-set.ts +126 -0
  92. package/coding/src/agent/read.ts +713 -0
  93. package/coding/src/agent/repository/glob.ts +147 -0
  94. package/coding/src/agent/repository/indexed-search.ts +480 -0
  95. package/coding/src/agent/repository/list.ts +131 -0
  96. package/coding/src/agent/repository/operations.ts +22 -0
  97. package/coding/src/agent/repository/path.ts +98 -0
  98. package/coding/src/agent/repository/search.ts +277 -0
  99. package/coding/src/agent/repository/types.ts +243 -0
  100. package/coding/src/agent/repository/walk.ts +126 -0
  101. package/coding/src/agent/repository.ts +12 -0
  102. package/coding/src/agent/shell-background.ts +264 -0
  103. package/coding/src/agent/shell-output.ts +75 -0
  104. package/coding/src/agent/shell.ts +526 -0
  105. package/coding/src/agent/todo.ts +399 -0
  106. package/coding/src/agent/truncate.ts +251 -0
  107. package/coding/src/agent/write.ts +170 -0
  108. package/coding/src/ask-user-host.ts +48 -0
  109. package/coding/src/config.ts +278 -0
  110. package/coding/src/hard-deny.ts +97 -0
  111. package/coding/src/index.ts +318 -0
  112. package/coding/src/principal-guard.ts +84 -0
  113. package/coding/src/sandbox.ts +92 -0
  114. package/coding/src/security/approval.ts +144 -0
  115. package/coding/src/security/command-rules.ts +57 -0
  116. package/coding/src/security/docker-cli.ts +222 -0
  117. package/coding/src/security/docker-sandbox.ts +1205 -0
  118. package/coding/src/security/e2b-sandbox.ts +853 -0
  119. package/coding/src/security/egress/dns-pin.ts +88 -0
  120. package/coding/src/security/egress/index.ts +32 -0
  121. package/coding/src/security/egress/limits.ts +57 -0
  122. package/coding/src/security/egress/policy.ts +137 -0
  123. package/coding/src/security/egress/proxy.ts +599 -0
  124. package/coding/src/security/egress/types.ts +30 -0
  125. package/coding/src/security/index.ts +199 -0
  126. package/coding/src/security/native-sandbox.ts +639 -0
  127. package/coding/src/security/path-containment.ts +55 -0
  128. package/coding/src/security/sandbox-coding-operations.ts +392 -0
  129. package/coding/src/security/sandbox-fs-operations.ts +644 -0
  130. package/coding/src/security/sandbox-limits.ts +147 -0
  131. package/coding/src/security/sandbox-tar.ts +308 -0
  132. package/coding/src/security/sandbox.ts +179 -0
  133. package/coding/src/security/semaphore.ts +55 -0
  134. package/coding/src/targets.ts +110 -0
  135. package/coding/src/workspace/diff.ts +78 -0
  136. package/coding/src/workspace/errors.ts +28 -0
  137. package/coding/src/workspace/index.ts +5 -0
  138. package/coding/src/workspace/merge.ts +151 -0
  139. package/coding/src/workspace/routing.ts +76 -0
  140. package/coding/src/workspace/service.ts +545 -0
  141. package/computer-use/README.md +105 -0
  142. package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
  143. package/computer-use/src/classify.ts +53 -0
  144. package/computer-use/src/command.ts +29 -0
  145. package/computer-use/src/config.ts +69 -0
  146. package/computer-use/src/create.ts +170 -0
  147. package/computer-use/src/devices.ts +247 -0
  148. package/computer-use/src/env.ts +28 -0
  149. package/computer-use/src/index.ts +157 -0
  150. package/computer-use/src/skill.ts +21 -0
  151. package/openapi/README.md +97 -0
  152. package/openapi/src/compile.ts +386 -0
  153. package/openapi/src/config.ts +73 -0
  154. package/openapi/src/errors.ts +16 -0
  155. package/openapi/src/execute.ts +241 -0
  156. package/openapi/src/index.ts +124 -0
  157. package/openapi/src/limits.ts +63 -0
  158. package/openapi/src/specs.ts +86 -0
  159. package/openapi/src/tools.ts +60 -0
  160. package/openapi/src/types.ts +61 -0
  161. package/package.json +171 -4
  162. package/research/README.md +72 -0
  163. package/research/skills/research-report/SKILL.md +12 -0
  164. package/research/skills/research-scoping/SKILL.md +10 -0
  165. package/research/skills/research-synthesis/SKILL.md +10 -0
  166. package/research/skills/source-triage/SKILL.md +10 -0
  167. package/research/src/check.ts +71 -0
  168. package/research/src/config.ts +41 -0
  169. package/research/src/index.ts +147 -0
  170. package/research/src/ledger.ts +157 -0
  171. package/research/src/urls.ts +21 -0
  172. package/web/README.md +287 -0
  173. package/web/skills/web-research/SKILL.md +17 -0
  174. package/web/src/brave.ts +66 -0
  175. package/web/src/cache.ts +151 -0
  176. package/web/src/config.ts +210 -0
  177. package/web/src/controls.ts +128 -0
  178. package/web/src/domains.ts +114 -0
  179. package/web/src/exa.ts +60 -0
  180. package/web/src/firecrawl.ts +160 -0
  181. package/web/src/index.ts +387 -0
  182. package/web/src/kagi.ts +73 -0
  183. package/web/src/limits.ts +55 -0
  184. package/web/src/native/convert.ts +84 -0
  185. package/web/src/native/fetch.ts +226 -0
  186. package/web/src/normalize.ts +131 -0
  187. package/web/src/obscura/cdp.ts +201 -0
  188. package/web/src/obscura/classify.ts +35 -0
  189. package/web/src/obscura/cli.ts +254 -0
  190. package/web/src/obscura/errors.ts +8 -0
  191. package/web/src/obscura/index.ts +59 -0
  192. package/web/src/obscura/limits.ts +92 -0
  193. package/web/src/obscura/mcp.ts +104 -0
  194. package/web/src/obscura/playwright.ts +133 -0
  195. package/web/src/obscura/process.ts +235 -0
  196. package/web/src/obscura/search-profile.ts +73 -0
  197. package/web/src/obscura/types.ts +48 -0
  198. package/web/src/obscura/web.ts +419 -0
  199. package/web/src/prompt-fetch.ts +88 -0
  200. package/web/src/render.ts +75 -0
  201. package/web/src/searxng.ts +78 -0
  202. package/web/src/slice.ts +139 -0
  203. package/web/src/tavily.ts +77 -0
  204. package/web/src/tools.ts +182 -0
  205. package/web/src/transport.ts +310 -0
  206. package/web/src/types.ts +199 -0
  207. package/work/README.md +77 -0
  208. package/work/THIRD_PARTY_NOTICES +24 -0
  209. package/work/docling/ocr.py +150 -0
  210. package/work/sandbox/Dockerfile +36 -0
  211. package/work/sandbox/soffice.sh +12 -0
  212. package/work/src/command.ts +29 -0
  213. package/work/src/config.ts +138 -0
  214. package/work/src/connectors/cli.ts +343 -0
  215. package/work/src/connectors/drafts.ts +647 -0
  216. package/work/src/connectors/errors.ts +8 -0
  217. package/work/src/connectors/file-bytes.ts +149 -0
  218. package/work/src/connectors/google-workspace-http.ts +399 -0
  219. package/work/src/connectors/google-workspace.ts +465 -0
  220. package/work/src/connectors/gws-tools.ts +378 -0
  221. package/work/src/connectors/http.ts +123 -0
  222. package/work/src/connectors/idempotency.ts +235 -0
  223. package/work/src/connectors/identity.ts +34 -0
  224. package/work/src/connectors/index.ts +93 -0
  225. package/work/src/connectors/limits.ts +50 -0
  226. package/work/src/connectors/m365-tools.ts +308 -0
  227. package/work/src/connectors/microsoft365-http.ts +428 -0
  228. package/work/src/connectors/microsoft365.ts +402 -0
  229. package/work/src/connectors/normalize.ts +120 -0
  230. package/work/src/connectors/tool-helpers.ts +398 -0
  231. package/work/src/connectors/tools.ts +42 -0
  232. package/work/src/connectors/types.ts +399 -0
  233. package/work/src/diagrams/canonicalize.ts +166 -0
  234. package/work/src/diagrams/caps.ts +52 -0
  235. package/work/src/diagrams/embed.ts +340 -0
  236. package/work/src/diagrams/errors.ts +76 -0
  237. package/work/src/diagrams/index.ts +81 -0
  238. package/work/src/diagrams/messages.ts +150 -0
  239. package/work/src/diagrams/origin.ts +52 -0
  240. package/work/src/diagrams/telemetry.ts +34 -0
  241. package/work/src/diagrams/xml.ts +267 -0
  242. package/work/src/document-extraction/index.ts +563 -0
  243. package/work/src/document-reader/ambient.d.ts +2 -0
  244. package/work/src/document-reader/errors.ts +7 -0
  245. package/work/src/document-reader/index.ts +181 -0
  246. package/work/src/document-reader/mistral-ocr.ts +318 -0
  247. package/work/src/document-reader/parsers.ts +171 -0
  248. package/work/src/documents/caps.ts +135 -0
  249. package/work/src/documents/diff.ts +269 -0
  250. package/work/src/documents/errors.ts +44 -0
  251. package/work/src/documents/fidelity.ts +98 -0
  252. package/work/src/documents/generate.ts +96 -0
  253. package/work/src/documents/hash.ts +8 -0
  254. package/work/src/documents/index.ts +14 -0
  255. package/work/src/documents/model-schema.ts +639 -0
  256. package/work/src/documents/parse.ts +252 -0
  257. package/work/src/documents/patch-history.ts +81 -0
  258. package/work/src/documents/patch.ts +476 -0
  259. package/work/src/documents/preview-html.ts +245 -0
  260. package/work/src/documents/preview.ts +227 -0
  261. package/work/src/documents/telemetry.ts +36 -0
  262. package/work/src/documents/translate/docx.ts +292 -0
  263. package/work/src/documents/translate/pptx.ts +304 -0
  264. package/work/src/documents/translate/xlsx.ts +137 -0
  265. package/work/src/documents/types.ts +188 -0
  266. package/work/src/index.ts +311 -0
  267. package/work/src/runtime/worker-pool-entry.ts +102 -0
  268. package/work/src/runtime/worker-pool.ts +267 -0
  269. package/work/src/sandbox/composition.ts +212 -0
  270. package/work/src/sandbox/image.ts +6 -0
  271. package/work/src/sandbox/index.ts +14 -0
  272. package/work/src/sheets/caps.ts +68 -0
  273. package/work/src/sheets/csv.ts +351 -0
  274. package/work/src/sheets/decimal.ts +388 -0
  275. package/work/src/sheets/errors.ts +52 -0
  276. package/work/src/sheets/index.ts +62 -0
  277. package/work/src/sheets/inference.ts +378 -0
  278. package/work/src/sheets/telemetry.ts +34 -0
  279. package/work/src/sheets/types.ts +162 -0
  280. package/work/src/sheets/xlsx.ts +388 -0
  281. package/work/src/skills/index.ts +8 -0
  282. package/work/src/skills/load.ts +43 -0
  283. package/work/src/tools/filesystem.ts +21 -0
  284. package/work/src/tools/index.ts +1 -0
  285. package/work/src/tools/local-filesystem.ts +33 -0
  286. package/work/src/tools/office.ts +311 -0
  287. package/work/vendor/hermes-agent/LICENSE +21 -0
  288. package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
  289. package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
  290. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
  291. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
  292. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
  293. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
  294. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
  295. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
  296. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
  297. package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
  298. package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
  299. package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
  300. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
  301. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
  302. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
  303. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
  304. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
  305. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
  306. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
  307. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
  308. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
  309. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
  310. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
  311. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
  312. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
  313. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
  314. package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
  315. package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
  316. package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
  317. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
  318. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
  319. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
  320. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
  321. package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
  322. package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
  323. package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
  324. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
  325. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
  326. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
  327. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
  328. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
  329. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
  330. package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
  331. package/work/vendor-lock.json +11 -0
@@ -0,0 +1,245 @@
1
+ import type { DocumentsTelemetry } from "./telemetry.js";
2
+ import type { CellValue, DeckModel, DocBlock, DocModel, DocRun, DocumentModel, ListItem, SheetModel, SlideData } from "./types.js";
3
+
4
+ export interface PreviewHtmlOptions {
5
+ /** Maximum output size in UTF-8 bytes (default 512 KiB). Excess content is truncated cleanly. */
6
+ readonly maxHtmlBytes?: number;
7
+ /** Optional telemetry seam hook. */
8
+ readonly telemetry?: DocumentsTelemetry;
9
+ }
10
+
11
+ const DEFAULT_MAX_HTML_BYTES = 512 * 1024; // 512 KiB
12
+
13
+ /**
14
+ * Escapes characters with special meaning in HTML text and attribute values,
15
+ * and neutralizes active/external URL protocols (javascript:, http://, https://).
16
+ */
17
+ export function escapeHtml(input: string): string {
18
+ return input
19
+ .replace(/&/g, "&")
20
+ .replace(/</g, "&lt;")
21
+ .replace(/>/g, "&gt;")
22
+ .replace(/"/g, "&quot;")
23
+ .replace(/'/g, "&#39;")
24
+ .replace(/javascript\s*:/gi, "blocked-script:")
25
+ .replace(/https?:\/\//gi, "");
26
+ }
27
+
28
+ function renderRunHtml(run: DocRun): string {
29
+ let content = escapeHtml(run.text);
30
+ if (run.code) content = `<code>${content}</code>`;
31
+ if (run.strikethrough) content = `<s>${content}</s>`;
32
+ if (run.underline) content = `<u>${content}</u>`;
33
+ if (run.italic) content = `<em>${content}</em>`;
34
+ if (run.bold) content = `<strong>${content}</strong>`;
35
+ if (run.link) {
36
+ // Sanitize-by-construction: link targets are escaped as inert text, never rendered as live clickable href attributes
37
+ content = `${content} <span class="prism-link-text">(${escapeHtml(run.link)})</span>`;
38
+ }
39
+ return content;
40
+ }
41
+
42
+ function renderDocBlockHtml(block: DocBlock): string {
43
+ switch (block.type) {
44
+ case "heading": {
45
+ const tag = `h${block.level}`;
46
+ const idAttr = block.id ? ` id="${escapeHtml(block.id)}"` : "";
47
+ return `<${tag} class="prism-heading prism-heading-${block.level}"${idAttr}>${escapeHtml(block.text)}</${tag}>`;
48
+ }
49
+ case "paragraph": {
50
+ let body = "";
51
+ if (block.runs && block.runs.length > 0) {
52
+ body = block.runs.map(renderRunHtml).join("");
53
+ } else if (block.text !== undefined) {
54
+ body = escapeHtml(block.text);
55
+ }
56
+ return `<p class="prism-paragraph">${body}</p>`;
57
+ }
58
+ case "list": {
59
+ const tag = block.ordered ? "ol" : "ul";
60
+ const cls = block.ordered ? "prism-list prism-list-ordered" : "prism-list prism-list-unordered";
61
+ const items = block.items
62
+ .map((item) => {
63
+ if (typeof item === "string") {
64
+ return `<li>${escapeHtml(item)}</li>`;
65
+ }
66
+ const li = item as ListItem;
67
+ const body = li.runs && li.runs.length > 0 ? li.runs.map(renderRunHtml).join("") : escapeHtml(li.text);
68
+ return `<li>${body}</li>`;
69
+ })
70
+ .join("");
71
+ return `<${tag} class="${cls}">${items}</${tag}>`;
72
+ }
73
+ case "table": {
74
+ let tableHtml = '<table class="prism-table">';
75
+ if (block.headers && block.headers.length > 0) {
76
+ tableHtml += "<thead><tr>";
77
+ for (const h of block.headers) {
78
+ tableHtml += `<th>${escapeHtml(h)}</th>`;
79
+ }
80
+ tableHtml += "</tr></thead>";
81
+ }
82
+ tableHtml += "<tbody>";
83
+ for (const row of block.cells) {
84
+ tableHtml += "<tr>";
85
+ for (const cell of row) {
86
+ tableHtml += `<td>${renderCellHtml(cell)}</td>`;
87
+ }
88
+ tableHtml += "</tr>";
89
+ }
90
+ tableHtml += "</tbody></table>";
91
+ return tableHtml;
92
+ }
93
+ case "page-break":
94
+ return '<hr class="prism-page-break" />';
95
+ case "image": {
96
+ const alt = block.alt ? escapeHtml(block.alt) : "Embedded Image";
97
+ return `<div class="prism-image-placeholder"><span class="prism-image-alt">[Image: ${alt}]</span></div>`;
98
+ }
99
+ case "chart": {
100
+ const title = block.title ? ` - ${escapeHtml(block.title)}` : "";
101
+ return `<div class="prism-chart-placeholder"><strong class="prism-chart-title">[Chart: ${escapeHtml(block.chartType)}${title}]</strong></div>`;
102
+ }
103
+ default:
104
+ return "";
105
+ }
106
+ }
107
+
108
+ function renderCellHtml(cell: CellValue): string {
109
+ if (cell === null || cell === undefined) return "";
110
+ if (typeof cell === "string") return escapeHtml(cell);
111
+ if (typeof cell === "number" || typeof cell === "boolean") return String(cell);
112
+ if ("type" in cell) {
113
+ if (cell.type === "decimal" || cell.type === "date" || cell.type === "datetime") {
114
+ return escapeHtml(cell.value);
115
+ }
116
+ }
117
+ if ("formula" in cell) {
118
+ const cached = cell.cachedValue !== undefined && cell.cachedValue !== null ? ` = ${escapeHtml(String(cell.cachedValue))}` : "";
119
+ return `<code>${escapeHtml(cell.formula)}${cached}</code>`;
120
+ }
121
+ return "";
122
+ }
123
+
124
+ function renderDocHtml(doc: DocModel): string {
125
+ let html = '<article class="prism-preview prism-doc-preview">';
126
+ if (doc.title) {
127
+ html += `<h1 class="prism-doc-title">${escapeHtml(doc.title)}</h1>`;
128
+ }
129
+ for (const block of doc.blocks) {
130
+ html += renderDocBlockHtml(block);
131
+ }
132
+ html += "</article>";
133
+ return html;
134
+ }
135
+
136
+ function renderSheetHtml(model: SheetModel): string {
137
+ let html = '<div class="prism-preview prism-sheet-preview">';
138
+ if (model.title) {
139
+ html += `<h1 class="prism-sheet-title">${escapeHtml(model.title)}</h1>`;
140
+ }
141
+ for (const sheet of model.sheets) {
142
+ html += `<section class="prism-worksheet"><h2 class="prism-worksheet-name">${escapeHtml(sheet.name)}</h2>`;
143
+ html += '<table class="prism-table"><tbody>';
144
+ for (const row of sheet.cells) {
145
+ html += "<tr>";
146
+ for (const cell of row) {
147
+ html += `<td>${renderCellHtml(cell)}</td>`;
148
+ }
149
+ html += "</tr>";
150
+ }
151
+ html += "</tbody></table></section>";
152
+ }
153
+ html += "</div>";
154
+ return html;
155
+ }
156
+
157
+ function renderSlideHtml(slide: SlideData, index: number): string {
158
+ let html = `<section class="prism-slide prism-slide-${escapeHtml(slide.layout)}" data-slide-index="${index}">`;
159
+ if (slide.title) {
160
+ html += `<h2 class="prism-slide-title">${escapeHtml(slide.title)}</h2>`;
161
+ }
162
+ if (slide.subtitle) {
163
+ html += `<p class="prism-slide-subtitle">${escapeHtml(slide.subtitle)}</p>`;
164
+ }
165
+ if (slide.bullets && slide.bullets.length > 0) {
166
+ html += '<ul class="prism-slide-bullets">';
167
+ for (const bullet of slide.bullets) {
168
+ if (typeof bullet === "string") {
169
+ html += `<li>${escapeHtml(bullet)}</li>`;
170
+ } else {
171
+ const li = bullet as ListItem;
172
+ const body = li.runs && li.runs.length > 0 ? li.runs.map(renderRunHtml).join("") : escapeHtml(li.text);
173
+ html += `<li>${body}</li>`;
174
+ }
175
+ }
176
+ html += "</ul>";
177
+ }
178
+ if (slide.notes) {
179
+ html += `<aside class="prism-slide-notes"><small>${escapeHtml(slide.notes)}</small></aside>`;
180
+ }
181
+ html += "</section>";
182
+ return html;
183
+ }
184
+
185
+ function renderDeckHtml(deck: DeckModel): string {
186
+ let html = '<div class="prism-preview prism-deck-preview">';
187
+ if (deck.title) {
188
+ html += `<h1 class="prism-deck-title">${escapeHtml(deck.title)}</h1>`;
189
+ }
190
+ for (let i = 0; i < deck.slides.length; i += 1) {
191
+ html += renderSlideHtml(deck.slides[i], i);
192
+ }
193
+ html += "</div>";
194
+ return html;
195
+ }
196
+
197
+ /**
198
+ * Renders a Prism Document Model into safe, bounded, framework-neutral HTML.
199
+ *
200
+ * Guaranteed by construction to contain:
201
+ * - No `<script>` tags
202
+ * - No `javascript:` or external URL protocols (`http://`, `https://`)
203
+ * - No active iframes or live link anchors
204
+ * - All text values entity-escaped
205
+ * - Output capped at `maxHtmlBytes` budget
206
+ */
207
+ export function renderPreviewHtml(model: DocumentModel, options?: PreviewHtmlOptions): string {
208
+ const maxBytes = options?.maxHtmlBytes ?? DEFAULT_MAX_HTML_BYTES;
209
+ const span = options?.telemetry?.startSpan("documents.preview", {
210
+ "documents.kind": model?.kind ?? "unknown",
211
+ "documents.preview_type": "html",
212
+ });
213
+
214
+ try {
215
+ let rawHtml: string;
216
+ switch (model.kind) {
217
+ case "doc":
218
+ rawHtml = renderDocHtml(model as DocModel);
219
+ break;
220
+ case "sheet":
221
+ rawHtml = renderSheetHtml(model as SheetModel);
222
+ break;
223
+ case "deck":
224
+ rawHtml = renderDeckHtml(model as DeckModel);
225
+ break;
226
+ default:
227
+ rawHtml = "";
228
+ }
229
+
230
+ const encodedBytes = new TextEncoder().encode(rawHtml);
231
+ if (encodedBytes.byteLength <= maxBytes) {
232
+ return rawHtml;
233
+ }
234
+
235
+ // Budget exceeded: truncate and append terminal note
236
+ const truncatedSlice = encodedBytes.subarray(0, Math.max(0, maxBytes - 128));
237
+ const decoded = new TextDecoder("utf-8", { fatal: false }).decode(truncatedSlice);
238
+ return `${decoded}<div class="prism-preview-truncated">[Preview truncated: byte budget exceeded]</div>`;
239
+ } catch (err) {
240
+ span?.recordError();
241
+ throw err;
242
+ } finally {
243
+ span?.end();
244
+ }
245
+ }
@@ -0,0 +1,227 @@
1
+ import type { DocumentsTelemetry } from "./telemetry.js";
2
+ import type { CellValue, DeckModel, DocBlock, DocModel, DocumentModel, HeadingBlock, SheetData, SheetModel, SlideData } from "./types.js";
3
+
4
+ // --- Preview Block Definitions ---
5
+
6
+ export interface DocOutlineHeading {
7
+ readonly level: number;
8
+ readonly text: string;
9
+ readonly id?: string;
10
+ }
11
+
12
+ export interface DocOutlinePreviewBlock {
13
+ readonly type: "doc-outline";
14
+ readonly title?: string;
15
+ readonly headings: readonly DocOutlineHeading[];
16
+ }
17
+
18
+ export interface DocBlocksPreviewBlock {
19
+ readonly type: "doc-blocks";
20
+ readonly title?: string;
21
+ readonly blocks: readonly DocBlock[];
22
+ readonly totalBlocks: number;
23
+ readonly bounds: {
24
+ readonly fromIndex: number;
25
+ readonly toIndex: number;
26
+ };
27
+ }
28
+
29
+ export interface SheetGridPreviewBlock {
30
+ readonly type: "sheet-grid";
31
+ readonly sheetIndex: number;
32
+ readonly name: string;
33
+ readonly rows: readonly (readonly CellValue[])[];
34
+ readonly totalRows: number;
35
+ readonly totalColumns: number;
36
+ readonly bounds: {
37
+ readonly fromRow: number;
38
+ readonly toRow: number;
39
+ };
40
+ }
41
+
42
+ export interface DeckSlideListPreviewBlock {
43
+ readonly type: "deck-slides";
44
+ readonly title?: string;
45
+ readonly slides: readonly SlideData[];
46
+ readonly totalSlides: number;
47
+ readonly bounds: {
48
+ readonly fromIndex: number;
49
+ readonly toIndex: number;
50
+ };
51
+ }
52
+
53
+ export interface TruncationNotePreviewBlock {
54
+ readonly type: "truncation-note";
55
+ readonly message: string;
56
+ readonly droppedItems: number;
57
+ }
58
+
59
+ export type PreviewBlock =
60
+ | DocOutlinePreviewBlock
61
+ | DocBlocksPreviewBlock
62
+ | SheetGridPreviewBlock
63
+ | DeckSlideListPreviewBlock
64
+ | TruncationNotePreviewBlock;
65
+
66
+ export interface PreviewBlocksOptions {
67
+ /** Maximum rows per sheet-grid snapshot block (default: 200). */
68
+ readonly maxRowsPerBlock?: number;
69
+ /** Maximum total rows previewed per sheet across all grid blocks (default: 1,000). */
70
+ readonly maxTotalRowsPerSheet?: number;
71
+ /** Maximum blocks per document preview chunk (default: 200). */
72
+ readonly maxBlocksPerChunk?: number;
73
+ /** Maximum slides previewed (default: 100). */
74
+ readonly maxSlides?: number;
75
+ /** Optional telemetry seam hook. */
76
+ readonly telemetry?: DocumentsTelemetry;
77
+ }
78
+
79
+ const DEFAULT_MAX_ROWS_PER_BLOCK = 200;
80
+ const DEFAULT_MAX_TOTAL_ROWS_PER_SHEET = 1_000;
81
+ const DEFAULT_MAX_BLOCKS_PER_CHUNK = 200;
82
+ const DEFAULT_MAX_SLIDES = 100;
83
+
84
+ function renderDocPreviewBlocks(doc: DocModel, options?: PreviewBlocksOptions): PreviewBlock[] {
85
+ const blocks: PreviewBlock[] = [];
86
+ const maxBlocksPerChunk = options?.maxBlocksPerChunk ?? DEFAULT_MAX_BLOCKS_PER_CHUNK;
87
+
88
+ // 1. Extract outline
89
+ const headings: DocOutlineHeading[] = [];
90
+ for (const block of doc.blocks) {
91
+ if (block.type === "heading") {
92
+ const h = block as HeadingBlock;
93
+ headings.push({
94
+ level: h.level,
95
+ text: h.text,
96
+ id: h.id,
97
+ });
98
+ }
99
+ }
100
+
101
+ blocks.push({
102
+ type: "doc-outline",
103
+ title: doc.title,
104
+ headings,
105
+ });
106
+
107
+ // 2. Chunk document blocks into bounded windows
108
+ const total = doc.blocks.length;
109
+ for (let i = 0; i < total; i += maxBlocksPerChunk) {
110
+ const chunk = doc.blocks.slice(i, i + maxBlocksPerChunk);
111
+ blocks.push({
112
+ type: "doc-blocks",
113
+ title: doc.title,
114
+ blocks: chunk,
115
+ totalBlocks: total,
116
+ bounds: {
117
+ fromIndex: i,
118
+ toIndex: i + chunk.length - 1,
119
+ },
120
+ });
121
+ }
122
+
123
+ return blocks;
124
+ }
125
+
126
+ function renderSheetPreviewBlocks(model: SheetModel, options?: PreviewBlocksOptions): PreviewBlock[] {
127
+ const blocks: PreviewBlock[] = [];
128
+ const maxRowsPerBlock = options?.maxRowsPerBlock ?? DEFAULT_MAX_ROWS_PER_BLOCK;
129
+ const maxTotalRows = options?.maxTotalRowsPerSheet ?? DEFAULT_MAX_TOTAL_ROWS_PER_SHEET;
130
+
131
+ for (let sheetIdx = 0; sheetIdx < model.sheets.length; sheetIdx += 1) {
132
+ const sheet: SheetData = model.sheets[sheetIdx];
133
+ const totalRows = sheet.cells.length;
134
+ let maxCols = 0;
135
+ for (const r of sheet.cells) {
136
+ if (r.length > maxCols) maxCols = r.length;
137
+ }
138
+
139
+ const previewableRows = Math.min(totalRows, maxTotalRows);
140
+
141
+ for (let r = 0; r < previewableRows; r += maxRowsPerBlock) {
142
+ const chunk = sheet.cells.slice(r, r + maxRowsPerBlock);
143
+ blocks.push({
144
+ type: "sheet-grid",
145
+ sheetIndex: sheetIdx,
146
+ name: sheet.name,
147
+ rows: chunk,
148
+ totalRows,
149
+ totalColumns: maxCols,
150
+ bounds: {
151
+ fromRow: r,
152
+ toRow: r + chunk.length - 1,
153
+ },
154
+ });
155
+ }
156
+
157
+ if (totalRows > maxTotalRows) {
158
+ const dropped = totalRows - maxTotalRows;
159
+ blocks.push({
160
+ type: "truncation-note",
161
+ message: `Sheet "${sheet.name}" truncated. Showing first ${maxTotalRows} of ${totalRows} rows.`,
162
+ droppedItems: dropped,
163
+ });
164
+ }
165
+ }
166
+
167
+ return blocks;
168
+ }
169
+
170
+ function renderDeckPreviewBlocks(deck: DeckModel, options?: PreviewBlocksOptions): PreviewBlock[] {
171
+ const blocks: PreviewBlock[] = [];
172
+ const maxSlides = options?.maxSlides ?? DEFAULT_MAX_SLIDES;
173
+ const total = deck.slides.length;
174
+ const previewSlides = deck.slides.slice(0, maxSlides);
175
+
176
+ blocks.push({
177
+ type: "deck-slides",
178
+ title: deck.title,
179
+ slides: previewSlides,
180
+ totalSlides: total,
181
+ bounds: {
182
+ fromIndex: 0,
183
+ toIndex: previewSlides.length - 1,
184
+ },
185
+ });
186
+
187
+ if (total > maxSlides) {
188
+ const dropped = total - maxSlides;
189
+ blocks.push({
190
+ type: "truncation-note",
191
+ message: `Presentation preview truncated. Showing first ${maxSlides} of ${total} slides.`,
192
+ droppedItems: dropped,
193
+ });
194
+ }
195
+
196
+ return blocks;
197
+ }
198
+
199
+ /**
200
+ * Renders a Prism Document Model into framework-neutral, structured preview blocks.
201
+ *
202
+ * Produces bounded snapshots with configurable row/block pagination for native UI rendering.
203
+ */
204
+ export function renderPreviewBlocks(model: DocumentModel, options?: PreviewBlocksOptions): PreviewBlock[] {
205
+ const span = options?.telemetry?.startSpan("documents.preview", {
206
+ "documents.kind": model?.kind ?? "unknown",
207
+ "documents.preview_type": "blocks",
208
+ });
209
+
210
+ try {
211
+ switch (model.kind) {
212
+ case "doc":
213
+ return renderDocPreviewBlocks(model as DocModel, options);
214
+ case "sheet":
215
+ return renderSheetPreviewBlocks(model as SheetModel, options);
216
+ case "deck":
217
+ return renderDeckPreviewBlocks(model as DeckModel, options);
218
+ default:
219
+ return [];
220
+ }
221
+ } catch (err) {
222
+ span?.recordError();
223
+ throw err;
224
+ } finally {
225
+ span?.end();
226
+ }
227
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Dependency-free telemetry seam for Document operations. When `telemetry` is omitted every
3
+ * call site short-circuits on an optional chain — zero allocations, zero per-span work.
4
+ * Implementations own timing/status; the seam only carries structure and allow-listed metadata attributes.
5
+ */
6
+
7
+ export type DocumentsTelemetryAttributeValue = string | number | boolean;
8
+
9
+ export interface DocumentsTelemetrySpan {
10
+ setAttribute(name: string, value: DocumentsTelemetryAttributeValue): void;
11
+ addEvent(name: string, attributes?: Readonly<Record<string, DocumentsTelemetryAttributeValue>>): void;
12
+ /** Flags the span as failed without carrying any error text (no user data leaves the host). */
13
+ recordError(): void;
14
+ end(): void;
15
+ }
16
+
17
+ export interface DocumentsTelemetry {
18
+ startSpan(
19
+ name: string,
20
+ attributes?: Readonly<Record<string, DocumentsTelemetryAttributeValue>>,
21
+ parent?: DocumentsTelemetrySpan,
22
+ ): DocumentsTelemetrySpan;
23
+ }
24
+
25
+ export const noopDocumentsSpan: DocumentsTelemetrySpan = {
26
+ setAttribute() {},
27
+ addEvent() {},
28
+ recordError() {},
29
+ end() {},
30
+ };
31
+
32
+ export const noopDocumentsTelemetry: DocumentsTelemetry = {
33
+ startSpan() {
34
+ return noopDocumentsSpan;
35
+ },
36
+ };