@peaske7/readit 0.3.0-rc.0 → 0.3.0-rc.2

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 (374) hide show
  1. package/README.md +3 -3
  2. package/dist/.vite/manifest.json +1111 -0
  3. package/dist/assets/_basePickBy-BMMA4Tou.js +1 -0
  4. package/dist/assets/_baseUniq-D40qku1I.js +1 -0
  5. package/dist/assets/arc-Ckg65iy8.js +1 -0
  6. package/dist/assets/architecture-YZFGNWBL-Dv3EY0zV.js +1 -0
  7. package/dist/assets/architectureDiagram-Q4EWVU46-DQnkwSaB.js +36 -0
  8. package/dist/assets/array-Bjz-wYpJ.js +1 -0
  9. package/dist/assets/blockDiagram-DXYQGD6D-UB6_S1lm.js +132 -0
  10. package/dist/assets/c4Diagram-AHTNJAMY-sn3k2GND.js +10 -0
  11. package/dist/assets/channel-D9wPw2fQ.js +1 -0
  12. package/dist/assets/chunk-2KRD3SAO-DaFfaCGO.js +1 -0
  13. package/dist/assets/chunk-336JU56O-C8siO5Of.js +2 -0
  14. package/dist/assets/chunk-426QAEUC-BB478m3j.js +1 -0
  15. package/dist/assets/chunk-4BX2VUAB-DRuTD7x5.js +1 -0
  16. package/dist/assets/chunk-4TB4RGXK-_l6jvVAY.js +206 -0
  17. package/dist/assets/chunk-55IACEB6-BExiaAoD.js +1 -0
  18. package/dist/assets/chunk-5FUZZQ4R-HOSFTxuG.js +62 -0
  19. package/dist/assets/chunk-5PVQY5BW-BRVNNRAX.js +2 -0
  20. package/dist/assets/chunk-67CJDMHE-DMt8LNEX.js +1 -0
  21. package/dist/assets/chunk-7N4EOEYR-CzLGefVf.js +1 -0
  22. package/dist/assets/chunk-AA7GKIK3-B6GFAk4U.js +1 -0
  23. package/dist/assets/chunk-BSJP7CBP-BK29yehL.js +1 -0
  24. package/dist/assets/chunk-CIAEETIT-D7hBXImP.js +1 -0
  25. package/dist/assets/chunk-Dlc7tRH4.js +1 -0
  26. package/dist/assets/chunk-EDXVE4YY-CSvKh9DT.js +1 -0
  27. package/dist/assets/chunk-ENJZ2VHE-QApb5cYr.js +10 -0
  28. package/dist/assets/chunk-FMBD7UC4-2FWyCCAV.js +15 -0
  29. package/dist/assets/chunk-FOC6F5B3-DKFHrt4K.js +1 -0
  30. package/dist/assets/chunk-ICPOFSXX-agBjBxsW.js +122 -0
  31. package/dist/assets/chunk-K5T4RW27-D51O7IkG.js +94 -0
  32. package/dist/assets/chunk-KGLVRYIC-DMHSCH4T.js +1 -0
  33. package/dist/assets/chunk-LIHQZDEY-C2aANxt9.js +1 -0
  34. package/dist/assets/chunk-ORNJ4GCN-Db_37NRX.js +1 -0
  35. package/dist/assets/chunk-OYMX7WX6-HGUtT2Q9.js +231 -0
  36. package/dist/assets/chunk-QZHKN3VN-8Lcg9gti.js +1 -0
  37. package/dist/assets/chunk-U2HBQHQK-BFYYQeuC.js +70 -0
  38. package/dist/assets/chunk-X2U36JSP-p8ehTP6s.js +1 -0
  39. package/dist/assets/chunk-XPW4576I-Bqbompq4.js +32 -0
  40. package/dist/assets/chunk-YZCP3GAM-HIMez9pG.js +1 -0
  41. package/dist/assets/chunk-ZZ45TVLE-DRIE_0bu.js +1 -0
  42. package/dist/assets/classDiagram-6PBFFD2Q-BawhEeUl.js +1 -0
  43. package/dist/assets/classDiagram-v2-HSJHXN6E-CLNjgH9n.js +1 -0
  44. package/dist/assets/clone-BBjvuERA.js +1 -0
  45. package/dist/assets/cose-bilkent-S5V4N54A-q90QeGKv.js +1 -0
  46. package/dist/assets/cytoscape.esm-BfXff3fb.js +321 -0
  47. package/dist/assets/dagre-Dxbob2Lr.js +1 -0
  48. package/dist/assets/dagre-KV5264BT-BuvpNxMw.js +4 -0
  49. package/dist/assets/defaultLocale-BwmRmqJp.js +1 -0
  50. package/dist/assets/diagram-5BDNPKRD-DQLsxwwt.js +10 -0
  51. package/dist/assets/diagram-G4DWMVQ6-Jv9Eefw4.js +24 -0
  52. package/dist/assets/diagram-MMDJMWI5-D-0YgNhU.js +43 -0
  53. package/dist/assets/diagram-TYMM5635-BHwO7zQG.js +24 -0
  54. package/dist/assets/dist-BNz65Ibc.js +1 -0
  55. package/dist/assets/erDiagram-SMLLAGMA-BjZGGBJz.js +85 -0
  56. package/dist/assets/flowDiagram-DWJPFMVM-CFbFUm_m.js +162 -0
  57. package/dist/assets/ganttDiagram-T4ZO3ILL-CXk4TcBi.js +292 -0
  58. package/dist/assets/gitGraph-7Q5UKJZL-BGFRt2qs.js +1 -0
  59. package/dist/assets/gitGraphDiagram-UUTBAWPF-C8yZOxjo.js +106 -0
  60. package/dist/assets/graphlib-DGcD9J2L.js +1 -0
  61. package/dist/assets/index-D-m0LiFI.js +14 -0
  62. package/dist/assets/index-DANHO6J0.css +2 -0
  63. package/dist/assets/info-OMHHGYJF-DI6-Z9vh.js +1 -0
  64. package/dist/assets/infoDiagram-42DDH7IO-p-PXDra2.js +2 -0
  65. package/dist/assets/init-TPm5RB77.js +1 -0
  66. package/dist/assets/isArrayLikeObject-69BLnVNM.js +1 -0
  67. package/dist/assets/isEmpty-DUS28g5f.js +1 -0
  68. package/dist/assets/ishikawaDiagram-UXIWVN3A-BrIoEvtb.js +70 -0
  69. package/dist/assets/journeyDiagram-VCZTEJTY-aZpvKa9g.js +139 -0
  70. package/dist/assets/kanban-definition-6JOO6SKY-CoOAY9ji.js +89 -0
  71. package/dist/assets/katex-5SGEXwpi.js +261 -0
  72. package/dist/assets/line-4MF1lR4d.js +1 -0
  73. package/dist/assets/linear-CXMqTN8N.js +1 -0
  74. package/dist/assets/mermaid-config-C8a4L22x.js +1 -0
  75. package/dist/assets/mermaid-parser.core-DREsY2u4.js +4 -0
  76. package/dist/assets/mermaid.core-8ysLpTJi.js +11 -0
  77. package/dist/assets/mindmap-definition-QFDTVHPH-CsqUJCMn.js +96 -0
  78. package/dist/assets/ordinal-D7l-8DAO.js +1 -0
  79. package/dist/assets/packet-4T2RLAQJ-DidW3JFc.js +1 -0
  80. package/dist/assets/path-BVpCanzE.js +1 -0
  81. package/dist/assets/pie-ZZUOXDRM-Bff2e5hg.js +1 -0
  82. package/dist/assets/pieDiagram-DEJITSTG-k0Br4NDS.js +30 -0
  83. package/dist/assets/quadrantDiagram-34T5L4WZ-Be9oCSza.js +7 -0
  84. package/dist/assets/radar-PYXPWWZC-CsdZBH3M.js +1 -0
  85. package/dist/assets/requirementDiagram-MS252O5E-8ECT7dEs.js +84 -0
  86. package/dist/assets/rough.esm-BoTisKeL.js +1 -0
  87. package/dist/assets/sankeyDiagram-XADWPNL6-CoKpeJJ0.js +10 -0
  88. package/dist/assets/sequenceDiagram-FGHM5R23-BTT2fFxG.js +157 -0
  89. package/dist/assets/src-CrmkjRpa.js +1 -0
  90. package/dist/assets/stateDiagram-FHFEXIEX-CIF47NYe.js +1 -0
  91. package/dist/assets/stateDiagram-v2-QKLJ7IA2-Cy1rmPfG.js +1 -0
  92. package/dist/assets/timeline-definition-GMOUNBTQ-Bes4B58n.js +120 -0
  93. package/dist/assets/treeView-SZITEDCU-DPKseaET.js +1 -0
  94. package/dist/assets/treemap-W4RFUUIX-DH-7GZe_.js +1 -0
  95. package/dist/assets/vennDiagram-DHZGUBPP-3wx2huKk.js +34 -0
  96. package/dist/assets/wardley-RL74JXVD-AgyXyBN5.js +1 -0
  97. package/dist/assets/wardleyDiagram-NUSXRM2D-DzViT1Yx.js +20 -0
  98. package/dist/assets/xychartDiagram-5P7HB3ND-BO_dbU0r.js +7 -0
  99. package/{index.html → dist/index.html} +2 -1
  100. package/dist/index.js +2625 -0
  101. package/package.json +11 -1
  102. package/.agents/skills/remotion-best-practices/SKILL.md +0 -61
  103. package/.agents/skills/remotion-best-practices/rules/3d.md +0 -86
  104. package/.agents/skills/remotion-best-practices/rules/animations.md +0 -27
  105. package/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +0 -178
  106. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +0 -100
  107. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +0 -108
  108. package/.agents/skills/remotion-best-practices/rules/assets.md +0 -78
  109. package/.agents/skills/remotion-best-practices/rules/audio-visualization.md +0 -198
  110. package/.agents/skills/remotion-best-practices/rules/audio.md +0 -169
  111. package/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +0 -134
  112. package/.agents/skills/remotion-best-practices/rules/can-decode.md +0 -75
  113. package/.agents/skills/remotion-best-practices/rules/charts.md +0 -120
  114. package/.agents/skills/remotion-best-practices/rules/compositions.md +0 -154
  115. package/.agents/skills/remotion-best-practices/rules/display-captions.md +0 -184
  116. package/.agents/skills/remotion-best-practices/rules/extract-frames.md +0 -229
  117. package/.agents/skills/remotion-best-practices/rules/ffmpeg.md +0 -38
  118. package/.agents/skills/remotion-best-practices/rules/fonts.md +0 -152
  119. package/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +0 -58
  120. package/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +0 -68
  121. package/.agents/skills/remotion-best-practices/rules/get-video-duration.md +0 -60
  122. package/.agents/skills/remotion-best-practices/rules/gifs.md +0 -141
  123. package/.agents/skills/remotion-best-practices/rules/images.md +0 -134
  124. package/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +0 -69
  125. package/.agents/skills/remotion-best-practices/rules/light-leaks.md +0 -73
  126. package/.agents/skills/remotion-best-practices/rules/lottie.md +0 -70
  127. package/.agents/skills/remotion-best-practices/rules/maps.md +0 -412
  128. package/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +0 -34
  129. package/.agents/skills/remotion-best-practices/rules/measuring-text.md +0 -140
  130. package/.agents/skills/remotion-best-practices/rules/parameters.md +0 -109
  131. package/.agents/skills/remotion-best-practices/rules/sequencing.md +0 -118
  132. package/.agents/skills/remotion-best-practices/rules/sfx.md +0 -26
  133. package/.agents/skills/remotion-best-practices/rules/subtitles.md +0 -36
  134. package/.agents/skills/remotion-best-practices/rules/tailwind.md +0 -11
  135. package/.agents/skills/remotion-best-practices/rules/text-animations.md +0 -20
  136. package/.agents/skills/remotion-best-practices/rules/timing.md +0 -179
  137. package/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +0 -70
  138. package/.agents/skills/remotion-best-practices/rules/transitions.md +0 -197
  139. package/.agents/skills/remotion-best-practices/rules/transparent-videos.md +0 -106
  140. package/.agents/skills/remotion-best-practices/rules/trimming.md +0 -51
  141. package/.agents/skills/remotion-best-practices/rules/videos.md +0 -171
  142. package/.agents/skills/remotion-best-practices/rules/voiceover.md +0 -99
  143. package/.agents/skills/simple/SKILL.md +0 -52
  144. package/.agents/skills/vercel-react-best-practices/AGENTS.md +0 -3254
  145. package/.agents/skills/vercel-react-best-practices/README.md +0 -123
  146. package/.agents/skills/vercel-react-best-practices/SKILL.md +0 -141
  147. package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  148. package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  149. package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  150. package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  151. package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  152. package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  153. package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  154. package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  155. package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  156. package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  157. package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  158. package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  159. package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  160. package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  161. package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  162. package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  163. package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  164. package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  165. package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  166. package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  167. package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  168. package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  169. package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  170. package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  171. package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  172. package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  173. package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  174. package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  175. package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  176. package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  177. package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  178. package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  179. package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  180. package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  181. package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  182. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  183. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  184. package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  185. package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  186. package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  187. package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  188. package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  189. package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  190. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  191. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  192. package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  193. package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  194. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  195. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  196. package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  197. package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  198. package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  199. package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  200. package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  201. package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  202. package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  203. package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  204. package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  205. package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  206. package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
  207. package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  208. package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  209. package/.claude/CLAUDE.md +0 -184
  210. package/.claude/commands/review.md +0 -120
  211. package/.claude/commands/sync-docs.md +0 -71
  212. package/.claude/roadmap.md +0 -121
  213. package/.claude/rules/style-guide.md +0 -830
  214. package/.claude/settings.json +0 -18
  215. package/.claude/user-stories.md +0 -333
  216. package/AGENTS.md +0 -68
  217. package/Makefile +0 -32
  218. package/biome.json +0 -79
  219. package/bun.lock +0 -854
  220. package/bunfig.toml +0 -2
  221. package/docs/design.md +0 -563
  222. package/docs/perf-baseline.md +0 -130
  223. package/docs/plans/2026-03-13-client-mode-design.md +0 -86
  224. package/docs/plans/2026-03-13-client-mode-plan.md +0 -605
  225. package/docs/plans/2026-03-13-keyboard-shortcuts-design.md +0 -129
  226. package/docs/plans/2026-03-13-keyboard-shortcuts-plan.md +0 -1471
  227. package/docs/plans/2026-03-13-multi-document-design.md +0 -183
  228. package/docs/plans/2026-03-13-performance-benchmarks-design.md +0 -121
  229. package/docs/superpowers/plans/2026-03-26-surgical-pruning.md +0 -1176
  230. package/docs/superpowers/specs/2026-03-27-go-server-rewrite-design.md +0 -284
  231. package/e2e/comments.spec.ts +0 -81
  232. package/e2e/document-load.spec.ts +0 -32
  233. package/e2e/export.spec.ts +0 -58
  234. package/e2e/fixtures/sample.md +0 -7
  235. package/e2e/perf/add-comment.spec.ts +0 -116
  236. package/e2e/perf/fixtures/generate.ts +0 -327
  237. package/e2e/perf/initial-load.spec.ts +0 -49
  238. package/e2e/perf/perf.setup.ts +0 -23
  239. package/e2e/perf/perf.teardown.ts +0 -9
  240. package/e2e/perf/screenshot-final.png +0 -0
  241. package/e2e/perf/scroll.spec.ts +0 -39
  242. package/e2e/perf/tab-switch.spec.ts +0 -69
  243. package/e2e/perf/text-selection.spec.ts +0 -119
  244. package/e2e/perf/utils/metrics.ts +0 -350
  245. package/e2e/perf/utils/perf-cli.ts +0 -86
  246. package/e2e/persistence-file.spec.ts +0 -357
  247. package/e2e/utils/cli.ts +0 -84
  248. package/e2e/utils/selection.ts +0 -79
  249. package/go/cmd/readit/main.go +0 -416
  250. package/go/go.mod +0 -20
  251. package/go/go.sum +0 -41
  252. package/go/internal/server/anchor.go +0 -302
  253. package/go/internal/server/anchor_test.go +0 -111
  254. package/go/internal/server/comments.go +0 -390
  255. package/go/internal/server/documents.go +0 -113
  256. package/go/internal/server/embed.go +0 -17
  257. package/go/internal/server/headings.go +0 -33
  258. package/go/internal/server/headings_test.go +0 -75
  259. package/go/internal/server/htmltext.go +0 -123
  260. package/go/internal/server/markdown.go +0 -157
  261. package/go/internal/server/markdown_bench_test.go +0 -42
  262. package/go/internal/server/markdown_test.go +0 -79
  263. package/go/internal/server/server.go +0 -453
  264. package/go/internal/server/server_bench_test.go +0 -122
  265. package/go/internal/server/settings.go +0 -110
  266. package/go/internal/server/sse.go +0 -140
  267. package/go/internal/server/storage.go +0 -275
  268. package/go/internal/server/storage_test.go +0 -152
  269. package/go/internal/server/template.go +0 -66
  270. package/go/internal/server/types.go +0 -101
  271. package/go/internal/server/watcher.go +0 -74
  272. package/lefthook.yml +0 -8
  273. package/nvim-readit/lua/readit/health.lua +0 -64
  274. package/nvim-readit/lua/readit/init.lua +0 -463
  275. package/nvim-readit/plugin/readit.lua +0 -19
  276. package/playwright.config.ts +0 -34
  277. package/skills-lock.json +0 -20
  278. package/src/App.svelte +0 -890
  279. package/src/cli.ts +0 -881
  280. package/src/components/ActionsMenu.svelte +0 -95
  281. package/src/components/CommentBadge.svelte +0 -67
  282. package/src/components/CommentErrorBanner.svelte +0 -33
  283. package/src/components/CommentInput.svelte +0 -75
  284. package/src/components/CommentListItem.svelte +0 -95
  285. package/src/components/CommentManager.svelte +0 -129
  286. package/src/components/CommentNav.svelte +0 -109
  287. package/src/components/DocumentViewer.svelte +0 -233
  288. package/src/components/FloatingComment.svelte +0 -107
  289. package/src/components/Header.svelte +0 -76
  290. package/src/components/InlineEditor.svelte +0 -72
  291. package/src/components/MarginNote.svelte +0 -167
  292. package/src/components/MarginNotesContainer.svelte +0 -33
  293. package/src/components/MermaidEnhancer.svelte +0 -218
  294. package/src/components/MermaidModal.svelte +0 -67
  295. package/src/components/RawModal.svelte +0 -126
  296. package/src/components/ReanchorConfirm.svelte +0 -30
  297. package/src/components/SettingsModal.svelte +0 -220
  298. package/src/components/ShortcutCapture.svelte +0 -82
  299. package/src/components/ShortcutList.svelte +0 -145
  300. package/src/components/TabBar.svelte +0 -52
  301. package/src/components/TableOfContents.svelte +0 -125
  302. package/src/components/ui/ActionLink.svelte +0 -40
  303. package/src/components/ui/Button.svelte +0 -53
  304. package/src/components/ui/Dialog.svelte +0 -97
  305. package/src/components/ui/DropdownMenu.svelte +0 -85
  306. package/src/components/ui/DropdownMenuItem.svelte +0 -38
  307. package/src/components/ui/DropdownMenuSeparator.svelte +0 -11
  308. package/src/components/ui/Text.svelte +0 -42
  309. package/src/env.d.ts +0 -6
  310. package/src/index.css +0 -859
  311. package/src/lib/__fixtures__/bench-data.ts +0 -114
  312. package/src/lib/anchor.bench.ts +0 -91
  313. package/src/lib/anchor.test.ts +0 -527
  314. package/src/lib/anchor.ts +0 -381
  315. package/src/lib/comment-storage.bench.ts +0 -49
  316. package/src/lib/comment-storage.test.ts +0 -694
  317. package/src/lib/comment-storage.ts +0 -226
  318. package/src/lib/export.bench.ts +0 -21
  319. package/src/lib/export.ts +0 -36
  320. package/src/lib/fetch-or-throw.test.ts +0 -59
  321. package/src/lib/fetch-or-throw.ts +0 -12
  322. package/src/lib/headings.test.ts +0 -103
  323. package/src/lib/headings.ts +0 -44
  324. package/src/lib/highlight/core.test.ts +0 -93
  325. package/src/lib/highlight/dom.ts +0 -187
  326. package/src/lib/highlight/highlight-registry.ts +0 -221
  327. package/src/lib/highlight/highlight.bench.ts +0 -92
  328. package/src/lib/highlight/highlighter.ts +0 -247
  329. package/src/lib/highlight/resolver.ts +0 -38
  330. package/src/lib/highlight/types.ts +0 -17
  331. package/src/lib/html-text.test.ts +0 -162
  332. package/src/lib/html-text.ts +0 -161
  333. package/src/lib/i18n/en.ts +0 -124
  334. package/src/lib/i18n/index.ts +0 -3
  335. package/src/lib/i18n/ja.ts +0 -126
  336. package/src/lib/i18n/translations.ts +0 -27
  337. package/src/lib/i18n/types.ts +0 -130
  338. package/src/lib/key-lock.test.ts +0 -104
  339. package/src/lib/key-lock.ts +0 -23
  340. package/src/lib/margin-layout.bench.ts +0 -61
  341. package/src/lib/margin-layout.ts +0 -71
  342. package/src/lib/markdown-renderer.test.ts +0 -154
  343. package/src/lib/markdown-renderer.ts +0 -178
  344. package/src/lib/mermaid-config.ts +0 -38
  345. package/src/lib/mermaid-renderer.ts +0 -162
  346. package/src/lib/mermaid-worker.ts +0 -60
  347. package/src/lib/positions.ts +0 -157
  348. package/src/lib/shortcut-registry.ts +0 -244
  349. package/src/lib/utils.ts +0 -15
  350. package/src/main.ts +0 -16
  351. package/src/schema.ts +0 -92
  352. package/src/server.ts +0 -1216
  353. package/src/stores/app.svelte.ts +0 -231
  354. package/src/stores/locale.svelte.ts +0 -46
  355. package/src/stores/settings.svelte.ts +0 -90
  356. package/src/stores/shortcuts.svelte.ts +0 -104
  357. package/src/stores/ui.svelte.ts +0 -12
  358. package/src/template.ts +0 -104
  359. package/src/test-setup.ts +0 -48
  360. package/svelte.config.js +0 -5
  361. package/test.md +0 -74
  362. package/tsconfig.cli.json +0 -12
  363. package/tsconfig.json +0 -20
  364. package/vite.config.ts +0 -47
  365. package/vitest.config.ts +0 -15
  366. package/vscode-readit/.mcp.json +0 -7
  367. package/vscode-readit/.vscodeignore +0 -7
  368. package/vscode-readit/bun.lock +0 -78
  369. package/vscode-readit/icon.svg +0 -10
  370. package/vscode-readit/package.json +0 -110
  371. package/vscode-readit/src/extension.ts +0 -117
  372. package/vscode-readit/src/server-manager.ts +0 -272
  373. package/vscode-readit/src/webview-provider.ts +0 -204
  374. package/vscode-readit/tsconfig.json +0 -20
