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.
- package/bin/vibora.js +1 -1
- package/dist/assets/abap-BdImnpbu.js +1 -0
- package/dist/assets/actionscript-3-CfeIJUat.js +1 -0
- package/dist/assets/ada-bCR0ucgS.js +1 -0
- package/dist/assets/andromeeda-C-Jbm3Hp.js +1 -0
- package/dist/assets/angular-html-CU67Zn6k.js +1 -0
- package/dist/assets/angular-ts-BwZT4LLn.js +1 -0
- package/dist/assets/apache-Pmp26Uib.js +1 -0
- package/dist/assets/apex-DDbsPZ6N.js +1 -0
- package/dist/assets/apl-dKokRX4l.js +1 -0
- package/dist/assets/applescript-Co6uUVPk.js +1 -0
- package/dist/assets/ara-BRHolxvo.js +1 -0
- package/dist/assets/asciidoc-Dv7Oe6Be.js +1 -0
- package/dist/assets/asm-D_Q5rh1f.js +1 -0
- package/dist/assets/astro-CbQHKStN.js +1 -0
- package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/dist/assets/awk-DMzUqQB5.js +1 -0
- package/dist/assets/ayu-dark-Cv9koXgw.js +1 -0
- package/dist/assets/ballerina-BFfxhgS-.js +1 -0
- package/dist/assets/bat-BkioyH1T.js +1 -0
- package/dist/assets/beancount-k_qm7-4y.js +1 -0
- package/dist/assets/berry-uYugtg8r.js +1 -0
- package/dist/assets/bibtex-CHM0blh-.js +1 -0
- package/dist/assets/bicep-Bmn6On1c.js +1 -0
- package/dist/assets/blade-DVc8C-J4.js +1 -0
- package/dist/assets/bsl-BO_Y6i37.js +1 -0
- package/dist/assets/c-BIGW1oBm.js +1 -0
- package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
- package/dist/assets/cairo-KRGpt6FW.js +1 -0
- package/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/dist/assets/clarity-D53aC0YG.js +1 -0
- package/dist/assets/clojure-P80f7IUj.js +1 -0
- package/dist/assets/cmake-D1j8_8rp.js +1 -0
- package/dist/assets/cobol-nwyudZeR.js +1 -0
- package/dist/assets/codeowners-Bp6g37R7.js +1 -0
- package/dist/assets/codeql-DsOJ9woJ.js +1 -0
- package/dist/assets/coffee-Ch7k5sss.js +1 -0
- package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/dist/assets/coq-DkFqJrB1.js +1 -0
- package/dist/assets/cpp-CofmeUqb.js +1 -0
- package/dist/assets/crystal-tKQVLTB8.js +1 -0
- package/dist/assets/csharp-K5feNrxe.js +1 -0
- package/dist/assets/css-DPfMkruS.js +1 -0
- package/dist/assets/csv-fuZLfV_i.js +1 -0
- package/dist/assets/cue-D82EKSYY.js +1 -0
- package/dist/assets/cypher-COkxafJQ.js +1 -0
- package/dist/assets/d-85-TOEBH.js +1 -0
- package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/assets/dart-CF10PKvl.js +1 -0
- package/dist/assets/dax-CEL-wOlO.js +1 -0
- package/dist/assets/desktop-BmXAJ9_W.js +1 -0
- package/dist/assets/diff-D97Zzqfu.js +1 -0
- package/dist/assets/docker-BcOcwvcX.js +1 -0
- package/dist/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/assets/dracula-BzJJZx-M.js +1 -0
- package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
- package/dist/assets/edge-BkV0erSs.js +1 -0
- package/dist/assets/elixir-CDX3lj18.js +1 -0
- package/dist/assets/elm-DbKCFpqz.js +1 -0
- package/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
- package/dist/assets/erb-BOJIQeun.js +1 -0
- package/dist/assets/erlang-DsQrWhSR.js +1 -0
- package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/dist/assets/everforest-light-C8M2exoo.js +1 -0
- package/dist/assets/fennel-BYunw83y.js +1 -0
- package/dist/assets/fish-BvzEVeQv.js +1 -0
- package/dist/assets/fluent-C4IJs8-o.js +1 -0
- package/dist/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
- package/dist/assets/fortran-free-form-D22FLkUw.js +1 -0
- package/dist/assets/fsharp-CXgrBDvD.js +1 -0
- package/dist/assets/gdresource-B7Tvp0Sc.js +1 -0
- package/dist/assets/gdscript-DTMYz4Jt.js +1 -0
- package/dist/assets/gdshader-DkwncUOv.js +1 -0
- package/dist/assets/genie-D0YGMca9.js +1 -0
- package/dist/assets/gherkin-DyxjwDmM.js +1 -0
- package/dist/assets/git-commit-F4YmCXRG.js +1 -0
- package/dist/assets/git-rebase-r7XF79zn.js +1 -0
- package/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/dist/assets/github-light-DAi9KRSo.js +1 -0
- package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
- package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/dist/assets/gleam-BspZqrRM.js +1 -0
- package/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
- package/dist/assets/glimmer-ts-U6CK756n.js +1 -0
- package/dist/assets/glsl-DplSGwfg.js +1 -0
- package/dist/assets/gnuplot-DdkO51Og.js +1 -0
- package/dist/assets/go-Dn2_MT6a.js +1 -0
- package/dist/assets/graphql-ChdNCCLP.js +1 -0
- package/dist/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/dist/assets/hack-CaT9iCJl.js +1 -0
- package/dist/assets/haml-B8DHNrY2.js +1 -0
- package/dist/assets/handlebars-BL8al0AC.js +1 -0
- package/dist/assets/haskell-Df6bDoY_.js +1 -0
- package/dist/assets/haxe-CzTSHFRz.js +1 -0
- package/dist/assets/hcl-BWvSN4gD.js +1 -0
- package/dist/assets/hjson-D5-asLiD.js +1 -0
- package/dist/assets/hlsl-D3lLCCz7.js +1 -0
- package/dist/assets/houston-DnULxvSX.js +1 -0
- package/dist/assets/html-GMplVEZG.js +1 -0
- package/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
- package/dist/assets/http-jrhK8wxY.js +1 -0
- package/dist/assets/hurl-irOxFIW8.js +1 -0
- package/dist/assets/hxml-Bvhsp5Yf.js +1 -0
- package/dist/assets/hy-DFXneXwc.js +1 -0
- package/dist/assets/imba-DGztddWO.js +1 -0
- package/dist/assets/{index-ur6QLS8W.css → index-C4UPW6KM.css} +1 -1
- package/dist/assets/{index-CIzRMMYe.js → index-s4vGtpm_.js} +141 -129
- package/dist/assets/ini-BEwlwnbL.js +1 -0
- package/dist/assets/java-CylS5w8V.js +1 -0
- package/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/assets/jinja-4LBKfQ-Z.js +1 -0
- package/dist/assets/jison-wvAkD_A8.js +1 -0
- package/dist/assets/json-Cp-IABpG.js +1 -0
- package/dist/assets/json5-C9tS-k6U.js +1 -0
- package/dist/assets/jsonc-Des-eS-w.js +1 -0
- package/dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/dist/assets/jsonnet-DFQXde-d.js +1 -0
- package/dist/assets/jssm-C2t-YnRu.js +1 -0
- package/dist/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/assets/julia-C8NyazO9.js +1 -0
- package/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/dist/assets/kdl-DV7GczEv.js +1 -0
- package/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/assets/kusto-BvAqAH-y.js +1 -0
- package/dist/assets/laserwave-DUszq2jm.js +1 -0
- package/dist/assets/latex-BdAV_C_H.js +1 -0
- package/dist/assets/lean-Bc6EcWN3.js +1 -0
- package/dist/assets/less-B1dDrJ26.js +1 -0
- package/dist/assets/light-plus-B7mTdjB0.js +1 -0
- package/dist/assets/liquid-DYVedYrR.js +1 -0
- package/dist/assets/llvm-BtvRca6l.js +1 -0
- package/dist/assets/log-2UxHyX5q.js +1 -0
- package/dist/assets/logo-BtOb2qkB.js +1 -0
- package/dist/assets/lua-BbnMAYS6.js +1 -0
- package/dist/assets/luau-CXu1NL6O.js +1 -0
- package/dist/assets/make-CHLpvVh8.js +1 -0
- package/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/dist/assets/marko-CPi9NSCl.js +1 -0
- package/dist/assets/material-theme-D5KoaKCx.js +1 -0
- package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/dist/assets/matlab-D7o27uSR.js +1 -0
- package/dist/assets/mdc-DUICxH0z.js +1 -0
- package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/dist/assets/mermaid-DKYwYmdq.js +1 -0
- package/dist/assets/min-dark-CafNBF8u.js +1 -0
- package/dist/assets/min-light-CTRr51gU.js +1 -0
- package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
- package/dist/assets/mojo-1DNp92w6.js +1 -0
- package/dist/assets/monokai-D4h5O-jR.js +1 -0
- package/dist/assets/move-Bu9oaDYs.js +1 -0
- package/dist/assets/narrat-DRg8JJMk.js +1 -0
- package/dist/assets/nextflow-BrzmwbiE.js +1 -0
- package/dist/assets/nginx-DknmC5AR.js +1 -0
- package/dist/assets/night-owl-C39BiMTA.js +1 -0
- package/dist/assets/nim-CVrawwO9.js +1 -0
- package/dist/assets/nix-c8nO5XWb.js +1 -0
- package/dist/assets/nord-Ddv68eIx.js +1 -0
- package/dist/assets/nushell-C-sUppwS.js +1 -0
- package/dist/assets/objective-c-DXmwc3jG.js +1 -0
- package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
- package/dist/assets/ocaml-C0hk2d4L.js +1 -0
- package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/dist/assets/one-light-PoHY5YXO.js +1 -0
- package/dist/assets/openscad-C4EeE6gA.js +1 -0
- package/dist/assets/pascal-D93ZcfNL.js +1 -0
- package/dist/assets/perl-C0TMdlhV.js +1 -0
- package/dist/assets/php-CDn_0X-4.js +1 -0
- package/dist/assets/pkl-u5AG7uiY.js +1 -0
- package/dist/assets/plastic-3e1v2bzS.js +1 -0
- package/dist/assets/plsql-ChMvpjG-.js +1 -0
- package/dist/assets/po-BTJTHyun.js +1 -0
- package/dist/assets/poimandres-CS3Unz2-.js +1 -0
- package/dist/assets/polar-C0HS_06l.js +1 -0
- package/dist/assets/postcss-CXtECtnM.js +1 -0
- package/dist/assets/powerquery-CEu0bR-o.js +1 -0
- package/dist/assets/powershell-Dpen1YoG.js +1 -0
- package/dist/assets/prisma-Dd19v3D-.js +1 -0
- package/dist/assets/prolog-CbFg5uaA.js +1 -0
- package/dist/assets/proto-DyJlTyXw.js +1 -0
- package/dist/assets/pug-CGlum2m_.js +1 -0
- package/dist/assets/puppet-BMWR74SV.js +1 -0
- package/dist/assets/purescript-CklMAg4u.js +1 -0
- package/dist/assets/python-B6aJPvgy.js +1 -0
- package/dist/assets/qml-3beO22l8.js +1 -0
- package/dist/assets/qmldir-C8lEn-DE.js +1 -0
- package/dist/assets/qss-IeuSbFQv.js +1 -0
- package/dist/assets/r-DiinP2Uv.js +1 -0
- package/dist/assets/racket-BqYA7rlc.js +1 -0
- package/dist/assets/raku-DXvB9xmW.js +1 -0
- package/dist/assets/razor-CE9lU5zL.js +1 -0
- package/dist/assets/red-bN70gL4F.js +1 -0
- package/dist/assets/reg-C-SQnVFl.js +1 -0
- package/dist/assets/regexp-CDVJQ6XC.js +1 -0
- package/dist/assets/rel-C3B-1QV4.js +1 -0
- package/dist/assets/riscv-BM1_JUlF.js +1 -0
- package/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
- package/dist/assets/rst-B0xPkSld.js +1 -0
- package/dist/assets/ruby-BvKwtOVI.js +1 -0
- package/dist/assets/rust-B1yitclQ.js +1 -0
- package/dist/assets/sas-cz2c8ADy.js +1 -0
- package/dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/dist/assets/scala-C151Ov-r.js +1 -0
- package/dist/assets/scheme-C98Dy4si.js +1 -0
- package/dist/assets/scss-OYdSNvt2.js +1 -0
- package/dist/assets/sdbl-DVxCFoDh.js +1 -0
- package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/dist/assets/shellscript-Yzrsuije.js +1 -0
- package/dist/assets/shellsession-BADoaaVG.js +1 -0
- package/dist/assets/slack-dark-BthQWCQV.js +1 -0
- package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
- package/dist/assets/smalltalk-BERRCDM3.js +1 -0
- package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
- package/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/dist/assets/solarized-light-L9t79GZl.js +1 -0
- package/dist/assets/solidity-rGO070M0.js +1 -0
- package/dist/assets/soy-Brmx7dQM.js +1 -0
- package/dist/assets/sparql-rVzFXLq3.js +1 -0
- package/dist/assets/splunk-BtCnVYZw.js +1 -0
- package/dist/assets/sql-BLtJtn59.js +1 -0
- package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
- package/dist/assets/stata-BH5u7GGu.js +1 -0
- package/dist/assets/stylus-BEDo0Tqx.js +1 -0
- package/dist/assets/svelte-3Dk4HxPD.js +1 -0
- package/dist/assets/swift-Dg5xB15N.js +1 -0
- package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/dist/assets/system-verilog-CnnmHF94.js +1 -0
- package/dist/assets/systemd-4A_iFExJ.js +1 -0
- package/dist/assets/talonscript-CkByrt1z.js +1 -0
- package/dist/assets/tasl-QIJgUcNo.js +1 -0
- package/dist/assets/tcl-dwOrl1Do.js +1 -0
- package/dist/assets/templ-W15q3VgB.js +1 -0
- package/dist/assets/terraform-BETggiCN.js +1 -0
- package/dist/assets/tex-CxkMU7Pf.js +1 -0
- package/dist/assets/tokyo-night-hegEt444.js +1 -0
- package/dist/assets/toml-vGWfd6FD.js +1 -0
- package/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
- package/dist/assets/tsv-B_m7g4N7.js +1 -0
- package/dist/assets/tsx-COt5Ahok.js +1 -0
- package/dist/assets/turtle-BsS91CYL.js +1 -0
- package/dist/assets/twig-CO9l9SDP.js +1 -0
- package/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/assets/typespec-BGHnOYBU.js +1 -0
- package/dist/assets/typst-DHCkPAjA.js +1 -0
- package/dist/assets/v-BcVCzyr7.js +1 -0
- package/dist/assets/vala-CsfeWuGM.js +1 -0
- package/dist/assets/vb-D17OF-Vu.js +1 -0
- package/dist/assets/verilog-BQ8w6xss.js +1 -0
- package/dist/assets/vesper-DU1UobuO.js +1 -0
- package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
- package/dist/assets/viml-CJc9bBzg.js +1 -0
- package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/dist/assets/vue-DnHKYNfI.js +1 -0
- package/dist/assets/vue-html-CChd_i61.js +1 -0
- package/dist/assets/vue-vine-8moa0y9V.js +1 -0
- package/dist/assets/vyper-CDx5xZoG.js +1 -0
- package/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/assets/wasm-MzD3tlZU.js +1 -0
- package/dist/assets/wenyan-BV7otONQ.js +1 -0
- package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
- package/dist/assets/wikitext-BhOHFoWU.js +1 -0
- package/dist/assets/wit-5i3qLPDT.js +1 -0
- package/dist/assets/wolfram-lXgVvXCa.js +1 -0
- package/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/dist/assets/xsl-CtQFsRM5.js +1 -0
- package/dist/assets/yaml-Buea-lGh.js +1 -0
- package/dist/assets/zenscript-DVFEvuxE.js +1 -0
- package/dist/assets/zig-VOosw3JB.js +1 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- 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
|
|
43656
|
-
import { existsSync as
|
|
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
|
-
|
|
181875
|
-
|
|
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
|
|
181881
|
-
return c.json(
|
|
182362
|
+
const jobs = listJobs2(scope);
|
|
182363
|
+
return c.json(jobs);
|
|
181882
182364
|
} catch (err) {
|
|
181883
|
-
log2.jobs.error("Failed to list
|
|
181884
|
-
return c.json({ error: "Failed to list
|
|
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
|
|
181892
|
-
if (!
|
|
181893
|
-
return c.json({ error: "
|
|
182373
|
+
const job = getJob2(name, scope);
|
|
182374
|
+
if (!job) {
|
|
182375
|
+
return c.json({ error: "Job not found" }, 404);
|
|
181894
182376
|
}
|
|
181895
|
-
return c.json(
|
|
182377
|
+
return c.json(job);
|
|
181896
182378
|
} catch (err) {
|
|
181897
|
-
log2.jobs.error("Failed to get
|
|
181898
|
-
return c.json({ error: "Failed to get
|
|
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 =
|
|
182388
|
+
const entries = getJobLogs2(name, scope, lines);
|
|
181907
182389
|
return c.json({ entries });
|
|
181908
182390
|
} catch (err) {
|
|
181909
|
-
log2.jobs.error("Failed to get
|
|
181910
|
-
return c.json({ error: "Failed to get
|
|
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: "
|
|
182405
|
+
return c.json({ error: "Job name must contain only alphanumeric characters, hyphens, and underscores" }, 400);
|
|
181921
182406
|
}
|
|
181922
|
-
|
|
182407
|
+
createJob(body);
|
|
181923
182408
|
return c.json({ success: true }, 201);
|
|
181924
182409
|
} catch (err) {
|
|
181925
|
-
log2.jobs.error("Failed to create
|
|
181926
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to create
|
|
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
|
-
|
|
182421
|
+
updateJob(name, body);
|
|
181934
182422
|
return c.json({ success: true });
|
|
181935
182423
|
} catch (err) {
|
|
181936
|
-
log2.jobs.error("Failed to update
|
|
181937
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to update
|
|
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
|
-
|
|
182434
|
+
deleteJob(name);
|
|
181944
182435
|
return c.json({ success: true });
|
|
181945
182436
|
} catch (err) {
|
|
181946
|
-
log2.jobs.error("Failed to delete
|
|
181947
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to delete
|
|
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
|
-
|
|
182448
|
+
enableJob(name, scope, true);
|
|
181955
182449
|
return c.json({ success: true });
|
|
181956
182450
|
} catch (err) {
|
|
181957
|
-
log2.jobs.error("Failed to enable
|
|
181958
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to enable
|
|
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
|
-
|
|
182462
|
+
enableJob(name, scope, false);
|
|
181966
182463
|
return c.json({ success: true });
|
|
181967
182464
|
} catch (err) {
|
|
181968
|
-
log2.jobs.error("Failed to disable
|
|
181969
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to disable
|
|
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
|
-
|
|
182476
|
+
startJob(name, scope);
|
|
181977
182477
|
return c.json({ success: true });
|
|
181978
182478
|
} catch (err) {
|
|
181979
|
-
log2.jobs.error("Failed to start
|
|
181980
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to start
|
|
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
|
-
|
|
182490
|
+
stopJob(name, scope);
|
|
181988
182491
|
return c.json({ success: true });
|
|
181989
182492
|
} catch (err) {
|
|
181990
|
-
log2.jobs.error("Failed to stop
|
|
181991
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to stop
|
|
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
|
-
|
|
182504
|
+
runJobNow(name, scope);
|
|
181999
182505
|
return c.json({ success: true });
|
|
182000
182506
|
} catch (err) {
|
|
182001
|
-
log2.jobs.error("Failed to run
|
|
182002
|
-
return c.json({ error: err instanceof Error ? err.message : "Failed to run
|
|
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
|
|
182149
|
-
import { homedir as
|
|
182150
|
-
import { resolve as resolve5, join as
|
|
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 (!
|
|
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:
|
|
182786
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
182281
182787
|
const { mkdirSync: mkdirSync7, rmSync: rmSync6 } = await import("fs");
|
|
182282
|
-
const { homedir:
|
|
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 =
|
|
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 =
|
|
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 (
|
|
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 (!
|
|
182819
|
+
if (!existsSync19(parentDir)) {
|
|
182314
182820
|
mkdirSync7(parentDir, { recursive: true });
|
|
182315
182821
|
}
|
|
182316
182822
|
try {
|
|
182317
|
-
|
|
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 (
|
|
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 =
|
|
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 (
|
|
182439
|
-
const gitPath =
|
|
182440
|
-
if (!
|
|
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:
|
|
182591
|
-
const { join:
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
182610
|
-
const gitPath =
|
|
182611
|
-
if (
|
|
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:
|
|
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 (!
|
|
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
|
|
183219
|
+
return join27(process.env.VIBORA_PACKAGE_ROOT, "dist");
|
|
182714
183220
|
}
|
|
182715
|
-
return
|
|
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 =
|
|
182792
|
-
if (
|
|
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 =
|
|
182799
|
-
if (
|
|
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 =
|
|
182808
|
-
if (
|
|
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(
|
|
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
|
|
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 =
|
|
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,
|