offsite 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -2
  3. package/apps/server/dist/args.js +11 -0
  4. package/apps/server/dist/claude.js +196 -0
  5. package/apps/server/dist/config.js +184 -0
  6. package/apps/server/dist/content.js +172 -0
  7. package/apps/server/dist/files.js +50 -0
  8. package/apps/server/dist/folders.js +12 -0
  9. package/apps/server/dist/git.js +133 -0
  10. package/apps/server/dist/history.js +103 -0
  11. package/apps/server/dist/hub.js +10 -0
  12. package/apps/server/dist/main.js +64 -0
  13. package/apps/server/dist/protocol.js +20 -0
  14. package/apps/server/dist/push.js +152 -0
  15. package/apps/server/dist/run.js +371 -0
  16. package/apps/server/dist/runs.js +102 -0
  17. package/apps/server/dist/schemes.js +262 -0
  18. package/apps/server/dist/sessions.js +64 -0
  19. package/apps/server/dist/socket.js +139 -0
  20. package/apps/server/dist/storage.js +22 -0
  21. package/apps/server/dist/terminal/alerts.js +145 -0
  22. package/apps/server/dist/terminal/process.js +207 -0
  23. package/apps/server/dist/terminal/shell-check.js +91 -0
  24. package/apps/server/dist/terminal/shell-integration.js +112 -0
  25. package/apps/server/dist/terminal/terminal.js +402 -0
  26. package/apps/server/src/terminal/shell-integration/bash/offsite.bash +112 -0
  27. package/apps/server/src/terminal/shell-integration/fish/offsite.fish +22 -0
  28. package/apps/server/src/terminal/shell-integration/zsh/.zshenv +100 -0
  29. package/apps/web/dist/assets/CaskaydiaCove-Bold-EtG3C8NJ.woff2 +0 -0
  30. package/apps/web/dist/assets/CaskaydiaCove-Regular-C8p8BuDw.woff2 +0 -0
  31. package/apps/web/dist/assets/FiraCode-Bold-CWkMdXEH.woff2 +0 -0
  32. package/apps/web/dist/assets/FiraCode-Regular-DlIV_a-6.woff2 +0 -0
  33. package/apps/web/dist/assets/Hack-Bold-CJ2nw9Fn.woff2 +0 -0
  34. package/apps/web/dist/assets/Hack-Regular-DQT7wDXD.woff2 +0 -0
  35. package/apps/web/dist/assets/JetBrainsMono-Bold-C3RVijod.woff2 +0 -0
  36. package/apps/web/dist/assets/JetBrainsMono-Regular-BhNseNRl.woff2 +0 -0
  37. package/apps/web/dist/assets/abap-CLvhMVsD.js +1 -0
  38. package/apps/web/dist/assets/actionscript-3-Cs6JJXT5.js +1 -0
  39. package/apps/web/dist/assets/ada-X3Y2mlq2.js +1 -0
  40. package/apps/web/dist/assets/ahk-DwADkxyd.js +1 -0
  41. package/apps/web/dist/assets/ahk2-_6rzW9BS.js +1 -0
  42. package/apps/web/dist/assets/andromeeda-vGVdxbeo.js +1 -0
  43. package/apps/web/dist/assets/angular-html-_TZra42G.js +1 -0
  44. package/apps/web/dist/assets/angular-ts-CVVZOQsp.js +1 -0
  45. package/apps/web/dist/assets/apache-U0d_L8uA.js +1 -0
  46. package/apps/web/dist/assets/apex-KFGFyKwG.js +1 -0
  47. package/apps/web/dist/assets/apl-Cyzt__4P.js +1 -0
  48. package/apps/web/dist/assets/applescript-CCn79oCD.js +1 -0
  49. package/apps/web/dist/assets/ara-4CJ0cIlV.js +1 -0
  50. package/apps/web/dist/assets/asciidoc-SCjQUq34.js +1 -0
  51. package/apps/web/dist/assets/asm-Cmm7eHzH.js +1 -0
  52. package/apps/web/dist/assets/astro-DvoD4nYz.js +1 -0
  53. package/apps/web/dist/assets/aurora-x-CDeNXAV0.js +1 -0
  54. package/apps/web/dist/assets/awk-BWXHIvNe.js +1 -0
  55. package/apps/web/dist/assets/ayu-dark-DluEY0Gj.js +1 -0
  56. package/apps/web/dist/assets/ayu-light-C3h-C4tm.js +1 -0
  57. package/apps/web/dist/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  58. package/apps/web/dist/assets/ballerina-B7ZEbQpA.js +1 -0
  59. package/apps/web/dist/assets/bat-qdxAdBWQ.js +1 -0
  60. package/apps/web/dist/assets/beancount-C2IN4Vk8.js +1 -0
  61. package/apps/web/dist/assets/berry-DKpUyyne.js +1 -0
  62. package/apps/web/dist/assets/bibtex-Ci_nEsc7.js +1 -0
  63. package/apps/web/dist/assets/bicep-CUHmPFLl.js +1 -0
  64. package/apps/web/dist/assets/bird2-CYIUgYqB.js +1 -0
  65. package/apps/web/dist/assets/blade-SFrvNJcM.js +1 -0
  66. package/apps/web/dist/assets/bsl-_VjlB9mv.js +1 -0
  67. package/apps/web/dist/assets/c-BzXljoEl.js +1 -0
  68. package/apps/web/dist/assets/c3-D0apG41V.js +1 -0
  69. package/apps/web/dist/assets/cadence-CQ2zXKGN.js +1 -0
  70. package/apps/web/dist/assets/cairo-DLTphjLi.js +1 -0
  71. package/apps/web/dist/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
  72. package/apps/web/dist/assets/catppuccin-latte-CtsyrtPq.js +1 -0
  73. package/apps/web/dist/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
  74. package/apps/web/dist/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
  75. package/apps/web/dist/assets/chapel-CSqeAvDr.js +1 -0
  76. package/apps/web/dist/assets/clarity-CtfBBspg.js +1 -0
  77. package/apps/web/dist/assets/clojure-DqKBuwfJ.js +1 -0
  78. package/apps/web/dist/assets/cmake-Bj61d0ZC.js +1 -0
  79. package/apps/web/dist/assets/cobol-DnK1h_4j.js +1 -0
  80. package/apps/web/dist/assets/codeowners-C8r90Shi.js +1 -0
  81. package/apps/web/dist/assets/codeql-oeQT6MSM.js +1 -0
  82. package/apps/web/dist/assets/coffee-BrM2hs_V.js +1 -0
  83. package/apps/web/dist/assets/common-lisp-Cv5bFMCO.js +1 -0
  84. package/apps/web/dist/assets/coq-CGaSfhwR.js +1 -0
  85. package/apps/web/dist/assets/cpp-C_7gVSp4.js +1 -0
  86. package/apps/web/dist/assets/crystal-DbpY_y_D.js +1 -0
  87. package/apps/web/dist/assets/csharp-dmMxLVLW.js +1 -0
  88. package/apps/web/dist/assets/css-CcKWTG1c.js +1 -0
  89. package/apps/web/dist/assets/csv-Dx-8-gkx.js +1 -0
  90. package/apps/web/dist/assets/cue-CE9AQfxI.js +1 -0
  91. package/apps/web/dist/assets/cypher-ClKdZ_lG.js +1 -0
  92. package/apps/web/dist/assets/d-qD-0Kul2.js +1 -0
  93. package/apps/web/dist/assets/dark-plus-Cs2F2srj.js +1 -0
  94. package/apps/web/dist/assets/dart-CHZY9Xhz.js +1 -0
  95. package/apps/web/dist/assets/dax-BkyTk9wS.js +1 -0
  96. package/apps/web/dist/assets/desktop-Dlh5hvp9.js +1 -0
  97. package/apps/web/dist/assets/diff-woXpYk--.js +1 -0
  98. package/apps/web/dist/assets/docker-IyjqRm3v.js +1 -0
  99. package/apps/web/dist/assets/dotenv-CuH5my32.js +1 -0
  100. package/apps/web/dist/assets/dracula-BHWKrbxM.js +1 -0
  101. package/apps/web/dist/assets/dracula-soft-5eyTD99u.js +1 -0
  102. package/apps/web/dist/assets/dream-maker-DW3nJb8Q.js +1 -0
  103. package/apps/web/dist/assets/edge-CqcnepJa.js +1 -0
  104. package/apps/web/dist/assets/elixir-DG0UMMTO.js +1 -0
  105. package/apps/web/dist/assets/elm-D81_16hi.js +1 -0
  106. package/apps/web/dist/assets/emacs-lisp-DR2vtWaj.js +1 -0
  107. package/apps/web/dist/assets/erb-BHb0Ji2T.js +1 -0
  108. package/apps/web/dist/assets/erlang-Cphh6RMH.js +1 -0
  109. package/apps/web/dist/assets/everforest-dark-sB-x3p7T.js +1 -0
  110. package/apps/web/dist/assets/everforest-light-Df2xbC6M.js +1 -0
  111. package/apps/web/dist/assets/fennel-DQxkIbk2.js +1 -0
  112. package/apps/web/dist/assets/fish-BJitypiv.js +1 -0
  113. package/apps/web/dist/assets/fluent-C03EYrpw.js +1 -0
  114. package/apps/web/dist/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
  115. package/apps/web/dist/assets/fortran-free-form-CYNrtFtB.js +1 -0
  116. package/apps/web/dist/assets/fsharp-D13ZGOAj.js +1 -0
  117. package/apps/web/dist/assets/gdresource-xMC7jr7x.js +1 -0
  118. package/apps/web/dist/assets/gdscript-DYvRD3hg.js +1 -0
  119. package/apps/web/dist/assets/gdshader-CBce3t8t.js +1 -0
  120. package/apps/web/dist/assets/genie-CV2tkWYe.js +1 -0
  121. package/apps/web/dist/assets/gherkin-DExj1W_8.js +1 -0
  122. package/apps/web/dist/assets/ghostty-vt-CQAu1Gs5.wasm +0 -0
  123. package/apps/web/dist/assets/git-commit-BSykSTBG.js +1 -0
  124. package/apps/web/dist/assets/git-rebase-Bzcz_AWI.js +1 -0
  125. package/apps/web/dist/assets/github-dark-C-LZuMrd.js +1 -0
  126. package/apps/web/dist/assets/github-dark-default-DXG-b-1a.js +1 -0
  127. package/apps/web/dist/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  128. package/apps/web/dist/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  129. package/apps/web/dist/assets/github-light-EUqPIrTm.js +1 -0
  130. package/apps/web/dist/assets/github-light-default-BXViO-2h.js +1 -0
  131. package/apps/web/dist/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  132. package/apps/web/dist/assets/gleam-CSRkHgEL.js +1 -0
  133. package/apps/web/dist/assets/glimmer-js-BbGaPXN7.js +1 -0
  134. package/apps/web/dist/assets/glimmer-ts-B2OBt1Cw.js +1 -0
  135. package/apps/web/dist/assets/glsl-Cuu3Xc_3.js +1 -0
  136. package/apps/web/dist/assets/gn-CAXYAgV-.js +1 -0
  137. package/apps/web/dist/assets/gnuplot-7GGW24-e.js +1 -0
  138. package/apps/web/dist/assets/go-rLFTqkRN.js +1 -0
  139. package/apps/web/dist/assets/graphql-XBGrkq1T.js +1 -0
  140. package/apps/web/dist/assets/groovy-CacY0gHj.js +1 -0
  141. package/apps/web/dist/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  142. package/apps/web/dist/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  143. package/apps/web/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  144. package/apps/web/dist/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  145. package/apps/web/dist/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  146. package/apps/web/dist/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  147. package/apps/web/dist/assets/hack-D-n58M0B.js +1 -0
  148. package/apps/web/dist/assets/haml-06aMoWFC.js +1 -0
  149. package/apps/web/dist/assets/handlebars-BSCSPRHp.js +1 -0
  150. package/apps/web/dist/assets/haskell-D8IpX4py.js +1 -0
  151. package/apps/web/dist/assets/haxe-C8oCnwJJ.js +1 -0
  152. package/apps/web/dist/assets/hcl-Dh228itO.js +1 -0
  153. package/apps/web/dist/assets/hjson-CxZEssPk.js +1 -0
  154. package/apps/web/dist/assets/hlsl-Cvrh5tZx.js +1 -0
  155. package/apps/web/dist/assets/horizon-CE9ld1lL.js +1 -0
  156. package/apps/web/dist/assets/horizon-bright-DSNQnXHK.js +1 -0
  157. package/apps/web/dist/assets/houston-CsvMBhTu.js +1 -0
  158. package/apps/web/dist/assets/html-CRYhxgas.js +1 -0
  159. package/apps/web/dist/assets/html-derivative-El-EKb6H.js +1 -0
  160. package/apps/web/dist/assets/http-Cj-Wbb2c.js +1 -0
  161. package/apps/web/dist/assets/hurl--dF5MzC1.js +1 -0
  162. package/apps/web/dist/assets/hxml-Dcm88srW.js +1 -0
  163. package/apps/web/dist/assets/hy-CZbG8q4J.js +1 -0
  164. package/apps/web/dist/assets/imba-DsUTQ-LC.js +1 -0
  165. package/apps/web/dist/assets/index-CN9uEzWa.js +899 -0
  166. package/apps/web/dist/assets/index-Ck79gpc3.css +2 -0
  167. package/apps/web/dist/assets/ini-B5eOa1yu.js +1 -0
  168. package/apps/web/dist/assets/java-_zuIdTC3.js +1 -0
  169. package/apps/web/dist/assets/javascript-Dw2bor_9.js +1 -0
  170. package/apps/web/dist/assets/jinja-CtYhL6FS.js +1 -0
  171. package/apps/web/dist/assets/jison-BS6VCOAt.js +1 -0
  172. package/apps/web/dist/assets/json-D6Mznwzn.js +1 -0
  173. package/apps/web/dist/assets/json5-BR5RXkoi.js +1 -0
  174. package/apps/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
  175. package/apps/web/dist/assets/jsonl-CmCQp5Yx.js +1 -0
  176. package/apps/web/dist/assets/jsonnet-CJTPZ8u_.js +1 -0
  177. package/apps/web/dist/assets/jssm-DXw9l8Rf.js +1 -0
  178. package/apps/web/dist/assets/jsx-DLuxOqjU.js +1 -0
  179. package/apps/web/dist/assets/julia-CMgTtdec.js +1 -0
  180. package/apps/web/dist/assets/just-D_e2Cdol.js +1 -0
  181. package/apps/web/dist/assets/kanagawa-dragon-Bozd7klA.js +1 -0
  182. package/apps/web/dist/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
  183. package/apps/web/dist/assets/kanagawa-wave-BML5mF2J.js +1 -0
  184. package/apps/web/dist/assets/kdl-CsD5j6eV.js +1 -0
  185. package/apps/web/dist/assets/kotlin-DhhofPvG.js +1 -0
  186. package/apps/web/dist/assets/kusto-C7mF5XQf.js +1 -0
  187. package/apps/web/dist/assets/laserwave-C_8bwKvT.js +1 -0
  188. package/apps/web/dist/assets/latex-C7F9cbcZ.js +1 -0
  189. package/apps/web/dist/assets/lean-CewbzKMR.js +1 -0
  190. package/apps/web/dist/assets/less-DVTAwKKz.js +1 -0
  191. package/apps/web/dist/assets/light-plus-DVQuIRkW.js +1 -0
  192. package/apps/web/dist/assets/liquid-DZ0eHbL-.js +1 -0
  193. package/apps/web/dist/assets/llvm-DqHOMS-s.js +1 -0
  194. package/apps/web/dist/assets/log-BNLmms1o.js +1 -0
  195. package/apps/web/dist/assets/logo-Cluzi2Zq.js +1 -0
  196. package/apps/web/dist/assets/lua-DA_XbnYa.js +1 -0
  197. package/apps/web/dist/assets/luau-VGWVLoqX.js +1 -0
  198. package/apps/web/dist/assets/make-Dixweg8N.js +1 -0
  199. package/apps/web/dist/assets/markdown-BYOwaDjH.js +1 -0
  200. package/apps/web/dist/assets/marko-BOjbwMe_.js +1 -0
  201. package/apps/web/dist/assets/material-theme-Bm3Qr25_.js +1 -0
  202. package/apps/web/dist/assets/material-theme-darker-2IIEA8gg.js +1 -0
  203. package/apps/web/dist/assets/material-theme-lighter-uhdI0v04.js +1 -0
  204. package/apps/web/dist/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  205. package/apps/web/dist/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  206. package/apps/web/dist/assets/matlab-D7qyCx1q.js +1 -0
  207. package/apps/web/dist/assets/mdc-BLQdrSL9.js +1 -0
  208. package/apps/web/dist/assets/mdx-DQZ5AkYe.js +1 -0
  209. package/apps/web/dist/assets/mermaid-BxpfTIzt.js +1 -0
  210. package/apps/web/dist/assets/min-dark-BSWPekZh.js +1 -0
  211. package/apps/web/dist/assets/min-light-DDpmG2fV.js +1 -0
  212. package/apps/web/dist/assets/mipsasm-BMqwQI7S.js +1 -0
  213. package/apps/web/dist/assets/mojo-fg40_ntQ.js +1 -0
  214. package/apps/web/dist/assets/monokai-BscAjiQZ.js +1 -0
  215. package/apps/web/dist/assets/moonbit-D9W784E_.js +1 -0
  216. package/apps/web/dist/assets/move-BYnGhZoM.js +1 -0
  217. package/apps/web/dist/assets/narrat-_X_XdTYD.js +1 -0
  218. package/apps/web/dist/assets/nextflow-CSgcYZcx.js +1 -0
  219. package/apps/web/dist/assets/nextflow-groovy-D7IRt6Pp.js +1 -0
  220. package/apps/web/dist/assets/nginx-CRuAoyv9.js +1 -0
  221. package/apps/web/dist/assets/night-owl-DhmEMT88.js +1 -0
  222. package/apps/web/dist/assets/night-owl-light-eJ-hLW7d.js +1 -0
  223. package/apps/web/dist/assets/nim--m3L_KpX.js +1 -0
  224. package/apps/web/dist/assets/nix-IvuFDN5E.js +1 -0
  225. package/apps/web/dist/assets/nord-Cb4Vim4T.js +1 -0
  226. package/apps/web/dist/assets/nsis-CjNLYCLg.js +1 -0
  227. package/apps/web/dist/assets/nushell--0fT3PI1.js +1 -0
  228. package/apps/web/dist/assets/objective-c-D1A_Heim.js +1 -0
  229. package/apps/web/dist/assets/objective-cpp-BsSzOQcm.js +1 -0
  230. package/apps/web/dist/assets/ocaml-O90oeIOV.js +1 -0
  231. package/apps/web/dist/assets/odin-B1RWQWA5.js +1 -0
  232. package/apps/web/dist/assets/one-dark-pro-C6YyR8OD.js +1 -0
  233. package/apps/web/dist/assets/one-light-D7Lr4KcI.js +1 -0
  234. package/apps/web/dist/assets/openscad-BUDT5pXO.js +1 -0
  235. package/apps/web/dist/assets/org-BNxSv-BH.js +1 -0
  236. package/apps/web/dist/assets/pascal-4ZHwLPI5.js +1 -0
  237. package/apps/web/dist/assets/perl-DEB_cAoG.js +1 -0
  238. package/apps/web/dist/assets/php-Cei4P5ds.js +1 -0
  239. package/apps/web/dist/assets/pierre-dark-CpLgRqie.js +1 -0
  240. package/apps/web/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
  241. package/apps/web/dist/assets/pierre-dark-soft-kZQmAZld.js +1 -0
  242. package/apps/web/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
  243. package/apps/web/dist/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
  244. package/apps/web/dist/assets/pierre-light-CoaEpmwp.js +1 -0
  245. package/apps/web/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
  246. package/apps/web/dist/assets/pierre-light-soft-lWLdNTOI.js +1 -0
  247. package/apps/web/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
  248. package/apps/web/dist/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
  249. package/apps/web/dist/assets/pkl-ot-7Btpt.js +1 -0
  250. package/apps/web/dist/assets/plastic-DQwYfKfQ.js +1 -0
  251. package/apps/web/dist/assets/plsql-DGHpHOYJ.js +1 -0
  252. package/apps/web/dist/assets/po-BiJDBrnU.js +1 -0
  253. package/apps/web/dist/assets/poimandres-DRFjx7u4.js +1 -0
  254. package/apps/web/dist/assets/polar-C7UOKdEL.js +1 -0
  255. package/apps/web/dist/assets/postcss-BXeXVLqQ.js +1 -0
  256. package/apps/web/dist/assets/powerquery-DNMTfnFr.js +1 -0
  257. package/apps/web/dist/assets/powershell-QtSnmXcu.js +1 -0
  258. package/apps/web/dist/assets/prisma-DMgNhnYS.js +1 -0
  259. package/apps/web/dist/assets/prolog-iXnhIJG7.js +1 -0
  260. package/apps/web/dist/assets/proto-DB4EqR-F.js +1 -0
  261. package/apps/web/dist/assets/pug-BtkQ8Y8B.js +1 -0
  262. package/apps/web/dist/assets/puppet-CDv2pdJW.js +1 -0
  263. package/apps/web/dist/assets/purescript-9MfHhQsQ.js +1 -0
  264. package/apps/web/dist/assets/python-gzcpVVnB.js +1 -0
  265. package/apps/web/dist/assets/qml-yI-6sShm.js +1 -0
  266. package/apps/web/dist/assets/qmldir-DCQb3MpD.js +1 -0
  267. package/apps/web/dist/assets/qss-Fe1Jh2GI.js +1 -0
  268. package/apps/web/dist/assets/r-CJ8zo4yy.js +1 -0
  269. package/apps/web/dist/assets/racket-DcIDlBhZ.js +1 -0
  270. package/apps/web/dist/assets/raku-B3gFvitq.js +1 -0
  271. package/apps/web/dist/assets/razor-CTPI_hHO.js +1 -0
  272. package/apps/web/dist/assets/rbs-C0MpOrj4.js +1 -0
  273. package/apps/web/dist/assets/red-CYlAq2b0.js +1 -0
  274. package/apps/web/dist/assets/reg-CRGYupPL.js +1 -0
  275. package/apps/web/dist/assets/regexp-j43xPEIH.js +1 -0
  276. package/apps/web/dist/assets/rel-BtDbiS_P.js +1 -0
  277. package/apps/web/dist/assets/riscv-Ckw8ddFX.js +1 -0
  278. package/apps/web/dist/assets/ron-VUp2lXgN.js +1 -0
  279. package/apps/web/dist/assets/rose-pine-aMsaMD1D.js +1 -0
  280. package/apps/web/dist/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
  281. package/apps/web/dist/assets/rose-pine-moon-DO-qXg-I.js +1 -0
  282. package/apps/web/dist/assets/rosmsg-CAekHB0j.js +1 -0
  283. package/apps/web/dist/assets/rst-CfIeFcNC.js +1 -0
  284. package/apps/web/dist/assets/ruby-CtmudUkS.js +1 -0
  285. package/apps/web/dist/assets/rust-DpiIf5JO.js +1 -0
  286. package/apps/web/dist/assets/sas-BBgd1Oa5.js +1 -0
  287. package/apps/web/dist/assets/sass-DXrisJhu.js +1 -0
  288. package/apps/web/dist/assets/scala-BiFt_7mu.js +1 -0
  289. package/apps/web/dist/assets/scheme-DQCgrYNe.js +1 -0
  290. package/apps/web/dist/assets/scss-BOSyZrIf.js +1 -0
  291. package/apps/web/dist/assets/sdbl-bTVj8UrX.js +1 -0
  292. package/apps/web/dist/assets/shaderlab-TOUzSsQk.js +1 -0
  293. package/apps/web/dist/assets/shellscript-BES_U9_l.js +1 -0
  294. package/apps/web/dist/assets/shellsession-CdF1AgdN.js +1 -0
  295. package/apps/web/dist/assets/slack-dark-DnToyrRv.js +1 -0
  296. package/apps/web/dist/assets/slack-ochin-B2OO5cIa.js +1 -0
  297. package/apps/web/dist/assets/smalltalk-BHpQb5nM.js +1 -0
  298. package/apps/web/dist/assets/smithy-Dgaz7aur.js +1 -0
  299. package/apps/web/dist/assets/snazzy-light-4G7pJPwS.js +1 -0
  300. package/apps/web/dist/assets/solarized-dark-b97czJOk.js +1 -0
  301. package/apps/web/dist/assets/solarized-light-DFPxpIYQ.js +1 -0
  302. package/apps/web/dist/assets/solidity-Bj7E1mRn.js +1 -0
  303. package/apps/web/dist/assets/soy-hqjXYWz3.js +1 -0
  304. package/apps/web/dist/assets/sparql-D_iOobhT.js +1 -0
  305. package/apps/web/dist/assets/splunk-BC2Px7Mm.js +1 -0
  306. package/apps/web/dist/assets/sql-D5hYy2r7.js +1 -0
  307. package/apps/web/dist/assets/ssh-config-BgfXC-Er.js +1 -0
  308. package/apps/web/dist/assets/stata-GNNI7e-r.js +1 -0
  309. package/apps/web/dist/assets/stylus-B6D30XZt.js +1 -0
  310. package/apps/web/dist/assets/surrealql-gm8__PDR.js +1 -0
  311. package/apps/web/dist/assets/svelte-DK6xQ-Vs.js +1 -0
  312. package/apps/web/dist/assets/swift-CyEgAFGc.js +1 -0
  313. package/apps/web/dist/assets/synthwave-84-nFMaYfgc.js +1 -0
  314. package/apps/web/dist/assets/system-verilog-Dh5ihWbf.js +1 -0
  315. package/apps/web/dist/assets/systemd-BxMlprV5.js +1 -0
  316. package/apps/web/dist/assets/talonscript-CohzipZa.js +1 -0
  317. package/apps/web/dist/assets/tasl-DMoTqEGO.js +1 -0
  318. package/apps/web/dist/assets/tcl-CZd0xW_V.js +1 -0
  319. package/apps/web/dist/assets/templ-Dy-PHEH0.js +1 -0
  320. package/apps/web/dist/assets/terraform-DswuEJGm.js +1 -0
  321. package/apps/web/dist/assets/tex-gYu3IM_T.js +1 -0
  322. package/apps/web/dist/assets/tokyo-night-oM2G3aXe.js +1 -0
  323. package/apps/web/dist/assets/toml-CcmNWLt0.js +1 -0
  324. package/apps/web/dist/assets/ts-tags-C8akqtaV.js +1 -0
  325. package/apps/web/dist/assets/tsv-sltzmVWM.js +1 -0
  326. package/apps/web/dist/assets/tsx-CtF99HYc.js +1 -0
  327. package/apps/web/dist/assets/turtle-ByJddavk.js +1 -0
  328. package/apps/web/dist/assets/twig-D7-O9s37.js +1 -0
  329. package/apps/web/dist/assets/typescript-o4QHcKOF.js +1 -0
  330. package/apps/web/dist/assets/typespec-BGhR2SqG.js +1 -0
  331. package/apps/web/dist/assets/typst-CsLzgkYX.js +1 -0
  332. package/apps/web/dist/assets/v-DBj4K9d_.js +1 -0
  333. package/apps/web/dist/assets/vala-zf12oZj6.js +1 -0
  334. package/apps/web/dist/assets/vb-DOwzaHZ0.js +1 -0
  335. package/apps/web/dist/assets/verilog-B2gwz-sJ.js +1 -0
  336. package/apps/web/dist/assets/vesper-DdrHHSXu.js +1 -0
  337. package/apps/web/dist/assets/vhdl-BroJfC0k.js +1 -0
  338. package/apps/web/dist/assets/viml-DvXPmvsu.js +1 -0
  339. package/apps/web/dist/assets/vitesse-black-fwtXNY1n.js +1 -0
  340. package/apps/web/dist/assets/vitesse-dark-BZCL-v6S.js +1 -0
  341. package/apps/web/dist/assets/vitesse-light-VbXTXTou.js +1 -0
  342. package/apps/web/dist/assets/vue-C67X0ZYE.js +1 -0
  343. package/apps/web/dist/assets/vue-html-3wcw93oK.js +1 -0
  344. package/apps/web/dist/assets/vue-vine-Bq8-4EKU.js +1 -0
  345. package/apps/web/dist/assets/vyper-CgoNMtux.js +1 -0
  346. package/apps/web/dist/assets/wasm-BnjxR4X6.js +1 -0
  347. package/apps/web/dist/assets/wasm-ByWQv1Qj.js +1 -0
  348. package/apps/web/dist/assets/wenyan-C8pVoKbM.js +1 -0
  349. package/apps/web/dist/assets/wgsl-BsKzXJz4.js +1 -0
  350. package/apps/web/dist/assets/wikitext-ClFFjSW2.js +1 -0
  351. package/apps/web/dist/assets/wit-DdvCle-K.js +1 -0
  352. package/apps/web/dist/assets/wolfram-DLL8P-h_.js +1 -0
  353. package/apps/web/dist/assets/xml-DXCI-6Wi.js +1 -0
  354. package/apps/web/dist/assets/xsl-Dr0qfgBg.js +1 -0
  355. package/apps/web/dist/assets/yaml-DHhOWIuf.js +1 -0
  356. package/apps/web/dist/assets/zenscript-BnlCZFoB.js +1 -0
  357. package/apps/web/dist/assets/zig-CMLA9XwU.js +1 -0
  358. package/apps/web/dist/index.html +17 -0
  359. package/apps/web/dist/sw.js +81 -0
  360. package/bin/offsite.js +2 -0
  361. package/package.json +20 -4
