vibora 9.0.2 → 9.0.4

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 (293) hide show
  1. package/bin/vibora.js +1 -1
  2. package/dist/assets/abap-BdImnpbu.js +1 -0
  3. package/dist/assets/actionscript-3-CfeIJUat.js +1 -0
  4. package/dist/assets/ada-bCR0ucgS.js +1 -0
  5. package/dist/assets/andromeeda-C-Jbm3Hp.js +1 -0
  6. package/dist/assets/angular-html-CU67Zn6k.js +1 -0
  7. package/dist/assets/angular-ts-BwZT4LLn.js +1 -0
  8. package/dist/assets/apache-Pmp26Uib.js +1 -0
  9. package/dist/assets/apex-DDbsPZ6N.js +1 -0
  10. package/dist/assets/apl-dKokRX4l.js +1 -0
  11. package/dist/assets/applescript-Co6uUVPk.js +1 -0
  12. package/dist/assets/ara-BRHolxvo.js +1 -0
  13. package/dist/assets/asciidoc-Dv7Oe6Be.js +1 -0
  14. package/dist/assets/asm-D_Q5rh1f.js +1 -0
  15. package/dist/assets/astro-CbQHKStN.js +1 -0
  16. package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  17. package/dist/assets/awk-DMzUqQB5.js +1 -0
  18. package/dist/assets/ayu-dark-Cv9koXgw.js +1 -0
  19. package/dist/assets/ballerina-BFfxhgS-.js +1 -0
  20. package/dist/assets/bat-BkioyH1T.js +1 -0
  21. package/dist/assets/beancount-k_qm7-4y.js +1 -0
  22. package/dist/assets/berry-uYugtg8r.js +1 -0
  23. package/dist/assets/bibtex-CHM0blh-.js +1 -0
  24. package/dist/assets/bicep-Bmn6On1c.js +1 -0
  25. package/dist/assets/blade-DVc8C-J4.js +1 -0
  26. package/dist/assets/bsl-BO_Y6i37.js +1 -0
  27. package/dist/assets/c-BIGW1oBm.js +1 -0
  28. package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  29. package/dist/assets/cairo-KRGpt6FW.js +1 -0
  30. package/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  31. package/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  32. package/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  33. package/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  34. package/dist/assets/clarity-D53aC0YG.js +1 -0
  35. package/dist/assets/clojure-P80f7IUj.js +1 -0
  36. package/dist/assets/cmake-D1j8_8rp.js +1 -0
  37. package/dist/assets/cobol-nwyudZeR.js +1 -0
  38. package/dist/assets/codeowners-Bp6g37R7.js +1 -0
  39. package/dist/assets/codeql-DsOJ9woJ.js +1 -0
  40. package/dist/assets/coffee-Ch7k5sss.js +1 -0
  41. package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  42. package/dist/assets/coq-DkFqJrB1.js +1 -0
  43. package/dist/assets/cpp-CofmeUqb.js +1 -0
  44. package/dist/assets/crystal-tKQVLTB8.js +1 -0
  45. package/dist/assets/csharp-K5feNrxe.js +1 -0
  46. package/dist/assets/css-DPfMkruS.js +1 -0
  47. package/dist/assets/csv-fuZLfV_i.js +1 -0
  48. package/dist/assets/cue-D82EKSYY.js +1 -0
  49. package/dist/assets/cypher-COkxafJQ.js +1 -0
  50. package/dist/assets/d-85-TOEBH.js +1 -0
  51. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  52. package/dist/assets/dart-CF10PKvl.js +1 -0
  53. package/dist/assets/dax-CEL-wOlO.js +1 -0
  54. package/dist/assets/desktop-BmXAJ9_W.js +1 -0
  55. package/dist/assets/diff-D97Zzqfu.js +1 -0
  56. package/dist/assets/docker-BcOcwvcX.js +1 -0
  57. package/dist/assets/dotenv-Da5cRb03.js +1 -0
  58. package/dist/assets/dracula-BzJJZx-M.js +1 -0
  59. package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  60. package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  61. package/dist/assets/edge-BkV0erSs.js +1 -0
  62. package/dist/assets/elixir-CDX3lj18.js +1 -0
  63. package/dist/assets/elm-DbKCFpqz.js +1 -0
  64. package/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
  65. package/dist/assets/erb-BOJIQeun.js +1 -0
  66. package/dist/assets/erlang-DsQrWhSR.js +1 -0
  67. package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  68. package/dist/assets/everforest-light-C8M2exoo.js +1 -0
  69. package/dist/assets/fennel-BYunw83y.js +1 -0
  70. package/dist/assets/fish-BvzEVeQv.js +1 -0
  71. package/dist/assets/fluent-C4IJs8-o.js +1 -0
  72. package/dist/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  73. package/dist/assets/fortran-free-form-D22FLkUw.js +1 -0
  74. package/dist/assets/fsharp-CXgrBDvD.js +1 -0
  75. package/dist/assets/gdresource-B7Tvp0Sc.js +1 -0
  76. package/dist/assets/gdscript-DTMYz4Jt.js +1 -0
  77. package/dist/assets/gdshader-DkwncUOv.js +1 -0
  78. package/dist/assets/genie-D0YGMca9.js +1 -0
  79. package/dist/assets/gherkin-DyxjwDmM.js +1 -0
  80. package/dist/assets/git-commit-F4YmCXRG.js +1 -0
  81. package/dist/assets/git-rebase-r7XF79zn.js +1 -0
  82. package/dist/assets/github-dark-DHJKELXO.js +1 -0
  83. package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  84. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  85. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  86. package/dist/assets/github-light-DAi9KRSo.js +1 -0
  87. package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  88. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  89. package/dist/assets/gleam-BspZqrRM.js +1 -0
  90. package/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
  91. package/dist/assets/glimmer-ts-U6CK756n.js +1 -0
  92. package/dist/assets/glsl-DplSGwfg.js +1 -0
  93. package/dist/assets/gnuplot-DdkO51Og.js +1 -0
  94. package/dist/assets/go-Dn2_MT6a.js +1 -0
  95. package/dist/assets/graphql-ChdNCCLP.js +1 -0
  96. package/dist/assets/groovy-gcz8RCvz.js +1 -0
  97. package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  98. package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  99. package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  100. package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  101. package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  102. package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  103. package/dist/assets/hack-CaT9iCJl.js +1 -0
  104. package/dist/assets/haml-B8DHNrY2.js +1 -0
  105. package/dist/assets/handlebars-BL8al0AC.js +1 -0
  106. package/dist/assets/haskell-Df6bDoY_.js +1 -0
  107. package/dist/assets/haxe-CzTSHFRz.js +1 -0
  108. package/dist/assets/hcl-BWvSN4gD.js +1 -0
  109. package/dist/assets/hjson-D5-asLiD.js +1 -0
  110. package/dist/assets/hlsl-D3lLCCz7.js +1 -0
  111. package/dist/assets/houston-DnULxvSX.js +1 -0
  112. package/dist/assets/html-GMplVEZG.js +1 -0
  113. package/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
  114. package/dist/assets/http-jrhK8wxY.js +1 -0
  115. package/dist/assets/hurl-irOxFIW8.js +1 -0
  116. package/dist/assets/hxml-Bvhsp5Yf.js +1 -0
  117. package/dist/assets/hy-DFXneXwc.js +1 -0
  118. package/dist/assets/imba-DGztddWO.js +1 -0
  119. package/dist/assets/{index-ur6QLS8W.css → index-C4UPW6KM.css} +1 -1
  120. package/dist/assets/{index-CIzRMMYe.js → index-s4vGtpm_.js} +141 -129
  121. package/dist/assets/ini-BEwlwnbL.js +1 -0
  122. package/dist/assets/java-CylS5w8V.js +1 -0
  123. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  124. package/dist/assets/jinja-4LBKfQ-Z.js +1 -0
  125. package/dist/assets/jison-wvAkD_A8.js +1 -0
  126. package/dist/assets/json-Cp-IABpG.js +1 -0
  127. package/dist/assets/json5-C9tS-k6U.js +1 -0
  128. package/dist/assets/jsonc-Des-eS-w.js +1 -0
  129. package/dist/assets/jsonl-DcaNXYhu.js +1 -0
  130. package/dist/assets/jsonnet-DFQXde-d.js +1 -0
  131. package/dist/assets/jssm-C2t-YnRu.js +1 -0
  132. package/dist/assets/jsx-g9-lgVsj.js +1 -0
  133. package/dist/assets/julia-C8NyazO9.js +1 -0
  134. package/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  135. package/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  136. package/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
  137. package/dist/assets/kdl-DV7GczEv.js +1 -0
  138. package/dist/assets/kotlin-BdnUsdx6.js +1 -0
  139. package/dist/assets/kusto-BvAqAH-y.js +1 -0
  140. package/dist/assets/laserwave-DUszq2jm.js +1 -0
  141. package/dist/assets/latex-BdAV_C_H.js +1 -0
  142. package/dist/assets/lean-Bc6EcWN3.js +1 -0
  143. package/dist/assets/less-B1dDrJ26.js +1 -0
  144. package/dist/assets/light-plus-B7mTdjB0.js +1 -0
  145. package/dist/assets/liquid-DYVedYrR.js +1 -0
  146. package/dist/assets/llvm-BtvRca6l.js +1 -0
  147. package/dist/assets/log-2UxHyX5q.js +1 -0
  148. package/dist/assets/logo-BtOb2qkB.js +1 -0
  149. package/dist/assets/lua-BbnMAYS6.js +1 -0
  150. package/dist/assets/luau-CXu1NL6O.js +1 -0
  151. package/dist/assets/make-CHLpvVh8.js +1 -0
  152. package/dist/assets/markdown-Cvjx9yec.js +1 -0
  153. package/dist/assets/marko-CPi9NSCl.js +1 -0
  154. package/dist/assets/material-theme-D5KoaKCx.js +1 -0
  155. package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  156. package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  157. package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  158. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  159. package/dist/assets/matlab-D7o27uSR.js +1 -0
  160. package/dist/assets/mdc-DUICxH0z.js +1 -0
  161. package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  162. package/dist/assets/mermaid-DKYwYmdq.js +1 -0
  163. package/dist/assets/min-dark-CafNBF8u.js +1 -0
  164. package/dist/assets/min-light-CTRr51gU.js +1 -0
  165. package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  166. package/dist/assets/mojo-1DNp92w6.js +1 -0
  167. package/dist/assets/monokai-D4h5O-jR.js +1 -0
  168. package/dist/assets/move-Bu9oaDYs.js +1 -0
  169. package/dist/assets/narrat-DRg8JJMk.js +1 -0
  170. package/dist/assets/nextflow-BrzmwbiE.js +1 -0
  171. package/dist/assets/nginx-DknmC5AR.js +1 -0
  172. package/dist/assets/night-owl-C39BiMTA.js +1 -0
  173. package/dist/assets/nim-CVrawwO9.js +1 -0
  174. package/dist/assets/nix-c8nO5XWb.js +1 -0
  175. package/dist/assets/nord-Ddv68eIx.js +1 -0
  176. package/dist/assets/nushell-C-sUppwS.js +1 -0
  177. package/dist/assets/objective-c-DXmwc3jG.js +1 -0
  178. package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  179. package/dist/assets/ocaml-C0hk2d4L.js +1 -0
  180. package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  181. package/dist/assets/one-light-PoHY5YXO.js +1 -0
  182. package/dist/assets/openscad-C4EeE6gA.js +1 -0
  183. package/dist/assets/pascal-D93ZcfNL.js +1 -0
  184. package/dist/assets/perl-C0TMdlhV.js +1 -0
  185. package/dist/assets/php-CDn_0X-4.js +1 -0
  186. package/dist/assets/pkl-u5AG7uiY.js +1 -0
  187. package/dist/assets/plastic-3e1v2bzS.js +1 -0
  188. package/dist/assets/plsql-ChMvpjG-.js +1 -0
  189. package/dist/assets/po-BTJTHyun.js +1 -0
  190. package/dist/assets/poimandres-CS3Unz2-.js +1 -0
  191. package/dist/assets/polar-C0HS_06l.js +1 -0
  192. package/dist/assets/postcss-CXtECtnM.js +1 -0
  193. package/dist/assets/powerquery-CEu0bR-o.js +1 -0
  194. package/dist/assets/powershell-Dpen1YoG.js +1 -0
  195. package/dist/assets/prisma-Dd19v3D-.js +1 -0
  196. package/dist/assets/prolog-CbFg5uaA.js +1 -0
  197. package/dist/assets/proto-DyJlTyXw.js +1 -0
  198. package/dist/assets/pug-CGlum2m_.js +1 -0
  199. package/dist/assets/puppet-BMWR74SV.js +1 -0
  200. package/dist/assets/purescript-CklMAg4u.js +1 -0
  201. package/dist/assets/python-B6aJPvgy.js +1 -0
  202. package/dist/assets/qml-3beO22l8.js +1 -0
  203. package/dist/assets/qmldir-C8lEn-DE.js +1 -0
  204. package/dist/assets/qss-IeuSbFQv.js +1 -0
  205. package/dist/assets/r-DiinP2Uv.js +1 -0
  206. package/dist/assets/racket-BqYA7rlc.js +1 -0
  207. package/dist/assets/raku-DXvB9xmW.js +1 -0
  208. package/dist/assets/razor-CE9lU5zL.js +1 -0
  209. package/dist/assets/red-bN70gL4F.js +1 -0
  210. package/dist/assets/reg-C-SQnVFl.js +1 -0
  211. package/dist/assets/regexp-CDVJQ6XC.js +1 -0
  212. package/dist/assets/rel-C3B-1QV4.js +1 -0
  213. package/dist/assets/riscv-BM1_JUlF.js +1 -0
  214. package/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  215. package/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  216. package/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
  217. package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  218. package/dist/assets/rst-B0xPkSld.js +1 -0
  219. package/dist/assets/ruby-BvKwtOVI.js +1 -0
  220. package/dist/assets/rust-B1yitclQ.js +1 -0
  221. package/dist/assets/sas-cz2c8ADy.js +1 -0
  222. package/dist/assets/sass-Cj5Yp3dK.js +1 -0
  223. package/dist/assets/scala-C151Ov-r.js +1 -0
  224. package/dist/assets/scheme-C98Dy4si.js +1 -0
  225. package/dist/assets/scss-OYdSNvt2.js +1 -0
  226. package/dist/assets/sdbl-DVxCFoDh.js +1 -0
  227. package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  228. package/dist/assets/shellscript-Yzrsuije.js +1 -0
  229. package/dist/assets/shellsession-BADoaaVG.js +1 -0
  230. package/dist/assets/slack-dark-BthQWCQV.js +1 -0
  231. package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  232. package/dist/assets/smalltalk-BERRCDM3.js +1 -0
  233. package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  234. package/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
  235. package/dist/assets/solarized-light-L9t79GZl.js +1 -0
  236. package/dist/assets/solidity-rGO070M0.js +1 -0
  237. package/dist/assets/soy-Brmx7dQM.js +1 -0
  238. package/dist/assets/sparql-rVzFXLq3.js +1 -0
  239. package/dist/assets/splunk-BtCnVYZw.js +1 -0
  240. package/dist/assets/sql-BLtJtn59.js +1 -0
  241. package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  242. package/dist/assets/stata-BH5u7GGu.js +1 -0
  243. package/dist/assets/stylus-BEDo0Tqx.js +1 -0
  244. package/dist/assets/svelte-3Dk4HxPD.js +1 -0
  245. package/dist/assets/swift-Dg5xB15N.js +1 -0
  246. package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  247. package/dist/assets/system-verilog-CnnmHF94.js +1 -0
  248. package/dist/assets/systemd-4A_iFExJ.js +1 -0
  249. package/dist/assets/talonscript-CkByrt1z.js +1 -0
  250. package/dist/assets/tasl-QIJgUcNo.js +1 -0
  251. package/dist/assets/tcl-dwOrl1Do.js +1 -0
  252. package/dist/assets/templ-W15q3VgB.js +1 -0
  253. package/dist/assets/terraform-BETggiCN.js +1 -0
  254. package/dist/assets/tex-CxkMU7Pf.js +1 -0
  255. package/dist/assets/tokyo-night-hegEt444.js +1 -0
  256. package/dist/assets/toml-vGWfd6FD.js +1 -0
  257. package/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
  258. package/dist/assets/tsv-B_m7g4N7.js +1 -0
  259. package/dist/assets/tsx-COt5Ahok.js +1 -0
  260. package/dist/assets/turtle-BsS91CYL.js +1 -0
  261. package/dist/assets/twig-CO9l9SDP.js +1 -0
  262. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  263. package/dist/assets/typespec-BGHnOYBU.js +1 -0
  264. package/dist/assets/typst-DHCkPAjA.js +1 -0
  265. package/dist/assets/v-BcVCzyr7.js +1 -0
  266. package/dist/assets/vala-CsfeWuGM.js +1 -0
  267. package/dist/assets/vb-D17OF-Vu.js +1 -0
  268. package/dist/assets/verilog-BQ8w6xss.js +1 -0
  269. package/dist/assets/vesper-DU1UobuO.js +1 -0
  270. package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  271. package/dist/assets/viml-CJc9bBzg.js +1 -0
  272. package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  273. package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  274. package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  275. package/dist/assets/vue-DnHKYNfI.js +1 -0
  276. package/dist/assets/vue-html-CChd_i61.js +1 -0
  277. package/dist/assets/vue-vine-8moa0y9V.js +1 -0
  278. package/dist/assets/vyper-CDx5xZoG.js +1 -0
  279. package/dist/assets/wasm-CG6Dc4jp.js +1 -0
  280. package/dist/assets/wasm-MzD3tlZU.js +1 -0
  281. package/dist/assets/wenyan-BV7otONQ.js +1 -0
  282. package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  283. package/dist/assets/wikitext-BhOHFoWU.js +1 -0
  284. package/dist/assets/wit-5i3qLPDT.js +1 -0
  285. package/dist/assets/wolfram-lXgVvXCa.js +1 -0
  286. package/dist/assets/xml-sdJ4AIDG.js +1 -0
  287. package/dist/assets/xsl-CtQFsRM5.js +1 -0
  288. package/dist/assets/yaml-Buea-lGh.js +1 -0
  289. package/dist/assets/zenscript-DVFEvuxE.js +1 -0
  290. package/dist/assets/zig-VOosw3JB.js +1 -0
  291. package/dist/index.html +2 -2
  292. package/package.json +1 -1
  293. package/server/index.js +584 -78