@@ -1,284 +0,0 @@
1
- # Go Server Rewrite Design Spec
2
-
3
- ## Summary
4
-
5
- Rewrite readit's server and CLI from Bun/TypeScript to Go. The Svelte 5 frontend stays unchanged. Go handles all heavy computation (markdown rendering, syntax highlighting, comment storage, file watching, SSE) while Svelte handles client-side interactivity (highlights, margin notes, comment CRUD UI).
6
-
7
- ## Motivation
8
-
9
- The current Bun server's cold-start path is dominated by Shiki WASM initialization (80-200ms) and the JSDOM mermaid worker (2-5s). A compiled Go binary with native libraries eliminates both bottlenecks:
10
-
11
- - Process startup: 30-50ms (Bun) → <1ms (Go binary)
12
- - Syntax highlighting init: 80-200ms (Shiki WASM) → 0ms (chroma, compiled in)
13
- - Markdown render (3000 lines): 5-20ms (markdown-it) → <1ms (goldmark)
14
- - Single binary distribution, no node_modules runtime dependency
15
-
16
- Target: 50-100x improvement on server-side TTFB.
17
-
18
- ## Architecture
19
-
20
- ```
21
- readit/
22
- ├── go/
23
- │ ├── cmd/readit/main.go # CLI entry point
24
- │ ├── internal/server/
25
- │ │ ├── server.go # Mux setup, static serving, dev proxy
26
- │ │ ├── documents.go # Document routes + file state
27
- │ │ ├── comments.go # Comment CRUD routes
28
- │ │ ├── settings.go # Settings routes
29
- │ │ ├── sse.go # SSE broker, heartbeat, shutdown timer
30
- │ │ ├── markdown.go # goldmark + chroma rendering
31
- │ │ ├── headings.go # AST-based heading extraction
32
- │ │ ├── storage.go # .comments.md parse/serialize
33
- │ │ ├── anchor.go # Anchor resolution + fuzzy matching
34
- │ │ ├── watcher.go # fsnotify file watching + debounce
35
- │ │ ├── template.go # HTML page template
36
- │ │ ├── types.go # Shared types
37
- │ │ └── embed.go # go:embed dist/ assets
38
- │ ├── go.mod
39
- │ └── go.sum
40
- ├── src/ # Svelte frontend (unchanged)
41
- ├── dist/ # Vite build output (Go embeds this)
42
- ├── Makefile
43
- ├── vite.config.ts
44
- └── package.json
45
- ```
46
-
47
- Single Go package (`internal/server`) with flat files. `cmd/readit/main.go` calls `server.Start(opts)`. No nested packages, no interface indirection.
48
-
49
- ## Decisions
50
-
51
- | Decision | Choice | Rationale |
52
- |----------|--------|-----------|
53
- | Language | Go | goldmark+chroma ecosystem, fast dev velocity, single binary |
54
- | Repo structure | Monorepo (`go/` + `src/`) | Shared build pipeline, colocated frontend |
55
- | Asset serving | `go:embed` + `--assets-dir` override | Single binary for production, filesystem for dev |
56
- | Mermaid | Client-only with `<link rel="modulepreload">` | Eliminates JSDOM complexity, door open for server-side later |
57
- | Dev workflow | `make dev` — Go manages Vite child process | Single command, Go proxies to Vite for HMR |
58
- | Comment format | Keep `.comments.md` unchanged | Backward compatible, simple to parse in Go |
59
- | File support | Markdown only | Tight scope for v1 |
60
- | HTTP router | `net/http.ServeMux` (Go 1.22+) | Method+pattern routing, no framework dependency |
61
- | CLI parsing | `flag` package | Simple subcommands, no cobra overhead |
62
-
63
- ## Server Core
64
-
65
- The `Server` struct holds all shared state:
66
-
67
- ```go
68
- type Server struct {
69
- mux *http.ServeMux
70
- files map[string]*FileState
71
- fileOrder []string
72
- sse *SSEBroker
73
- watcher *Watcher
74
- renderer *Renderer
75
- settings Settings
76
- workingDir string
77
- clean bool
78
- assetsFS fs.FS
79
- template *template.Template
80
- mu sync.RWMutex
81
- }
82
- ```
83
-
84
- Routes registered as methods on `Server` — no handler interfaces, no middleware chain. Dev mode proxies non-API requests to Vite at `localhost:24678`.
85
-
86
- ## API Contract
87
-
88
- The Go server implements the exact same API the Svelte frontend consumes. No changes to request/response shapes.
89
-
90
- ### Document Routes (`documents.go`)
91
-
92
- | Method | Path | Purpose |
93
- |--------|------|---------|
94
- | GET | `/api/documents` | List open files |
95
- | POST | `/api/documents` | Add file to session |
96
- | GET | `/api/document?path=` | Get rendered HTML + headings |
97
-
98
- ### Comment Routes (`comments.go`)
99
-
100
- | Method | Path | Purpose |
101
- |--------|------|---------|
102
- | GET | `/api/comments?path=` | List comments (with anchor resolution) |
103
- | POST | `/api/comments?path=` | Create comment |
104
- | PUT | `/api/comments/{id}?path=` | Update comment text |
105
- | DELETE | `/api/comments/{id}?path=` | Delete comment |
106
- | DELETE | `/api/comments?path=` | Delete all comments |
107
- | PUT | `/api/comments/{id}/reanchor?path=` | Reanchor comment |
108
- | GET | `/api/comments/raw?path=` | Raw .comments.md content |
109
-
110
- ### Settings Routes (`settings.go`)
111
-
112
- | Method | Path | Purpose |
113
- |--------|------|---------|
114
- | GET | `/api/settings` | Read settings |
115
- | PUT | `/api/settings` | Update font family |
116
-
117
- ### SSE Endpoints (`sse.go`)
118
-
119
- | Method | Path | Purpose |
120
- |--------|------|---------|
121
- | GET | `/api/document/stream` | Document change events |
122
- | GET | `/api/heartbeat` | Keep-alive, manages auto-shutdown |
123
-
124
- ### Other
125
-
126
- | Method | Path | Purpose |
127
- |--------|------|---------|
128
- | GET | `/api/health` | Health check (`{"status":"ok"}`) |
129
- | GET | `/` | SSR page with inline data |
130
- | GET | `/assets/*` | Static assets (embedded or filesystem) |
131
-
132
- ### Inline Data Shape
133
-
134
- The root page embeds JSON in `<script type="application/json" id="__readit">`:
135
-
136
- ```json
137
- {
138
- "files": [{"path": "...", "fileName": "..."}],
139
- "activeFile": "...",
140
- "clean": false,
141
- "workingDirectory": "...",
142
- "documents": {
143
- "/path/to/file.md": {
144
- "html": "...",
145
- "headings": [{"id": "...", "text": "...", "level": 1}],
146
- "comments": [...]
147
- }
148
- },
149
- "settings": {"version": 1, "fontFamily": "serif"}
150
- }
151
- ```
152
-
153
- ## Markdown Pipeline (`markdown.go` + `headings.go`)
154
-
155
- goldmark with extensions, configured once at startup:
156
-
157
- - **GFM**: tables, strikethrough, autolinks, task lists
158
- - **Chroma highlighting**: `onedark` style, CSS classes (not inline styles)
159
- - **Auto heading IDs**: generated from heading text
160
- - **Unsafe HTML**: raw HTML passthrough (matches current behavior)
161
-
162
- Heading extraction walks the goldmark AST directly instead of regex.
163
-
164
- Mermaid fenced code blocks pass through as `<pre><code class="language-mermaid">`. The Svelte frontend's `DocumentViewer.svelte` hydrates these client-side via lazy `import("mermaid")`. A `<link rel="modulepreload">` hint in the template accelerates the mermaid chunk download.
165
-
166
- ## Comment Storage (`storage.go` + `anchor.go`)
167
-
168
- Parses and serializes the existing `.comments.md` format unchanged:
169
-
170
- - Storage path: `~/.readit/comments/<mirrored-path>.comments.md`
171
- - Format: YAML frontmatter (`source`, `hash`, `version`) + comment blocks separated by `---`
172
- - Atomic writes: temp file + `os.Rename`
173
- - Hash: SHA-256 of source content, truncated to 16 hex chars
174
-
175
- Anchor resolution algorithm (direct port):
176
-
177
- 1. Exact match near `lineHint` position
178
- 2. Exact match anywhere in source
179
- 3. Normalized match (collapse whitespace)
180
- 4. Mark as `unresolved`
181
-
182
- Two-key cache: comment file mtime + source content hash. Skip re-parsing when neither changed.
183
-
184
- ## SSE & File Watching (`sse.go` + `watcher.go`)
185
-
186
- SSE broker manages two client sets:
187
-
188
- - **Document stream clients**: receive `document-updated` and `document-added` events
189
- - **Heartbeat clients**: keep-alive pings, manage auto-shutdown timer (1.5s grace after last client disconnects, production only)
190
-
191
- File watcher uses `fsnotify` with 100ms debounce per file. On change: invalidate render cache → invalidate comment cache → broadcast SSE event.
192
-
193
- ## CLI (`cmd/readit/main.go`)
194
-
195
- Subcommands:
196
-
197
- - `readit <file.md> [flags]` — start server + open browser
198
- - `readit list` — list files with comments (stdout)
199
- - `readit show <file.md>` — print comments for file (stdout)
200
- - `readit open <file.md>` — attach to running server or start new one
201
-
202
- Flags:
203
-
204
- - `--port` (default: random available)
205
- - `--host` (default: `127.0.0.1`)
206
- - `--no-open` (skip browser launch)
207
- - `--clean` (clear existing comments)
208
- - `--assets-dir` (override embedded assets)
209
- - `--dev` (spawn Vite child process, proxy to it)
210
-
211
- Server discovery: `~/.readit/server.json` with PID liveness check + HTTP health check. File lock (`server.lock`) prevents race conditions.
212
-
213
- ## Build & Dev Workflow
214
-
215
- ```makefile
216
- dev: # Go spawns Vite child process, single command
217
- build: # bun vite build → go build (embeds dist/)
218
- test: # go test ./...
219
- test-client: # bun run test
220
- test-e2e: # playwright
221
- ```
222
-
223
- Dev mode: `make dev` → Go runs with `--dev`, spawns `bunx vite` on port 24678, proxies non-API requests. Ctrl+C kills both.
224
-
225
- Production build: `make build` → Vite builds frontend into `dist/`, then `go build` embeds `dist/` into the binary.
226
-
227
- ## Types (`types.go`)
228
-
229
- ```go
230
- type Comment struct {
231
- ID string `json:"id"`
232
- SelectedText string `json:"selectedText"`
233
- Comment string `json:"comment"`
234
- StartOffset int `json:"startOffset"`
235
- EndOffset int `json:"endOffset"`
236
- CreatedAt string `json:"createdAt"`
237
- LineHint string `json:"lineHint,omitempty"`
238
- AnchorConfidence string `json:"anchorConfidence,omitempty"`
239
- AnchorPrefix string `json:"anchorPrefix,omitempty"`
240
- }
241
-
242
- type Heading struct {
243
- ID string `json:"id"`
244
- Text string `json:"text"`
245
- Level int `json:"level"`
246
- }
247
-
248
- type FileState struct {
249
- FilePath string
250
- FileName string
251
- Content []byte
252
- RenderedHTML string
253
- Headings []Heading
254
- mu sync.Mutex
255
- }
256
-
257
- type Settings struct {
258
- Version int `json:"version"`
259
- FontFamily string `json:"fontFamily"`
260
- }
261
- ```
262
-
263
- JSON tags match the current API responses exactly.
264
-
265
- ## Go Dependencies
266
-
267
- | Package | Purpose |
268
- |---------|---------|
269
- | `github.com/yuin/goldmark` | Markdown → HTML |
270
- | `github.com/yuin/goldmark-highlighting/v2` | Chroma integration for goldmark |
271
- | `github.com/alecthomas/chroma/v2` | Syntax highlighting (native Go) |
272
- | `github.com/fsnotify/fsnotify` | Cross-platform file watching |
273
- | `github.com/pkg/browser` | Cross-platform browser launch |
274
-
275
- Five dependencies total. No HTTP framework, no CLI framework.
276
-
277
- ## Migration Path
278
-
279
- 1. Build Go server implementing the full API contract
280
- 2. Verify Svelte frontend works unchanged against Go server
281
- 3. Run existing E2E perf tests, compare against React/Svelte baselines
282
- 4. Remove `src/server.ts`, `src/cli.ts`, `src/lib/markdown-renderer.ts`, `src/lib/mermaid-worker.ts`, `src/lib/mermaid-renderer.ts`, `src/lib/comment-storage.ts`, `src/lib/anchor.ts`, related server-side code
283
- 5. Update `package.json` scripts to use Makefile
284
- 6. Remove server-side JS dependencies (`shiki`, `markdown-it`, `jsdom`, `mermaid`, `commander`)
@@ -1,81 +0,0 @@
1
- import { existsSync, rmSync } from "node:fs";
2
- import * as os from "node:os";
3
- import { join, resolve } from "node:path";
4
- import { expect, test } from "@playwright/test";
5
- import { spawnCli } from "./utils/cli";
6
- import { addComment, selectTextInArticle } from "./utils/selection";
7
-
8
- const FIXTURES_DIR = resolve(import.meta.dirname, "fixtures");
9
-
10
- /**
11
- * Get the expected comment file path for a source file.
12
- */
13
- function getCommentPath(sourcePath: string): string {
14
- const absolute = resolve(sourcePath);
15
- const normalized = absolute.replace(/^\//, "").replace(/^[A-Z]:[\\/]/, "");
16
- const ext = normalized.lastIndexOf(".");
17
- const withoutExt = ext > 0 ? normalized.slice(0, ext) : normalized;
18
- return join(os.homedir(), ".readit", "comments", `${withoutExt}.comments.md`);
19
- }
20
-
21
- /**
22
- * Clean up comment file for a source file.
23
- */
24
- function cleanupCommentFile(sourcePath: string): void {
25
- const commentPath = getCommentPath(sourcePath);
26
- if (existsSync(commentPath)) {
27
- rmSync(commentPath);
28
- }
29
- }
30
-
31
- test.describe("Comment Creation", () => {
32
- const sampleMdPath = resolve(FIXTURES_DIR, "sample.md");
33
-
34
- test.beforeEach(() => {
35
- cleanupCommentFile(sampleMdPath);
36
- });
37
-
38
- test.afterEach(() => {
39
- cleanupCommentFile(sampleMdPath);
40
- });
41
-
42
- test("adds comment to selected text in markdown document", async ({
43
- page,
44
- }) => {
45
- const { url, cleanup } = await spawnCli(sampleMdPath, { port: 4572 });
46
-
47
- try {
48
- await page.goto(url);
49
-
50
- // Wait for document to load
51
- const article = page.locator("article#document-content");
52
- await expect(article).toBeVisible();
53
-
54
- // Select text in the article
55
- const textToSelect = "testing text selection";
56
- await selectTextInArticle(page, textToSelect);
57
-
58
- // Add a comment
59
- const commentText = "This is my test comment";
60
- await addComment(page, commentText);
61
-
62
- // Verify: highlight exists via CSS Custom Highlight API observability hook
63
- await page.waitForFunction(
64
- () => {
65
- const h = (window as unknown as Record<string, unknown>)
66
- .__readitHighlights as { commentIds: string[] } | undefined;
67
- return h && h.commentIds.length > 0;
68
- },
69
- { timeout: 10_000 },
70
- );
71
-
72
- // Verify the selected text is still visible in the article
73
- await expect(article).toContainText(textToSelect);
74
-
75
- // Verify: margin note shows the comment
76
- await expect(page.locator("body")).toContainText(commentText);
77
- } finally {
78
- await cleanup();
79
- }
80
- });
81
- });
@@ -1,32 +0,0 @@
1
- import { resolve } from "node:path";
2
- import { expect, test } from "@playwright/test";
3
- import { spawnCli } from "./utils/cli";
4
-
5
- const FIXTURES_DIR = resolve(import.meta.dirname, "fixtures");
6
-
7
- test.describe("Document Loading", () => {
8
- test("loads markdown document and displays content", async ({ page }) => {
9
- const { url, cleanup } = await spawnCli(
10
- resolve(FIXTURES_DIR, "sample.md"),
11
- { port: 4570 },
12
- );
13
-
14
- try {
15
- await page.goto(url);
16
-
17
- // Wait for document to load - use article scope to avoid header h1
18
- const article = page.locator("article#document-content");
19
- await expect(article.locator("h1")).toContainText("Test Document");
20
-
21
- // Verify paragraph content is rendered
22
- await expect(article).toContainText(
23
- "This is a paragraph for testing text selection",
24
- );
25
-
26
- // Verify second section is visible
27
- await expect(article.locator("h2")).toContainText("Second Section");
28
- } finally {
29
- await cleanup();
30
- }
31
- });
32
- });
@@ -1,58 +0,0 @@
1
- import { resolve } from "node:path";
2
- import { expect, test } from "@playwright/test";
3
- import { spawnCli } from "./utils/cli";
4
- import { addComment, selectTextInArticle } from "./utils/selection";
5
-
6
- const FIXTURES_DIR = resolve(import.meta.dirname, "fixtures");
7
-
8
- test.describe("Comment Export", () => {
9
- test("Copy All generates valid prompt format", async ({ page, context }) => {
10
- // Grant clipboard permissions
11
- await context.grantPermissions(["clipboard-read", "clipboard-write"]);
12
-
13
- const { url, cleanup } = await spawnCli(
14
- resolve(FIXTURES_DIR, "sample.md"),
15
- { port: 4590 },
16
- );
17
-
18
- try {
19
- await page.goto(url);
20
-
21
- // Wait for document to load
22
- const article = page.locator("article#document-content");
23
- await expect(article).toBeVisible();
24
-
25
- // Add a comment
26
- const textToSelect = "testing text selection";
27
- const commentText = "This is my review comment";
28
- await selectTextInArticle(page, textToSelect);
29
- await addComment(page, commentText);
30
-
31
- // Verify comment was added
32
- await expect(page.locator("body")).toContainText(commentText);
33
-
34
- // Open the actions menu and click "Copy All"
35
- const menuButton = page.getByRole("button", { name: /actions menu/i });
36
- await menuButton.click();
37
-
38
- const copyButton = page.getByRole("menuitem", { name: /copy all/i });
39
- await copyButton.click();
40
-
41
- // Read clipboard content
42
- const clipboardContent = await page.evaluate(() =>
43
- navigator.clipboard.readText(),
44
- );
45
-
46
- // Verify the format contains expected parts
47
- expect(clipboardContent).toContain("# Review Comments for sample.md");
48
- expect(clipboardContent).toContain(textToSelect);
49
- expect(clipboardContent).toContain(commentText);
50
-
51
- // Verify it follows the prompt format (quoted selected text + comment)
52
- expect(clipboardContent).toMatch(/"testing text selection"/);
53
- expect(clipboardContent).toContain("This is my review comment");
54
- } finally {
55
- await cleanup();
56
- }
57
- });
58
- });
@@ -1,7 +0,0 @@
1
- # Test Document
2
-
3
- This is a paragraph for testing text selection.
4
-
5
- ## Second Section
6
-
7
- Here is another paragraph with some more text to select and comment on.
@@ -1,116 +0,0 @@
1
- import { expect, test } from "@playwright/test";
2
- import { getFixturePath, TIERS } from "./fixtures/generate";
3
- import {
4
- measureInteraction,
5
- reportInteraction,
6
- waitForHighlightCount,
7
- } from "./utils/metrics";
8
- import { spawnPerfCli } from "./utils/perf-cli";
9
-
10
- // Use the medium tier — most representative of real usage
11
- const tier = TIERS[0];
12
-
13
- test(`add-comment: ${tier.name} (${tier.lines} lines, ${tier.comments} comments)`, async ({
14
- page,
15
- }, testInfo) => {
16
- const fixturePath = getFixturePath(tier);
17
- const { url, cleanup } = await spawnPerfCli(fixturePath, { port: 4620 });
18
-
19
- try {
20
- await page.goto(url);
21
- await waitForHighlightCount(page, tier.comments);
22
- await page.waitForTimeout(300);
23
-
24
- // Capture actual highlight count as baseline (may differ from tier.comments)
25
- const baselineCount = await page.evaluate(() => {
26
- const h = (window as unknown as Record<string, unknown>)
27
- .__readitHighlights as { commentIds: string[] } | undefined;
28
- return h?.commentIds?.length ?? 0;
29
- });
30
-
31
- // Find a text that isn't already highlighted — use a line near the end
32
- const selectionText = await page.evaluate(() => {
33
- const article = document.querySelector("article");
34
- if (!article) throw new Error("Article not found");
35
-
36
- // Find paragraph text near the bottom of the document
37
- const paragraphs = article.querySelectorAll("p");
38
- const target = paragraphs[paragraphs.length - 2];
39
- if (!target?.textContent) throw new Error("No paragraph found");
40
-
41
- // Use first 30 chars
42
- return target.textContent.slice(0, 30).trim();
43
- });
44
-
45
- // Select text via custom event
46
- await page.evaluate((text) => {
47
- const article = document.querySelector("article");
48
- if (!article) throw new Error("Article not found");
49
-
50
- const walker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
51
- let currentOffset = 0;
52
-
53
- while (walker.nextNode()) {
54
- const textNode = walker.currentNode as Text;
55
- const content = textNode.textContent || "";
56
- const index = content.indexOf(text);
57
-
58
- if (index !== -1) {
59
- const startOffset = currentOffset + index;
60
- const endOffset = startOffset + text.length;
61
- window.dispatchEvent(
62
- new CustomEvent("test:select-text", {
63
- detail: { text, startOffset, endOffset },
64
- }),
65
- );
66
- return;
67
- }
68
-
69
- currentOffset += content.length;
70
- }
71
-
72
- throw new Error(`Text "${text}" not found`);
73
- }, selectionText);
74
-
75
- // Wait for comment input to appear
76
- const textarea = page.locator(
77
- 'textarea[placeholder="Add your comment..."]',
78
- );
79
- await textarea.waitFor({ state: "visible", timeout: 10_000 });
80
-
81
- // Fill in the comment
82
- await textarea.fill("Performance benchmark comment");
83
-
84
- // Mark start and click Add
85
- const duration = await measureInteraction(
86
- page,
87
- "add-comment",
88
- async () => {
89
- await page.getByRole("button", { name: "Add" }).click();
90
- },
91
- async () => {
92
- await page.waitForFunction((expected) => {
93
- const h = (window as unknown as Record<string, unknown>)
94
- .__readitHighlights as { commentIds: string[] } | undefined;
95
- return (h?.commentIds?.length ?? 0) > expected;
96
- }, baselineCount);
97
- },
98
- );
99
-
100
- reportInteraction(
101
- testInfo,
102
- `add-comment: time to new highlight (${tier.name})`,
103
- duration,
104
- );
105
-
106
- // Verify the highlight actually appeared
107
- const finalCount = await page.evaluate(() => {
108
- const h = (window as unknown as Record<string, unknown>)
109
- .__readitHighlights as { commentIds: string[] } | undefined;
110
- return h?.commentIds?.length ?? 0;
111
- });
112
- expect(finalCount).toBeGreaterThan(tier.comments);
113
- } finally {
114
- await cleanup();
115
- }
116
- });