@@ -0,0 +1,133 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { readFileSync, statSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ import { query } from '@anthropic-ai/claude-agent-sdk';
6
+ import { claudeOptions } from './claude.js';
7
+ const DIFF_LIMIT = 80_000;
8
+ const UNTRACKED_LIMIT = 100;
9
+ const NEW_FILE_LIMIT = 256 * 1024;
10
+ export async function gitStatus(cwd) {
11
+ let output;
12
+ try {
13
+ output = await git(cwd, ['status', '--porcelain=v2', '--branch']);
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ const status = {
19
+ branch: null,
20
+ upstream: null,
21
+ ahead: 0,
22
+ behind: 0,
23
+ changed: 0,
24
+ };
25
+ for (const line of output.stdout.split('\n').filter(Boolean)) {
26
+ const [marker, key, ...rest] = line.split(' ');
27
+ if (marker !== '#')
28
+ status.changed++;
29
+ else if (key === 'branch.head')
30
+ status.branch = rest[0] === '(detached)' ? null : rest[0];
31
+ else if (key === 'branch.upstream')
32
+ status.upstream = rest[0];
33
+ else if (key === 'branch.ab') {
34
+ status.ahead = Number(rest[0]);
35
+ status.behind = -Number(rest[1]);
36
+ }
37
+ }
38
+ return status;
39
+ }
40
+ export async function commit(cwd, message) {
41
+ if (message.trim() === '')
42
+ throw new Error('Write a commit message first');
43
+ await git(cwd, ['add', '--all']);
44
+ await git(cwd, ['commit', '--message', message]);
45
+ return gitStatus(cwd);
46
+ }
47
+ export async function push(cwd) {
48
+ const status = await gitStatus(cwd);
49
+ if (status === null)
50
+ throw new Error(`${cwd} is not a git repository`);
51
+ if (status.upstream === null)
52
+ await git(cwd, ['push', '--set-upstream', 'origin', 'HEAD']);
53
+ else
54
+ await git(cwd, ['push']);
55
+ return gitStatus(cwd);
56
+ }
57
+ export async function createPullRequest(cwd) {
58
+ const { stdout } = await promisify(execFile)('gh', ['pr', 'create', '--fill'], { cwd });
59
+ const url = stdout.trim().split('\n').at(-1);
60
+ if (url === undefined)
61
+ throw new Error('gh did not return a pull request URL');
62
+ return { url };
63
+ }
64
+ export async function suggestCommitMessage(accountId, cwd) {
65
+ const diff = (await workingDiff(cwd)).slice(0, DIFF_LIMIT);
66
+ if (diff === '')
67
+ throw new Error('There is nothing to commit');
68
+ const conversation = query({
69
+ prompt: `Write a git commit message for this diff. Reply with only the message: a short summary line, optionally followed by a blank line and a brief body.\n\n${diff}`,
70
+ options: {
71
+ ...claudeOptions(accountId, cwd),
72
+ systemPrompt: 'You write concise git commit messages.',
73
+ tools: [],
74
+ model: 'haiku',
75
+ maxTurns: 1,
76
+ persistSession: false,
77
+ },
78
+ });
79
+ for await (const message of conversation) {
80
+ if (message.type !== 'result')
81
+ continue;
82
+ if (message.subtype !== 'success')
83
+ throw new Error(message.errors.join('\n'));
84
+ if (message.is_error)
85
+ throw new Error(message.result);
86
+ return { message: message.result.trim() };
87
+ }
88
+ throw new Error('Claude did not reply');
89
+ }
90
+ export async function workingDiff(cwd) {
91
+ try {
92
+ await git(cwd, ['rev-parse', '--is-inside-work-tree']);
93
+ }
94
+ catch {
95
+ throw new Error(`${cwd} is not a git repository`);
96
+ }
97
+ const tracked = await git(cwd, [
98
+ 'diff',
99
+ 'HEAD',
100
+ '--no-color',
101
+ '--no-ext-diff',
102
+ ]);
103
+ const untracked = await git(cwd, [
104
+ 'ls-files',
105
+ '--others',
106
+ '--exclude-standard',
107
+ ]);
108
+ const added = untracked.stdout
109
+ .split('\n')
110
+ .filter(Boolean)
111
+ .slice(0, UNTRACKED_LIMIT)
112
+ .map((file) => newFilePatch(cwd, file));
113
+ return [tracked.stdout, ...added].join('');
114
+ }
115
+ export function git(cwd, args) {
116
+ return promisify(execFile)('git', args, {
117
+ cwd,
118
+ maxBuffer: 64 * 1024 * 1024,
119
+ });
120
+ }
121
+ function newFilePatch(cwd, file) {
122
+ const header = `diff --git a/${file} b/${file}\nnew file\n--- /dev/null\n+++ b/${file}\n`;
123
+ const full = path.join(cwd, file);
124
+ if (statSync(full).size > NEW_FILE_LIMIT)
125
+ return `${header}Binary or large file\n`;
126
+ const content = readFileSync(full, 'utf8');
127
+ if (content.includes('\0'))
128
+ return `${header}Binary or large file\n`;
129
+ const lines = content.split('\n');
130
+ if (lines.at(-1) === '')
131
+ lines.pop();
132
+ return `${header}@@ -0,0 +1,${lines.length} @@\n${lines.map((line) => `+${line}\n`).join('')}`;
133
+ }
@@ -0,0 +1,103 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { getSessionMessages, getSubagentMessages, } from '@anthropic-ai/claude-agent-sdk';
5
+ import { contextTokens, toMessage } from './content.js';
6
+ import { runs } from './run.js';
7
+ const projectsDir = path.join(process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), '.claude'), 'projects');
8
+ async function messageTimes(sessionId) {
9
+ const times = new Map();
10
+ for (const dir of await readdir(projectsDir)) {
11
+ let text;
12
+ try {
13
+ text = await readFile(path.join(projectsDir, dir, `${sessionId}.jsonl`), 'utf8');
14
+ }
15
+ catch (error) {
16
+ if (error.code === 'ENOENT')
17
+ continue;
18
+ throw error;
19
+ }
20
+ for (const line of text.split('\n')) {
21
+ const entry = parseLine(line);
22
+ if (entry !== null &&
23
+ typeof entry.uuid === 'string' &&
24
+ typeof entry.timestamp === 'string')
25
+ times.set(entry.uuid, Date.parse(entry.timestamp));
26
+ }
27
+ return times;
28
+ }
29
+ return times;
30
+ }
31
+ function parseLine(line) {
32
+ try {
33
+ return JSON.parse(line);
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export async function history(sessionId, cwd) {
40
+ const run = runs.get(sessionId);
41
+ const [disk, times] = await Promise.all([
42
+ getSessionMessages(sessionId, { dir: cwd }),
43
+ messageTimes(sessionId),
44
+ ]);
45
+ const resumeAt = run?.resumeAt ?? null;
46
+ const kept = resumeAt === null
47
+ ? disk
48
+ : disk.slice(0, disk.findIndex((item) => item.uuid === resumeAt) + 1);
49
+ const messages = kept.flatMap((item) => item.type === 'system' || item.parent_tool_use_id !== null
50
+ ? []
51
+ : [toMessage(item.type, item, times.get(item.uuid) ?? null)]);
52
+ messages.push(...(await subagentMessages(sessionId, cwd, messages)));
53
+ const seen = new Set(messages.map((item) => item.uuid));
54
+ const last = kept.findLast((item) => item.type === 'assistant' && item.parent_tool_use_id === null);
55
+ const tokens = last === undefined ? null : contextTokens(last.message);
56
+ return {
57
+ type: 'history',
58
+ sessionId,
59
+ messages: [
60
+ ...messages,
61
+ ...(run?.messages.filter((item) => !seen.has(item.uuid)) ?? []),
62
+ ],
63
+ requests: [...(run?.pending.values() ?? [])].map((item) => item.request),
64
+ queue: run?.queue ?? [],
65
+ settings: run?.settings ?? null,
66
+ context: run?.context ??
67
+ (tokens === null
68
+ ? null
69
+ : { tokens, window: null, model: null, categories: [], sections: [] }),
70
+ };
71
+ }
72
+ async function subagentMessages(sessionId, cwd, messages) {
73
+ const agents = new Set(messages.flatMap((message) => message.type === 'assistant'
74
+ ? message.content.flatMap((block) => block.type === 'tool_use' &&
75
+ (block.name === 'Agent' || block.name === 'Task')
76
+ ? [block.id]
77
+ : [])
78
+ : []));
79
+ const launches = messages.flatMap((message) => message.type === 'user'
80
+ ? message.content.flatMap((block) => {
81
+ if (block.type !== 'tool_result' || !agents.has(block.toolUseId))
82
+ return [];
83
+ const agentId = /agentId: (\w+)/.exec(block.content
84
+ .map((item) => (item.type === 'text' ? item.text : ''))
85
+ .join('\n'))?.[1];
86
+ return agentId === undefined
87
+ ? []
88
+ : [{ agentId, parent: block.toolUseId }];
89
+ })
90
+ : []);
91
+ const loaded = await Promise.all(launches.map(async (launch) => {
92
+ const disk = await getSubagentMessages(sessionId, launch.agentId, {
93
+ dir: cwd,
94
+ });
95
+ const items = disk.flatMap((item) => item.type === 'system'
96
+ ? []
97
+ : [
98
+ toMessage(item.type, { ...item, parent_tool_use_id: launch.parent }, null),
99
+ ]);
100
+ return [...items, ...(await subagentMessages(sessionId, cwd, items))];
101
+ }));
102
+ return loaded.flat();
103
+ }
@@ -0,0 +1,10 @@
1
+ export const clients = new Set();
2
+ export function publish(sessionId, event) {
3
+ for (const client of clients)
4
+ if (client.sessionId === sessionId)
5
+ client.send(event);
6
+ }
7
+ export function broadcast(event) {
8
+ for (const client of clients)
9
+ client.send(event);
10
+ }
@@ -0,0 +1,64 @@
1
+ import { createReadStream, existsSync, statSync } from 'node:fs';
2
+ import { createServer } from 'node:http';
3
+ import path from 'node:path';
4
+ import { WebSocketServer } from 'ws';
5
+ import { args } from './args.js';
6
+ import { findClaude } from './claude.js';
7
+ import { startPush } from './push.js';
8
+ import { stopAll } from './runs.js';
9
+ import { connectClient } from './socket.js';
10
+ const contentTypes = {
11
+ '.html': 'text/html; charset=utf-8',
12
+ '.js': 'text/javascript; charset=utf-8',
13
+ '.css': 'text/css; charset=utf-8',
14
+ '.svg': 'image/svg+xml',
15
+ '.png': 'image/png',
16
+ '.ico': 'image/x-icon',
17
+ '.json': 'application/json',
18
+ '.webmanifest': 'application/manifest+json',
19
+ '.woff2': 'font/woff2',
20
+ };
21
+ const port = Number(args.port);
22
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
23
+ console.error(`invalid port ${args.port}`);
24
+ process.exit(1);
25
+ }
26
+ if (findClaude() === null) {
27
+ console.error('could not find claude on PATH; install Claude Code first');
28
+ process.exit(1);
29
+ }
30
+ const publicDir = path.join(import.meta.dirname, '..', '..', 'web', 'dist');
31
+ const server = createServer((request, response) => {
32
+ const url = new URL(request.url ?? '/', 'http://localhost');
33
+ serveFile(url.pathname, response);
34
+ });
35
+ const sockets = new WebSocketServer({ noServer: true });
36
+ server.on('upgrade', (request, socket, head) => {
37
+ const url = new URL(request.url ?? '/', 'http://localhost');
38
+ if (url.pathname === '/ws')
39
+ sockets.handleUpgrade(request, socket, head, connectClient);
40
+ else
41
+ socket.destroy();
42
+ });
43
+ server.listen(port, args.host, () => {
44
+ startPush(`${args.host}:${port}`);
45
+ console.log(`offsite is running at http://${args.host}:${port}`);
46
+ });
47
+ process.on('SIGINT', () => {
48
+ stopAll();
49
+ process.exit(0);
50
+ });
51
+ function serveFile(pathname, response) {
52
+ const requested = path.join(publicDir, path.normalize(pathname));
53
+ const file = requested.startsWith(publicDir + path.sep) &&
54
+ statSync(requested, { throwIfNoEntry: false })?.isFile()
55
+ ? requested
56
+ : path.join(publicDir, 'index.html');
57
+ if (!existsSync(file)) {
58
+ response.statusCode = 404;
59
+ response.end('web app not built; run pnpm build');
60
+ return;
61
+ }
62
+ response.setHeader('content-type', contentTypes[path.extname(file)] ?? 'application/octet-stream');
63
+ createReadStream(file).pipe(response);
64
+ }
@@ -0,0 +1,20 @@
1
+ export const FRAME_INPUT = 0;
2
+ export const FRAME_REPLY = 1;
3
+ export const FRAME_OUTPUT = 2;
4
+ export const FRAME_REPLAY = 3;
5
+ export function encodeFrame(kind, id, data) {
6
+ const frame = new Uint8Array(5 + data.length);
7
+ frame[0] = kind;
8
+ new DataView(frame.buffer).setUint32(1, id);
9
+ frame.set(data, 5);
10
+ return frame;
11
+ }
12
+ export function decodeFrame(frame) {
13
+ if (frame.length < 5)
14
+ throw new Error('terminal frame is too short');
15
+ return {
16
+ kind: frame[0],
17
+ id: new DataView(frame.buffer, frame.byteOffset, frame.byteLength).getUint32(1),
18
+ data: frame.subarray(5),
19
+ };
20
+ }
@@ -0,0 +1,152 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { renameSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import webPush from 'web-push';
5
+ import { home, readJson, writeJson } from './storage.js';
6
+ const pushFile = path.join(home, 'push.json');
7
+ const TITLE_LIMIT = 100;
8
+ const BODY_LIMIT = 500;
9
+ const TIME_TO_LIVE = 15 * 60;
10
+ const SEND_TIMEOUT = 10_000;
11
+ const SUBJECT = 'https://github.com/NazmusSayad/offsite';
12
+ let server = '';
13
+ let active = false;
14
+ export function startPush(address) {
15
+ server = address;
16
+ try {
17
+ const store = readJson('push.json');
18
+ if (store !== null)
19
+ track(store);
20
+ }
21
+ catch (error) {
22
+ console.warn(`push notifications are off until a browser turns them on again, could not read ${pushFile}: ${error}`);
23
+ }
24
+ }
25
+ export function pushActive() {
26
+ return active;
27
+ }
28
+ export function pushKey() {
29
+ return { publicKey: read().publicKey };
30
+ }
31
+ export function subscribe(subscription) {
32
+ const endpoint = new URL(subscription.endpoint);
33
+ if (endpoint.protocol !== 'https:')
34
+ throw new Error('the endpoint must be an https URL');
35
+ update((store) => {
36
+ store.subscriptions = store.subscriptions.filter((existing) => existing.endpoint !== subscription.endpoint);
37
+ store.subscriptions.push({
38
+ endpoint: subscription.endpoint,
39
+ keys: { p256dh: subscription.keys.p256dh, auth: subscription.keys.auth },
40
+ server,
41
+ });
42
+ });
43
+ console.log('a browser subscribed to push notifications');
44
+ }
45
+ export function unsubscribe(endpoint) {
46
+ update((store) => {
47
+ store.subscriptions = store.subscriptions.filter((existing) => existing.endpoint !== endpoint);
48
+ });
49
+ console.log('a browser unsubscribed from push notifications');
50
+ }
51
+ export async function sendPush(message) {
52
+ let store;
53
+ try {
54
+ store = read();
55
+ }
56
+ catch (error) {
57
+ console.error(`could not read push subscriptions: ${error}`);
58
+ return;
59
+ }
60
+ const subscriptions = store.subscriptions.filter(ours);
61
+ if (subscriptions.length === 0)
62
+ return;
63
+ const payload = JSON.stringify({
64
+ ...message,
65
+ title: [...message.title].slice(0, TITLE_LIMIT).join(''),
66
+ body: [...message.body].slice(0, BODY_LIMIT).join(''),
67
+ });
68
+ const gone = [];
69
+ await Promise.all(subscriptions.map(async (subscription) => {
70
+ try {
71
+ await webPush.sendNotification(subscription, payload, {
72
+ vapidDetails: {
73
+ subject: SUBJECT,
74
+ publicKey: store.publicKey,
75
+ privateKey: store.privateKey,
76
+ },
77
+ TTL: TIME_TO_LIVE,
78
+ urgency: 'high',
79
+ timeout: SEND_TIMEOUT,
80
+ });
81
+ }
82
+ catch (error) {
83
+ const status = error.statusCode;
84
+ if (status !== undefined && [401, 403, 404, 410].includes(status)) {
85
+ console.log(`push subscription ${subscription.endpoint} is gone or was made for another key, removing it`);
86
+ gone.push(subscription.endpoint);
87
+ return;
88
+ }
89
+ console.warn(`could not send a push to ${subscription.endpoint}: ${error}`);
90
+ }
91
+ }));
92
+ if (gone.length === 0)
93
+ return;
94
+ try {
95
+ update((current) => {
96
+ current.subscriptions = current.subscriptions.filter((subscription) => !gone.includes(subscription.endpoint));
97
+ });
98
+ }
99
+ catch (error) {
100
+ console.error(`could not remove gone push subscriptions: ${error}`);
101
+ }
102
+ }
103
+ function ours(subscription) {
104
+ return subscription.server === server;
105
+ }
106
+ function track(store) {
107
+ active = store.subscriptions.some(ours);
108
+ }
109
+ function load() {
110
+ let store;
111
+ try {
112
+ store = readJson('push.json');
113
+ }
114
+ catch (error) {
115
+ if (!(error instanceof SyntaxError))
116
+ throw error;
117
+ return replaceCorrupt(error);
118
+ }
119
+ if (store === null)
120
+ return create();
121
+ if (typeof store.publicKey !== 'string' ||
122
+ typeof store.privateKey !== 'string' ||
123
+ !Array.isArray(store.subscriptions))
124
+ return replaceCorrupt(new Error('it is missing its keys or subscriptions'));
125
+ return store;
126
+ }
127
+ function replaceCorrupt(error) {
128
+ const aside = `${pushFile}.corrupt-${randomUUID()}`;
129
+ renameSync(pushFile, aside);
130
+ console.warn(`${pushFile} is corrupt, moved it to ${aside} and created a new one: ${error}`);
131
+ return create();
132
+ }
133
+ function create() {
134
+ const keys = webPush.generateVAPIDKeys();
135
+ const store = { ...keys, subscriptions: [] };
136
+ save(store);
137
+ return store;
138
+ }
139
+ function save(store) {
140
+ writeJson('push.json', store);
141
+ }
142
+ function read() {
143
+ const store = load();
144
+ track(store);
145
+ return store;
146
+ }
147
+ function update(change) {
148
+ const store = load();
149
+ change(store);
150
+ save(store);
151
+ track(store);
152
+ }