package/server/index.js CHANGED
@@ -43652,8 +43652,8 @@ var logger = (fn = console.log) => {
43652
43652
 
43653
43653
  // server/app.ts
43654
43654
  import { readFile as readFile7 } from "fs/promises";
43655
- import { join as join26 } from "path";
43656
- import { existsSync as existsSync19 } from "fs";
43655
+ import { join as join27 } from "path";
43656
+ import { existsSync as existsSync20 } from "fs";
43657
43657
 
43658
43658
  // server/routes/health.ts
43659
43659
  var app = new Hono2;
@@ -181365,6 +181365,9 @@ app17.post("/caddy/stop", async (c) => {
181365
181365
  });
181366
181366
  var deployment_default = app17;
181367
181367
 
181368
+ // server/services/job-service.ts
181369
+ import { platform as platform3 } from "os";
181370
+
181368
181371
  // server/services/systemd-timer.ts
181369
181372
  init_logger3();
181370
181373
  import { execSync as execSync8 } from "child_process";
@@ -181867,35 +181870,514 @@ function deleteTimer(name) {
181867
181870
  log2.jobs.info("Timer deleted", { name: timerName });
181868
181871
  }
181869
181872
 
181873
+ // server/services/launchd-service.ts
181874
+ init_logger3();
181875
+ import { execSync as execSync9 } from "child_process";
181876
+ import { homedir as homedir9, platform as platform2 } from "os";
181877
+ import { join as join25 } from "path";
181878
+ import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
181879
+ var USER_LAUNCH_AGENTS = join25(homedir9(), "Library/LaunchAgents");
181880
+ var GLOBAL_LAUNCH_AGENTS = "/Library/LaunchAgents";
181881
+ var GLOBAL_LAUNCH_DAEMONS = "/Library/LaunchDaemons";
181882
+ var launchdAvailable = null;
181883
+ function isLaunchdAvailable() {
181884
+ if (launchdAvailable !== null) {
181885
+ return launchdAvailable;
181886
+ }
181887
+ if (platform2() !== "darwin") {
181888
+ launchdAvailable = false;
181889
+ return false;
181890
+ }
181891
+ try {
181892
+ execSync9("launchctl version", {
181893
+ encoding: "utf-8",
181894
+ timeout: 5000,
181895
+ stdio: ["pipe", "pipe", "pipe"]
181896
+ });
181897
+ launchdAvailable = true;
181898
+ return true;
181899
+ } catch {
181900
+ launchdAvailable = false;
181901
+ return false;
181902
+ }
181903
+ }
181904
+ function parsePlist(plistPath) {
181905
+ try {
181906
+ const json = execSync9(`plutil -convert json -o - "${plistPath}"`, {
181907
+ encoding: "utf-8",
181908
+ timeout: 5000,
181909
+ stdio: ["pipe", "pipe", "pipe"]
181910
+ });
181911
+ return JSON.parse(json);
181912
+ } catch (err) {
181913
+ log2.jobs.debug("Failed to parse plist", { plistPath, error: String(err) });
181914
+ return null;
181915
+ }
181916
+ }
181917
+ function parseLaunchctlList() {
181918
+ const entries = new Map;
181919
+ try {
181920
+ const output = execSync9("launchctl list", {
181921
+ encoding: "utf-8",
181922
+ timeout: 1e4,
181923
+ stdio: ["pipe", "pipe", "pipe"]
181924
+ });
181925
+ for (const line of output.split(`
181926
+ `).slice(1)) {
181927
+ const parts = line.trim().split(/\s+/);
181928
+ if (parts.length >= 3) {
181929
+ const [pidStr, statusStr, ...labelParts] = parts;
181930
+ const label = labelParts.join(" ");
181931
+ if (label) {
181932
+ entries.set(label, {
181933
+ pid: pidStr === "-" ? null : parseInt(pidStr, 10),
181934
+ status: parseInt(statusStr, 10) || 0,
181935
+ label
181936
+ });
181937
+ }
181938
+ }
181939
+ }
181940
+ } catch (err) {
181941
+ log2.jobs.error("Failed to run launchctl list", { error: String(err) });
181942
+ }
181943
+ return entries;
181944
+ }
181945
+ function formatCalendarInterval(ci) {
181946
+ const parts = [];
181947
+ if (ci.Weekday !== undefined) {
181948
+ const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
181949
+ parts.push(days[ci.Weekday] || `Weekday ${ci.Weekday}`);
181950
+ }
181951
+ if (ci.Month !== undefined) {
181952
+ const months = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
181953
+ parts.push(months[ci.Month] || `Month ${ci.Month}`);
181954
+ }
181955
+ if (ci.Day !== undefined) {
181956
+ parts.push(`Day ${ci.Day}`);
181957
+ }
181958
+ const hour = ci.Hour ?? 0;
181959
+ const minute = ci.Minute ?? 0;
181960
+ const time2 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
181961
+ if (parts.length === 0) {
181962
+ return `Daily at ${time2}`;
181963
+ }
181964
+ return `${parts.join(" ")} at ${time2}`;
181965
+ }
181966
+ function formatSchedule(plist) {
181967
+ if (plist.StartCalendarInterval) {
181968
+ const intervals = Array.isArray(plist.StartCalendarInterval) ? plist.StartCalendarInterval : [plist.StartCalendarInterval];
181969
+ if (intervals.length === 1) {
181970
+ return formatCalendarInterval(intervals[0]);
181971
+ }
181972
+ return `${intervals.length} schedules`;
181973
+ }
181974
+ if (plist.StartInterval) {
181975
+ const secs = plist.StartInterval;
181976
+ if (secs < 60)
181977
+ return `Every ${secs}s`;
181978
+ if (secs < 3600)
181979
+ return `Every ${Math.round(secs / 60)}m`;
181980
+ if (secs < 86400)
181981
+ return `Every ${Math.round(secs / 3600)}h`;
181982
+ return `Every ${Math.round(secs / 86400)}d`;
181983
+ }
181984
+ if (plist.KeepAlive)
181985
+ return "KeepAlive";
181986
+ if (plist.RunAtLoad)
181987
+ return "RunAtLoad";
181988
+ return null;
181989
+ }
181990
+ function calculateNextRun(plist) {
181991
+ if (!plist.StartCalendarInterval && !plist.StartInterval) {
181992
+ return null;
181993
+ }
181994
+ const now = new Date;
181995
+ if (plist.StartInterval) {
181996
+ const nextRun = new Date(now.getTime() + plist.StartInterval * 1000);
181997
+ return nextRun.toISOString();
181998
+ }
181999
+ if (plist.StartCalendarInterval) {
182000
+ const intervals = Array.isArray(plist.StartCalendarInterval) ? plist.StartCalendarInterval : [plist.StartCalendarInterval];
182001
+ let nextRun = null;
182002
+ for (const ci of intervals) {
182003
+ const candidate = new Date(now);
182004
+ candidate.setHours(ci.Hour ?? 0);
182005
+ candidate.setMinutes(ci.Minute ?? 0);
182006
+ candidate.setSeconds(0);
182007
+ candidate.setMilliseconds(0);
182008
+ if (candidate <= now) {
182009
+ if (ci.Weekday !== undefined) {
182010
+ candidate.setDate(candidate.getDate() + 7);
182011
+ } else if (ci.Day !== undefined) {
182012
+ candidate.setMonth(candidate.getMonth() + 1);
182013
+ } else {
182014
+ candidate.setDate(candidate.getDate() + 1);
182015
+ }
182016
+ }
182017
+ if (!nextRun || candidate < nextRun) {
182018
+ nextRun = candidate;
182019
+ }
182020
+ }
182021
+ return nextRun?.toISOString() ?? null;
182022
+ }
182023
+ return null;
182024
+ }
182025
+ function getCommand(plist) {
182026
+ if (plist.ProgramArguments && plist.ProgramArguments.length > 0) {
182027
+ return plist.ProgramArguments.join(" ");
182028
+ }
182029
+ if (plist.Program) {
182030
+ return plist.Program;
182031
+ }
182032
+ return null;
182033
+ }
182034
+ function getJobState(entry) {
182035
+ if (!entry) {
182036
+ return "inactive";
182037
+ }
182038
+ if (entry.pid !== null && entry.pid > 0) {
182039
+ return "active";
182040
+ }
182041
+ if (entry.status !== 0) {
182042
+ return "failed";
182043
+ }
182044
+ return "waiting";
182045
+ }
182046
+ function getLastResult2(entry) {
182047
+ if (!entry) {
182048
+ return null;
182049
+ }
182050
+ if (entry.status === 0) {
182051
+ return "success";
182052
+ }
182053
+ if (entry.status !== 0) {
182054
+ return "failed";
182055
+ }
182056
+ return "unknown";
182057
+ }
182058
+ function scanPlistDirectory(dir, scope) {
182059
+ const results = [];
182060
+ if (!existsSync18(dir)) {
182061
+ return results;
182062
+ }
182063
+ try {
182064
+ const files = readdirSync8(dir);
182065
+ for (const file of files) {
182066
+ if (file.endsWith(".plist")) {
182067
+ results.push({ path: join25(dir, file), scope });
182068
+ }
182069
+ }
182070
+ } catch (err) {
182071
+ log2.jobs.debug("Failed to scan directory", { dir, error: String(err) });
182072
+ }
182073
+ return results;
182074
+ }
182075
+ function listJobs(scope = "all") {
182076
+ const jobs = [];
182077
+ const launchctlStatus = parseLaunchctlList();
182078
+ const plistFiles = [];
182079
+ if (scope === "all" || scope === "user") {
182080
+ plistFiles.push(...scanPlistDirectory(USER_LAUNCH_AGENTS, "user"));
182081
+ }
182082
+ if (scope === "all" || scope === "system") {
182083
+ plistFiles.push(...scanPlistDirectory(GLOBAL_LAUNCH_AGENTS, "system"));
182084
+ plistFiles.push(...scanPlistDirectory(GLOBAL_LAUNCH_DAEMONS, "system"));
182085
+ }
182086
+ for (const { path: path10, scope: jobScope } of plistFiles) {
182087
+ const plist = parsePlist(path10);
182088
+ if (!plist || !plist.Label) {
182089
+ continue;
182090
+ }
182091
+ const entry = launchctlStatus.get(plist.Label);
182092
+ const state = getJobState(entry);
182093
+ const enabled = entry !== undefined && !plist.Disabled;
182094
+ jobs.push({
182095
+ name: plist.Label,
182096
+ scope: jobScope,
182097
+ description: null,
182098
+ state,
182099
+ enabled,
182100
+ nextRun: calculateNextRun(plist),
182101
+ lastRun: null,
182102
+ lastResult: getLastResult2(entry),
182103
+ schedule: formatSchedule(plist),
182104
+ serviceName: plist.Label,
182105
+ unitPath: path10
182106
+ });
182107
+ }
182108
+ jobs.sort((a, b) => {
182109
+ if (a.scope !== b.scope) {
182110
+ return a.scope === "user" ? -1 : 1;
182111
+ }
182112
+ return a.name.localeCompare(b.name);
182113
+ });
182114
+ return jobs;
182115
+ }
182116
+ function getJob(name, scope) {
182117
+ const directories = scope === "user" ? [USER_LAUNCH_AGENTS] : [GLOBAL_LAUNCH_AGENTS, GLOBAL_LAUNCH_DAEMONS];
182118
+ let plistPath = null;
182119
+ let plist = null;
182120
+ for (const dir of directories) {
182121
+ const candidates = [
182122
+ join25(dir, `${name}.plist`)
182123
+ ];
182124
+ for (const candidate of candidates) {
182125
+ if (existsSync18(candidate)) {
182126
+ const parsed = parsePlist(candidate);
182127
+ if (parsed?.Label === name) {
182128
+ plistPath = candidate;
182129
+ plist = parsed;
182130
+ break;
182131
+ }
182132
+ }
182133
+ }
182134
+ if (plist)
182135
+ break;
182136
+ if (existsSync18(dir)) {
182137
+ try {
182138
+ const files = readdirSync8(dir);
182139
+ for (const file of files) {
182140
+ if (file.endsWith(".plist")) {
182141
+ const path10 = join25(dir, file);
182142
+ const parsed = parsePlist(path10);
182143
+ if (parsed?.Label === name) {
182144
+ plistPath = path10;
182145
+ plist = parsed;
182146
+ break;
182147
+ }
182148
+ }
182149
+ }
182150
+ } catch {}
182151
+ }
182152
+ if (plist)
182153
+ break;
182154
+ }
182155
+ if (!plist || !plistPath) {
182156
+ return null;
182157
+ }
182158
+ const launchctlStatus = parseLaunchctlList();
182159
+ const entry = launchctlStatus.get(name);
182160
+ const state = getJobState(entry);
182161
+ const enabled = entry !== undefined && !plist.Disabled;
182162
+ let plistContent = null;
182163
+ try {
182164
+ plistContent = execSync9(`cat "${plistPath}"`, {
182165
+ encoding: "utf-8",
182166
+ timeout: 5000,
182167
+ stdio: ["pipe", "pipe", "pipe"]
182168
+ });
182169
+ } catch {}
182170
+ return {
182171
+ name,
182172
+ scope,
182173
+ description: null,
182174
+ state,
182175
+ enabled,
182176
+ nextRun: calculateNextRun(plist),
182177
+ lastRun: null,
182178
+ lastResult: getLastResult2(entry),
182179
+ schedule: formatSchedule(plist),
182180
+ serviceName: name,
182181
+ unitPath: plistPath,
182182
+ timerContent: plistContent,
182183
+ serviceContent: null,
182184
+ command: getCommand(plist),
182185
+ workingDirectory: plist.WorkingDirectory ?? null,
182186
+ lastRunStart: null,
182187
+ lastRunEnd: null,
182188
+ lastRunDurationMs: null,
182189
+ lastRunCpuTimeMs: null
182190
+ };
182191
+ }
182192
+ function getJobLogs(name, scope, lines = 100) {
182193
+ const job = getJob(name, scope);
182194
+ if (!job) {
182195
+ return [];
182196
+ }
182197
+ let processName = name;
182198
+ if (job.command) {
182199
+ const parts = job.command.split(/\s+/);
182200
+ if (parts.length > 0) {
182201
+ const executable = parts[0];
182202
+ processName = executable.split("/").pop() || name;
182203
+ }
182204
+ }
182205
+ try {
182206
+ const cmd = `log show --predicate 'process == "${processName}" OR subsystem == "${name}"' --last 1h --style json 2>/dev/null | head -${lines * 20}`;
182207
+ const output = execSync9(cmd, {
182208
+ encoding: "utf-8",
182209
+ timeout: 30000,
182210
+ stdio: ["pipe", "pipe", "pipe"],
182211
+ maxBuffer: 10 * 1024 * 1024
182212
+ });
182213
+ const entries = [];
182214
+ try {
182215
+ const parsed = JSON.parse(output);
182216
+ if (Array.isArray(parsed)) {
182217
+ for (const entry of parsed.slice(-lines)) {
182218
+ entries.push({
182219
+ timestamp: entry.timestamp || new Date().toISOString(),
182220
+ message: entry.eventMessage || entry.message || "",
182221
+ priority: mapLogLevel(entry.messageType)
182222
+ });
182223
+ }
182224
+ }
182225
+ } catch {
182226
+ for (const line of output.split(`
182227
+ `)) {
182228
+ if (!line.trim())
182229
+ continue;
182230
+ try {
182231
+ const entry = JSON.parse(line);
182232
+ entries.push({
182233
+ timestamp: entry.timestamp || new Date().toISOString(),
182234
+ message: entry.eventMessage || entry.message || "",
182235
+ priority: mapLogLevel(entry.messageType)
182236
+ });
182237
+ } catch {}
182238
+ }
182239
+ }
182240
+ return entries.slice(-lines);
182241
+ } catch (err) {
182242
+ log2.jobs.debug("Failed to get job logs", { name, error: String(err) });
182243
+ const job2 = getJob(name, scope);
182244
+ if (job2) {}
182245
+ return [];
182246
+ }
182247
+ }
182248
+ function mapLogLevel(messageType) {
182249
+ switch (messageType) {
182250
+ case "Error":
182251
+ case "Fault":
182252
+ return "error";
182253
+ case "Warning":
182254
+ return "warning";
182255
+ default:
182256
+ return "info";
182257
+ }
182258
+ }
182259
+
182260
+ // server/services/job-service.ts
182261
+ function getPlatform() {
182262
+ if (platform3() === "darwin" && isLaunchdAvailable()) {
182263
+ return "launchd";
182264
+ }
182265
+ if (platform3() === "linux" && isSystemdAvailable()) {
182266
+ return "systemd";
182267
+ }
182268
+ return null;
182269
+ }
182270
+ function isJobsAvailable() {
182271
+ return getPlatform() !== null;
182272
+ }
182273
+ function canCreateJobs() {
182274
+ return getPlatform() === "systemd";
182275
+ }
182276
+ function listJobs2(scope = "all") {
182277
+ const p = getPlatform();
182278
+ if (p === "launchd") {
182279
+ return listJobs(scope);
182280
+ }
182281
+ if (p === "systemd") {
182282
+ return listTimers(scope);
182283
+ }
182284
+ return [];
182285
+ }
182286
+ function getJob2(name, scope) {
182287
+ const p = getPlatform();
182288
+ if (p === "launchd") {
182289
+ return getJob(name, scope);
182290
+ }
182291
+ if (p === "systemd") {
182292
+ return getTimer(name, scope);
182293
+ }
182294
+ return null;
182295
+ }
182296
+ function getJobLogs2(name, scope, lines = 100) {
182297
+ const p = getPlatform();
182298
+ if (p === "launchd") {
182299
+ return getJobLogs(name, scope, lines);
182300
+ }
182301
+ if (p === "systemd") {
182302
+ return getTimerLogs(name, scope, lines);
182303
+ }
182304
+ return [];
182305
+ }
182306
+ function enableJob(name, scope, enable) {
182307
+ if (!canCreateJobs()) {
182308
+ throw new Error("Job modification not supported on this platform");
182309
+ }
182310
+ enableTimer(name, scope, enable);
182311
+ }
182312
+ function startJob(name, scope) {
182313
+ if (!canCreateJobs()) {
182314
+ throw new Error("Job modification not supported on this platform");
182315
+ }
182316
+ startTimer(name, scope);
182317
+ }
182318
+ function stopJob(name, scope) {
182319
+ if (!canCreateJobs()) {
182320
+ throw new Error("Job modification not supported on this platform");
182321
+ }
182322
+ stopTimer(name, scope);
182323
+ }
182324
+ function runJobNow(name, scope) {
182325
+ if (!canCreateJobs()) {
182326
+ throw new Error("Job modification not supported on this platform");
182327
+ }
182328
+ runNow(name, scope);
182329
+ }
182330
+ function createJob(config) {
182331
+ if (!canCreateJobs()) {
182332
+ throw new Error("Job creation not supported on this platform");
182333
+ }
182334
+ createTimer(config);
182335
+ }
182336
+ function updateJob(name, updates) {
182337
+ if (!canCreateJobs()) {
182338
+ throw new Error("Job modification not supported on this platform");
182339
+ }
182340
+ updateTimer(name, updates);
182341
+ }
182342
+ function deleteJob(name) {
182343
+ if (!canCreateJobs()) {
182344
+ throw new Error("Job deletion not supported on this platform");
182345
+ }
182346
+ deleteTimer(name);
182347
+ }
182348
+
181870
182349
  // server/routes/jobs.ts
181871
182350
  init_logger3();
181872
182351
  var app18 = new Hono2;
181873
182352
  app18.get("/available", (c) => {
181874
- const available = isSystemdAvailable();
181875
- return c.json({ available });
182353
+ return c.json({
182354
+ available: isJobsAvailable(),
182355
+ canCreate: canCreateJobs(),
182356
+ platform: getPlatform()
182357
+ });
181876
182358
  });
181877
182359
  app18.get("/", (c) => {
181878
182360
  const scope = c.req.query("scope") || "all";
181879
182361
  try {
181880
- const timers = listTimers(scope);
181881
- return c.json(timers);
182362
+ const jobs = listJobs2(scope);
182363
+ return c.json(jobs);
181882
182364
  } catch (err) {
181883
- log2.jobs.error("Failed to list timers", { error: String(err) });
181884
- return c.json({ error: "Failed to list timers" }, 500);
182365
+ log2.jobs.error("Failed to list jobs", { error: String(err) });
182366
+ return c.json({ error: "Failed to list jobs" }, 500);
181885
182367
  }
181886
182368
  });
181887
182369
  app18.get("/:name", (c) => {
181888
182370
  const name = c.req.param("name");
181889
182371
  const scope = c.req.query("scope") || "user";
181890
182372
  try {
181891
- const timer = getTimer(name, scope);
181892
- if (!timer) {
181893
- return c.json({ error: "Timer not found" }, 404);
182373
+ const job = getJob2(name, scope);
182374
+ if (!job) {
182375
+ return c.json({ error: "Job not found" }, 404);
181894
182376
  }
181895
- return c.json(timer);
182377
+ return c.json(job);
181896
182378
  } catch (err) {
181897
- log2.jobs.error("Failed to get timer", { name, error: String(err) });
181898
- return c.json({ error: "Failed to get timer" }, 500);
182379
+ log2.jobs.error("Failed to get job", { name, error: String(err) });
182380
+ return c.json({ error: "Failed to get job" }, 500);
181899
182381
  }
181900
182382
  });
181901
182383
  app18.get("/:name/logs", (c) => {
@@ -181903,103 +182385,127 @@ app18.get("/:name/logs", (c) => {
181903
182385
  const scope = c.req.query("scope") || "user";
181904
182386
  const lines = parseInt(c.req.query("lines") || "100", 10);
181905
182387
  try {
181906
- const entries = getTimerLogs(name, scope, lines);
182388
+ const entries = getJobLogs2(name, scope, lines);
181907
182389
  return c.json({ entries });
181908
182390
  } catch (err) {
181909
- log2.jobs.error("Failed to get timer logs", { name, error: String(err) });
181910
- return c.json({ error: "Failed to get timer logs" }, 500);
182391
+ log2.jobs.error("Failed to get job logs", { name, error: String(err) });
182392
+ return c.json({ error: "Failed to get job logs" }, 500);
181911
182393
  }
181912
182394
  });
181913
182395
  app18.post("/", async (c) => {
182396
+ if (!canCreateJobs()) {
182397
+ return c.json({ error: "Job creation not supported on this platform" }, 400);
182398
+ }
181914
182399
  try {
181915
182400
  const body = await c.req.json();
181916
182401
  if (!body.name || !body.description || !body.schedule || !body.command) {
181917
182402
  return c.json({ error: "name, description, schedule, and command are required" }, 400);
181918
182403
  }
181919
182404
  if (!/^[a-zA-Z0-9_-]+$/.test(body.name)) {
181920
- return c.json({ error: "Timer name must contain only alphanumeric characters, hyphens, and underscores" }, 400);
182405
+ return c.json({ error: "Job name must contain only alphanumeric characters, hyphens, and underscores" }, 400);
181921
182406
  }
181922
- createTimer(body);
182407
+ createJob(body);
181923
182408
  return c.json({ success: true }, 201);
181924
182409
  } catch (err) {
181925
- log2.jobs.error("Failed to create timer", { error: String(err) });
181926
- return c.json({ error: err instanceof Error ? err.message : "Failed to create timer" }, 400);
182410
+ log2.jobs.error("Failed to create job", { error: String(err) });
182411
+ return c.json({ error: err instanceof Error ? err.message : "Failed to create job" }, 400);
181927
182412
  }
181928
182413
  });
181929
182414
  app18.patch("/:name", async (c) => {
182415
+ if (!canCreateJobs()) {
182416
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182417
+ }
181930
182418
  const name = c.req.param("name");
181931
182419
  try {
181932
182420
  const body = await c.req.json();
181933
- updateTimer(name, body);
182421
+ updateJob(name, body);
181934
182422
  return c.json({ success: true });
181935
182423
  } catch (err) {
181936
- log2.jobs.error("Failed to update timer", { name, error: String(err) });
181937
- return c.json({ error: err instanceof Error ? err.message : "Failed to update timer" }, 400);
182424
+ log2.jobs.error("Failed to update job", { name, error: String(err) });
182425
+ return c.json({ error: err instanceof Error ? err.message : "Failed to update job" }, 400);
181938
182426
  }
181939
182427
  });
181940
182428
  app18.delete("/:name", (c) => {
182429
+ if (!canCreateJobs()) {
182430
+ return c.json({ error: "Job deletion not supported on this platform" }, 400);
182431
+ }
181941
182432
  const name = c.req.param("name");
181942
182433
  try {
181943
- deleteTimer(name);
182434
+ deleteJob(name);
181944
182435
  return c.json({ success: true });
181945
182436
  } catch (err) {
181946
- log2.jobs.error("Failed to delete timer", { name, error: String(err) });
181947
- return c.json({ error: err instanceof Error ? err.message : "Failed to delete timer" }, 400);
182437
+ log2.jobs.error("Failed to delete job", { name, error: String(err) });
182438
+ return c.json({ error: err instanceof Error ? err.message : "Failed to delete job" }, 400);
181948
182439
  }
181949
182440
  });
181950
182441
  app18.post("/:name/enable", (c) => {
182442
+ if (!canCreateJobs()) {
182443
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182444
+ }
181951
182445
  const name = c.req.param("name");
181952
182446
  const scope = c.req.query("scope") || "user";
181953
182447
  try {
181954
- enableTimer(name, scope, true);
182448
+ enableJob(name, scope, true);
181955
182449
  return c.json({ success: true });
181956
182450
  } catch (err) {
181957
- log2.jobs.error("Failed to enable timer", { name, error: String(err) });
181958
- return c.json({ error: err instanceof Error ? err.message : "Failed to enable timer" }, 400);
182451
+ log2.jobs.error("Failed to enable job", { name, error: String(err) });
182452
+ return c.json({ error: err instanceof Error ? err.message : "Failed to enable job" }, 400);
181959
182453
  }
181960
182454
  });
181961
182455
  app18.post("/:name/disable", (c) => {
182456
+ if (!canCreateJobs()) {
182457
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182458
+ }
181962
182459
  const name = c.req.param("name");
181963
182460
  const scope = c.req.query("scope") || "user";
181964
182461
  try {
181965
- enableTimer(name, scope, false);
182462
+ enableJob(name, scope, false);
181966
182463
  return c.json({ success: true });
181967
182464
  } catch (err) {
181968
- log2.jobs.error("Failed to disable timer", { name, error: String(err) });
181969
- return c.json({ error: err instanceof Error ? err.message : "Failed to disable timer" }, 400);
182465
+ log2.jobs.error("Failed to disable job", { name, error: String(err) });
182466
+ return c.json({ error: err instanceof Error ? err.message : "Failed to disable job" }, 400);
181970
182467
  }
181971
182468
  });
181972
182469
  app18.post("/:name/start", (c) => {
182470
+ if (!canCreateJobs()) {
182471
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182472
+ }
181973
182473
  const name = c.req.param("name");
181974
182474
  const scope = c.req.query("scope") || "user";
181975
182475
  try {
181976
- startTimer(name, scope);
182476
+ startJob(name, scope);
181977
182477
  return c.json({ success: true });
181978
182478
  } catch (err) {
181979
- log2.jobs.error("Failed to start timer", { name, error: String(err) });
181980
- return c.json({ error: err instanceof Error ? err.message : "Failed to start timer" }, 400);
182479
+ log2.jobs.error("Failed to start job", { name, error: String(err) });
182480
+ return c.json({ error: err instanceof Error ? err.message : "Failed to start job" }, 400);
181981
182481
  }
181982
182482
  });
181983
182483
  app18.post("/:name/stop", (c) => {
182484
+ if (!canCreateJobs()) {
182485
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182486
+ }
181984
182487
  const name = c.req.param("name");
181985
182488
  const scope = c.req.query("scope") || "user";
181986
182489
  try {
181987
- stopTimer(name, scope);
182490
+ stopJob(name, scope);
181988
182491
  return c.json({ success: true });
181989
182492
  } catch (err) {
181990
- log2.jobs.error("Failed to stop timer", { name, error: String(err) });
181991
- return c.json({ error: err instanceof Error ? err.message : "Failed to stop timer" }, 400);
182493
+ log2.jobs.error("Failed to stop job", { name, error: String(err) });
182494
+ return c.json({ error: err instanceof Error ? err.message : "Failed to stop job" }, 400);
181992
182495
  }
181993
182496
  });
181994
182497
  app18.post("/:name/run", (c) => {
182498
+ if (!canCreateJobs()) {
182499
+ return c.json({ error: "Job modification not supported on this platform" }, 400);
182500
+ }
181995
182501
  const name = c.req.param("name");
181996
182502
  const scope = c.req.query("scope") || "user";
181997
182503
  try {
181998
- runNow(name, scope);
182504
+ runJobNow(name, scope);
181999
182505
  return c.json({ success: true });
182000
182506
  } catch (err) {
182001
- log2.jobs.error("Failed to run timer service", { name, error: String(err) });
182002
- return c.json({ error: err instanceof Error ? err.message : "Failed to run timer service" }, 400);
182507
+ log2.jobs.error("Failed to run job service", { name, error: String(err) });
182508
+ return c.json({ error: err instanceof Error ? err.message : "Failed to run job service" }, 400);
182003
182509
  }
182004
182510
  });
182005
182511
  var jobs_default = app18;
@@ -182145,9 +182651,9 @@ var opencode_default = app19;
182145
182651
  init_nanoid();
182146
182652
  init_db2();
182147
182653
  init_drizzle_orm();
182148
- import { existsSync as existsSync18, rmSync as rmSync5 } from "fs";
182149
- import { homedir as homedir9 } from "os";
182150
- import { resolve as resolve5, join as join25 } from "path";
182654
+ import { existsSync as existsSync19, rmSync as rmSync5 } from "fs";
182655
+ import { homedir as homedir10 } from "os";
182656
+ import { resolve as resolve5, join as join26 } from "path";
182151
182657
  var app20 = new Hono2;
182152
182658
  function buildProjectWithDetails(project, repo, appRow, services, tab) {
182153
182659
  return {
@@ -182254,7 +182760,7 @@ app20.post("/", async (c) => {
182254
182760
  }
182255
182761
  } else if (body.path) {
182256
182762
  const repoPath = expandPath2(body.path);
182257
- if (!existsSync18(repoPath)) {
182763
+ if (!existsSync19(repoPath)) {
182258
182764
  return c.json({ error: `Directory does not exist: ${repoPath}` }, 400);
182259
182765
  }
182260
182766
  const existing = db2.select().from(repositories).where(eq(repositories.path, repoPath)).get();
@@ -182277,16 +182783,16 @@ app20.post("/", async (c) => {
182277
182783
  } else if (body.url) {
182278
182784
  const { isGitUrl: isGitUrl2, extractRepoNameFromUrl: extractRepoNameFromUrl2 } = await Promise.resolve().then(() => exports_git_utils);
182279
182785
  const { getSettings: getSettings2 } = await Promise.resolve().then(() => (init_settings(), exports_settings));
182280
- const { execSync: execSync9 } = await import("child_process");
182786
+ const { execSync: execSync10 } = await import("child_process");
182281
182787
  const { mkdirSync: mkdirSync7, rmSync: rmSync6 } = await import("fs");
182282
- const { homedir: homedir10 } = await import("os");
182788
+ const { homedir: homedir11 } = await import("os");
182283
182789
  if (!isGitUrl2(body.url)) {
182284
182790
  return c.json({ error: "Invalid git URL format" }, 400);
182285
182791
  }
182286
182792
  const settings = getSettings2();
182287
182793
  let parentDir = body.targetDir?.trim() || settings.paths.defaultGitReposDir;
182288
182794
  parentDir = expandPath2(parentDir);
182289
- const home = homedir10();
182795
+ const home = homedir11();
182290
182796
  if (resolve5(parentDir) === home) {
182291
182797
  return c.json({ error: "Cannot clone directly into home directory. Please specify a subdirectory." }, 400);
182292
182798
  }
@@ -182297,30 +182803,30 @@ app20.post("/", async (c) => {
182297
182803
  if (repoName.includes("/") || repoName.includes("\\")) {
182298
182804
  return c.json({ error: "Folder name cannot contain path separators" }, 400);
182299
182805
  }
182300
- const targetPath = join25(parentDir, repoName);
182806
+ const targetPath = join26(parentDir, repoName);
182301
182807
  const resolvedParent = resolve5(parentDir);
182302
182808
  const resolvedTarget = resolve5(targetPath);
182303
182809
  if (!resolvedTarget.startsWith(resolvedParent + "/") && resolvedTarget !== resolvedParent) {
182304
182810
  return c.json({ error: "Invalid target path" }, 400);
182305
182811
  }
182306
- if (existsSync18(targetPath)) {
182812
+ if (existsSync19(targetPath)) {
182307
182813
  return c.json({ error: `Directory already exists: ${targetPath}` }, 400);
182308
182814
  }
182309
182815
  const existingRepo = db2.select().from(repositories).where(eq(repositories.path, targetPath)).get();
182310
182816
  if (existingRepo) {
182311
182817
  return c.json({ error: "Repository with this path already exists in database" }, 400);
182312
182818
  }
182313
- if (!existsSync18(parentDir)) {
182819
+ if (!existsSync19(parentDir)) {
182314
182820
  mkdirSync7(parentDir, { recursive: true });
182315
182821
  }
182316
182822
  try {
182317
- execSync9(`git clone "${body.url}" "${targetPath}"`, {
182823
+ execSync10(`git clone "${body.url}" "${targetPath}"`, {
182318
182824
  encoding: "utf-8",
182319
182825
  stdio: "pipe",
182320
182826
  timeout: 120000
182321
182827
  });
182322
182828
  } catch (cloneErr) {
182323
- if (existsSync18(targetPath) && resolvedTarget.startsWith(resolvedParent + "/")) {
182829
+ if (existsSync19(targetPath) && resolvedTarget.startsWith(resolvedParent + "/")) {
182324
182830
  rmSync6(targetPath, { recursive: true, force: true });
182325
182831
  }
182326
182832
  const errorMessage = cloneErr instanceof Error ? cloneErr.message : "Clone failed";
@@ -182427,7 +182933,7 @@ app20.delete("/:id", async (c) => {
182427
182933
  }
182428
182934
  let directoryDeleted = false;
182429
182935
  if (deleteDirectory && repoPath) {
182430
- const home = homedir9();
182936
+ const home = homedir10();
182431
182937
  if (resolve5(repoPath) === home) {
182432
182938
  return c.json({ error: "Cannot delete home directory" }, 400);
182433
182939
  }
@@ -182435,9 +182941,9 @@ app20.delete("/:id", async (c) => {
182435
182941
  if (dangerousPaths.includes(resolve5(repoPath))) {
182436
182942
  return c.json({ error: "Cannot delete system directory" }, 400);
182437
182943
  }
182438
- if (existsSync18(repoPath)) {
182439
- const gitPath = join25(repoPath, ".git");
182440
- if (!existsSync18(gitPath)) {
182944
+ if (existsSync19(repoPath)) {
182945
+ const gitPath = join26(repoPath, ".git");
182946
+ if (!existsSync19(gitPath)) {
182441
182947
  return c.json({ error: "Directory does not appear to be a git repository" }, 400);
182442
182948
  }
182443
182949
  try {
@@ -182587,12 +183093,12 @@ app20.delete("/:id/app", async (c) => {
182587
183093
  app20.post("/scan", async (c) => {
182588
183094
  try {
182589
183095
  const body = await c.req.json().catch(() => ({}));
182590
- const { existsSync: existsSync19, readdirSync: readdirSync8 } = await import("fs");
182591
- const { join: join26 } = await import("path");
183096
+ const { existsSync: existsSync20, readdirSync: readdirSync9 } = await import("fs");
183097
+ const { join: join27 } = await import("path");
182592
183098
  const { getSettings: getSettings2, expandPath: expandPath2 } = await Promise.resolve().then(() => (init_settings(), exports_settings));
182593
183099
  const settings = getSettings2();
182594
183100
  const directory = expandPath2(body.directory || settings.paths.defaultGitReposDir);
182595
- if (!existsSync19(directory)) {
183101
+ if (!existsSync20(directory)) {
182596
183102
  return c.json({ error: `Directory does not exist: ${directory}` }, 400);
182597
183103
  }
182598
183104
  const allRepos = db2.select().from(repositories).all();
@@ -182600,15 +183106,15 @@ app20.post("/scan", async (c) => {
182600
183106
  const allProjects = db2.select().from(projects).all();
182601
183107
  const repoIdWithProject = new Set(allProjects.filter((p) => p.repositoryId).map((p) => p.repositoryId));
182602
183108
  const discovered = [];
182603
- const entries = readdirSync8(directory, { withFileTypes: true });
183109
+ const entries = readdirSync9(directory, { withFileTypes: true });
182604
183110
  for (const entry of entries) {
182605
183111
  if (!entry.isDirectory())
182606
183112
  continue;
182607
183113
  if (entry.name.startsWith("."))
182608
183114
  continue;
182609
- const subPath = join26(directory, entry.name);
182610
- const gitPath = join26(subPath, ".git");
182611
- if (existsSync19(gitPath)) {
183115
+ const subPath = join27(directory, entry.name);
183116
+ const gitPath = join27(subPath, ".git");
183117
+ if (existsSync20(gitPath)) {
182612
183118
  const existingRepo = repoPathMap.get(subPath);
182613
183119
  discovered.push({
182614
183120
  path: subPath,
@@ -182630,14 +183136,14 @@ app20.post("/bulk", async (c) => {
182630
183136
  if (!body.repositories || !Array.isArray(body.repositories) || body.repositories.length === 0) {
182631
183137
  return c.json({ error: "repositories array is required" }, 400);
182632
183138
  }
182633
- const { existsSync: existsSync19 } = await import("fs");
183139
+ const { existsSync: existsSync20 } = await import("fs");
182634
183140
  const { expandPath: expandPath2 } = await Promise.resolve().then(() => (init_settings(), exports_settings));
182635
183141
  const now = new Date().toISOString();
182636
183142
  const createdProjects = [];
182637
183143
  let skipped = 0;
182638
183144
  for (const repoInput of body.repositories) {
182639
183145
  const repoPath = expandPath2(repoInput.path);
182640
- if (!existsSync19(repoPath)) {
183146
+ if (!existsSync20(repoPath)) {
182641
183147
  skipped++;
182642
183148
  continue;
182643
183149
  }
@@ -182710,9 +183216,9 @@ var projects_default = app20;
182710
183216
  init_logger3();
182711
183217
  function getDistPath() {
182712
183218
  if (process.env.VIBORA_PACKAGE_ROOT) {
182713
- return join26(process.env.VIBORA_PACKAGE_ROOT, "dist");
183219
+ return join27(process.env.VIBORA_PACKAGE_ROOT, "dist");
182714
183220
  }
182715
- return join26(process.cwd(), "dist");
183221
+ return join27(process.cwd(), "dist");
182716
183222
  }
182717
183223
  function createApp() {
182718
183224
  const app21 = new Hono2;
@@ -182788,15 +183294,15 @@ function createApp() {
182788
183294
  });
182789
183295
  };
182790
183296
  app21.get("/assets/*", async (c) => {
182791
- const assetPath = join26(distPath, c.req.path);
182792
- if (existsSync19(assetPath)) {
183297
+ const assetPath = join27(distPath, c.req.path);
183298
+ if (existsSync20(assetPath)) {
182793
183299
  return serveFile(assetPath);
182794
183300
  }
182795
183301
  return c.notFound();
182796
183302
  });
182797
183303
  app21.get("/sounds/*", async (c) => {
182798
- const soundPath = join26(distPath, c.req.path);
182799
- if (existsSync19(soundPath)) {
183304
+ const soundPath = join27(distPath, c.req.path);
183305
+ if (existsSync20(soundPath)) {
182800
183306
  return serveFile(soundPath);
182801
183307
  }
182802
183308
  return c.notFound();
@@ -182804,8 +183310,8 @@ function createApp() {
182804
183310
  const staticFiles = ["vibora-icon.png", "vibora-logo.jpeg", "vite.svg", "logo.png", "goat.jpeg"];
182805
183311
  for (const file of staticFiles) {
182806
183312
  app21.get(`/${file}`, async () => {
182807
- const filePath = join26(distPath, file);
182808
- if (existsSync19(filePath)) {
183313
+ const filePath = join27(distPath, file);
183314
+ if (existsSync20(filePath)) {
182809
183315
  return serveFile(filePath);
182810
183316
  }
182811
183317
  return new Response("Not Found", { status: 404 });
@@ -182816,7 +183322,7 @@ function createApp() {
182816
183322
  if (path10.startsWith("/api/") || path10.startsWith("/ws/") || path10 === "/health") {
182817
183323
  return next();
182818
183324
  }
182819
- const html = await readFile7(join26(distPath, "index.html"), "utf-8");
183325
+ const html = await readFile7(join27(distPath, "index.html"), "utf-8");
182820
183326
  return c.html(html);
182821
183327
  });
182822
183328
  }
@@ -182832,7 +183338,7 @@ init_settings();
182832
183338
  init_db2();
182833
183339
  init_schema();
182834
183340
  init_drizzle_orm();
182835
- import { execSync as execSync9 } from "child_process";
183341
+ import { execSync as execSync10 } from "child_process";
182836
183342
  init_logger3();
182837
183343
  var POLL_INTERVAL = 60000;
182838
183344
  function parsePrUrl(url) {
@@ -182848,7 +183354,7 @@ function checkPrStatus(prUrl) {
182848
183354
  return null;
182849
183355
  }
182850
183356
  try {
182851
- const output = execSync9(`gh pr view ${parsed.number} --repo ${parsed.owner}/${parsed.repo} --json state,mergedAt`, { encoding: "utf-8", timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
183357
+ const output = execSync10(`gh pr view ${parsed.number} --repo ${parsed.owner}/${parsed.repo} --json state,mergedAt`, { encoding: "utf-8", timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
182852
183358
  const data = JSON.parse(output);
182853
183359
  return {
182854
183360
  state: data.state,